~darkxst/ubuntu/saucy/gnome-shell/upstart_log

« back to all changes in this revision

Viewing changes to src/st/st-texture-cache.c

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha
  • Date: 2013-05-31 12:01:12 UTC
  • mfrom: (1.1.49) (19.1.36 experimental)
  • Revision ID: package-import@ubuntu.com-20130531120112-ew91khxf051x9i2r
Tags: 3.8.2-1ubuntu1
* Merge with Debian (LP: #1185869, #1185721). Remaining changes:
  - debian/control.in:
    + Build-depend on libsystemd-login-dev & libsystemd-daemon-dev
    + Depend on gdm instead of gdm3
    + Don't recommend gnome-session-fallback
  - debian/patches/40_change-pam-name-to-match-gdm.patch:
  - debian/patches/revert-suspend-break.patch:
    + Disabled, not needed on Ubuntu
  - debian/patches/ubuntu-lightdm-user-switching.patch:
    + Allow user switching when using LightDM. Thanks Gerhard Stein
      for rebasing against gnome-shell 3.8!
  - debian/patches/ubuntu_lock_on_suspend.patch
    + Respect Ubuntu's lock-on-suspend setting.
      Disabled until it can be rewritten.
  - debian/patches/git_relock_screen_after_crash.patch:
    + Add Upstream fix for unlocked session after crash (LP: #1064584)
* Note that the new GNOME Classic mode (which requires installing
  gnome-shell-extensions) won't work until gnome-session 3.8 is
  available in Ubuntu

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
#define CACHE_PREFIX_ICON "icon:"
31
31
#define CACHE_PREFIX_URI "uri:"
32
32
#define CACHE_PREFIX_URI_FOR_CAIRO "uri-for-cairo:"
33
 
#define CACHE_PREFIX_RAW_CHECKSUM "raw-checksum:"
34
 
#define CACHE_PREFIX_COMPRESSED_CHECKSUM "compressed-checksum:"
35
33
 
36
34
struct _StTextureCachePrivate
37
35
{
42
40
 
43
41
  /* Presently this is used to de-duplicate requests for GIcons and async URIs. */
44
42
  GHashTable *outstanding_requests; /* char * -> AsyncTextureLoadData * */
 
43
 
 
44
  /* File monitors to evict cache data on changes */
 
45
  GHashTable *file_monitors; /* char * -> GFileMonitor * */
45
46
};
46
47
 
47
48
static void st_texture_cache_dispose (GObject *object);
50
51
enum
51
52
{
52
53
  ICON_THEME_CHANGED,
 
54
  TEXTURE_FILE_CHANGED,
53
55
 
54
56
  LAST_SIGNAL
55
57
};
92
94
                  0, /* no default handler slot */
93
95
                  NULL, NULL, NULL,
94
96
                  G_TYPE_NONE, 0);
95
 
}
96
 
 
97
 
/**
98
 
 * st_texture_cache_clear_uri:
99
 
 * @cache: A #StTextureCache
100
 
 * @uri: URI of cached object
101
 
 *
102
 
 * If the given @uri is known to have been modified
103
 
 * externally, this function may be used to invalidate
104
 
 * the in-memory cache.
105
 
 */
106
 
void
107
 
st_texture_cache_clear_uri (StTextureCache *cache,
108
 
                            const char     *uri)
109
 
{
110
 
  char *key;
111
 
 
112
 
  g_return_if_fail (ST_IS_TEXTURE_CACHE (cache));
113
 
  g_return_if_fail (uri != NULL);
114
 
 
115
 
  key = g_strconcat (CACHE_PREFIX_URI, uri, NULL);
116
 
  g_hash_table_remove (cache->priv->keyed_cache, key);
117
 
  g_free (key);
118
 
 
119
 
  key = g_strconcat (CACHE_PREFIX_URI_FOR_CAIRO, uri, NULL);
120
 
  g_hash_table_remove (cache->priv->keyed_cache, key);
121
 
  g_free (key);
 
97
 
 
98
  signals[TEXTURE_FILE_CHANGED] =
 
99
    g_signal_new ("texture-file-changed",
 
100
                  G_TYPE_FROM_CLASS (klass),
 
101
                  G_SIGNAL_RUN_LAST,
 
102
                  0, /* no default handler slot */
 
103
                  NULL, NULL, NULL,
 
104
                  G_TYPE_NONE, 1, G_TYPE_STRING);
122
105
}
123
106
 
