~ubuntu-branches/ubuntu/utopic/thunar/utopic-proposed

« back to all changes in this revision

Viewing changes to .pc/menu-icon-tweaks.patch/thunar/thunar-templates-action.c

  • Committer: Package Import Robot
  • Author(s): Jackson Doak
  • Date: 2014-04-05 08:22:40 UTC
  • Revision ID: package-import@ubuntu.com-20140405082240-b3iiyypyyo3uliy3
Tags: 1.6.3-1ubuntu5
* Add git-save-keyboard-shortcuts.patch. LP: #1186846
  - Keyboard shortcuts save when changed rather than when thunar is closed
* Add menu-icon-tweaks.patch. LP: #1271861
  - Don't use generic folder icons for open with default application
  - Add icons for open in new tab, new window
* Add git-force-toolbr-icons.patch
  - Fix for "Home" and "Open Parent" icons going missing from toolbar

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id$ */
 
2
/*-
 
3
 * Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
 
4
 * Copyright (c) 2009 Jannis Pohlmann <jannis@xfce.org>
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify it
 
7
 * under the terms of the GNU General Public License as published by the Free
 
8
 * Software Foundation; either version 2 of the License, or (at your option)
 
9
 * any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful, but WITHOUT
 
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 
14
 * more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License along with
 
17
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 
18
 * Place, Suite 330, Boston, MA  02111-1307  USA
 
19
 */
 
20
 
 
21
#ifdef HAVE_CONFIG_H
 
22
#include <config.h>
 
23
#endif
 
24
 
 
25
#include <gio/gio.h>
 
26
 
 
27
#include <thunar/thunar-icon-factory.h>
 
28
#include <thunar/thunar-job.h>
 
29
#include <thunar/thunar-misc-jobs.h>
 
30
#include <thunar/thunar-private.h>
 
31
#include <thunar/thunar-templates-action.h>
 
32
 
 
33
 
 
34
 
 
35
/* Signal identifiers */
 
36
enum
 
37
{
 
38
  CREATE_EMPTY_FILE,
 
39
  CREATE_TEMPLATE,
 
40
  LAST_SIGNAL,
 
41
};
 
42
 
 
43
 
 
44
 
 
45
static void       thunar_templates_action_finalize          (GObject                    *object);
 
46
static GtkWidget *thunar_templates_action_create_menu_item  (GtkAction                  *action);
 
47
static void       thunar_templates_action_menu_shown        (GtkWidget                  *menu,
 
48
                                                             ThunarTemplatesAction      *templates_action);
 
49
 
 
50
 
 
51
 
 
52
struct _ThunarTemplatesActionClass
 
53
{
 
54
  GtkActionClass __parent__;
 
55
 
 
56
  void (*create_empty_file) (ThunarTemplatesAction *templates_action);
 
57
  void (*create_template)   (ThunarTemplatesAction *templates_action,
 
58
                             const ThunarFile      *file);
 
59
};
 
60
 
 
61
struct _ThunarTemplatesAction
 
62
{
 
63
  GtkAction  __parent__;
 
64
 
 
65
  ThunarJob *job;
 
66
};
 
67
 
 
68
 
 
69
 
 
70
static guint templates_action_signals[LAST_SIGNAL];
 
71
 
 
72
 
 
73
 
 
74
G_DEFINE_TYPE (ThunarTemplatesAction, thunar_templates_action, GTK_TYPE_ACTION)
 
75
 
 
76
 
 
77
 
 
78
static void
 
79
thunar_templates_action_class_init (ThunarTemplatesActionClass *klass)
 
