Compare commits
	
		
			37 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					63e31af476 | ||
| 
						 | 
					718a89eb2f | ||
| 
						 | 
					a43ca7b5b1 | ||
| 
						 | 
					af00ca534a | ||
| 
						 | 
					4b2b431700 | ||
| 
						 | 
					2c1a6b6a12 | ||
| 
						 | 
					b3544f8ec1 | ||
| 
						 | 
					df384965c3 | ||
| 
						 | 
					700d367937 | ||
| 
						 | 
					7c5989c978 | ||
| 
						 | 
					8819d9ce66 | ||
| 
						 | 
					b63413e5b0 | ||
| 
						 | 
					cd1e1d4bf1 | ||
| 
						 | 
					9710c013c5 | ||
| 
						 | 
					05f8d79323 | ||
| 
						 | 
					f2546dfeea | ||
| 
						 | 
					47e339b46e | ||
| 
						 | 
					016b8f5b4a | ||
| 
						 | 
					b3821c4f90 | ||
| 
						 | 
					29e5c6c363 | ||
| 
						 | 
					e1704acda4 | ||
| 
						 | 
					60cbb41f42 | ||
| 
						 | 
					d88c8d9ced | ||
| 
						 | 
					60ab11ecbf | ||
| 
						 | 
					34516aeab6 | ||
| 
						 | 
					a37f632b1b | ||
| 
						 | 
					8a6542c242 | ||
| 
						 | 
					7e12000d97 | ||
| 
						 | 
					23f086da8a | ||
| 
						 | 
					4c2c1c4dd2 | ||
| 
						 | 
					545f298921 | ||
| 
						 | 
					64295e8cd7 | ||
| 
						 | 
					722d4c6c17 | ||
| 
						 | 
					cc8462969d | ||
| 
						 | 
					989bb6ebb1 | ||
| 
						 | 
					1dbda68839 | ||
| 
						 | 
					a460f88b31 | 
							
								
								
									
										14
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								NEWS
									
									
									
									
									
								
							@@ -1,12 +1,14 @@
 | 
			
		||||
3.14.1.5
 | 
			
		||||
========
 | 
			
		||||
3.15.1
 | 
			
		||||
======
 | 
			
		||||