124
107
/* Evicts all cached textures for named icons */
164
147
                                                   g_free, cogl_handle_unref);
165
148
  self->priv->outstanding_requests = g_hash_table_new_full (g_str_hash, g_str_equal,
166
149
                                                            g_free, NULL);
 
150
  self->priv->file_monitors = g_hash_table_new_full (g_str_hash, g_str_equal,
 
151
                                                     g_object_unref, g_object_unref);
 
152
 
167
153
}
168
154
 
169
155
static void
179
165
      self->priv->icon_theme = NULL;
180
166
    }
181
167
 
182
 
  if (self->priv->keyed_cache)
183
 
    g_hash_table_destroy (self->priv->keyed_cache);
184
 
  self->priv->keyed_cache = NULL;
185
 
 
186
 
  if (self->priv->outstanding_requests)
187
 
    g_hash_table_destroy (self->priv->outstanding_requests);
188
 
  self->priv->outstanding_requests = NULL;
 
168
  g_clear_pointer (&self->priv->keyed_cache, g_hash_table_destroy);
 
169
  g_clear_pointer (&self->priv->outstanding_requests, g_hash_table_destroy);
 
170
  g_clear_pointer (&self->priv->file_monitors, g_hash_table_destroy);
189
171
 
190
172
  G_OBJECT_CLASS (st_texture_cache_parent_class)->dispose (object);
191
173
}
258
240
  rgba->alpha = color->alpha / 255.;
259
241
}
260
242
 
261
 
static GdkPixbuf *
262
 
impl_load_pixbuf_gicon (GtkIconInfo  *info,
263
 
                        int           size,
264
 
                        StIconColors *colors,
265
 
                        GError      **error)
266
 
{
267
 
  int scaled_width, scaled_height;
268
 
  GdkPixbuf *pixbuf;
269
 
  int width, height;
270
 
 
271
 
  if (colors)
272
 
    {
273
 
      GdkRGBA foreground_color;
274
 
      GdkRGBA success_color;
275
 
      GdkRGBA warning_color;
276
 
      GdkRGBA error_color;
277
 
 
278
 
      rgba_from_clutter (&foreground_color, &colors->foreground);
279
 
      rgba_from_clutter (&success_color, &colors->success);
280
 
      rgba_from_clutter (&warning_color, &colors->warning);
281
 
      rgba_from_clutter (&error_color, &colors->error);
282
 
 
283
 
      pixbuf = gtk_icon_info_load_symbolic (info,
284
 
                                            &foreground_color, &success_color,
285
 
                                            &warning_color, &error_color,
286
 
                                            NULL, error);
287
 
    }
288
 
  else
289
 
    {
290
 
      pixbuf = gtk_icon_info_load_icon (info, error);
291
 
    }
292
 
 
293
 
  if (!pixbuf)
294
 
    return NULL;
295
 
 
296
 
  width = gdk_pixbuf_get_width (pixbuf);
297
 
  height = gdk_pixbuf_get_height (pixbuf);
298
 
 
299
 
  if (compute_pixbuf_scale (width,
300
 
                            height,
301
 
                            size, size,
302
 
                            &scaled_width, &scaled_height))
303
 
    {
304
 
      GdkPixbuf *scaled = gdk_pixbuf_scale_simple (pixbuf, width, height, GDK_INTERP_BILINEAR);
305
 
      g_object_unref (pixbuf);
306
 
      pixbuf = scaled;
307
 
    }
308
 
  return pixbuf;
309
 
}
310
 
 
311
243
/* A private structure for keeping width and height. */
312
244
typedef struct {
313
245
  int width;
334
266
} AsyncTextureLoadData;
335
267
 
336
268
static void
337
 
texture_load_data_destroy (gpointer p)
 