80
{
 
81
  GtkActionClass *gtkaction_class;
 
82
  GObjectClass   *gobject_class;
 
83
 
 
84
  gobject_class = G_OBJECT_CLASS (klass);
 
85
  gobject_class->finalize = thunar_templates_action_finalize;
 
86
 
 
87
  gtkaction_class = GTK_ACTION_CLASS (klass);
 
88
  gtkaction_class->create_menu_item = thunar_templates_action_create_menu_item;
 
89
 
 
90
  /**
 
91
   * ThunarTemplatesAction::create-empty-file:
 
92
   * @templates_action : a #ThunarTemplatesAction.
 
93
   *
 
94
   * Emitted by @templates_action whenever the user requests to
 
95
   * create a new empty file.
 
96
   **/
 
97
  templates_action_signals[CREATE_EMPTY_FILE] =
 
98
    g_signal_new (I_("create-empty-file"),
 
99
                  G_TYPE_FROM_CLASS (klass),
 
100
                  G_SIGNAL_RUN_LAST,
 
101
                  G_STRUCT_OFFSET (ThunarTemplatesActionClass, create_empty_file),
 
102
                  NULL, NULL, g_cclosure_marshal_VOID__VOID,
 
103
                  G_TYPE_NONE, 0);
 
104
 
 
105
  /**
 
106
   * ThunarTemplatesAction::create-template:
 
107
   * @templates_action : a #ThunarTemplatesAction.
 
108
   * @file             : the #ThunarFile of the template file.
 
109
   *
 
110
   * Emitted by @templates_action whenever the user requests to
 
111
   * create a new file based on the template referred to by
 
112
   * @file.
 
113
   **/
 
114
  templates_action_signals[CREATE_TEMPLATE] =
 
115
    g_signal_new (I_("create-template"),
 
116
                  G_TYPE_FROM_CLASS (klass),
 
117
                  G_SIGNAL_RUN_LAST,
 
118
                  G_STRUCT_OFFSET (ThunarTemplatesActionClass, create_template),
 
119
                  NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
 
120
                  G_TYPE_NONE, 1, THUNAR_TYPE_FILE);
 
121
}
 
122
 
 
123
 
 
124
 
 
125
static void
 
126
thunar_templates_action_init (ThunarTemplatesAction *templates_action)
 
127
{
 
128
  templates_action->job = NULL;
 
129
}
 
130
 
 
131
 
 
132
 
 
133
static void
 
134
thunar_templates_action_finalize (GObject *object)
 
135
{
 
136
  ThunarTemplatesAction *templates_action = THUNAR_TEMPLATES_ACTION (object);
 
137
 
 
138
  if (templates_action->job != NULL)
 
139
    {
 
140
      g_signal_handlers_disconnect_matched (templates_action->job,
 
141
                                            G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL,
 
142
                                            templates_action);
 
143
      g_object_unref (templates_action->job);
 
144
    }
 
145
 
 
146
  (*G_OBJECT_CLASS (thunar_templates_action_parent_class)->finalize) (object);
 
147
}
 
148
 
 
149
 
 
150
 
 
151
static GtkWidget*
 
152
thunar_templates_action_create_menu_item (GtkAction *action)
 
153
{
 
154
  GtkWidget *item;
 
155
  GtkWidget *menu;
 
156
 
 
157
  _thunar_return_val_if_fail (THUNAR_IS_TEMPLATES_ACTION (action), NULL);
 
158
 
 
159
  /* let GtkAction allocate the menu item */
 
160
  item = (*GTK_ACTION_CLASS (thunar_templates_action_parent_class)->create_menu_item) (action);
 
161
 
 
162
  /* associate an empty submenu with the item (will be filled when shown) */
 
163
  menu = gtk_menu_new ();
 
164
  g_signal_connect (G_OBJECT (menu), "show", G_CALLBACK (thunar_templates_action_menu_shown), action);
 
165
  gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu);
 
166
 
 
167
  return item;
 
168
}
 
169
 
 
170
 
 
171
 
 
172
static void
 
173
item_activated (GtkWidget             *item,
 
174
                ThunarTemplatesAction *templates_action)
 
175
{
 
176
  const ThunarFile *file;
 
177
 
 
178
  _thunar_return_if_fail (THUNAR_IS_TEMPLATES_ACTION (templates_action));
 
179
  _thunar_return_if_fail (GTK_IS_WIDGET (item));
 
180
 
 
181
  /* check if a file is set for the item (else it's the "Empty File" item) */
 
182
  file = g_object_get_data (G_OBJECT (item), I_("thunar-file"));
 
183
  if (G_UNLIKELY (file != NULL))
 
184
    {
 
185
      g_signal_emit (G_OBJECT (templates_action), 
 
186
                     templates_action_signals[CREATE_TEMPLATE], 0, file);
 
187
    }
 
188
  else
 
189
    {
 
190
      g_signal_emit (G_OBJECT (templates_action), 
 
191
                     templates_action_signals[CREATE_EMPTY_FILE], 0);
 
192
    }
 
193
}
 
194
 
 
195
 
 
196
 
 
197
static GtkWidget *
 
198
find_parent_menu (ThunarFile *file,
 
199
                  GList      *dirs,
 
200
                  GList      *items)
 