* Use GResources for theme loading [Cosimo; #736936]
 | 
			
		||||
* Fix headerbar drag getting stuck on xwayland [Carlos; #738411]
 | 
			
		||||
* Fix wayland hiDPI regressions [Adel; #739161]
 | 
			
		||||
* Misc bug fixes and cleanups [Jasper, Rui, Carlos; #662962, #738630, #738888,
 | 
			
		||||
  #738890]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Adel Gadllah, Florian Müllner, Jasper St. Pierre
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Dušan Kazik [sk]
 | 
			
		||||
  Cosimo Cecchi, Adel Gadllah, Carlos Garnacho, Rui Matos, Florian Müllner,
 | 
			
		||||
  Jasper St. Pierre
 | 
			
		||||
 | 
			
		||||
3.14.1
 | 
			
		||||
======
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
AC_PREREQ(2.62)
 | 
			
		||||
 | 
			
		||||
m4_define([mutter_major_version], [3])
 | 
			
		||||
m4_define([mutter_minor_version], [14])
 | 
			
		||||
m4_define([mutter_micro_version], [1.5])
 | 
			
		||||
m4_define([mutter_minor_version], [15])
 | 
			
		||||
m4_define([mutter_micro_version], [1])
 | 
			
		||||
 | 
			
		||||
m4_define([mutter_version],
 | 
			
		||||
          [mutter_major_version.mutter_minor_version.mutter_micro_version])
 | 
			
		||||
@@ -78,7 +78,6 @@ MUTTER_PC_MODULES="
 | 
			
		||||
   gsettings-desktop-schemas >= 3.7.3
 | 
			
		||||
   $CLUTTER_PACKAGE >= 1.19.5
 | 
			
		||||
   cogl-1.0 >= 1.17.1
 | 
			
		||||
   gbm >= 10.3
 | 
			
		||||
   upower-glib >= 0.99.0
 | 
			
		||||
   gnome-desktop-3.0
 | 
			
		||||
   xcomposite >= 0.2
 | 
			
		||||
@@ -201,7 +200,7 @@ AC_SUBST(XWAYLAND_PATH)
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES)
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_MODULES(MUTTER_NATIVE_BACKEND, [clutter-egl-1.0 libdrm libsystemd libinput], [have_native_backend=yes], [have_native_backend=no])
 | 
			
		||||
PKG_CHECK_MODULES(MUTTER_NATIVE_BACKEND, [clutter-egl-1.0 libdrm libsystemd libinput gudev-1.0 gbm >= 10.3], [have_native_backend=yes], [have_native_backend=no])
 | 
			
		||||
if test $have_native_backend = yes; then
 | 
			
		||||
   AC_DEFINE([HAVE_NATIVE_BACKEND],[1],[Define if you want to enable the native (KMS) backend based on systemd])
 | 
			
		||||
fi
 | 
			
		||||
 
 | 
			
		||||
@@ -259,8 +259,6 @@ Overview of Theme Format Version 1
 | 
			
		||||
    <!-- color obtained by a 0.5 alpha composite of the second color onto the first -->
 | 
			
		||||
    <color value="blend/gtk:bg[SELECTED]/gtk:fg[SELECTED]/0.5"/>
 | 
			
		||||
  </gradient>
 | 
			
		||||
  <!-- image has an optional colorize="#color" attribute to give the
 | 
			
		||||
       image a certain color -->
 | 
			
		||||
  <image filename="foo.png" alpha="0.7"
 | 
			
		||||
         x="10" y="30" width="width / 3" height="height / 4"/>
 | 
			
		||||
  <gtk_arrow state="normal" shadow="in" arrow="up"
 | 
			
		||||
 
 | 
			
		||||
@@ -41,11 +41,9 @@ endif
 | 
			
		||||
# Some random test programs for bits of the code
 | 
			
		||||
 | 
			
		||||
testboxes_SOURCES = core/testboxes.c
 | 
			
		||||
testgradient_SOURCES = ui/testgradient.c
 | 
			
		||||
testasyncgetprop_SOURCES = x11/testasyncgetprop.c
 | 
			
		||||
 | 
			
		||||
noinst_PROGRAMS+=testboxes testgradient testasyncgetprop
 | 
			
		||||
noinst_PROGRAMS+=testboxes testasyncgetprop
 | 
			
		||||
 | 
			
		||||
testboxes_LDADD = $(MUTTER_LIBS) libmutter.la
 | 
			
		||||
testgradient_LDADD = $(MUTTER_LIBS) libmutter.la
 | 
			
		||||
testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter.la
 | 
			
		||||
 
 | 
			
		||||
@@ -162,8 +162,6 @@ libmutter_la_SOURCES =				\
 | 
			
		||||
	meta/errors.h				\
 | 
			
		||||
	core/frame.c				\
 | 
			
		||||
	core/frame.h				\
 | 
			
		||||
	ui/gradient.c				\
 | 
			
		||||
	meta/gradient.h				\
 | 
			
		||||
	core/meta-gesture-tracker.c		\
 | 
			
		||||
	core/meta-gesture-tracker-private.h	\
 | 
			
		||||
	core/keybindings.c			\
 | 
			
		||||
@@ -290,7 +288,6 @@ libmutterinclude_headers =			\
 | 
			
		||||
	meta/compositor.h			\
 | 
			
		||||
	meta/display.h				\
 | 
			
		||||
	meta/errors.h				\
 | 
			
		||||
	meta/gradient.h				\
 | 
			
		||||
	meta/group.h				\
 | 
			
		||||
	meta/keybindings.h			\
 | 
			
		||||
	meta/main.h				\
 | 
			
		||||
 
 | 
			
		||||
@@ -29,8 +29,11 @@
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  CoglTexture2D *texture;
 | 
			
		||||
  struct gbm_bo *bo;
 | 
			
		||||
  int hot_x, hot_y;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
  struct gbm_bo *bo;
 | 
			
		||||
#endif
 | 
			
		||||
} MetaCursorImage;
 | 
			
		||||
 | 
			
		||||
struct _MetaCursorReference {
 | 
			
		||||
@@ -44,8 +47,10 @@ CoglTexture *meta_cursor_reference_get_cogl_texture (MetaCursorReference *cursor
 | 
			
		||||
                                                     int                 *hot_x,
 | 
			
		||||
                                                     int                 *hot_y);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
struct gbm_bo *meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
 | 
			
		||||
                                                 int                 *hot_x,
 | 
			
		||||
                                                 int                 *hot_y);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* META_CURSOR_PRIVATE_H */
 | 
			
		||||
 
 | 
			
		||||
@@ -56,8 +56,11 @@ static void
 | 
			
		||||
meta_cursor_image_free (MetaCursorImage *image)
 | 
			
		||||
{
 | 
			
		||||
  cogl_object_unref (image->texture);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
  if (image->bo)
 | 
			
		||||
    gbm_bo_destroy (image->bo);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -139,10 +142,10 @@ load_cursor_on_client (MetaCursor cursor)
 | 
			
		||||
                                  meta_prefs_get_cursor_size ());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
static void
 | 
			
		||||
get_hardware_cursor_size (uint64_t *cursor_width, uint64_t *cursor_height)
 | 
			
		||||
{
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
  MetaBackend *meta_backend = meta_get_backend ();
 | 
			
		||||
  MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (meta_backend);
 | 
			
		||||
 | 
			
		||||
@@ -151,11 +154,12 @@ get_hardware_cursor_size (uint64_t *cursor_width, uint64_t *cursor_height)
 | 
			
		||||
      meta_cursor_renderer_native_get_cursor_size (META_CURSOR_RENDERER_NATIVE (renderer), cursor_width, cursor_height);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  g_assert_not_reached ();
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
static void
 | 
			
		||||
meta_cursor_image_load_gbm_buffer (struct gbm_device *gbm,
 | 
			
		||||
                                   MetaCursorImage   *image,
 | 
			
		||||
@@ -193,20 +197,21 @@ meta_cursor_image_load_gbm_buffer (struct gbm_device *gbm,
 | 
			
		||||
  else
 | 
			
		||||
    meta_warning ("HW cursor for format %d not supported\n", gbm_format);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
static struct gbm_device *
 | 
			
		||||
get_gbm_device (void)
 | 
			
		||||
{
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
  MetaBackend *meta_backend = meta_get_backend ();
 | 
			
		||||
  MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (meta_backend);
 | 
			
		||||
 | 
			
		||||
  if (META_IS_CURSOR_RENDERER_NATIVE (renderer))
 | 
			
		||||
    return meta_cursor_renderer_native_get_gbm_device (META_CURSOR_RENDERER_NATIVE (renderer));
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  return NULL;
 | 
			
		||||
  else
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_cursor_image_load_from_xcursor_image (MetaCursorImage   *image,
 | 
			
		||||
@@ -214,16 +219,13 @@ meta_cursor_image_load_from_xcursor_image (MetaCursorImage   *image,
 | 
			
		||||
{
 | 
			
		||||
  uint width, height, rowstride;
 | 
			
		||||
  CoglPixelFormat cogl_format;
 | 
			
		||||
  uint32_t gbm_format;
 | 
			
		||||
  ClutterBackend *clutter_backend;
 | 
			
		||||
  CoglContext *cogl_context;
 | 
			
		||||
  struct gbm_device *gbm;
 | 
			
		||||
 | 
			
		||||
  width           = xc_image->width;
 | 
			
		||||
  height          = xc_image->height;
 | 
			
		||||
  rowstride       = width * 4;
 | 
			
		||||
 | 
			
		||||
  gbm_format = GBM_FORMAT_ARGB8888;
 | 
			
		||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
 | 
			
		||||
  cogl_format = COGL_PIXEL_FORMAT_BGRA_8888;
 | 
			
		||||
#else
 | 
			
		||||
@@ -242,13 +244,15 @@ meta_cursor_image_load_from_xcursor_image (MetaCursorImage   *image,
 | 
			
		||||
                                                  (uint8_t *) xc_image->pixels,
 | 
			
		||||
                                                  NULL);
 | 
			
		||||
 | 
			
		||||
  gbm = get_gbm_device ();
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
  struct gbm_device *gbm = get_gbm_device ();
 | 
			
		||||
  if (gbm)
 | 
			
		||||
    meta_cursor_image_load_gbm_buffer (gbm,
 | 
			
		||||
                                       image,
 | 
			
		||||
                                       (uint8_t *) xc_image->pixels,
 | 
			
		||||
                                       width, height, rowstride,
 | 
			
		||||
                                       gbm_format);
 | 
			
		||||
                                       GBM_FORMAT_ARGB8888);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaCursorReference *
 | 
			
		||||
@@ -277,14 +281,8 @@ meta_cursor_image_load_from_buffer (MetaCursorImage    *image,
 | 
			
		||||
                                    int                 hot_x,
 | 
			
		||||
                                    int                 hot_y)
 | 
			
		||||
{
 | 
			
		||||
  struct gbm_device *gbm = get_gbm_device ();
 | 
			
		||||
 | 
			
		||||
  ClutterBackend *backend;
 | 
			
		||||
  CoglContext *cogl_context;
 | 
			
		||||
  struct wl_shm_buffer *shm_buffer;
 | 
			
		||||
  uint32_t gbm_format;
 | 
			
		||||
  uint64_t cursor_width, cursor_height;
 | 
			
		||||
  uint width, height;
 | 
			
		||||
 | 
			
		||||
  image->hot_x = hot_x;
 | 
			
		||||
  image->hot_y = hot_y;
 | 
			
		||||
@@ -294,13 +292,19 @@ meta_cursor_image_load_from_buffer (MetaCursorImage    *image,
 | 
			
		||||
 | 
			
		||||
  image->texture = cogl_wayland_texture_2d_new_from_buffer (cogl_context, buffer, NULL);
 | 
			
		||||
 | 
			
		||||
  width = cogl_texture_get_width (COGL_TEXTURE (image->texture));
 | 
			
		||||
  height = cogl_texture_get_height (COGL_TEXTURE (image->texture));
 | 
			
		||||
 | 
			
		||||
  shm_buffer = wl_shm_buffer_get (buffer);
 | 
			
		||||
  if (shm_buffer)
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
  struct gbm_device *gbm = get_gbm_device ();
 | 
			
		||||
  if (gbm)
 | 
			
		||||
    {
 | 
			
		||||
      if (gbm)
 | 
			
		||||
      uint32_t gbm_format;
 | 
			
		||||
      uint64_t cursor_width, cursor_height;
 | 
			
		||||
      uint width, height;
 | 
			
		||||
 | 
			
		||||
      width = cogl_texture_get_width (COGL_TEXTURE (image->texture));
 | 
			
		||||
      height = cogl_texture_get_height (COGL_TEXTURE (image->texture));
 | 
			
		||||
 | 
			
		||||
      struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (buffer);
 | 
			
		||||
      if (shm_buffer)
 | 
			
		||||
        {
 | 
			
		||||
          int rowstride = wl_shm_buffer_get_stride (shm_buffer);
 | 
			
		||||
 | 
			
		||||
@@ -332,10 +336,7 @@ meta_cursor_image_load_from_buffer (MetaCursorImage    *image,
 | 
			
		||||
                                             width, height, rowstride,
 | 
			
		||||
                                             gbm_format);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      if (gbm)
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          /* HW cursors have a predefined size (at least 64x64), which usually is bigger than cursor theme
 | 
			
		||||
             size, so themed cursors must be padded with transparent pixels to fill the
 | 
			
		||||
@@ -356,6 +357,7 @@ meta_cursor_image_load_from_buffer (MetaCursorImage    *image,
 | 
			
		||||
            meta_warning ("Importing HW cursor from wl_buffer failed\n");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaCursorReference *
 | 
			
		||||
@@ -385,6 +387,7 @@ meta_cursor_reference_get_cogl_texture (MetaCursorReference *cursor,
 | 
			
		||||
  return COGL_TEXTURE (cursor->image.texture);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
struct gbm_bo *
 | 
			
		||||
meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
 | 
			
		||||
                                  int                 *hot_x,
 | 
			
		||||
@@ -396,6 +399,7 @@ meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
 | 
			
		||||
    *hot_y = cursor->image.hot_y;
 | 
			
		||||
  return cursor->image.bo;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
MetaCursor
 | 
			
		||||
meta_cursor_reference_get_meta_cursor (MetaCursorReference *cursor)
 | 
			
		||||
 
 | 
			
		||||
@@ -67,6 +67,7 @@ typedef struct {
 | 
			
		||||
} MetaOutputConfig;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  guint refcount;
 | 
			
		||||
  MetaOutputKey *keys;
 | 
			
		||||
  MetaOutputConfig *outputs;
 | 
			
		||||
  unsigned int n_outputs;
 | 
			
		||||
@@ -77,7 +78,6 @@ struct _MetaMonitorConfig {
 | 
			
		||||
 | 
			
		||||
  GHashTable *configs;
 | 
			
		||||
  MetaConfiguration *current;
 | 
			
		||||
  gboolean current_is_stored;
 | 
			
		||||
  gboolean current_is_for_laptop_lid;
 | 
			
		||||
  MetaConfiguration *previous;
 | 
			
		||||
 | 
			
		||||
@@ -124,11 +124,29 @@ config_clear (MetaConfiguration *config)
 | 
			
		||||
  g_free (config->outputs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
config_free (gpointer config)
 | 
			
		||||
static MetaConfiguration *
 | 
			
		||||
config_ref (MetaConfiguration *config)
 | 
			
		||||
{
 | 
			
		||||
  config_clear (config);
 | 
			
		||||
  g_slice_free (MetaConfiguration, config);
 | 
			
		||||
  config->refcount++;
 | 
			
		||||
  return config;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
config_unref (MetaConfiguration *config)
 | 
			
		||||
{
 | 
			
		||||
  if (--config->refcount == 0)
 | 
			
		||||
    {
 | 
			
		||||
      config_clear (config);
 | 
			
		||||
      g_slice_free (MetaConfiguration, config);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaConfiguration *
 | 
			
		||||
config_new (void)
 | 
			
		||||
{
 | 
			
		||||
  MetaConfiguration *config = g_slice_new0 (MetaConfiguration);
 | 
			
		||||
  config->refcount = 1;
 | 
			
		||||
  return config;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned long
 | 
			
		||||
@@ -220,7 +238,7 @@ meta_monitor_config_init (MetaMonitorConfig *self)
 | 
			
		||||
  const char *filename;
 | 
			
		||||
  char *path;
 | 
			
		||||
 | 
			
		||||
  self->configs = g_hash_table_new_full (config_hash, config_equal, NULL, config_free);
 | 
			
		||||
  self->configs = g_hash_table_new_full (config_hash, config_equal, NULL, (GDestroyNotify) config_unref);
 | 
			
		||||
 | 
			
		||||
  filename = g_getenv ("MUTTER_MONITOR_FILENAME");
 | 
			
		||||
  if (filename == NULL)
 | 
			
		||||
@@ -796,27 +814,6 @@ make_config_key (MetaConfiguration *key,
 | 
			
		||||
  key->n_outputs = o;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_monitor_config_match_current (MetaMonitorConfig  *self,
 | 
			
		||||
                                   MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
  MetaOutput *outputs;
 | 
			
		||||
  unsigned n_outputs;
 | 
			
		||||
  MetaConfiguration key;
 | 
			
		||||
  gboolean ok;
 | 
			
		||||
 | 
			
		||||
  if (self->current == NULL)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  outputs = meta_monitor_manager_get_outputs (manager, &n_outputs);
 | 
			
		||||
 | 
			
		||||
  make_config_key (&key, outputs, n_outputs, -1);
 | 
			
		||||
  ok = config_equal (&key, self->current);
 | 
			
		||||
 | 
			
		||||
  config_clear (&key);
 | 
			
		||||
  return ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
@@ -851,73 +848,45 @@ meta_monitor_config_get_stored (MetaMonitorConfig *self,
 | 
			
		||||
  return stored;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
set_current (MetaMonitorConfig *self,
 | 
			
		||||
             MetaConfiguration *config)
 | 
			
		||||
{
 | 
			
		||||
  g_clear_pointer (&self->previous, (GDestroyNotify) config_unref);
 | 
			
		||||
  self->previous = self->current;
 | 
			
		||||
  self->current = config_ref (config);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
apply_configuration (MetaMonitorConfig  *self,
 | 
			
		||||
                     MetaConfiguration  *config,
 | 
			
		||||
		     MetaMonitorManager *manager,
 | 
			
		||||
                     gboolean            stored)
 | 
			
		||||
		     MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
  GPtrArray *crtcs, *outputs;
 | 
			
		||||
  gboolean ret = FALSE;
 | 
			
		||||
 | 
			
		||||
  crtcs = g_ptr_array_new_full (config->n_outputs, (GDestroyNotify)meta_crtc_info_free);
 | 
			
		||||
  outputs = g_ptr_array_new_full (config->n_outputs, (GDestroyNotify)meta_output_info_free);
 | 
			
		||||
 | 
			
		||||
  if (!meta_monitor_config_assign_crtcs (config, manager, crtcs, outputs))
 | 
			
		||||
    {
 | 
			
		||||
      g_ptr_array_unref (crtcs);
 | 
			
		||||
      g_ptr_array_unref (outputs);
 | 
			
		||||
      if (!stored)
 | 
			
		||||
        config_free (config);
 | 
			
		||||
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
    goto out;
 | 
			
		||||
 | 
			
		||||
  meta_monitor_manager_apply_configuration (manager,
 | 
			
		||||
                                            (MetaCRTCInfo**)crtcs->pdata, crtcs->len,
 | 
			
		||||
                                            (MetaOutputInfo**)outputs->pdata, outputs->len);
 | 
			
		||||
 | 
			
		||||
  /* Stored (persistent) configurations override the previous one always.
 | 
			
		||||
     Also, we clear the previous configuration if the current one (which is
 | 
			
		||||
     about to become previous) is stored, or if the current one has
 | 
			
		||||
     different outputs.
 | 
			
		||||
  */
 | 
			
		||||
  if (stored ||
 | 
			
		||||
      (self->current && self->current_is_stored))
 | 
			
		||||
    {
 | 
			
		||||
      if (self->previous)
 | 
			
		||||
        config_free (self->previous);
 | 
			
		||||
      self->previous = NULL;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      /* Despite the name, config_equal() only checks the set of outputs,
 | 
			
		||||
         not their modes
 | 
			
		||||
      */
 | 
			
		||||
      if (self->current && config_equal (self->current, config))
 | 
			
		||||
        {
 | 
			
		||||
          self->previous = self->current;
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          if (self->current)
 | 
			
		||||
            config_free (self->current);
 | 
			
		||||
          self->previous = NULL;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  set_current (self, config);
 | 
			
		||||
 | 
			
		||||
  self->current = config;
 | 
			
		||||
  self->current_is_stored = stored;
 | 
			
		||||
  /* If true, we'll be overridden at the end of this call
 | 
			
		||||
     inside turn_off_laptop_display()
 | 
			
		||||
  */
 | 
			
		||||
   * inside turn_off_laptop_display / apply_configuration_with_lid */
 | 
			
		||||
  self->current_is_for_laptop_lid = FALSE;
 | 
			
		||||
 | 
			
		||||
  if (self->current == self->previous)
 | 
			
		||||
    self->previous = NULL;
 | 
			
		||||
  ret = TRUE;
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
  g_ptr_array_unref (crtcs);
 | 
			
		||||
  g_ptr_array_unref (outputs);
 | 
			
		||||
  return TRUE;
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
@@ -956,7 +925,7 @@ make_laptop_lid_config (MetaConfiguration  *reference)
 | 
			
		||||
 | 
			
		||||
  g_assert (reference->n_outputs > 1);
 | 
			
		||||
 | 
			
		||||
  new = g_slice_new0 (MetaConfiguration);
 | 
			
		||||
  new = config_new ();
 | 
			
		||||
  new->n_outputs = reference->n_outputs;
 | 
			
		||||
  new->keys = g_new0 (MetaOutputKey, reference->n_outputs);
 | 
			
		||||
  new->outputs = g_new0 (MetaOutputConfig, reference->n_outputs);
 | 
			
		||||
@@ -1011,6 +980,32 @@ make_laptop_lid_config (MetaConfiguration  *reference)
 | 
			
		||||
  return new;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
apply_configuration_with_lid (MetaMonitorConfig  *self,
 | 
			
		||||
                              MetaConfiguration  *config,
 | 
			
		||||
                              MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
  if (self->lid_is_closed &&
 | 
			
		||||
      config->n_outputs > 1 &&
 | 
			
		||||
      laptop_display_is_on (config))
 | 
			
		||||
    {
 | 
			
		||||
      MetaConfiguration *laptop_lid_config = make_laptop_lid_config (config);
 | 
			
		||||
      if (apply_configuration (self, laptop_lid_config, manager))
 | 
			
		||||
        {
 | 
			
		||||
          self->current_is_for_laptop_lid = TRUE;
 | 
			
		||||
          config_unref (laptop_lid_config);
 | 
			
		||||
          return TRUE;
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          config_unref (laptop_lid_config);
 | 
			
		||||
          return FALSE;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    return apply_configuration (self, config, manager);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_monitor_config_apply_stored (MetaMonitorConfig  *self,
 | 
			
		||||
				  MetaMonitorManager *manager)
 | 
			
		||||
@@ -1023,23 +1018,7 @@ meta_monitor_config_apply_stored (MetaMonitorConfig  *self,
 | 
			
		||||
  stored = meta_monitor_config_get_stored (self, outputs, n_outputs);
 | 
			
		||||
 | 
			
		||||
  if (stored)
 | 
			
		||||
    {
 | 
			
		||||
      if (self->lid_is_closed &&
 | 
			
		||||
          stored->n_outputs > 1 &&
 | 
			
		||||
          laptop_display_is_on (stored))
 | 
			
		||||
        {
 | 
			
		||||
          if (apply_configuration (self, make_laptop_lid_config (stored),
 | 
			
		||||
                                   manager, FALSE))
 | 
			
		||||
            {
 | 
			
		||||
              self->current_is_for_laptop_lid = TRUE;
 | 
			
		||||
              return TRUE;
 | 
			
		||||
            }
 | 
			
		||||
          else
 | 
			
		||||
            return FALSE;
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        return apply_configuration (self, stored, manager, TRUE);
 | 
			
		||||
    }
 | 
			
		||||
    return apply_configuration_with_lid (self, stored, manager);
 | 
			
		||||
  else
 | 
			
		||||
    return FALSE;
 | 
			
		||||
}
 | 
			
		||||
@@ -1101,7 +1080,7 @@ make_default_config (MetaMonitorConfig *self,
 | 
			
		||||
  MetaConfiguration *ret;
 | 
			
		||||
  MetaOutput *primary;
 | 
			
		||||
 | 
			
		||||
  ret = g_slice_new (MetaConfiguration);
 | 
			
		||||
  ret = config_new ();
 | 
			
		||||
  make_config_key (ret, outputs, n_outputs, -1);
 | 
			
		||||
  ret->outputs = g_new0 (MetaOutputConfig, n_outputs);
 | 
			
		||||
 | 
			
		||||
@@ -1221,7 +1200,7 @@ ensure_at_least_one_output (MetaMonitorConfig  *self,
 | 
			
		||||
                            MetaOutput         *outputs,
 | 
			
		||||
                            unsigned            n_outputs)
 | 
			
		||||
{
 | 
			
		||||
  MetaConfiguration *ret;
 | 
			
		||||
  MetaConfiguration *config;
 | 
			
		||||
  MetaOutput *primary;
 | 
			
		||||
  unsigned i;
 | 
			
		||||
 | 
			
		||||
@@ -1232,9 +1211,9 @@ ensure_at_least_one_output (MetaMonitorConfig  *self,
 | 
			
		||||
 | 
			
		||||
  /* Oh no, we don't! Activate the primary one and disable everything else */
 | 
			
		||||
 | 
			
		||||
  ret = g_slice_new (MetaConfiguration);
 | 
			
		||||
  make_config_key (ret, outputs, n_outputs, -1);
 | 
			
		||||
  ret->outputs = g_new0 (MetaOutputConfig, n_outputs);
 | 
			
		||||
  config = config_new ();
 | 
			
		||||
  make_config_key (config, outputs, n_outputs, -1);
 | 
			
		||||
  config->outputs = g_new0 (MetaOutputConfig, n_outputs);
 | 
			
		||||
 | 
			
		||||
  primary = find_primary_output (outputs, n_outputs);
 | 
			
		||||
 | 
			
		||||
@@ -1244,22 +1223,23 @@ ensure_at_least_one_output (MetaMonitorConfig  *self,
 | 
			
		||||
 | 
			
		||||
      if (output == primary)
 | 
			
		||||
        {
 | 
			
		||||
          ret->outputs[i].enabled = TRUE;
 | 
			
		||||
          ret->outputs[i].rect.x = 0;
 | 
			
		||||
          ret->outputs[i].rect.y = 0;
 | 
			
		||||
          ret->outputs[i].rect.width = output->preferred_mode->width;
 | 
			
		||||
          ret->outputs[i].rect.height = output->preferred_mode->height;
 | 
			
		||||
          ret->outputs[i].refresh_rate = output->preferred_mode->refresh_rate;
 | 
			
		||||
          ret->outputs[i].transform = META_MONITOR_TRANSFORM_NORMAL;
 | 
			
		||||
          ret->outputs[i].is_primary = TRUE;
 | 
			
		||||
          config->outputs[i].enabled = TRUE;
 | 
			
		||||
          config->outputs[i].rect.x = 0;
 | 
			
		||||
          config->outputs[i].rect.y = 0;
 | 
			
		||||
          config->outputs[i].rect.width = output->preferred_mode->width;
 | 
			
		||||
          config->outputs[i].rect.height = output->preferred_mode->height;
 | 
			
		||||
          config->outputs[i].refresh_rate = output->preferred_mode->refresh_rate;
 | 
			
		||||
          config->outputs[i].transform = META_MONITOR_TRANSFORM_NORMAL;
 | 
			
		||||
          config->outputs[i].is_primary = TRUE;
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          ret->outputs[i].enabled = FALSE;
 | 
			
		||||
          config->outputs[i].enabled = FALSE;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  apply_configuration (self, ret, manager, FALSE);
 | 
			
		||||
  apply_configuration (self, config, manager);
 | 
			
		||||
  config_unref (config);
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1270,7 +1250,7 @@ meta_monitor_config_make_default (MetaMonitorConfig  *self,
 | 
			
		||||
  MetaOutput *outputs;
 | 
			
		||||
  MetaConfiguration *default_config;
 | 
			
		||||
  unsigned n_outputs;
 | 
			
		||||
  gboolean ok;
 | 
			
		||||
  gboolean ok = FALSE;
 | 
			
		||||
  int max_width, max_height;
 | 
			
		||||
 | 
			
		||||
  outputs = meta_monitor_manager_get_outputs (manager, &n_outputs);
 | 
			
		||||
@@ -1283,22 +1263,11 @@ meta_monitor_config_make_default (MetaMonitorConfig  *self,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  default_config = make_default_config (self, outputs, n_outputs, max_width, max_height);
 | 
			
		||||
 | 
			
		||||
  if (default_config != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      if (self->lid_is_closed &&
 | 
			
		||||
          default_config->n_outputs > 1 &&
 | 
			
		||||
          laptop_display_is_on (default_config))
 | 
			
		||||
        {
 | 
			
		||||
          ok = apply_configuration (self, make_laptop_lid_config (default_config),
 | 
			
		||||
                                    manager, FALSE);
 | 
			
		||||
          config_free (default_config);
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        ok = apply_configuration (self, default_config, manager, FALSE);
 | 
			
		||||
      ok = apply_configuration_with_lid (self, default_config, manager);
 | 
			
		||||
      config_unref (default_config);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    ok = FALSE;
 | 
			
		||||
 | 
			
		||||
  if (!ok)
 | 
			
		||||
    {
 | 
			
		||||
@@ -1335,7 +1304,7 @@ meta_monitor_config_update_current (MetaMonitorConfig  *self,
 | 
			
		||||
 | 
			
		||||
  outputs = meta_monitor_manager_get_outputs (manager, &n_outputs);
 | 
			
		||||
 | 
			
		||||
  current = g_slice_new (MetaConfiguration);
 | 
			
		||||
  current = config_new ();
 | 
			
		||||
  current->n_outputs = n_outputs;
 | 
			
		||||
  current->outputs = g_new0 (MetaOutputConfig, n_outputs);
 | 
			
		||||
  current->keys = g_new0 (MetaOutputKey, n_outputs);
 | 
			
		||||
@@ -1348,15 +1317,11 @@ meta_monitor_config_update_current (MetaMonitorConfig  *self,
 | 
			
		||||
 | 
			
		||||
  if (self->current && config_equal_full (current, self->current))
 | 
			
		||||
    {
 | 
			
		||||
      config_free (current);
 | 
			
		||||
      config_unref (current);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (self->current && !self->current_is_stored)
 | 
			
		||||
    config_free (self->current);
 | 
			
		||||
 | 
			
		||||
  self->current = current;
 | 
			
		||||
  self->current_is_stored = FALSE;
 | 
			
		||||
  set_current (self, current);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -1364,7 +1329,17 @@ meta_monitor_config_restore_previous (MetaMonitorConfig  *self,
 | 
			
		||||
                                      MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
  if (self->previous)
 | 
			
		||||
    apply_configuration (self, self->previous, manager, FALSE);
 | 
			
		||||
    {
 | 
			
		||||
      /* The user chose to restore the previous configuration. In this
 | 
			
		||||
       * case, restore the previous configuration. */
 | 
			
		||||
      MetaConfiguration *prev_config = config_ref (self->previous);
 | 
			
		||||
      apply_configuration (self, prev_config, manager);
 | 
			
		||||
      config_unref (prev_config);
 | 
			
		||||
 | 
			
		||||
      /* After this, self->previous contains the rejected configuration.
 | 
			
		||||
       * Since it was rejected, nuke it. */
 | 
			
		||||
      g_clear_pointer (&self->previous, (GDestroyNotify) config_unref);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      if (!meta_monitor_config_apply_stored (self, manager))
 | 
			
		||||
@@ -1382,7 +1357,8 @@ turn_off_laptop_display (MetaMonitorConfig  *self,
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  new = make_laptop_lid_config (self->current);
 | 
			
		||||
  apply_configuration (self, new, manager, FALSE);
 | 
			
		||||
  apply_configuration (self, new, manager);
 | 
			
		||||
  config_unref (new);
 | 
			
		||||
  self->current_is_for_laptop_lid = TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1541,16 +1517,7 @@ meta_monitor_config_save (MetaMonitorConfig *self)
 | 
			
		||||
void
 | 
			
		||||
meta_monitor_config_make_persistent (MetaMonitorConfig *self)
 | 
			
		||||
{
 | 
			
		||||
  if (self->current_is_stored)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  self->current_is_stored = TRUE;
 | 
			
		||||
  g_hash_table_replace (self->configs, self->current, self->current);
 | 
			
		||||
 | 
			
		||||
  if (self->previous)
 | 
			
		||||
    config_free (self->previous);
 | 
			
		||||
  self->previous = NULL;
 | 
			
		||||
 | 
			
		||||
  g_hash_table_replace (self->configs, self->current, config_ref (self->current));
 | 
			
		||||
  meta_monitor_config_save (self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -36,9 +36,6 @@ GType meta_monitor_config_get_type (void) G_GNUC_CONST;
 | 
			
		||||
 | 
			
		||||
MetaMonitorConfig *meta_monitor_config_new (void);
 | 
			
		||||
 | 
			
		||||
gboolean           meta_monitor_config_match_current (MetaMonitorConfig  *config,
 | 
			
		||||
                                                      MetaMonitorManager *manager);
 | 
			
		||||
 | 
			
		||||
gboolean           meta_monitor_config_apply_stored (MetaMonitorConfig  *config,
 | 
			
		||||
                                                     MetaMonitorManager *manager);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -58,14 +58,6 @@ meta_monitor_manager_init (MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
read_current_config (MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
  manager->serial++;
 | 
			
		||||
 | 
			
		||||
  META_MONITOR_MANAGER_GET_CLASS (manager)->read_current (manager);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * make_logical_config:
 | 
			
		||||
 *
 | 
			
		||||
@@ -198,7 +190,7 @@ meta_monitor_manager_constructed (GObject *object)
 | 
			
		||||
 | 
			
		||||
  manager->config = meta_monitor_config_new ();
 | 
			
		||||
 | 
			
		||||
  read_current_config (manager);
 | 
			
		||||
  meta_monitor_manager_read_current_config (manager);
 | 
			
		||||
 | 
			
		||||
  if (!meta_monitor_config_apply_stored (manager->config, manager))
 | 
			
		||||
    meta_monitor_config_make_default (manager->config, manager);
 | 
			
		||||
@@ -211,24 +203,7 @@ meta_monitor_manager_constructed (GObject *object)
 | 
			
		||||
     so this is not needed.
 | 
			
		||||
  */
 | 
			
		||||
  if (META_IS_MONITOR_MANAGER_XRANDR (manager))
 | 
			
		||||
    {
 | 
			
		||||
      MetaOutput *old_outputs;
 | 
			
		||||
      MetaCRTC *old_crtcs;
 | 
			
		||||
      MetaMonitorMode *old_modes;
 | 
			
		||||
      unsigned int n_old_outputs, n_old_modes;
 | 
			
		||||
 | 
			
		||||
      old_outputs = manager->outputs;
 | 
			
		||||
      n_old_outputs = manager->n_outputs;
 | 
			
		||||
      old_modes = manager->modes;
 | 
			
		||||
      n_old_modes = manager->n_modes;
 | 
			
		||||
      old_crtcs = manager->crtcs;
 | 
			
		||||
 | 
			
		||||
      read_current_config (manager);
 | 
			
		||||
 | 
			
		||||
      meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
 | 
			
		||||
      meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
 | 
			
		||||
      g_free (old_crtcs);
 | 
			
		||||
    }
 | 
			
		||||
    meta_monitor_manager_read_current_config (manager);
 | 
			
		||||
 | 
			
		||||
  make_logical_config (manager);
 | 
			
		||||
  initialize_dbus_interface (manager);
 | 
			
		||||
@@ -236,7 +211,7 @@ meta_monitor_manager_constructed (GObject *object)
 | 
			
		||||
  manager->in_init = FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
 | 
			
		||||
                                        int         n_old_outputs)
 | 
			
		||||
{
 | 
			
		||||
@@ -259,7 +234,7 @@ meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
 | 
			
		||||
  g_free (old_outputs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes,
 | 
			
		||||
                                      int              n_old_modes)
 | 
			
		||||
{
 | 
			
		||||
@@ -1162,6 +1137,31 @@ meta_monitor_manager_get_screen_limits (MetaMonitorManager *manager,
 | 
			
		||||
  *height = manager->max_screen_height;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_monitor_manager_read_current_config (MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
  MetaOutput *old_outputs;
 | 
			
		||||
  MetaCRTC *old_crtcs;
 | 
			
		||||
  MetaMonitorMode *old_modes;
 | 
			
		||||
  unsigned int n_old_outputs, n_old_modes;
 | 
			
		||||
 | 
			
		||||
  /* Some implementations of read_current use the existing information
 | 
			
		||||
   * we have available, so don't free the old configuration until after
 | 
			
		||||
   * read_current finishes. */
 | 
			
		||||
  old_outputs = manager->outputs;
 | 
			
		||||
  n_old_outputs = manager->n_outputs;
 | 
			
		||||
  old_modes = manager->modes;
 | 
			
		||||
  n_old_modes = manager->n_modes;
 | 
			
		||||
  old_crtcs = manager->crtcs;
 | 
			
		||||
 | 
			
		||||
  manager->serial++;
 | 
			
		||||
  META_MONITOR_MANAGER_GET_CLASS (manager)->read_current (manager);
 | 
			
		||||
 | 
			
		||||
  meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
 | 
			
		||||
  meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
 | 
			
		||||
  g_free (old_crtcs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
@@ -1179,3 +1179,22 @@ meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager)
 | 
			
		||||
  g_free (old_monitor_infos);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_monitor_manager_on_hotplug (MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
  gboolean applied_config = FALSE;
 | 
			
		||||
 | 
			
		||||
  /* If the monitor has hotplug_mode_update (which is used by VMs), don't bother
 | 
			
		||||
   * applying our stored configuration, because it's likely the user just resizing
 | 
			
		||||
   * the window.
 | 
			
		||||
   */
 | 
			
		||||
  if (!meta_monitor_manager_has_hotplug_mode_update (manager))
 | 
			
		||||
    {
 | 
			
		||||
      if (meta_monitor_config_apply_stored (manager->config, manager))
 | 
			
		||||
        applied_config = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* If we haven't applied any configuration, apply the default configuration. */
 | 
			
		||||
  if (!applied_config)
 | 
			
		||||
    meta_monitor_config_make_default (manager->config, manager);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -339,11 +339,9 @@ void                meta_monitor_manager_confirm_configuration (MetaMonitorManag
 | 
			
		||||
void               meta_crtc_info_free   (MetaCRTCInfo   *info);
 | 
			
		||||
void               meta_output_info_free (MetaOutputInfo *info);
 | 
			
		||||
 | 
			
		||||
void               meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
 | 
			
		||||
                                                           int         n_old_outputs);
 | 
			
		||||
void               meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes,
 | 
			
		||||
                                                         int              n_old_modes);
 | 
			
		||||
gboolean           meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager);
 | 
			
		||||
void               meta_monitor_manager_read_current_config (MetaMonitorManager *manager);
 | 
			
		||||
void               meta_monitor_manager_on_hotplug (MetaMonitorManager *manager);
 | 
			
		||||
 | 
			
		||||
/* Returns true if transform causes width and height to be inverted
 | 
			
		||||
   This is true for the odd transforms in the enum */
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include "meta-monitor-manager-kms.h"
 | 
			
		||||
#include "meta-monitor-config.h"
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
@@ -40,6 +41,8 @@
 | 
			
		||||
#include <meta/errors.h>
 | 
			
		||||
#include "edid.h"
 | 
			
		||||
 | 
			
		||||
#include <gudev/gudev.h>
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  drmModeConnector *connector;
 | 
			
		||||
 | 
			
		||||
@@ -68,6 +71,8 @@ struct _MetaMonitorManagerKms
 | 
			
		||||
  unsigned int       n_encoders;
 | 
			
		||||
 | 
			
		||||
  drmModeEncoder    *current_encoder;
 | 
			
		||||
 | 
			
		||||
  GUdevClient *udev;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaMonitorManagerKmsClass
 | 
			
		||||
@@ -893,6 +898,23 @@ meta_monitor_manager_kms_set_crtc_gamma (MetaMonitorManager *manager,
 | 
			
		||||
  drmModeCrtcSetGamma (manager_kms->fd, crtc->crtc_id, size, red, green, blue);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_uevent (GUdevClient *client,
 | 
			
		||||
           const char  *action,
 | 
			
		||||
           GUdevDevice *device,
 | 
			
		||||
           gpointer     user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (user_data);
 | 
			
		||||
  MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
 | 
			
		||||
 | 
			
		||||
  if (!g_udev_device_get_property_as_boolean (device, "HOTPLUG"))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  meta_monitor_manager_read_current_config (manager);
 | 
			
		||||
 | 
			
		||||
  meta_monitor_manager_on_hotplug (manager);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms)
 | 
			
		||||
{
 | 
			
		||||
@@ -907,6 +929,21 @@ meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms)
 | 
			
		||||
  cogl_renderer = cogl_display_get_renderer (cogl_display);
 | 
			
		||||
 | 
			
		||||
  manager_kms->fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
 | 
			
		||||
 | 
			
		||||
  const char *subsystems[2] = { "drm", NULL };
 | 
			
		||||
  manager_kms->udev = g_udev_client_new (subsystems);
 | 
			
		||||
  g_signal_connect (manager_kms->udev, "uevent",
 | 
			
		||||
                    G_CALLBACK (on_uevent), manager_kms);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_kms_dispose (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (object);
 | 
			
		||||
 | 
			
		||||
  g_clear_object (&manager_kms->udev);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (meta_monitor_manager_kms_parent_class)->dispose (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -925,6 +962,7 @@ meta_monitor_manager_kms_class_init (MetaMonitorManagerKmsClass *klass)
 | 
			
		||||
  MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass);
 | 
			
		||||
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  object_class->dispose = meta_monitor_manager_kms_dispose;
 | 
			
		||||
  object_class->finalize = meta_monitor_manager_kms_finalize;
 | 
			
		||||
 | 
			
		||||
  manager_class->read_current = meta_monitor_manager_kms_read_current;
 | 
			
		||||
 
 | 
			
		||||
@@ -57,7 +57,6 @@ struct _MetaMonitorManagerXrandr
 | 
			
		||||
 | 
			
		||||
  Display *xdisplay;
 | 
			
		||||
  XRRScreenResources *resources;
 | 
			
		||||
  int time;
 | 
			
		||||
  int rr_event_base;
 | 
			
		||||
  int rr_error_base;
 | 
			
		||||
};
 | 
			
		||||
@@ -413,7 +412,6 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  manager_xrandr->resources = resources;
 | 
			
		||||
  manager_xrandr->time = resources->configTimestamp;
 | 
			
		||||
  manager->n_outputs = resources->noutput;
 | 
			
		||||
  manager->n_crtcs = resources->ncrtc;
 | 
			
		||||
  manager->n_modes = resources->nmode;
 | 
			
		||||
@@ -747,7 +745,7 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
 | 
			
		||||
          XRRSetCrtcConfig (manager_xrandr->xdisplay,
 | 
			
		||||
                            manager_xrandr->resources,
 | 
			
		||||
                            (XID)crtc->crtc_id,
 | 
			
		||||
                            manager_xrandr->time,
 | 
			
		||||
                            CurrentTime,
 | 
			
		||||
                            0, 0,
 | 
			
		||||
                            None,
 | 
			
		||||
                            RR_Rotate_0,
 | 
			
		||||
@@ -777,7 +775,7 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
 | 
			
		||||
      XRRSetCrtcConfig (manager_xrandr->xdisplay,
 | 
			
		||||
                        manager_xrandr->resources,
 | 
			
		||||
                        (XID)crtc->crtc_id,
 | 
			
		||||
                        manager_xrandr->time,
 | 
			
		||||
                        CurrentTime,
 | 
			
		||||
                        0, 0,
 | 
			
		||||
                        None,
 | 
			
		||||
                        RR_Rotate_0,
 | 
			
		||||
@@ -860,7 +858,7 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
 | 
			
		||||
          ok = XRRSetCrtcConfig (manager_xrandr->xdisplay,
 | 
			
		||||
                                 manager_xrandr->resources,
 | 
			
		||||
                                 (XID)crtc->crtc_id,
 | 
			
		||||
                                 manager_xrandr->time,
 | 
			
		||||
                                 CurrentTime,
 | 
			
		||||
                                 crtc_info->x, crtc_info->y,
 | 
			
		||||
                                 (XID)mode->mode_id,
 | 
			
		||||
                                 meta_monitor_transform_to_xrandr (crtc_info->transform),
 | 
			
		||||
@@ -1001,16 +999,6 @@ meta_monitor_manager_xrandr_set_crtc_gamma (MetaMonitorManager *manager,
 | 
			
		||||
  XRRFreeGamma (gamma);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_xrandr_rebuild_derived (MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
  /* This will be a no-op if the change was from our side, as
 | 
			
		||||
     we already called it in the DBus method handler */
 | 
			
		||||
  meta_monitor_config_update_current (manager->config, manager);
 | 
			
		||||
 | 
			
		||||
  meta_monitor_manager_rebuild_derived (manager);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr)
 | 
			
		||||
{
 | 
			
		||||
@@ -1070,57 +1058,30 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra
 | 
			
		||||
					   XEvent                   *event)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr);
 | 
			
		||||
  MetaOutput *old_outputs;
 | 
			
		||||
  MetaCRTC *old_crtcs;
 | 
			
		||||
  MetaMonitorMode *old_modes;
 | 
			
		||||
  unsigned int n_old_outputs, n_old_modes;
 | 
			
		||||
  gboolean new_config;
 | 
			
		||||
  gboolean applied_config = FALSE;
 | 
			
		||||
  gboolean hotplug;
 | 
			
		||||
  Time old_timestamp;
 | 
			
		||||
 | 
			
		||||
  if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  XRRUpdateConfiguration (event);
 | 
			
		||||
 | 
			
		||||
  /* Save the old structures, so they stay valid during the update */
 | 
			
		||||
  old_outputs = manager->outputs;
 | 
			
		||||
  n_old_outputs = manager->n_outputs;
 | 
			
		||||
  old_modes = manager->modes;
 | 
			
		||||
  n_old_modes = manager->n_modes;
 | 
			
		||||
  old_crtcs = manager->crtcs;
 | 
			
		||||
  old_timestamp = manager_xrandr->resources->timestamp;
 | 
			
		||||
 | 
			
		||||
  manager->serial++;
 | 
			
		||||
  meta_monitor_manager_xrandr_read_current (manager);
 | 
			
		||||
  meta_monitor_manager_read_current_config (manager);
 | 
			
		||||
 | 
			
		||||
  new_config = manager_xrandr->resources->timestamp >= manager_xrandr->resources->configTimestamp;
 | 
			
		||||
 | 
			
		||||
  /* If this is the X server telling us we set a new configuration,
 | 
			
		||||
   * we can simply short-cut to rebuilding our logical configuration.
 | 
			
		||||
   */
 | 
			
		||||
  if (new_config || meta_monitor_config_match_current (manager->config, manager))
 | 
			
		||||
  hotplug = manager_xrandr->resources->timestamp < manager_xrandr->resources->configTimestamp;
 | 
			
		||||
  if (hotplug)
 | 
			
		||||
    {
 | 
			
		||||
      meta_monitor_manager_xrandr_rebuild_derived (manager);
 | 
			
		||||
      goto out;
 | 
			
		||||
      /* This is a hotplug event, so go ahead and build a new configuration. */
 | 
			
		||||
      meta_monitor_manager_on_hotplug (manager);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* If the monitor has hotplug_mode_update (which is used by VMs), don't bother
 | 
			
		||||
   * applying our stored configuration, because it's likely the user just resizing
 | 
			
		||||
   * the window.
 | 
			
		||||
   */
 | 
			
		||||
  if (!meta_monitor_manager_has_hotplug_mode_update (manager))
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      if (meta_monitor_config_apply_stored (manager->config, manager))
 | 
			
		||||
        applied_config = TRUE;
 | 
			
		||||
      /* If something else changed -- tell the world about it. */
 | 
			
		||||
      if (old_timestamp < manager_xrandr->resources->timestamp)
 | 
			
		||||
        meta_monitor_manager_rebuild_derived (manager);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* If we haven't applied any configuration, apply the default configuration. */
 | 
			
		||||
  if (!applied_config)
 | 
			
		||||
    meta_monitor_config_make_default (manager->config, manager);
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
  meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
 | 
			
		||||
  meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
 | 
			
		||||
  g_free (old_crtcs);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -53,7 +53,7 @@ struct _MetaBackgroundImageCacheClass
 | 
			
		||||
struct _MetaBackgroundImage
 | 
			
		||||
{
 | 
			
		||||
  GObject parent_instance;
 | 
			
		||||
  char *filename;
 | 
			
		||||
  GFile *file;
 | 
			
		||||
  MetaBackgroundImageCache *cache;
 | 
			
		||||
  gboolean in_cache;
 | 
			
		||||
  gboolean loaded;
 | 
			
		||||
@@ -70,7 +70,7 @@ G_DEFINE_TYPE (MetaBackgroundImageCache, meta_background_image_cache, G_TYPE_OBJ
 | 
			
		||||
static void
 | 
			
		||||
meta_background_image_cache_init (MetaBackgroundImageCache *cache)
 | 
			
		||||
{
 | 
			
		||||
  cache->images = g_hash_table_new (g_str_hash, g_str_equal);
 | 
			
		||||
  cache->images = g_hash_table_new (g_file_hash, (GEqualFunc) g_file_equal);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -124,9 +124,17 @@ load_file (GTask               *task,
 | 
			
		||||
{
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
  GdkPixbuf *pixbuf;
 | 
			
		||||
  GFileInputStream *stream;
 | 
			
		||||
 | 
			
		||||
  pixbuf = gdk_pixbuf_new_from_file (image->filename,
 | 
			
		||||
                                     &error);
 | 
			
		||||
  stream = g_file_read (image->file, NULL, &error);
 | 
			
		||||
  if (stream == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      g_task_return_error (task, error);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  pixbuf = gdk_pixbuf_new_from_stream (G_INPUT_STREAM (stream), NULL, &error);
 | 
			
		||||
  g_object_unref (stream);
 | 
			
		||||
 | 
			
		||||
  if (pixbuf == NULL)
 | 
			
		||||
    {
 | 
			
		||||
@@ -156,9 +164,11 @@ file_loaded (GObject      *source_object,
 | 
			
		||||
 | 
			
		||||
  if (pixbuf == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      char *uri = g_file_get_uri (image->file);
 | 
			
		||||
      g_warning ("Failed to load background '%s': %s",
 | 
			
		||||
                 image->filename, error->message);
 | 
			
		||||
                 uri, error->message);
 | 
			
		||||
      g_clear_error (&error);
 | 
			
		||||
      g_free (uri);
 | 
			
		||||
      goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -195,7 +205,7 @@ out:
 | 
			
		||||
/**
 | 
			
		||||
 * meta_background_image_cache_load:
 | 
			
		||||
 * @cache: a #MetaBackgroundImageCache
 | 
			
		||||
 * @filename: filename to load
 | 
			
		||||
 * @file: #GFile to load
 | 
			
		||||
 *
 | 
			
		||||
 * Loads an image to use as a background, or returns a reference to an
 | 
			
		||||
 * image that is already in the process of loading or loaded. In either
 | 
			
		||||
@@ -209,23 +219,23 @@ out:
 | 
			
		||||
 */
 | 
			
		||||
MetaBackgroundImage *
 | 
			
		||||
meta_background_image_cache_load (MetaBackgroundImageCache *cache,
 | 
			
		||||
                                  const char               *filename)
 | 
			
		||||
                                  GFile                    *file)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackgroundImage *image;
 | 
			
		||||
  GTask *task;
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (META_IS_BACKGROUND_IMAGE_CACHE (cache), NULL);
 | 
			
		||||
  g_return_val_if_fail (filename != NULL, NULL);
 | 
			
		||||
  g_return_val_if_fail (file != NULL, NULL);
 | 
			
		||||
 | 
			
		||||
  image = g_hash_table_lookup (cache->images, filename);
 | 
			
		||||
  image = g_hash_table_lookup (cache->images, file);
 | 
			
		||||
  if (image != NULL)
 | 
			
		||||
    return g_object_ref (image);
 | 
			
		||||
 | 
			
		||||
  image = g_object_new (META_TYPE_BACKGROUND_IMAGE, NULL);
 | 
			
		||||
  image->cache = cache;
 | 
			
		||||
  image->in_cache = TRUE;
 | 
			
		||||
  image->filename = g_strdup (filename);
 | 
			
		||||
  g_hash_table_insert (cache->images, image->filename, image);
 | 
			
		||||
  image->file = g_object_ref (file);
 | 
			
		||||
  g_hash_table_insert (cache->images, image->file, image);
 | 
			
		||||
 | 
			
		||||
  task = g_task_new (image, NULL, file_loaded, NULL);
 | 
			
		||||
 | 
			
		||||
@@ -238,25 +248,25 @@ meta_background_image_cache_load (MetaBackgroundImageCache *cache,
 | 
			
		||||
/**
 | 
			
		||||
 * meta_background_image_cache_purge:
 | 
			
		||||
 * @cache: a #MetaBackgroundImageCache
 | 
			
		||||
 * @filename: filename to remove from the cache
 | 
			
		||||
 * @file: file to remove from the cache
 | 
			
		||||
 *
 | 
			
		||||
 * Remove an entry from the cache; this would be used if monitoring
 | 
			
		||||
 * showed that the file changed.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
meta_background_image_cache_purge (MetaBackgroundImageCache *cache,
 | 
			
		||||
                                   const char               *filename)
 | 
			
		||||
                                   GFile                    *file)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackgroundImage *image;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (META_IS_BACKGROUND_IMAGE_CACHE (cache));
 | 
			
		||||
  g_return_if_fail (filename != NULL);
 | 
			
		||||
  g_return_if_fail (file != NULL);
 | 
			
		||||
 | 
			
		||||
  image = g_hash_table_lookup (cache->images, filename);
 | 
			
		||||
  image = g_hash_table_lookup (cache->images, file);
 | 
			
		||||
  if (image == NULL)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  g_hash_table_remove (cache->images, image->filename);
 | 
			
		||||
  g_hash_table_remove (cache->images, image->file);
 | 
			
		||||
  image->in_cache = FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -273,12 +283,12 @@ meta_background_image_finalize (GObject *object)
 | 
			
		||||
  MetaBackgroundImage *image = META_BACKGROUND_IMAGE (object);
 | 
			
		||||
 | 
			
		||||
  if (image->in_cache)
 | 
			
		||||
    g_hash_table_remove (image->cache->images, image->filename);
 | 
			
		||||
    g_hash_table_remove (image->cache->images, image->file);
 | 
			
		||||
 | 
			
		||||
  if (image->texture)
 | 
			
		||||
    cogl_object_unref (image->texture);
 | 
			
		||||
  if (image->filename)
 | 
			
		||||
    g_free (image->filename);
 | 
			
		||||
  if (image->file)
 | 
			
		||||
    g_object_unref (image->file);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (meta_background_image_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -50,9 +50,9 @@ struct _MetaBackgroundPrivate
 | 
			
		||||
  ClutterColor              color;
 | 
			
		||||
  ClutterColor              second_color;
 | 
			
		||||
 | 
			
		||||
  char *filename1;
 | 
			
		||||
  GFile *file1;
 | 
			
		||||
  MetaBackgroundImage *background_image1;
 | 
			
		||||
  char *filename2;
 | 
			
		||||
  GFile *file2;
 | 
			
		||||
  MetaBackgroundImage *background_image2;
 | 
			
		||||
 | 
			
		||||
  CoglTexture *color_texture;
 | 
			
		||||
@@ -241,16 +241,28 @@ on_background_loaded (MetaBackgroundImage *image,
 | 
			
		||||
  mark_changed (self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
set_filename (MetaBackground       *self,
 | 
			
		||||
              char                **filenamep,
 | 
			
		||||
              MetaBackgroundImage **imagep,
 | 
			
		||||
              const char           *filename)
 | 
			
		||||
static gboolean
 | 
			
		||||
file_equal0 (GFile *file1,
 | 
			
		||||
             GFile *file2)
 | 
			
		||||
{
 | 
			
		||||
  if (g_strcmp0 (filename, *filenamep) != 0)
 | 
			
		||||
  if (file1 == file2)
 | 
			
		||||
    return TRUE;
 | 
			
		||||
 | 
			
		||||
  if ((file1 == NULL) || (file2 == NULL))
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  return g_file_equal (file1, file2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
set_file (MetaBackground       *self,
 | 
			
		||||
          GFile               **filep,
 | 
			
		||||
          MetaBackgroundImage **imagep,
 | 
			
		||||
          GFile                *file)
 | 
			
		||||
{
 | 
			
		||||
  if (!file_equal0 (*filep, file))
 | 
			
		||||
    {
 | 
			
		||||
      g_free (*filenamep);
 | 
			
		||||
      *filenamep = g_strdup (filename);
 | 
			
		||||
      g_clear_object (filep);
 | 
			
		||||
 | 
			
		||||
      if (*imagep)
 | 
			
		||||
        {
 | 
			
		||||
@@ -261,10 +273,12 @@ set_filename (MetaBackground       *self,
 | 
			
		||||
          *imagep = NULL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      if (filename)
 | 
			
		||||
      if (file)
 | 
			
		||||
        {
 | 
			
		||||
          MetaBackgroundImageCache *cache = meta_background_image_cache_get_default ();
 | 
			
		||||
          *imagep = meta_background_image_cache_load (cache, filename);
 | 
			
		||||
 | 
			
		||||
          *filep = g_object_ref (file);
 | 
			
		||||
          *imagep = meta_background_image_cache_load (cache, file);
 | 
			
		||||
          g_signal_connect (*imagep, "loaded",
 | 
			
		||||
                            G_CALLBACK (on_background_loaded), self);
 | 
			
		||||
        }
 | 
			
		||||
@@ -280,8 +294,8 @@ meta_background_dispose (GObject *object)
 | 
			
		||||
  free_color_texture (self);
 | 
			
		||||
  free_wallpaper_texture (self);
 | 
			
		||||
 | 
			
		||||
  set_filename (self, &priv->filename1, &priv->background_image1, NULL);
 | 
			
		||||
  set_filename (self, &priv->filename2, &priv->background_image2, NULL);
 | 
			
		||||
  set_file (self, &priv->file1, &priv->background_image1, NULL);
 | 
			
		||||
  set_file (self, &priv->file2, &priv->background_image2, NULL);
 | 
			
		||||
 | 
			
		||||
  set_screen (self, NULL);
 | 
			
		||||
 | 
			
		||||
@@ -867,19 +881,19 @@ meta_background_set_gradient (MetaBackground            *self,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_background_set_filename (MetaBackground            *self,
 | 
			
		||||
                              const char                *filename,
 | 
			
		||||
                              GDesktopBackgroundStyle    style)
 | 
			
		||||
meta_background_set_file (MetaBackground            *self,
 | 
			
		||||
                          GFile                     *file,
 | 
			
		||||
                          GDesktopBackgroundStyle    style)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (META_IS_BACKGROUND (self));
 | 
			
		||||
 | 
			
		||||
  meta_background_set_blend (self, filename, NULL, 0.0, style);
 | 
			
		||||
  meta_background_set_blend (self, file, NULL, 0.0, style);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_background_set_blend (MetaBackground          *self,
 | 
			
		||||
                           const char              *filename1,
 | 
			
		||||
                           const char              *filename2,
 | 
			
		||||
                           GFile                   *file1,
 | 
			
		||||
                           GFile                   *file2,
 | 
			
		||||
                           double                   blend_factor,
 | 
			
		||||
                           GDesktopBackgroundStyle  style)
 | 
			
		||||
{
 | 
			
		||||
@@ -890,8 +904,8 @@ meta_background_set_blend (MetaBackground          *self,
 | 
			
		||||
 | 
			
		||||
  priv = self->priv;
 | 
			
		||||
 | 
			
		||||
  set_filename (self, &priv->filename1, &priv->background_image1, filename1);
 | 
			
		||||
  set_filename (self, &priv->filename2, &priv->background_image2, filename2);
 | 
			
		||||
  set_file (self, &priv->file1, &priv->background_image1, file1);
 | 
			
		||||
  set_file (self, &priv->file2, &priv->background_image2, file2);
 | 
			
		||||
 | 
			
		||||
  priv->blend_factor = blend_factor;
 | 
			
		||||
  priv->style = style;
 | 
			
		||||
 
 | 
			
		||||
@@ -65,6 +65,8 @@ meta_surface_actor_pick (ClutterActor       *actor,
 | 
			
		||||
      CoglContext *ctx;
 | 
			
		||||
      CoglFramebuffer *fb;
 | 
			
		||||
      CoglColor cogl_color;
 | 
			
		||||
      ClutterActorIter iter;
 | 
			
		||||
      ClutterActor *child;
 | 
			
		||||
 | 
			
		||||
      n_rects = cairo_region_num_rectangles (priv->input_region);
 | 
			
		||||
      rectangles = g_alloca (sizeof (float) * 4 * n_rects);
 | 
			
		||||
@@ -91,6 +93,11 @@ meta_surface_actor_pick (ClutterActor       *actor,
 | 
			
		||||
      cogl_pipeline_set_color (pipeline, &cogl_color);
 | 
			
		||||
      cogl_framebuffer_draw_rectangles (fb, pipeline, rectangles, n_rects);
 | 
			
		||||
      cogl_object_unref (pipeline);
 | 
			
		||||
 | 
			
		||||
      clutter_actor_iter_init (&iter, actor);
 | 
			
		||||
 | 
			
		||||
      while (clutter_actor_iter_next (&iter, &child))
 | 
			
		||||
        clutter_actor_paint (child);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -151,23 +151,6 @@ sequence_is_pointer_emulated (MetaDisplay        *display,
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_display_update_pointer_emulating_sequence (MetaDisplay        *display,
 | 
			
		||||
                                                const ClutterEvent *event)
 | 
			
		||||
{
 | 
			
		||||
  ClutterEventSequence *sequence;
 | 
			
		||||
 | 
			
		||||
  sequence = clutter_event_get_event_sequence (event);
 | 
			
		||||
 | 
			
		||||
  if (event->type == CLUTTER_TOUCH_BEGIN &&
 | 
			
		||||
      !display->pointer_emulating_sequence &&
 | 
			
		||||
      sequence_is_pointer_emulated (display, event))
 | 
			
		||||
    display->pointer_emulating_sequence = sequence;
 | 
			
		||||
  else if (event->type == CLUTTER_TOUCH_END &&
 | 
			
		||||
           display->pointer_emulating_sequence == sequence)
 | 
			
		||||
    display->pointer_emulating_sequence = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_display_handle_event (MetaDisplay        *display,
 | 
			
		||||
                           const ClutterEvent *event)
 | 
			
		||||
@@ -176,8 +159,15 @@ meta_display_handle_event (MetaDisplay        *display,
 | 
			
		||||
  gboolean bypass_clutter = FALSE;
 | 
			
		||||
  G_GNUC_UNUSED gboolean bypass_wayland = FALSE;
 | 
			
		||||
  MetaGestureTracker *tracker;
 | 
			
		||||
  ClutterEventSequence *sequence;
 | 
			
		||||
 | 
			
		||||
  meta_display_update_pointer_emulating_sequence (display, event);
 | 
			
		||||
  sequence = clutter_event_get_event_sequence (event);
 | 
			
		||||
 | 
			
		||||
  /* Set the pointer emulating sequence on touch begin, if eligible */
 | 
			
		||||
  if (event->type == CLUTTER_TOUCH_BEGIN &&
 | 
			
		||||
      !display->pointer_emulating_sequence &&
 | 
			
		||||
      sequence_is_pointer_emulated (display, event))
 | 
			
		||||
    display->pointer_emulating_sequence = sequence;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
  MetaWaylandCompositor *compositor = NULL;
 | 
			
		||||
@@ -314,6 +304,11 @@ meta_display_handle_event (MetaDisplay        *display,
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  /* Unset the pointer emulating sequence after its end event is processed */
 | 
			
		||||
  if (event->type == CLUTTER_TOUCH_END &&
 | 
			
		||||
      display->pointer_emulating_sequence == sequence)
 | 
			
		||||
    display->pointer_emulating_sequence = NULL;
 | 
			
		||||
 | 
			
		||||
  display->current_time = CurrentTime;
 | 
			
		||||
  return bypass_clutter;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1660,13 +1660,14 @@ meta_window_ungrab_all_keys (MetaWindow *window, guint32 timestamp)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_display_freeze_keyboard (MetaDisplay *display, Window window, guint32 timestamp)
 | 
			
		||||
meta_display_freeze_keyboard (MetaDisplay *display, guint32 timestamp)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackend *backend = meta_get_backend ();
 | 
			
		||||
 | 
			
		||||
  if (!META_IS_BACKEND_X11 (backend))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  Window window = meta_backend_x11_get_xwindow (META_BACKEND_X11 (backend));
 | 
			
		||||
  grab_keyboard (window, timestamp, XIGrabModeSync);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5851,7 +5851,7 @@ update_resize (MetaWindow *window,
 | 
			
		||||
  int new_w, new_h;
 | 
			
		||||
  int gravity;
 | 
			
		||||
  MetaRectangle old;
 | 
			
		||||
  double remaining;
 | 
			
		||||
  double remaining = 0;
 | 
			
		||||
  MetaMaximizeFlags new_unmaximize;
 | 
			
		||||
 | 
			
		||||
  window->display->grab_latest_motion_x = x;
 | 
			
		||||
@@ -6110,10 +6110,8 @@ meta_window_handle_mouse_grab_op_event  (MetaWindow         *window,
 | 
			
		||||
    case CLUTTER_BUTTON_RELEASE:
 | 
			
		||||
      if (event->button.button == 1 ||
 | 
			
		||||
          event->button.button == (unsigned int) meta_prefs_get_mouse_button_resize ())
 | 
			
		||||
        {
 | 
			
		||||
          end_grab_op (window, event);
 | 
			
		||||
          return FALSE;
 | 
			
		||||
        }
 | 
			
		||||
        end_grab_op (window, event);
 | 
			
		||||
 | 
			
		||||
      return TRUE;
 | 
			
		||||
 | 
			
		||||
    case CLUTTER_TOUCH_BEGIN:
 | 
			
		||||
 
 | 
			
		||||
@@ -173,7 +173,6 @@ void meta_display_unmanage_screen (MetaDisplay *display,
 | 
			
		||||
void meta_display_clear_mouse_mode (MetaDisplay *display);
 | 
			
		||||
 | 
			
		||||
void meta_display_freeze_keyboard (MetaDisplay *display,
 | 
			
		||||
                                   Window       window,
 | 
			
		||||
                                   guint32      timestamp);
 | 
			
		||||
void meta_display_ungrab_keyboard (MetaDisplay *display,
 | 
			
		||||
                                   guint32      timestamp);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,71 +0,0 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/* Mutter gradient rendering */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001 Havoc Pennington, 99% copied from wrlib in
 | 
			
		||||
 * WindowMaker, Copyright (C) 1997-2000 Dan Pascu and Alfredo Kojima
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU General Public License as
 | 
			
		||||
 * published by the Free Software Foundation; either version 2 of the
 | 
			
		||||
 * License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful, but
 | 
			
		||||
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, see <http://www.gnu.org/licenses/>.  */
 | 
			
		||||
 | 
			
		||||
#ifndef META_GRADIENT_H
 | 
			
		||||
#define META_GRADIENT_H
 | 
			
		||||
 | 
			
		||||
#include <gdk-pixbuf/gdk-pixbuf.h>
 | 
			
		||||
#include <gdk/gdk.h>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MetaGradientType:
 | 
			
		||||
 * @META_GRADIENT_VERTICAL: Vertical gradient
 | 
			
		||||
 * @META_GRADIENT_HORIZONTAL: Horizontal gradient
 | 
			
		||||
 * @META_GRADIENT_DIAGONAL: Diagonal gradient
 | 
			
		||||
 * @META_GRADIENT_LAST: Marks the end of the #MetaGradientType enumeration
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
typedef enum
 | 
			
		||||
{
 | 
			
		||||
  META_GRADIENT_VERTICAL,
 | 
			
		||||
  META_GRADIENT_HORIZONTAL,
 | 
			
		||||
  META_GRADIENT_DIAGONAL,
 | 
			
		||||
  META_GRADIENT_LAST
 | 
			
		||||
} MetaGradientType;
 | 
			
		||||
 | 
			
		||||
GdkPixbuf* meta_gradient_create_simple     (int               width,
 | 
			
		||||
                                            int               height,
 | 
			
		||||
                                            const GdkRGBA    *from,
 | 
			
		||||
                                            const GdkRGBA    *to,
 | 
			
		||||
                                            MetaGradientType  style);
 | 
			
		||||
GdkPixbuf* meta_gradient_create_multi      (int               width,
 | 
			
		||||
                                            int               height,
 | 
			
		||||
                                            const GdkRGBA    *colors,
 | 
			
		||||
                                            int               n_colors,
 | 
			
		||||
                                            MetaGradientType  style);
 | 
			
		||||
GdkPixbuf* meta_gradient_create_interwoven (int               width,
 | 
			
		||||
                                            int               height,
 | 
			
		||||
                                            const GdkRGBA     colors1[2],
 | 
			
		||||
                                            int               thickness1,
 | 
			
		||||
                                            const GdkRGBA     colors2[2],
 | 
			
		||||
                                            int               thickness2);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Generate an alpha gradient and multiply it with the existing alpha
 | 
			
		||||
 * channel of the given pixbuf
 | 
			
		||||
 */
 | 
			
		||||
void meta_gradient_add_alpha (GdkPixbuf       *pixbuf,
 | 
			
		||||
                              const guchar    *alphas,
 | 
			
		||||
                              int              n_alphas,
 | 
			
		||||
                              MetaGradientType type);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -69,8 +69,8 @@ MetaBackgroundImageCache *meta_background_image_cache_get_default (void);
 | 
			
		||||
GType meta_background_image_cache_get_type (void);
 | 
			
		||||
 | 
			
		||||
MetaBackgroundImage *meta_background_image_cache_load  (MetaBackgroundImageCache *cache,
 | 
			
		||||
                                                        const char               *filename);
 | 
			
		||||
                                                        GFile                    *file);
 | 
			
		||||
void                 meta_background_image_cache_purge (MetaBackgroundImageCache *cache,
 | 
			
		||||
                                                        const char               *filename);
 | 
			
		||||
                                                        GFile                    *file);
 | 
			
		||||
 | 
			
		||||
#endif /* __META_BACKGROUND_IMAGE_H__ */
 | 
			
		||||
 
 | 
			
		||||
@@ -67,12 +67,12 @@ void meta_background_set_gradient (MetaBackground            *self,
 | 
			
		||||
                                   GDesktopBackgroundShading  shading_direction,
 | 
			
		||||
                                   ClutterColor              *color,
 | 
			
		||||
                                   ClutterColor              *second_color);
 | 
			
		||||
void meta_background_set_filename (MetaBackground            *self,
 | 
			
		||||
                                   const char                *filename,
 | 
			
		||||
void meta_background_set_file     (MetaBackground            *self,
 | 
			
		||||
                                   GFile                     *file,
 | 
			
		||||
                                   GDesktopBackgroundStyle    style);
 | 
			
		||||
void meta_background_set_blend    (MetaBackground            *self,
 | 
			
		||||
                                   const char                *filename1,
 | 
			
		||||
                                   const char                *filename2,
 | 
			
		||||
                                   GFile                     *file1,
 | 
			
		||||
                                   GFile                     *file2,
 | 
			
		||||
                                   double                     blend_factor,
 | 
			
		||||
                                   GDesktopBackgroundStyle    style);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,902 +0,0 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001 Havoc Pennington, 99% copied from wrlib in
 | 
			
		||||
 * WindowMaker, Copyright (C) 1997-2000 Dan Pascu and Alfredo Kojima
 | 
			
		||||
 * Copyright (C) 2005 Elijah Newren
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU General Public License as
 | 
			
		||||
 * published by the Free Software Foundation; either version 2 of the
 | 
			
		||||
 * License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful, but
 | 
			
		||||
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, see <http://www.gnu.org/licenses/>.  */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SECTION:gradient
 | 
			
		||||
 * @title: Gradients
 | 
			
		||||
 * @short_description: Metacity gradient rendering
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <meta/gradient.h>
 | 
			
		||||
#include <meta/util.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
/* This is all Alfredo's and Dan's usual very nice WindowMaker code,
 | 
			
		||||
 * slightly GTK-ized
 | 
			
		||||
 */
 | 
			
		||||
static GdkPixbuf* meta_gradient_create_horizontal       (int             width,
 | 
			
		||||
                                                         int             height,
 | 
			
		||||
                                                         const GdkRGBA  *from,
 | 
			
		||||
                                                         const GdkRGBA  *to);
 | 
			
		||||
static GdkPixbuf* meta_gradient_create_vertical         (int             width,
 | 
			
		||||
                                                         int             height,
 | 
			
		||||
                                                         const GdkRGBA  *from,
 | 
			
		||||
                                                         const GdkRGBA  *to);
 | 
			
		||||
static GdkPixbuf* meta_gradient_create_diagonal         (int             width,
 | 
			
		||||
                                                         int             height,
 | 
			
		||||
                                                         const GdkRGBA  *from,
 | 
			
		||||
                                                         const GdkRGBA  *to);
 | 
			
		||||
static GdkPixbuf* meta_gradient_create_multi_horizontal (int             width,
 | 
			
		||||
                                                         int             height,
 | 
			
		||||
                                                         const GdkRGBA  *colors,
 | 
			
		||||
                                                         int             count);
 | 
			
		||||
static GdkPixbuf* meta_gradient_create_multi_vertical   (int             width,
 | 
			
		||||
                                                         int             height,
 | 
			
		||||
                                                         const GdkRGBA  *colors,
 | 
			
		||||
                                                         int             count);
 | 
			
		||||
static GdkPixbuf* meta_gradient_create_multi_diagonal   (int             width,
 | 
			
		||||
                                                         int             height,
 | 
			
		||||
                                                         const GdkRGBA  *colors,
 | 
			
		||||
                                                         int             count);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Used as the destroy notification function for gdk_pixbuf_new() */
 | 
			
		||||
static void
 | 
			
		||||
free_buffer (guchar *pixels, gpointer data)
 | 
			
		||||
{
 | 
			
		||||
  g_free (pixels);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GdkPixbuf*
 | 
			
		||||
blank_pixbuf (int width, int height)
 | 
			
		||||
{
 | 
			
		||||
  guchar *buf;
 | 
			
		||||
  int rowstride;
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (width > 0, NULL);
 | 
			
		||||
  g_return_val_if_fail (height > 0, NULL);
 | 
			
		||||
 | 
			
		||||
  /* Always align rows to 32-bit boundaries */
 | 
			
		||||
  rowstride = 4 * ((4 * width + 4) / 4);
 | 
			
		||||
 | 
			
		||||
  buf = g_try_malloc (height * rowstride);
 | 
			
		||||
  if (!buf)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  return gdk_pixbuf_new_from_data (buf, GDK_COLORSPACE_RGB,
 | 
			
		||||
                                   TRUE, 8,
 | 
			
		||||
                                   width, height, rowstride,
 | 
			
		||||
                                   free_buffer, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_gradient_create_simple:
 | 
			
		||||
 * @width: Width in pixels
 | 
			
		||||
 * @height: Height in pixels
 | 
			
		||||
 * @from: Starting color
 | 
			
		||||
 * @to: Ending color
 | 
			
		||||
 * @style: Gradient style
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: (transfer full): A new linear gradient
 | 
			
		||||
 */
 | 
			
		||||
GdkPixbuf*
 | 
			
		||||
meta_gradient_create_simple (int              width,
 | 
			
		||||
                             int              height,
 | 
			
		||||
                             const GdkRGBA   *from,
 | 
			
		||||
                             const GdkRGBA   *to,
 | 
			
		||||
                             MetaGradientType style)
 | 
			
		||||
{
 | 
			
		||||
  switch (style)
 | 
			
		||||
    {
 | 
			
		||||
    case META_GRADIENT_HORIZONTAL:
 | 
			
		||||
      return meta_gradient_create_horizontal (width, height,
 | 
			
		||||
                                              from, to);
 | 
			
		||||
    case META_GRADIENT_VERTICAL:
 | 
			
		||||
      return meta_gradient_create_vertical (width, height,
 | 
			
		||||
                                            from, to);
 | 
			
		||||
 | 
			
		||||
    case META_GRADIENT_DIAGONAL:
 | 
			
		||||
      return meta_gradient_create_diagonal (width, height,
 | 
			
		||||
                                            from, to);
 | 
			
		||||
    case META_GRADIENT_LAST:
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  g_assert_not_reached ();
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_gradient_create_multi:
 | 
			
		||||
 * @width: Width in pixels
 | 
			
		||||
 * @height: Height in pixels
 | 
			
		||||
 * @colors: (array length=n_colors): Array of colors
 | 
			
		||||
 * @n_colors: Number of colors
 | 
			
		||||
 * @style: Gradient style
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: (transfer full): A new multi-step linear gradient
 | 
			
		||||
 */
 | 
			
		||||
GdkPixbuf*
 | 
			
		||||
meta_gradient_create_multi (int              width,
 | 
			
		||||
                            int              height,
 | 
			
		||||
                            const GdkRGBA   *colors,
 | 
			
		||||
                            int              n_colors,
 | 
			
		||||
                            MetaGradientType style)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
  if (n_colors > 2)
 | 
			
		||||
    {
 | 
			
		||||
      switch (style)
 | 
			
		||||
        {
 | 
			
		||||
        case META_GRADIENT_HORIZONTAL:
 | 
			
		||||
          return meta_gradient_create_multi_horizontal (width, height, colors, n_colors);
 | 
			
		||||
        case META_GRADIENT_VERTICAL:
 | 
			
		||||
          return meta_gradient_create_multi_vertical (width, height, colors, n_colors);
 | 
			
		||||
        case META_GRADIENT_DIAGONAL:
 | 
			
		||||
          return meta_gradient_create_multi_diagonal (width, height, colors, n_colors);
 | 
			
		||||
        case META_GRADIENT_LAST:
 | 
			
		||||
          g_assert_not_reached ();
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  else if (n_colors > 1)
 | 
			
		||||
    {
 | 
			
		||||
      return meta_gradient_create_simple (width, height, &colors[0], &colors[1],
 | 
			
		||||
                                          style);
 | 
			
		||||
    }
 | 
			
		||||
  else if (n_colors > 0)
 | 
			
		||||
    {
 | 
			
		||||
      return meta_gradient_create_simple (width, height, &colors[0], &colors[0],
 | 
			
		||||
                                          style);
 | 
			
		||||
    }
 | 
			
		||||
  g_assert_not_reached ();
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_gradient_create_interwoven: (skip)
 | 
			
		||||
 * @width: Width in pixels
 | 
			
		||||
 * @height: Height in pixels
 | 
			
		||||
 * @colors1: Array of colors
 | 
			
		||||
 * @thickness1: Thickness
 | 
			
		||||
 * @colors2: Array of colors
 | 
			
		||||
 * @thickness2: Thickness
 | 
			
		||||
 *
 | 
			
		||||
 * Interwoven essentially means we have two vertical gradients,
 | 
			
		||||
 * cut into horizontal strips of the given thickness, and then the strips
 | 
			
		||||
 * are alternated. I'm not sure what it's good for, just copied since
 | 
			
		||||
 * WindowMaker had it.
 | 
			
		||||
 */
 | 
			
		||||
GdkPixbuf*
 | 
			
		||||
meta_gradient_create_interwoven (int            width,
 | 
			
		||||
                                 int            height,
 | 
			
		||||
                                 const GdkRGBA  colors1[2],
 | 
			
		||||
                                 int            thickness1,
 | 
			
		||||
                                 const GdkRGBA  colors2[2],
 | 
			
		||||
                                 int            thickness2)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
  int i, j, k, l, ll;
 | 
			
		||||
  long r1, g1, b1, a1, dr1, dg1, db1, da1;
 | 
			
		||||
  long r2, g2, b2, a2, dr2, dg2, db2, da2;
 | 
			
		||||
  GdkPixbuf *pixbuf;
 | 
			
		||||
  unsigned char *ptr;
 | 
			
		||||
  unsigned char *pixels;
 | 
			
		||||
  int rowstride;
 | 
			
		||||
 | 
			
		||||
  pixbuf = blank_pixbuf (width, height);
 | 
			
		||||
  if (pixbuf == NULL)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  pixels = gdk_pixbuf_get_pixels (pixbuf);
 | 
			
		||||
  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
 | 
			
		||||
 | 
			
		||||
  r1 = (long)(colors1[0].red*0xffffff);
 | 
			
		||||
  g1 = (long)(colors1[0].green*0xffffff);
 | 
			
		||||
  b1 = (long)(colors1[0].blue*0xffffff);
 | 
			
		||||
  a1 = (long)(colors1[0].alpha*0xffffff);
 | 
			
		||||
 | 
			
		||||
  r2 = (long)(colors2[0].red*0xffffff);
 | 
			
		||||
  g2 = (long)(colors2[0].green*0xffffff);
 | 
			
		||||
  b2 = (long)(colors2[0].blue*0xffffff);
 | 
			
		||||
  a2 = (long)(colors2[0].alpha*0xffffff);
 | 
			
		||||
 | 
			
		||||
  dr1 = ((colors1[1].red-colors1[0].red)*0xffffff)/(int)height;
 | 
			
		||||
  dg1 = ((colors1[1].green-colors1[0].green)*0xffffff)/(int)height;
 | 
			
		||||
  db1 = ((colors1[1].blue-colors1[0].blue)*0xffffff)/(int)height;
 | 
			
		||||
  da1 = ((colors1[1].alpha-colors1[0].alpha)*0xffffff)/(int)height;
 | 
			
		||||
 | 
			
		||||
  dr2 = ((colors2[1].red-colors2[0].red)*0xffffff)/(int)height;
 | 
			
		||||
  dg2 = ((colors2[1].green-colors2[0].green)*0xffffff)/(int)height;
 | 
			
		||||
  db2 = ((colors2[1].blue-colors2[0].blue)*0xffffff)/(int)height;
 | 
			
		||||
  da2 = ((colors2[1].alpha-colors2[0].alpha)*0xffffff)/(int)height;
 | 
			
		||||
 | 
			
		||||
  for (i=0,k=0,l=0,ll=thickness1; i<height; i++)
 | 
			
		||||
    {
 | 
			
		||||
      ptr = pixels + i * rowstride;
 | 
			
		||||
 | 
			
		||||
      if (k == 0)
 | 
			
		||||
        {
 | 
			
		||||
          ptr[0] = (unsigned char) (r1>>16);
 | 
			
		||||
          ptr[1] = (unsigned char) (g1>>16);
 | 
			
		||||
          ptr[2] = (unsigned char) (b1>>16);
 | 
			
		||||
          ptr[3] = (unsigned char) (a1>>16);
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          ptr[0] = (unsigned char) (r2>>16);
 | 
			
		||||
          ptr[1] = (unsigned char) (g2>>16);
 | 
			
		||||
          ptr[2] = (unsigned char) (b2>>16);
 | 
			
		||||
          ptr[3] = (unsigned char) (a2>>16);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      for (j=1; j <= width/2; j *= 2)
 | 
			
		||||
        memcpy (&(ptr[j*4]), ptr, j*4);
 | 
			
		||||
      memcpy (&(ptr[j*4]), ptr, (width - j)*4);
 | 
			
		||||
 | 
			
		||||
      if (++l == ll)
 | 
			
		||||
        {
 | 
			
		||||
          if (k == 0)
 | 
			
		||||
            {
 | 
			
		||||
              k = 1;
 | 
			
		||||
              ll = thickness2;
 | 
			
		||||
            }
 | 
			
		||||
          else
 | 
			
		||||
            {
 | 
			
		||||
              k = 0;
 | 
			
		||||
              ll = thickness1;
 | 
			
		||||
            }
 | 
			
		||||
          l = 0;
 | 
			
		||||
        }
 | 
			
		||||
      r1+=dr1;
 | 
			
		||||
      g1+=dg1;
 | 
			
		||||
      b1+=db1;
 | 
			
		||||
      a1+=da1;
 | 
			
		||||
 | 
			
		||||
      r2+=dr2;
 | 
			
		||||
      g2+=dg2;
 | 
			
		||||
      b2+=db2;
 | 
			
		||||
      a2+=da2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return pixbuf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *----------------------------------------------------------------------
 | 
			
		||||
 * meta_gradient_create_horizontal--
 | 
			
		||||
 * 	Renders a horizontal linear gradient of the specified size in the
 | 
			
		||||
 * GdkPixbuf format with a border of the specified type.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns:
 | 
			
		||||
 * 	A 24bit GdkPixbuf with the gradient (no alpha channel).
 | 
			
		||||
 *
 | 
			
		||||
 * Side effects:
 | 
			
		||||
 * 	None
 | 
			
		||||
 *----------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
static GdkPixbuf*
 | 
			
		||||
meta_gradient_create_horizontal (int width, int height,
 | 
			
		||||
                                 const GdkRGBA *from,
 | 
			
		||||
                                 const GdkRGBA *to)
 | 
			
		||||
{
 | 
			
		||||
  int i;
 | 
			
		||||
  long r, g, b, a, dr, dg, db, da;
 | 
			
		||||
  GdkPixbuf *pixbuf;
 | 
			
		||||
  unsigned char *ptr;
 | 
			
		||||
  unsigned char *pixels;
 | 
			
		||||
  int r0, g0, b0, a0;
 | 
			
		||||
  int rf, gf, bf, af;
 | 
			
		||||
  int rowstride;
 | 
			
		||||
 | 
			
		||||
  pixbuf = blank_pixbuf (width, height);
 | 
			
		||||
  if (pixbuf == NULL)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  pixels = gdk_pixbuf_get_pixels (pixbuf);
 | 
			
		||||
  ptr = pixels;
 | 
			
		||||
  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
 | 
			
		||||
 | 
			
		||||
  r0 = (guchar) (from->red * 0xff);
 | 
			
		||||
  g0 = (guchar) (from->green * 0xff);
 | 
			
		||||
  b0 = (guchar) (from->blue * 0xff);
 | 
			
		||||
  a0 = (guchar) (from->alpha * 0xff);
 | 
			
		||||
  rf = (guchar) (to->red * 0xff);
 | 
			
		||||
  gf = (guchar) (to->green * 0xff);
 | 
			
		||||
  bf = (guchar) (to->blue * 0xff);
 | 
			
		||||
  af = (guchar) (to->alpha * 0xff);
 | 
			
		||||
 | 
			
		||||
  r = r0 << 16;
 | 
			
		||||
  g = g0 << 16;
 | 
			
		||||
  b = b0 << 16;
 | 
			
		||||
  a = a0 << 16;
 | 
			
		||||
 | 
			
		||||
  dr = ((rf-r0)<<16)/(int)width;
 | 
			
		||||
  dg = ((gf-g0)<<16)/(int)width;
 | 
			
		||||
  db = ((bf-b0)<<16)/(int)width;
 | 
			
		||||
  da = ((af-a0)<<16)/(int)width;
 | 
			
		||||
  /* render the first line */
 | 
			
		||||
  for (i=0; i<width; i++)
 | 
			
		||||
    {
 | 
			
		||||
      *(ptr++) = (unsigned char)(r>>16);
 | 
			
		||||
      *(ptr++) = (unsigned char)(g>>16);
 | 
			
		||||
      *(ptr++) = (unsigned char)(b>>16);
 | 
			
		||||
      *(ptr++) = (unsigned char)(a>>16);
 | 
			
		||||
      r += dr;
 | 
			
		||||
      g += dg;
 | 
			
		||||
      b += db;
 | 
			
		||||
      a += da;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* copy the first line to the other lines */
 | 
			
		||||
  for (i=1; i<height; i++)
 | 
			
		||||
    {
 | 
			
		||||
      memcpy (&(pixels[i*rowstride]), pixels, rowstride);
 | 
			
		||||
    }
 | 
			
		||||
  return pixbuf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *----------------------------------------------------------------------
 | 
			
		||||
 * meta_gradient_create_vertical--
 | 
			
		||||
 *      Renders a vertical linear gradient of the specified size in the
 | 
			
		||||
 * GdkPixbuf format with a border of the specified type.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns:
 | 
			
		||||
 *      A 24bit GdkPixbuf with the gradient (no alpha channel).
 | 
			
		||||
 *
 | 
			
		||||
 * Side effects:
 | 
			
		||||
 *      None
 | 
			
		||||
 *----------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
static GdkPixbuf*
 | 
			
		||||
meta_gradient_create_vertical (int width, int height,
 | 
			
		||||
                               const GdkRGBA *from,
 | 
			
		||||
                               const GdkRGBA *to)
 | 
			
		||||
{
 | 
			
		||||
  int i, j;
 | 
			
		||||
  long r, g, b, a, dr, dg, db, da;
 | 
			
		||||
  GdkPixbuf *pixbuf;
 | 
			
		||||
  unsigned char *ptr;
 | 
			
		||||
  int r0, g0, b0, a0;
 | 
			
		||||
  int rf, gf, bf, af;
 | 
			
		||||
  int rowstride;
 | 
			
		||||
  unsigned char *pixels;
 | 
			
		||||
 | 
			
		||||
  pixbuf = blank_pixbuf (width, height);
 | 
			
		||||
  if (pixbuf == NULL)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  pixels = gdk_pixbuf_get_pixels (pixbuf);
 | 
			
		||||
  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
 | 
			
		||||
 | 
			
		||||
  r0 = (guchar) (from->red * 0xff);
 | 
			
		||||
  g0 = (guchar) (from->green * 0xff);
 | 
			
		||||
  b0 = (guchar) (from->blue * 0xff);
 | 
			
		||||
  a0 = (guchar) (from->alpha * 0xff);
 | 
			
		||||
  rf = (guchar) (to->red * 0xff);
 | 
			
		||||
  gf = (guchar) (to->green * 0xff);
 | 
			
		||||
  bf = (guchar) (to->blue * 0xff);
 | 
			
		||||
  af = (guchar) (to->alpha * 0xff);
 | 
			
		||||
 | 
			
		||||
  r = r0<<16;
 | 
			
		||||
  g = g0<<16;
 | 
			
		||||
  b = b0<<16;
 | 
			
		||||
  a = a0<<16;
 | 
			
		||||
 | 
			
		||||
  dr = ((rf-r0)<<16)/(int)height;
 | 
			
		||||
  dg = ((gf-g0)<<16)/(int)height;
 | 
			
		||||
  db = ((bf-b0)<<16)/(int)height;
 | 
			
		||||
  da = ((af-a0)<<16)/(int)height;
 | 
			
		||||
 | 
			
		||||
  for (i=0; i<height; i++)
 | 
			
		||||
    {
 | 
			
		||||
      ptr = pixels + i * rowstride;
 | 
			
		||||
 | 
			
		||||
      ptr[0] = (unsigned char)(r>>16);
 | 
			
		||||
      ptr[1] = (unsigned char)(g>>16);
 | 
			
		||||
      ptr[2] = (unsigned char)(b>>16);
 | 
			
		||||
      ptr[3] = (unsigned char)(a>>16);
 | 
			
		||||
 | 
			
		||||
      for (j=1; j <= width/2; j *= 2)
 | 
			
		||||
        memcpy (&(ptr[j*4]), ptr, j*4);
 | 
			
		||||
      memcpy (&(ptr[j*4]), ptr, (width - j)*4);
 | 
			
		||||
 | 
			
		||||
      r+=dr;
 | 
			
		||||
      g+=dg;
 | 
			
		||||
      b+=db;
 | 
			
		||||
      a+=da;
 | 
			
		||||
    }
 | 
			
		||||
  return pixbuf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *----------------------------------------------------------------------
 | 
			
		||||
 * meta_gradient_create_diagonal--
 | 
			
		||||
 *      Renders a diagonal linear gradient of the specified size in the
 | 
			
		||||
 * GdkPixbuf format with a border of the specified type.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns:
 | 
			
		||||
 *      A 24bit GdkPixbuf with the gradient (no alpha channel).
 | 
			
		||||
 *
 | 
			
		||||
 * Side effects:
 | 
			
		||||
 *      None
 | 
			
		||||
 *----------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static GdkPixbuf*
 | 
			
		||||
meta_gradient_create_diagonal (int width, int height,
 | 
			
		||||
                               const GdkRGBA *from,
 | 
			
		||||
                               const GdkRGBA *to)
 | 
			
		||||
{
 | 
			
		||||
  GdkPixbuf *pixbuf, *tmp;
 | 
			
		||||
  int j;
 | 
			
		||||
  float a, offset;
 | 
			
		||||
  unsigned char *ptr;
 | 
			
		||||
  unsigned char *pixels;
 | 
			
		||||
  int rowstride;
 | 
			
		||||
 | 
			
		||||
  if (width == 1)
 | 
			
		||||
    return meta_gradient_create_vertical (width, height, from, to);
 | 
			
		||||
  else if (height == 1)
 | 
			
		||||
    return meta_gradient_create_horizontal (width, height, from, to);
 | 
			
		||||
 | 
			
		||||
  pixbuf = blank_pixbuf (width, height);
 | 
			
		||||
  if (pixbuf == NULL)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  pixels = gdk_pixbuf_get_pixels (pixbuf);
 | 
			
		||||
  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
 | 
			
		||||
 | 
			
		||||
  tmp = meta_gradient_create_horizontal (2*width-1, 1, from, to);
 | 
			
		||||
  if (!tmp)
 | 
			
		||||
    {
 | 
			
		||||
      g_object_unref (G_OBJECT (pixbuf));
 | 
			
		||||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  ptr = gdk_pixbuf_get_pixels (tmp);
 | 
			
		||||
 | 
			
		||||
  a = ((float)(width - 1))/((float)(height - 1));
 | 
			
		||||
  width = width * 4;
 | 
			
		||||
 | 
			
		||||
  /* copy the first line to the other lines with corresponding offset */
 | 
			
		||||
  for (j=0, offset=0.0; j<rowstride*height; j += rowstride)
 | 
			
		||||
    {
 | 
			
		||||
      memcpy (&(pixels[j]), &ptr[4*(int)offset], width);
 | 
			
		||||
      offset += a;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_object_unref (G_OBJECT (tmp));
 | 
			
		||||
  return pixbuf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static GdkPixbuf*
 | 
			
		||||
meta_gradient_create_multi_horizontal (int width, int height,
 | 
			
		||||
                                       const GdkRGBA *colors,
 | 
			
		||||
                                       int count)
 | 
			
		||||
{
 | 
			
		||||
  int i, j, k;
 | 
			
		||||
  long r, g, b, a, dr, dg, db, da;
 | 
			
		||||
  GdkPixbuf *pixbuf;
 | 
			
		||||
  unsigned char *ptr;
 | 
			
		||||
  unsigned char *pixels;
 | 
			
		||||
  int width2;
 | 
			
		||||
  int rowstride;
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (count > 2, NULL);
 | 
			
		||||
 | 
			
		||||
  pixbuf = blank_pixbuf (width, height);
 | 
			
		||||
  if (pixbuf == NULL)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  pixels = gdk_pixbuf_get_pixels (pixbuf);
 | 
			
		||||
  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
 | 
			
		||||
  ptr = pixels;
 | 
			
		||||
 | 
			
		||||
  if (count > width)
 | 
			
		||||
    count = width;
 | 
			
		||||
 | 
			
		||||
  if (count > 1)
 | 
			
		||||
    width2 = width/(count-1);
 | 
			
		||||
  else
 | 
			
		||||
    width2 = width;
 | 
			
		||||
 | 
			
		||||
  k = 0;
 | 
			
		||||
 | 
			
		||||
  r = (long)(colors[0].red * 0xffffff);
 | 
			
		||||
  g = (long)(colors[0].green * 0xffffff);
 | 
			
		||||
  b = (long)(colors[0].blue * 0xffffff);
 | 
			
		||||
  a = (long)(colors[0].alpha * 0xffffff);
 | 
			
		||||
 | 
			
		||||
  /* render the first line */
 | 
			
		||||
  for (i=1; i<count; i++)
 | 
			
		||||
    {
 | 
			
		||||
      dr = (int)((colors[i].red   - colors[i-1].red)  *0xffffff)/(int)width2;
 | 
			
		||||
      dg = (int)((colors[i].green - colors[i-1].green)*0xffffff)/(int)width2;
 | 
			
		||||
      db = (int)((colors[i].blue  - colors[i-1].blue) *0xffffff)/(int)width2;
 | 
			
		||||
      da = (int)((colors[i].alpha  - colors[i-1].alpha) *0xffffff)/(int)width2;
 | 
			
		||||
      for (j=0; j<width2; j++)
 | 
			
		||||
        {
 | 
			
		||||
          *ptr++ = (unsigned char)(r>>16);
 | 
			
		||||
          *ptr++ = (unsigned char)(g>>16);
 | 
			
		||||
          *ptr++ = (unsigned char)(b>>16);
 | 
			
		||||
          *ptr++ = (unsigned char)(a>>16);
 | 
			
		||||
          r += dr;
 | 
			
		||||
          g += dg;
 | 
			
		||||
          b += db;
 | 
			
		||||
          a += da;
 | 
			
		||||
          k++;
 | 
			
		||||
	}
 | 
			
		||||
      r = (long)(colors[i].red   * 0xffffff);
 | 
			
		||||
      g = (long)(colors[i].green * 0xffffff);
 | 
			
		||||
      b = (long)(colors[i].blue  * 0xffffff);
 | 
			
		||||
      a = (long)(colors[i].alpha  * 0xffffff);
 | 
			
		||||
    }
 | 
			
		||||
  for (j=k; j<width; j++)
 | 
			
		||||
    {
 | 
			
		||||
      *ptr++ = (unsigned char)(r>>16);
 | 
			
		||||
      *ptr++ = (unsigned char)(g>>16);
 | 
			
		||||
      *ptr++ = (unsigned char)(b>>16);
 | 
			
		||||
      *ptr++ = (unsigned char)(a>>16);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* copy the first line to the other lines */
 | 
			
		||||
  for (i=1; i<height; i++)
 | 
			
		||||
    {
 | 
			
		||||
      memcpy (&(pixels[i*rowstride]), pixels, rowstride);
 | 
			
		||||
    }
 | 
			
		||||
  return pixbuf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GdkPixbuf*
 | 
			
		||||
meta_gradient_create_multi_vertical (int width, int height,
 | 
			
		||||
                                     const GdkRGBA *colors,
 | 
			
		||||
                                     int count)
 | 
			
		||||
{
 | 
			
		||||
  int i, j, k;
 | 
			
		||||
  long r, g, b, a, dr, dg, db, da;
 | 
			
		||||
  GdkPixbuf *pixbuf;
 | 
			
		||||
  unsigned char *ptr, *tmp, *pixels;
 | 
			
		||||
  int height2;
 | 
			
		||||
  int x;
 | 
			
		||||
  int rowstride;
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (count > 2, NULL);
 | 
			
		||||
 | 
			
		||||
  pixbuf = blank_pixbuf (width, height);
 | 
			
		||||
  if (pixbuf == NULL)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  pixels = gdk_pixbuf_get_pixels (pixbuf);
 | 
			
		||||
  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
 | 
			
		||||
  ptr = pixels;
 | 
			
		||||
 | 
			
		||||
  if (count > height)
 | 
			
		||||
    count = height;
 | 
			
		||||
 | 
			
		||||
  if (count > 1)
 | 
			
		||||
    height2 = height/(count-1);
 | 
			
		||||
  else
 | 
			
		||||
    height2 = height;
 | 
			
		||||
 | 
			
		||||
  k = 0;
 | 
			
		||||
 | 
			
		||||
  r = (long)(colors[0].red * 0xffffff);
 | 
			
		||||
  g = (long)(colors[0].green * 0xffffff);
 | 
			
		||||
  b = (long)(colors[0].blue * 0xffffff);
 | 
			
		||||
  a = (long)(colors[0].alpha * 0xffffff);
 | 
			
		||||
 | 
			
		||||
  for (i=1; i<count; i++)
 | 
			
		||||
    {
 | 
			
		||||
      dr = (int)((colors[i].red   - colors[i-1].red)  *0xffffff)/(int)height2;
 | 
			
		||||
      dg = (int)((colors[i].green - colors[i-1].green)*0xffffff)/(int)height2;
 | 
			
		||||
      db = (int)((colors[i].blue  - colors[i-1].blue) *0xffffff)/(int)height2;
 | 
			
		||||
      da = (int)((colors[i].alpha  - colors[i-1].alpha) *0xffffff)/(int)height2;
 | 
			
		||||
 | 
			
		||||
      for (j=0; j<height2; j++)
 | 
			
		||||
        {
 | 
			
		||||
          ptr[0] = (unsigned char)(r>>16);
 | 
			
		||||
          ptr[1] = (unsigned char)(g>>16);
 | 
			
		||||
          ptr[2] = (unsigned char)(b>>16);
 | 
			
		||||
          ptr[3] = (unsigned char)(a>>16);
 | 
			
		||||
 | 
			
		||||
          for (x=1; x <= width/2; x *= 2)
 | 
			
		||||
            memcpy (&(ptr[x*4]), ptr, x*4);
 | 
			
		||||
          memcpy (&(ptr[x*4]), ptr, (width - x)*4);
 | 
			
		||||
 | 
			
		||||
          ptr += rowstride;
 | 
			
		||||
 | 
			
		||||
          r += dr;
 | 
			
		||||
          g += dg;
 | 
			
		||||
          b += db;
 | 
			
		||||
          a += da;
 | 
			
		||||
          k++;
 | 
			
		||||
	}
 | 
			
		||||
      r = (long)(colors[i].red   * 0xffffff);
 | 
			
		||||
      g = (long)(colors[i].green * 0xffffff);
 | 
			
		||||
      b = (long)(colors[i].blue  * 0xffffff);
 | 
			
		||||
      a = (long)(colors[i].alpha  * 0xffffff);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (k<height)
 | 
			
		||||
    {
 | 
			
		||||
      tmp = ptr;
 | 
			
		||||
 | 
			
		||||
      ptr[0] = (unsigned char) (r>>16);
 | 
			
		||||
      ptr[1] = (unsigned char) (g>>16);
 | 
			
		||||
      ptr[2] = (unsigned char) (b>>16);
 | 
			
		||||
      ptr[3] = (unsigned char) (a>>16);
 | 
			
		||||
 | 
			
		||||
      for (x=1; x <= width/2; x *= 2)
 | 
			
		||||
        memcpy (&(ptr[x*4]), ptr, x*4);
 | 
			
		||||
      memcpy (&(ptr[x*4]), ptr, (width - x)*4);
 | 
			
		||||
 | 
			
		||||
      ptr += rowstride;
 | 
			
		||||
 | 
			
		||||
      for (j=k+1; j<height; j++)
 | 
			
		||||
        {
 | 
			
		||||
          memcpy (ptr, tmp, rowstride);
 | 
			
		||||
          ptr += rowstride;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return pixbuf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static GdkPixbuf*
 | 
			
		||||
meta_gradient_create_multi_diagonal (int width, int height,
 | 
			
		||||
                                     const GdkRGBA *colors,
 | 
			
		||||
                                     int count)
 | 
			
		||||
{
 | 
			
		||||
  GdkPixbuf *pixbuf, *tmp;
 | 
			
		||||
  float a, offset;
 | 
			
		||||
  int j;
 | 
			
		||||
  unsigned char *ptr;
 | 
			
		||||
  unsigned char *pixels;
 | 
			
		||||
  int rowstride;
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (count > 2, NULL);
 | 
			
		||||
 | 
			
		||||
  if (width == 1)
 | 
			
		||||
    return meta_gradient_create_multi_vertical (width, height, colors, count);
 | 
			
		||||
  else if (height == 1)
 | 
			
		||||
    return meta_gradient_create_multi_horizontal (width, height, colors, count);
 | 
			
		||||
 | 
			
		||||
  pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
 | 
			
		||||
                           width, height);
 | 
			
		||||
  if (pixbuf == NULL)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  pixels = gdk_pixbuf_get_pixels (pixbuf);
 | 
			
		||||
  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
 | 
			
		||||
 | 
			
		||||
  if (count > width)
 | 
			
		||||
    count = width;
 | 
			
		||||
  if (count > height)
 | 
			
		||||
    count = height;
 | 
			
		||||
 | 
			
		||||
  if (count > 2)
 | 
			
		||||
    tmp = meta_gradient_create_multi_horizontal (2*width-1, 1, colors, count);
 | 
			
		||||
  else
 | 
			
		||||
    /* wrlib multiplies these colors by 256 before passing them in, but
 | 
			
		||||
     * I think it's a bug in wrlib, so changed here. I could be wrong
 | 
			
		||||
     * though, if we notice two-color multi diagonals not working.
 | 
			
		||||
     */
 | 
			
		||||
    tmp = meta_gradient_create_horizontal (2*width-1, 1,
 | 
			
		||||
                                           &colors[0], &colors[1]);
 | 
			
		||||
 | 
			
		||||
  if (!tmp)
 | 
			
		||||
    {
 | 
			
		||||
      g_object_unref (G_OBJECT (pixbuf));
 | 
			
		||||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
  ptr = gdk_pixbuf_get_pixels (tmp);
 | 
			
		||||
 | 
			
		||||
  a = ((float)(width - 1))/((float)(height - 1));
 | 
			
		||||
  width = width * 3;
 | 
			
		||||
 | 
			
		||||
  /* copy the first line to the other lines with corresponding offset */
 | 
			
		||||
  for (j=0, offset=0; j<rowstride*height; j += rowstride)
 | 
			
		||||
    {
 | 
			
		||||
      memcpy (&(pixels[j]), &ptr[3*(int)offset], width);
 | 
			
		||||
      offset += a;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_object_unref (G_OBJECT (tmp));
 | 
			
		||||
  return pixbuf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
simple_multiply_alpha (GdkPixbuf *pixbuf,
 | 
			
		||||
                       guchar     alpha)
 | 
			
		||||
{
 | 
			
		||||
  guchar *pixels;
 | 
			
		||||
  int rowstride;
 | 
			
		||||
  int height;
 | 
			
		||||
  int row;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
 | 
			
		||||
 | 
			
		||||
  if (alpha == 255)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  g_assert (gdk_pixbuf_get_has_alpha (pixbuf));
 | 
			
		||||
 | 
			
		||||
  pixels = gdk_pixbuf_get_pixels (pixbuf);
 | 
			
		||||
  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
 | 
			
		||||
  height = gdk_pixbuf_get_height (pixbuf);
 | 
			
		||||
 | 
			
		||||
  row = 0;
 | 
			
		||||
  while (row < height)
 | 
			
		||||
    {
 | 
			
		||||
      guchar *p;
 | 
			
		||||
      guchar *end;
 | 
			
		||||
 | 
			
		||||
      p = pixels + row * rowstride;
 | 
			
		||||
      end = p + rowstride;
 | 
			
		||||
 | 
			
		||||
      while (p != end)
 | 
			
		||||
        {
 | 
			
		||||
          p += 3; /* skip RGB */
 | 
			
		||||
 | 
			
		||||
          /* multiply the two alpha channels. not sure this is right.
 | 
			
		||||
           * but some end cases are that if the pixbuf contains 255,
 | 
			
		||||
           * then it should be modified to contain "alpha"; if the
 | 
			
		||||
           * pixbuf contains 0, it should remain 0.
 | 
			
		||||
           */
 | 
			
		||||
          /* ((*p / 255.0) * (alpha / 255.0)) * 255; */
 | 
			
		||||
          *p = (guchar) (((int) *p * (int) alpha) / (int) 255);
 | 
			
		||||
 | 
			
		||||
          ++p; /* skip A */
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      ++row;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_gradient_add_alpha_horizontal (GdkPixbuf           *pixbuf,
 | 
			
		||||
                                    const unsigned char *alphas,
 | 
			
		||||
                                    int                  n_alphas)
 | 
			
		||||
{
 | 
			
		||||
  int i, j;
 | 
			
		||||
  long a, da;
 | 
			
		||||
  unsigned char *p;
 | 
			
		||||
  unsigned char *pixels;
 | 
			
		||||
  int width2;
 | 
			
		||||
  int rowstride;
 | 
			
		||||
  int width, height;
 | 
			
		||||
  unsigned char *gradient;
 | 
			
		||||
  unsigned char *gradient_p;
 | 
			
		||||
  unsigned char *gradient_end;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (n_alphas > 0);
 | 
			
		||||
 | 
			
		||||
  if (n_alphas == 1)
 | 
			
		||||
    {
 | 
			
		||||
      /* Optimize this */
 | 
			
		||||
      simple_multiply_alpha (pixbuf, alphas[0]);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  width = gdk_pixbuf_get_width (pixbuf);
 | 
			
		||||
  height = gdk_pixbuf_get_height (pixbuf);
 | 
			
		||||
 | 
			
		||||
  gradient = g_new (unsigned char, width);
 | 
			
		||||
  gradient_end = gradient + width;
 | 
			
		||||
 | 
			
		||||
  if (n_alphas > width)
 | 
			
		||||
    n_alphas = width;
 | 
			
		||||
 | 
			
		||||
  if (n_alphas > 1)
 | 
			
		||||
    width2 = width / (n_alphas - 1);
 | 
			
		||||
  else
 | 
			
		||||
    width2 = width;
 | 
			
		||||
 | 
			
		||||
  a = alphas[0] << 8;
 | 
			
		||||
  gradient_p = gradient;
 | 
			
		||||
 | 
			
		||||
  /* render the gradient into an array */
 | 
			
		||||
  for (i = 1; i < n_alphas; i++)
 | 
			
		||||
    {
 | 
			
		||||
      da = (((int)(alphas[i] - (int) alphas[i-1])) << 8) / (int) width2;
 | 
			
		||||
 | 
			
		||||
      for (j = 0; j < width2; j++)
 | 
			
		||||
        {
 | 
			
		||||
          *gradient_p++ = (a >> 8);
 | 
			
		||||
 | 
			
		||||
          a += da;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
      a = alphas[i] << 8;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* get leftover pixels */
 | 
			
		||||
  while (gradient_p != gradient_end)
 | 
			
		||||
    {
 | 
			
		||||
      *gradient_p++ = a >> 8;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Now for each line of the pixbuf, fill in with the gradient */
 | 
			
		||||
  pixels = gdk_pixbuf_get_pixels (pixbuf);
 | 
			
		||||
  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
 | 
			
		||||
 | 
			
		||||
  p = pixels;
 | 
			
		||||
  i = 0;
 | 
			
		||||
  while (i < height)
 | 
			
		||||
    {
 | 
			
		||||
      unsigned char *row_end = p + rowstride;
 | 
			
		||||
      gradient_p = gradient;
 | 
			
		||||
 | 
			
		||||
      p += 3;
 | 
			
		||||
      while (gradient_p != gradient_end)
 | 
			
		||||
        {
 | 
			
		||||
          /* multiply the two alpha channels. not sure this is right.
 | 
			
		||||
           * but some end cases are that if the pixbuf contains 255,
 | 
			
		||||
           * then it should be modified to contain "alpha"; if the
 | 
			
		||||
           * pixbuf contains 0, it should remain 0.
 | 
			
		||||
           */
 | 
			
		||||
          /* ((*p / 255.0) * (alpha / 255.0)) * 255; */
 | 
			
		||||
          *p = (guchar) (((int) *p * (int) *gradient_p) / (int) 255);
 | 
			
		||||
 | 
			
		||||
          p += 4;
 | 
			
		||||
          ++gradient_p;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      p = row_end;
 | 
			
		||||
      ++i;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_free (gradient);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_gradient_add_alpha (GdkPixbuf       *pixbuf,
 | 
			
		||||
                         const guchar    *alphas,
 | 
			
		||||
                         int              n_alphas,
 | 
			
		||||
                         MetaGradientType type)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
 | 
			
		||||
  g_return_if_fail (gdk_pixbuf_get_has_alpha (pixbuf));
 | 
			
		||||
  g_return_if_fail (n_alphas > 0);
 | 
			
		||||
 | 
			
		||||
  switch (type)
 | 
			
		||||
    {
 | 
			
		||||
    case META_GRADIENT_HORIZONTAL:
 | 
			
		||||
      meta_gradient_add_alpha_horizontal (pixbuf, alphas, n_alphas);
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case META_GRADIENT_VERTICAL:
 | 
			
		||||
      g_printerr ("metacity: vertical alpha channel gradient not implemented yet\n");
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case META_GRADIENT_DIAGONAL:
 | 
			
		||||
      g_printerr ("metacity: diagonal alpha channel gradient not implemented yet\n");
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case META_GRADIENT_LAST:
 | 
			
		||||
      g_assert_not_reached ();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,315 +0,0 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/* Mutter gradient test program */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002 Havoc Pennington
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU General Public License as
 | 
			
		||||
 * published by the Free Software Foundation; either version 2 of the
 | 
			
		||||
 * License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful, but
 | 
			
		||||
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, see <http://www.gnu.org/licenses/>.  */
 | 
			
		||||
 | 
			
		||||
#include <meta/gradient.h>
 | 
			
		||||
#include <gtk/gtk.h>
 | 
			
		||||
 | 
			
		||||
typedef void (* RenderGradientFunc) (cairo_t     *cr,
 | 
			
		||||
                                     int          width,
 | 
			
		||||
                                     int          height);
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
draw_checkerboard (cairo_t *cr,
 | 
			
		||||
                   int      width,
 | 
			
		||||
                   int      height)
 | 
			
		||||
{
 | 
			
		||||
  gint i, j, xcount, ycount;
 | 
			
		||||
  GdkRGBA color1, color2;
 | 
			
		||||
 | 
			
		||||
#define CHECK_SIZE 10
 | 
			
		||||
#define SPACING 2
 | 
			
		||||
 | 
			
		||||
  color1.red = 30000. / 65535.;
 | 
			
		||||
  color1.green = 30000. / 65535.;
 | 
			
		||||
  color1.blue = 30000. / 65535.;
 | 
			
		||||
  color1.alpha = 1.0;
 | 
			
		||||
 | 
			
		||||
  color2.red = 50000. / 65535.;
 | 
			
		||||
  color2.green = 50000. / 65535.;
 | 
			
		||||
  color2.blue = 50000. / 65535.;
 | 
			
		||||
  color2.alpha = 1.0;
 | 
			
		||||
 | 
			
		||||
  xcount = 0;
 | 
			
		||||
  i = SPACING;
 | 
			
		||||
  while (i < width)
 | 
			
		||||
    {
 | 
			
		||||
      j = SPACING;
 | 
			
		||||
      ycount = xcount % 2; /* start with even/odd depending on row */
 | 
			
		||||
      while (j < height)
 | 
			
		||||
	{
 | 
			
		||||
	  if (ycount % 2)
 | 
			
		||||
	    gdk_cairo_set_source_rgba (cr, &color1);
 | 
			
		||||
	  else
 | 
			
		||||
	    gdk_cairo_set_source_rgba (cr, &color2);
 | 
			
		||||
 | 
			
		||||
	  /* If we're outside event->area, this will do nothing.
 | 
			
		||||
	   * It might be mildly more efficient if we handled
 | 
			
		||||
	   * the clipping ourselves, but again we're feeling lazy.
 | 
			
		||||
	   */
 | 
			
		||||
          cairo_rectangle (cr, i, j, CHECK_SIZE, CHECK_SIZE);
 | 
			
		||||
          cairo_fill (cr);
 | 
			
		||||
 | 
			
		||||
	  j += CHECK_SIZE + SPACING;
 | 
			
		||||
	  ++ycount;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
      i += CHECK_SIZE + SPACING;
 | 
			
		||||
      ++xcount;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
render_simple (cairo_t     *cr,
 | 
			
		||||
               int width, int height,
 | 
			
		||||
               MetaGradientType type,
 | 
			
		||||
               gboolean    with_alpha)
 | 
			
		||||
{
 | 
			
		||||
  GdkPixbuf *pixbuf;
 | 
			
		||||
  GdkRGBA from, to;
 | 
			
		||||
 | 
			
		||||
  gdk_rgba_parse (&from, "blue");
 | 
			
		||||
  gdk_rgba_parse (&to, "green");
 | 
			
		||||
 | 
			
		||||
  pixbuf = meta_gradient_create_simple (width, height,
 | 
			
		||||
                                        &from, &to,
 | 
			
		||||
                                        type);
 | 
			
		||||
 | 
			
		||||
  if (with_alpha)
 | 
			
		||||
    {
 | 
			
		||||
      const unsigned char alphas[] = { 0xff, 0xaa, 0x2f, 0x0, 0xcc, 0xff, 0xff };
 | 
			
		||||
 | 
			
		||||
      if (!gdk_pixbuf_get_has_alpha (pixbuf))
 | 
			
		||||
        {
 | 
			
		||||
          GdkPixbuf *new_pixbuf;
 | 
			
		||||
 | 
			
		||||
          new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
 | 
			
		||||
          g_object_unref (G_OBJECT (pixbuf));
 | 
			
		||||
          pixbuf = new_pixbuf;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      meta_gradient_add_alpha (pixbuf,
 | 
			
		||||
                               alphas, G_N_ELEMENTS (alphas),
 | 
			
		||||
                               META_GRADIENT_HORIZONTAL);
 | 
			
		||||
 | 
			
		||||
      draw_checkerboard (cr , width, height);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
 | 
			
		||||
  cairo_rectangle (cr, 0, 0, width, height);
 | 
			
		||||
  cairo_fill (cr);
 | 
			
		||||
 | 
			
		||||
  g_object_unref (G_OBJECT (pixbuf));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
render_vertical_func (cairo_t *cr,
 | 
			
		||||
                      int width, int height)
 | 
			
		||||
{
 | 
			
		||||
  render_simple (cr, width, height, META_GRADIENT_VERTICAL, FALSE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
render_horizontal_func (cairo_t *cr,
 | 
			
		||||
                        int width, int height)
 | 
			
		||||
{
 | 
			
		||||
  render_simple (cr, width, height, META_GRADIENT_HORIZONTAL, FALSE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
render_diagonal_func (cairo_t *cr,
 | 
			
		||||
                      int width, int height)
 | 
			
		||||
{
 | 
			
		||||
  render_simple (cr, width, height, META_GRADIENT_DIAGONAL, FALSE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
render_diagonal_alpha_func (cairo_t *cr,
 | 
			
		||||
                            int width, int height)
 | 
			
		||||
{
 | 
			
		||||
  render_simple (cr, width, height, META_GRADIENT_DIAGONAL, TRUE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
render_multi (cairo_t     *cr,
 | 
			
		||||
              int width, int height,
 | 
			
		||||
              MetaGradientType type)
 | 
			
		||||
{
 | 
			
		||||
  GdkPixbuf *pixbuf;
 | 
			
		||||
#define N_COLORS 5
 | 
			
		||||
  GdkRGBA colors[N_COLORS];
 | 
			
		||||
 | 
			
		||||
  gdk_rgba_parse (&colors[0], "red");
 | 
			
		||||
  gdk_rgba_parse (&colors[1], "blue");
 | 
			
		||||
  gdk_rgba_parse (&colors[2], "orange");
 | 
			
		||||
  gdk_rgba_parse (&colors[3], "pink");
 | 
			
		||||
  gdk_rgba_parse (&colors[4], "green");
 | 
			
		||||
 | 
			
		||||
  pixbuf = meta_gradient_create_multi (width, height,
 | 
			
		||||
                                       colors, N_COLORS,
 | 
			
		||||
                                       type);
 | 
			
		||||
 | 
			
		||||
  gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
 | 
			
		||||
  cairo_rectangle (cr, 0, 0, width, height);
 | 
			
		||||
  cairo_fill (cr);
 | 
			
		||||
 | 
			
		||||
  g_object_unref (G_OBJECT (pixbuf));
 | 
			
		||||
#undef N_COLORS
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
render_vertical_multi_func (cairo_t *cr,
 | 
			
		||||
                            int width, int height)
 | 
			
		||||
{
 | 
			
		||||
  render_multi (cr, width, height, META_GRADIENT_VERTICAL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
render_horizontal_multi_func (cairo_t *cr,
 | 
			
		||||
                              int width, int height)
 | 
			
		||||
{
 | 
			
		||||
  render_multi (cr, width, height, META_GRADIENT_HORIZONTAL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
render_diagonal_multi_func (cairo_t *cr,
 | 
			
		||||
                            int width, int height)
 | 
			
		||||
{
 | 
			
		||||
  render_multi (cr, width, height, META_GRADIENT_DIAGONAL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
render_interwoven_func (cairo_t *cr,
 | 
			
		||||
                        int width, int height)
 | 
			
		||||
{
 | 
			
		||||
  GdkPixbuf *pixbuf;
 | 
			
		||||
#define N_COLORS 4
 | 
			
		||||
  GdkRGBA colors[N_COLORS];
 | 
			
		||||
 | 
			
		||||
  gdk_rgba_parse (&colors[0], "red");
 | 
			
		||||
  gdk_rgba_parse (&colors[1], "blue");
 | 
			
		||||
  gdk_rgba_parse (&colors[2], "pink");
 | 
			
		||||
  gdk_rgba_parse (&colors[3], "green");
 | 
			
		||||
 | 
			
		||||
  pixbuf = meta_gradient_create_interwoven (width, height,
 | 
			
		||||
                                            colors, height / 10,
 | 
			
		||||
                                            colors + 2, height / 14);
 | 
			
		||||
 | 
			
		||||
  gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
 | 
			
		||||
  cairo_rectangle (cr, 0, 0, width, height);
 | 
			
		||||
  cairo_fill (cr);
 | 
			
		||||
 | 
			
		||||
  g_object_unref (G_OBJECT (pixbuf));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
draw_callback (GtkWidget *widget,
 | 
			
		||||
               cairo_t   *cr,
 | 
			
		||||
               gpointer   data)
 | 
			
		||||
{
 | 
			
		||||
  RenderGradientFunc func = data;
 | 
			
		||||
  GtkStyleContext *style;
 | 
			
		||||
  GdkRGBA color;
 | 
			
		||||
 | 
			
		||||
  style = gtk_widget_get_style_context (widget);
 | 
			
		||||
 | 
			
		||||
  gtk_style_context_save (style);
 | 
			
		||||
  gtk_style_context_set_state (style, gtk_widget_get_state_flags (widget));
 | 
			
		||||
  gtk_style_context_lookup_color (style, "foreground-color", &color);
 | 
			
		||||
  gtk_style_context_restore (style);
 | 
			
		||||
 | 
			
		||||
  gdk_cairo_set_source_rgba (cr, &color);
 | 
			
		||||
 | 
			
		||||
  (* func) (cr,
 | 
			
		||||
            gtk_widget_get_allocated_width (widget),
 | 
			
		||||
            gtk_widget_get_allocated_height (widget));
 | 
			
		||||
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GtkWidget*
 | 
			
		||||
create_gradient_window (const char *title,
 | 
			
		||||
                        RenderGradientFunc func)
 | 
			
		||||
{
 | 
			
		||||
  GtkWidget *window;
 | 
			
		||||
  GtkWidget *drawing_area;
 | 
			
		||||
 | 
			
		||||
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 | 
			
		||||
 | 
			
		||||
  gtk_window_set_title (GTK_WINDOW (window), title);
 | 
			
		||||
 | 
			
		||||
  drawing_area = gtk_drawing_area_new ();
 | 
			
		||||
 | 
			
		||||
  gtk_widget_set_size_request (drawing_area, 1, 1);
 | 
			
		||||
 | 
			
		||||
  gtk_window_set_default_size (GTK_WINDOW (window), 175, 175);
 | 
			
		||||
 | 
			
		||||
  g_signal_connect (G_OBJECT (drawing_area),
 | 
			
		||||
                    "draw",
 | 
			
		||||
                    G_CALLBACK (draw_callback),
 | 
			
		||||
                    func);
 | 
			
		||||
 | 
			
		||||
  gtk_container_add (GTK_CONTAINER (window), drawing_area);
 | 
			
		||||
 | 
			
		||||
  gtk_widget_show_all (window);
 | 
			
		||||
 | 
			
		||||
  return window;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_gradient_test (void)
 | 
			
		||||
{
 | 
			
		||||
  create_gradient_window ("Simple vertical",
 | 
			
		||||
                          render_vertical_func);
 | 
			
		||||
 | 
			
		||||
  create_gradient_window ("Simple horizontal",
 | 
			
		||||
                          render_horizontal_func);
 | 
			
		||||
 | 
			
		||||
  create_gradient_window ("Simple diagonal",
 | 
			
		||||
                          render_diagonal_func);
 | 
			
		||||
 | 
			
		||||
  create_gradient_window ("Multi vertical",
 | 
			
		||||
                          render_vertical_multi_func);
 | 
			
		||||
 | 
			
		||||
  create_gradient_window ("Multi horizontal",
 | 
			
		||||
                          render_horizontal_multi_func);
 | 
			
		||||
 | 
			
		||||
  create_gradient_window ("Multi diagonal",
 | 
			
		||||
                          render_diagonal_multi_func);
 | 
			
		||||
 | 
			
		||||
  create_gradient_window ("Interwoven",
 | 
			
		||||
                          render_interwoven_func);
 | 
			
		||||
 | 
			
		||||
  create_gradient_window ("Simple diagonal with horizontal multi alpha",
 | 
			
		||||
                          render_diagonal_alpha_func);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
main (int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
  gtk_init (&argc, &argv);
 | 
			
		||||
 | 
			
		||||
  meta_gradient_test ();
 | 
			
		||||
 | 
			
		||||
  gtk_main ();
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -774,9 +774,6 @@ parse_alpha (const char             *str,
 | 
			
		||||
 | 
			
		||||
  n_alphas = i;
 | 
			
		||||
 | 
			
		||||
  /* FIXME allow specifying horizontal/vertical/diagonal in theme format,
 | 
			
		||||
   * once we implement vertical/diagonal in gradient.c
 | 
			
		||||
   */
 | 
			
		||||
  spec = meta_alpha_gradient_spec_new (META_GRADIENT_HORIZONTAL,
 | 
			
		||||
                                       n_alphas);
 | 
			
		||||
 | 
			
		||||
@@ -2150,11 +2147,9 @@ parse_draw_op_element (GMarkupParseContext  *context,
 | 
			
		||||
      const char *width;
 | 
			
		||||
      const char *height;
 | 
			
		||||
      const char *alpha;
 | 
			
		||||
      const char *colorize;
 | 
			
		||||
      const char *fill_type;
 | 
			
		||||
      MetaAlphaGradientSpec *alpha_spec;
 | 
			
		||||
      GdkPixbuf *pixbuf;
 | 
			
		||||
      MetaColorSpec *colorize_spec = NULL;
 | 
			
		||||
      MetaImageFillType fill_type_val;
 | 
			
		||||
      int h, w, c;
 | 
			
		||||
      int pixbuf_width, pixbuf_height, pixbuf_n_channels, pixbuf_rowstride;
 | 
			
		||||
@@ -2165,7 +2160,6 @@ parse_draw_op_element (GMarkupParseContext  *context,
 | 
			
		||||
                              "!x", &x, "!y", &y,
 | 
			
		||||
                              "!width", &width, "!height", &height,
 | 
			
		||||
                              "alpha", &alpha, "!filename", &filename,
 | 
			
		||||
                              "colorize", &colorize,
 | 
			
		||||
                              "fill_type", &fill_type,
 | 
			
		||||
                              NULL))
 | 
			
		||||
        return;
 | 
			
		||||
@@ -2211,18 +2205,6 @@ parse_draw_op_element (GMarkupParseContext  *context,
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      if (colorize)
 | 
			
		||||
        {
 | 
			
		||||
          colorize_spec = parse_color (info->theme, colorize, error);
 | 
			
		||||
 | 
			
		||||
          if (colorize_spec == NULL)
 | 
			
		||||
            {
 | 
			
		||||
              add_context_to_error (error, context);
 | 
			
		||||
              g_object_unref (G_OBJECT (pixbuf));
 | 
			
		||||
              return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      alpha_spec = NULL;
 | 
			
		||||
      if (alpha && !parse_alpha (alpha, &alpha_spec, context, error))
 | 
			
		||||
        {
 | 
			
		||||
@@ -2233,7 +2215,6 @@ parse_draw_op_element (GMarkupParseContext  *context,
 | 
			
		||||
      op = meta_draw_op_new (META_DRAW_IMAGE);
 | 
			
		||||
 | 
			
		||||
      op->data.image.pixbuf = pixbuf;
 | 
			
		||||
      op->data.image.colorize_spec = colorize_spec;
 | 
			
		||||
 | 
			
		||||
      op->data.image.x = meta_draw_spec_new (info->theme, x, NULL);
 | 
			
		||||
      op->data.image.y = meta_draw_spec_new (info->theme, y, NULL);
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,6 @@
 | 
			
		||||
#define META_THEME_PRIVATE_H
 | 
			
		||||
 | 
			
		||||
#include <meta/boxes.h>
 | 
			
		||||
#include <meta/gradient.h>
 | 
			
		||||
#include <meta/theme.h>
 | 
			
		||||
#include <meta/common.h>
 | 
			
		||||
#include <gtk/gtk.h>
 | 
			
		||||
@@ -273,6 +272,14 @@ typedef enum
 | 
			
		||||
  META_IMAGE_FILL_TILE
 | 
			
		||||
} MetaImageFillType;
 | 
			
		||||
 | 
			
		||||
typedef enum
 | 
			
		||||
{
 | 
			
		||||
  META_GRADIENT_VERTICAL,
 | 
			
		||||
  META_GRADIENT_HORIZONTAL,
 | 
			
		||||
  META_GRADIENT_DIAGONAL,
 | 
			
		||||
  META_GRADIENT_LAST
 | 
			
		||||
} MetaGradientType;
 | 
			
		||||
 | 
			
		||||
typedef enum
 | 
			
		||||
{
 | 
			
		||||
  META_COLOR_SPEC_BASIC,
 | 
			
		||||
@@ -538,7 +545,6 @@ struct _MetaDrawOp
 | 
			
		||||
    } gradient;
 | 
			
		||||
 | 
			
		||||
    struct {
 | 
			
		||||
      MetaColorSpec *colorize_spec;
 | 
			
		||||
      MetaAlphaGradientSpec *alpha_spec;
 | 
			
		||||
      GdkPixbuf *pixbuf;
 | 
			
		||||
      MetaDrawSpec *x;
 | 
			
		||||
@@ -546,8 +552,6 @@ struct _MetaDrawOp
 | 
			
		||||
      MetaDrawSpec *width;
 | 
			
		||||
      MetaDrawSpec *height;
 | 
			
		||||
 | 
			
		||||
      guint32 colorize_cache_pixel;
 | 
			
		||||
      GdkPixbuf *colorize_cache_pixbuf;
 | 
			
		||||
      MetaImageFillType fill_type;
 | 
			
		||||
      unsigned int vertical_stripes : 1;
 | 
			
		||||
      unsigned int horizontal_stripes : 1;
 | 
			
		||||
@@ -972,8 +976,12 @@ gboolean       meta_draw_op_list_contains (MetaDrawOpList    *op_list,
 | 
			
		||||
 | 
			
		||||
MetaGradientSpec* meta_gradient_spec_new    (MetaGradientType        type);
 | 
			
		||||
void              meta_gradient_spec_free   (MetaGradientSpec       *desc);
 | 
			
		||||
GdkPixbuf*        meta_gradient_spec_render (const MetaGradientSpec *desc,
 | 
			
		||||
                                             GtkStyleContext        *gtk_style,
 | 
			
		||||
void              meta_gradient_spec_render (const MetaGradientSpec *spec,
 | 
			
		||||
                                             const MetaAlphaGradientSpec *alpha_spec,
 | 
			
		||||
                                             cairo_t                *cr,
 | 
			
		||||
                                             GtkStyleContext        *style,
 | 
			
		||||
                                             int                     x,
 | 
			
		||||
                                             int                     y,
 | 
			
		||||
                                             int                     width,
 | 
			
		||||
                                             int                     height);
 | 
			
		||||
gboolean          meta_gradient_spec_validate (MetaGradientSpec     *spec,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										760
									
								
								src/ui/theme.c
									
									
									
									
									
								
							
							
						
						
									
										760
									
								
								src/ui/theme.c
									
									
									
									
									
								
							@@ -38,7 +38,6 @@
 | 
			
		||||
#include "theme-private.h"
 | 
			
		||||
#include "frames.h" /* for META_TYPE_FRAMES */
 | 
			
		||||
#include "util-private.h"
 | 
			
		||||
#include <meta/gradient.h>
 | 
			
		||||
#include <meta/prefs.h>
 | 
			
		||||
#include <gtk/gtk.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
@@ -75,84 +74,6 @@ static void hls_to_rgb			(gdouble	 *h,
 | 
			
		||||
 */
 | 
			
		||||
static MetaTheme *meta_current_theme = NULL;
 | 
			
		||||
 | 
			
		||||
static GdkPixbuf *
 | 
			
		||||
colorize_pixbuf (GdkPixbuf *orig,
 | 
			
		||||
                 GdkRGBA   *new_color)
 | 
			
		||||
{
 | 
			
		||||
  GdkPixbuf *pixbuf;
 | 
			
		||||
  double intensity;
 | 
			
		||||
  int x, y;
 | 
			
		||||
  const guchar *src;
 | 
			
		||||
  guchar *dest;
 | 
			
		||||
  int orig_rowstride;
 | 
			
		||||
  int dest_rowstride;
 | 
			
		||||
  int width, height;
 | 
			
		||||
  gboolean has_alpha;
 | 
			
		||||
  const guchar *src_pixels;
 | 
			
		||||
  guchar *dest_pixels;
 | 
			
		||||
 | 
			
		||||
  pixbuf = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (orig), gdk_pixbuf_get_has_alpha (orig),
 | 
			
		||||
                           gdk_pixbuf_get_bits_per_sample (orig),
 | 
			
		||||
                           gdk_pixbuf_get_width (orig), gdk_pixbuf_get_height (orig));
 | 
			
		||||
 | 
			
		||||
  if (pixbuf == NULL)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  orig_rowstride = gdk_pixbuf_get_rowstride (orig);
 | 
			
		||||
  dest_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
 | 
			
		||||
  width = gdk_pixbuf_get_width (pixbuf);
 | 
			
		||||
  height = gdk_pixbuf_get_height (pixbuf);
 | 
			
		||||
  has_alpha = gdk_pixbuf_get_has_alpha (orig);
 | 
			
		||||
  src_pixels = gdk_pixbuf_get_pixels (orig);
 | 
			
		||||
  dest_pixels = gdk_pixbuf_get_pixels (pixbuf);
 | 
			
		||||
 | 
			
		||||
  for (y = 0; y < height; y++)
 | 
			
		||||
    {
 | 
			
		||||
      src = src_pixels + y * orig_rowstride;
 | 
			
		||||
      dest = dest_pixels + y * dest_rowstride;
 | 
			
		||||
 | 
			
		||||
      for (x = 0; x < width; x++)
 | 
			
		||||
        {
 | 
			
		||||
          double dr, dg, db;
 | 
			
		||||
 | 
			
		||||
          intensity = INTENSITY (src[0], src[1], src[2]) / 255.0;
 | 
			
		||||
 | 
			
		||||
          if (intensity <= 0.5)
 | 
			
		||||
            {
 | 
			
		||||
              /* Go from black at intensity = 0.0 to new_color at intensity = 0.5 */
 | 
			
		||||
              dr = new_color->red * intensity * 2.0;
 | 
			
		||||
              dg = new_color->green * intensity * 2.0;
 | 
			
		||||
              db = new_color->blue * intensity * 2.0;
 | 
			
		||||
            }
 | 
			
		||||
          else
 | 
			
		||||
            {
 | 
			
		||||
              /* Go from new_color at intensity = 0.5 to white at intensity = 1.0 */
 | 
			
		||||
              dr = new_color->red + (1.0 - new_color->red) * (intensity - 0.5) * 2.0;
 | 
			
		||||
              dg = new_color->green + (1.0 - new_color->green) * (intensity - 0.5) * 2.0;
 | 
			
		||||
              db = new_color->blue + (1.0 - new_color->blue) * (intensity - 0.5) * 2.0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          dest[0] = CLAMP_UCHAR (255 * dr);
 | 
			
		||||
          dest[1] = CLAMP_UCHAR (255 * dg);
 | 
			
		||||
          dest[2] = CLAMP_UCHAR (255 * db);
 | 
			
		||||
 | 
			
		||||
          if (has_alpha)
 | 
			
		||||
            {
 | 
			
		||||
              dest[3] = src[3];
 | 
			
		||||
              src += 4;
 | 
			
		||||
              dest += 4;
 | 
			
		||||
            }
 | 
			
		||||
          else
 | 
			
		||||
            {
 | 
			
		||||
              src += 3;
 | 
			
		||||
              dest += 3;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return pixbuf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
color_composite (const GdkRGBA *bg,
 | 
			
		||||
                 const GdkRGBA *fg,
 | 
			
		||||
@@ -1010,42 +931,84 @@ meta_gradient_spec_free (MetaGradientSpec *spec)
 | 
			
		||||
  g_free (spec);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GdkPixbuf*
 | 
			
		||||
meta_gradient_spec_render (const MetaGradientSpec *spec,
 | 
			
		||||
                           GtkStyleContext        *style,
 | 
			
		||||
                           int                     width,
 | 
			
		||||
                           int                     height)
 | 
			
		||||
static cairo_pattern_t *
 | 
			
		||||
meta_gradient_spec_pattern (const MetaGradientSpec *spec,
 | 
			
		||||
                            const MetaAlphaGradientSpec *alpha_spec,
 | 
			
		||||
                            GtkStyleContext        *style)
 | 
			
		||||
{
 | 
			
		||||
  cairo_pattern_t *pattern;
 | 
			
		||||
  int n_colors;
 | 
			
		||||
  GdkRGBA *colors;
 | 
			
		||||
  GSList *tmp;
 | 
			
		||||
  GSList *l;
 | 
			
		||||
  int i;
 | 
			
		||||
  GdkPixbuf *pixbuf;
 | 
			
		||||
 | 
			
		||||
  if (spec->type == META_GRADIENT_HORIZONTAL)
 | 
			
		||||
    pattern = cairo_pattern_create_linear (0, 0, 1, 0);
 | 
			
		||||
  if (spec->type == META_GRADIENT_VERTICAL)
 | 
			
		||||
    pattern = cairo_pattern_create_linear (0, 0, 0, 1);
 | 
			
		||||
  else if (spec->type == META_GRADIENT_DIAGONAL)
 | 
			
		||||
    pattern = cairo_pattern_create_linear (0, 0, 1, 1);
 | 
			
		||||
  else
 | 
			
		||||
    g_assert_not_reached ();
 | 
			
		||||
 | 
			
		||||
  n_colors = g_slist_length (spec->color_specs);
 | 
			
		||||
 | 
			
		||||
  if (n_colors == 0)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  colors = g_new (GdkRGBA, n_colors);
 | 
			
		||||
  if (alpha_spec != NULL)
 | 
			
		||||
    g_assert (n_colors == alpha_spec->n_alphas);
 | 
			
		||||
 | 
			
		||||
  i = 0;
 | 
			
		||||
  tmp = spec->color_specs;
 | 
			
		||||
  while (tmp != NULL)
 | 
			
		||||
  for (l = spec->color_specs; l != NULL; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      meta_color_spec_render (tmp->data, style, &colors[i]);
 | 
			
		||||
      MetaColorSpec *color_spec = l->data;
 | 
			
		||||
      GdkRGBA color;
 | 
			
		||||
 | 
			
		||||
      tmp = tmp->next;
 | 
			
		||||
      meta_color_spec_render (color_spec, style, &color);
 | 
			
		||||
 | 
			
		||||
      if (alpha_spec != NULL)
 | 
			
		||||
        color.alpha *= alpha_spec->alphas[i];
 | 
			
		||||
 | 
			
		||||
      cairo_pattern_add_color_stop_rgba (pattern,
 | 
			
		||||
                                         i / (float) n_colors,
 | 
			
		||||
                                         color.red,
 | 
			
		||||
                                         color.green,
 | 
			
		||||
                                         color.blue,
 | 
			
		||||
                                         color.alpha);
 | 
			
		||||
      ++i;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  pixbuf = meta_gradient_create_multi (width, height,
 | 
			
		||||
                                       colors, n_colors,
 | 
			
		||||
                                       spec->type);
 | 
			
		||||
  return pattern;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
  g_free (colors);
 | 
			
		||||
void
 | 
			
		||||
meta_gradient_spec_render (const MetaGradientSpec *spec,
 | 
			
		||||
                           const MetaAlphaGradientSpec *alpha_spec,
 | 
			
		||||
                           cairo_t                *cr,
 | 
			
		||||
                           GtkStyleContext        *style,
 | 
			
		||||
                           int                     x,
 | 
			
		||||
                           int                     y,
 | 
			
		||||
                           int                     width,
 | 
			
		||||
                           int                     height)
 | 
			
		||||
{
 | 
			
		||||
  cairo_pattern_t *pattern;
 | 
			
		||||
 | 
			
		||||
  return pixbuf;
 | 
			
		||||
  cairo_save (cr);
 | 
			
		||||
 | 
			
		||||
  pattern = meta_gradient_spec_pattern (spec, alpha_spec, style);
 | 
			
		||||
  if (pattern == NULL)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  cairo_rectangle (cr, x, y, width, height);
 | 
			
		||||
 | 
			
		||||
  cairo_translate (cr, x, y);
 | 
			
		||||
  cairo_scale (cr, width, height);
 | 
			
		||||
 | 
			
		||||
  cairo_set_source (cr, pattern);
 | 
			
		||||
  cairo_fill (cr);
 | 
			
		||||
  cairo_pattern_destroy (pattern);
 | 
			
		||||
 | 
			
		||||
  cairo_restore (cr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
@@ -3052,12 +3015,6 @@ meta_draw_op_free (MetaDrawOp *op)
 | 
			
		||||
      if (op->data.image.pixbuf)
 | 
			
		||||
        g_object_unref (G_OBJECT (op->data.image.pixbuf));
 | 
			
		||||
 | 
			
		||||
      if (op->data.image.colorize_spec)
 | 
			
		||||
        meta_color_spec_free (op->data.image.colorize_spec);
 | 
			
		||||
 | 
			
		||||
      if (op->data.image.colorize_cache_pixbuf)
 | 
			
		||||
        g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf));
 | 
			
		||||
 | 
			
		||||
      meta_draw_spec_free (op->data.image.x);
 | 
			
		||||
      meta_draw_spec_free (op->data.image.y);
 | 
			
		||||
      meta_draw_spec_free (op->data.image.width);
 | 
			
		||||
@@ -3132,413 +3089,6 @@ meta_draw_op_free (MetaDrawOp *op)
 | 
			
		||||
  g_free (op);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GdkPixbuf*
 | 
			
		||||
apply_alpha (GdkPixbuf             *pixbuf,
 | 
			
		||||
             MetaAlphaGradientSpec *spec,
 | 
			
		||||
             gboolean               force_copy)
 | 
			
		||||
{
 | 
			
		||||
  GdkPixbuf *new_pixbuf;
 | 
			
		||||
  gboolean needs_alpha;
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
 | 
			
		||||
 | 
			
		||||
  needs_alpha = spec && (spec->n_alphas > 1 ||
 | 
			
		||||
                         spec->alphas[0] != 0xff);
 | 
			
		||||
 | 
			
		||||
  if (!needs_alpha)
 | 
			
		||||
    return pixbuf;
 | 
			
		||||
 | 
			
		||||
  if (!gdk_pixbuf_get_has_alpha (pixbuf))
 | 
			
		||||
    {
 | 
			
		||||
      new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
 | 
			
		||||
      g_object_unref (G_OBJECT (pixbuf));
 | 
			
		||||
      pixbuf = new_pixbuf;
 | 
			
		||||
    }
 | 
			
		||||
  else if (force_copy)
 | 
			
		||||
    {
 | 
			
		||||
      new_pixbuf = gdk_pixbuf_copy (pixbuf);
 | 
			
		||||
      g_object_unref (G_OBJECT (pixbuf));
 | 
			
		||||
      pixbuf = new_pixbuf;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_assert (gdk_pixbuf_get_has_alpha (pixbuf));
 | 
			
		||||
 | 
			
		||||
  meta_gradient_add_alpha (pixbuf, spec->alphas, spec->n_alphas, spec->type);
 | 
			
		||||
 | 
			
		||||
  return pixbuf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GdkPixbuf*
 | 
			
		||||
pixbuf_tile (GdkPixbuf *tile,
 | 
			
		||||
             int        width,
 | 
			
		||||
             int        height)
 | 
			
		||||
{
 | 
			
		||||
  GdkPixbuf *pixbuf;
 | 
			
		||||
  int tile_width;
 | 
			
		||||
  int tile_height;
 | 
			
		||||
  int i, j;
 | 
			
		||||
 | 
			
		||||
  tile_width = gdk_pixbuf_get_width (tile);
 | 
			
		||||
  tile_height = gdk_pixbuf_get_height (tile);
 | 
			
		||||
 | 
			
		||||
  pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
 | 
			
		||||
                           gdk_pixbuf_get_has_alpha (tile),
 | 
			
		||||
                           8, width, height);
 | 
			
		||||
 | 
			
		||||
  i = 0;
 | 
			
		||||
  while (i < width)
 | 
			
		||||
    {
 | 
			
		||||
      j = 0;
 | 
			
		||||
      while (j < height)
 | 
			
		||||
        {
 | 
			
		||||
          int w, h;
 | 
			
		||||
 | 
			
		||||
          w = MIN (tile_width, width - i);
 | 
			
		||||
          h = MIN (tile_height, height - j);
 | 
			
		||||
 | 
			
		||||
          gdk_pixbuf_copy_area (tile,
 | 
			
		||||
                                0, 0,
 | 
			
		||||
                                w, h,
 | 
			
		||||
                                pixbuf,
 | 
			
		||||
                                i, j);
 | 
			
		||||
 | 
			
		||||
          j += tile_height;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      i += tile_width;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return pixbuf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GdkPixbuf *
 | 
			
		||||
replicate_rows (GdkPixbuf  *src,
 | 
			
		||||
                int         src_x,
 | 
			
		||||
                int         src_y,
 | 
			
		||||
                int         width,
 | 
			
		||||
                int         height)
 | 
			
		||||
{
 | 
			
		||||
  unsigned int n_channels = gdk_pixbuf_get_n_channels (src);
 | 
			
		||||
  unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src);
 | 
			
		||||
  unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x
 | 
			
		||||
                           * n_channels);
 | 
			
		||||
  unsigned char *dest_pixels;
 | 
			
		||||
  GdkPixbuf *result;
 | 
			
		||||
  unsigned int dest_rowstride;
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
 | 
			
		||||
                           width, height);
 | 
			
		||||
  dest_rowstride = gdk_pixbuf_get_rowstride (result);
 | 
			
		||||
  dest_pixels = gdk_pixbuf_get_pixels (result);
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < height; i++)
 | 
			
		||||
    memcpy (dest_pixels + dest_rowstride * i, pixels, n_channels * width);
 | 
			
		||||
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GdkPixbuf *
 | 
			
		||||
replicate_cols (GdkPixbuf  *src,
 | 
			
		||||
                int         src_x,
 | 
			
		||||
                int         src_y,
 | 
			
		||||
                int         width,
 | 
			
		||||
                int         height)
 | 
			
		||||
{
 | 
			
		||||
  unsigned int n_channels = gdk_pixbuf_get_n_channels (src);
 | 
			
		||||
  unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src);
 | 
			
		||||
  unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x
 | 
			
		||||
                           * n_channels);
 | 
			
		||||
  unsigned char *dest_pixels;
 | 
			
		||||
  GdkPixbuf *result;
 | 
			
		||||
  unsigned int dest_rowstride;
 | 
			
		||||
  int i, j;
 | 
			
		||||
 | 
			
		||||
  result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
 | 
			
		||||
                           width, height);
 | 
			
		||||
  dest_rowstride = gdk_pixbuf_get_rowstride (result);
 | 
			
		||||
  dest_pixels = gdk_pixbuf_get_pixels (result);
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < height; i++)
 | 
			
		||||
    {
 | 
			
		||||
      unsigned char *p = dest_pixels + dest_rowstride * i;
 | 
			
		||||
      unsigned char *q = pixels + src_rowstride * i;
 | 
			
		||||
 | 
			
		||||
      unsigned char r = *(q++);
 | 
			
		||||
      unsigned char g = *(q++);
 | 
			
		||||
      unsigned char b = *(q++);
 | 
			
		||||
 | 
			
		||||
      if (n_channels == 4)
 | 
			
		||||
        {
 | 
			
		||||
          unsigned char a;
 | 
			
		||||
 | 
			
		||||
          a = *(q++);
 | 
			
		||||
 | 
			
		||||
          for (j = 0; j < width; j++)
 | 
			
		||||
            {
 | 
			
		||||
              *(p++) = r;
 | 
			
		||||
              *(p++) = g;
 | 
			
		||||
              *(p++) = b;
 | 
			
		||||
              *(p++) = a;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          for (j = 0; j < width; j++)
 | 
			
		||||
            {
 | 
			
		||||
              *(p++) = r;
 | 
			
		||||
              *(p++) = g;
 | 
			
		||||
              *(p++) = b;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GdkPixbuf*
 | 
			
		||||
scale_and_alpha_pixbuf (GdkPixbuf             *src,
 | 
			
		||||
                        MetaAlphaGradientSpec *alpha_spec,
 | 
			
		||||
                        MetaImageFillType      fill_type,
 | 
			
		||||
                        int                    width,
 | 
			
		||||
                        int                    height,
 | 
			
		||||
                        gboolean               vertical_stripes,
 | 
			
		||||
                        gboolean               horizontal_stripes)
 | 
			
		||||
{
 | 
			
		||||
  GdkPixbuf *pixbuf;
 | 
			
		||||
  GdkPixbuf *temp_pixbuf;
 | 
			
		||||
 | 
			
		||||
  pixbuf = NULL;
 | 
			
		||||
 | 
			
		||||
  pixbuf = src;
 | 
			
		||||
 | 
			
		||||
  if (gdk_pixbuf_get_width (pixbuf) == width &&
 | 
			
		||||
      gdk_pixbuf_get_height (pixbuf) == height)
 | 
			
		||||
    {
 | 
			
		||||
      g_object_ref (G_OBJECT (pixbuf));
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      if (fill_type == META_IMAGE_FILL_TILE)
 | 
			
		||||
        {
 | 
			
		||||
          pixbuf = pixbuf_tile (pixbuf, width, height);
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
    	  int src_h, src_w, dest_h, dest_w;
 | 
			
		||||
          src_h = gdk_pixbuf_get_height (src);
 | 
			
		||||
          src_w = gdk_pixbuf_get_width (src);
 | 
			
		||||
 | 
			
		||||
          /* prefer to replicate_cols if possible, as that
 | 
			
		||||
           * is faster (no memory reads)
 | 
			
		||||
           */
 | 
			
		||||
          if (horizontal_stripes)
 | 
			
		||||
            {
 | 
			
		||||
              dest_w = gdk_pixbuf_get_width (src);
 | 
			
		||||
              dest_h = height;
 | 
			
		||||
            }
 | 
			
		||||
          else if (vertical_stripes)
 | 
			
		||||
            {
 | 
			
		||||
              dest_w = width;
 | 
			
		||||
              dest_h = gdk_pixbuf_get_height (src);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          else
 | 
			
		||||
            {
 | 
			
		||||
              dest_w = width;
 | 
			
		||||
              dest_h = height;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          if (dest_w == src_w && dest_h == src_h)
 | 
			
		||||
            {
 | 
			
		||||
              temp_pixbuf = src;
 | 
			
		||||
              g_object_ref (G_OBJECT (temp_pixbuf));
 | 
			
		||||
            }
 | 
			
		||||
          else
 | 
			
		||||
            {
 | 
			
		||||
              temp_pixbuf = gdk_pixbuf_scale_simple (src,
 | 
			
		||||
                                                     dest_w, dest_h,
 | 
			
		||||
                                                     GDK_INTERP_BILINEAR);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          /* prefer to replicate_cols if possible, as that
 | 
			
		||||
           * is faster (no memory reads)
 | 
			
		||||
           */
 | 
			
		||||
          if (horizontal_stripes)
 | 
			
		||||
            {
 | 
			
		||||
              pixbuf = replicate_cols (temp_pixbuf, 0, 0, width, height);
 | 
			
		||||
              g_object_unref (G_OBJECT (temp_pixbuf));
 | 
			
		||||
            }
 | 
			
		||||
          else if (vertical_stripes)
 | 
			
		||||
            {
 | 
			
		||||
              pixbuf = replicate_rows (temp_pixbuf, 0, 0, width, height);
 | 
			
		||||
              g_object_unref (G_OBJECT (temp_pixbuf));
 | 
			
		||||
            }
 | 
			
		||||
          else
 | 
			
		||||
            {
 | 
			
		||||
              pixbuf = temp_pixbuf;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (pixbuf)
 | 
			
		||||
    pixbuf = apply_alpha (pixbuf, alpha_spec, pixbuf == src);
 | 
			
		||||
 | 
			
		||||
  return pixbuf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GdkPixbuf*
 | 
			
		||||
draw_op_as_pixbuf (const MetaDrawOp    *op,
 | 
			
		||||
                   GtkStyleContext     *context,
 | 
			
		||||
                   const MetaDrawInfo  *info,
 | 
			
		||||
                   int                  width,
 | 
			
		||||
                   int                  height)
 | 
			
		||||
{
 | 
			
		||||
  /* Try to get the op as a pixbuf, assuming w/h in the op
 | 
			
		||||
   * matches the width/height passed in. return NULL
 | 
			
		||||
   * if the op can't be converted to an equivalent pixbuf.
 | 
			
		||||
   */
 | 
			
		||||
  GdkPixbuf *pixbuf;
 | 
			
		||||
 | 
			
		||||
  pixbuf = NULL;
 | 
			
		||||
 | 
			
		||||
  switch (op->type)
 | 
			
		||||
    {
 | 
			
		||||
    case META_DRAW_TINT:
 | 
			
		||||
      {
 | 
			
		||||
        GdkRGBA color;
 | 
			
		||||
        guint32 rgba;
 | 
			
		||||
        gboolean has_alpha;
 | 
			
		||||
 | 
			
		||||
        meta_color_spec_render (op->data.rectangle.color_spec,
 | 
			
		||||
                                context,
 | 
			
		||||
                                &color);
 | 
			
		||||
 | 
			
		||||
        has_alpha =
 | 
			
		||||
          op->data.tint.alpha_spec &&
 | 
			
		||||
          (op->data.tint.alpha_spec->n_alphas > 1 ||
 | 
			
		||||
           op->data.tint.alpha_spec->alphas[0] != 0xff);
 | 
			
		||||
 | 
			
		||||
        pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
 | 
			
		||||
                                 has_alpha,
 | 
			
		||||
                                 8, width, height);
 | 
			
		||||
 | 
			
		||||
        if (!has_alpha)
 | 
			
		||||
          {
 | 
			
		||||
            rgba = GDK_COLOR_RGBA (color);
 | 
			
		||||
 | 
			
		||||
            gdk_pixbuf_fill (pixbuf, rgba);
 | 
			
		||||
          }
 | 
			
		||||
        else if (op->data.tint.alpha_spec->n_alphas == 1)
 | 
			
		||||
          {
 | 
			
		||||
            rgba = GDK_COLOR_RGBA (color);
 | 
			
		||||
            rgba &= ~0xff;
 | 
			
		||||
            rgba |= op->data.tint.alpha_spec->alphas[0];
 | 
			
		||||
 | 
			
		||||
            gdk_pixbuf_fill (pixbuf, rgba);
 | 
			
		||||
          }
 | 
			
		||||
        else
 | 
			
		||||
          {
 | 
			
		||||
            rgba = GDK_COLOR_RGBA (color);
 | 
			
		||||
 | 
			
		||||
            gdk_pixbuf_fill (pixbuf, rgba);
 | 
			
		||||
 | 
			
		||||
            meta_gradient_add_alpha (pixbuf,
 | 
			
		||||
                                     op->data.tint.alpha_spec->alphas,
 | 
			
		||||
                                     op->data.tint.alpha_spec->n_alphas,
 | 
			
		||||
                                     op->data.tint.alpha_spec->type);
 | 
			
		||||
          }
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case META_DRAW_GRADIENT:
 | 
			
		||||
      {
 | 
			
		||||
        pixbuf = meta_gradient_spec_render (op->data.gradient.gradient_spec,
 | 
			
		||||
                                            context, width, height);
 | 
			
		||||
 | 
			
		||||
        pixbuf = apply_alpha (pixbuf,
 | 
			
		||||
                              op->data.gradient.alpha_spec,
 | 
			
		||||
                              FALSE);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case META_DRAW_IMAGE:
 | 
			
		||||
      {
 | 
			
		||||
        if (op->data.image.colorize_spec)
 | 
			
		||||
          {
 | 
			
		||||
            GdkRGBA color;
 | 
			
		||||
 | 
			
		||||
            meta_color_spec_render (op->data.image.colorize_spec,
 | 
			
		||||
                                    context, &color);
 | 
			
		||||
 | 
			
		||||
            if (op->data.image.colorize_cache_pixbuf == NULL ||
 | 
			
		||||
                op->data.image.colorize_cache_pixel != GDK_COLOR_RGB (color))
 | 
			
		||||
              {
 | 
			
		||||
                if (op->data.image.colorize_cache_pixbuf)
 | 
			
		||||
                  g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf));
 | 
			
		||||
 | 
			
		||||
                /* const cast here */
 | 
			
		||||
                ((MetaDrawOp*)op)->data.image.colorize_cache_pixbuf =
 | 
			
		||||
                  colorize_pixbuf (op->data.image.pixbuf,
 | 
			
		||||
                                   &color);
 | 
			
		||||
                ((MetaDrawOp*)op)->data.image.colorize_cache_pixel =
 | 
			
		||||
                  GDK_COLOR_RGB (color);
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
            if (op->data.image.colorize_cache_pixbuf)
 | 
			
		||||
              {
 | 
			
		||||
                pixbuf = scale_and_alpha_pixbuf (op->data.image.colorize_cache_pixbuf,
 | 
			
		||||
                                                 op->data.image.alpha_spec,
 | 
			
		||||
                                                 op->data.image.fill_type,
 | 
			
		||||
                                                 width, height,
 | 
			
		||||
                                                 op->data.image.vertical_stripes,
 | 
			
		||||
                                                 op->data.image.horizontal_stripes);
 | 
			
		||||
              }
 | 
			
		||||
          }
 | 
			
		||||
        else
 | 
			
		||||
          {
 | 
			
		||||
            pixbuf = scale_and_alpha_pixbuf (op->data.image.pixbuf,
 | 
			
		||||
                                             op->data.image.alpha_spec,
 | 
			
		||||
                                             op->data.image.fill_type,
 | 
			
		||||
                                             width, height,
 | 
			
		||||
                                             op->data.image.vertical_stripes,
 | 
			
		||||
                                             op->data.image.horizontal_stripes);
 | 
			
		||||
          }
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    case META_DRAW_ICON:
 | 
			
		||||
      if (info->mini_icon &&
 | 
			
		||||
          width <= gdk_pixbuf_get_width (info->mini_icon) &&
 | 
			
		||||
          height <= gdk_pixbuf_get_height (info->mini_icon))
 | 
			
		||||
        pixbuf = scale_and_alpha_pixbuf (info->mini_icon,
 | 
			
		||||
                                         op->data.icon.alpha_spec,
 | 
			
		||||
                                         op->data.icon.fill_type,
 | 
			
		||||
                                         width, height,
 | 
			
		||||
                                         FALSE, FALSE);
 | 
			
		||||
      else if (info->icon)
 | 
			
		||||
        pixbuf = scale_and_alpha_pixbuf (info->icon,
 | 
			
		||||
                                         op->data.icon.alpha_spec,
 | 
			
		||||
                                         op->data.icon.fill_type,
 | 
			
		||||
                                         width, height,
 | 
			
		||||
                                         FALSE, FALSE);
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case META_DRAW_LINE:
 | 
			
		||||
    case META_DRAW_RECTANGLE:
 | 
			
		||||
    case META_DRAW_ARC:
 | 
			
		||||
    case META_DRAW_CLIP:
 | 
			
		||||
    case META_DRAW_GTK_ARROW:
 | 
			
		||||
    case META_DRAW_GTK_BOX:
 | 
			
		||||
    case META_DRAW_GTK_VLINE:
 | 
			
		||||
    case META_DRAW_TITLE:
 | 
			
		||||
    case META_DRAW_OP_LIST:
 | 
			
		||||
    case META_DRAW_TILE:
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return pixbuf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
fill_env (MetaPositionExprEnv *env,
 | 
			
		||||
          const MetaDrawInfo  *info,
 | 
			
		||||
@@ -3578,6 +3128,86 @@ fill_env (MetaPositionExprEnv *env,
 | 
			
		||||
  env->theme = meta_current_theme;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static cairo_pattern_t *
 | 
			
		||||
meta_alpha_gradient_spec_pattern (const MetaAlphaGradientSpec *alpha_spec)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
  /* Hardcoded in theme-parser.c */
 | 
			
		||||
  g_assert (alpha_spec->type == META_GRADIENT_HORIZONTAL);
 | 
			
		||||
 | 
			
		||||
  int n_alphas = alpha_spec->n_alphas;
 | 
			
		||||
  if (n_alphas == 0)
 | 
			
		||||
    return NULL;
 | 
			
		||||
  else if (n_alphas == 1)
 | 
			
		||||
    return cairo_pattern_create_rgba (0, 0, 0, alpha_spec->alphas[0]);
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      cairo_pattern_t *pattern = cairo_pattern_create_linear (0, 0, 1, 0);
 | 
			
		||||
      int i;
 | 
			
		||||
 | 
			
		||||
      for (i = 0; i < n_alphas; i++)
 | 
			
		||||
        cairo_pattern_add_color_stop_rgba (pattern,
 | 
			
		||||
                                           i / (float) n_alphas,
 | 
			
		||||
                                           0, 0, 0, alpha_spec->alphas[i]);
 | 
			
		||||
 | 
			
		||||
      return pattern;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
draw_image (cairo_t               *cr,
 | 
			
		||||
            GdkPixbuf             *src,
 | 
			
		||||
            MetaImageFillType      fill_type,
 | 
			
		||||
            MetaAlphaGradientSpec *alpha_spec,
 | 
			
		||||
            int                    x,
 | 
			
		||||
            int                    y,
 | 
			
		||||
            int                    width,
 | 
			
		||||
            int                    height)
 | 
			
		||||
{
 | 
			
		||||
  cairo_save (cr);
 | 
			
		||||
 | 
			
		||||
  cairo_rectangle (cr, x, y, width, height);
 | 
			
		||||
 | 
			
		||||
  if (fill_type == META_IMAGE_FILL_TILE)
 | 
			
		||||
    {
 | 
			
		||||
      gdk_cairo_set_source_pixbuf (cr, src, 0, 0);
 | 
			
		||||
 | 
			
		||||
      cairo_pattern_set_extend (cairo_get_source (cr),
 | 
			
		||||
                                CAIRO_EXTEND_REPEAT);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      float pixbuf_width, pixbuf_height;
 | 
			
		||||
 | 
			
		||||
      pixbuf_width = gdk_pixbuf_get_width (src);
 | 
			
		||||
      pixbuf_height = gdk_pixbuf_get_height (src);
 | 
			
		||||
 | 
			
		||||
      cairo_save (cr);
 | 
			
		||||
      cairo_translate (cr, x, y);
 | 
			
		||||
      cairo_scale (cr,
 | 
			
		||||
                   pixbuf_width / width,
 | 
			
		||||
                   pixbuf_height / height);
 | 
			
		||||
 | 
			
		||||
      gdk_cairo_set_source_pixbuf (cr, src, 0, 0);
 | 
			
		||||
      cairo_restore (cr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (alpha_spec)
 | 
			
		||||
    {
 | 
			
		||||
      cairo_translate (cr, x, y);
 | 
			
		||||
      cairo_scale (cr, width, height);
 | 
			
		||||
 | 
			
		||||
      cairo_pattern_t *pattern = meta_alpha_gradient_spec_pattern (alpha_spec);
 | 
			
		||||
      cairo_mask (cr, pattern);
 | 
			
		||||
      cairo_pattern_destroy (pattern);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      cairo_fill (cr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  cairo_restore (cr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* This code was originally rendering anti-aliased using X primitives, and
 | 
			
		||||
 * now has been switched to draw anti-aliased using cairo. In general, the
 | 
			
		||||
@@ -3601,7 +3231,6 @@ meta_draw_op_draw_with_env (const MetaDrawOp    *op,
 | 
			
		||||
  GdkRGBA color;
 | 
			
		||||
 | 
			
		||||
  cairo_save (cr);
 | 
			
		||||
  gtk_style_context_save (style_gtk);
 | 
			
		||||
 | 
			
		||||
  cairo_set_line_width (cr, 1.0);
 | 
			
		||||
 | 
			
		||||
@@ -3759,94 +3388,63 @@ meta_draw_op_draw_with_env (const MetaDrawOp    *op,
 | 
			
		||||
    case META_DRAW_TINT:
 | 
			
		||||
      {
 | 
			
		||||
        int rx, ry, rwidth, rheight;
 | 
			
		||||
        gboolean needs_alpha;
 | 
			
		||||
 | 
			
		||||
        needs_alpha = op->data.tint.alpha_spec &&
 | 
			
		||||
          (op->data.tint.alpha_spec->n_alphas > 1 ||
 | 
			
		||||
           op->data.tint.alpha_spec->alphas[0] != 0xff);
 | 
			
		||||
 | 
			
		||||
        rx = parse_x_position_unchecked (op->data.tint.x, env);
 | 
			
		||||
        ry = parse_y_position_unchecked (op->data.tint.y, env);
 | 
			
		||||
        rwidth = parse_size_unchecked (op->data.tint.width, env);
 | 
			
		||||
        rheight = parse_size_unchecked (op->data.tint.height, env);
 | 
			
		||||
 | 
			
		||||
        if (!needs_alpha)
 | 
			
		||||
          {
 | 
			
		||||
            meta_color_spec_render (op->data.tint.color_spec,
 | 
			
		||||
                                    style_gtk, &color);
 | 
			
		||||
            gdk_cairo_set_source_rgba (cr, &color);
 | 
			
		||||
        meta_color_spec_render (op->data.tint.color_spec,
 | 
			
		||||
                                style_gtk, &color);
 | 
			
		||||
 | 
			
		||||
            cairo_rectangle (cr, rx, ry, rwidth, rheight);
 | 
			
		||||
            cairo_fill (cr);
 | 
			
		||||
          }
 | 
			
		||||
        else
 | 
			
		||||
          {
 | 
			
		||||
            GdkPixbuf *pixbuf;
 | 
			
		||||
        if (op->data.tint.alpha_spec &&
 | 
			
		||||
            op->data.tint.alpha_spec->n_alphas == 1)
 | 
			
		||||
          color.alpha = op->data.tint.alpha_spec->alphas[0];
 | 
			
		||||
 | 
			
		||||
            pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
 | 
			
		||||
                                        rwidth, rheight);
 | 
			
		||||
        gdk_cairo_set_source_rgba (cr, &color);
 | 
			
		||||
 | 
			
		||||
            if (pixbuf)
 | 
			
		||||
              {
 | 
			
		||||
                gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
 | 
			
		||||
                cairo_paint (cr);
 | 
			
		||||
 | 
			
		||||
                g_object_unref (G_OBJECT (pixbuf));
 | 
			
		||||
              }
 | 
			
		||||
          }
 | 
			
		||||
        cairo_rectangle (cr, rx, ry, rwidth, rheight);
 | 
			
		||||
        cairo_fill (cr);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case META_DRAW_GRADIENT:
 | 
			
		||||
      {
 | 
			
		||||
        int rx, ry, rwidth, rheight;
 | 
			
		||||
        GdkPixbuf *pixbuf;
 | 
			
		||||
 | 
			
		||||
        rx = parse_x_position_unchecked (op->data.gradient.x, env);
 | 
			
		||||
        ry = parse_y_position_unchecked (op->data.gradient.y, env);
 | 
			
		||||
        rwidth = parse_size_unchecked (op->data.gradient.width, env);
 | 
			
		||||
        rheight = parse_size_unchecked (op->data.gradient.height, env);
 | 
			
		||||
 | 
			
		||||
        pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
 | 
			
		||||
                                    rwidth, rheight);
 | 
			
		||||
 | 
			
		||||
        if (pixbuf)
 | 
			
		||||
          {
 | 
			
		||||
            gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
 | 
			
		||||
            cairo_paint (cr);
 | 
			
		||||
 | 
			
		||||
            g_object_unref (G_OBJECT (pixbuf));
 | 
			
		||||
          }
 | 
			
		||||
        meta_gradient_spec_render (op->data.gradient.gradient_spec,
 | 
			
		||||
                                   op->data.gradient.alpha_spec,
 | 
			
		||||
                                   cr, style_gtk,
 | 
			
		||||
                                   rx, ry, rwidth, rheight);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case META_DRAW_IMAGE:
 | 
			
		||||
      {
 | 
			
		||||
        int rx, ry, rwidth, rheight;
 | 
			
		||||
        GdkPixbuf *pixbuf;
 | 
			
		||||
 | 
			
		||||
        if (op->data.image.pixbuf)
 | 
			
		||||
          {
 | 
			
		||||
            env->object_width = gdk_pixbuf_get_width (op->data.image.pixbuf);
 | 
			
		||||
            env->object_height = gdk_pixbuf_get_height (op->data.image.pixbuf);
 | 
			
		||||
          }
 | 
			
		||||
        if (op->data.image.pixbuf == NULL)
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        env->object_width = gdk_pixbuf_get_width (op->data.image.pixbuf);
 | 
			
		||||
        env->object_height = gdk_pixbuf_get_height (op->data.image.pixbuf);
 | 
			
		||||
 | 
			
		||||
        rx = parse_x_position_unchecked (op->data.image.x, env);
 | 
			
		||||
        ry = parse_y_position_unchecked (op->data.image.y, env);
 | 
			
		||||
 | 
			
		||||
        rwidth = parse_size_unchecked (op->data.image.width, env);
 | 
			
		||||
        rheight = parse_size_unchecked (op->data.image.height, env);
 | 
			
		||||
 | 
			
		||||
        pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
 | 
			
		||||
                                    rwidth, rheight);
 | 
			
		||||
 | 
			
		||||
        if (pixbuf)
 | 
			
		||||
          {
 | 
			
		||||
            rx = parse_x_position_unchecked (op->data.image.x, env);
 | 
			
		||||
            ry = parse_y_position_unchecked (op->data.image.y, env);
 | 
			
		||||
 | 
			
		||||
            gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
 | 
			
		||||
            cairo_paint (cr);
 | 
			
		||||
 | 
			
		||||
            g_object_unref (G_OBJECT (pixbuf));
 | 
			
		||||
          }
 | 
			
		||||
        draw_image (cr,
 | 
			
		||||
                    op->data.image.pixbuf,
 | 
			
		||||
                    op->data.image.fill_type,
 | 
			
		||||
                    op->data.image.alpha_spec,
 | 
			
		||||
                    rx, ry, rwidth, rheight);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
@@ -3916,24 +3514,27 @@ meta_draw_op_draw_with_env (const MetaDrawOp    *op,
 | 
			
		||||
    case META_DRAW_ICON:
 | 
			
		||||
      {
 | 
			
		||||
        int rx, ry, rwidth, rheight;
 | 
			
		||||
        GdkPixbuf *pixbuf;
 | 
			
		||||
        GdkPixbuf *src;
 | 
			
		||||
 | 
			
		||||
        rwidth = parse_size_unchecked (op->data.icon.width, env);
 | 
			
		||||
        rheight = parse_size_unchecked (op->data.icon.height, env);
 | 
			
		||||
 | 
			
		||||
        pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
 | 
			
		||||
                                    rwidth, rheight);
 | 
			
		||||
        if (info->mini_icon &&
 | 
			
		||||
            rwidth < gdk_pixbuf_get_width (info->mini_icon) &&
 | 
			
		||||
            rheight < gdk_pixbuf_get_height (info->mini_icon))
 | 
			
		||||
          src = info->mini_icon;
 | 
			
		||||
        else if (info->icon)
 | 
			
		||||
          src = info->icon;
 | 
			
		||||
        else
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        if (pixbuf)
 | 
			
		||||
          {
 | 
			
		||||
            rx = parse_x_position_unchecked (op->data.icon.x, env);
 | 
			
		||||
            ry = parse_y_position_unchecked (op->data.icon.y, env);
 | 
			
		||||
        rx = parse_x_position_unchecked (op->data.icon.x, env);
 | 
			
		||||
        ry = parse_y_position_unchecked (op->data.icon.y, env);
 | 
			
		||||
 | 
			
		||||
            gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
 | 
			
		||||
            cairo_paint (cr);
 | 
			
		||||
 | 
			
		||||
            g_object_unref (G_OBJECT (pixbuf));
 | 
			
		||||
          }
 | 
			
		||||
        draw_image (cr, src,
 | 
			
		||||
                    op->data.icon.fill_type,
 | 
			
		||||
                    op->data.icon.alpha_spec,
 | 
			
		||||
                    rx, ry, rwidth, rheight);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
@@ -4053,7 +3654,6 @@ meta_draw_op_draw_with_env (const MetaDrawOp    *op,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  cairo_restore (cr);
 | 
			
		||||
  gtk_style_context_restore (style_gtk);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
 
 | 
			
		||||
@@ -518,10 +518,11 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
 | 
			
		||||
 | 
			
		||||
      clutter_input_device_get_coords (pointer->device, NULL, &pos);
 | 
			
		||||
 | 
			
		||||
      meta_window_handle_enter (pointer->focus_surface->window,
 | 
			
		||||
                                /* XXX -- can we reliably get a timestamp for setting focus? */
 | 
			
		||||
                                clutter_get_current_event_time (),
 | 
			
		||||
                                pos.x, pos.y);
 | 
			
		||||
      if (pointer->focus_surface->window)
 | 
			
		||||
        meta_window_handle_enter (pointer->focus_surface->window,
 | 
			
		||||
                                  /* XXX -- can we reliably get a timestamp for setting focus? */
 | 
			
		||||
                                  clutter_get_current_event_time (),
 | 
			
		||||
                                  pos.x, pos.y);
 | 
			
		||||
 | 
			
		||||
      move_resources_for_client (&pointer->focus_resource_list,
 | 
			
		||||
                                 &pointer->resource_list,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user