269
texture_load_data_free (gpointer p)
338
270
{
339
271
  AsyncTextureLoadData *data = p;
340
272
 
352
284
 
353
285
  if (data->textures)
354
286
    g_slist_free_full (data->textures, (GDestroyNotify) g_object_unref);
 
287
 
 
288
  g_free (data);
355
289
}
356
290
 
357
291
/**
558
492
 
559
493
  data = g_async_result_get_user_data (G_ASYNC_RESULT (result));
560
494
  g_assert (data != NULL);
 
495
  g_assert (data->uri != NULL);
561
496
 
562
 
  if (data->uri)
563
 
    pixbuf = impl_load_pixbuf_file (data->uri, data->width, data->height, &error);
564
 
  else if (data->icon_info)
565
 
    pixbuf = impl_load_pixbuf_gicon (data->icon_info, data->width, data->colors, &error);
566
 
  else
567
 
    g_assert_not_reached ();
 
497
  pixbuf = impl_load_pixbuf_file (data->uri, data->width, data->height, &error);
568
498
 
569
499
  if (error != NULL)
570
500
    {
665
595
}
666
596
 
667
597
static void
668
 
on_pixbuf_loaded (GObject      *source,
669
 
                  GAsyncResult *result,
670
 
                  gpointer      user_data)
 
598
finish_texture_load (AsyncTextureLoadData *data,
 
599
                     GdkPixbuf            *pixbuf)
671
600
{
672
601
  GSList *iter;
673
602
  StTextureCache *cache;
674
 
  AsyncTextureLoadData *data;
675
 
  GdkPixbuf *pixbuf;
676
 
  GError *error = NULL;
677
603
  CoglHandle texdata = NULL;
678
604
 
679
 
  data = user_data;
680
 
  cache = ST_TEXTURE_CACHE (source);
 
605
  cache = data->cache;
681
606
 
682
607
  g_hash_table_remove (cache->priv->outstanding_requests, data->key);
683
608
 
684
 
  pixbuf = load_pixbuf_async_finish (cache, result, &error);
685
609
  if (pixbuf == NULL)
686
610
    goto out;
687
611
 
688
612
  texdata = pixbuf_to_cogl_handle (pixbuf, data->enforced_square);
689
613
 
690
 
  g_object_unref (pixbuf);
691
 
 
692
614
  if (data->policy != ST_TEXTURE_CACHE_POLICY_NONE)
693
615
    {
694
616
      gpointer orig_key, value;
712
634
  if (texdata)
713
635
    cogl_handle_unref (texdata);
714
636
 
715
 
  texture_load_data_destroy (data);
716
 
  g_free (data);
717
 
 
718
 
  g_clear_error (&error);
 
637
  texture_load_data_free (data);
 
638
}
 
639
 
 
640
static void
 
641
on_symbolic_icon_loaded (GObject      *source,
 
642
                         GAsyncResult *result,
 
643
                         gpointer      user_data)
 
644
{
 
645
  GdkPixbuf *pixbuf;
 
646
  pixbuf = gtk_icon_info_load_symbolic_finish (GTK_ICON_INFO (source), result, NULL, NULL);
 
647
  finish_texture_load (user_data, pixbuf);
 
648
  g_clear_object (&pixbuf);
 
649
}
 
650
 
 
651
static void
 
652
on_icon_loaded (GObject      *source,
 
653
                GAsyncResult *result,
 
654
                gpointer      user_data)
 
655
{
 
656
  GdkPixbuf *pixbuf;
 
657
  pixbuf = gtk_icon_info_load_icon_finish (GTK_ICON_INFO (source), result, NULL);
 
658
  finish_texture_load (user_data, pixbuf);
 
659
  g_clear_object (&pixbuf);
 
660
}
 
661
 
 
662
static void
 
663
on_pixbuf_loaded (GObject      *source,
 
664
                  GAsyncResult *result,
 
665
                  gpointer      user_data)
 
666
{
 
667
  GdkPixbuf *pixbuf;
 
668
  pixbuf = load_pixbuf_async_finish (ST_TEXTURE_CACHE (source), result, NULL);
 
669
  finish_texture_load (user_data, pixbuf);
 
670
  g_clear_object (&pixbuf);
719
671
}
720
672
 
721
673
static void
722
674
load_texture_async (StTextureCache       *cache,
723
675
                    AsyncTextureLoadData *data)
724
676
{
725
 
  GSimpleAsyncResult *result;
726
 
  result = g_simple_async_result_new (G_OBJECT (cache), on_pixbuf_loaded, data, load_texture_async);
727
 
  g_simple_async_result_run_in_thread (result, load_pixbuf_thread, G_PRIORITY_DEFAULT, NULL);
728
 
  g_object_unref (result);
 
677
  if (data->uri)
 
678
    {
 
679
      GSimpleAsyncResult *result;
 
680
      result = g_simple_async_result_new (G_OBJECT (cache), on_pixbuf_loaded, data, load_texture_async);
 
681
      g_simple_async_result_run_in_thread (result, load_pixbuf_thread, G_PRIORITY_DEFAULT, NULL);
 
682
      g_object_unref (result);
 
683
    }
 
684
  else if (data->icon_info)
 
685
    {
 
686
      StIconColors *colors = data->colors;
 
687
      if (colors)
 
688
        {
 
689
          GdkRGBA foreground_color;
 
690
          GdkRGBA success_color;
 
691
          GdkRGBA warning_color;
 
692
          GdkRGBA error_color;
 
693
 
 
694
          rgba_from_clutter (&foreground_color, &colors->foreground);
 
695
          rgba_from_clutter (&success_color, &colors->success);
 
696
          rgba_from_clutter (&warning_color, &colors->warning);
 
697
          rgba_from_clutter (&error_color, &colors->error);
 
698
 
 
699
          gtk_icon_info_load_symbolic_async (data->icon_info,
 
700
                                             &foreground_color, &success_color,
 
701
                                             &warning_color, &error_color,
 
702
                                             NULL, on_symbolic_icon_loaded, data);
 
703
        }
 
704
      else
 
705
        {
 
706
          gtk_icon_info_load_icon_async (data->icon_info, NULL, on_icon_loaded, data);
 
707
        }
 
708
    }
 
709
  else
 
710
    g_assert_not_reached ();
729
711
}
730
712
 
731
713
typedef struct {
1039
1021
  return CLUTTER_ACTOR (texture);
1040
1022
}
1041
1023
 
 
1024
static void
 
1025
file_changed_cb (GFileMonitor      *monitor,
 
1026
                 GFile             *file,
 
1027
                 GFile             *other,
 
1028
                 GFileMonitorEvent  event_type,
 
1029
                 gpointer           user_data)
 
1030
{
 
1031
  StTextureCache *cache = user_data;
 
1032
  char *uri, *key;
 
1033
 
 
1034
  if (event_type != G_FILE_MONITOR_EVENT_CHANGED)
 
1035
    return;
 
1036
 
 
1037
  uri = g_file_get_uri (file);
 
1038
 
 
1039
  key = g_strconcat (CACHE_PREFIX_URI, uri, NULL);
 
1040
  g_hash_table_remove (cache->priv->keyed_cache, key);
 
1041
  g_free (key);
 
1042
 
 
1043
  key = g_strconcat (CACHE_PREFIX_URI_FOR_CAIRO, uri, NULL);
 
1044
  g_hash_table_remove (cache->priv->keyed_cache, key);
 
1045
  g_free (key);
 
1046
 
 
1047
  g_signal_emit (cache, signals[TEXTURE_FILE_CHANGED], 0, uri);
 
1048
 
 
1049
  g_free (uri);
 
1050
}
 
1051
 
 
1052
static void
 
1053
ensure_monitor_for_uri (StTextureCache *cache,
 
1054
                        const gchar    *uri)
 
1055
{
 
1056
  StTextureCachePrivate *priv = cache->priv;
 
1057
  GFile *file = g_file_new_for_uri (uri);
 
1058
 
 
1059
  if (g_hash_table_lookup (priv->file_monitors, uri) == NULL)
 
1060
    {
 
1061
      GFileMonitor *monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE,
 
1062
                                                   NULL, NULL);
 
1063
      g_signal_connect (monitor, "changed",
 
1064
                        G_CALLBACK (file_changed_cb), cache);
 
1065
      g_hash_table_insert (priv->file_monitors, g_strdup (uri), monitor);
 
1066
    }
 
1067
  g_object_unref (file);
 
1068
}
 
1069
 
1042
1070
typedef struct {
1043
1071
  gchar *path;
1044
1072
  gint   grid_width, grid_height;
1045
1073
  ClutterActor *actor;
 
1074
  GFunc load_callback;
 
1075
  gpointer load_callback_data;
1046
1076
} AsyncImageData;
1047
1077
 
1048
1078
static void
1059
1089
                        GAsyncResult *res,
1060
1090
                        gpointer user_data)
1061
1091
{
 
1092
  GObject *cache = source_object;
1062
1093
  AsyncImageData *data = (AsyncImageData *)user_data;
1063
1094
  GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
1064
1095
  GList *list;
1072
1103
      clutter_actor_hide (actor);
1073
1104
      clutter_actor_add_child (data->actor, actor);
1074
1105
    }
 
1106
 
 
1107
  if (data->load_callback != NULL)
 
1108
    data->load_callback (cache, data->load_callback_data);
1075
1109
}
1076
1110
 
1077
1111
static void
1126
1160
 * @path: Path to a filename
1127
1161
 * @grid_width: Width in pixels
1128
1162
 * @grid_height: Height in pixels
 
1163
 * @load_callback: (scope async) (allow-none): Function called when the image is loaded, or %NULL
 
1164
 * @user_data: Data to pass to the load callback
1129
1165
 *
1130
1166
 * This function reads a single image file which contains multiple images internally.
1131
1167
 * The image file will be divided using @grid_width and @grid_height;
1135
1171
 * Returns: (transfer none): A new #ClutterActor
1136
1172
 */