201
{
 
202
  GtkWidget *parent_menu = NULL;
 
203
  GFile     *parent;
 
204
  GList     *lp;
 
205
  GList     *ip;
 
206
 
 
207
  /* determine the parent of the file */
 
208
  parent = g_file_get_parent (thunar_file_get_file (file));
 
209
 
 
210
  /* check if the file has a parent at all */
 
211
  if (parent == NULL)
 
212
    return NULL;
 
213
 
 
214
  /* iterate over all dirs and menu items */
 
215
  for (lp = g_list_first (dirs), ip = g_list_first (items); 
 
216
       parent_menu == NULL && lp != NULL && ip != NULL; 
 
217
       lp = lp->next, ip = ip->next)
 
218
    {
 
219
      /* check if the current dir/item is the parent of our file */
 
220
      if (g_file_equal (parent, thunar_file_get_file (lp->data)))
 
221
        {
 
222
          /* we want to insert an item for the file in this menu */
 
223
          parent_menu = gtk_menu_item_get_submenu (ip->data);
 
224
        }
 
225
    }
 
226
 
 
227
  /* destroy the parent GFile */
 
228
  g_object_unref (parent);
 
229
 
 
230
  return parent_menu;
 
231
}
 
232
 
 
233
 
 
234
 
 
235
static gint
 
236
compare_files (ThunarFile *a,
 
237
               ThunarFile *b)
 
238
{
 
239
  GFile *file_a;
 
240
  GFile *file_b;
 
241
  GFile *parent_a;
 
242
  GFile *parent_b;
 
243
 
 
244
  file_a = thunar_file_get_file (a);
 
245
  file_b = thunar_file_get_file (b);
 
246
 
 
247
  /* check whether the files are equal */
 
248
  if (g_file_equal (file_a, file_b))
 
249
    return 0;
 
250
  
 
251
  /* directories always come first */
 
252
  if (thunar_file_get_kind (a) == G_FILE_TYPE_DIRECTORY 
 
253
      && thunar_file_get_kind (b) != G_FILE_TYPE_DIRECTORY)
 
254
    {
 
255
      return -1;
 
256
    }
 
257
  else if (thunar_file_get_kind (a) != G_FILE_TYPE_DIRECTORY 
 
258
           && thunar_file_get_kind (b) == G_FILE_TYPE_DIRECTORY)
 
259
    {
 
260
      return 1;
 
261
    }
 
262
 
 
263
  /* ancestors come first */
 
264
  if (g_file_has_prefix (file_b, file_a))
 
265
    return -1;
 
266
  else if (g_file_has_prefix (file_a, file_b))
 
267
    return 1;
 
268
 
 
269
  parent_a = g_file_get_parent (file_a);
 
270
  parent_b = g_file_get_parent (file_b);
 
271
 
 
272
  if (g_file_equal (parent_a, parent_b))
 
273
    {
 
274
      g_object_unref (parent_a);
 
275
      g_object_unref (parent_b);
 
276
 
 
277
      /* compare siblings by their display name */
 
278
      return g_utf8_collate (thunar_file_get_display_name (a),
 
279
                             thunar_file_get_display_name (b));
 
280
    }
 
281
 
 
282
  /* again, ancestors come first */
 
283
  if (g_file_has_prefix (file_b, parent_a))
 
284
    {
 
285
      g_object_unref (parent_a);
 
286
      g_object_unref (parent_b);
 
287
 
 
288
      return -1;
 
289
    }
 
290
  else if (g_file_has_prefix (file_a, parent_b))
 
291
    {
 
292
      g_object_unref (parent_a);
 
293
      g_object_unref (parent_b);
 
294
 
 
295
      return 1;
 
296
    }
 
297
 
 
298
  g_object_unref (parent_a);
 
299
  g_object_unref (parent_b);
 
300
 
 
301
  return 0;
 
302
}
 
303
 
 
304
 
 
305
 
 
306
static gboolean
 
307
thunar_templates_action_files_ready (ThunarJob             *job,
 
308
                                     GList                 *files,
 
309
                                     ThunarTemplatesAction *templates_action)
 
