Compare commits
	
		
			15 Commits
		
	
	
		
			wip/tiling
			...
			configurab
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 0a4cfde4e2 | ||
|   | c853d197e3 | ||
|   | bf7ae3e4d3 | ||
|   | 2b21f1d48c | ||
|   | 4c91e05b86 | ||
|   | bc91c328f3 | ||
|   | 5bbbac65d6 | ||
|   | a0a0fc14d7 | ||
|   | cc9efe1289 | ||
|   | 8825ded1ca | ||
|   | b823ef0007 | ||
|   | a846434bcf | ||
|   | 825fc2c0c8 | ||
|   | 4fbe547f16 | ||
|   | fc2ba0afbe | 
| @@ -28,6 +28,8 @@ mutter_SOURCES= 				\ | ||||
| 	compositor/meta-plugin.c		\ | ||||
| 	compositor/meta-plugin-manager.c	\ | ||||
| 	compositor/meta-plugin-manager.h	\ | ||||
| 	compositor/meta-shadow-factory.c	\ | ||||
| 	compositor/meta-shadow-factory-private.h	\ | ||||
| 	compositor/meta-shaped-texture.c	\ | ||||
| 	compositor/meta-shaped-texture.h	\ | ||||
| 	compositor/meta-texture-tower.c		\ | ||||
| @@ -36,12 +38,13 @@ mutter_SOURCES= 				\ | ||||
| 	compositor/meta-window-actor-private.h	\ | ||||
| 	compositor/meta-window-group.c		\ | ||||
| 	compositor/meta-window-group.h		\ | ||||
| 	compositor/shadow.c			\ | ||||
| 	compositor/shadow.h			\ | ||||
| 	compositor/tidy/tidy-texture-frame.c	\ | ||||
| 	compositor/tidy/tidy-texture-frame.h	\ | ||||
| 	compositor/meta-window-shape.c		\ | ||||
| 	compositor/meta-window-shape.h		\ | ||||
| 	compositor/region-utils.c		\ | ||||
| 	compositor/region-utils.h		\ | ||||
| 	include/compositor.h			\ | ||||
| 	include/meta-plugin.h			\ | ||||
| 	include/meta-shadow-factory.h		\ | ||||
| 	include/meta-window-actor.h		\ | ||||
| 	include/compositor-mutter.h 		\ | ||||
| 	core/constraints.c			\ | ||||
| @@ -167,6 +170,7 @@ libmutterinclude_base_headers =		\ | ||||
| 	include/group.h				\ | ||||
| 	include/keybindings.h			\ | ||||
| 	include/meta-plugin.h			\ | ||||
| 	include/meta-shadow-factory.h		\ | ||||
| 	include/meta-window-actor.h | ||||
|  | ||||
| # Excluded from scanning for introspection but installed | ||||
|   | ||||
| @@ -11,6 +11,7 @@ | ||||
| #include "compositor-mutter.h" | ||||
| #include "xprops.h" | ||||
| #include "prefs.h" | ||||
| #include "meta-shadow-factory.h" | ||||
| #include "meta-window-actor-private.h" | ||||
| #include "meta-window-group.h" | ||||
| #include "../core/window-private.h" /* to check window->hidden */ | ||||
| @@ -1017,6 +1018,26 @@ meta_repaint_func (gpointer data) | ||||
|   return TRUE; | ||||
| } | ||||
|  | ||||
| static void | ||||
| on_shadow_factory_changed (MetaShadowFactory *factory, | ||||
|                            MetaCompositor    *compositor) | ||||
| { | ||||
|   GSList *screens = meta_display_get_screens (compositor->display); | ||||
|   GList *l; | ||||
|   GSList *sl; | ||||
|  | ||||
|   for (sl = screens; sl; sl = sl->next) | ||||
|     { | ||||
|       MetaScreen *screen = sl->data; | ||||
|       MetaCompScreen *info = meta_screen_get_compositor_data (screen); | ||||
|       if (!info) | ||||
|         continue; | ||||
|  | ||||
|       for (l = info->windows; l; l = l->next) | ||||
|         meta_window_actor_invalidate_shadow (l->data); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * meta_compositor_new: (skip) | ||||
|  * | ||||
| @@ -1047,6 +1068,11 @@ meta_compositor_new (MetaDisplay *display) | ||||
|   XInternAtoms (xdisplay, atom_names, G_N_ELEMENTS (atom_names), | ||||
|                 False, atoms); | ||||
|  | ||||
|   g_signal_connect (meta_shadow_factory_get_default (), | ||||
|                     "changed", | ||||
|                     G_CALLBACK (on_shadow_factory_changed), | ||||
|                     compositor); | ||||
|  | ||||
|   compositor->atom_x_root_pixmap = atoms[0]; | ||||
|   compositor->atom_x_set_root = atoms[1]; | ||||
|   compositor->atom_net_wm_window_opacity = atoms[2]; | ||||
|   | ||||
							
								
								
									
										65
									
								
								src/compositor/meta-shadow-factory-private.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								src/compositor/meta-shadow-factory-private.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | ||||
| /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ | ||||
| /* | ||||
|  * MetaShadowFactory: | ||||
|  * | ||||
|  * Create and cache shadow textures for arbitrary window shapes | ||||
|  * | ||||
|  * Copyright (C) 2010 Red Hat, Inc. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU General Public License as | ||||
|  * published by the Free Software Foundation; either version 2 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, but | ||||
|  * WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software | ||||
|  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||||
|  * 02111-1307, USA. | ||||
|  */ | ||||
|  | ||||
| #ifndef __META_SHADOW_FACTORY_PRIVATE_H__ | ||||
| #define __META_SHADOW_FACTORY_PRIVATE_H__ | ||||
|  | ||||
| #include <cairo.h> | ||||
| #include <clutter/clutter.h> | ||||
| #include "meta-window-shape.h" | ||||
| #include "meta-shadow-factory.h" | ||||
|  | ||||
| /** | ||||
|  * MetaShadow: | ||||
|  * #MetaShadow holds a shadow texture along with information about how to | ||||
|  * apply that texture to draw a window texture. (E.g., it knows how big the | ||||
|  * unscaled borders are on each side of the shadow texture.) | ||||
|  */ | ||||
| typedef struct _MetaShadow MetaShadow; | ||||
|  | ||||
| MetaShadow *meta_shadow_ref         (MetaShadow            *shadow); | ||||
| void        meta_shadow_unref       (MetaShadow            *shadow); | ||||
| CoglHandle  meta_shadow_get_texture (MetaShadow            *shadow); | ||||
| void        meta_shadow_paint       (MetaShadow            *shadow, | ||||
|                                      int                    window_x, | ||||
|                                      int                    window_y, | ||||
|                                      int                    window_width, | ||||
|                                      int                    window_height, | ||||
|                                      guint8                 opacity, | ||||
|                                      cairo_region_t        *clip); | ||||
| void        meta_shadow_get_bounds  (MetaShadow            *shadow, | ||||
|                                      int                    window_x, | ||||
|                                      int                    window_y, | ||||
|                                      int                    window_width, | ||||
|                                      int                    window_height, | ||||
|                                      cairo_rectangle_int_t *bounds); | ||||
|  | ||||
| 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__ */ | ||||
							
								
								
									
										1032
									
								
								src/compositor/meta-shadow-factory.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1032
									
								
								src/compositor/meta-shadow-factory.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -28,6 +28,8 @@ void meta_window_actor_process_damage (MetaWindowActor    *self, | ||||
|                                        XDamageNotifyEvent *event); | ||||
| void meta_window_actor_pre_paint      (MetaWindowActor    *self); | ||||
|  | ||||
| void meta_window_actor_invalidate_shadow (MetaWindowActor *self); | ||||
|  | ||||
| gboolean meta_window_actor_effect_in_progress  (MetaWindowActor *self); | ||||
| void     meta_window_actor_sync_actor_position (MetaWindowActor *self); | ||||
| void     meta_window_actor_sync_visibility     (MetaWindowActor *self); | ||||
|   | ||||
| @@ -9,6 +9,7 @@ | ||||
| #include <X11/extensions/Xrender.h> | ||||
|  | ||||
| #include <clutter/x11/clutter-x11.h> | ||||
| #include <gdk/gdk.h> /* for gdk_rectangle_union() */ | ||||
|  | ||||
| #include "display.h" | ||||
| #include "errors.h" | ||||
| @@ -17,10 +18,9 @@ | ||||
| #include "xprops.h" | ||||
|  | ||||
| #include "compositor-private.h" | ||||
| #include "meta-shadow-factory-private.h" | ||||
| #include "meta-shaped-texture.h" | ||||
| #include "meta-window-actor-private.h" | ||||
| #include "shadow.h" | ||||
| #include "tidy/tidy-texture-frame.h" | ||||
|  | ||||
| struct _MetaWindowActorPrivate | ||||
| { | ||||
| @@ -31,12 +31,27 @@ struct _MetaWindowActorPrivate | ||||
|   MetaScreen       *screen; | ||||
|  | ||||
|   ClutterActor     *actor; | ||||
|   ClutterActor     *shadow; | ||||
|  | ||||
|   /* MetaShadowFactory only caches shadows that are actually in use; | ||||
|    * to avoid unnecessary recomputation we do two things: 1) we store | ||||
|    * both a focused and unfocused shadow for the window. If the window | ||||
|    * doesn't have different focused and unfocused shadow parameters, | ||||
|    * these will be the same. 2) when the shadow potentially changes we | ||||
|    * don't immediately unreference the old shadow, we just flag it as | ||||
|    * dirty and recompute it when we next need it (recompute_focused_shadow, | ||||
|    * recompute_unfocused_shadow.)  Because of the our extraction of | ||||
|    * size-invariant window shape, we'll often find that the new shadow | ||||
|    * is the same as the old shadow. | ||||
|    */ | ||||
|   MetaShadow       *focused_shadow; | ||||
|   MetaShadow       *unfocused_shadow; | ||||
|  | ||||
|   Pixmap            back_pixmap; | ||||
|  | ||||
|   Damage            damage; | ||||
|  | ||||
|   guint8            opacity; | ||||
|   guint8            shadow_opacity; | ||||
|  | ||||
|   gchar *           desc; | ||||
|  | ||||
| @@ -45,9 +60,16 @@ struct _MetaWindowActorPrivate | ||||
|   /* A rectangular region with the unshaped extends of the window | ||||
|    * texture */ | ||||
|   cairo_region_t   *bounding_region; | ||||
|   /* The region we should clip to when painting the shadow */ | ||||
|   cairo_region_t   *shadow_clip; | ||||
|  | ||||
|   /* Extracted size-invariant shape used for shadows */ | ||||
|   MetaWindowShape  *shadow_shape; | ||||
|  | ||||
|   gint              freeze_count; | ||||
|  | ||||
|   char *            shadow_class; | ||||
|  | ||||
|   /* | ||||
|    * These need to be counters rather than flags, since more plugins | ||||
|    * can implement same effect; the practicality of stacking effects | ||||
| @@ -70,7 +92,9 @@ struct _MetaWindowActorPrivate | ||||
|   guint		    received_damage        : 1; | ||||
|  | ||||
|   guint		    needs_pixmap           : 1; | ||||
|   guint		    needs_reshape          : 1; | ||||
|   guint             needs_reshape          : 1; | ||||
|   guint             recompute_focused_shadow   : 1; | ||||
|   guint             recompute_unfocused_shadow : 1; | ||||
|   guint		    size_changed           : 1; | ||||
|  | ||||
|   guint		    needs_destroy	   : 1; | ||||
| @@ -87,8 +111,13 @@ enum | ||||
|   PROP_X_WINDOW, | ||||
|   PROP_X_WINDOW_ATTRIBUTES, | ||||
|   PROP_NO_SHADOW, | ||||
|   PROP_SHADOW_CLASS | ||||
| }; | ||||
|  | ||||
| #define DEFAULT_SHADOW_RADIUS 12 | ||||
| #define DEFAULT_SHADOW_X_OFFSET 0 | ||||
| #define DEFAULT_SHADOW_Y_OFFSET 8 | ||||
|  | ||||
| static void meta_window_actor_dispose    (GObject *object); | ||||
| static void meta_window_actor_finalize   (GObject *object); | ||||
| static void meta_window_actor_constructed (GObject *object); | ||||
| @@ -101,11 +130,18 @@ static void meta_window_actor_get_property (GObject      *object, | ||||
|                                             GValue       *value, | ||||
|                                             GParamSpec   *pspec); | ||||
|  | ||||
| static void meta_window_actor_paint (ClutterActor *actor); | ||||
| #if CLUTTER_CHECK_VERSION(1, 5, 2) | ||||
| static gboolean meta_window_actor_get_paint_volume (ClutterActor       *actor, | ||||
|                                                     ClutterPaintVolume *volume); | ||||
| #endif | ||||
|  | ||||
| static void     meta_window_actor_detach     (MetaWindowActor *self); | ||||
| static gboolean meta_window_actor_has_shadow (MetaWindowActor *self); | ||||
|  | ||||
| static void meta_window_actor_clear_shape_region    (MetaWindowActor *self); | ||||
| static void meta_window_actor_clear_bounding_region (MetaWindowActor *self); | ||||
| static void meta_window_actor_clear_shadow_clip     (MetaWindowActor *self); | ||||
|  | ||||
| static gboolean is_shaped                (MetaDisplay  *display, | ||||
|                                           Window        xwindow); | ||||
| @@ -161,6 +197,7 @@ static void | ||||
| meta_window_actor_class_init (MetaWindowActorClass *klass) | ||||
| { | ||||
|   GObjectClass *object_class = G_OBJECT_CLASS (klass); | ||||
|   ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); | ||||
|   GParamSpec   *pspec; | ||||
|  | ||||
|   g_type_class_add_private (klass, sizeof (MetaWindowActorPrivate)); | ||||
| @@ -171,6 +208,11 @@ meta_window_actor_class_init (MetaWindowActorClass *klass) | ||||
|   object_class->get_property = meta_window_actor_get_property; | ||||
|   object_class->constructed  = meta_window_actor_constructed; | ||||
|  | ||||
|   actor_class->paint = meta_window_actor_paint; | ||||
| #if CLUTTER_CHECK_VERSION(1, 5, 2) | ||||
|   actor_class->get_paint_volume = meta_window_actor_get_paint_volume; | ||||
| #endif | ||||
|  | ||||
|   pspec = g_param_spec_object ("meta-window", | ||||
|                                "MetaWindow", | ||||
|                                "The displayed MetaWindow", | ||||
| @@ -216,11 +258,21 @@ meta_window_actor_class_init (MetaWindowActorClass *klass) | ||||
|                                 "No shadow", | ||||
|                                 "Do not add shaddow to this window", | ||||
|                                 FALSE, | ||||
|                                 G_PARAM_READWRITE | G_PARAM_CONSTRUCT); | ||||
|                                 G_PARAM_READWRITE); | ||||
|  | ||||
|   g_object_class_install_property (object_class, | ||||
|                                    PROP_NO_SHADOW, | ||||
|                                    pspec); | ||||
|  | ||||
|   pspec = g_param_spec_string ("shadow-class", | ||||
|                                "Name of the shadow class for this window.", | ||||
|                                "NULL means to use the default shadow class for this window type", | ||||
|                                NULL, | ||||
|                                G_PARAM_READWRITE); | ||||
|  | ||||
|   g_object_class_install_property (object_class, | ||||
|                                    PROP_SHADOW_CLASS, | ||||
|                                    pspec); | ||||
| } | ||||
|  | ||||
| static void | ||||
| @@ -232,6 +284,7 @@ meta_window_actor_init (MetaWindowActor *self) | ||||
| 						   META_TYPE_WINDOW_ACTOR, | ||||
| 						   MetaWindowActorPrivate); | ||||
|   priv->opacity = 0xff; | ||||
|   priv->shadow_class = NULL; | ||||
| } | ||||
|  | ||||
| static void | ||||
| @@ -291,18 +344,6 @@ window_decorated_notify (MetaWindow *mw, | ||||
|  | ||||
|   g_object_set (self, "x-window-attributes", &attrs, NULL); | ||||
|  | ||||
|   if (priv->shadow) | ||||
|     { | ||||
|       ClutterActor *p = clutter_actor_get_parent (priv->shadow); | ||||
|  | ||||
|       if (CLUTTER_IS_CONTAINER (p)) | ||||
|         clutter_container_remove_actor (CLUTTER_CONTAINER (p), priv->shadow); | ||||
|       else | ||||
|         clutter_actor_unparent (priv->shadow); | ||||
|  | ||||
|       priv->shadow = NULL; | ||||
|     } | ||||
|  | ||||
|   /* | ||||
|    * Recreate the contents. | ||||
|    */ | ||||
| @@ -344,13 +385,6 @@ meta_window_actor_constructed (GObject *object) | ||||
|  | ||||
|   meta_window_actor_update_opacity (self); | ||||
|  | ||||
|   if (meta_window_actor_has_shadow (self)) | ||||
|     { | ||||
|       priv->shadow = meta_create_shadow_frame (compositor); | ||||
|  | ||||
|       clutter_container_add_actor (CLUTTER_CONTAINER (self), priv->shadow); | ||||
|     } | ||||
|  | ||||
|   if (!priv->actor) | ||||
|     { | ||||
|       priv->actor = meta_shaped_texture_new (); | ||||
| @@ -406,6 +440,31 @@ meta_window_actor_dispose (GObject *object) | ||||
|  | ||||
|   meta_window_actor_clear_shape_region (self); | ||||
|   meta_window_actor_clear_bounding_region (self); | ||||
|   meta_window_actor_clear_shadow_clip (self); | ||||
|  | ||||
|   if (priv->shadow_class != NULL) | ||||
|     { | ||||
|       g_free (priv->shadow_class); | ||||
|       priv->shadow_class = NULL; | ||||
|     } | ||||
|  | ||||
|   if (priv->focused_shadow != NULL) | ||||
|     { | ||||
|       meta_shadow_unref (priv->focused_shadow); | ||||
|       priv->focused_shadow = NULL; | ||||
|     } | ||||
|  | ||||
|   if (priv->unfocused_shadow != NULL) | ||||
|     { | ||||
|       meta_shadow_unref (priv->unfocused_shadow); | ||||
|       priv->unfocused_shadow = NULL; | ||||
|     } | ||||
|  | ||||
|   if (priv->shadow_shape != NULL) | ||||
|     { | ||||
|       meta_window_shape_unref (priv->shadow_shape); | ||||
|       priv->shadow_shape = NULL; | ||||
|     } | ||||
|  | ||||
|   if (priv->damage != None) | ||||
|     { | ||||
| @@ -463,36 +522,27 @@ meta_window_actor_set_property (GObject      *object, | ||||
|       break; | ||||
|     case PROP_NO_SHADOW: | ||||
|       { | ||||
|         gboolean oldv = priv->no_shadow ? TRUE : FALSE; | ||||
|         gboolean newv = g_value_get_boolean (value); | ||||
|  | ||||
|         if (oldv == newv) | ||||
|         if (newv == priv->no_shadow) | ||||
|           return; | ||||
|  | ||||
|         priv->no_shadow = newv; | ||||
|  | ||||
|         if (newv && priv->shadow) | ||||
|           { | ||||
|             clutter_container_remove_actor (CLUTTER_CONTAINER (object), | ||||
|                                             priv->shadow); | ||||
|             priv->shadow = NULL; | ||||
|           } | ||||
|         else if (!newv && !priv->shadow && meta_window_actor_has_shadow (self)) | ||||
|           { | ||||
|             gfloat       w, h; | ||||
|             MetaDisplay *display = meta_screen_get_display (priv->screen); | ||||
|             MetaCompositor *compositor; | ||||
|         meta_window_actor_invalidate_shadow (self); | ||||
|       } | ||||
|       break; | ||||
|     case PROP_SHADOW_CLASS: | ||||
|       { | ||||
|         const char *newv = g_value_get_string (value); | ||||
|  | ||||
|             compositor = meta_display_get_compositor (display); | ||||
|         if (g_strcmp0 (newv, priv->shadow_class) == 0) | ||||
|           return; | ||||
|  | ||||
|             clutter_actor_get_size (CLUTTER_ACTOR (self), &w, &h); | ||||
|         g_free (priv->shadow_class); | ||||
|         priv->shadow_class = g_strdup (newv); | ||||
|  | ||||
|             priv->shadow = meta_create_shadow_frame (compositor); | ||||
|  | ||||
|             clutter_actor_set_size (priv->shadow, w, h); | ||||
|  | ||||
|             clutter_container_add_actor (CLUTTER_CONTAINER (self), priv->shadow); | ||||
|           } | ||||
|         meta_window_actor_invalidate_shadow (self); | ||||
|       } | ||||
|       break; | ||||
|     default: | ||||
| @@ -526,12 +576,164 @@ meta_window_actor_get_property (GObject      *object, | ||||
|     case PROP_NO_SHADOW: | ||||
|       g_value_set_boolean (value, priv->no_shadow); | ||||
|       break; | ||||
|     case PROP_SHADOW_CLASS: | ||||
|       g_value_set_string (value, priv->shadow_class); | ||||
|       break; | ||||
|     default: | ||||
|       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | ||||
|       break; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static const char * | ||||
| meta_window_actor_get_shadow_class (MetaWindowActor *self) | ||||
| { | ||||
|   MetaWindowActorPrivate *priv = self->priv; | ||||
|  | ||||
|   if (priv->shadow_class != NULL) | ||||
|     return priv->shadow_class; | ||||
|   else | ||||
|     { | ||||
|       MetaWindowType window_type = meta_window_get_window_type (priv->window); | ||||
|  | ||||
|       switch (window_type) | ||||
|         { | ||||
|         case META_WINDOW_DROPDOWN_MENU: | ||||
|           return "dropdown-menu"; | ||||
|         case META_WINDOW_POPUP_MENU: | ||||
|           return "popup-menu"; | ||||
|         default: | ||||
|           { | ||||
|             MetaFrameType frame_type = meta_window_get_frame_type (priv->window); | ||||
|             return meta_frame_type_to_string (frame_type); | ||||
|           } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void | ||||
| meta_window_actor_get_shadow_params (MetaWindowActor  *self, | ||||
|                                      gboolean          appears_focused, | ||||
|                                      MetaShadowParams *params) | ||||
| { | ||||
|   const char *shadow_class = meta_window_actor_get_shadow_class (self); | ||||
|  | ||||
|   meta_shadow_factory_get_params (meta_shadow_factory_get_default (), | ||||
|                                   shadow_class, appears_focused, | ||||
|                                   params); | ||||
| } | ||||
|  | ||||
| static void | ||||
| meta_window_actor_get_shape_bounds (MetaWindowActor       *self, | ||||
|                                     cairo_rectangle_int_t *bounds) | ||||
| { | ||||
|   MetaWindowActorPrivate *priv = self->priv; | ||||
|  | ||||
|   /* We need to be defensive here because there are corner cases | ||||
|    * where getting the shape fails on a window being destroyed | ||||
|    * and similar. | ||||
|    */ | ||||
|   if (priv->shaped && priv->shape_region) | ||||
|     cairo_region_get_extents (priv->shape_region, bounds); | ||||
|   else if (priv->bounding_region) | ||||
|     cairo_region_get_extents (priv->bounding_region, bounds); | ||||
|   else | ||||
|     bounds->x = bounds->y = bounds->width = bounds->height = 0; | ||||
| } | ||||
|  | ||||
| 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); | ||||
| } | ||||
|  | ||||
| static void | ||||
| meta_window_actor_paint (ClutterActor *actor) | ||||
| { | ||||
|   MetaWindowActor *self = META_WINDOW_ACTOR (actor); | ||||
|   MetaWindowActorPrivate *priv = self->priv; | ||||
|   gboolean appears_focused = meta_window_appears_focused (priv->window); | ||||
|   MetaShadow *shadow = appears_focused ? priv->focused_shadow : priv->unfocused_shadow; | ||||
|  | ||||
|   if (shadow != NULL) | ||||
|     { | ||||
|       MetaShadowParams params; | ||||
|       cairo_rectangle_int_t shape_bounds; | ||||
|  | ||||
|       meta_window_actor_get_shape_bounds (self, &shape_bounds); | ||||
|       meta_window_actor_get_shadow_params (self, appears_focused, ¶ms); | ||||
|  | ||||
|       meta_shadow_paint (shadow, | ||||
|                          params.x_offset + shape_bounds.x, | ||||
|                          params.y_offset + shape_bounds.y, | ||||
|                          shape_bounds.width, | ||||
|                          shape_bounds.height, | ||||
|                          (clutter_actor_get_paint_opacity (actor) * params.opacity) / 255, | ||||
|                          priv->shadow_clip); | ||||
|     } | ||||
|  | ||||
|   CLUTTER_ACTOR_CLASS (meta_window_actor_parent_class)->paint (actor); | ||||
| } | ||||
|  | ||||
| #if CLUTTER_CHECK_VERSION(1, 5, 2) | ||||
| static gboolean | ||||
| meta_window_actor_get_paint_volume (ClutterActor       *actor, | ||||
|                                     ClutterPaintVolume *volume) | ||||
| { | ||||
|   MetaWindowActor *self = META_WINDOW_ACTOR (actor); | ||||
|   MetaWindowActorPrivate *priv = self->priv; | ||||
|   cairo_rectangle_int_t bounds; | ||||
|   gboolean appears_focused = meta_window_appears_focused (priv->window); | ||||
|   ClutterVertex origin; | ||||
|  | ||||
|   /* The paint volume is computed before paint functions are called | ||||
|    * so our bounds might not be updated yet. Force an update. */ | ||||
|   meta_window_actor_pre_paint (self); | ||||
|  | ||||
|   meta_window_actor_get_shape_bounds (self, &bounds); | ||||
|  | ||||
|   if (appears_focused ? priv->focused_shadow : priv->unfocused_shadow) | ||||
|     { | ||||
|       cairo_rectangle_int_t shadow_bounds; | ||||
|  | ||||
|       /* We could compute an full clip region as we do for the window | ||||
|        * texture, but the shadow is relatively cheap to draw, and | ||||
|        * a little more complex to clip, so we just catch the case where | ||||
|        * the shadow is completely obscured and doesn't need to be drawn | ||||
|        * at all. | ||||
|        */ | ||||
|  | ||||
|       meta_window_actor_get_shadow_bounds (self, appears_focused, &shadow_bounds); | ||||
|       gdk_rectangle_union (&bounds, &shadow_bounds, &bounds); | ||||
|     } | ||||
|  | ||||
|   origin.x = bounds.x; | ||||
|   origin.y = bounds.y; | ||||
|   origin.z = 0.0f; | ||||
|   clutter_paint_volume_set_origin (volume, &origin); | ||||
|  | ||||
|   clutter_paint_volume_set_width (volume, bounds.width); | ||||
|   clutter_paint_volume_set_height (volume, bounds.height); | ||||
|  | ||||
|   return TRUE; | ||||
| } | ||||
| #endif /* CLUTTER_CHECK_VERSION */ | ||||
|  | ||||
| static gboolean | ||||
| is_shaped (MetaDisplay *display, Window xwindow) | ||||
| { | ||||
| @@ -560,10 +762,16 @@ meta_window_actor_has_shadow (MetaWindowActor *self) | ||||
|   if (priv->no_shadow) | ||||
|     return FALSE; | ||||
|  | ||||
|   /* Leaving out shadows for maximized and fullscreen windows is an effeciency | ||||
|    * win and also prevents the unsightly effect of the shadow of maximized | ||||
|    * window appearing on an adjacent window */ | ||||
|   if ((meta_window_get_maximized (priv->window) == (META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL)) || | ||||
|       meta_window_is_fullscreen (priv->window)) | ||||
|     return FALSE; | ||||
|  | ||||
|   /* | ||||
|    * Always put a shadow around windows with a frame - This should override | ||||
|    * the restriction about not putting a shadow around shaped windows | ||||
|    * as the frame might be the reason the window is shaped | ||||
|    * the restriction about not putting a shadow around ARGB windows. | ||||
|    */ | ||||
|   if (priv->window) | ||||
|     { | ||||
| @@ -576,7 +784,8 @@ meta_window_actor_has_shadow (MetaWindowActor *self) | ||||
|     } | ||||
|  | ||||
|   /* | ||||
|    * Do not add shadows to ARGB windows (since they are probably transparent) | ||||
|    * Do not add shadows to ARGB windows; eventually we should generate a | ||||
|    * shadow from the input shape for such windows. | ||||
|    */ | ||||
|   if (priv->argb32 || priv->opacity != 0xff) | ||||
|     { | ||||
| @@ -585,19 +794,8 @@ meta_window_actor_has_shadow (MetaWindowActor *self) | ||||
|       return FALSE; | ||||
|     } | ||||
|  | ||||
|   /* | ||||
|    * Never put a shadow around shaped windows | ||||
|    */ | ||||
|   if (priv->shaped) | ||||
|     { | ||||
|       meta_verbose ("Window 0x%x has no shadow as it is shaped\n", | ||||
| 		    (guint)priv->xwindow); | ||||
|       return FALSE; | ||||
|     } | ||||
|  | ||||
|   /* | ||||
|    * Add shadows to override redirect windows (e.g., Gtk menus). | ||||
|    * This must have lower priority than window shape test. | ||||
|    */ | ||||
|   if (priv->attrs.override_redirect) | ||||
|     { | ||||
| @@ -1358,6 +1556,18 @@ meta_window_actor_clear_bounding_region (MetaWindowActor *self) | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void | ||||
| meta_window_actor_clear_shadow_clip (MetaWindowActor *self) | ||||
| { | ||||
|   MetaWindowActorPrivate *priv = self->priv; | ||||
|  | ||||
|   if (priv->shadow_clip) | ||||
|     { | ||||
|       cairo_region_destroy (priv->shadow_clip); | ||||
|       priv->shadow_clip = NULL; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void | ||||
| meta_window_actor_update_bounding_region (MetaWindowActor *self, | ||||
|                                           int              width, | ||||
| @@ -1366,9 +1576,26 @@ meta_window_actor_update_bounding_region (MetaWindowActor *self, | ||||
|   MetaWindowActorPrivate *priv = self->priv; | ||||
|   cairo_rectangle_int_t bounding_rectangle = { 0, 0, width, height }; | ||||
|  | ||||
|   if (priv->bounding_region != NULL) | ||||
|     { | ||||
|       cairo_rectangle_int_t old_bounding_rectangle; | ||||
|       cairo_region_get_extents (priv->bounding_region, &old_bounding_rectangle); | ||||
|  | ||||
|       if (old_bounding_rectangle.width == width && old_bounding_rectangle.height == height) | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|   meta_window_actor_clear_bounding_region (self); | ||||
|  | ||||
|   priv->bounding_region = cairo_region_create_rectangle (&bounding_rectangle); | ||||
|  | ||||
|   /* When we're shaped, we use the shape region to generate the shadow; the shape | ||||
|    * region only changes when we get ShapeNotify event; but for unshaped windows | ||||
|    * we generate the shadow from the bounding region, so we need to recompute | ||||
|    * the shadow when the size changes. | ||||
|    */ | ||||
|   if (!priv->shaped) | ||||
|     meta_window_actor_invalidate_shadow (self); | ||||
| } | ||||
|  | ||||
| static void | ||||
| @@ -1497,30 +1724,12 @@ meta_window_actor_set_visible_region_beneath (MetaWindowActor *self, | ||||
|                                               cairo_region_t  *beneath_region) | ||||
| { | ||||
|   MetaWindowActorPrivate *priv = self->priv; | ||||
|   gboolean appears_focused = meta_window_appears_focused (priv->window); | ||||
|  | ||||
|   if (priv->shadow) | ||||
|   if (appears_focused ? priv->focused_shadow : priv->unfocused_shadow) | ||||
|     { | ||||
|       cairo_rectangle_int_t shadow_rect; | ||||
|       ClutterActorBox box; | ||||
|       cairo_region_overlap_t overlap; | ||||
|  | ||||
|       /* We could compute an full clip region as we do for the window | ||||
|        * texture, but the shadow is relatively cheap to draw, and | ||||
|        * a little more complex to clip, so we just catch the case where | ||||
|        * the shadow is completely obscured and doesn't need to be drawn | ||||
|        * at all. | ||||
|        */ | ||||
|       clutter_actor_get_allocation_box (priv->shadow, &box); | ||||
|  | ||||
|       shadow_rect.x = roundf (box.x1); | ||||
|       shadow_rect.y = roundf (box.y1); | ||||
|       shadow_rect.width = roundf (box.x2 - box.x1); | ||||
|       shadow_rect.height = roundf (box.y2 - box.y1); | ||||
|  | ||||
|       overlap = cairo_region_contains_rectangle (beneath_region, &shadow_rect); | ||||
|  | ||||
|       tidy_texture_frame_set_needs_paint (TIDY_TEXTURE_FRAME (priv->shadow), | ||||
|                                           overlap != CAIRO_REGION_OVERLAP_OUT); | ||||
|       meta_window_actor_clear_shadow_clip (self); | ||||
|       priv->shadow_clip = cairo_region_copy (beneath_region); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -1538,8 +1747,7 @@ meta_window_actor_reset_visible_regions (MetaWindowActor *self) | ||||
|  | ||||
|   meta_shaped_texture_set_clip_region (META_SHAPED_TEXTURE (priv->actor), | ||||
|                                        NULL); | ||||
|   if (priv->shadow) | ||||
|     tidy_texture_frame_set_needs_paint (TIDY_TEXTURE_FRAME (priv->shadow), TRUE); | ||||
|   meta_window_actor_clear_shadow_clip (self); | ||||
| } | ||||
|  | ||||
| static void | ||||
| @@ -1622,9 +1830,6 @@ check_needs_pixmap (MetaWindowActor *self) | ||||
|                     "pixmap-height", &pxm_height, | ||||
|                     NULL); | ||||
|  | ||||
|       if (priv->shadow) | ||||
|         clutter_actor_set_size (priv->shadow, pxm_width, pxm_height); | ||||
|  | ||||
|       meta_window_actor_update_bounding_region (self, pxm_width, pxm_height); | ||||
|  | ||||
|       full = TRUE; | ||||
| @@ -1635,6 +1840,77 @@ check_needs_pixmap (MetaWindowActor *self) | ||||
|   priv->needs_pixmap = FALSE; | ||||
| } | ||||
|  | ||||
| static void | ||||
| check_needs_shadow (MetaWindowActor *self) | ||||
| { | ||||
|   MetaWindowActorPrivate *priv = self->priv; | ||||
|   MetaShadow *old_shadow = NULL; | ||||
|   MetaShadow **shadow_location; | ||||
|   gboolean recompute_shadow; | ||||
|   gboolean should_have_shadow; | ||||
|   gboolean appears_focused; | ||||
|  | ||||
|   if (!priv->mapped) | ||||
|     return; | ||||
|  | ||||
|   /* Calling meta_window_actor_has_shadow() here at every pre-paint is cheap | ||||
|    * and avoids the need to explicitly handle window type changes, which | ||||
|    * we would do if tried to keep track of when we might be adding or removing | ||||
|    * a shadow more explicitly. We only keep track of changes to the *shape* of | ||||
|    * the shadow with priv->recompute_shadow. | ||||
|    */ | ||||
|  | ||||
|   should_have_shadow = meta_window_actor_has_shadow (self); | ||||
|   appears_focused = meta_window_appears_focused (priv->window); | ||||
|  | ||||
|   if (appears_focused) | ||||
|     { | ||||
|       recompute_shadow = priv->recompute_focused_shadow; | ||||
|       priv->recompute_focused_shadow = FALSE; | ||||
|       shadow_location = &priv->focused_shadow; | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       recompute_shadow = priv->recompute_unfocused_shadow; | ||||
|       priv->recompute_unfocused_shadow = FALSE; | ||||
|       shadow_location = &priv->unfocused_shadow; | ||||
|     } | ||||
|  | ||||
|   if (!should_have_shadow || recompute_shadow) | ||||
|     { | ||||
|       if (*shadow_location != NULL) | ||||
|         { | ||||
|           old_shadow = *shadow_location; | ||||
|           *shadow_location = NULL; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   if (*shadow_location == NULL && should_have_shadow) | ||||
|     { | ||||
|       MetaShadowFactory *factory = meta_shadow_factory_get_default (); | ||||
|       const char *shadow_class = meta_window_actor_get_shadow_class (self); | ||||
|       cairo_rectangle_int_t shape_bounds; | ||||
|  | ||||
|       if (priv->shadow_shape == NULL) | ||||
|         { | ||||
|           if (priv->shaped) | ||||
|             priv->shadow_shape = meta_window_shape_new (priv->shape_region); | ||||
|           else | ||||
|             priv->shadow_shape = meta_window_shape_new (priv->bounding_region); | ||||
|         } | ||||
|  | ||||
|       meta_window_actor_get_shape_bounds (self, &shape_bounds); | ||||
|  | ||||
|       *shadow_location = meta_shadow_factory_get_shadow (factory, | ||||
|                                                          priv->shadow_shape, | ||||
|                                                          shape_bounds.width, shape_bounds.height, | ||||
|                                                          shadow_class, appears_focused); | ||||
|     } | ||||
|  | ||||
|   if (old_shadow != NULL) | ||||
|     meta_shadow_unref (old_shadow); | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| is_frozen (MetaWindowActor *self) | ||||
| { | ||||
| @@ -1733,6 +2009,7 @@ check_needs_reshape (MetaWindowActor *self) | ||||
| #endif | ||||
|  | ||||
|   priv->needs_reshape = FALSE; | ||||
|   meta_window_actor_invalidate_shadow (self); | ||||
| } | ||||
|  | ||||
| void | ||||
| @@ -1743,6 +2020,11 @@ meta_window_actor_update_shape (MetaWindowActor   *self, | ||||
|  | ||||
|   priv->shaped = shaped; | ||||
|   priv->needs_reshape = TRUE; | ||||
|   if (priv->shadow_shape != NULL) | ||||
|     { | ||||
|       meta_window_shape_unref (priv->shadow_shape); | ||||
|       priv->shadow_shape = NULL; | ||||
|     } | ||||
|  | ||||
|   clutter_actor_queue_redraw (priv->actor); | ||||
| } | ||||
| @@ -1770,8 +2052,19 @@ meta_window_actor_pre_paint (MetaWindowActor *self) | ||||
|       priv->received_damage = FALSE; | ||||
|     } | ||||
|  | ||||
|   check_needs_reshape (self); | ||||
|   check_needs_pixmap (self); | ||||
|   check_needs_reshape (self); | ||||
|   check_needs_shadow (self); | ||||
| } | ||||
|  | ||||
| void | ||||
| meta_window_actor_invalidate_shadow (MetaWindowActor *self) | ||||
| { | ||||
|   MetaWindowActorPrivate *priv = self->priv; | ||||
|  | ||||
|   priv->recompute_focused_shadow = TRUE; | ||||
|   priv->recompute_unfocused_shadow = TRUE; | ||||
|   clutter_actor_queue_redraw (CLUTTER_ACTOR (self)); | ||||
| } | ||||
|  | ||||
| void | ||||
|   | ||||
							
								
								
									
										253
									
								
								src/compositor/meta-window-shape.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										253
									
								
								src/compositor/meta-window-shape.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,253 @@ | ||||
| /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ | ||||
| /* | ||||
|  * MetaWindowShape | ||||
|  * | ||||
|  * Extracted invariant window shape | ||||
|  * | ||||
|  * Copyright (C) 2010 Red Hat, Inc. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU General Public License as | ||||
|  * published by the Free Software Foundation; either version 2 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, but | ||||
|  * WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software | ||||
|  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||||
|  * 02111-1307, USA. | ||||
|  */ | ||||
| #include <string.h> | ||||
|  | ||||
| #include "meta-window-shape.h" | ||||
| #include "region-utils.h" | ||||
|  | ||||
| struct _MetaWindowShape | ||||
| { | ||||
|   guint ref_count; | ||||
|  | ||||
|   int top, right, bottom, left; | ||||
|   int n_rectangles; | ||||
|   cairo_rectangle_int_t *rectangles; | ||||
|   guint hash; | ||||
| }; | ||||
|  | ||||
| MetaWindowShape * | ||||
| meta_window_shape_new (cairo_region_t *region) | ||||
| { | ||||
|   MetaWindowShape *shape; | ||||
|   MetaRegionIterator iter; | ||||
|   cairo_rectangle_int_t extents; | ||||
|   int max_yspan_y1 = 0; | ||||
|   int max_yspan_y2 = 0; | ||||
|   int max_xspan_x1 = -1; | ||||
|   int max_xspan_x2 = -1; | ||||
|   guint hash; | ||||
|  | ||||
|   shape = g_slice_new0 (MetaWindowShape); | ||||
|   shape->ref_count = 1; | ||||
|  | ||||
|   cairo_region_get_extents (region, &extents); | ||||
|  | ||||
|   shape->n_rectangles = cairo_region_num_rectangles (region); | ||||
|  | ||||
|   if (shape->n_rectangles == 0) | ||||
|     { | ||||
|       shape->rectangles = NULL; | ||||
|       shape->top = shape->right = shape->bottom = shape->left = 0; | ||||
|       shape->hash = 0; | ||||
|       return shape; | ||||
|     } | ||||
|  | ||||
|   for (meta_region_iterator_init (&iter, region); | ||||
|        !meta_region_iterator_at_end (&iter); | ||||
|        meta_region_iterator_next (&iter)) | ||||
|     { | ||||
|       int max_line_xspan_x1 = -1; | ||||
|       int max_line_xspan_x2 = -1; | ||||
|  | ||||
|       if (iter.rectangle.width > max_line_xspan_x2 - max_line_xspan_x1) | ||||
|         { | ||||
|           max_line_xspan_x1 = iter.rectangle.x; | ||||
|           max_line_xspan_x2 = iter.rectangle.x + iter.rectangle.width; | ||||
|         } | ||||
|  | ||||
|       if (iter.line_end) | ||||
|         { | ||||
|           if (iter.rectangle.height > max_yspan_y2 - max_yspan_y1) | ||||
|             { | ||||
|               max_yspan_y1 = iter.rectangle.y; | ||||
|               max_yspan_y2 = iter.rectangle.y + iter.rectangle.height; | ||||
|             } | ||||
|  | ||||
|           if (max_xspan_x1 < 0) /* First line */ | ||||
|             { | ||||
|               max_xspan_x1 = max_line_xspan_x1; | ||||
|               max_xspan_x2 = max_line_xspan_x2; | ||||
|             } | ||||
|           else | ||||
|             { | ||||
|               max_xspan_x1 = MAX (max_xspan_x1, max_line_xspan_x1); | ||||
|               max_xspan_x2 = MIN (max_xspan_x2, max_line_xspan_x2); | ||||
|  | ||||
|               if (max_xspan_x2 < max_xspan_x1) | ||||
|                 max_xspan_x2 = max_xspan_x1; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| #if 0 | ||||
|   g_print ("xspan: %d -> %d, yspan: %d -> %d\n", | ||||
|            max_xspan_x1, max_xspan_x2, | ||||
|            max_yspan_y1, max_yspan_y2); | ||||
| #endif | ||||
|  | ||||
|   shape->top = max_yspan_y1 - extents.y; | ||||
|   shape->right = extents.x + extents.width - max_xspan_x2; | ||||
|   shape->bottom = extents.y + extents.height - max_yspan_y2; | ||||
|   shape->left = max_xspan_x1 - extents.x; | ||||
|  | ||||
|   shape->rectangles = g_new (cairo_rectangle_int_t, shape->n_rectangles); | ||||
|  | ||||
|   hash = 0; | ||||
|   for (meta_region_iterator_init (&iter, region); | ||||
|        !meta_region_iterator_at_end (&iter); | ||||
|        meta_region_iterator_next (&iter)) | ||||
|     { | ||||
|       int x1, x2, y1, y2; | ||||
|  | ||||
|       x1 = iter.rectangle.x; | ||||
|       x2 = iter.rectangle.x + iter.rectangle.width; | ||||
|       y1 = iter.rectangle.y; | ||||
|       y2 = iter.rectangle.y + iter.rectangle.height; | ||||
|  | ||||
|       if (x1 > max_xspan_x1) | ||||
|         x1 -= MIN (x1, max_xspan_x2 - 1) - max_xspan_x1; | ||||
|       if (x2 > max_xspan_x1) | ||||
|         x2 -= MIN (x2, max_xspan_x2 - 1) - max_xspan_x1; | ||||
|       if (y1 > max_yspan_y1) | ||||
|         y1 -= MIN (y1, max_yspan_y2 - 1) - max_yspan_y1; | ||||
|       if (y2 > max_yspan_y1) | ||||
|         y2 -= MIN (y2, max_yspan_y2 - 1) - max_yspan_y1; | ||||
|  | ||||
|       shape->rectangles[iter.i].x = x1 - extents.x; | ||||
|       shape->rectangles[iter.i].y = y1 - extents.y; | ||||
|       shape->rectangles[iter.i].width = x2 - x1; | ||||
|       shape->rectangles[iter.i].height = y2 - y1; | ||||
|  | ||||
| #if 0 | ||||
|       g_print ("%d: +%d+%dx%dx%d => +%d+%dx%dx%d\n", | ||||
|                i, iter.rectangle.x, iter.rectangle.y, iter.rectangle.width, iter.rectangle.height, | ||||
|                shape->rectangles[i].x, shape->rectangles[i].y, shape->rectangles[i].width, shape->rectangles[i].height); | ||||
| #endif | ||||
|  | ||||
|       hash = hash * 31 + x1 * 17 + x2 * 27 + y1 * 37 + y2 * 43; | ||||
|     } | ||||
|  | ||||
|   shape->hash = hash; | ||||
|  | ||||
| #if 0 | ||||
|   g_print ("%d %d %d %d: %#x\n\n", shape->top, shape->right, shape->bottom, shape->left, shape->hash); | ||||
| #endif | ||||
|  | ||||
|   return shape; | ||||
| } | ||||
|  | ||||
| MetaWindowShape * | ||||
| meta_window_shape_ref (MetaWindowShape *shape) | ||||
| { | ||||
|   shape->ref_count++; | ||||
|  | ||||
|   return shape; | ||||
| } | ||||
|  | ||||
| void | ||||
| meta_window_shape_unref (MetaWindowShape *shape) | ||||
| { | ||||
|   shape->ref_count--; | ||||
|   if (shape->ref_count == 0) | ||||
|     { | ||||
|       g_free (shape->rectangles); | ||||
|       g_slice_free (MetaWindowShape, shape); | ||||
|     } | ||||
| } | ||||
|  | ||||
| guint | ||||
| meta_window_shape_hash (MetaWindowShape *shape) | ||||
| { | ||||
|   return shape->hash; | ||||
| } | ||||
|  | ||||
| gboolean | ||||
| meta_window_shape_equal (MetaWindowShape *shape_a, | ||||
|                          MetaWindowShape *shape_b) | ||||
| { | ||||
|   if (shape_a->n_rectangles != shape_b->n_rectangles) | ||||
|     return FALSE; | ||||
|  | ||||
|   return memcmp (shape_a->rectangles, shape_b->rectangles, | ||||
|                  sizeof (cairo_rectangle_int_t) * shape_a->n_rectangles) == 0; | ||||
| } | ||||
|  | ||||
| void | ||||
| meta_window_shape_get_borders (MetaWindowShape *shape, | ||||
|                                int             *border_top, | ||||
|                                int             *border_right, | ||||
|                                int             *border_bottom, | ||||
|                                int             *border_left) | ||||
| { | ||||
|   if (border_top) | ||||
|     *border_top = shape->top; | ||||
|   if (border_right) | ||||
|     *border_right = shape->right; | ||||
|   if (border_bottom) | ||||
|     *border_bottom = shape->bottom; | ||||
|   if (border_left) | ||||
|     *border_left = shape->left; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * meta_window_shape_to_region: | ||||
|  * @shape: a #MetaWindowShape | ||||
|  * @center_width: size of the central region horizontally | ||||
|  * @center_height: size of the central region vertically | ||||
|  * | ||||
|  * Converts the shape to to a cairo_region_t using the given width | ||||
|  * and height for the central scaled region. | ||||
|  * | ||||
|  * Return value: a newly created region | ||||
|  */ | ||||
| cairo_region_t * | ||||
| meta_window_shape_to_region (MetaWindowShape *shape, | ||||
|                              int              center_width, | ||||
|                              int              center_height) | ||||
| { | ||||
|   cairo_region_t *region; | ||||
|   int i; | ||||
|  | ||||
|   region = cairo_region_create (); | ||||
|  | ||||
|   for (i = 0; i < shape->n_rectangles; i++) | ||||
|     { | ||||
|       cairo_rectangle_int_t rect = shape->rectangles[i]; | ||||
|  | ||||
|       if (rect.x <= shape->left && rect.x + rect.width >= shape->left + 1) | ||||
|         rect.width += center_width; | ||||
|       else if (rect.x >= shape->left + 1) | ||||
|         rect.x += center_width; | ||||
|  | ||||
|       if (rect.y <= shape->top && rect.y + rect.height >= shape->top + 1) | ||||
|         rect.height += center_height; | ||||
|       else if (rect.y >= shape->top + 1) | ||||
|         rect.y += center_height; | ||||
|  | ||||
|       cairo_region_union_rectangle (region, &rect); | ||||
|     } | ||||
|  | ||||
|   return region; | ||||
| } | ||||
|  | ||||
							
								
								
									
										60
									
								
								src/compositor/meta-window-shape.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								src/compositor/meta-window-shape.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ | ||||
| /* | ||||
|  * MetaWindowShape | ||||
|  * | ||||
|  * Extracted invariant window shape | ||||
|  * | ||||
|  * Copyright (C) 2010 Red Hat, Inc. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU General Public License as | ||||
|  * published by the Free Software Foundation; either version 2 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, but | ||||
|  * WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software | ||||
|  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||||
|  * 02111-1307, USA. | ||||
|  */ | ||||
|  | ||||
| #ifndef __META_WINDOW_SHAPE_H__ | ||||
| #define __META_WINDOW_SHAPE_H__ | ||||
|  | ||||
| #include <cairo.h> | ||||
| #include <glib.h> | ||||
|  | ||||
| /** | ||||
|  * MetaWindowShape: | ||||
|  * #MetaWindowShape represents a 9-sliced region with borders on all sides that | ||||
|  * are unscaled, and a constant central region that is scaled. For example, | ||||
|  * if you the regions representing two windows that around rounded rectangles, | ||||
|  * with the same corner regions, but different sizes, they 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 __*/ | ||||
|  | ||||
							
								
								
									
										334
									
								
								src/compositor/region-utils.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										334
									
								
								src/compositor/region-utils.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,334 @@ | ||||
| /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ | ||||
| /* | ||||
|  * Utilities for region manipulation | ||||
|  * | ||||
|  * Copyright (C) 2010 Red Hat, Inc. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU General Public License as | ||||
|  * published by the Free Software Foundation; either version 2 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, but | ||||
|  * WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software | ||||
|  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||||
|  * 02111-1307, USA. | ||||
|  */ | ||||
|  | ||||
| #include "region-utils.h" | ||||
|  | ||||
| #include <math.h> | ||||
|  | ||||
| /* MetaRegionBuilder */ | ||||
|  | ||||
| /* Various algorithms in this file require unioning together a set of rectangles | ||||
|  * that are unsorted or overlap; unioning such a set of rectangles 1-by-1 | ||||
|  * using cairo_region_union_rectangle() produces O(N^2) behavior (if the union | ||||
|  * adds or removes rectangles in the middle of the region, then it has to | ||||
|  * move all the rectangles after that.) To avoid this behavior, MetaRegionBuilder | ||||
|  * creates regions for small groups of rectangles and merges them together in | ||||
|  * a binary tree. | ||||
|  * | ||||
|  * Possible improvement: From a glance at the code, accumulating all the rectangles | ||||
|  *  into a flat array and then calling the (not usefully documented) | ||||
|  *  cairo_region_create_rectangles() would have the same behavior and would be | ||||
|  *  simpler and a bit more efficient. | ||||
|  */ | ||||
|  | ||||
| /* Optimium performance seems to be with MAX_CHUNK_RECTANGLES=4; 8 is about 10% slower. | ||||
|  * But using 8 may be more robust to systems with slow malloc(). */ | ||||
| #define MAX_CHUNK_RECTANGLES 8 | ||||
| #define MAX_LEVELS 16 | ||||
|  | ||||
| typedef struct | ||||
| { | ||||
|   /* To merge regions in a binary tree, we need to keep track of The way these are filled is in the pattern: | ||||
|    * | ||||
|    * |a  | | ||||
|    * |b  |a  | | ||||
|    * |c  |   |ab | | ||||
|    * |d  |c  |ab | | ||||
|    * |e  |   |   |abcd| | ||||
|    */ | ||||
|   cairo_region_t *levels[MAX_LEVELS]; | ||||
|   int n_levels; | ||||
| } MetaRegionBuilder; | ||||
|  | ||||
| static void | ||||
| meta_region_builder_init (MetaRegionBuilder *builder) | ||||
| { | ||||
|   int i; | ||||
|   for (i = 0; i < MAX_LEVELS; i++) | ||||
|     builder->levels[i] = NULL; | ||||
|   builder->n_levels = 1; | ||||
| } | ||||
|  | ||||
| static void | ||||
| meta_region_builder_add_rectangle (MetaRegionBuilder *builder, | ||||
|                                    int                x, | ||||
|                                    int                y, | ||||
|                                    int                width, | ||||
|                                    int                height) | ||||
| { | ||||
|   cairo_rectangle_int_t rect; | ||||
|   int i; | ||||
|  | ||||
|   if (builder->levels[0] == NULL) | ||||
|     builder->levels[0] = cairo_region_create (); | ||||
|  | ||||
|   rect.x = x; | ||||
|   rect.y = y; | ||||
|   rect.width = width; | ||||
|   rect.height = height; | ||||
|  | ||||
|   cairo_region_union_rectangle (builder->levels[0], &rect); | ||||
|   if (cairo_region_num_rectangles (builder->levels[0]) >= MAX_CHUNK_RECTANGLES) | ||||
|     { | ||||
|       for (i = 1; i < builder->n_levels + 1; i++) | ||||
|         { | ||||
|           if (builder->levels[i] == NULL) | ||||
|             { | ||||
|               if (i < MAX_LEVELS) | ||||
|                 { | ||||
|                   builder->levels[i] = builder->levels[i - 1]; | ||||
|                   builder->levels[i - 1] = NULL; | ||||
|                   if (i == builder->n_levels) | ||||
|                     builder->n_levels++; | ||||
|                 } | ||||
|  | ||||
|               break; | ||||
|             } | ||||
|           else | ||||
|             { | ||||
|               cairo_region_union (builder->levels[i], builder->levels[i - 1]); | ||||
|               cairo_region_destroy (builder->levels[i - 1]); | ||||
|               builder->levels[i - 1] = NULL; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| static cairo_region_t * | ||||
| meta_region_builder_finish (MetaRegionBuilder *builder) | ||||
| { | ||||
|   cairo_region_t *result = NULL; | ||||
|   int i; | ||||
|  | ||||
|   for (i = 0; i < builder->n_levels; i++) | ||||
|     { | ||||
|       if (builder->levels[i]) | ||||
|         { | ||||
|           if (result == NULL) | ||||
|             result = builder->levels[i]; | ||||
|           else | ||||
|             { | ||||
|               cairo_region_union(result, builder->levels[i]); | ||||
|               cairo_region_destroy (builder->levels[i]); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   if (result == NULL) | ||||
|     result = cairo_region_create (); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* MetaRegionIterator */ | ||||
|  | ||||
| void | ||||
| meta_region_iterator_init (MetaRegionIterator *iter, | ||||
|                            cairo_region_t     *region) | ||||
| { | ||||
|   iter->region = region; | ||||
|   iter->i = 0; | ||||
|   iter->n_rectangles = cairo_region_num_rectangles (region); | ||||
|   iter->line_start = TRUE; | ||||
|  | ||||
|   if (iter->n_rectangles > 1) | ||||
|     { | ||||
|       cairo_region_get_rectangle (region, 0, &iter->rectangle); | ||||
|       cairo_region_get_rectangle (region, 1, &iter->next_rectangle); | ||||
|  | ||||
|       iter->line_end = iter->next_rectangle.y != iter->rectangle.y; | ||||
|     } | ||||
|   else if (iter->n_rectangles > 0) | ||||
|     { | ||||
|       cairo_region_get_rectangle (region, 0, &iter->rectangle); | ||||
|       iter->line_end = TRUE; | ||||
|     } | ||||
| } | ||||
|  | ||||
| gboolean | ||||
| meta_region_iterator_at_end (MetaRegionIterator *iter) | ||||
| { | ||||
|   return iter->i >= iter->n_rectangles; | ||||
| } | ||||
|  | ||||
| void | ||||
| meta_region_iterator_next (MetaRegionIterator *iter) | ||||
| { | ||||
|   iter->i++; | ||||
|   iter->rectangle = iter->next_rectangle; | ||||
|   iter->line_start = iter->line_end; | ||||
|  | ||||
|   if (iter->i < iter->n_rectangles) | ||||
|     { | ||||
|       cairo_region_get_rectangle (iter->region, iter->i + 1, &iter->next_rectangle); | ||||
|       iter->line_end = iter->next_rectangle.y != iter->rectangle.y; | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       iter->line_end = TRUE; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void | ||||
| add_expanded_rect (MetaRegionBuilder  *builder, | ||||
|                    int                 x, | ||||
|                    int                 y, | ||||
|                    int                 width, | ||||
|                    int                 height, | ||||
|                    int                 x_amount, | ||||
|                    int                 y_amount, | ||||
|                    gboolean            flip) | ||||
| { | ||||
|   if (flip) | ||||
|     meta_region_builder_add_rectangle (builder, | ||||
|                                          y - y_amount, x - x_amount, | ||||
|                                          height + 2 * y_amount, width + 2 * x_amount); | ||||
|   else | ||||
|     meta_region_builder_add_rectangle (builder, | ||||
|                                          x - x_amount, y - y_amount, | ||||
|                                          width + 2 * x_amount, height + 2 * y_amount); | ||||
| } | ||||
|  | ||||
| static cairo_region_t * | ||||
| expand_region (cairo_region_t *region, | ||||
|                int             x_amount, | ||||
|                int             y_amount, | ||||
|                gboolean        flip) | ||||
| { | ||||
|   MetaRegionBuilder builder; | ||||
|   int n; | ||||
|   int i; | ||||
|  | ||||
|   meta_region_builder_init (&builder); | ||||
|  | ||||
|   n = cairo_region_num_rectangles (region); | ||||
|   for (i = 0; i < n; i++) | ||||
|     { | ||||
|       cairo_rectangle_int_t rect; | ||||
|  | ||||
|       cairo_region_get_rectangle (region, i, &rect); | ||||
|       add_expanded_rect (&builder, | ||||
|                          rect.x, rect.y, rect.width, rect.height, | ||||
|                          x_amount, y_amount, flip); | ||||
|     } | ||||
|  | ||||
|   return meta_region_builder_finish (&builder); | ||||
| } | ||||
|  | ||||
| /* This computes a (clipped version) of the inverse of the region | ||||
|  * and expands it by the given amount */ | ||||
| static cairo_region_t * | ||||
| expand_region_inverse (cairo_region_t *region, | ||||
|                        int             x_amount, | ||||
|                        int             y_amount, | ||||
|                        gboolean        flip) | ||||
| { | ||||
|   MetaRegionBuilder builder; | ||||
|   MetaRegionIterator iter; | ||||
|   cairo_rectangle_int_t extents; | ||||
|   cairo_region_t *chunk; | ||||
|  | ||||
|   int last_x; | ||||
|  | ||||
|   meta_region_builder_init (&builder); | ||||
|  | ||||
|   cairo_region_get_extents (region, &extents); | ||||
|   add_expanded_rect (&builder, | ||||
|                      extents.x, extents.y - 1, extents.width, 1, | ||||
|                      x_amount, y_amount, flip); | ||||
|   add_expanded_rect (&builder, | ||||
|                      extents.x - 1, extents.y, 1, extents.height, | ||||
|                      x_amount, y_amount, flip); | ||||
|   add_expanded_rect (&builder, | ||||
|                      extents.x + extents.width, extents.y, 1, extents.height, | ||||
|                      x_amount, y_amount, flip); | ||||
|   add_expanded_rect (&builder, | ||||
|                      extents.x, extents.y + extents.height, extents.width, 1, | ||||
|                      x_amount, y_amount, flip); | ||||
|  | ||||
|   chunk = NULL; | ||||
|  | ||||
|   last_x = extents.x; | ||||
|   for (meta_region_iterator_init (&iter, region); | ||||
|        !meta_region_iterator_at_end (&iter); | ||||
|        meta_region_iterator_next (&iter)) | ||||
|     { | ||||
|       if (chunk == NULL) | ||||
|         chunk = cairo_region_create (); | ||||
|  | ||||
|       if (iter.rectangle.x > last_x) | ||||
|         add_expanded_rect (&builder, | ||||
|                            last_x, iter.rectangle.y, | ||||
|                            iter.rectangle.x - last_x, iter.rectangle.height, | ||||
|                            x_amount, y_amount, flip); | ||||
|  | ||||
|       if (iter.line_end) | ||||
|         { | ||||
|           if (extents.x + extents.width > iter.rectangle.x + iter.rectangle.width) | ||||
|             add_expanded_rect (&builder, | ||||
|                                iter.rectangle.x + iter.rectangle.width, iter.rectangle.y, | ||||
|                                (extents.x + extents.width) - (iter.rectangle.x + iter.rectangle.width), iter.rectangle.height, | ||||
|                                x_amount, y_amount, flip); | ||||
|           last_x = extents.x; | ||||
|         } | ||||
|       else | ||||
|         last_x = iter.rectangle.x + iter.rectangle.width; | ||||
|     } | ||||
|  | ||||
|   return meta_region_builder_finish (&builder); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * meta_make_border_region: | ||||
|  * @region: a #cairo_region_t | ||||
|  * @x_amount: distance from the border to extend horizontally | ||||
|  * @y_amount: distance from the border to extend vertically | ||||
|  * @flip: if true, the result is computed with x and y interchanged | ||||
|  * | ||||
|  * Computes the "border region" of a given region, which is roughly | ||||
|  * speaking the set of points near the boundary of the region.  If we | ||||
|  * define the operation of growing a region as computing the set of | ||||
|  * points within a given manhattan distance of the region, then the | ||||
|  * border is 'grow(region) intersect grow(inverse(region))'. | ||||
|  * | ||||
|  * If we create an image by filling the region with a solid color, | ||||
|  * the border is the region affected by blurring the region. | ||||
|  * | ||||
|  * Return value: a new region which is the border of the given region | ||||
|  */ | ||||
| cairo_region_t * | ||||
| meta_make_border_region (cairo_region_t *region, | ||||
|                          int             x_amount, | ||||
|                          int             y_amount, | ||||
|                          gboolean        flip) | ||||
| { | ||||
|   cairo_region_t *border_region; | ||||
|   cairo_region_t *inverse_region; | ||||
|  | ||||
|   border_region = expand_region (region, x_amount, y_amount, flip); | ||||
|   inverse_region = expand_region_inverse (region, x_amount, y_amount, flip); | ||||
|   cairo_region_intersect (border_region, inverse_region); | ||||
|   cairo_region_destroy (inverse_region); | ||||
|  | ||||
|   return border_region; | ||||
| } | ||||
							
								
								
									
										76
									
								
								src/compositor/region-utils.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								src/compositor/region-utils.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ | ||||
| /* | ||||
|  * Utilities for region manipulation | ||||
|  * | ||||
|  * Copyright (C) 2010 Red Hat, Inc. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU General Public License as | ||||
|  * published by the Free Software Foundation; either version 2 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, but | ||||
|  * WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software | ||||
|  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||||
|  * 02111-1307, USA. | ||||
|  */ | ||||
|  | ||||
| #ifndef __META_REGION_UTILS_H__ | ||||
| #define __META_REGION_UTILS_H__ | ||||
|  | ||||
| #include <clutter/clutter.h> | ||||
|  | ||||
| #include <cairo.h> | ||||
| #include <glib.h> | ||||
|  | ||||
| /** | ||||
|  * MetaRegionIterator: | ||||
|  * @region: region being iterated | ||||
|  * @rectangle: current rectangle | ||||
|  * @line_start: whether the current rectangle starts a horizontal band | ||||
|  * @line_end: whether the current rectangle ends a horizontal band | ||||
|  * | ||||
|  * cairo_region_t is a yx banded region; sometimes its useful to iterate through | ||||
|  * such a region treating the start and end of each horizontal band in a distinct | ||||
|  * fashion. | ||||
|  * | ||||
|  * Usage: | ||||
|  * | ||||
|  *  MetaRegionIterator iter; | ||||
|  *  for (meta_region_iterator_init (&iter, region); | ||||
|  *       !meta_region_iterator_at_end (&iter); | ||||
|  *       meta_region_iterator_next (&iter)) | ||||
|  *  { | ||||
|  *    [ Use iter.rectangle, iter.line_start, iter.line_end ] | ||||
|  *  } | ||||
|  */ | ||||
| typedef struct _MetaRegionIterator MetaRegionIterator; | ||||
|  | ||||
| struct _MetaRegionIterator { | ||||
|   cairo_region_t *region; | ||||
|   cairo_rectangle_int_t rectangle; | ||||
|   gboolean line_start; | ||||
|   gboolean line_end; | ||||
|   int i; | ||||
|  | ||||
|   /*< private >*/ | ||||
|   int n_rectangles; | ||||
|   cairo_rectangle_int_t next_rectangle; | ||||
| }; | ||||
|  | ||||
| void     meta_region_iterator_init      (MetaRegionIterator *iter, | ||||
|                                          cairo_region_t     *region); | ||||
| gboolean meta_region_iterator_at_end    (MetaRegionIterator *iter); | ||||
| void     meta_region_iterator_next      (MetaRegionIterator *iter); | ||||
|  | ||||
| cairo_region_t *meta_make_border_region (cairo_region_t *region, | ||||
|                                          int             x_amount, | ||||
|                                          int             y_amount, | ||||
|                                          gboolean        flip); | ||||
|  | ||||
| #endif /* __META_REGION_UTILS_H__ */ | ||||
| @@ -1,350 +0,0 @@ | ||||
| /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ | ||||
|  | ||||
| #define _GNU_SOURCE /* For M_PI */ | ||||
|  | ||||
| #include <math.h> | ||||
|  | ||||
| #include "compositor-private.h" | ||||
| #include "shadow.h" | ||||
| #include "tidy/tidy-texture-frame.h" | ||||
|  | ||||
| #define SHADOW_RADIUS 8 | ||||
| #define SHADOW_OPACITY	0.9 | ||||
| #define SHADOW_OFFSET_X	(SHADOW_RADIUS) | ||||
| #define SHADOW_OFFSET_Y	(SHADOW_RADIUS) | ||||
|  | ||||
| #define MAX_TILE_SZ 8 	/* Must be <= shaddow radius */ | ||||
| #define TILE_WIDTH  (3*MAX_TILE_SZ) | ||||
| #define TILE_HEIGHT (3*MAX_TILE_SZ) | ||||
|  | ||||
| static unsigned char* shadow_gaussian_make_tile (void); | ||||
|  | ||||
| ClutterActor * | ||||
| meta_create_shadow_frame (MetaCompositor *compositor) | ||||
| { | ||||
|   ClutterActor *frame; | ||||
|  | ||||
|   if (!compositor->shadow_src) | ||||
|     { | ||||
|       guchar *data; | ||||
|  | ||||
|       data = shadow_gaussian_make_tile (); | ||||
|  | ||||
|       compositor->shadow_src = clutter_texture_new (); | ||||
|  | ||||
|       clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (compositor->shadow_src), | ||||
|                                          data, | ||||
|                                          TRUE, | ||||
|                                          TILE_WIDTH, | ||||
|                                          TILE_HEIGHT, | ||||
|                                          TILE_WIDTH*4, | ||||
|                                          4, | ||||
|                                          0, | ||||
|                                          NULL); | ||||
|       g_free (data); | ||||
|     } | ||||
|  | ||||
|   frame = tidy_texture_frame_new (CLUTTER_TEXTURE (compositor->shadow_src), | ||||
|                                   MAX_TILE_SZ, | ||||
|                                   MAX_TILE_SZ, | ||||
|                                   MAX_TILE_SZ, | ||||
|                                   MAX_TILE_SZ); | ||||
|  | ||||
|   clutter_actor_set_position (frame, | ||||
|                               SHADOW_OFFSET_X , SHADOW_OFFSET_Y); | ||||
|  | ||||
|   return frame; | ||||
| } | ||||
|  | ||||
| typedef struct GaussianMap | ||||
| { | ||||
|   int	   size; | ||||
|   double * data; | ||||
| } GaussianMap; | ||||
|  | ||||
| static double | ||||
| gaussian (double r, double x, double y) | ||||
| { | ||||
|   return ((1 / (sqrt (2 * M_PI * r))) * | ||||
| 	  exp ((- (x * x + y * y)) / (2 * r * r))); | ||||
| } | ||||
|  | ||||
|  | ||||
| static GaussianMap * | ||||
| make_gaussian_map (double r) | ||||
| { | ||||
|   GaussianMap  *c; | ||||
|   int	          size = ((int) ceil ((r * 3)) + 1) & ~1; | ||||
|   int	          center = size / 2; | ||||
|   int	          x, y; | ||||
|   double          t = 0.0; | ||||
|   double          g; | ||||
|  | ||||
|   c = g_malloc (sizeof (GaussianMap) + size * size * sizeof (double)); | ||||
|   c->size = size; | ||||
|  | ||||
|   c->data = (double *) (c + 1); | ||||
|  | ||||
|   for (y = 0; y < size; y++) | ||||
|     for (x = 0; x < size; x++) | ||||
|       { | ||||
| 	g = gaussian (r, (double) (x - center), (double) (y - center)); | ||||
| 	t += g; | ||||
| 	c->data[y * size + x] = g; | ||||
|       } | ||||
|  | ||||
|   for (y = 0; y < size; y++) | ||||
|     for (x = 0; x < size; x++) | ||||
|       c->data[y*size + x] /= t; | ||||
|  | ||||
|   return c; | ||||
| } | ||||
|  | ||||
| static unsigned char | ||||
| sum_gaussian (GaussianMap * map, double opacity, | ||||
|               int x, int y, int width, int height) | ||||
| { | ||||
|   int	           fx, fy; | ||||
|   double         * g_data; | ||||
|   double         * g_line = map->data; | ||||
|   int	           g_size = map->size; | ||||
|   int	           center = g_size / 2; | ||||
|   int	           fx_start, fx_end; | ||||
|   int	           fy_start, fy_end; | ||||
|   double           v; | ||||
|   unsigned int     r; | ||||
|  | ||||
|   /* | ||||
|    * Compute set of filter values which are "in range", | ||||
|    * that's the set with: | ||||
|    *	0 <= x + (fx-center) && x + (fx-center) < width && | ||||
|    *  0 <= y + (fy-center) && y + (fy-center) < height | ||||
|    * | ||||
|    *  0 <= x + (fx - center)	x + fx - center < width | ||||
|    *  center - x <= fx	fx < width + center - x | ||||
|    */ | ||||
|  | ||||
|   fx_start = center - x; | ||||
|   if (fx_start < 0) | ||||
|     fx_start = 0; | ||||
|   fx_end = width + center - x; | ||||
|   if (fx_end > g_size) | ||||
|     fx_end = g_size; | ||||
|  | ||||
|   fy_start = center - y; | ||||
|   if (fy_start < 0) | ||||
|     fy_start = 0; | ||||
|   fy_end = height + center - y; | ||||
|   if (fy_end > g_size) | ||||
|     fy_end = g_size; | ||||
|  | ||||
|   g_line = g_line + fy_start * g_size + fx_start; | ||||
|  | ||||
|   v = 0; | ||||
|   for (fy = fy_start; fy < fy_end; fy++) | ||||
|     { | ||||
|       g_data = g_line; | ||||
|       g_line += g_size; | ||||
|  | ||||
|       for (fx = fx_start; fx < fx_end; fx++) | ||||
| 	v += *g_data++; | ||||
|     } | ||||
|   if (v > 1) | ||||
|     v = 1; | ||||
|  | ||||
|   v *= (opacity * 255.0); | ||||
|  | ||||
|   r = (unsigned int) v; | ||||
|  | ||||
|   return (unsigned char) r; | ||||
| } | ||||
|  | ||||
| static unsigned char * | ||||
| shadow_gaussian_make_tile () | ||||
| { | ||||
|   unsigned char              * data; | ||||
|   int		               size; | ||||
|   int		               center; | ||||
|   int		               x, y; | ||||
|   unsigned char                d; | ||||
|   int                          pwidth, pheight; | ||||
|   double                       opacity = SHADOW_OPACITY; | ||||
|   static GaussianMap       * gaussian_map = NULL; | ||||
|  | ||||
|   struct _mypixel | ||||
|   { | ||||
|     unsigned char r; | ||||
|     unsigned char g; | ||||
|     unsigned char b; | ||||
|     unsigned char a; | ||||
|   } * _d; | ||||
|  | ||||
|  | ||||
|   if (!gaussian_map) | ||||
|     gaussian_map = | ||||
|       make_gaussian_map (SHADOW_RADIUS); | ||||
|  | ||||
|   size   = gaussian_map->size; | ||||
|   center = size / 2; | ||||
|  | ||||
|   /* Top & bottom */ | ||||
|  | ||||
|   pwidth  = MAX_TILE_SZ; | ||||
|   pheight = MAX_TILE_SZ; | ||||
|  | ||||
|   data = g_malloc0 (4 * TILE_WIDTH * TILE_HEIGHT); | ||||
|  | ||||
|   _d = (struct _mypixel*) data; | ||||
|  | ||||
|   /* N */ | ||||
|   for (y = 0; y < pheight; y++) | ||||
|     { | ||||
|       d = sum_gaussian (gaussian_map, opacity, | ||||
|                         center, y - center, | ||||
|                         TILE_WIDTH, TILE_HEIGHT); | ||||
|       for (x = 0; x < pwidth; x++) | ||||
| 	{ | ||||
| 	  _d[y*3*pwidth + x + pwidth].r = 0; | ||||
| 	  _d[y*3*pwidth + x + pwidth].g = 0; | ||||
| 	  _d[y*3*pwidth + x + pwidth].b = 0; | ||||
| 	  _d[y*3*pwidth + x + pwidth].a = d; | ||||
| 	} | ||||
|  | ||||
|     } | ||||
|  | ||||
|   /* S */ | ||||
|   pwidth = MAX_TILE_SZ; | ||||
|   pheight = MAX_TILE_SZ; | ||||
|  | ||||
|   for (y = 0; y < pheight; y++) | ||||
|     { | ||||
|       d = sum_gaussian (gaussian_map, opacity, | ||||
|                         center, y - center, | ||||
|                         TILE_WIDTH, TILE_HEIGHT); | ||||
|       for (x = 0; x < pwidth; x++) | ||||
| 	{ | ||||
| 	  _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x + pwidth].r = 0; | ||||
| 	  _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x + pwidth].g = 0; | ||||
| 	  _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x + pwidth].b = 0; | ||||
| 	  _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x + pwidth].a = d; | ||||
| 	} | ||||
|  | ||||
|     } | ||||
|  | ||||
|  | ||||
|   /* w */ | ||||
|   pwidth = MAX_TILE_SZ; | ||||
|   pheight = MAX_TILE_SZ; | ||||
|  | ||||
|   for (x = 0; x < pwidth; x++) | ||||
|     { | ||||
|       d = sum_gaussian (gaussian_map, opacity, | ||||
|                         x - center, center, | ||||
|                         TILE_WIDTH, TILE_HEIGHT); | ||||
|       for (y = 0; y < pheight; y++) | ||||
| 	{ | ||||
| 	  _d[y*3*pwidth + 3*pwidth*pheight + x].r = 0; | ||||
| 	  _d[y*3*pwidth + 3*pwidth*pheight + x].g = 0; | ||||
| 	  _d[y*3*pwidth + 3*pwidth*pheight + x].b = 0; | ||||
| 	  _d[y*3*pwidth + 3*pwidth*pheight + x].a = d; | ||||
| 	} | ||||
|  | ||||
|     } | ||||
|  | ||||
|   /* E */ | ||||
|   for (x = 0; x < pwidth; x++) | ||||
|     { | ||||
|       d = sum_gaussian (gaussian_map, opacity, | ||||
| 					       x - center, center, | ||||
| 					       TILE_WIDTH, TILE_HEIGHT); | ||||
|       for (y = 0; y < pheight; y++) | ||||
| 	{ | ||||
| 	  _d[y*3*pwidth + 3*pwidth*pheight + (pwidth-x-1) + 2*pwidth].r = 0; | ||||
| 	  _d[y*3*pwidth + 3*pwidth*pheight + (pwidth-x-1) + 2*pwidth].g = 0; | ||||
| 	  _d[y*3*pwidth + 3*pwidth*pheight + (pwidth-x-1) + 2*pwidth].b = 0; | ||||
| 	  _d[y*3*pwidth + 3*pwidth*pheight + (pwidth-x-1) + 2*pwidth].a = d; | ||||
| 	} | ||||
|  | ||||
|     } | ||||
|  | ||||
|   /* NW */ | ||||
|   pwidth = MAX_TILE_SZ; | ||||
|   pheight = MAX_TILE_SZ; | ||||
|  | ||||
|   for (x = 0; x < pwidth; x++) | ||||
|     for (y = 0; y < pheight; y++) | ||||
|       { | ||||
| 	d = sum_gaussian (gaussian_map, opacity, | ||||
|                           x-center, y-center, | ||||
|                           TILE_WIDTH, TILE_HEIGHT); | ||||
|  | ||||
| 	_d[y*3*pwidth + x].r = 0; | ||||
| 	_d[y*3*pwidth + x].g = 0; | ||||
| 	_d[y*3*pwidth + x].b = 0; | ||||
| 	_d[y*3*pwidth + x].a = d; | ||||
|       } | ||||
|  | ||||
|   /* SW */ | ||||
|   for (x = 0; x < pwidth; x++) | ||||
|     for (y = 0; y < pheight; y++) | ||||
|       { | ||||
| 	d = sum_gaussian (gaussian_map, opacity, | ||||
|                           x-center, y-center, | ||||
|                           TILE_WIDTH, TILE_HEIGHT); | ||||
|  | ||||
| 	_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x].r = 0; | ||||
| 	_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x].g = 0; | ||||
| 	_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x].b = 0; | ||||
| 	_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x].a = d; | ||||
|       } | ||||
|  | ||||
|   /* SE */ | ||||
|   for (x = 0; x < pwidth; x++) | ||||
|     for (y = 0; y < pheight; y++) | ||||
|       { | ||||
| 	d = sum_gaussian (gaussian_map, opacity, | ||||
|                           x-center, y-center, | ||||
|                           TILE_WIDTH, TILE_HEIGHT); | ||||
|  | ||||
| 	_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + (pwidth-x-1) + | ||||
| 	   2*pwidth].r = 0; | ||||
| 	_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + (pwidth-x-1) + | ||||
| 	   2*pwidth].g = 0; | ||||
| 	_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + (pwidth-x-1) + | ||||
| 	   2*pwidth].b = 0; | ||||
| 	_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + (pwidth-x-1) + | ||||
| 	   2*pwidth].a = d; | ||||
|       } | ||||
|  | ||||
|   /* NE */ | ||||
|   for (x = 0; x < pwidth; x++) | ||||
|     for (y = 0; y < pheight; y++) | ||||
|       { | ||||
| 	d = sum_gaussian (gaussian_map, opacity, | ||||
|                           x-center, y-center, | ||||
|                           TILE_WIDTH, TILE_HEIGHT); | ||||
|  | ||||
| 	_d[y*3*pwidth + (pwidth - x - 1) + 2*pwidth].r = 0; | ||||
| 	_d[y*3*pwidth + (pwidth - x - 1) + 2*pwidth].g = 0; | ||||
| 	_d[y*3*pwidth + (pwidth - x - 1) + 2*pwidth].b = 0; | ||||
| 	_d[y*3*pwidth + (pwidth - x - 1) + 2*pwidth].a = d; | ||||
|       } | ||||
|  | ||||
|   /* center */ | ||||
|   pwidth = MAX_TILE_SZ; | ||||
|   pheight = MAX_TILE_SZ; | ||||
|  | ||||
|   d = sum_gaussian (gaussian_map, opacity, | ||||
|                     center, center, TILE_WIDTH, TILE_HEIGHT); | ||||
|  | ||||
|   for (x = 0; x < pwidth; x++) | ||||
|     for (y = 0; y < pheight; y++) | ||||
|       { | ||||
| 	_d[y*3*pwidth + 3*pwidth*pheight + x + pwidth].r = 0; | ||||
| 	_d[y*3*pwidth + 3*pwidth*pheight + x + pwidth].g = 0; | ||||
| 	_d[y*3*pwidth + 3*pwidth*pheight + x + pwidth].b = 0; | ||||
| 	_d[y*3*pwidth + 3*pwidth*pheight + x + pwidth].a = 0; | ||||
|       } | ||||
|  | ||||
|   return data; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| #ifndef SHADOW_H | ||||
| #define SHADOW_H | ||||
|  | ||||
| #include <clutter/clutter.h> | ||||
| #include "compositor.h" | ||||
|  | ||||
| ClutterActor *meta_create_shadow_frame (MetaCompositor *compositor); | ||||
|  | ||||
| #endif /* SHADOW_H */ | ||||
| @@ -1,641 +0,0 @@ | ||||
| /* tidy-texture-frame.h: Expandible texture actor | ||||
|  * | ||||
|  * Copyright (C) 2007 OpenedHand | ||||
|  * | ||||
|  * This library is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU Lesser General Public | ||||
|  * License as published by the Free Software Foundation; either | ||||
|  * version 2 of the License, or (at your option) any later version. | ||||
|  * | ||||
|  * This library is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * Lesser General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public | ||||
|  * License along with this library; if not, write to the | ||||
|  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||||
|  * Boston, MA 02111-1307, USA. | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * SECTION:tidy-texture-frame | ||||
|  * @short_description: Stretch a texture to fit the entire allocation | ||||
|  * | ||||
|  * #TidyTextureFrame | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <cogl/cogl.h> | ||||
|  | ||||
| #include "tidy-texture-frame.h" | ||||
|  | ||||
| #define TIDY_PARAM_READABLE     \ | ||||
|         (G_PARAM_READABLE |     \ | ||||
|          G_PARAM_STATIC_NICK | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB) | ||||
|  | ||||
| #define TIDY_PARAM_READWRITE    \ | ||||
|         (G_PARAM_READABLE | G_PARAM_WRITABLE | \ | ||||
|          G_PARAM_STATIC_NICK | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB) | ||||
|  | ||||
| enum | ||||
| { | ||||
|   PROP_0, | ||||
|  | ||||
|   PROP_PARENT_TEXTURE, | ||||
|  | ||||
|   PROP_LEFT, | ||||
|   PROP_TOP, | ||||
|   PROP_RIGHT, | ||||
|   PROP_BOTTOM | ||||
| }; | ||||
|  | ||||
| G_DEFINE_TYPE (TidyTextureFrame, tidy_texture_frame, CLUTTER_TYPE_ACTOR); | ||||
|  | ||||
| #define TIDY_TEXTURE_FRAME_GET_PRIVATE(obj)     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TIDY_TYPE_TEXTURE_FRAME, TidyTextureFramePrivate)) | ||||
|  | ||||
| struct _TidyTextureFramePrivate | ||||
| { | ||||
|   ClutterTexture *parent_texture; | ||||
|  | ||||
|   gfloat left; | ||||
|   gfloat top; | ||||
|   gfloat right; | ||||
|   gfloat bottom; | ||||
|  | ||||
|   CoglHandle material; | ||||
|  | ||||
|   guint needs_paint : 1; | ||||
| }; | ||||
|  | ||||
| static void | ||||
| tidy_texture_frame_get_preferred_width (ClutterActor *self, | ||||
|                                         gfloat        for_height, | ||||
|                                         gfloat       *min_width_p, | ||||
|                                         gfloat       *natural_width_p) | ||||
| { | ||||
|   TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (self)->priv; | ||||
|  | ||||
|   if (G_UNLIKELY (priv->parent_texture == NULL)) | ||||
|     { | ||||
|       if (min_width_p) | ||||
|         *min_width_p = 0; | ||||
|  | ||||
|       if (natural_width_p) | ||||
|         *natural_width_p = 0; | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       ClutterActorClass *klass; | ||||
|  | ||||
|       /* by directly querying the parent texture's class implementation | ||||
|        * we are going around any override mechanism the parent texture | ||||
|        * might have in place, and we ask directly for the original | ||||
|        * preferred width | ||||
|        */ | ||||
|       klass = CLUTTER_ACTOR_GET_CLASS (priv->parent_texture); | ||||
|       klass->get_preferred_width (CLUTTER_ACTOR (priv->parent_texture), | ||||
|                                   for_height, | ||||
|                                   min_width_p, | ||||
|                                   natural_width_p); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void | ||||
| tidy_texture_frame_get_preferred_height (ClutterActor *self, | ||||
|                                          gfloat        for_width, | ||||
|                                          gfloat       *min_height_p, | ||||
|                                          gfloat       *natural_height_p) | ||||
| { | ||||
|   TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (self)->priv; | ||||
|  | ||||
|   if (G_UNLIKELY (priv->parent_texture == NULL)) | ||||
|     { | ||||
|       if (min_height_p) | ||||
|         *min_height_p = 0; | ||||
|  | ||||
|       if (natural_height_p) | ||||
|         *natural_height_p = 0; | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       ClutterActorClass *klass; | ||||
|  | ||||
|       /* by directly querying the parent texture's class implementation | ||||
|        * we are going around any override mechanism the parent texture | ||||
|        * might have in place, and we ask directly for the original | ||||
|        * preferred height | ||||
|        */ | ||||
|       klass = CLUTTER_ACTOR_GET_CLASS (priv->parent_texture); | ||||
|       klass->get_preferred_height (CLUTTER_ACTOR (priv->parent_texture), | ||||
|                                    for_width, | ||||
|                                    min_height_p, | ||||
|                                    natural_height_p); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void | ||||
| tidy_texture_frame_realize (ClutterActor *self) | ||||
| { | ||||
|   TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (self)->priv; | ||||
|  | ||||
|   if (priv->material != COGL_INVALID_HANDLE) | ||||
|     return; | ||||
|  | ||||
|   priv->material = cogl_material_new (); | ||||
|  | ||||
|   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED); | ||||
| } | ||||
|  | ||||
| static void | ||||
| tidy_texture_frame_unrealize (ClutterActor *self) | ||||
| { | ||||
|   TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (self)->priv; | ||||
|  | ||||
|   if (priv->material == COGL_INVALID_HANDLE) | ||||
|     return; | ||||
|  | ||||
|   cogl_handle_unref (priv->material); | ||||
|   priv->material = COGL_INVALID_HANDLE; | ||||
|  | ||||
|   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED); | ||||
| } | ||||
|  | ||||
| static void | ||||
| tidy_texture_frame_paint (ClutterActor *self) | ||||
| { | ||||
|   TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (self)->priv; | ||||
|   CoglHandle cogl_texture = COGL_INVALID_HANDLE; | ||||
|   ClutterActorBox box = { 0, }; | ||||
|   gfloat width, height; | ||||
|   gfloat tex_width, tex_height; | ||||
|   gfloat ex, ey; | ||||
|   gfloat tx1, ty1, tx2, ty2; | ||||
|   guint8 opacity; | ||||
|  | ||||
|   /* no need to paint stuff if we don't have a texture */ | ||||
|   if (G_UNLIKELY (priv->parent_texture == NULL)) | ||||
|     return; | ||||
|  | ||||
|   if (!priv->needs_paint) | ||||
|     return; | ||||
|  | ||||
|   /* parent texture may have been hidden, so need to make sure it gets | ||||
|    * realized | ||||
|    */ | ||||
|   if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent_texture)) | ||||
|     clutter_actor_realize (CLUTTER_ACTOR (priv->parent_texture)); | ||||
|  | ||||
|   cogl_texture = clutter_texture_get_cogl_texture (priv->parent_texture); | ||||
|   if (cogl_texture == COGL_INVALID_HANDLE) | ||||
|     return; | ||||
|  | ||||
|   tex_width  = cogl_texture_get_width (cogl_texture); | ||||
|   tex_height = cogl_texture_get_height (cogl_texture); | ||||
|  | ||||
|   clutter_actor_get_allocation_box (self, &box); | ||||
|   width = box.x2 - box.x1; | ||||
|   height = box.y2 - box.y1; | ||||
|  | ||||
|   tx1 = priv->left / tex_width; | ||||
|   tx2 = (tex_width - priv->right) / tex_width; | ||||
|   ty1 = priv->top / tex_height; | ||||
|   ty2 = (tex_height - priv->bottom) / tex_height; | ||||
|  | ||||
|   ex = width - priv->right; | ||||
|   if (ex < 0) | ||||
|     ex = priv->right; 		/* FIXME ? */ | ||||
|  | ||||
|   ey = height - priv->bottom; | ||||
|   if (ey < 0) | ||||
|     ey = priv->bottom; 		/* FIXME ? */ | ||||
|  | ||||
|   opacity = clutter_actor_get_paint_opacity (self); | ||||
|  | ||||
|   g_assert (priv->material != COGL_INVALID_HANDLE); | ||||
|  | ||||
|   /* set the source material using the parent texture's COGL handle */ | ||||
|   cogl_material_set_color4ub (priv->material, opacity, opacity, opacity, opacity); | ||||
|   cogl_material_set_layer (priv->material, 0, cogl_texture); | ||||
|   cogl_set_source (priv->material); | ||||
|  | ||||
|   /* top left corner */ | ||||
|   cogl_rectangle_with_texture_coords (0, 0, priv->left, priv->top, | ||||
|                                       0.0, 0.0, | ||||
|                                       tx1, ty1); | ||||
|  | ||||
|   /* top middle */ | ||||
|   cogl_rectangle_with_texture_coords (priv->left, 0, ex, priv->top, | ||||
|                                       tx1, 0.0, | ||||
|                                       tx2, ty1); | ||||
|  | ||||
|   /* top right */ | ||||
|   cogl_rectangle_with_texture_coords (ex, 0, width, priv->top, | ||||
|                                       tx2, 0.0, | ||||
|                                       1.0, ty1); | ||||
|  | ||||
|   /* mid left */ | ||||
|   cogl_rectangle_with_texture_coords (0, priv->top, priv->left, ey, | ||||
|                                       0.0, ty1, | ||||
|                                       tx1, ty2); | ||||
|  | ||||
|   /* center */ | ||||
|   cogl_rectangle_with_texture_coords (priv->left, priv->top, ex, ey, | ||||
|                                       tx1, ty1, | ||||
|                                       tx2, ty2); | ||||
|  | ||||
|   /* mid right */ | ||||
|   cogl_rectangle_with_texture_coords (ex, priv->top, width, ey, | ||||
|                                       tx2, ty1, | ||||
|                                       1.0, ty2); | ||||
|    | ||||
|   /* bottom left */ | ||||
|   cogl_rectangle_with_texture_coords (0, ey, priv->left, height, | ||||
|                                       0.0, ty2, | ||||
|                                       tx1, 1.0); | ||||
|  | ||||
|   /* bottom center */ | ||||
|   cogl_rectangle_with_texture_coords (priv->left, ey, ex, height, | ||||
|                                       tx1, ty2, | ||||
|                                       tx2, 1.0); | ||||
|  | ||||
|   /* bottom right */ | ||||
|   cogl_rectangle_with_texture_coords (ex, ey, width, height, | ||||
|                                       tx2, ty2, | ||||
|                                       1.0, 1.0); | ||||
| } | ||||
|  | ||||
| static inline void | ||||
| tidy_texture_frame_set_frame_internal (TidyTextureFrame *frame, | ||||
|                                        gfloat            left, | ||||
|                                        gfloat            top, | ||||
|                                        gfloat            right, | ||||
|                                        gfloat            bottom) | ||||
| { | ||||
|   TidyTextureFramePrivate *priv = frame->priv; | ||||
|   GObject *gobject = G_OBJECT (frame); | ||||
|   gboolean changed = FALSE; | ||||
|  | ||||
|   g_object_freeze_notify (gobject); | ||||
|  | ||||
|   if (priv->top != top) | ||||
|     { | ||||
|       priv->top = top; | ||||
|       g_object_notify (gobject, "top"); | ||||
|       changed = TRUE; | ||||
|     } | ||||
|  | ||||
|   if (priv->right != right) | ||||
|     { | ||||
|       priv->right = right; | ||||
|       g_object_notify (gobject, "right"); | ||||
|       changed = TRUE; | ||||
|     } | ||||
|  | ||||
|   if (priv->bottom != bottom) | ||||
|     { | ||||
|       priv->bottom = bottom; | ||||
|       g_object_notify (gobject, "bottom"); | ||||
|       changed = TRUE; | ||||
|     } | ||||
|  | ||||
|   if (priv->left != left) | ||||
|     { | ||||
|       priv->left = left; | ||||
|       g_object_notify (gobject, "left"); | ||||
|       changed = TRUE; | ||||
|     } | ||||
|  | ||||
|   if (changed && CLUTTER_ACTOR_IS_VISIBLE (frame)) | ||||
|     clutter_actor_queue_redraw (CLUTTER_ACTOR (frame)); | ||||
|  | ||||
|   g_object_thaw_notify (gobject); | ||||
| } | ||||
|  | ||||
| static void | ||||
| tidy_texture_frame_set_property (GObject      *gobject, | ||||
|                                  guint         prop_id, | ||||
|                                  const GValue *value, | ||||
|                                  GParamSpec   *pspec) | ||||
| { | ||||
|   TidyTextureFrame *frame = TIDY_TEXTURE_FRAME (gobject); | ||||
|   TidyTextureFramePrivate *priv = frame->priv; | ||||
|  | ||||
|   switch (prop_id) | ||||
|     { | ||||
|     case PROP_PARENT_TEXTURE: | ||||
|       tidy_texture_frame_set_parent_texture (frame, | ||||
|                                              g_value_get_object (value)); | ||||
|       break; | ||||
|  | ||||
|     case PROP_TOP: | ||||
|       tidy_texture_frame_set_frame_internal (frame, | ||||
|                                              priv->left, | ||||
|                                              g_value_get_float (value), | ||||
|                                              priv->right, | ||||
|                                              priv->bottom); | ||||
|       break; | ||||
|  | ||||
|     case PROP_RIGHT: | ||||
|       tidy_texture_frame_set_frame_internal (frame, | ||||
|                                              priv->top, | ||||
|                                              g_value_get_float (value), | ||||
|                                              priv->bottom, | ||||
|                                              priv->left); | ||||
|       break; | ||||
|  | ||||
|     case PROP_BOTTOM: | ||||
|       tidy_texture_frame_set_frame_internal (frame, | ||||
|                                              priv->top, | ||||
|                                              priv->right, | ||||
|                                              g_value_get_float (value), | ||||
|                                              priv->left); | ||||
|       break; | ||||
|  | ||||
|     case PROP_LEFT: | ||||
|       tidy_texture_frame_set_frame_internal (frame, | ||||
|                                              priv->top, | ||||
|                                              priv->right, | ||||
|                                              priv->bottom, | ||||
|                                              g_value_get_float (value)); | ||||
|       break; | ||||
|  | ||||
|     default: | ||||
|       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); | ||||
|       break; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void | ||||
| tidy_texture_frame_get_property (GObject    *gobject, | ||||
|                                  guint       prop_id, | ||||
|                                  GValue     *value, | ||||
|                                  GParamSpec *pspec) | ||||
| { | ||||
|   TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (gobject)->priv; | ||||
|  | ||||
|   switch (prop_id) | ||||
|     { | ||||
|     case PROP_PARENT_TEXTURE: | ||||
|       g_value_set_object (value, priv->parent_texture); | ||||
|       break; | ||||
|  | ||||
|     case PROP_LEFT: | ||||
|       g_value_set_float (value, priv->left); | ||||
|       break; | ||||
|  | ||||
|     case PROP_TOP: | ||||
|       g_value_set_float (value, priv->top); | ||||
|       break; | ||||
|  | ||||
|     case PROP_RIGHT: | ||||
|       g_value_set_float (value, priv->right); | ||||
|       break; | ||||
|  | ||||
|     case PROP_BOTTOM: | ||||
|       g_value_set_float (value, priv->bottom); | ||||
|       break; | ||||
|  | ||||
|     default: | ||||
|       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); | ||||
|       break; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void | ||||
| tidy_texture_frame_dispose (GObject *gobject) | ||||
| { | ||||
|   TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (gobject)->priv; | ||||
|  | ||||
|   if (priv->parent_texture) | ||||
|     { | ||||
|       g_object_unref (priv->parent_texture); | ||||
|       priv->parent_texture = NULL; | ||||
|     } | ||||
|  | ||||
|   if (priv->material) | ||||
|     { | ||||
|       cogl_handle_unref (priv->material); | ||||
|       priv->material = COGL_INVALID_HANDLE; | ||||
|     } | ||||
|  | ||||
|   G_OBJECT_CLASS (tidy_texture_frame_parent_class)->dispose (gobject); | ||||
| } | ||||
|  | ||||
| static void | ||||
| tidy_texture_frame_class_init (TidyTextureFrameClass *klass) | ||||
| { | ||||
|   GObjectClass *gobject_class = G_OBJECT_CLASS (klass); | ||||
|   ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); | ||||
|   GParamSpec *pspec; | ||||
|  | ||||
|   g_type_class_add_private (gobject_class, sizeof (TidyTextureFramePrivate)); | ||||
|  | ||||
|   actor_class->get_preferred_width = | ||||
|     tidy_texture_frame_get_preferred_width; | ||||
|   actor_class->get_preferred_height = | ||||
|     tidy_texture_frame_get_preferred_height; | ||||
|   actor_class->realize = tidy_texture_frame_realize; | ||||
|   actor_class->unrealize = tidy_texture_frame_unrealize; | ||||
|   actor_class->paint = tidy_texture_frame_paint; | ||||
|  | ||||
|   gobject_class->set_property = tidy_texture_frame_set_property; | ||||
|   gobject_class->get_property = tidy_texture_frame_get_property; | ||||
|   gobject_class->dispose = tidy_texture_frame_dispose; | ||||
|  | ||||
|   pspec = g_param_spec_object ("parent-texture", | ||||
|                                "Parent Texture", | ||||
|                                "The parent ClutterTexture", | ||||
|                                CLUTTER_TYPE_TEXTURE, | ||||
|                                TIDY_PARAM_READWRITE | | ||||
|                                G_PARAM_CONSTRUCT); | ||||
|   g_object_class_install_property (gobject_class, PROP_PARENT_TEXTURE, pspec); | ||||
|  | ||||
|   pspec = g_param_spec_float ("left", | ||||
|                               "Left", | ||||
|                               "Left offset", | ||||
| 			      0, G_MAXFLOAT, | ||||
|                               0, | ||||
|                               TIDY_PARAM_READWRITE); | ||||
|   g_object_class_install_property (gobject_class, PROP_LEFT, pspec); | ||||
|  | ||||
|   pspec = g_param_spec_float ("top", | ||||
|                               "Top", | ||||
|                               "Top offset", | ||||
|                               0, G_MAXFLOAT, | ||||
|                               0, | ||||
|                               TIDY_PARAM_READWRITE); | ||||
|   g_object_class_install_property (gobject_class, PROP_TOP, pspec); | ||||
|  | ||||
|   pspec = g_param_spec_float ("bottom", | ||||
|                               "Bottom", | ||||
|                               "Bottom offset", | ||||
|                               0, G_MAXFLOAT, | ||||
|                               0, | ||||
|                               TIDY_PARAM_READWRITE); | ||||
|   g_object_class_install_property (gobject_class, PROP_BOTTOM, pspec); | ||||
|  | ||||
|   pspec = g_param_spec_float ("right", | ||||
|                               "Right", | ||||
|                               "Right offset", | ||||
|                               0, G_MAXFLOAT, | ||||
|                               0, | ||||
|                               TIDY_PARAM_READWRITE); | ||||
|   g_object_class_install_property (gobject_class, PROP_RIGHT, pspec); | ||||
| } | ||||
|  | ||||
| static void | ||||
| tidy_texture_frame_init (TidyTextureFrame *self) | ||||
| { | ||||
|   TidyTextureFramePrivate *priv; | ||||
|  | ||||
|   self->priv = priv = TIDY_TEXTURE_FRAME_GET_PRIVATE (self); | ||||
|  | ||||
|   priv->material = COGL_INVALID_HANDLE; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * tidy_texture_frame_new: | ||||
|  * @texture: a #ClutterTexture or %NULL | ||||
|  * @left: left margin preserving its content | ||||
|  * @top: top margin preserving its content | ||||
|  * @right: right margin preserving its content | ||||
|  * @bottom: bottom margin preserving its content | ||||
|  * | ||||
|  * A #TidyTextureFrame is a specialized texture that efficiently clones | ||||
|  * an area of the given @texture while keeping preserving portions of the | ||||
|  * same texture. | ||||
|  * | ||||
|  * A #TidyTextureFrame can be used to make a rectangular texture fit a | ||||
|  * given size without stretching its borders. | ||||
|  * | ||||
|  * Return value: the newly created #TidyTextureFrame | ||||
|  */ | ||||
| ClutterActor* | ||||
| tidy_texture_frame_new (ClutterTexture *texture,  | ||||
| 			gfloat          left, | ||||
| 			gfloat          top, | ||||
| 			gfloat          right, | ||||
| 			gfloat          bottom) | ||||
| { | ||||
|   g_return_val_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture), NULL); | ||||
|  | ||||
|   return g_object_new (TIDY_TYPE_TEXTURE_FRAME, | ||||
|  		       "parent-texture", texture, | ||||
| 		       "left", left, | ||||
| 		       "top", top, | ||||
| 		       "right", right, | ||||
| 		       "bottom", bottom, | ||||
| 		       NULL); | ||||
| } | ||||
|  | ||||
| ClutterTexture * | ||||
| tidy_texture_frame_get_parent_texture (TidyTextureFrame *frame) | ||||
| { | ||||
|   g_return_val_if_fail (TIDY_IS_TEXTURE_FRAME (frame), NULL); | ||||
|  | ||||
|   return frame->priv->parent_texture; | ||||
| } | ||||
|  | ||||
| void | ||||
| tidy_texture_frame_set_parent_texture (TidyTextureFrame *frame, | ||||
|                                        ClutterTexture   *texture) | ||||
| { | ||||
|   TidyTextureFramePrivate *priv; | ||||
|   gboolean was_visible; | ||||
|  | ||||
|   g_return_if_fail (TIDY_IS_TEXTURE_FRAME (frame)); | ||||
|   g_return_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture)); | ||||
|  | ||||
|   priv = frame->priv; | ||||
|  | ||||
|   was_visible = CLUTTER_ACTOR_IS_VISIBLE (frame); | ||||
|  | ||||
|   if (priv->parent_texture == texture) | ||||
|     return; | ||||
|  | ||||
|   if (priv->parent_texture) | ||||
|     { | ||||
|       g_object_unref (priv->parent_texture); | ||||
|       priv->parent_texture = NULL; | ||||
|  | ||||
|       if (was_visible) | ||||
|         clutter_actor_hide (CLUTTER_ACTOR (frame)); | ||||
|     } | ||||
|  | ||||
|   if (texture) | ||||
|     { | ||||
|       priv->parent_texture = g_object_ref (texture); | ||||
|  | ||||
|       if (was_visible && CLUTTER_ACTOR_IS_VISIBLE (priv->parent_texture)) | ||||
|         clutter_actor_show (CLUTTER_ACTOR (frame)); | ||||
|     } | ||||
|  | ||||
|   clutter_actor_queue_relayout (CLUTTER_ACTOR (frame)); | ||||
|  | ||||
|   g_object_notify (G_OBJECT (frame), "parent-texture"); | ||||
| } | ||||
|  | ||||
| void | ||||
| tidy_texture_frame_set_frame (TidyTextureFrame *frame, | ||||
|                               gfloat            top, | ||||
|                               gfloat            right, | ||||
|                               gfloat            bottom, | ||||
|                               gfloat            left) | ||||
| { | ||||
|   g_return_if_fail (TIDY_IS_TEXTURE_FRAME (frame)); | ||||
|  | ||||
|   tidy_texture_frame_set_frame_internal (frame, top, right, bottom, left); | ||||
| } | ||||
|  | ||||
| void | ||||
| tidy_texture_frame_get_frame (TidyTextureFrame *frame, | ||||
|                               gfloat           *top, | ||||
|                               gfloat           *right, | ||||
|                               gfloat           *bottom, | ||||
|                               gfloat           *left) | ||||
| { | ||||
|   TidyTextureFramePrivate *priv; | ||||
|  | ||||
|   g_return_if_fail (TIDY_IS_TEXTURE_FRAME (frame)); | ||||
|  | ||||
|   priv = frame->priv; | ||||
|  | ||||
|   if (top) | ||||
|     *top = priv->top; | ||||
|  | ||||
|   if (right) | ||||
|     *right = priv->right; | ||||
|  | ||||
|   if (bottom) | ||||
|     *bottom = priv->bottom; | ||||
|  | ||||
|   if (left) | ||||
|     *left = priv->left; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * tidy_texture_frame_set_needs_paint: | ||||
|  * @frame: a #TidyTextureframe | ||||
|  * @needs_paint: if %FALSE, the paint will be skipped | ||||
|  * | ||||
|  * Provides a hint to the texture frame that it is totally obscured | ||||
|  * and doesn't need to be painted. This would typically be called | ||||
|  * by a parent container if it detects the condition prior to | ||||
|  * painting its children and then unset afterwards. | ||||
|  * | ||||
|  * Since it is not supposed to have any effect on display, it does | ||||
|  * not queue a repaint. | ||||
|  */ | ||||
| void | ||||
| tidy_texture_frame_set_needs_paint (TidyTextureFrame *frame, | ||||
| 				    gboolean          needs_paint) | ||||
| { | ||||
|   TidyTextureFramePrivate *priv; | ||||
|  | ||||
|   g_return_if_fail (TIDY_IS_TEXTURE_FRAME (frame)); | ||||
|  | ||||
|   priv = frame->priv; | ||||
|  | ||||
|   priv->needs_paint = needs_paint; | ||||
| } | ||||
| @@ -1,84 +0,0 @@ | ||||
| /* tidy-texture-frame.h: Expandible texture actor | ||||
|  * | ||||
|  * Copyright (C) 2007, 2008 OpenedHand Ltd | ||||
|  * Copyright (C) 2009 Intel Corp. | ||||
|  * | ||||
|  * This library is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU Lesser General Public | ||||
|  * License as published by the Free Software Foundation; either | ||||
|  * version 2 of the License, or (at your option) any later version. | ||||
|  * | ||||
|  * This library is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * Lesser General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public | ||||
|  * License along with this library; if not, write to the | ||||
|  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||||
|  * Boston, MA 02111-1307, USA. | ||||
|  */ | ||||
|  | ||||
| #ifndef _HAVE_TIDY_TEXTURE_FRAME_H | ||||
| #define _HAVE_TIDY_TEXTURE_FRAME_H | ||||
|  | ||||
| #include <clutter/clutter.h> | ||||
|  | ||||
| G_BEGIN_DECLS | ||||
|  | ||||
| #define TIDY_TYPE_TEXTURE_FRAME                 (tidy_texture_frame_get_type ()) | ||||
| #define TIDY_TEXTURE_FRAME(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_TEXTURE_FRAME, TidyTextureFrame)) | ||||
| #define TIDY_TEXTURE_FRAME_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), TIDY_TYPE_TEXTURE_FRAME, TidyTextureFrameClass)) | ||||
| #define TIDY_IS_TEXTURE_FRAME(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_TEXTURE_FRAME)) | ||||
| #define TIDY_IS_TEXTURE_FRAME_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), TIDY_TYPE_TEXTURE_FRAME)) | ||||
| #define TIDY_TEXTURE_FRAME_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), TIDY_TYPE_TEXTURE_FRAME, TidyTextureFrameClass)) | ||||
|  | ||||
| typedef struct _TidyTextureFrame                TidyTextureFrame; | ||||
| typedef struct _TidyTextureFramePrivate         TidyTextureFramePrivate; | ||||
| typedef struct _TidyTextureFrameClass           TidyTextureFrameClass; | ||||
|  | ||||
| struct _TidyTextureFrame | ||||
| { | ||||
|   /*< private >*/ | ||||
|   ClutterActor parent_instance; | ||||
|    | ||||
|   TidyTextureFramePrivate    *priv; | ||||
| }; | ||||
|  | ||||
| struct _TidyTextureFrameClass | ||||
| { | ||||
|   ClutterActorClass parent_class; | ||||
|  | ||||
|   /* padding for future expansion */ | ||||
|   void (*_clutter_box_1) (void); | ||||
|   void (*_clutter_box_2) (void); | ||||
|   void (*_clutter_box_3) (void); | ||||
|   void (*_clutter_box_4) (void); | ||||
| }; | ||||
|  | ||||
| GType           tidy_texture_frame_get_type           (void) G_GNUC_CONST; | ||||
| ClutterActor *  tidy_texture_frame_new                (ClutterTexture   *texture, | ||||
|                                                        gfloat            top, | ||||
|                                                        gfloat            right, | ||||
|                                                        gfloat            bottom, | ||||
|                                                        gfloat            left); | ||||
| void            tidy_texture_frame_set_parent_texture (TidyTextureFrame *frame, | ||||
|                                                        ClutterTexture   *texture); | ||||
| ClutterTexture *tidy_texture_frame_get_parent_texture (TidyTextureFrame *frame); | ||||
| void            tidy_texture_frame_set_frame          (TidyTextureFrame *frame, | ||||
|                                                        gfloat            top, | ||||
|                                                        gfloat            right, | ||||
|                                                        gfloat            bottom, | ||||
|                                                        gfloat            left); | ||||
| void            tidy_texture_frame_get_frame          (TidyTextureFrame *frame, | ||||
|                                                        gfloat           *top, | ||||
|                                                        gfloat           *right, | ||||
|                                                        gfloat           *bottom, | ||||
|                                                        gfloat           *left); | ||||
|  | ||||
| void            tidy_texture_frame_set_needs_paint    (TidyTextureFrame *frame, | ||||
|                                                        gboolean          needs_paint); | ||||
|  | ||||
| G_END_DECLS | ||||
|  | ||||
| #endif /* _HAVE_TIDY_TEXTURE_FRAME_H */ | ||||
| @@ -117,65 +117,8 @@ meta_core_get (Display *xdisplay, | ||||
|         *((MetaFrameFlags*)answer) = meta_frame_get_flags (window->frame); | ||||
|         break;  | ||||
|       case META_CORE_GET_FRAME_TYPE: | ||||
|           { | ||||
|           MetaFrameType base_type = META_FRAME_TYPE_LAST; | ||||
|  | ||||
|           switch (window->type) | ||||
|             { | ||||
|             case META_WINDOW_NORMAL: | ||||
|               base_type = META_FRAME_TYPE_NORMAL; | ||||
|               break; | ||||
|  | ||||
|             case META_WINDOW_DIALOG: | ||||
|               base_type = META_FRAME_TYPE_DIALOG; | ||||
|               break; | ||||
|  | ||||
|             case META_WINDOW_MODAL_DIALOG: | ||||
|               base_type = META_FRAME_TYPE_MODAL_DIALOG; | ||||
|               break; | ||||
|  | ||||
|             case META_WINDOW_MENU: | ||||
|               base_type = META_FRAME_TYPE_MENU; | ||||
|               break; | ||||
|  | ||||
|             case META_WINDOW_UTILITY: | ||||
|               base_type = META_FRAME_TYPE_UTILITY; | ||||
|               break; | ||||
|  | ||||
|             case META_WINDOW_DESKTOP: | ||||
|             case META_WINDOW_DOCK: | ||||
|             case META_WINDOW_TOOLBAR: | ||||
|             case META_WINDOW_SPLASHSCREEN: | ||||
| 	    case META_WINDOW_DROPDOWN_MENU: | ||||
| 	    case META_WINDOW_POPUP_MENU: | ||||
| 	    case META_WINDOW_TOOLTIP: | ||||
| 	    case META_WINDOW_NOTIFICATION: | ||||
| 	    case META_WINDOW_COMBO: | ||||
| 	    case META_WINDOW_DND: | ||||
| 	    case META_WINDOW_OVERRIDE_OTHER: | ||||
|               /* No frame */ | ||||
|               base_type = META_FRAME_TYPE_LAST; | ||||
|               break; | ||||
|  | ||||
|             } | ||||
|  | ||||
|           if (base_type == META_FRAME_TYPE_LAST) | ||||
|             { | ||||
|               /* can't add border if undecorated */ | ||||
|               *((MetaFrameType*)answer) = META_FRAME_TYPE_LAST;  | ||||
|             } | ||||
|           else if (window->border_only) | ||||
|             { | ||||
|               /* override base frame type */ | ||||
|               *((MetaFrameType*)answer) = META_FRAME_TYPE_BORDER;  | ||||
|             } | ||||
|           else | ||||
|             { | ||||
|               *((MetaFrameType*)answer) = base_type; | ||||
|             } | ||||
|  | ||||
|           break;  | ||||
|           } | ||||
|         *((MetaFrameType*)answer) = meta_window_get_frame_type (window); | ||||
|         break; | ||||
|       case META_CORE_GET_MINI_ICON: | ||||
|         *((GdkPixbuf**)answer) = window->mini_icon; | ||||
|         break; | ||||
|   | ||||
| @@ -461,8 +461,6 @@ void        meta_window_update_fullscreen_monitors (MetaWindow    *window, | ||||
|                                                     unsigned long  left, | ||||
|                                                     unsigned long  right); | ||||
|  | ||||
| gboolean meta_window_appears_focused (MetaWindow *window); | ||||
|  | ||||
| /* args to move are window pos, not frame pos */ | ||||
| void        meta_window_move               (MetaWindow  *window, | ||||
|                                             gboolean     user_op, | ||||
|   | ||||
| @@ -3158,6 +3158,32 @@ meta_window_maximize (MetaWindow        *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; | ||||
| } | ||||
|  | ||||
| static void | ||||
| meta_window_tile (MetaWindow *window) | ||||
| { | ||||
| @@ -9275,9 +9301,22 @@ transient_has_focus (MetaWindow *window, | ||||
|   return FALSE; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * meta_window_appears_focused: | ||||
|  * @window: a #MetaWindow | ||||
|  * | ||||
|  * Determines if the window should be drawn with a focused appearance. This is | ||||
|  * true for focused windows but also true for windows with a focused modal | ||||
|  * dialog attached. | ||||
|  * | ||||
|  * Return value: %TRUE if the window should be drawn with a focused frame | ||||
|  */ | ||||
| gboolean | ||||
| meta_window_appears_focused (MetaWindow *window) | ||||
| { | ||||
|   /* FIXME: meta_window_foreach_transient() iterates over all windows; we | ||||
|    *  should eat the complexity to cache a bit for this. | ||||
|    */ | ||||
|   if (!window->has_focus && meta_prefs_get_attach_modal_dialogs ()) | ||||
|     { | ||||
|       gboolean focus = FALSE; | ||||
| @@ -9655,3 +9694,74 @@ meta_window_get_mutter_hints (MetaWindow *window) | ||||
|  | ||||
|   return window->mutter_hints; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * meta_window_get_frame_type: | ||||
|  * @window: a #MetaWindow | ||||
|  * | ||||
|  * Gets the type of window decorations that should be used for this window. | ||||
|  * | ||||
|  * Return value: the frame type | ||||
|  */ | ||||
| MetaFrameType | ||||
| meta_window_get_frame_type (MetaWindow *window) | ||||
| { | ||||
|   MetaFrameType base_type = META_FRAME_TYPE_LAST; | ||||
|  | ||||
|   switch (window->type) | ||||
|     { | ||||
|     case META_WINDOW_NORMAL: | ||||
|       base_type = META_FRAME_TYPE_NORMAL; | ||||
|       break; | ||||
|  | ||||
|     case META_WINDOW_DIALOG: | ||||
|       base_type = META_FRAME_TYPE_DIALOG; | ||||
|       break; | ||||
|  | ||||
|     case META_WINDOW_MODAL_DIALOG: | ||||
|       if (meta_prefs_get_attach_modal_dialogs () && | ||||
|           meta_window_get_transient_for (window) != NULL) | ||||
|         base_type = META_FRAME_TYPE_ATTACHED; | ||||
|       else | ||||
|         base_type = META_FRAME_TYPE_MODAL_DIALOG; | ||||
|       break; | ||||
|  | ||||
|     case META_WINDOW_MENU: | ||||
|       base_type = META_FRAME_TYPE_MENU; | ||||
|       break; | ||||
|  | ||||
|     case META_WINDOW_UTILITY: | ||||
|       base_type = META_FRAME_TYPE_UTILITY; | ||||
|       break; | ||||
|  | ||||
|     case META_WINDOW_DESKTOP: | ||||
|     case META_WINDOW_DOCK: | ||||
|     case META_WINDOW_TOOLBAR: | ||||
|     case META_WINDOW_SPLASHSCREEN: | ||||
|     case META_WINDOW_DROPDOWN_MENU: | ||||
|     case META_WINDOW_POPUP_MENU: | ||||
|     case META_WINDOW_TOOLTIP: | ||||
|     case META_WINDOW_NOTIFICATION: | ||||
|     case META_WINDOW_COMBO: | ||||
|     case META_WINDOW_DND: | ||||
|     case META_WINDOW_OVERRIDE_OTHER: | ||||
|       /* No frame */ | ||||
|       base_type = META_FRAME_TYPE_LAST; | ||||
|       break; | ||||
|     } | ||||
|  | ||||
|   if (base_type == META_FRAME_TYPE_LAST) | ||||
|     { | ||||
|       /* can't add border if undecorated */ | ||||
|       return META_FRAME_TYPE_LAST; | ||||
|     } | ||||
|   else if (window->border_only && base_type != META_FRAME_TYPE_ATTACHED) | ||||
|     { | ||||
|       /* override base frame type */ | ||||
|       return META_FRAME_TYPE_BORDER; | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       return base_type; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -195,6 +195,7 @@ typedef enum | ||||
|   META_FRAME_TYPE_UTILITY, | ||||
|   META_FRAME_TYPE_MENU, | ||||
|   META_FRAME_TYPE_BORDER, | ||||
|   META_FRAME_TYPE_ATTACHED, | ||||
|   META_FRAME_TYPE_LAST | ||||
| } MetaFrameType; | ||||
|  | ||||
|   | ||||
							
								
								
									
										86
									
								
								src/include/meta-shadow-factory.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								src/include/meta-shadow-factory.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ | ||||
| /* | ||||
|  * MetaShadowFactory: | ||||
|  * | ||||
|  * Create and cache shadow textures for arbitrary window shapes | ||||
|  * | ||||
|  * Copyright (C) 2010 Red Hat, Inc. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU General Public License as | ||||
|  * published by the Free Software Foundation; either version 2 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, but | ||||
|  * WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software | ||||
|  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||||
|  * 02111-1307, USA. | ||||
|  */ | ||||
|  | ||||
| #ifndef __META_SHADOW_FACTORY_H__ | ||||
| #define __META_SHADOW_FACTORY_H__ | ||||
|  | ||||
| #include <glib-object.h> | ||||
|  | ||||
| /** | ||||
|  * MetaShadowParams: | ||||
|  * The #MetaShadowParams structure holds information about how to draw | ||||
|  * a particular style of shadow. | ||||
|  * @radius: the radius (gaussian standard deviation) of the shadow | ||||
|  * @top_fade: if >= 0, the shadow doesn't extend above the top | ||||
|  *  of the shape, and fades out over the given number of pixels | ||||
|  * @x_offset: horizontal offset of the shadow with respect to the | ||||
|  *  shape being shadowed, in pixels | ||||
|  * @y_offset: vertical offset of the shadow with respect to the | ||||
|  *  shape being shadowed, in pixels | ||||
|  * @opacity: opacity of the shadow, from 0 to 255 | ||||
|  */ | ||||
|  | ||||
| typedef struct _MetaShadowParams MetaShadowParams; | ||||
|  | ||||
| struct _MetaShadowParams | ||||
| { | ||||
|   int radius; | ||||
|   int top_fade; | ||||
|   int x_offset; | ||||
|   int y_offset; | ||||
|   guint8 opacity; | ||||
| }; | ||||
|  | ||||
| #define META_TYPE_SHADOW_FACTORY            (meta_shadow_factory_get_type ()) | ||||
| #define META_SHADOW_FACTORY(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SHADOW_FACTORY, MetaShadowFactory)) | ||||
| #define META_SHADOW_FACTORY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  META_TYPE_SHADOW_FACTORY, MetaShadowFactoryClass)) | ||||
| #define META_IS_SHADOW_FACTORY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_SHADOW_FACTORY)) | ||||
| #define META_IS_SHADOW_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  META_TYPE_SHADOW_FACTORY)) | ||||
| #define META_SHADOW_FACTORY_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  META_TYPE_SHADOW_FACTORY, MetaShadowFactoryClass)) | ||||
|  | ||||
| /** | ||||
|  * MetaShadowFactory: | ||||
|  * #MetaShadowFactory is used to create window shadows. It caches shadows internally | ||||
|  * so that multiple shadows created for the same shape with the same radius will | ||||
|  * share the same MetaShadow. | ||||
|  */ | ||||
| typedef struct _MetaShadowFactory      MetaShadowFactory; | ||||
| typedef struct _MetaShadowFactoryClass MetaShadowFactoryClass; | ||||
|  | ||||
| MetaShadowFactory *meta_shadow_factory_get_default (void); | ||||
|  | ||||
| GType meta_shadow_factory_get_type (void); | ||||
|  | ||||
| MetaShadowFactory *meta_shadow_factory_new        (void); | ||||
|  | ||||
| void meta_shadow_factory_set_params (MetaShadowFactory *factory, | ||||
|                                      const char        *class_name, | ||||
|                                      gboolean           focused, | ||||
|                                      MetaShadowParams  *params); | ||||
| void meta_shadow_factory_get_params (MetaShadowFactory *factory, | ||||
|                                      const char        *class_name, | ||||
|                                      gboolean           focused, | ||||
|                                      MetaShadowParams  *params); | ||||
|  | ||||
| #endif /* __META_SHADOW_FACTORY_H__ */ | ||||
| @@ -28,6 +28,8 @@ | ||||
| #include <glib.h> | ||||
| #include <glib-object.h> | ||||
|  | ||||
| #include "common.h" | ||||
|  | ||||
| gboolean meta_is_verbose  (void); | ||||
| void     meta_set_verbose (gboolean setting); | ||||
| gboolean meta_is_debugging (void); | ||||
| @@ -91,6 +93,7 @@ guint meta_unsigned_long_hash  (gconstpointer v); | ||||
|  | ||||
| void meta_print_backtrace (void); | ||||
|  | ||||
| const char* meta_frame_type_to_string (MetaFrameType type); | ||||
| const char* meta_gravity_to_string (int gravity); | ||||
|  | ||||
| #include <libintl.h> | ||||
|   | ||||
| @@ -69,6 +69,7 @@ GType meta_window_get_type (void); | ||||
|  | ||||
| MetaFrame *meta_window_get_frame (MetaWindow *window); | ||||
| gboolean meta_window_has_focus (MetaWindow *window); | ||||
| gboolean meta_window_appears_focused (MetaWindow *window); | ||||
| gboolean meta_window_is_shaded (MetaWindow *window); | ||||
| gboolean meta_window_is_override_redirect (MetaWindow *window); | ||||
| gboolean meta_window_is_skip_taskbar (MetaWindow *window); | ||||
| @@ -119,6 +120,9 @@ void     meta_window_foreach_ancestor         (MetaWindow            *window, | ||||
|                                                MetaWindowForeachFunc  func, | ||||
|                                                void                  *user_data); | ||||
|  | ||||
| MetaMaximizeFlags meta_window_get_maximized (MetaWindow *window); | ||||
| gboolean          meta_window_is_fullscreen (MetaWindow *window); | ||||
|  | ||||
| gboolean meta_window_is_mapped (MetaWindow  *window); | ||||
| gboolean meta_window_toplevel_is_mapped (MetaWindow  *window); | ||||
| gboolean meta_window_get_icon_geometry (MetaWindow    *window, | ||||
| @@ -143,4 +147,7 @@ const char *meta_window_get_client_machine (MetaWindow *window); | ||||
| gboolean    meta_window_is_remote (MetaWindow *window); | ||||
| gboolean    meta_window_is_modal (MetaWindow *window); | ||||
| const char *meta_window_get_mutter_hints (MetaWindow *window); | ||||
|  | ||||
| MetaFrameType meta_window_get_frame_type (MetaWindow *window); | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -38,7 +38,7 @@ | ||||
|  * look out for. | ||||
|  */ | ||||
| #define THEME_MAJOR_VERSION 3 | ||||
| #define THEME_MINOR_VERSION 1 | ||||
| #define THEME_MINOR_VERSION 2 | ||||
| #define THEME_VERSION (1000 * THEME_MAJOR_VERSION + THEME_MINOR_VERSION) | ||||
|  | ||||
| #define METACITY_THEME_FILENAME_FORMAT "metacity-theme-%d.xml" | ||||
| @@ -1257,7 +1257,8 @@ parse_toplevel_element (GMarkupParseContext  *context, | ||||
|  | ||||
|       type = meta_frame_type_from_string (type_name); | ||||
|  | ||||
|       if (type == META_FRAME_TYPE_LAST) | ||||
|       if (type == META_FRAME_TYPE_LAST || | ||||
|           (type == META_FRAME_TYPE_ATTACHED && peek_required_version (info) < 3002)) | ||||
|         { | ||||
|           set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, | ||||
|                      _("Unknown type \"%s\" on <%s> element"), | ||||
|   | ||||
| @@ -1189,7 +1189,6 @@ const char*           meta_frame_resize_to_string      (MetaFrameResize        r | ||||
| MetaFrameFocus        meta_frame_focus_from_string     (const char            *str); | ||||
| const char*           meta_frame_focus_to_string       (MetaFrameFocus         focus); | ||||
| MetaFrameType         meta_frame_type_from_string      (const char            *str); | ||||
| const char*           meta_frame_type_to_string        (MetaFrameType          type); | ||||
| MetaGradientType      meta_gradient_type_from_string   (const char            *str); | ||||
| const char*           meta_gradient_type_to_string     (MetaGradientType       type); | ||||
| GtkStateType          meta_gtk_state_from_string       (const char            *str); | ||||
|   | ||||
| @@ -407,6 +407,10 @@ get_window_contents (MetaFrameType  type, | ||||
|     case META_FRAME_TYPE_BORDER: | ||||
|       *title = _("Border"); | ||||
|       return border_only_contents (); | ||||
|  | ||||
|     case META_FRAME_TYPE_ATTACHED: | ||||
|       *title = _("Attached Modal Dialog"); | ||||
|       return dialog_contents (); | ||||
|        | ||||
|     case META_FRAME_TYPE_LAST: | ||||
|       g_assert_not_reached (); | ||||
| @@ -454,6 +458,9 @@ get_window_flags (MetaFrameType type) | ||||
|  | ||||
|     case META_FRAME_TYPE_BORDER: | ||||
|       break; | ||||
|  | ||||
|     case META_FRAME_TYPE_ATTACHED: | ||||
|       break; | ||||
|        | ||||
|     case META_FRAME_TYPE_LAST: | ||||
|       g_assert_not_reached (); | ||||
|   | ||||
| @@ -4992,7 +4992,7 @@ meta_theme_validate (MetaTheme *theme, | ||||
|     } | ||||
|  | ||||
|   for (i = 0; i < (int)META_FRAME_TYPE_LAST; i++) | ||||
|     if (theme->style_sets_by_type[i] == NULL) | ||||
|     if (i != (int)META_FRAME_TYPE_ATTACHED && theme->style_sets_by_type[i] == NULL) | ||||
|       { | ||||
|         g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED, | ||||
|                      _("No frame style set for window type \"%s\" in theme \"%s\", add a <window type=\"%s\" style_set=\"whatever\"/> element"), | ||||
| @@ -5074,7 +5074,10 @@ theme_get_style (MetaTheme     *theme, | ||||
|  | ||||
|   style_set = theme->style_sets_by_type[type]; | ||||
|  | ||||
|   /* Right now the parser forces a style set for all types, | ||||
|   if (style_set == NULL && type == META_FRAME_TYPE_ATTACHED) | ||||
|     style_set = theme->style_sets_by_type[META_FRAME_TYPE_BORDER]; | ||||
|  | ||||
|   /* Right now the parser forces a style set for all other types, | ||||
|    * but this fallback code is here in case I take that out. | ||||
|    */ | ||||
|   if (style_set == NULL) | ||||
| @@ -6004,6 +6007,8 @@ meta_frame_type_from_string (const char *str) | ||||
|     return META_FRAME_TYPE_MENU; | ||||
|   else if (strcmp ("border", str) == 0) | ||||
|     return META_FRAME_TYPE_BORDER; | ||||
|   else if (strcmp ("attached", str) == 0) | ||||
|     return META_FRAME_TYPE_ATTACHED; | ||||
| #if 0 | ||||
|   else if (strcmp ("toolbar", str) == 0) | ||||
|     return META_FRAME_TYPE_TOOLBAR; | ||||
| @@ -6012,6 +6017,14 @@ meta_frame_type_from_string (const char *str) | ||||
|     return META_FRAME_TYPE_LAST; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * meta_frame_type_to_string: | ||||
|  * | ||||
|  * Converts a frame type enum value to the name string that would | ||||
|  * appear in the theme definition file. | ||||
|  * | ||||
|  * Return value: the string value | ||||
|  */ | ||||
| const char* | ||||
| meta_frame_type_to_string (MetaFrameType type) | ||||
| { | ||||
| @@ -6029,6 +6042,8 @@ meta_frame_type_to_string (MetaFrameType type) | ||||
|       return "menu"; | ||||
|     case META_FRAME_TYPE_BORDER: | ||||
|       return "border"; | ||||
|     case META_FRAME_TYPE_ATTACHED: | ||||
|       return "attached"; | ||||
| #if 0 | ||||
|     case META_FRAME_TYPE_TOOLBAR: | ||||
|       return "toolbar"; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user