1137
1173
ClutterActor *
1138
 
st_texture_cache_load_sliced_image (StTextureCache    *cache,
1139
 
                                    const gchar       *path,
1140
 
                                    gint               grid_width,
1141
 
                                    gint               grid_height)
 
1174
st_texture_cache_load_sliced_image (StTextureCache *cache,
 
1175
                                    const gchar    *path,
 
1176
                                    gint            grid_width,
 
1177
                                    gint            grid_height,
 
1178
                                    GFunc           load_callback,
 
1179
                                    gpointer        user_data)
1142
1180
{
1143
1181
  AsyncImageData *data;
1144
1182
  GSimpleAsyncResult *result;
1149
1187
  data->grid_height = grid_height;
1150
1188
  data->path = g_strdup (path);
1151
1189
  data->actor = actor;
 
1190
  data->load_callback = load_callback;
 
1191
  data->load_callback_data = user_data;
1152
1192
  g_object_ref (G_OBJECT (actor));
1153
1193
 
1154
1194
  result = g_simple_async_result_new (G_OBJECT (cache), on_sliced_image_loaded, data, st_texture_cache_load_sliced_image);
1162
1202
}
1163
1203
 
1164
1204
/**
1165
 
 * st_texture_cache_load_icon_name:
1166
 
 * @cache: The texture cache instance
1167
 
 * @theme_node: (allow-none): a #StThemeNode
1168
 
 * @name: Name of a themed icon
1169
 
 * @size: Size of themed icon
1170
 
 *
1171
 
 * Load a themed icon into a texture. The colors used for symbolic
1172
 
 * icons are derived from @theme_node.
1173
 
 *
1174
 
 * Return Value: (transfer none): A new #ClutterTexture for the icon
1175
 
 */
