1 /* GIO - GLib Input, Output and Streaming Library 2 * 3 * Copyright (C) 2006-2007 Red Hat, Inc. 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General 16 * Public License along with this library; if not, write to the 17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, 18 * Boston, MA 02111-1307, USA. 19 * 20 * Author: Alexander Larsson <alexl (at) redhat.com> 21 */ 22 23 #include "config.h" 24 25 #include "gfileicon.h" 26 #include "gfile.h" 27 #include "gicon.h" 28 #include "glibintl.h" 29 #include "gloadableicon.h" 30 #include "ginputstream.h" 31 #include "gsimpleasyncresult.h" 32 #include "gioerror.h" 33 34 #include "gioalias.h" 35 36 /** 37 * SECTION:gfileicon 38 * @short_description: Icons pointing to an image file 39 * @include: gio/gio.h 40 * @see_also: #GIcon, #GLoadableIcon 41 * 42 * #GFileIcon specifies an icon by pointing to an image file 43 * to be used as icon. 44 * 45 **/ 46 47 static void g_file_icon_icon_iface_init (GIconIface *iface); 48 static void g_file_icon_loadable_icon_iface_init (GLoadableIconIface *iface); 49 static void g_file_icon_load_async (GLoadableIcon *icon, 50 int size, 51 GCancellable *cancellable, 52 GAsyncReadyCallback callback, 53 gpointer user_data); 54 55 struct _GFileIcon 56 { 57 GObject parent_instance; 58 59 GFile *file; 60 }; 61 62 struct _GFileIconClass 63 { 64 GObjectClass parent_class; 65 }; 66 67 enum 68 { 69 PROP_0, 70 PROP_FILE 71 }; 72 73 G_DEFINE_TYPE_WITH_CODE (GFileIcon, g_file_icon, G_TYPE_OBJECT, 74 G_IMPLEMENT_INTERFACE (G_TYPE_ICON, 75 g_file_icon_icon_iface_init) 76 G_IMPLEMENT_INTERFACE (G_TYPE_LOADABLE_ICON, 77 g_file_icon_loadable_icon_iface_init)) 78 79 static void 80 g_file_icon_get_property (GObject *object, 81 guint prop_id, 82 GValue *value, 83 GParamSpec *pspec) 84 { 85 GFileIcon *icon = G_FILE_ICON (object); 86 87 switch (prop_id) 88 { 89 case PROP_FILE: 90 g_value_set_object (value, icon->file); 91 break; 92 93 default: 94 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 95 } 96 } 97 98 static void 99 g_file_icon_set_property (GObject *object, 100 guint prop_id, 101 const GValue *value, 102 GParamSpec *pspec) 103 { 104 GFileIcon *icon = G_FILE_ICON (object); 105 106 switch (prop_id) 107 { 108 case PROP_FILE: 109 icon->file = G_FILE (g_value_dup_object (value)); 110 break; 111 112 default: 113 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 114 } 115 } 116 117 static void 118 g_file_icon_finalize (GObject *object) 119 { 120 GFileIcon *icon; 121 122 icon = G_FILE_ICON (object); 123 124 g_object_unref (icon->file); 125 126 G_OBJECT_CLASS (g_file_icon_parent_class)->finalize (object); 127 } 128 129 static void 130 g_file_icon_class_init (GFileIconClass *klass) 131 { 132 GObjectClass *gobject_class = G_OBJECT_CLASS (klass); 133 134 gobject_class->get_property = g_file_icon_get_property; 135 gobject_class->set_property = g_file_icon_set_property; 136 gobject_class->finalize = g_file_icon_finalize; 137 138 /** 139 * GFileIcon:file: 140 * 141 * The file containing the icon. 142 */ 143 g_object_class_install_property (gobject_class, PROP_FILE, 144 g_param_spec_object ("file", 145 _("file"), 146 _("The file containing the icon"), 147 G_TYPE_FILE, 148 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); 149 } 150 151 static void 152 g_file_icon_init (GFileIcon *file) 153 { 154 } 155 156 /** 157 * g_file_icon_new: 158 * @file: a #GFile. 159 * 160 * Creates a new icon for a file. 161 * 162 * Returns: a #GIcon for the given @file, or %NULL on error. 163 **/ 164 GIcon * 165 g_file_icon_new (GFile *file) 166 { 167 g_return_val_if_fail (G_IS_FILE (file), NULL); 168 169 return G_ICON (g_object_new (G_TYPE_FILE_ICON, "file", file, NULL)); 170 } 171 172 /** 173 * g_file_icon_get_file: 174 * @icon: a #GIcon. 175 * 176 * Gets the #GFile associated with the given @icon. 177 * 178 * Returns: a #GFile, or %NULL. 179 **/ 180 GFile * 181 g_file_icon_get_file (GFileIcon *icon) 182 { 183 g_return_val_if_fail (G_IS_FILE_ICON (icon), NULL); 184 185 return icon->file; 186 } 187 188 static guint 189 g_file_icon_hash (GIcon *icon) 190 { 191 GFileIcon *file_icon = G_FILE_ICON (icon); 192 193 return g_file_hash (file_icon->file); 194 } 195 196 static gboolean 197 g_file_icon_equal (GIcon *icon1, 198 GIcon *icon2) 199 { 200 GFileIcon *file1 = G_FILE_ICON (icon1); 201 GFileIcon *file2 = G_FILE_ICON (icon2); 202 203 return g_file_equal (file1->file, file2->file); 204 } 205 206 static gboolean 207 g_file_icon_to_tokens (GIcon *icon, 208 GPtrArray *tokens, 209 gint *out_version) 210 { 211 GFileIcon *file_icon = G_FILE_ICON (icon); 212 213 g_return_val_if_fail (out_version != NULL, FALSE); 214 215 *out_version = 0; 216 217 g_ptr_array_add (tokens, g_file_get_uri (file_icon->file)); 218 return TRUE; 219 } 220 221 static GIcon * 222 g_file_icon_from_tokens (gchar **tokens, 223 gint num_tokens, 224 gint version, 225 GError **error) 226 { 227 GIcon *icon; 228 GFile *file; 229 230 icon = NULL; 231 232 if (version != 0) 233 { 234 g_set_error (error, 235 G_IO_ERROR, 236 G_IO_ERROR_INVALID_ARGUMENT, 237 _("Can't handle version %d of GFileIcon encoding"), 238 version); 239 goto out; 240 } 241 242 if (num_tokens != 1) 243 { 244 g_set_error_literal (error, 245 G_IO_ERROR, 246 G_IO_ERROR_INVALID_ARGUMENT, 247 _("Malformed input data for GFileIcon")); 248 goto out; 249 } 250 251 file = g_file_new_for_uri (tokens[0]); 252 icon = g_file_icon_new (file); 253 g_object_unref (file); 254 255 out: 256 return icon; 257 } 258 259 static void 260 g_file_icon_icon_iface_init (GIconIface *iface) 261 { 262 iface->hash = g_file_icon_hash; 263 iface->equal = g_file_icon_equal; 264 iface->to_tokens = g_file_icon_to_tokens; 265 iface->from_tokens = g_file_icon_from_tokens; 266 } 267 268 269 static GInputStream * 270 g_file_icon_load (GLoadableIcon *icon, 271 int size, 272 char **type, 273 GCancellable *cancellable, 274 GError **error) 275 { 276 GFileInputStream *stream; 277 GFileIcon *file_icon = G_FILE_ICON (icon); 278 279 stream = g_file_read (file_icon->file, 280 cancellable, 281 error); 282 283 return G_INPUT_STREAM (stream); 284 } 285 286 typedef struct { 287 GLoadableIcon *icon; 288 GAsyncReadyCallback callback; 289 gpointer user_data; 290 } LoadData; 291 292 static void 293 load_data_free (LoadData *data) 294 { 295 g_object_unref (data->icon); 296 g_free (data); 297 } 298 299 static void 300 load_async_callback (GObject *source_object, 301 GAsyncResult *res, 302 gpointer user_data) 303 { 304 GFileInputStream *stream; 305 GError *error = NULL; 306 GSimpleAsyncResult *simple; 307 LoadData *data = user_data; 308 309 stream = g_file_read_finish (G_FILE (source_object), res, &error); 310 311 if (stream == NULL) 312 { 313 simple = g_simple_async_result_new_from_error (G_OBJECT (data->icon), 314 data->callback, 315 data->user_data, 316 error); 317 g_error_free (error); 318 } 319 else 320 { 321 simple = g_simple_async_result_new (G_OBJECT (data->icon), 322 data->callback, 323 data->user_data, 324 g_file_icon_load_async); 325 326 g_simple_async_result_set_op_res_gpointer (simple, 327 stream, 328 g_object_unref); 329 } 330 331 332 g_simple_async_result_complete (simple); 333 334 load_data_free (data); 335 } 336 337 static void 338 g_file_icon_load_async (GLoadableIcon *icon, 339 int size, 340 GCancellable *cancellable, 341 GAsyncReadyCallback callback, 342 gpointer user_data) 343 { 344 GFileIcon *file_icon = G_FILE_ICON (icon); 345 LoadData *data; 346 347 data = g_new0 (LoadData, 1); 348 data->icon = g_object_ref (icon); 349 data->callback = callback; 350 data->user_data = user_data; 351 352 g_file_read_async (file_icon->file, 0, 353 cancellable, 354 load_async_callback, data); 355 356 } 357 358 static GInputStream * 359 g_file_icon_load_finish (GLoadableIcon *icon, 360 GAsyncResult *res, 361 char **type, 362 GError **error) 363 { 364 GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res); 365 gpointer op; 366 367 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_file_icon_load_async); 368 369 if (type) 370 *type = NULL; 371 372 op = g_simple_async_result_get_op_res_gpointer (simple); 373 if (op) 374 return g_object_ref (op); 375 376 return NULL; 377 } 378 379 static void 380 g_file_icon_loadable_icon_iface_init (GLoadableIconIface *iface) 381 { 382 iface->load = g_file_icon_load; 383 iface->load_async = g_file_icon_load_async; 384 iface->load_finish = g_file_icon_load_finish; 385 } 386 387 #define __G_FILE_ICON_C__ 388 #include "gioaliasdef.c" 389