]> Pileus Git - ~andy/gtk/blob - gtk/gtkrecentchooserdefault.c
Clean up unneeded includes
[~andy/gtk] / gtk / gtkrecentchooserdefault.c
1 /* GTK - The GIMP Toolkit
2  * gtkrecentchooserdefault.c
3  * Copyright (C) 2005-2006, Emmanuele Bassi
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 Public
16  * 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
21 #include "config.h"
22
23 #include <string.h>
24 #include <time.h>
25 #include <errno.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31
32 #include "gtkstock.h"
33 #include "gtkicontheme.h"
34 #include "gtkiconfactory.h"
35 #include "gtksettings.h"
36 #include "gtktreeview.h"
37 #include "gtkliststore.h"
38 #include "gtkbutton.h"
39 #include "gtkcelllayout.h"
40 #include "gtkcellrendererpixbuf.h"
41 #include "gtkcellrenderertext.h"
42 #include "gtkcheckmenuitem.h"
43 #include "gtkclipboard.h"
44 #include "gtkcomboboxtext.h"
45 #include "gtkentry.h"
46 #include "gtkeventbox.h"
47 #include "gtkexpander.h"
48 #include "gtkframe.h"
49 #include "gtkbox.h"
50 #include "gtkpaned.h"
51 #include "gtkimage.h"
52 #include "gtkimagemenuitem.h"
53 #include "gtkintl.h"
54 #include "gtklabel.h"
55 #include "gtkmenuitem.h"
56 #include "gtkmessagedialog.h"
57 #include "gtkscrolledwindow.h"
58 #include "gtkseparatormenuitem.h"
59 #include "gtksizegroup.h"
60 #include "gtksizerequest.h"
61 #include "gtktreemodelsort.h"
62 #include "gtktreemodelfilter.h"
63 #include "gtktreeselection.h"
64 #include "gtktreestore.h"
65 #include "gtktooltip.h"
66 #include "gtktypebuiltins.h"
67 #include "gtkorientable.h"
68 #include "gtkactivatable.h"
69
70 #include "gtkrecentmanager.h"
71 #include "gtkrecentfilter.h"
72 #include "gtkrecentchooser.h"
73 #include "gtkrecentchooserprivate.h"
74 #include "gtkrecentchooserutils.h"
75 #include "gtkrecentchooserdefault.h"
76
77 #include "gtkprivate.h"
78
79
80 enum 
81 {
82   PROP_0,
83
84   /* activatable properties */
85   PROP_ACTIVATABLE_RELATED_ACTION,
86   PROP_ACTIVATABLE_USE_ACTION_APPEARANCE
87 };
88
89
90 struct _GtkRecentChooserDefault
91 {
92   GtkBox parent_instance;
93
94   GtkRecentManager *manager;
95   gulong manager_changed_id;
96   guint local_manager : 1;
97
98   gint icon_size;
99
100   /* RecentChooser properties */
101   gint limit;
102   GtkRecentSortType sort_type;
103   guint show_private : 1;
104   guint show_not_found : 1;
105   guint select_multiple : 1;
106   guint show_tips : 1;
107   guint show_icons : 1;
108   guint local_only : 1;
109
110   guint limit_set : 1;
111   
112   GSList *filters;
113   GtkRecentFilter *current_filter;
114   GtkWidget *filter_combo_hbox;
115   GtkWidget *filter_combo;
116   
117   GtkRecentSortFunc sort_func;
118   gpointer sort_data;
119   GDestroyNotify sort_data_destroy;
120
121   GtkIconTheme *icon_theme;
122   
123   GtkWidget *recent_view;
124   GtkListStore *recent_store;
125   GtkTreeViewColumn *icon_column;
126   GtkTreeViewColumn *meta_column;
127   GtkCellRenderer *meta_renderer;
128   GtkTreeSelection *selection;
129   
130   GtkWidget *recent_popup_menu;
131   GtkWidget *recent_popup_menu_copy_item;
132   GtkWidget *recent_popup_menu_remove_item;
133   GtkWidget *recent_popup_menu_clear_item;
134   GtkWidget *recent_popup_menu_show_private_item;
135  
136   guint load_id;
137   GList *recent_items;
138   gint n_recent_items;
139   gint loaded_items;
140   guint load_state;
141 };
142
143 typedef struct _GtkRecentChooserDefaultClass
144 {
145   GtkBoxClass parent_class;
146 } GtkRecentChooserDefaultClass;
147
148 enum {
149   RECENT_URI_COLUMN,
150   RECENT_DISPLAY_NAME_COLUMN,
151   RECENT_INFO_COLUMN,
152   N_RECENT_COLUMNS
153 };
154
155 enum {
156   LOAD_EMPTY,    /* initial state: the model is empty */
157   LOAD_PRELOAD,  /* the model is loading and not inserted in the tree yet */
158   LOAD_LOADING,  /* the model is fully loaded but not inserted */
159   LOAD_FINISHED  /* the model is fully loaded and inserted */
160 };
161
162 /* Icon size for if we can't get it from the theme */
163 #define FALLBACK_ICON_SIZE  48
164 #define FALLBACK_ITEM_LIMIT 20
165
166 #define NUM_CHARS 40
167 #define NUM_LINES 9
168
169 \f
170
171 /* GObject */
172 static void     _gtk_recent_chooser_default_class_init  (GtkRecentChooserDefaultClass *klass);
173 static void     _gtk_recent_chooser_default_init        (GtkRecentChooserDefault      *impl);
174 static GObject *gtk_recent_chooser_default_constructor  (GType                         type,
175                                                          guint                         n_construct_prop,
176                                                          GObjectConstructParam        *construct_params);
177 static void     gtk_recent_chooser_default_finalize     (GObject                      *object);
178 static void     gtk_recent_chooser_default_dispose      (GObject                      *object);
179 static void     gtk_recent_chooser_default_set_property (GObject                      *object,
180                                                          guint                         prop_id,
181                                                          const GValue                 *value,
182                                                          GParamSpec                   *pspec);
183 static void     gtk_recent_chooser_default_get_property (GObject                      *object,
184                                                          guint                         prop_id,
185                                                          GValue                       *value,
186                                                          GParamSpec                   *pspec);
187
188 /* GtkRecentChooserIface */
189 static void              gtk_recent_chooser_iface_init                 (GtkRecentChooserIface  *iface);
190 static gboolean          gtk_recent_chooser_default_set_current_uri    (GtkRecentChooser       *chooser,
191                                                                         const gchar            *uri,
192                                                                         GError                **error);
193 static gchar *           gtk_recent_chooser_default_get_current_uri    (GtkRecentChooser       *chooser);
194 static gboolean          gtk_recent_chooser_default_select_uri         (GtkRecentChooser       *chooser,
195                                                                         const gchar            *uri,
196                                                                         GError                **error);
197 static void              gtk_recent_chooser_default_unselect_uri       (GtkRecentChooser       *chooser,
198                                                                         const gchar            *uri);
199 static void              gtk_recent_chooser_default_select_all         (GtkRecentChooser       *chooser);
200 static void              gtk_recent_chooser_default_unselect_all       (GtkRecentChooser       *chooser);
201 static GList *           gtk_recent_chooser_default_get_items          (GtkRecentChooser       *chooser);
202 static GtkRecentManager *gtk_recent_chooser_default_get_recent_manager (GtkRecentChooser       *chooser);
203 static void              gtk_recent_chooser_default_set_sort_func      (GtkRecentChooser       *chooser,
204                                                                         GtkRecentSortFunc       sort_func,
205                                                                         gpointer                sort_data,
206                                                                         GDestroyNotify          data_destroy);
207 static void              gtk_recent_chooser_default_add_filter         (GtkRecentChooser       *chooser,
208                                                                         GtkRecentFilter        *filter);
209 static void              gtk_recent_chooser_default_remove_filter      (GtkRecentChooser       *chooser,
210                                                                         GtkRecentFilter        *filter);
211 static GSList *          gtk_recent_chooser_default_list_filters       (GtkRecentChooser       *chooser);
212
213
214 static void gtk_recent_chooser_default_map      (GtkWidget *widget);
215 static void gtk_recent_chooser_default_show_all (GtkWidget *widget);
216
217 static void set_current_filter        (GtkRecentChooserDefault *impl,
218                                        GtkRecentFilter         *filter);
219
220 static GtkIconTheme *get_icon_theme_for_widget (GtkWidget   *widget);
221 static gint          get_icon_size_for_widget  (GtkWidget   *widget,
222                                                 GtkIconSize  icon_size);
223 static gint          get_recent_files_limit    (GtkWidget   *widget);
224
225 static void reload_recent_items (GtkRecentChooserDefault *impl);
226 static void chooser_set_model   (GtkRecentChooserDefault *impl);
227
228 static void set_recent_manager (GtkRecentChooserDefault *impl,
229                                 GtkRecentManager        *manager);
230
231 static void chooser_set_sort_type (GtkRecentChooserDefault *impl,
232                                    GtkRecentSortType        sort_type);
233
234 static void recent_manager_changed_cb (GtkRecentManager  *manager,
235                                        gpointer           user_data);
236 static void recent_icon_data_func     (GtkTreeViewColumn *tree_column,
237                                        GtkCellRenderer   *cell,
238                                        GtkTreeModel      *model,
239                                        GtkTreeIter       *iter,
240                                        gpointer           user_data);
241 static void recent_meta_data_func     (GtkTreeViewColumn *tree_column,
242                                        GtkCellRenderer   *cell,
243                                        GtkTreeModel      *model,
244                                        GtkTreeIter       *iter,
245                                        gpointer           user_data);
246
247 static void selection_changed_cb      (GtkTreeSelection  *z,
248                                        gpointer           user_data);
249 static void row_activated_cb          (GtkTreeView       *tree_view,
250                                        GtkTreePath       *tree_path,
251                                        GtkTreeViewColumn *tree_column,
252                                        gpointer           user_data);
253 static void filter_combo_changed_cb   (GtkComboBox       *combo_box,
254                                        gpointer           user_data);
255
256 static void remove_all_activated_cb   (GtkMenuItem       *menu_item,
257                                        gpointer           user_data);
258 static void remove_item_activated_cb  (GtkMenuItem       *menu_item,
259                                        gpointer           user_data);
260 static void show_private_toggled_cb   (GtkCheckMenuItem  *menu_item,
261                                        gpointer           user_data);
262
263 static gboolean recent_view_popup_menu_cb   (GtkWidget      *widget,
264                                              gpointer        user_data);
265 static gboolean recent_view_button_press_cb (GtkWidget      *widget,
266                                              GdkEventButton *event,
267                                              gpointer        user_data);
268
269 static void     recent_view_drag_begin_cb         (GtkWidget        *widget,
270                                                    GdkDragContext   *context,
271                                                    gpointer          user_data);
272 static void     recent_view_drag_data_get_cb      (GtkWidget        *widget,
273                                                    GdkDragContext   *context,
274                                                    GtkSelectionData *selection_data,
275                                                    guint             info,
276                                                    guint32           time_,
277                                                    gpointer          data);
278 static gboolean recent_view_query_tooltip_cb      (GtkWidget        *widget,
279                                                    gint              x,
280                                                    gint              y,
281                                                    gboolean          keyboard_tip,
282                                                    GtkTooltip       *tooltip,
283                                                    gpointer          user_data);
284
285 static void gtk_recent_chooser_activatable_iface_init (GtkActivatableIface  *iface);
286 static void gtk_recent_chooser_update                 (GtkActivatable       *activatable,
287                                                        GtkAction            *action,
288                                                        const gchar          *property_name);
289 static void gtk_recent_chooser_sync_action_properties (GtkActivatable       *activatable,
290                                                        GtkAction            *action);
291
292 G_DEFINE_TYPE_WITH_CODE (GtkRecentChooserDefault,
293                          _gtk_recent_chooser_default,
294                          GTK_TYPE_BOX,
295                          G_IMPLEMENT_INTERFACE (GTK_TYPE_RECENT_CHOOSER,
296                                                 gtk_recent_chooser_iface_init)
297                          G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
298                                                 gtk_recent_chooser_activatable_iface_init))
299
300
301 \f
302
303 static void
304 gtk_recent_chooser_iface_init (GtkRecentChooserIface *iface)
305 {
306   iface->set_current_uri = gtk_recent_chooser_default_set_current_uri;
307   iface->get_current_uri = gtk_recent_chooser_default_get_current_uri;
308   iface->select_uri = gtk_recent_chooser_default_select_uri;
309   iface->unselect_uri = gtk_recent_chooser_default_unselect_uri;
310   iface->select_all = gtk_recent_chooser_default_select_all;
311   iface->unselect_all = gtk_recent_chooser_default_unselect_all;
312   iface->get_items = gtk_recent_chooser_default_get_items;
313   iface->get_recent_manager = gtk_recent_chooser_default_get_recent_manager;
314   iface->set_sort_func = gtk_recent_chooser_default_set_sort_func;
315   iface->add_filter = gtk_recent_chooser_default_add_filter;
316   iface->remove_filter = gtk_recent_chooser_default_remove_filter;
317   iface->list_filters = gtk_recent_chooser_default_list_filters;
318 }
319
320 static void
321 gtk_recent_chooser_activatable_iface_init (GtkActivatableIface *iface)
322
323 {
324   iface->update = gtk_recent_chooser_update;
325   iface->sync_action_properties = gtk_recent_chooser_sync_action_properties;
326 }
327
328 static void
329 _gtk_recent_chooser_default_class_init (GtkRecentChooserDefaultClass *klass)
330 {
331   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
332   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
333
334   gobject_class->constructor = gtk_recent_chooser_default_constructor;
335   gobject_class->set_property = gtk_recent_chooser_default_set_property;
336   gobject_class->get_property = gtk_recent_chooser_default_get_property;
337   gobject_class->dispose = gtk_recent_chooser_default_dispose;
338   gobject_class->finalize = gtk_recent_chooser_default_finalize;
339   
340   widget_class->map = gtk_recent_chooser_default_map;
341   widget_class->show_all = gtk_recent_chooser_default_show_all;
342   
343   _gtk_recent_chooser_install_properties (gobject_class);
344
345   g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_RELATED_ACTION, "related-action");
346   g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_USE_ACTION_APPEARANCE, "use-action-appearance");
347 }
348
349 static void
350 _gtk_recent_chooser_default_init (GtkRecentChooserDefault *impl)
351 {
352   gtk_box_set_spacing (GTK_BOX (impl), 6);
353
354   gtk_orientable_set_orientation (GTK_ORIENTABLE (impl),
355                                   GTK_ORIENTATION_VERTICAL);
356
357   /* by default, we use the global manager */
358   impl->local_manager = FALSE;
359
360   impl->limit = FALLBACK_ITEM_LIMIT;
361   impl->sort_type = GTK_RECENT_SORT_NONE;
362
363   impl->show_icons = TRUE;
364   impl->show_private = FALSE;
365   impl->show_not_found = TRUE;
366   impl->show_tips = FALSE;
367   impl->select_multiple = FALSE;
368   impl->local_only = TRUE;
369   
370   impl->icon_size = FALLBACK_ICON_SIZE;
371   impl->icon_theme = NULL;
372   
373   impl->current_filter = NULL;
374
375   impl->recent_items = NULL;
376   impl->n_recent_items = 0;
377   impl->loaded_items = 0;
378   
379   impl->load_state = LOAD_EMPTY;
380 }
381
382 static GObject *
383 gtk_recent_chooser_default_constructor (GType                  type,
384                                         guint                  n_params,
385                                         GObjectConstructParam *params)
386 {
387   GObjectClass *parent_class;
388   GtkRecentChooserDefault *impl;
389   GObject *object;
390   GtkWidget *scrollw;
391   GtkCellRenderer *renderer;
392
393   parent_class = G_OBJECT_CLASS (_gtk_recent_chooser_default_parent_class);
394   object = parent_class->constructor (type, n_params, params);
395   impl = GTK_RECENT_CHOOSER_DEFAULT (object);
396   
397   g_assert (impl->manager);
398   
399   gtk_widget_push_composite_child ();
400
401   impl->limit = get_recent_files_limit (GTK_WIDGET (impl));
402   
403   scrollw = gtk_scrolled_window_new (NULL, NULL);
404   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollw),
405                                        GTK_SHADOW_IN);
406   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollw),
407                                   GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
408   gtk_box_pack_start (GTK_BOX (impl), scrollw, TRUE, TRUE, 0);
409   gtk_widget_show (scrollw);
410   
411   impl->recent_view = gtk_tree_view_new ();
412   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (impl->recent_view), FALSE);
413   g_signal_connect (impl->recent_view, "row-activated",
414                     G_CALLBACK (row_activated_cb), impl);
415   g_signal_connect (impl->recent_view, "popup-menu",
416                     G_CALLBACK (recent_view_popup_menu_cb), impl);
417   g_signal_connect (impl->recent_view, "button-press-event",
418                     G_CALLBACK (recent_view_button_press_cb), impl);
419   g_signal_connect (impl->recent_view, "drag-begin",
420                     G_CALLBACK (recent_view_drag_begin_cb), impl);
421   g_signal_connect (impl->recent_view, "drag-data-get",
422                     G_CALLBACK (recent_view_drag_data_get_cb), impl);
423
424   g_object_set (impl->recent_view, "has-tooltip", TRUE, NULL);
425   g_signal_connect (impl->recent_view, "query-tooltip",
426                     G_CALLBACK (recent_view_query_tooltip_cb), impl);
427
428   g_object_set_data (G_OBJECT (impl->recent_view),
429                      "GtkRecentChooserDefault", impl);
430   
431   gtk_container_add (GTK_CONTAINER (scrollw), impl->recent_view);
432   gtk_widget_show (impl->recent_view);
433   
434   impl->icon_column = gtk_tree_view_column_new ();
435   gtk_tree_view_column_set_expand (impl->icon_column, FALSE);
436   gtk_tree_view_column_set_resizable (impl->icon_column, FALSE);
437   
438   renderer = gtk_cell_renderer_pixbuf_new ();
439   g_object_set (renderer, "stock-size", GTK_ICON_SIZE_BUTTON, NULL);
440   gtk_tree_view_column_pack_start (impl->icon_column, renderer, FALSE);
441   gtk_tree_view_column_set_cell_data_func (impl->icon_column,
442                                            renderer,
443                                            recent_icon_data_func,
444                                            impl,
445                                            NULL);
446   gtk_tree_view_append_column (GTK_TREE_VIEW (impl->recent_view),
447                                impl->icon_column);
448   
449   impl->meta_column = gtk_tree_view_column_new ();
450   gtk_tree_view_column_set_expand (impl->meta_column, TRUE);
451   gtk_tree_view_column_set_resizable (impl->meta_column, FALSE);
452   
453   impl->meta_renderer = gtk_cell_renderer_text_new ();
454   g_object_set (G_OBJECT (impl->meta_renderer),
455                 "ellipsize", PANGO_ELLIPSIZE_END,
456                 NULL);
457   gtk_tree_view_column_pack_start (impl->meta_column, impl->meta_renderer, TRUE);
458   gtk_tree_view_column_set_cell_data_func (impl->meta_column,
459                                            impl->meta_renderer,
460                                            recent_meta_data_func,
461                                            impl,
462                                            NULL);
463   gtk_tree_view_append_column (GTK_TREE_VIEW (impl->recent_view),
464                                impl->meta_column);
465   
466   impl->selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->recent_view));
467   gtk_tree_selection_set_mode (impl->selection, GTK_SELECTION_SINGLE);
468   g_signal_connect (impl->selection, "changed", G_CALLBACK (selection_changed_cb), impl);
469
470   /* drag and drop */
471   gtk_drag_source_set (impl->recent_view,
472                        GDK_BUTTON1_MASK,
473                        NULL, 0,
474                        GDK_ACTION_COPY);
475   gtk_drag_source_add_uri_targets (impl->recent_view);
476
477   impl->filter_combo_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
478
479   impl->filter_combo = gtk_combo_box_text_new ();
480   gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (impl->filter_combo), FALSE);
481   g_signal_connect (impl->filter_combo, "changed",
482                     G_CALLBACK (filter_combo_changed_cb), impl);
483   gtk_widget_set_tooltip_text (impl->filter_combo,
484                                _("Select which type of documents are shown"));
485   
486   gtk_box_pack_end (GTK_BOX (impl->filter_combo_hbox),
487                     impl->filter_combo,
488                     FALSE, FALSE, 0);
489   gtk_widget_show (impl->filter_combo);
490   
491   gtk_box_pack_end (GTK_BOX (impl), impl->filter_combo_hbox, FALSE, FALSE, 0);
492   
493   gtk_widget_pop_composite_child ();
494   
495   impl->recent_store = gtk_list_store_new (N_RECENT_COLUMNS,
496                                            G_TYPE_STRING,       /* uri */
497                                            G_TYPE_STRING,       /* display_name */
498                                            GTK_TYPE_RECENT_INFO /* info */);
499   
500   return object;
501 }
502
503 static void
504 gtk_recent_chooser_default_set_property (GObject      *object,
505                                          guint         prop_id,
506                                          const GValue *value,
507                                          GParamSpec   *pspec)
508 {
509   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (object);
510   
511   switch (prop_id)
512     {
513     case GTK_RECENT_CHOOSER_PROP_RECENT_MANAGER:
514       set_recent_manager (impl, g_value_get_object (value));
515       break;
516     case GTK_RECENT_CHOOSER_PROP_SHOW_PRIVATE:
517       impl->show_private = g_value_get_boolean (value);
518       if (impl->recent_popup_menu_show_private_item)
519         {
520           GtkCheckMenuItem *item = GTK_CHECK_MENU_ITEM (impl->recent_popup_menu_show_private_item);
521           g_signal_handlers_block_by_func (item, G_CALLBACK (show_private_toggled_cb), impl);
522           gtk_check_menu_item_set_active (item, impl->show_private);
523           g_signal_handlers_unblock_by_func (item, G_CALLBACK (show_private_toggled_cb), impl);
524         }
525       reload_recent_items (impl);
526       break;
527     case GTK_RECENT_CHOOSER_PROP_SHOW_NOT_FOUND:
528       impl->show_not_found = g_value_get_boolean (value);
529       reload_recent_items (impl);
530       break;
531     case GTK_RECENT_CHOOSER_PROP_SHOW_TIPS:
532       impl->show_tips = g_value_get_boolean (value);
533       break;
534     case GTK_RECENT_CHOOSER_PROP_SHOW_ICONS:
535       impl->show_icons = g_value_get_boolean (value);
536       gtk_tree_view_column_set_visible (impl->icon_column, impl->show_icons);
537       break;
538     case GTK_RECENT_CHOOSER_PROP_SELECT_MULTIPLE:
539       impl->select_multiple = g_value_get_boolean (value);
540       
541       if (impl->select_multiple)
542         gtk_tree_selection_set_mode (impl->selection, GTK_SELECTION_MULTIPLE);
543       else
544         gtk_tree_selection_set_mode (impl->selection, GTK_SELECTION_SINGLE);
545       break;
546     case GTK_RECENT_CHOOSER_PROP_LOCAL_ONLY:
547       impl->local_only = g_value_get_boolean (value);
548       reload_recent_items (impl);
549       break;
550     case GTK_RECENT_CHOOSER_PROP_LIMIT:
551       impl->limit = g_value_get_int (value);
552       impl->limit_set = TRUE;
553       reload_recent_items (impl);
554       break;
555     case GTK_RECENT_CHOOSER_PROP_SORT_TYPE:
556       chooser_set_sort_type (impl, g_value_get_enum (value));
557       break;
558     case GTK_RECENT_CHOOSER_PROP_FILTER:
559       set_current_filter (impl, g_value_get_object (value));
560       break;
561     case PROP_ACTIVATABLE_RELATED_ACTION:
562       _gtk_recent_chooser_set_related_action (GTK_RECENT_CHOOSER (impl), g_value_get_object (value));
563       break;
564     case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE: 
565       _gtk_recent_chooser_set_use_action_appearance (GTK_RECENT_CHOOSER (impl), g_value_get_boolean (value));
566       break;
567     default:
568       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
569       break;
570     }
571 }
572
573 static void
574 gtk_recent_chooser_default_get_property (GObject    *object,
575                                          guint       prop_id,
576                                          GValue     *value,
577                                          GParamSpec *pspec)
578 {
579   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (object);
580   
581   switch (prop_id)
582     {
583     case GTK_RECENT_CHOOSER_PROP_LIMIT:
584       g_value_set_int (value, impl->limit);
585       break;
586     case GTK_RECENT_CHOOSER_PROP_SORT_TYPE:
587       g_value_set_enum (value, impl->sort_type);
588       break;
589     case GTK_RECENT_CHOOSER_PROP_SHOW_PRIVATE:
590       g_value_set_boolean (value, impl->show_private);
591       break;
592     case GTK_RECENT_CHOOSER_PROP_SHOW_ICONS:
593       g_value_set_boolean (value, impl->show_icons);
594       break;
595     case GTK_RECENT_CHOOSER_PROP_SHOW_NOT_FOUND:
596       g_value_set_boolean (value, impl->show_not_found);
597       break;
598     case GTK_RECENT_CHOOSER_PROP_SHOW_TIPS:
599       g_value_set_boolean (value, impl->show_tips);
600       break;
601     case GTK_RECENT_CHOOSER_PROP_LOCAL_ONLY:
602       g_value_set_boolean (value, impl->local_only);
603       break;
604     case GTK_RECENT_CHOOSER_PROP_SELECT_MULTIPLE:
605       g_value_set_boolean (value, impl->select_multiple);
606       break;
607     case GTK_RECENT_CHOOSER_PROP_FILTER:
608       g_value_set_object (value, impl->current_filter);
609       break;
610     case PROP_ACTIVATABLE_RELATED_ACTION:
611       g_value_set_object (value, _gtk_recent_chooser_get_related_action (GTK_RECENT_CHOOSER (impl)));
612       break;
613     case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE: 
614       g_value_set_boolean (value, _gtk_recent_chooser_get_use_action_appearance (GTK_RECENT_CHOOSER (impl)));
615       break;
616     default:
617       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
618       break;
619     }
620 }
621
622 static void
623 gtk_recent_chooser_default_dispose (GObject *object)
624 {
625   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (object);
626
627   if (impl->load_id)
628     {
629       g_source_remove (impl->load_id);
630       impl->load_state = LOAD_EMPTY;
631       impl->load_id = 0;
632     }
633
634   if (impl->recent_items)
635     {
636       g_list_foreach (impl->recent_items, (GFunc) gtk_recent_info_unref, NULL);
637       g_list_free (impl->recent_items);
638       impl->recent_items = NULL;
639     }
640
641   if (impl->manager && impl->manager_changed_id)
642     {
643       g_signal_handler_disconnect (impl->manager, impl->manager_changed_id);
644       impl->manager_changed_id = 0;
645     }
646
647   if (impl->filters)
648     {
649       g_slist_foreach (impl->filters, (GFunc) g_object_unref, NULL);
650       g_slist_free (impl->filters);
651       impl->filters = NULL;
652     }
653   
654   if (impl->current_filter)
655     {
656       g_object_unref (impl->current_filter);
657       impl->current_filter = NULL;
658     }
659
660   if (impl->recent_store)
661     {
662       g_object_unref (impl->recent_store);
663       impl->recent_store = NULL;
664     }
665
666   G_OBJECT_CLASS (_gtk_recent_chooser_default_parent_class)->dispose (object);
667 }
668
669 static void
670 gtk_recent_chooser_default_finalize (GObject *object)
671 {
672   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (object);
673
674   impl->manager = NULL; 
675   
676   if (impl->sort_data_destroy)
677     {
678       impl->sort_data_destroy (impl->sort_data);
679       impl->sort_data_destroy = NULL;
680     }
681   
682   impl->sort_data = NULL;
683   impl->sort_func = NULL;
684   
685   G_OBJECT_CLASS (_gtk_recent_chooser_default_parent_class)->finalize (object);
686 }
687
688 /* override GtkWidget::show_all since we have internal widgets we wish to keep
689  * hidden unless we decide otherwise, like the filter combo box.
690  */
691 static void
692 gtk_recent_chooser_default_show_all (GtkWidget *widget)
693 {
694   gtk_widget_show (widget);
695 }
696
697
698
699 /* Shows an error dialog set as transient for the specified window */
700 static void
701 error_message_with_parent (GtkWindow   *parent,
702                            const gchar *msg,
703                            const gchar *detail)
704 {
705   GtkWidget *dialog;
706
707   dialog = gtk_message_dialog_new (parent,
708                                    GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
709                                    GTK_MESSAGE_ERROR,
710                                    GTK_BUTTONS_OK,
711                                    "%s",
712                                    msg);
713   gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
714                                             "%s", detail);
715
716   if (gtk_window_has_group (parent))
717     gtk_window_group_add_window (gtk_window_get_group (parent),
718                                  GTK_WINDOW (dialog));
719
720   gtk_dialog_run (GTK_DIALOG (dialog));
721   gtk_widget_destroy (dialog);
722 }
723
724 /* Returns a toplevel GtkWindow, or NULL if none */
725 static GtkWindow *
726 get_toplevel (GtkWidget *widget)
727 {
728   GtkWidget *toplevel;
729
730   toplevel = gtk_widget_get_toplevel (widget);
731   if (!gtk_widget_is_toplevel (toplevel))
732     return NULL;
733   else
734     return GTK_WINDOW (toplevel);
735 }
736
737 /* Shows an error dialog for the file chooser */
738 static void
739 error_message (GtkRecentChooserDefault *impl,
740                const gchar             *msg,
741                const gchar             *detail)
742 {
743   error_message_with_parent (get_toplevel (GTK_WIDGET (impl)), msg, detail);
744 }
745
746 static void
747 set_busy_cursor (GtkRecentChooserDefault *impl,
748                  gboolean                 show_busy_cursor)
749 {
750   GtkWindow *toplevel;
751   GdkDisplay *display;
752   GdkCursor *cursor;
753
754   toplevel = get_toplevel (GTK_WIDGET (impl));
755   if (!toplevel || !gtk_widget_get_realized (GTK_WIDGET (toplevel)))
756     return;
757   
758   display = gtk_widget_get_display (GTK_WIDGET (toplevel));
759   
760   cursor = NULL;
761   if (show_busy_cursor)
762     cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
763
764   gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (toplevel)),
765                          cursor);
766   gdk_display_flush (display);
767
768   if (cursor)
769     g_object_unref (cursor);
770 }
771
772 static void
773 chooser_set_model (GtkRecentChooserDefault *impl)
774 {
775   g_assert (impl->recent_store != NULL);
776   g_assert (impl->load_state == LOAD_LOADING);
777
778   gtk_tree_view_set_model (GTK_TREE_VIEW (impl->recent_view),
779                            GTK_TREE_MODEL (impl->recent_store));
780   gtk_tree_view_columns_autosize (GTK_TREE_VIEW (impl->recent_view));
781   gtk_tree_view_set_enable_search (GTK_TREE_VIEW (impl->recent_view), TRUE);
782   gtk_tree_view_set_search_column (GTK_TREE_VIEW (impl->recent_view),
783                                    RECENT_DISPLAY_NAME_COLUMN);
784
785   impl->load_state = LOAD_FINISHED;
786 }
787
788 static gboolean
789 load_recent_items (gpointer user_data)
790 {
791   GtkRecentChooserDefault *impl;
792   GtkRecentInfo *info;
793   GtkTreeIter iter;
794   const gchar *uri, *name;
795   gboolean retval;
796   
797   impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
798   
799   g_assert ((impl->load_state == LOAD_EMPTY) ||
800             (impl->load_state == LOAD_PRELOAD));
801   
802   /* store the items for multiple runs */
803   if (!impl->recent_items)
804     {
805       impl->recent_items = gtk_recent_chooser_get_items (GTK_RECENT_CHOOSER (impl));
806       if (!impl->recent_items)
807         {
808           impl->load_state = LOAD_FINISHED;
809           
810           return FALSE;
811         }
812         
813       impl->n_recent_items = g_list_length (impl->recent_items);
814       impl->loaded_items = 0;
815       impl->load_state = LOAD_PRELOAD;
816     }
817   
818   info = (GtkRecentInfo *) g_list_nth_data (impl->recent_items,
819                                             impl->loaded_items);
820   g_assert (info);
821
822   uri = gtk_recent_info_get_uri (info);
823   name = gtk_recent_info_get_display_name (info);
824   
825   /* at this point, everything goes inside the model; operations on the
826    * visualization of items inside the model are done in the cell data
827    * funcs (remember that there are two of those: one for the icon and
828    * one for the text), while the filtering is done only when a filter
829    * is actually loaded. */
830   gtk_list_store_append (impl->recent_store, &iter);
831   gtk_list_store_set (impl->recent_store, &iter,
832                       RECENT_URI_COLUMN, uri,           /* uri  */
833                       RECENT_DISPLAY_NAME_COLUMN, name, /* display_name */
834                       RECENT_INFO_COLUMN, info,         /* info */
835                       -1);
836   
837   impl->loaded_items += 1;
838
839   if (impl->loaded_items == impl->n_recent_items)
840     {
841       /* we have finished loading, so we remove the items cache */
842       impl->load_state = LOAD_LOADING;
843       
844       g_list_foreach (impl->recent_items,
845                       (GFunc) gtk_recent_info_unref,
846                       NULL);
847       g_list_free (impl->recent_items);
848       
849       impl->recent_items = NULL;
850       impl->n_recent_items = 0;
851       impl->loaded_items = 0;
852
853       /* load the filled up model */
854       chooser_set_model (impl);
855
856       retval = FALSE;
857     }
858   else
859     {
860       /* we did not finish, so continue loading */
861       retval = TRUE;
862     }
863   
864   return retval;
865 }
866
867 static void
868 cleanup_after_load (gpointer user_data)
869 {
870   GtkRecentChooserDefault *impl;
871   
872   impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
873
874   if (impl->load_id != 0)
875     {
876       g_assert ((impl->load_state == LOAD_EMPTY) ||
877                 (impl->load_state == LOAD_PRELOAD) ||
878                 (impl->load_state == LOAD_LOADING) ||
879                 (impl->load_state == LOAD_FINISHED));
880       
881       /* we have officialy finished loading all the items,
882        * so we can reset the state machine
883        */
884       g_source_remove (impl->load_id);
885       impl->load_id = 0;
886       impl->load_state = LOAD_EMPTY;
887     }
888   else
889     g_assert ((impl->load_state == LOAD_EMPTY) ||
890               (impl->load_state == LOAD_LOADING) ||
891               (impl->load_state == LOAD_FINISHED));
892
893   set_busy_cursor (impl, FALSE);
894 }
895
896 /* clears the current model and reloads the recently used resources */
897 static void
898 reload_recent_items (GtkRecentChooserDefault *impl)
899 {
900   GtkWidget *widget;
901
902   /* reload is already in progress - do not disturb */
903   if (impl->load_id)
904     return;
905   
906   widget = GTK_WIDGET (impl);
907
908   gtk_tree_view_set_model (GTK_TREE_VIEW (impl->recent_view), NULL);
909   gtk_list_store_clear (impl->recent_store);
910   
911   if (!impl->icon_theme)
912     impl->icon_theme = get_icon_theme_for_widget (widget);
913
914   impl->icon_size = get_icon_size_for_widget (widget,
915                                               GTK_ICON_SIZE_BUTTON);
916
917   if (!impl->limit_set)
918     impl->limit = get_recent_files_limit (widget);
919
920   set_busy_cursor (impl, TRUE);
921
922   impl->load_state = LOAD_EMPTY;
923   impl->load_id = gdk_threads_add_idle_full (G_PRIORITY_HIGH_IDLE + 30,
924                                              load_recent_items,
925                                              impl,
926                                              cleanup_after_load);
927 }
928
929 /* taken form gtkfilechooserdialog.c */
930 static void
931 set_default_size (GtkRecentChooserDefault *impl)
932 {
933   GtkScrolledWindow *scrollw;
934   GtkWidget *widget;
935   gint width, height;
936   gint font_size;
937   GdkScreen *screen;
938   gint monitor_num;
939   GtkRequisition req;
940   GdkRectangle monitor;
941   GtkStyleContext *context;
942   GtkStateFlags state;
943
944   widget = GTK_WIDGET (impl);
945   context = gtk_widget_get_style_context (widget);
946   state = gtk_widget_get_state_flags (widget);
947
948   /* Size based on characters and the icon size */
949   font_size = pango_font_description_get_size (gtk_style_context_get_font (context, state));
950   font_size = PANGO_PIXELS (font_size);
951
952   width = impl->icon_size + font_size * NUM_CHARS;
953   height = (impl->icon_size + font_size) * NUM_LINES;
954
955   /* Use at least the requisition size... */
956   gtk_widget_get_preferred_size (widget, &req, NULL);
957   width = MAX (width, req.width);
958   height = MAX (height, req.height);
959
960   /* ... but no larger than the monitor */
961   screen = gtk_widget_get_screen (widget);
962   monitor_num = gdk_screen_get_monitor_at_window (screen,
963                                                   gtk_widget_get_window (widget));
964
965   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
966
967   width = MIN (width, monitor.width * 3 / 4);
968   height = MIN (height, monitor.height * 3 / 4);
969
970   /* Set size */
971   scrollw = GTK_SCROLLED_WINDOW (gtk_widget_get_parent (impl->recent_view));
972   gtk_scrolled_window_set_min_content_width (scrollw, width);
973   gtk_scrolled_window_set_min_content_height (scrollw, height);
974 }
975
976 static void
977 gtk_recent_chooser_default_map (GtkWidget *widget)
978 {
979   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (widget);
980
981   GTK_WIDGET_CLASS (_gtk_recent_chooser_default_parent_class)->map (widget);
982
983   /* reloads everything */
984   reload_recent_items (impl);
985
986   set_default_size (impl);
987 }
988
989 static void
990 recent_icon_data_func (GtkTreeViewColumn *tree_column,
991                        GtkCellRenderer   *cell,
992                        GtkTreeModel      *model,
993                        GtkTreeIter       *iter,
994                        gpointer           user_data)
995 {
996   GtkRecentInfo *info = NULL;
997   GIcon *icon;
998
999   gtk_tree_model_get (model, iter, RECENT_INFO_COLUMN, &info, -1);
1000   g_assert (info != NULL);
1001
1002   icon = gtk_recent_info_get_gicon (info);
1003   g_object_set (cell, "gicon", icon, NULL);
1004
1005   if (icon != NULL)
1006     g_object_unref (icon);
1007
1008   gtk_recent_info_unref (info);
1009 }
1010
1011 static void
1012 recent_meta_data_func (GtkTreeViewColumn *tree_column,
1013                        GtkCellRenderer   *cell,
1014                        GtkTreeModel      *model,
1015                        GtkTreeIter       *iter,
1016                        gpointer           user_data)
1017 {
1018   GtkRecentInfo *info = NULL;
1019   gchar *name;
1020   
1021   gtk_tree_model_get (model, iter,
1022                       RECENT_DISPLAY_NAME_COLUMN, &name,
1023                       RECENT_INFO_COLUMN, &info,
1024                       -1);
1025   g_assert (info != NULL);
1026   
1027   if (!name)
1028     name = gtk_recent_info_get_short_name (info);
1029
1030   g_object_set (cell, "text", name, NULL);
1031   
1032   g_free (name);
1033   gtk_recent_info_unref (info);
1034 }
1035
1036
1037 static gchar *
1038 gtk_recent_chooser_default_get_current_uri (GtkRecentChooser *chooser)
1039 {
1040   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
1041   
1042   g_assert (impl->selection != NULL);
1043   
1044   if (!impl->select_multiple)
1045     {
1046       GtkTreeModel *model;
1047       GtkTreeIter iter;
1048       gchar *uri = NULL;
1049       
1050       if (!gtk_tree_selection_get_selected (impl->selection, &model, &iter))
1051         return NULL;
1052       
1053       gtk_tree_model_get (model, &iter, RECENT_URI_COLUMN, &uri, -1);
1054       
1055       return uri;
1056     }
1057   
1058   return NULL;
1059 }
1060
1061 typedef struct
1062 {
1063   guint found : 1;
1064   guint do_select : 1;
1065   guint do_activate : 1;
1066   
1067   gchar *uri;
1068   
1069   GtkRecentChooserDefault *impl;
1070 } SelectURIData;
1071
1072 static gboolean
1073 scan_for_uri_cb (GtkTreeModel *model,
1074                  GtkTreePath  *path,
1075                  GtkTreeIter  *iter,
1076                  gpointer      user_data)
1077 {
1078   SelectURIData *select_data = (SelectURIData *) user_data;
1079   gchar *uri = NULL;
1080   
1081   if (!select_data)
1082     return TRUE;
1083   
1084   if (select_data->found)
1085     return TRUE;
1086   
1087   gtk_tree_model_get (model, iter, RECENT_URI_COLUMN, &uri, -1);
1088   if (!uri)
1089     return FALSE;
1090   
1091   if (strcmp (uri, select_data->uri) == 0)
1092     {
1093       select_data->found = TRUE;
1094       
1095       if (select_data->do_activate)
1096         gtk_tree_view_row_activated (GTK_TREE_VIEW (select_data->impl->recent_view),
1097                                      path,
1098                                      select_data->impl->meta_column);
1099       
1100       if (select_data->do_select)
1101         gtk_tree_selection_select_path (select_data->impl->selection, path);
1102       else
1103         gtk_tree_selection_unselect_path (select_data->impl->selection, path);
1104
1105       g_free (uri);
1106       
1107       return TRUE;
1108     }
1109
1110   g_free (uri);
1111   
1112   return FALSE;
1113 }
1114
1115 static gboolean
1116 gtk_recent_chooser_default_set_current_uri (GtkRecentChooser  *chooser,
1117                                             const gchar       *uri,
1118                                             GError           **error)
1119 {
1120   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
1121   SelectURIData *data;
1122   
1123   data = g_new0 (SelectURIData, 1);
1124   data->uri = g_strdup (uri);
1125   data->impl = impl;
1126   data->found = FALSE;
1127   data->do_activate = TRUE;
1128   data->do_select = TRUE;
1129   
1130   gtk_tree_model_foreach (GTK_TREE_MODEL (impl->recent_store),
1131                           scan_for_uri_cb,
1132                           data);
1133   
1134   if (!data->found)
1135     {
1136       g_free (data->uri);
1137       g_free (data);
1138       
1139       g_set_error (error, GTK_RECENT_CHOOSER_ERROR,
1140                    GTK_RECENT_CHOOSER_ERROR_NOT_FOUND,
1141                    _("No item for URI '%s' found"),
1142                    uri);
1143       return FALSE;
1144     }
1145   
1146   g_free (data->uri);
1147   g_free (data);
1148
1149   return TRUE;
1150 }
1151
1152 static gboolean
1153 gtk_recent_chooser_default_select_uri (GtkRecentChooser  *chooser,
1154                                        const gchar       *uri,
1155                                        GError           **error)
1156 {
1157   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
1158   SelectURIData *data;
1159   
1160   data = g_new0 (SelectURIData, 1);
1161   data->uri = g_strdup (uri);
1162   data->impl = impl;
1163   data->found = FALSE;
1164   data->do_activate = FALSE;
1165   data->do_select = TRUE;
1166   
1167   gtk_tree_model_foreach (GTK_TREE_MODEL (impl->recent_store),
1168                           scan_for_uri_cb,
1169                           data);
1170   
1171   if (!data->found)
1172     {
1173       g_free (data->uri);
1174       g_free (data);
1175       
1176       g_set_error (error, GTK_RECENT_CHOOSER_ERROR,
1177                    GTK_RECENT_CHOOSER_ERROR_NOT_FOUND,
1178                    _("No item for URI '%s' found"),
1179                    uri);
1180       return FALSE;
1181     }
1182   
1183   g_free (data->uri);
1184   g_free (data);
1185
1186   return TRUE;
1187 }
1188
1189 static void
1190 gtk_recent_chooser_default_unselect_uri (GtkRecentChooser *chooser,
1191                                          const gchar      *uri)
1192 {
1193   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
1194   SelectURIData *data;
1195   
1196   data = g_new0 (SelectURIData, 1);
1197   data->uri = g_strdup (uri);
1198   data->impl = impl;
1199   data->found = FALSE;
1200   data->do_activate = FALSE;
1201   data->do_select = FALSE;
1202   
1203   gtk_tree_model_foreach (GTK_TREE_MODEL (impl->recent_store),
1204                           scan_for_uri_cb,
1205                           data);
1206   
1207   g_free (data->uri);
1208   g_free (data);
1209 }
1210
1211 static void
1212 gtk_recent_chooser_default_select_all (GtkRecentChooser *chooser)
1213 {
1214   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
1215   
1216   if (!impl->select_multiple)
1217     return;
1218   
1219   gtk_tree_selection_select_all (impl->selection);
1220 }
1221
1222 static void
1223 gtk_recent_chooser_default_unselect_all (GtkRecentChooser *chooser)
1224 {
1225   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
1226   
1227   gtk_tree_selection_unselect_all (impl->selection);
1228 }
1229
1230 static void
1231 gtk_recent_chooser_default_set_sort_func (GtkRecentChooser  *chooser,
1232                                           GtkRecentSortFunc  sort_func,
1233                                           gpointer           sort_data,
1234                                           GDestroyNotify     data_destroy)
1235 {
1236   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
1237   
1238   if (impl->sort_data_destroy)
1239     {
1240       impl->sort_data_destroy (impl->sort_data);
1241       impl->sort_data_destroy = NULL;
1242     }
1243       
1244   impl->sort_func = NULL;
1245   impl->sort_data = NULL;
1246   
1247   if (sort_func)
1248     {
1249       impl->sort_func = sort_func;
1250       impl->sort_data = sort_data;
1251       impl->sort_data_destroy = data_destroy;
1252     }
1253 }
1254
1255 static GList *
1256 gtk_recent_chooser_default_get_items (GtkRecentChooser *chooser)
1257 {
1258   GtkRecentChooserDefault *impl;
1259
1260   impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
1261
1262   return _gtk_recent_chooser_get_items (chooser,
1263                                         impl->current_filter,
1264                                         impl->sort_func,
1265                                         impl->sort_data);
1266 }
1267
1268 static GtkRecentManager *
1269 gtk_recent_chooser_default_get_recent_manager (GtkRecentChooser *chooser)
1270 {
1271   return GTK_RECENT_CHOOSER_DEFAULT (chooser)->manager;
1272 }
1273
1274 static void
1275 show_filters (GtkRecentChooserDefault *impl,
1276               gboolean                 show)
1277 {
1278   if (show)
1279     gtk_widget_show (impl->filter_combo_hbox);
1280   else
1281     gtk_widget_hide (impl->filter_combo_hbox);
1282 }
1283
1284 static void
1285 gtk_recent_chooser_default_add_filter (GtkRecentChooser *chooser,
1286                                        GtkRecentFilter  *filter)
1287 {
1288   GtkRecentChooserDefault *impl;
1289   const gchar *name;
1290
1291   impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
1292   
1293   if (g_slist_find (impl->filters, filter))
1294     {
1295       g_warning ("gtk_recent_chooser_add_filter() called on filter already in list\n");
1296       return;
1297     }
1298   
1299   g_object_ref_sink (filter);
1300   impl->filters = g_slist_append (impl->filters, filter);
1301   
1302   /* display new filter */
1303   name = gtk_recent_filter_get_name (filter);
1304   if (!name)
1305     name = _("Untitled filter");
1306
1307   gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (impl->filter_combo), name);
1308
1309   if (!g_slist_find (impl->filters, impl->current_filter))
1310     set_current_filter (impl, filter);
1311   
1312   show_filters (impl, TRUE);
1313 }
1314
1315 static void
1316 gtk_recent_chooser_default_remove_filter (GtkRecentChooser *chooser,
1317                                           GtkRecentFilter  *filter)
1318 {
1319   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
1320   GtkTreeModel *model;
1321   GtkTreeIter iter;
1322   gint filter_idx;
1323   
1324   filter_idx = g_slist_index (impl->filters, filter);
1325   
1326   if (filter_idx < 0)
1327     {
1328       g_warning ("gtk_recent_chooser_remove_filter() called on filter not in list\n");
1329       return;  
1330     }
1331   
1332   impl->filters = g_slist_remove (impl->filters, filter);
1333   
1334   if (filter == impl->current_filter)
1335     {
1336       if (impl->filters)
1337         set_current_filter (impl, impl->filters->data);
1338       else
1339         set_current_filter (impl, NULL);
1340     }
1341   
1342   model = gtk_combo_box_get_model (GTK_COMBO_BOX (impl->filter_combo));
1343   gtk_tree_model_iter_nth_child (model, &iter, NULL, filter_idx);
1344   gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
1345   
1346   g_object_unref (filter);
1347   
1348   if (!impl->filters)
1349     show_filters (impl, FALSE);
1350 }
1351
1352 static GSList *
1353 gtk_recent_chooser_default_list_filters (GtkRecentChooser *chooser)
1354 {
1355   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
1356   
1357   return g_slist_copy (impl->filters);
1358 }
1359
1360 static void
1361 set_current_filter (GtkRecentChooserDefault *impl,
1362                     GtkRecentFilter         *filter)
1363 {
1364   if (impl->current_filter != filter)
1365     {
1366       gint filter_idx;
1367       
1368       filter_idx = g_slist_index (impl->filters, filter);
1369       if (impl->filters && filter && filter_idx < 0)
1370         return;
1371       
1372       if (impl->current_filter)
1373         g_object_unref (impl->current_filter);
1374       
1375       impl->current_filter = filter;
1376       
1377       if (impl->current_filter)     
1378         {
1379           g_object_ref_sink (impl->current_filter);
1380         }
1381       
1382       if (impl->filters)
1383         gtk_combo_box_set_active (GTK_COMBO_BOX (impl->filter_combo),
1384                                   filter_idx);
1385       
1386       if (impl->recent_store)
1387         reload_recent_items (impl);
1388
1389       g_object_notify (G_OBJECT (impl), "filter");
1390     }
1391 }
1392
1393 static void
1394 chooser_set_sort_type (GtkRecentChooserDefault *impl,
1395                        GtkRecentSortType        sort_type)
1396 {
1397   if (impl->sort_type != sort_type)
1398     {
1399       impl->sort_type = sort_type;
1400       reload_recent_items (impl);
1401
1402       g_object_notify (G_OBJECT (impl), "sort-type");
1403     }
1404 }
1405
1406
1407 static GtkIconTheme *
1408 get_icon_theme_for_widget (GtkWidget *widget)
1409 {
1410   if (gtk_widget_has_screen (widget))
1411     return gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
1412
1413   return gtk_icon_theme_get_default ();
1414 }
1415
1416 static gint
1417 get_icon_size_for_widget (GtkWidget   *widget,
1418                           GtkIconSize  icon_size)
1419 {
1420   GtkSettings *settings;
1421   gint width, height;
1422
1423   if (gtk_widget_has_screen (widget))
1424     settings = gtk_settings_get_for_screen (gtk_widget_get_screen (widget));
1425   else
1426     settings = gtk_settings_get_default ();
1427
1428   if (gtk_icon_size_lookup_for_settings (settings, icon_size,
1429                                          &width, &height))
1430     return MAX (width, height);
1431
1432   return FALLBACK_ICON_SIZE;
1433 }
1434
1435 static gint
1436 get_recent_files_limit (GtkWidget *widget)
1437 {
1438   GtkSettings *settings;
1439   gint limit;
1440
1441   if (gtk_widget_has_screen (widget))
1442     settings = gtk_settings_get_for_screen (gtk_widget_get_screen (widget));
1443   else
1444     settings = gtk_settings_get_default ();
1445   
1446   g_object_get (G_OBJECT (settings), "gtk-recent-files-limit", &limit, NULL);
1447
1448   return limit;
1449 }
1450
1451 static void
1452 recent_manager_changed_cb (GtkRecentManager *manager,
1453                            gpointer          user_data)
1454 {
1455   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
1456
1457   reload_recent_items (impl);
1458 }
1459
1460 static void
1461 selection_changed_cb (GtkTreeSelection *selection,
1462                       gpointer          user_data)
1463 {
1464   _gtk_recent_chooser_selection_changed (GTK_RECENT_CHOOSER (user_data));
1465 }
1466
1467 static void
1468 row_activated_cb (GtkTreeView       *tree_view,
1469                   GtkTreePath       *tree_path,
1470                   GtkTreeViewColumn *tree_column,
1471                   gpointer           user_data)
1472 {
1473   _gtk_recent_chooser_item_activated (GTK_RECENT_CHOOSER (user_data));
1474 }
1475
1476 static void
1477 filter_combo_changed_cb (GtkComboBox *combo_box,
1478                          gpointer     user_data)
1479 {
1480   GtkRecentChooserDefault *impl;
1481   gint new_index;
1482   GtkRecentFilter *filter;
1483   
1484   impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
1485   
1486   new_index = gtk_combo_box_get_active (combo_box);
1487   filter = g_slist_nth_data (impl->filters, new_index);
1488   
1489   set_current_filter (impl, filter);
1490 }
1491
1492 static GdkPixbuf *
1493 get_drag_pixbuf (GtkRecentChooserDefault *impl)
1494 {
1495   GtkRecentInfo *info;
1496   GdkPixbuf *retval;
1497   gint size;
1498   
1499   g_assert (GTK_IS_RECENT_CHOOSER_DEFAULT (impl));
1500
1501   info = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (impl));
1502   if (!info)
1503     return NULL;
1504
1505   size = get_icon_size_for_widget (GTK_WIDGET (impl), GTK_ICON_SIZE_DND);
1506
1507   retval = gtk_recent_info_get_icon (info, size);
1508   gtk_recent_info_unref (info);
1509
1510   return retval;
1511 }
1512
1513 static void
1514 recent_view_drag_begin_cb (GtkWidget      *widget,
1515                            GdkDragContext *context,
1516                            gpointer        user_data)
1517 {
1518   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
1519   GdkPixbuf *pixbuf;
1520
1521   pixbuf = get_drag_pixbuf (impl);
1522   if (pixbuf)
1523     {
1524       gtk_drag_set_icon_pixbuf (context, pixbuf, 0, 0);
1525       g_object_unref (pixbuf);
1526     }
1527   else
1528     gtk_drag_set_icon_default (context);
1529 }
1530
1531 typedef struct
1532 {
1533   gchar **uri_list;
1534   gsize next_pos;
1535 } DragData;
1536
1537 static void
1538 append_uri_to_urilist (GtkTreeModel *model,
1539                        GtkTreePath  *path,
1540                        GtkTreeIter  *iter,
1541                        gpointer      user_data)
1542 {
1543   DragData *drag_data = (DragData *) user_data;
1544   GtkTreeModel *child_model;
1545   GtkTreeIter child_iter;
1546   gchar *uri = NULL;
1547   gsize pos;
1548
1549   child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
1550   gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model),
1551                                                     &child_iter,
1552                                                     iter);
1553   gtk_tree_model_get (child_model, &child_iter,
1554                       RECENT_URI_COLUMN, &uri,
1555                       -1);
1556   g_assert (uri != NULL);
1557
1558   pos = drag_data->next_pos;
1559   drag_data->uri_list[pos] = g_strdup (uri);
1560   drag_data->next_pos = pos + 1;
1561 }
1562
1563 static void
1564 recent_view_drag_data_get_cb (GtkWidget        *widget,
1565                               GdkDragContext   *context,
1566                               GtkSelectionData *selection_data,
1567                               guint             info,
1568                               guint32           time_,
1569                               gpointer          data)
1570 {
1571   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (data);
1572   DragData drag_data;
1573   gsize n_uris;
1574   
1575   n_uris = gtk_tree_selection_count_selected_rows (impl->selection);
1576   if (n_uris == 0)
1577     return;
1578
1579   drag_data.uri_list = g_new0 (gchar *, n_uris + 1);
1580   drag_data.next_pos = 0;
1581   
1582   gtk_tree_selection_selected_foreach (impl->selection,
1583                                        append_uri_to_urilist,
1584                                        &drag_data);
1585   
1586   gtk_selection_data_set_uris (selection_data, drag_data.uri_list);
1587
1588   g_strfreev (drag_data.uri_list);
1589 }
1590
1591 static gboolean
1592 recent_view_query_tooltip_cb (GtkWidget  *widget,
1593                               gint        x,
1594                               gint        y,
1595                               gboolean    keyboard_tip,
1596                               GtkTooltip *tooltip,
1597                               gpointer    user_data)
1598 {
1599   GtkRecentChooserDefault *impl = user_data;
1600   GtkTreeView *tree_view;
1601   GtkTreeIter iter;
1602   GtkTreePath *path = NULL;
1603   GtkRecentInfo *info = NULL;
1604   gchar *uri_display;
1605
1606   if (!impl->show_tips)
1607     return FALSE;
1608
1609   tree_view = GTK_TREE_VIEW (impl->recent_view);
1610
1611   gtk_tree_view_get_tooltip_context (tree_view,
1612                                      &x, &y,
1613                                      keyboard_tip,
1614                                      NULL, &path, NULL);
1615   if (!path)
1616     return FALSE;
1617
1618   if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->recent_store), &iter, path))
1619     {
1620       gtk_tree_path_free (path);
1621       return FALSE;
1622     }
1623
1624   gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_store), &iter,
1625                       RECENT_INFO_COLUMN, &info,
1626                       -1);
1627
1628   uri_display = gtk_recent_info_get_uri_display (info);
1629   
1630   gtk_tooltip_set_text (tooltip, uri_display);
1631   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
1632
1633   g_free (uri_display);
1634   gtk_tree_path_free (path);
1635   gtk_recent_info_unref (info);
1636
1637   return TRUE;
1638 }
1639
1640 static void
1641 remove_selected_from_list (GtkRecentChooserDefault *impl)
1642 {
1643   gchar *uri;
1644   GError *err;
1645   
1646   if (impl->select_multiple)
1647     return;
1648   
1649   uri = gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (impl));
1650   if (!uri)
1651     return;
1652   
1653   err = NULL;
1654   if (!gtk_recent_manager_remove_item (impl->manager, uri, &err))
1655     {
1656       gchar *msg;
1657    
1658       msg = g_strdup (_("Could not remove item"));
1659       error_message (impl, msg, err->message);
1660       
1661       g_free (msg);
1662       g_error_free (err);
1663     }
1664   
1665   g_free (uri);
1666 }
1667
1668 static void
1669 copy_activated_cb (GtkMenuItem *menu_item,
1670                    gpointer     user_data)
1671 {
1672   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
1673   GtkRecentInfo *info;
1674   gchar *utf8_uri;
1675
1676   info = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (impl));
1677   if (!info)
1678     return;
1679
1680   utf8_uri = gtk_recent_info_get_uri_display (info);
1681   
1682   gtk_clipboard_set_text (gtk_widget_get_clipboard (GTK_WIDGET (impl),
1683                                                     GDK_SELECTION_CLIPBOARD),
1684                           utf8_uri, -1);
1685
1686   gtk_recent_info_unref (info);
1687   g_free (utf8_uri);
1688 }
1689
1690 static void
1691 remove_all_activated_cb (GtkMenuItem *menu_item,
1692                          gpointer     user_data)
1693 {
1694   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
1695   GError *err = NULL;
1696   
1697   gtk_recent_manager_purge_items (impl->manager, &err);
1698   if (err)
1699     {
1700        gchar *msg;
1701
1702        msg = g_strdup (_("Could not clear list"));
1703
1704        error_message (impl, msg, err->message);
1705        
1706        g_free (msg);
1707        g_error_free (err);
1708     }
1709 }
1710
1711 static void
1712 remove_item_activated_cb (GtkMenuItem *menu_item,
1713                           gpointer     user_data)
1714 {
1715   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
1716   
1717   remove_selected_from_list (impl);
1718 }
1719
1720 static void
1721 show_private_toggled_cb (GtkCheckMenuItem *menu_item,
1722                          gpointer          user_data)
1723 {
1724   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
1725   
1726   g_object_set (G_OBJECT (impl),
1727                 "show-private", gtk_check_menu_item_get_active (menu_item),
1728                 NULL);
1729 }
1730
1731 static void
1732 recent_popup_menu_detach_cb (GtkWidget *attach_widget,
1733                              GtkMenu   *menu)
1734 {
1735   GtkRecentChooserDefault *impl;
1736   
1737   impl = g_object_get_data (G_OBJECT (attach_widget), "GtkRecentChooserDefault");
1738   g_assert (GTK_IS_RECENT_CHOOSER_DEFAULT (impl));
1739   
1740   impl->recent_popup_menu = NULL;
1741   impl->recent_popup_menu_remove_item = NULL;
1742   impl->recent_popup_menu_copy_item = NULL;
1743   impl->recent_popup_menu_clear_item = NULL;
1744   impl->recent_popup_menu_show_private_item = NULL;
1745 }
1746
1747 static void
1748 recent_view_menu_ensure_state (GtkRecentChooserDefault *impl)
1749 {
1750   gint count;
1751   
1752   g_assert (GTK_IS_RECENT_CHOOSER_DEFAULT (impl));
1753   g_assert (impl->recent_popup_menu != NULL);
1754
1755   if (!impl->manager)
1756     count = 0;
1757   else
1758     g_object_get (G_OBJECT (impl->manager), "size", &count, NULL);
1759
1760   if (count == 0)
1761     {
1762       gtk_widget_set_sensitive (impl->recent_popup_menu_remove_item, FALSE);
1763       gtk_widget_set_sensitive (impl->recent_popup_menu_copy_item, FALSE);
1764       gtk_widget_set_sensitive (impl->recent_popup_menu_clear_item, FALSE);
1765       gtk_widget_set_sensitive (impl->recent_popup_menu_show_private_item, FALSE);
1766     }
1767 }
1768
1769 static void
1770 recent_view_menu_build (GtkRecentChooserDefault *impl)
1771 {
1772   GtkWidget *item;
1773   
1774   if (impl->recent_popup_menu)
1775     {
1776       recent_view_menu_ensure_state (impl);
1777       
1778       return;
1779     }
1780   
1781   impl->recent_popup_menu = gtk_menu_new ();
1782   gtk_menu_attach_to_widget (GTK_MENU (impl->recent_popup_menu),
1783                              impl->recent_view,
1784                              recent_popup_menu_detach_cb);
1785   
1786   item = gtk_image_menu_item_new_with_mnemonic (_("Copy _Location"));
1787   impl->recent_popup_menu_copy_item = item;
1788   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
1789                                  gtk_image_new_from_stock (GTK_STOCK_COPY, GTK_ICON_SIZE_MENU));
1790   g_signal_connect (item, "activate",
1791                     G_CALLBACK (copy_activated_cb), impl);
1792   gtk_widget_show (item);
1793   gtk_menu_shell_append (GTK_MENU_SHELL (impl->recent_popup_menu), item);
1794
1795   item = gtk_separator_menu_item_new ();
1796   gtk_widget_show (item);
1797   gtk_menu_shell_append (GTK_MENU_SHELL (impl->recent_popup_menu), item);
1798   
1799   item = gtk_image_menu_item_new_with_mnemonic (_("_Remove From List"));
1800   impl->recent_popup_menu_remove_item = item;
1801   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
1802                                  gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU));
1803   g_signal_connect (item, "activate",
1804                     G_CALLBACK (remove_item_activated_cb), impl);
1805   gtk_widget_show (item);
1806   gtk_menu_shell_append (GTK_MENU_SHELL (impl->recent_popup_menu), item);
1807
1808   item = gtk_image_menu_item_new_with_mnemonic (_("_Clear List"));
1809   impl->recent_popup_menu_clear_item = item;
1810   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
1811                                  gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU));
1812   g_signal_connect (item, "activate",
1813                     G_CALLBACK (remove_all_activated_cb), impl);
1814   
1815   gtk_widget_show (item);
1816   gtk_menu_shell_append (GTK_MENU_SHELL (impl->recent_popup_menu), item);
1817   
1818   item = gtk_separator_menu_item_new ();
1819   gtk_widget_show (item);
1820   gtk_menu_shell_append (GTK_MENU_SHELL (impl->recent_popup_menu), item);
1821   
1822   item = gtk_check_menu_item_new_with_mnemonic (_("Show _Private Resources"));
1823   impl->recent_popup_menu_show_private_item = item;
1824   gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), impl->show_private);
1825   g_signal_connect (item, "toggled",
1826                     G_CALLBACK (show_private_toggled_cb), impl);
1827   gtk_widget_show (item);
1828   gtk_menu_shell_append (GTK_MENU_SHELL (impl->recent_popup_menu), item);
1829   
1830   recent_view_menu_ensure_state (impl);
1831 }
1832
1833 /* taken from gtkfilechooserdefault.c */
1834 static void
1835 popup_position_func (GtkMenu   *menu,
1836                      gint      *x,
1837                      gint      *y,
1838                      gboolean  *push_in,
1839                      gpointer   user_data)
1840 {
1841   GtkAllocation allocation;
1842   GtkWidget *widget = GTK_WIDGET (user_data);
1843   GdkScreen *screen = gtk_widget_get_screen (widget);
1844   GtkRequisition req;
1845   gint monitor_num;
1846   GdkRectangle monitor;
1847
1848   if (G_UNLIKELY (!gtk_widget_get_realized (widget)))
1849     return;
1850
1851   gdk_window_get_origin (gtk_widget_get_window (widget),
1852                          x, y);
1853
1854   gtk_widget_get_preferred_size (GTK_WIDGET (menu),
1855                                  &req, NULL);
1856
1857   gtk_widget_get_allocation (widget, &allocation);
1858   *x += (allocation.width - req.width) / 2;
1859   *y += (allocation.height - req.height) / 2;
1860
1861   monitor_num = gdk_screen_get_monitor_at_point (screen, *x, *y);
1862   gtk_menu_set_monitor (menu, monitor_num);
1863   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
1864
1865   *x = CLAMP (*x, monitor.x, monitor.x + MAX (0, monitor.width - req.width));
1866   *y = CLAMP (*y, monitor.y, monitor.y + MAX (0, monitor.height - req.height));
1867
1868   *push_in = FALSE;
1869 }
1870
1871
1872 static void
1873 recent_view_menu_popup (GtkRecentChooserDefault *impl,
1874                         GdkEventButton          *event)
1875 {
1876   recent_view_menu_build (impl);
1877   
1878   if (event)
1879     gtk_menu_popup (GTK_MENU (impl->recent_popup_menu),
1880                     NULL, NULL, NULL, NULL,
1881                     event->button, event->time);
1882   else
1883     {
1884       gtk_menu_popup (GTK_MENU (impl->recent_popup_menu),
1885                       NULL, NULL,
1886                       popup_position_func, impl->recent_view,
1887                       0, GDK_CURRENT_TIME);
1888       gtk_menu_shell_select_first (GTK_MENU_SHELL (impl->recent_popup_menu),
1889                                    FALSE);
1890     }
1891 }
1892
1893 static gboolean
1894 recent_view_popup_menu_cb (GtkWidget *widget,
1895                            gpointer   user_data)
1896 {
1897   recent_view_menu_popup (GTK_RECENT_CHOOSER_DEFAULT (user_data), NULL);
1898   return TRUE;
1899 }
1900
1901 static gboolean
1902 recent_view_button_press_cb (GtkWidget      *widget,
1903                              GdkEventButton *event,
1904                              gpointer        user_data)
1905 {
1906   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
1907   
1908   if (event->button == 3)
1909     {
1910       GtkTreePath *path;
1911       gboolean res;
1912
1913       if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (impl->recent_view)))
1914         return FALSE;
1915
1916       res = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (impl->recent_view),
1917                                            event->x, event->y,
1918                                            &path,
1919                                            NULL, NULL, NULL);
1920       if (!res)
1921         return FALSE;
1922
1923       /* select the path before creating the popup menu */
1924       gtk_tree_selection_select_path (impl->selection, path);
1925       gtk_tree_path_free (path);
1926       
1927       recent_view_menu_popup (impl, event);
1928
1929       return TRUE;
1930     }
1931   
1932   return FALSE;
1933 }
1934
1935 static void
1936 set_recent_manager (GtkRecentChooserDefault *impl,
1937                     GtkRecentManager        *manager)
1938 {
1939   if (impl->manager)
1940     {
1941       if (impl->manager_changed_id)
1942         {
1943           g_signal_handler_disconnect (impl, impl->manager_changed_id);
1944           impl->manager_changed_id = 0;
1945         }
1946
1947       impl->manager = NULL;
1948     }
1949   
1950   if (manager)
1951     impl->manager = manager;
1952   else
1953     impl->manager = gtk_recent_manager_get_default ();
1954   
1955   if (impl->manager)
1956     {
1957       impl->manager_changed_id = g_signal_connect (impl->manager, "changed",
1958                                                    G_CALLBACK (recent_manager_changed_cb),
1959                                                    impl);
1960     }
1961 }
1962
1963 static void
1964 gtk_recent_chooser_update (GtkActivatable *activatable,
1965                            GtkAction      *action,
1966                            const gchar    *property_name)
1967 {
1968   if (strcmp (property_name, "visible") == 0)
1969     {
1970       if (gtk_action_is_visible (action))
1971         gtk_widget_show (GTK_WIDGET (activatable));
1972       else
1973         gtk_widget_hide (GTK_WIDGET (activatable));
1974     }
1975
1976   if (strcmp (property_name, "sensitive") == 0)
1977     gtk_widget_set_sensitive (GTK_WIDGET (activatable), gtk_action_is_sensitive (action));
1978
1979   _gtk_recent_chooser_update (activatable, action, property_name);
1980 }
1981
1982
1983 static void 
1984 gtk_recent_chooser_sync_action_properties (GtkActivatable *activatable,
1985                                            GtkAction      *action)
1986 {
1987   if (action)
1988     {
1989       if (gtk_action_is_visible (action))
1990         gtk_widget_show (GTK_WIDGET (activatable));
1991       else
1992         gtk_widget_hide (GTK_WIDGET (activatable));
1993       
1994       gtk_widget_set_sensitive (GTK_WIDGET (activatable), gtk_action_is_sensitive (action));
1995     }
1996
1997   _gtk_recent_chooser_sync_action_properties (activatable, action);
1998 }
1999
2000
2001 GtkWidget *
2002 _gtk_recent_chooser_default_new (GtkRecentManager *manager)
2003 {
2004   return g_object_new (GTK_TYPE_RECENT_CHOOSER_DEFAULT,
2005                        "recent-manager", manager,
2006                        NULL);
2007 }