1176
 
ClutterActor *
1177
 
st_texture_cache_load_icon_name (StTextureCache    *cache,
1178
 
                                 StThemeNode       *theme_node,
1179
 
                                 const char        *name,
1180
 
                                 gint               size)
1181
 
{
1182
 
  ClutterActor *texture;
1183
 
  GIcon *themed;
1184
 
 
1185
 
  themed = g_themed_icon_new_with_default_fallbacks (name);
1186
 
  texture = load_gicon_with_colors (cache, themed, size,
1187
 
                                    theme_node ? st_theme_node_get_icon_colors (theme_node) : NULL);
1188
 
  g_object_unref (themed);
1189
 
 
1190
 
  if (texture == NULL)
1191
 
    {
1192
 
      texture = (ClutterActor *) create_default_texture ();
1193
 
      clutter_actor_set_size (texture, size, size);
1194
 
    }
1195
 
 
1196
 
  return texture;
1197
 
}
1198
 
 
1199
 
/**
1200
1205
 * st_texture_cache_load_uri_async:
1201
1206
 * @cache: The texture cache instance
1202
1207
 * @uri: uri of the image file from which to create a pixbuf
1246
1251
      load_texture_async (cache, request);
1247
1252
    }
1248
1253
 
 
1254
  ensure_monitor_for_uri (cache, uri);
 
1255
 
1249
1256
  return CLUTTER_ACTOR (texture);
1250
1257
}
1251
1258
 
1283
1290
  else
1284
1291
    cogl_handle_ref (texdata);
1285
1292
 
 
1293
  ensure_monitor_for_uri (cache, uri);
 
1294
 
1286
1295
out:
1287
1296
  g_free (key);
1288
1297
  return texdata;
1322
1331
  else
1323
1332
    cairo_surface_reference (surface);
1324
1333
 
 
1334
  ensure_monitor_for_uri (cache, uri);
 
1335
 
1325
1336
out:
1326
1337
  g_free (key);
1327
1338
  return surface;
1401
1412
  return surface;
1402
1413
}
1403
1414
 
1404
 
/**
1405
 
 * st_texture_cache_load_from_raw:
1406
 
 * @cache: a #StTextureCache
1407
 
 * @data: (array length=len): raw pixel data
1408
 
 * @len: the length of @data
1409
 
 * @has_alpha: whether @data includes an alpha channel
1410
 
 * @width: width in pixels of @data
1411
 
 * @height: width in pixels of @data
1412
 
 * @rowstride: rowstride of @data
1413
 
 * @size: size of icon to return
1414
 
 *
1415
 
 * Creates (or retrieves from cache) an icon based on raw pixel data.
1416
 
 *
1417
 
 * Return value: (transfer none): a new #ClutterActor displaying a
1418
 
 * pixbuf created from @data and the other parameters.
1419
 
 **/