310
{
 
311
  ThunarIconFactory *icon_factory;
 
312
  ThunarFile        *file;
 
313
  GdkPixbuf         *icon;
 
314
  GtkWidget         *menu;
 
315
  GtkWidget         *parent_menu;
 
316
  GtkWidget         *submenu;
 
317
  GtkWidget         *image;
 
318
  GtkWidget         *item;
 
319
  GList             *lp;
 
320
  GList             *dirs = NULL;
 
321
  GList             *items = NULL;
 
322
  GList             *parent_menus = NULL;
 
323
  GList             *pp;
 
324
 
 
325
  /* determine the menu to add the items and submenus to */
 
326
  menu = g_object_get_data (G_OBJECT (job), "menu");
 
327
 
 
328
  /* do nothing if there is no menu */
 
329
  if (menu == NULL)
 
330
    return FALSE;
 
331
 
 
332
  /* get the icon factory */
 
333
  icon_factory = thunar_icon_factory_get_default ();
 
334
 
 
335
  /* sort items so that directories come before files and ancestors come 
 
336
   * before descendants */
 
337
  files = g_list_sort (files, (GCompareFunc) compare_files);
 
338
 
 
339
  for (lp = g_list_first (files); lp != NULL; lp = lp->next)
 
340
    {
 
341
      file = lp->data;
 
342
      
 
343
      /* determine the parent menu for this file/directory */
 
344
      parent_menu = find_parent_menu (file, dirs, items);
 
345
      parent_menu = parent_menu == NULL ? menu : parent_menu;
 
346
 
 
347
      if (thunar_file_get_kind (file) == G_FILE_TYPE_DIRECTORY)
 
348
        {
 
349
          /* allocate a new submenu for the directory */
 
350
          submenu = gtk_menu_new ();
 
351
          g_object_ref_sink (G_OBJECT (submenu));
 
352
          gtk_menu_set_screen (GTK_MENU (submenu), gtk_widget_get_screen (menu));
 
353
 
 
354
          /* allocate a new menu item for the directory */
 
355
          item = gtk_image_menu_item_new_with_label (thunar_file_get_display_name (file));
 
356
          gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
 
357
 
 
358
          /* prepend the directory, its item and the parent menu it should 
 
359
           * later be added to to the respective lists */
 
360
          dirs = g_list_prepend (dirs, file);
 
361
          items = g_list_prepend (items, item);
 
362
          parent_menus = g_list_prepend (parent_menus, parent_menu);
 
363
        }
 
364
      else
 
365
        {
 
366
          /* allocate a new menu item */
 
367
          item = gtk_image_menu_item_new_with_label (thunar_file_get_display_name (file));
 
368
          g_object_set_data_full (G_OBJECT (item), I_("thunar-file"), 
 
369
                                  g_object_ref (file), g_object_unref);
 
370
          g_signal_connect (item, "activate", G_CALLBACK (item_activated), 
 
371
                            templates_action);
 
372
          gtk_menu_shell_append (GTK_MENU_SHELL (parent_menu), item);
 
373
          gtk_widget_show (item);
 
374
        }
 
375
 
 
376
      /* determine the icon for this file/directory */
 
377
      icon = thunar_icon_factory_load_file_icon (icon_factory, file,
 
378
                                                 THUNAR_FILE_ICON_STATE_DEFAULT,
 
379
                                                 16);
 
380
 
 
381
      /* allocate an image based on the icon */
 
382
      image = gtk_image_new_from_pixbuf (icon);
 
383
      gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
 
384
 
 
385
      /* release the icon reference */
 
386
      g_object_unref (icon);
 
387
    }
 
388
 
 
389
  /* add all non-empty directory items to their parent menu */
 
390
  for (lp = items, pp = parent_menus; 
 
391
       lp != NULL && pp != NULL; 
 
392
       lp = lp->next, pp = pp->next)
 
393
    {
 
394
      /* determine the submenu for this directory item */
 
395
      submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (lp->data));
 
396
 
 
397
      if (GTK_MENU_SHELL (submenu)->children == NULL)
 
398
        {
 
399
          /* the directory submenu is empty, destroy it */
 
400
          gtk_widget_destroy (lp->data);
 
401
        }
 
402
      else
 
403
        {
 
404
          /* the directory has template files, so add it to its parent menu */
 
405
          gtk_menu_shell_prepend (GTK_MENU_SHELL (pp->data), lp->data);
 
406
          gtk_widget_show (lp->data);
 
407
        }
 
408
    }
 
409
 
 
410
  /* destroy lists */
 
411
  g_list_free (dirs);
 
412
  g_list_free (items);
 
413
  g_list_free (parent_menus);
 
414
 
 
415
  /* release the icon factory */
 
416
  g_object_unref (icon_factory);
 
417
 
 
418
  /* let the job destroy the file list */
 
419
  return FALSE;
 
420
}
 
421
 
 
422
 
 
423
 
 
424
static void
 
425
thunar_templates_action_load_error (ThunarJob             *job,
 
426
                                    GError                *error,
 
427
                                    ThunarTemplatesAction *templates_action)
 
428
{
 
429
  GtkWidget *item;
 
430
  GtkWidget *menu;
 
431
 
 
432
  _thunar_return_if_fail (THUNAR_IS_JOB (job));
 
433
  _thunar_return_if_fail (error != NULL);
 
434
  _thunar_return_if_fail (THUNAR_IS_TEMPLATES_ACTION (templates_action));
 
435
  _thunar_return_if_fail (templates_action->job == job);
 
436
 
 
437
  menu = g_object_get_data (G_OBJECT (job), "menu");
 
438
 
 
439
  /* check if any items were added to the menu */
 
440
  if (G_LIKELY (menu != NULL && GTK_MENU_SHELL (menu)->children == NULL))
 
441
    {
 
442
      /* tell the user that no templates were found */
 
443
      item = gtk_menu_item_new_with_label (error->message);
 
444
      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 
445
      gtk_widget_set_sensitive (item, FALSE);
 
446
      gtk_widget_show (item);
 
447
    }
 
448
}
 
449
 
 
450
 
 
451
 
 
452
static void
 
453
thunar_templates_action_load_finished (ThunarJob             *job,
 
454
                                       ThunarTemplatesAction *templates_action)
 
455
{
 
456
  GtkWidget *image;
 
457
  GtkWidget *item;
 
458
  GtkWidget *menu;
 
459
 
 
460
  _thunar_return_if_fail (THUNAR_IS_JOB (job));
 
461
  _thunar_return_if_fail (THUNAR_IS_TEMPLATES_ACTION (templates_action));
 
462
  _thunar_return_if_fail (templates_action->job == job);
 
463
 
 
464
  menu = g_object_get_data (G_OBJECT (job), "menu");
 
465
  if (G_LIKELY (menu != NULL))
 
466
    {
 
467
      /* append a menu separator */
 
468
      item = gtk_separator_menu_item_new ();
 
469
      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 
470
      gtk_widget_show (item);
 
471
 
 
472
      /* add the "Empty File" item */
 
473
      item = gtk_image_menu_item_new_with_mnemonic (_("_Empty File"));
 
474
      g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (item_activated), 
 
475
                        templates_action);
 
476
      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 
477
      gtk_widget_show (item);
 
478
 
 
479
      /* add the icon for the emtpy file item */
 
480
      image = gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU);
 
481
      gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
 
482
    }
 
483
 
 
484
  g_signal_handlers_disconnect_matched (job, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL,
 
485
                                        templates_action);
 
486
  g_object_unref (job);
 
487
}
 
488
 
 
489
 
 
490
 
 
491
static void
 
492
thunar_templates_action_menu_shown (GtkWidget             *menu,
 
493
                                    ThunarTemplatesAction *templates_action)
 
494
{
 
495
  GList *children;
 
496
 
 
497
  _thunar_return_if_fail (THUNAR_IS_TEMPLATES_ACTION (templates_action));
 
498
  _thunar_return_if_fail (GTK_IS_MENU_SHELL (menu));
 
499
 
 
500
  /* drop all existing children of the menu first */
 
501
  children = gtk_container_get_children (GTK_CONTAINER (menu));
 
502
  g_list_free_full (children, (GDestroyNotify) gtk_widget_destroy);
 
503
 
 
504
  if (G_LIKELY (templates_action->job == NULL))
 
505
    {
 
506
      templates_action->job = thunar_misc_jobs_load_template_files (menu);
 
507
      g_object_add_weak_pointer (G_OBJECT (templates_action->job),
 
508
                                 (gpointer) &templates_action->job);
 
509
 
 
510
      g_signal_connect (templates_action->job, "files-ready",
 
511
                        G_CALLBACK (thunar_templates_action_files_ready), 
 
512
                        templates_action);
 
513
      g_signal_connect (templates_action->job, "error",
 
514
                        G_CALLBACK (thunar_templates_action_load_error), 
 
515
                        templates_action);
 
516
      g_signal_connect (templates_action->job, "finished",
 
517
                        G_CALLBACK (thunar_templates_action_load_finished), 
 
518
                        templates_action);
 
519
    }
 
520
}
 
521
 
 
522
 
 
523
 
 
524
/**
 
525
 * thunar_templates_action_new:
 
526
 * @name  : the internal name of the action.
 
527
 * @label : the label for the action.
 
528
 *
 
529
 * Allocates a new #ThunarTemplatesAction with the given
 
530
 * @name and @label.
 
531
 *
 
532
 * Return value: the newly allocated #ThunarTemplatesAction.
 
533
 **/
 
534
GtkAction*
 
535
thunar_templates_action_new (const gchar *name,
 
536
                             const gchar *label)
 
537
{
 
538
  _thunar_return_val_if_fail (name != NULL, NULL);
 
539
  _thunar_return_val_if_fail (label != NULL, NULL);
 
540
 
 
541
  return g_object_new (THUNAR_TYPE_TEMPLATES_ACTION,
 
542
                       "hide-if-empty", FALSE,
 
543
                       "label", label,
 
544
                       "name", name,
 
545
                       NULL);
 
546
}
 
547
 
 
548