1420
 
ClutterActor *
1421
 
st_texture_cache_load_from_raw (StTextureCache    *cache,
1422
 
                                const guchar      *data,
1423
 
                                gsize              len,
1424
 
                                gboolean           has_alpha,
1425
 
                                int                width,
1426
 
                                int                height,
1427
 
                                int                rowstride,
1428
 
                                int                size,
1429
 
                                GError           **error)
1430
 
{
1431
 
  ClutterTexture *texture;
1432
 
  CoglHandle texdata;
1433
 
  char *key;
1434
 
  char *checksum;
1435
 
 
1436
 
  texture = create_default_texture ();
1437
 
  clutter_actor_set_size (CLUTTER_ACTOR (texture), size, size);
1438
 
 
1439
 
  /* In theory, two images of with different width and height could have the same
1440
 
   * pixel data and thus hash the same. (Say, a 16x16 and a 8x32 blank image.)
1441
 
   * We ignore this for now. If anybody hits this problem they should use
1442
 
   * GChecksum directly to compute a checksum including the width and height.
1443
 
   */
1444
 
  checksum = g_compute_checksum_for_data (G_CHECKSUM_SHA1, data, len);
1445
 
  key = g_strdup_printf (CACHE_PREFIX_RAW_CHECKSUM "checksum=%s", checksum);
1446
 
  g_free (checksum);
1447
 
 
1448
 
  texdata = g_hash_table_lookup (cache->priv->keyed_cache, key);
1449
 
  if (texdata == NULL)
1450
 
    {
1451
 
      texdata = data_to_cogl_handle (data, has_alpha, width, height, rowstride, TRUE);
1452
 
      g_hash_table_insert (cache->priv->keyed_cache, g_strdup (key), texdata);
1453
 
    }
1454
 
 
1455
 
  g_free (key);
1456
 
 
1457
 
  set_texture_cogl_texture (texture, texdata);
1458
 
  return CLUTTER_ACTOR (texture);
1459
 
}
1460
 
 
1461
1415
static StTextureCache *instance = NULL;
1462
1416
 
1463
1417
/**