1 /* vi:set et ai sw=2 sts=2 ts=2: */
2 /*-
3  * Copyright (c) 2005-2007 Benedikt Meurer <benny@xfce.org>
4  * Copyright (c) 2009-2011 Jannis Pohlmann <jannis@xfce.org>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this program; if not, write to the Free
18  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #ifdef HAVE_LOCALE_H
30 #include <locale.h>
31 #endif
32 
33 #include <gdk/gdkkeysyms.h>
34 
35 #include <thunar/thunar-application.h>
36 #include <thunar/thunar-browser.h>
37 #include <thunar/thunar-clipboard-manager.h>
38 #include <thunar/thunar-compact-view.h>
39 #include <thunar/thunar-details-view.h>
40 #include <thunar/thunar-dialogs.h>
41 #include <thunar/thunar-shortcuts-pane.h>
42 #include <thunar/thunar-gio-extensions.h>
43 #include <thunar/thunar-gobject-extensions.h>
44 #include <thunar/thunar-gtk-extensions.h>
45 #include <thunar/thunar-history.h>
46 #include <thunar/thunar-icon-view.h>
47 #include <thunar/thunar-launcher.h>
48 #include <thunar/thunar-location-buttons.h>
49 #include <thunar/thunar-location-entry.h>
50 #include <thunar/thunar-marshal.h>
51 #include <thunar/thunar-menu.h>
52 #include <thunar/thunar-pango-extensions.h>
53 #include <thunar/thunar-preferences-dialog.h>
54 #include <thunar/thunar-preferences.h>
55 #include <thunar/thunar-private.h>
56 #include <thunar/thunar-util.h>
57 #include <thunar/thunar-statusbar.h>
58 #include <thunar/thunar-tree-pane.h>
59 #include <thunar/thunar-window.h>
60 #include <thunar/thunar-device-monitor.h>
61 
62 #include <glib.h>
63 
64 
65 
66 /* Property identifiers */
67 enum
68 {
69   PROP_0,
70   PROP_CURRENT_DIRECTORY,
71   PROP_ZOOM_LEVEL,
72   PROP_DIRECTORY_SPECIFIC_SETTINGS,
73 };
74 
75 /* Signal identifiers */
76 enum
77 {
78   BACK,
79   RELOAD,
80   TOGGLE_SIDEPANE,
81   TOGGLE_MENUBAR,
82   ZOOM_IN,
83   ZOOM_OUT,
84   ZOOM_RESET,
85   TAB_CHANGE,
86   LAST_SIGNAL,
87 };
88 
89 struct _ThunarBookmark
90 {
91   GFile *g_file;
92   gchar *name;
93 };
94 typedef struct _ThunarBookmark ThunarBookmark;
95 
96 
97 
98 static void      thunar_window_screen_changed             (GtkWidget              *widget,
99                                                            GdkScreen              *old_screen,
100                                                            gpointer                userdata);
101 static void      thunar_window_dispose                    (GObject                *object);
102 static void      thunar_window_finalize                   (GObject                *object);
103 static gboolean  thunar_window_delete                     (GtkWidget              *widget,
104                                                            GdkEvent               *event,
105                                                            gpointer                data);
106 static void      thunar_window_get_property               (GObject                *object,
107                                                            guint                   prop_id,
108                                                            GValue                 *value,
109                                                            GParamSpec             *pspec);
110 static void      thunar_window_set_property               (GObject                *object,
111                                                            guint                   prop_id,
112                                                            const GValue           *value,
113                                                            GParamSpec             *pspec);
114 static gboolean  thunar_window_reload                     (ThunarWindow           *window,
115                                                            gboolean                reload_info);
116 static gboolean  thunar_window_toggle_sidepane            (ThunarWindow           *window);
117 static gboolean  thunar_window_zoom_in                    (ThunarWindow           *window);
118 static gboolean  thunar_window_zoom_out                   (ThunarWindow           *window);
119 static gboolean  thunar_window_zoom_reset                 (ThunarWindow           *window);
120 static gboolean  thunar_window_tab_change                 (ThunarWindow           *window,
121                                                            gint                    nth);
122 static void      thunar_window_realize                    (GtkWidget              *widget);
123 static void      thunar_window_unrealize                  (GtkWidget              *widget);
124 static gboolean  thunar_window_configure_event            (GtkWidget              *widget,
125                                                            GdkEventConfigure      *event);
126 static void      thunar_window_notebook_switch_page       (GtkWidget              *notebook,
127                                                            GtkWidget              *page,
128                                                            guint                   page_num,
129                                                            ThunarWindow           *window);
130 static void      thunar_window_notebook_page_added        (GtkWidget              *notebook,
131                                                            GtkWidget              *page,
132                                                            guint                   page_num,
133                                                            ThunarWindow           *window);
134 static void      thunar_window_notebook_page_removed      (GtkWidget              *notebook,
135                                                            GtkWidget              *page,
136                                                            guint                   page_num,
137                                                            ThunarWindow           *window);
138 static gboolean  thunar_window_notebook_button_press_event(GtkWidget              *notebook,
139                                                            GdkEventButton         *event,
140                                                            ThunarWindow           *window);
141 static gboolean  thunar_window_notebook_popup_menu        (GtkWidget              *notebook,
142                                                            ThunarWindow           *window);
143 static gpointer  thunar_window_notebook_create_window     (GtkWidget              *notebook,
144                                                            GtkWidget              *page,
145                                                            gint                    x,
146                                                            gint                    y,
147                                                            ThunarWindow           *window);
148 static GtkWidget*thunar_window_notebook_insert            (ThunarWindow           *window,
149                                                            ThunarFile             *directory,
150                                                            GType                   view_type,
151                                                            gint                    position,
152                                                            ThunarHistory          *history);
153 static void      thunar_window_update_location_bar_visible(ThunarWindow           *window);
154 static void      thunar_window_handle_reload_request      (ThunarWindow           *window);
155 static void      thunar_window_install_sidepane           (ThunarWindow           *window,
156                                                            GType                   type);
157 static void      thunar_window_start_open_location        (ThunarWindow           *window,
158                                                            const gchar            *initial_text);
159 static void      thunar_window_action_open_new_tab        (ThunarWindow           *window,
160                                                            GtkWidget              *menu_item);
161 static void      thunar_window_action_open_new_window     (ThunarWindow           *window,
162                                                            GtkWidget              *menu_item);
163 static void      thunar_window_action_detach_tab          (ThunarWindow           *window,
164                                                            GtkWidget              *menu_item);
165 static void      thunar_window_action_close_all_windows   (ThunarWindow           *window,
166                                                            GtkWidget              *menu_item);
167 static void      thunar_window_action_close_tab           (ThunarWindow           *window,
168                                                            GtkWidget              *menu_item);
169 static void      thunar_window_action_close_window        (ThunarWindow           *window,
170                                                            GtkWidget              *menu_item);
171 static void      thunar_window_action_preferences         (ThunarWindow           *window,
172                                                            GtkWidget              *menu_item);
173 static void      thunar_window_action_reload              (ThunarWindow           *window,
174                                                            GtkWidget              *menu_item);
175 static void      thunar_window_action_switch_next_tab     (ThunarWindow           *window);
176 static void      thunar_window_action_switch_previous_tab (ThunarWindow           *window);
177 static void      thunar_window_action_pathbar_changed     (ThunarWindow           *window);
178 static void      thunar_window_action_toolbar_changed     (ThunarWindow           *window);
179 static void      thunar_window_action_shortcuts_changed   (ThunarWindow           *window);
180 static void      thunar_window_action_tree_changed        (ThunarWindow           *window);
181 static void      thunar_window_action_statusbar_changed   (ThunarWindow           *window);
182 static void      thunar_window_action_menubar_update      (ThunarWindow           *window);
183 static void      thunar_window_action_menubar_changed     (ThunarWindow           *window);
184 static void      thunar_window_action_detailed_view       (ThunarWindow           *window);
185 static void      thunar_window_action_icon_view           (ThunarWindow           *window);
186 static void      thunar_window_action_compact_view        (ThunarWindow           *window);
187 static void      thunar_window_replace_view               (ThunarWindow           *window,
188                                                            GtkWidget              *view,
189                                                            GType                   view_type);
190 static void      thunar_window_action_view_changed        (ThunarWindow           *window,
191                                                            GType                   view_type);
192 static void      thunar_window_action_go_up               (ThunarWindow           *window);
193 static void      thunar_window_action_back                (ThunarWindow           *window);
194 static void      thunar_window_action_forward             (ThunarWindow           *window);
195 static void      thunar_window_action_open_home           (ThunarWindow           *window);
196 static void      thunar_window_action_open_desktop        (ThunarWindow           *window);
197 static void      thunar_window_action_open_computer       (ThunarWindow           *window);
198 static void      thunar_window_action_open_templates      (ThunarWindow           *window);
199 static void      thunar_window_action_open_file_system    (ThunarWindow           *window);
200 static void      thunar_window_action_open_trash          (ThunarWindow           *window);
201 static void      thunar_window_action_open_network        (ThunarWindow           *window);
202 static void      thunar_window_action_open_bookmark       (GFile                  *g_file);
203 static void      thunar_window_action_open_location       (ThunarWindow           *window);
204 static void      thunar_window_action_contents            (ThunarWindow           *window);
205 static void      thunar_window_action_about               (ThunarWindow           *window);
206 static void      thunar_window_action_show_hidden         (ThunarWindow           *window);
207 static gboolean  thunar_window_propagate_key_event        (GtkWindow              *window,
208                                                            GdkEvent               *key_event,
209                                                            gpointer                user_data);
210 static void      thunar_window_action_open_file_menu      (ThunarWindow           *window);
211 static void      thunar_window_current_directory_changed  (ThunarFile             *current_directory,
212                                                            ThunarWindow           *window);
213 static void      thunar_window_menu_item_selected         (ThunarWindow           *window,
214                                                            GtkWidget              *menu_item);
215 static void      thunar_window_menu_item_deselected       (ThunarWindow           *window,
216                                                            GtkWidget              *menu_item);
217 static void      thunar_window_notify_loading             (ThunarView             *view,
218                                                            GParamSpec             *pspec,
219                                                            ThunarWindow           *window);
220 static void      thunar_window_device_pre_unmount         (ThunarDeviceMonitor    *device_monitor,
221                                                            ThunarDevice           *device,
222                                                            GFile                  *root_file,
223                                                            ThunarWindow           *window);
224 static void      thunar_window_device_changed             (ThunarDeviceMonitor    *device_monitor,
225                                                            ThunarDevice           *device,
226                                                            ThunarWindow           *window);
227 static gboolean  thunar_window_save_paned                 (ThunarWindow           *window);
228 static gboolean  thunar_window_save_geometry_timer        (gpointer                user_data);
229 static void      thunar_window_save_geometry_timer_destroy(gpointer                user_data);
230 static void      thunar_window_set_zoom_level             (ThunarWindow           *window,
231                                                            ThunarZoomLevel         zoom_level);
232 static void      thunar_window_update_window_icon         (ThunarWindow           *window);
233 static void      thunar_window_create_menu                (ThunarWindow           *window,
234                                                            ThunarWindowAction      action,
235                                                            GCallback               cb_update_menu);
236 static void      thunar_window_update_file_menu           (ThunarWindow           *window,
237                                                            GtkWidget              *menu);
238 static void      thunar_window_update_edit_menu           (ThunarWindow           *window,
239                                                            GtkWidget              *menu);
240 static void      thunar_window_update_view_menu           (ThunarWindow           *window,
241                                                            GtkWidget              *menu);
242 static void      thunar_window_update_go_menu             (ThunarWindow           *window,
243                                                            GtkWidget              *menu);
244 static void      thunar_window_update_help_menu           (ThunarWindow           *window,
245                                                            GtkWidget              *menu);
246 static void      thunar_window_binding_create             (ThunarWindow           *window,
247                                                            gpointer                src_object,
248                                                            const gchar            *src_prop,
249                                                            gpointer                dst_object,
250                                                            const                   gchar *dst_prop,
251                                                            GBindingFlags           flags);
252 static gboolean  thunar_window_history_clicked            (GtkWidget              *button,
253                                                            GdkEventButton         *event,
254                                                            GtkWidget              *window);
255 static gboolean  thunar_window_button_press_event         (GtkWidget              *view,
256                                                            GdkEventButton         *event,
257                                                            ThunarWindow           *window);
258 static void      thunar_window_history_changed            (ThunarWindow           *window);
259 static void      thunar_window_update_bookmarks           (ThunarWindow           *window);
260 static void      thunar_window_free_bookmarks             (ThunarWindow           *window);
261 static void      thunar_window_menu_add_bookmarks         (ThunarWindow           *window,
262                                                            GtkMenuShell           *view_menu);
263 static gboolean  thunar_window_check_uca_key_activation   (ThunarWindow           *window,
264                                                            GdkEventKey            *key_event,
265                                                            gpointer                user_data);
266 static void      thunar_window_set_directory_specific_settings (ThunarWindow      *window,
267                                                                 gboolean           directory_specific_settings);
268 static void      thunar_window_set_current_directory_gfile     (ThunarWindow      *window,
269                                                                 GFile             *current_directory);
270 static GType     thunar_window_view_type_for_directory         (ThunarWindow      *window,
271                                                                 ThunarFile        *directory);
272 static void      thunar_window_action_clear_directory_specific_settings (ThunarWindow  *window);
273 
274 
275 
276 struct _ThunarWindowClass
277 {
278   GtkWindowClass __parent__;
279 
280   /* internal action signals */
281   gboolean (*reload)          (ThunarWindow *window,
282                                gboolean      reload_info);
283   gboolean (*zoom_in)         (ThunarWindow *window);
284   gboolean (*zoom_out)        (ThunarWindow *window);
285   gboolean (*zoom_reset)      (ThunarWindow *window);
286   gboolean (*tab_change)      (ThunarWindow *window,
287                                gint          idx);
288 };
289 
290 struct _ThunarWindow
291 {
292   GtkWindow __parent__;
293 
294   /* support for custom preferences actions */
295   ThunarxProviderFactory *provider_factory;
296   GList                  *thunarx_preferences_providers;
297 
298   GFile                  *bookmark_file;
299   GList                  *bookmarks;
300   GFileMonitor           *bookmark_monitor;
301 
302   ThunarClipboardManager *clipboard;
303 
304   ThunarPreferences      *preferences;
305 
306   ThunarIconFactory      *icon_factory;
307 
308   /* to be able to change folder on "device-pre-unmount" if required */
309   ThunarDeviceMonitor    *device_monitor;
310 
311   GtkWidget              *grid;
312   GtkWidget              *menubar;
313   GtkWidget              *spinner;
314   GtkWidget              *paned;
315   GtkWidget              *sidepane;
316   GtkWidget              *view_box;
317   GtkWidget              *notebook;
318   GtkWidget              *view;
319   GtkWidget              *statusbar;
320 
321   GType                   view_type;
322   GSList                 *view_bindings;
323 
324   /* support for two different styles of location bars */
325   GtkWidget              *location_bar;
326   GtkWidget              *location_toolbar;
327 
328   /* we need to maintain pointers to be able to toggle sensitivity */
329   GtkWidget              *location_toolbar_item_back;
330   GtkWidget              *location_toolbar_item_forward;
331   GtkWidget              *location_toolbar_item_parent;
332 
333   ThunarLauncher         *launcher;
334 
335   gulong                  signal_handler_id_history_changed;
336 
337   ThunarFile             *current_directory;
338   GtkAccelGroup          *accel_group;
339 
340   /* zoom-level support */
341   ThunarZoomLevel         zoom_level;
342 
343   gboolean                show_hidden;
344 
345   gboolean                directory_specific_settings;
346 
347   /* support to remember window geometry */
348   guint                   save_geometry_timer_id;
349 
350   /* support to toggle side pane using F9,
351    * see the toggle_sidepane() function.
352    */
353   GType                   toggle_sidepane_type;
354 
355   /* Takes care to select a file after e.g. rename/create */
356   GClosure               *select_files_closure;
357 };
358 
359 
360 
361 static XfceGtkActionEntry thunar_window_action_entries[] =
362 {
363     { THUNAR_WINDOW_ACTION_FILE_MENU,                      "<Actions>/ThunarWindow/file-menu",                       "",                     XFCE_GTK_MENU_ITEM,       N_ ("_File"),                  NULL, NULL, NULL,},
364     { THUNAR_WINDOW_ACTION_NEW_TAB,                        "<Actions>/ThunarWindow/new-tab",                         "<Primary>t",           XFCE_GTK_IMAGE_MENU_ITEM, N_ ("New _Tab"),               N_ ("Open a new tab for the displayed location"),                                    "tab-new",                 G_CALLBACK (thunar_window_action_open_new_tab),       },
365     { THUNAR_WINDOW_ACTION_NEW_WINDOW,                     "<Actions>/ThunarWindow/new-window",                      "<Primary>n",           XFCE_GTK_IMAGE_MENU_ITEM, N_ ("New _Window"),            N_ ("Open a new Thunar window for the displayed location"),                          "window-new",              G_CALLBACK (thunar_window_action_open_new_window),    },
366     { THUNAR_WINDOW_ACTION_DETACH_TAB,                     "<Actions>/ThunarWindow/detach-tab",                      "",                     XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Detac_h Tab"),            N_ ("Open current folder in a new window"),                                          NULL,                      G_CALLBACK (thunar_window_action_detach_tab),         },
367     { THUNAR_WINDOW_ACTION_CLOSE_TAB,                      "<Actions>/ThunarWindow/close-tab",                       "<Primary>w",           XFCE_GTK_IMAGE_MENU_ITEM, N_ ("C_lose Tab"),             N_ ("Close this folder"),                                                            "window-close",            G_CALLBACK (thunar_window_action_close_tab),          },
368     { THUNAR_WINDOW_ACTION_CLOSE_WINDOW,                   "<Actions>/ThunarWindow/close-window",                    "<Primary>q",           XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Close Window"),          N_ ("Close this window"),                                                            "application-exit",        G_CALLBACK (thunar_window_action_close_window),       },
369     { THUNAR_WINDOW_ACTION_CLOSE_ALL_WINDOWS,              "<Actions>/ThunarWindow/close-all-windows",               "<Primary><Shift>w",    XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Close _All Windows"),     N_ ("Close all Thunar windows"),                                                     NULL,                      G_CALLBACK (thunar_window_action_close_all_windows),  },
370 
371     { THUNAR_WINDOW_ACTION_EDIT_MENU,                      "<Actions>/ThunarWindow/edit-menu",                       "",                     XFCE_GTK_MENU_ITEM,       N_ ("_Edit"),                  NULL,                                                                                NULL,                      NULL,                                                 },
372     { THUNAR_WINDOW_ACTION_PREFERENCES,                    "<Actions>/ThunarWindow/preferences",                     "",                     XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Pr_eferences..."),        N_ ("Edit Thunars Preferences"),                                                     "preferences-system",      G_CALLBACK (thunar_window_action_preferences),        },
373 
374     { THUNAR_WINDOW_ACTION_VIEW_MENU,                      "<Actions>/ThunarWindow/view-menu",                       "",                     XFCE_GTK_MENU_ITEM,       N_ ("_View"),                  NULL,                                                                                NULL,                      NULL,                                                 },
375     { THUNAR_WINDOW_ACTION_RELOAD,                         "<Actions>/ThunarWindow/reload",                          "<Primary>r",           XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Reload"),                N_ ("Reload the current folder"),                                                    "view-refresh-symbolic",   G_CALLBACK (thunar_window_action_reload),             },
376     { THUNAR_WINDOW_ACTION_RELOAD_ALT,                     "<Actions>/ThunarWindow/reload-alt",                      "F5",                   XFCE_GTK_IMAGE_MENU_ITEM, NULL,                          NULL,                                                                                NULL,                      G_CALLBACK (thunar_window_action_reload),             },
377     { THUNAR_WINDOW_ACTION_VIEW_LOCATION_SELECTOR_MENU,    "<Actions>/ThunarWindow/view-location-selector-menu",     "",                     XFCE_GTK_MENU_ITEM,       N_ ("_Location Selector"),     NULL,                                                                                NULL,                      NULL,                                                 },
378     { THUNAR_WINDOW_ACTION_VIEW_LOCATION_SELECTOR_PATHBAR, "<Actions>/ThunarWindow/view-location-selector-pathbar",  "",                     XFCE_GTK_CHECK_MENU_ITEM, N_ ("_Pathbar Style"),         N_ ("Modern approach with buttons that correspond to folders"),                      NULL,                      G_CALLBACK (thunar_window_action_pathbar_changed),    },
379     { THUNAR_WINDOW_ACTION_VIEW_LOCATION_SELECTOR_TOOLBAR, "<Actions>/ThunarWindow/view-location-selector-toolbar",  "",                     XFCE_GTK_CHECK_MENU_ITEM, N_ ("_Toolbar Style"),         N_ ("Traditional approach with location bar and navigation buttons"),                NULL,                      G_CALLBACK (thunar_window_action_toolbar_changed),    },
380     { THUNAR_WINDOW_ACTION_VIEW_SIDE_PANE_MENU,            "<Actions>/ThunarWindow/view-side-pane-menu",             "",                     XFCE_GTK_MENU_ITEM,       N_ ("_Side Pane"),             NULL,                                                                                NULL,                      NULL,                                                 },
381     { THUNAR_WINDOW_ACTION_VIEW_SIDE_PANE_SHORTCUTS,       "<Actions>/ThunarWindow/view-side-pane-shortcuts",        "<Primary>b",           XFCE_GTK_CHECK_MENU_ITEM, N_ ("_Shortcuts"),             N_ ("Toggles the visibility of the shortcuts pane"),                                 NULL,                      G_CALLBACK (thunar_window_action_shortcuts_changed),  },
382     { THUNAR_WINDOW_ACTION_VIEW_SIDE_PANE_TREE,            "<Actions>/ThunarWindow/view-side-pane-tree",             "<Primary>e",           XFCE_GTK_CHECK_MENU_ITEM, N_ ("_Tree"),                  N_ ("Toggles the visibility of the tree pane"),                                      NULL,                      G_CALLBACK (thunar_window_action_tree_changed),       },
383     { THUNAR_WINDOW_ACTION_TOGGLE_SIDE_PANE,               "<Actions>/ThunarWindow/toggle-side-pane",                "F9",                   XFCE_GTK_MENU_ITEM,       NULL,                          NULL,                                                                                NULL,                      G_CALLBACK (thunar_window_toggle_sidepane),           },
384     { THUNAR_WINDOW_ACTION_VIEW_STATUSBAR,                 "<Actions>/ThunarWindow/view-statusbar",                  "",                     XFCE_GTK_CHECK_MENU_ITEM, N_ ("St_atusbar"),             N_ ("Change the visibility of this window's statusbar"),                             NULL,                      G_CALLBACK (thunar_window_action_statusbar_changed),  },
385     { THUNAR_WINDOW_ACTION_VIEW_MENUBAR,                   "<Actions>/ThunarWindow/view-menubar",                    "<Primary>m",           XFCE_GTK_CHECK_MENU_ITEM, N_ ("_Menubar"),               N_ ("Change the visibility of this window's menubar"),                               NULL,                      G_CALLBACK (thunar_window_action_menubar_changed),    },
386     { THUNAR_WINDOW_ACTION_SHOW_HIDDEN,                    "<Actions>/ThunarWindow/show-hidden",                     "<Primary>h",           XFCE_GTK_CHECK_MENU_ITEM, N_ ("Show _Hidden Files"),     N_ ("Toggles the display of hidden files in the current window"),                    NULL,                      G_CALLBACK (thunar_window_action_show_hidden),        },
387     { THUNAR_WINDOW_ACTION_ZOOM_IN,                        "<Actions>/ThunarWindow/zoom-in",                         "<Primary>KP_Add",      XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Zoom I_n"),               N_ ("Show the contents in more detail"),                                             "zoom-in-symbolic",        G_CALLBACK (thunar_window_zoom_in),                   },
388     { THUNAR_WINDOW_ACTION_ZOOM_IN_ALT_1,                  "<Actions>/ThunarWindow/zoom-in-alt1",                    "<Primary>plus",        XFCE_GTK_IMAGE_MENU_ITEM, NULL,                          NULL,                                                                                NULL,                      G_CALLBACK (thunar_window_zoom_in),                   },
389     { THUNAR_WINDOW_ACTION_ZOOM_IN_ALT_2,                  "<Actions>/ThunarWindow/zoom-in-alt2",                    "<Primary>equal",       XFCE_GTK_IMAGE_MENU_ITEM, NULL,                          NULL,                                                                                NULL,                      G_CALLBACK (thunar_window_zoom_in),                   },
390     { THUNAR_WINDOW_ACTION_ZOOM_OUT,                       "<Actions>/ThunarWindow/zoom-out",                        "<Primary>KP_Subtract", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Zoom _Out"),              N_ ("Show the contents in less detail"),                                             "zoom-out-symbolic",       G_CALLBACK (thunar_window_zoom_out),                  },
391     { THUNAR_WINDOW_ACTION_ZOOM_OUT_ALT,                   "<Actions>/ThunarWindow/zoom-out-alt",                    "<Primary>minus",       XFCE_GTK_IMAGE_MENU_ITEM, NULL,                          NULL,                                                                                NULL,                      G_CALLBACK (thunar_window_zoom_out),                  },
392     { THUNAR_WINDOW_ACTION_ZOOM_RESET,                     "<Actions>/ThunarWindow/zoom-reset",                      "<Primary>KP_0",        XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Normal Si_ze"),           N_ ("Show the contents at the normal size"),                                         "zoom-original-symbolic",  G_CALLBACK (thunar_window_zoom_reset),                },
393     { THUNAR_WINDOW_ACTION_ZOOM_RESET_ALT,                 "<Actions>/ThunarWindow/zoom-reset-alt",                  "<Primary>0",           XFCE_GTK_IMAGE_MENU_ITEM, NULL,                          NULL,                                                                                NULL,                      G_CALLBACK (thunar_window_zoom_reset),                },
394     { THUNAR_WINDOW_ACTION_CLEAR_DIRECTORY_SPECIFIC_SETTINGS,"<Actions>/ThunarWindow/clear-directory-specific-settings","",                  XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Clear Saved _Folder View Settings"), N_ ("Delete saved view settings for this folder"),                         NULL,                     G_CALLBACK (thunar_window_action_clear_directory_specific_settings), },
395     { THUNAR_WINDOW_ACTION_VIEW_AS_ICONS,                  "<Actions>/ThunarWindow/view-as-icons",                   "<Primary>1",           XFCE_GTK_RADIO_MENU_ITEM, N_ ("_Icon View"),             N_ ("Display folder content in an icon view"),                                        NULL,                      G_CALLBACK (thunar_window_action_icon_view),          },
396     { THUNAR_WINDOW_ACTION_VIEW_AS_DETAILED_LIST,          "<Actions>/ThunarWindow/view-as-detailed-list",           "<Primary>2",           XFCE_GTK_RADIO_MENU_ITEM, N_ ("_List View"),             N_ ("Display folder content in a detailed list view"),                                NULL,                      G_CALLBACK (thunar_window_action_detailed_view),      },
397     { THUNAR_WINDOW_ACTION_VIEW_AS_COMPACT_LIST,           "<Actions>/ThunarWindow/view-as-compact-list",            "<Primary>3",           XFCE_GTK_RADIO_MENU_ITEM, N_ ("_Compact View"),          N_ ("Display folder content in a compact list view"),                                 NULL,                      G_CALLBACK (thunar_window_action_compact_view),       },
398 
399     { THUNAR_WINDOW_ACTION_GO_MENU,                        "<Actions>/ThunarWindow/go-menu",                         "",                     XFCE_GTK_MENU_ITEM,       N_ ("_Go"),                    NULL,                                                                                NULL,                      NULL                                                  },
400     { THUNAR_WINDOW_ACTION_OPEN_FILE_SYSTEM,               "<Actions>/ThunarWindow/open-file-system",                "",                     XFCE_GTK_IMAGE_MENU_ITEM, N_ ("File System"),            N_ ("Browse the file system"),                                                       "drive-harddisk",          G_CALLBACK (thunar_window_action_open_file_system),   },
401     { THUNAR_WINDOW_ACTION_OPEN_COMPUTER,                  "<Actions>/ThunarWindow/open-computer",                    "",                    XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Computer"),               N_ ("Go to the computer folder"),                                                    "computer",                G_CALLBACK (thunar_window_action_open_computer),      },
402     { THUNAR_WINDOW_ACTION_OPEN_HOME,                      "<Actions>/ThunarWindow/open-home",                       "<Alt>Home",            XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Home"),                  N_ ("Go to the home folder"),                                                        "go-home-symbolic",        G_CALLBACK (thunar_window_action_open_home),          },
403     { THUNAR_WINDOW_ACTION_OPEN_DESKTOP,                   "<Actions>/ThunarWindow/open-desktop",                    "",                     XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Desktop"),                N_ ("Go to the desktop folder"),                                                     "user-desktop",            G_CALLBACK (thunar_window_action_open_desktop),       },
404     { THUNAR_WINDOW_ACTION_OPEN_COMPUTER,                  "<Actions>/ThunarWindow/open-computer",                   "",                     XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Computer"),               N_ ("Browse all local and remote disks and folders accessible from this computer"),  "computer",                G_CALLBACK (thunar_window_action_open_computer),      },
405     { THUNAR_WINDOW_ACTION_OPEN_TRASH,                     "<Actions>/ThunarWindow/open-trash",                      "",                     XFCE_GTK_IMAGE_MENU_ITEM, N_ ("T_rash"),                 N_ ("Display the contents of the trash can"),                                        NULL,                      G_CALLBACK (thunar_window_action_open_trash),         },
406     { THUNAR_WINDOW_ACTION_OPEN_PARENT,                    "<Actions>/ThunarWindow/open-parent",                     "<Alt>Up",              XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Open _Parent"),           N_ ("Open the parent folder"),                                                       "go-up-symbolic",          G_CALLBACK (thunar_window_action_go_up),              },
407     { THUNAR_WINDOW_ACTION_OPEN_LOCATION,                  "<Actions>/ThunarWindow/open-location",                   "<Primary>l",           XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Open Location..."),      N_ ("Specify a location to open"),                                                   NULL,                      G_CALLBACK (thunar_window_action_open_location),      },
408     { THUNAR_WINDOW_ACTION_OPEN_LOCATION_ALT,              "<Actions>/ThunarWindow/open-location-alt",               "<Alt>d",               XFCE_GTK_MENU_ITEM,       "open-location-alt",           NULL,                                                                                NULL,                      G_CALLBACK (thunar_window_action_open_location),      },
409     { THUNAR_WINDOW_ACTION_OPEN_TEMPLATES,                 "<Actions>/ThunarWindow/open-templates",                  "",                     XFCE_GTK_IMAGE_MENU_ITEM, N_("T_emplates"),              N_ ("Go to the templates folder"),                                                   "text-x-generic-template", G_CALLBACK (thunar_window_action_open_templates),     },
410     { THUNAR_WINDOW_ACTION_OPEN_NETWORK,                   "<Actions>/ThunarWindow/open-network",                    "",                     XFCE_GTK_IMAGE_MENU_ITEM, N_("B_rowse Network"),         N_ ("Browse local network connections"),                                             "network-workgroup",       G_CALLBACK (thunar_window_action_open_network),       },
411 
412     { THUNAR_WINDOW_ACTION_HELP_MENU,                      "<Actions>/ThunarWindow/contents/help-menu",              "",                     XFCE_GTK_MENU_ITEM      , N_ ("_Help"),                  NULL, NULL, NULL},
413     { THUNAR_WINDOW_ACTION_CONTENTS,                       "<Actions>/ThunarWindow/contents",                        "F1",                   XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Contents"),              N_ ("Display Thunar user manual"),                                                   "help-browser",            G_CALLBACK (thunar_window_action_contents),            },
414     { THUNAR_WINDOW_ACTION_ABOUT,                          "<Actions>/ThunarWindow/about",                           "",                     XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_About"),                 N_ ("Display information about Thunar"),                                             "help-about",              G_CALLBACK (thunar_window_action_about),               },
415     { THUNAR_WINDOW_ACTION_BACK,                           "<Actions>/ThunarStandardView/back",                      "<Alt>Left",            XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Back"),                   N_ ("Go to the previous visited folder"),                                            "go-previous-symbolic",    G_CALLBACK (thunar_window_action_back),                },
416     { THUNAR_WINDOW_ACTION_BACK_ALT,                       "<Actions>/ThunarStandardView/back-alt",                  "BackSpace",            XFCE_GTK_IMAGE_MENU_ITEM, NULL,                          NULL,                                                                                NULL,                      G_CALLBACK (thunar_window_action_back),                },
417     { THUNAR_WINDOW_ACTION_FORWARD,                        "<Actions>/ThunarStandardView/forward",                   "<Alt>Right",           XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Forward"),                N_ ("Go to the next visited folder"),                                                "go-next-symbolic",        G_CALLBACK (thunar_window_action_forward),             },
418     { THUNAR_WINDOW_ACTION_SWITCH_PREV_TAB,                "<Actions>/ThunarWindow/switch-previous-tab",             "<Primary>Page_Up",     XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Previous Tab"),          N_ ("Switch to Previous Tab"),                                                       "go-previous",             G_CALLBACK (thunar_window_action_switch_previous_tab), },
419     { THUNAR_WINDOW_ACTION_SWITCH_NEXT_TAB,                "<Actions>/ThunarWindow/switch-next-tab",                 "<Primary>Page_Down",   XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Next Tab"),              N_ ("Switch to Next Tab"),                                                           "go-next",                 G_CALLBACK (thunar_window_action_switch_next_tab),     },
420     { 0,                                                   "<Actions>/ThunarWindow/open-file-menu",                  "F10",                  0,                        NULL,                          NULL,                                                                                NULL,                      G_CALLBACK (thunar_window_action_open_file_menu),      },
421 };
422 
423 #define get_action_entry(id) xfce_gtk_get_action_entry_by_id(thunar_window_action_entries,G_N_ELEMENTS(thunar_window_action_entries),id)
424 
425 
426 
427 static guint window_signals[LAST_SIGNAL];
428 
429 
430 
G_DEFINE_TYPE_WITH_CODE(ThunarWindow,thunar_window,GTK_TYPE_WINDOW,G_IMPLEMENT_INTERFACE (THUNAR_TYPE_BROWSER,NULL))431 G_DEFINE_TYPE_WITH_CODE (ThunarWindow, thunar_window, GTK_TYPE_WINDOW,
432                          G_IMPLEMENT_INTERFACE (THUNAR_TYPE_BROWSER, NULL))
433 
434 
435 
436 static void
437 thunar_window_class_init (ThunarWindowClass *klass)
438 {
439   GtkWidgetClass *gtkwidget_class;
440   GtkBindingSet  *binding_set;
441   GObjectClass   *gobject_class;
442   guint           i;
443 
444   gobject_class = G_OBJECT_CLASS (klass);
445   gobject_class->dispose = thunar_window_dispose;
446   gobject_class->finalize = thunar_window_finalize;
447   gobject_class->get_property = thunar_window_get_property;
448   gobject_class->set_property = thunar_window_set_property;
449 
450   gtkwidget_class = GTK_WIDGET_CLASS (klass);
451   gtkwidget_class->realize = thunar_window_realize;
452   gtkwidget_class->unrealize = thunar_window_unrealize;
453   gtkwidget_class->configure_event = thunar_window_configure_event;
454 
455   klass->reload = thunar_window_reload;
456   klass->zoom_in = thunar_window_zoom_in;
457   klass->zoom_out = thunar_window_zoom_out;
458   klass->zoom_reset = thunar_window_zoom_reset;
459   klass->tab_change = thunar_window_tab_change;
460 
461   xfce_gtk_translate_action_entries (thunar_window_action_entries, G_N_ELEMENTS (thunar_window_action_entries));
462 
463   /**
464    * ThunarWindow:current-directory:
465    *
466    * The directory currently displayed within this #ThunarWindow
467    * or %NULL.
468    **/
469   g_object_class_install_property (gobject_class,
470                                    PROP_CURRENT_DIRECTORY,
471                                    g_param_spec_object ("current-directory",
472                                                         "current-directory",
473                                                         "current-directory",
474                                                         THUNAR_TYPE_FILE,
475                                                         EXO_PARAM_READWRITE));
476 
477   /**
478    * ThunarWindow:zoom-level:
479    *
480    * The #ThunarZoomLevel applied to the #ThunarView currently
481    * shown within this window.
482    **/
483   g_object_class_install_property (gobject_class,
484                                    PROP_ZOOM_LEVEL,
485                                    g_param_spec_enum ("zoom-level",
486                                                       "zoom-level",
487                                                       "zoom-level",
488                                                       THUNAR_TYPE_ZOOM_LEVEL,
489                                                       THUNAR_ZOOM_LEVEL_100_PERCENT,
490                                                       EXO_PARAM_READWRITE));
491 
492   /**
493    * ThunarWindow:directory-specific-settings:
494    *
495    * Whether to use directory specific settings.
496    **/
497   g_object_class_install_property (gobject_class,
498                                    PROP_DIRECTORY_SPECIFIC_SETTINGS,
499                                    g_param_spec_boolean ("directory-specific-settings",
500                                                          "directory-specific-settings",
501                                                          "directory-specific-settings",
502                                                          FALSE,
503                                                          EXO_PARAM_READWRITE));
504 
505   /**
506    * ThunarWindow::reload:
507    * @window : a #ThunarWindow instance.
508    *
509    * Emitted whenever the user requests to reload the contents
510    * of the currently displayed folder.
511    **/
512   window_signals[RELOAD] =
513     g_signal_new (I_("reload"),
514                   G_TYPE_FROM_CLASS (klass),
515                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
516                   G_STRUCT_OFFSET (ThunarWindowClass, reload),
517                   g_signal_accumulator_true_handled, NULL,
518                   _thunar_marshal_BOOLEAN__BOOLEAN,
519                   G_TYPE_BOOLEAN, 1,
520                   G_TYPE_BOOLEAN);
521 
522   /**
523    * ThunarWindow::zoom-in:
524    * @window : a #ThunarWindow instance.
525    *
526    * Emitted whenever the user requests to zoom in. This
527    * is an internal signal used to bind the action to keys.
528    **/
529   window_signals[ZOOM_IN] =
530     g_signal_new (I_("zoom-in"),
531                   G_TYPE_FROM_CLASS (klass),
532                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
533                   G_STRUCT_OFFSET (ThunarWindowClass, zoom_in),
534                   g_signal_accumulator_true_handled, NULL,
535                   _thunar_marshal_BOOLEAN__VOID,
536                   G_TYPE_BOOLEAN, 0);
537 
538   /**
539    * ThunarWindow::zoom-out:
540    * @window : a #ThunarWindow instance.
541    *
542    * Emitted whenever the user requests to zoom out. This
543    * is an internal signal used to bind the action to keys.
544    **/
545   window_signals[ZOOM_OUT] =
546     g_signal_new (I_("zoom-out"),
547                   G_TYPE_FROM_CLASS (klass),
548                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
549                   G_STRUCT_OFFSET (ThunarWindowClass, zoom_out),
550                   g_signal_accumulator_true_handled, NULL,
551                   _thunar_marshal_BOOLEAN__VOID,
552                   G_TYPE_BOOLEAN, 0);
553 
554   /**
555    * ThunarWindow::zoom-reset:
556    * @window : a #ThunarWindow instance.
557    *
558    * Emitted whenever the user requests reset the zoom level.
559    * This is an internal signal used to bind the action to keys.
560    **/
561   window_signals[ZOOM_RESET] =
562     g_signal_new (I_("zoom-reset"),
563                   G_TYPE_FROM_CLASS (klass),
564                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
565                   G_STRUCT_OFFSET (ThunarWindowClass, zoom_reset),
566                   g_signal_accumulator_true_handled, NULL,
567                   _thunar_marshal_BOOLEAN__VOID,
568                   G_TYPE_BOOLEAN, 0);
569 
570   /**
571    * ThunarWindow::tab-change:
572    * @window : a #ThunarWindow instance.
573    * @idx    : tab index,
574    *
575    * Emitted whenever the user uses a Alt+N combination to
576    * switch tabs.
577    **/
578   window_signals[TAB_CHANGE] =
579     g_signal_new (I_("tab-change"),
580                   G_TYPE_FROM_CLASS (klass),
581                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
582                   G_STRUCT_OFFSET (ThunarWindowClass, tab_change),
583                   g_signal_accumulator_true_handled, NULL,
584                   _thunar_marshal_BOOLEAN__INT,
585                   G_TYPE_BOOLEAN, 1,
586                   G_TYPE_INT);
587 
588   /* setup the key bindings for the windows */
589   binding_set = gtk_binding_set_by_class (klass);
590 
591   /* setup the key bindings for Alt+N */
592   for (i = 0; i < 10; i++)
593     {
594       gtk_binding_entry_add_signal (binding_set, GDK_KEY_0 + i, GDK_MOD1_MASK,
595                                     "tab-change", 1, G_TYPE_UINT, i - 1);
596     }
597 }
598 
599 
600 
601 static void
thunar_window_init(ThunarWindow * window)602 thunar_window_init (ThunarWindow *window)
603 {
604   GtkWidget       *label;
605   GtkWidget       *infobar;
606   GtkWidget       *item;
607   gboolean         last_menubar_visible;
608   gchar           *last_location_bar;
609   gchar           *last_side_pane;
610   GType            type;
611   gint             last_separator_position;
612   gint             last_window_width;
613   gint             last_window_height;
614   gboolean         last_window_maximized;
615   gboolean         last_statusbar_visible;
616   GtkToolItem     *tool_item;
617   gboolean         small_icons;
618   GtkStyleContext *context;
619 
620   /* unset the view type */
621   window->view_type = G_TYPE_NONE;
622 
623   /* grab a reference on the provider factory and load the providers*/
624   window->provider_factory = thunarx_provider_factory_get_default ();
625   window->thunarx_preferences_providers = thunarx_provider_factory_list_providers (window->provider_factory, THUNARX_TYPE_PREFERENCES_PROVIDER);
626 
627   /* grab a reference on the preferences */
628   window->preferences = thunar_preferences_get ();
629 
630   window->accel_group = gtk_accel_group_new ();
631   xfce_gtk_accel_map_add_entries (thunar_window_action_entries, G_N_ELEMENTS (thunar_window_action_entries));
632   xfce_gtk_accel_group_connect_action_entries (window->accel_group,
633                                                thunar_window_action_entries,
634                                                G_N_ELEMENTS (thunar_window_action_entries),
635                                                window);
636 
637   gtk_window_add_accel_group (GTK_WINDOW (window), window->accel_group);
638 
639   /* get all properties for init */
640   g_object_get (G_OBJECT (window->preferences),
641                 "last-show-hidden", &window->show_hidden,
642                 "last-window-width", &last_window_width,
643                 "last-window-height", &last_window_height,
644                 "last-window-maximized", &last_window_maximized,
645                 "last-menubar-visible", &last_menubar_visible,
646                 "last-separator-position", &last_separator_position,
647                 "last-location-bar", &last_location_bar,
648                 "last-side-pane", &last_side_pane,
649                 "last-statusbar-visible", &last_statusbar_visible,
650                 "misc-small-toolbar-icons", &small_icons,
651                 NULL);
652 
653   /* update the visual on screen_changed events */
654   g_signal_connect (window, "screen-changed", G_CALLBACK (thunar_window_screen_changed), NULL);
655 
656   /* invoke the thunar_window_screen_changed function to initially set the best possible visual.*/
657   thunar_window_screen_changed (GTK_WIDGET (window), NULL, NULL);
658 
659   /* set up a handler to confirm exit when there are multiple tabs open  */
660   g_signal_connect (window, "delete-event", G_CALLBACK (thunar_window_delete), NULL);
661 
662   /* connect to the volume monitor */
663   window->device_monitor = thunar_device_monitor_get ();
664   g_signal_connect (window->device_monitor, "device-pre-unmount", G_CALLBACK (thunar_window_device_pre_unmount), window);
665   g_signal_connect (window->device_monitor, "device-removed", G_CALLBACK (thunar_window_device_changed), window);
666   g_signal_connect (window->device_monitor, "device-changed", G_CALLBACK (thunar_window_device_changed), window);
667 
668   window->icon_factory = thunar_icon_factory_get_default ();
669 
670   /* Catch key events before accelerators get processed */
671   g_signal_connect (window, "key-press-event", G_CALLBACK (thunar_window_propagate_key_event), NULL);
672   g_signal_connect (window, "key-release-event", G_CALLBACK (thunar_window_propagate_key_event), NULL);
673 
674 
675   window->select_files_closure = g_cclosure_new_swap (G_CALLBACK (thunar_window_select_files), window, NULL);
676   g_closure_ref (window->select_files_closure);
677   g_closure_sink (window->select_files_closure);
678   window->launcher = g_object_new (THUNAR_TYPE_LAUNCHER, "widget", GTK_WIDGET (window),
679                                   "select-files-closure",  window->select_files_closure, NULL);
680 
681   exo_binding_new (G_OBJECT (window), "current-directory", G_OBJECT (window->launcher), "current-directory");
682   g_signal_connect_swapped (G_OBJECT (window->launcher), "change-directory", G_CALLBACK (thunar_window_set_current_directory), window);
683   g_signal_connect_swapped (G_OBJECT (window->launcher), "open-new-tab", G_CALLBACK (thunar_window_notebook_open_new_tab), window);
684   thunar_launcher_append_accelerators (window->launcher, window->accel_group);
685 
686   /* determine the default window size from the preferences */
687   gtk_window_set_default_size (GTK_WINDOW (window), last_window_width, last_window_height);
688 
689   /* restore the maxized state of the window */
690   if (G_UNLIKELY (last_window_maximized))
691     gtk_window_maximize (GTK_WINDOW (window));
692 
693   /* add thunar style class for easier theming */
694   context = gtk_widget_get_style_context (GTK_WIDGET (window));
695   gtk_style_context_add_class (context, "thunar");
696 
697   window->grid = gtk_grid_new ();
698   gtk_container_add (GTK_CONTAINER (window), window->grid);
699   gtk_widget_show (window->grid);
700 
701   /* build the menubar */
702   window->menubar = gtk_menu_bar_new ();
703   thunar_window_create_menu (window, THUNAR_WINDOW_ACTION_FILE_MENU, G_CALLBACK (thunar_window_update_file_menu));
704   thunar_window_create_menu (window, THUNAR_WINDOW_ACTION_EDIT_MENU, G_CALLBACK (thunar_window_update_edit_menu));
705   thunar_window_create_menu (window, THUNAR_WINDOW_ACTION_VIEW_MENU, G_CALLBACK (thunar_window_update_view_menu));
706   thunar_window_create_menu (window, THUNAR_WINDOW_ACTION_GO_MENU, G_CALLBACK (thunar_window_update_go_menu));
707   thunar_window_create_menu (window, THUNAR_WINDOW_ACTION_HELP_MENU, G_CALLBACK (thunar_window_update_help_menu));
708   gtk_widget_show_all (window->menubar);
709 
710   if (last_menubar_visible == FALSE)
711     gtk_widget_hide (window->menubar);
712   gtk_widget_set_hexpand (window->menubar, TRUE);
713   gtk_grid_attach (GTK_GRID (window->grid), window->menubar, 0, 0, 1, 1);
714 
715   /* append the menu item for the spinner */
716   item = gtk_menu_item_new ();
717   gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE);
718   g_object_set (G_OBJECT (item), "right-justified", TRUE, NULL);
719   gtk_menu_shell_append (GTK_MENU_SHELL (window->menubar), item);
720   gtk_widget_show (item);
721 
722   /* Required if F10 is pushed while the menu is hidden */
723   g_signal_connect_swapped (G_OBJECT (window->menubar), "deactivate", G_CALLBACK (thunar_window_action_menubar_update), window);
724 
725   /* place the spinner into the menu item */
726   window->spinner = gtk_spinner_new ();
727   gtk_container_add (GTK_CONTAINER (item), window->spinner);
728   exo_binding_new (G_OBJECT (window->spinner), "active",
729                    G_OBJECT (window->spinner), "visible");
730 
731   /* check if we need to add the root warning */
732   if (G_UNLIKELY (geteuid () == 0))
733     {
734       /* add the bar for the root warning */
735       infobar = gtk_info_bar_new ();
736       gtk_info_bar_set_message_type (GTK_INFO_BAR (infobar), GTK_MESSAGE_WARNING);
737       gtk_widget_set_hexpand (infobar, TRUE);
738       gtk_grid_attach (GTK_GRID (window->grid), infobar, 0, 2, 1, 1);
739       gtk_widget_show (infobar);
740 
741       /* add the label with the root warning */
742       label = gtk_label_new (_("Warning: you are using the root account. You may harm your system."));
743       gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (infobar))), label);
744       gtk_widget_show (label);
745     }
746 
747   window->paned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
748   gtk_container_set_border_width (GTK_CONTAINER (window->paned), 0);
749   gtk_widget_set_hexpand (window->paned, TRUE);
750   gtk_widget_set_vexpand (window->paned, TRUE);
751   gtk_grid_attach (GTK_GRID (window->grid), window->paned, 0, 4, 1, 1);
752   gtk_widget_show (window->paned);
753 
754   /* determine the last separator position and apply it to the paned view */
755   gtk_paned_set_position (GTK_PANED (window->paned), last_separator_position);
756   g_signal_connect_swapped (window->paned, "accept-position", G_CALLBACK (thunar_window_save_paned), window);
757   g_signal_connect_swapped (window->paned, "button-release-event", G_CALLBACK (thunar_window_save_paned), window);
758 
759   window->view_box = gtk_grid_new ();
760   gtk_paned_pack2 (GTK_PANED (window->paned), window->view_box, TRUE, FALSE);
761   gtk_widget_show (window->view_box);
762 
763   /* tabs */
764   window->notebook = gtk_notebook_new ();
765   gtk_widget_set_hexpand (window->notebook, TRUE);
766   gtk_widget_set_vexpand (window->notebook, TRUE);
767   gtk_grid_attach (GTK_GRID (window->view_box), window->notebook, 0, 1, 1, 1);
768   g_signal_connect (G_OBJECT (window->notebook), "switch-page", G_CALLBACK (thunar_window_notebook_switch_page), window);
769   g_signal_connect (G_OBJECT (window->notebook), "page-added", G_CALLBACK (thunar_window_notebook_page_added), window);
770   g_signal_connect (G_OBJECT (window->notebook), "page-removed", G_CALLBACK (thunar_window_notebook_page_removed), window);
771   g_signal_connect_after (G_OBJECT (window->notebook), "button-press-event", G_CALLBACK (thunar_window_notebook_button_press_event), window);
772   g_signal_connect (G_OBJECT (window->notebook), "popup-menu", G_CALLBACK (thunar_window_notebook_popup_menu), window);
773   g_signal_connect (G_OBJECT (window->notebook), "create-window", G_CALLBACK (thunar_window_notebook_create_window), window);
774   gtk_notebook_set_show_border (GTK_NOTEBOOK (window->notebook), FALSE);
775   gtk_notebook_set_scrollable (GTK_NOTEBOOK (window->notebook), TRUE);
776   gtk_container_set_border_width (GTK_CONTAINER (window->notebook), 0);
777   gtk_notebook_set_group_name (GTK_NOTEBOOK (window->notebook), "thunar-tabs");
778   gtk_widget_show (window->notebook);
779 
780   /* allocate the new location bar widget */
781   window->location_bar = thunar_location_bar_new ();
782   g_object_bind_property (G_OBJECT (window), "current-directory", G_OBJECT (window->location_bar), "current-directory", G_BINDING_SYNC_CREATE);
783   g_signal_connect_swapped (G_OBJECT (window->location_bar), "change-directory", G_CALLBACK (thunar_window_set_current_directory), window);
784   g_signal_connect_swapped (G_OBJECT (window->location_bar), "open-new-tab", G_CALLBACK (thunar_window_notebook_open_new_tab), window);
785   g_signal_connect_swapped (G_OBJECT (window->location_bar), "reload-requested", G_CALLBACK (thunar_window_handle_reload_request), window);
786   g_signal_connect_swapped (G_OBJECT (window->location_bar), "entry-done", G_CALLBACK (thunar_window_update_location_bar_visible), window);
787 
788   /* setup the toolbar for the location bar */
789   window->location_toolbar = gtk_toolbar_new ();
790   gtk_toolbar_set_style (GTK_TOOLBAR (window->location_toolbar), GTK_TOOLBAR_ICONS);
791   gtk_toolbar_set_icon_size (GTK_TOOLBAR (window->location_toolbar),
792                               small_icons ? GTK_ICON_SIZE_SMALL_TOOLBAR : GTK_ICON_SIZE_LARGE_TOOLBAR);
793   gtk_widget_set_hexpand (window->location_toolbar, TRUE);
794   gtk_grid_attach (GTK_GRID (window->grid), window->location_toolbar, 0, 1, 1, 1);
795 
796   window->location_toolbar_item_back = xfce_gtk_tool_button_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_BACK), G_OBJECT (window), GTK_TOOLBAR (window->location_toolbar));
797   window->location_toolbar_item_forward = xfce_gtk_tool_button_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_FORWARD), G_OBJECT (window), GTK_TOOLBAR (window->location_toolbar));
798   window->location_toolbar_item_parent = xfce_gtk_tool_button_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_PARENT), G_OBJECT (window), GTK_TOOLBAR (window->location_toolbar));
799   xfce_gtk_tool_button_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_HOME), G_OBJECT (window), GTK_TOOLBAR (window->location_toolbar));
800 
801   g_signal_connect (G_OBJECT (window->location_toolbar_item_back), "button-press-event", G_CALLBACK (thunar_window_history_clicked), G_OBJECT (window));
802   g_signal_connect (G_OBJECT (window->location_toolbar_item_forward), "button-press-event", G_CALLBACK (thunar_window_history_clicked), G_OBJECT (window));
803   g_signal_connect (G_OBJECT (window), "button-press-event", G_CALLBACK (thunar_window_button_press_event), G_OBJECT (window));
804   window->signal_handler_id_history_changed = 0;
805 
806   /* The UCA shortcuts need to be checked 'by hand', since we dont want to permanently keep menu items for them */
807   g_signal_connect (window, "key-press-event", G_CALLBACK (thunar_window_check_uca_key_activation), NULL);
808 
809   /* add the location bar to the toolbar */
810   tool_item = gtk_tool_item_new ();
811   gtk_tool_item_set_expand (tool_item, TRUE);
812   gtk_toolbar_insert (GTK_TOOLBAR (window->location_toolbar), tool_item, -1);
813   gtk_toolbar_set_show_arrow (GTK_TOOLBAR (window->location_toolbar), FALSE);
814 
815   /* add the location bar itself */
816   gtk_container_add (GTK_CONTAINER (tool_item), window->location_bar);
817 
818   /* display the toolbar */
819   gtk_widget_show_all (window->location_toolbar);
820 
821   g_free (last_location_bar);
822 
823   /* setup setting the location bar visibility on-demand */
824   g_signal_connect_object (G_OBJECT (window->preferences), "notify::last-location-bar", G_CALLBACK (thunar_window_update_location_bar_visible), window, G_CONNECT_SWAPPED);
825   thunar_window_update_location_bar_visible (window);
826 
827   /* update window icon whenever preferences change */
828   g_signal_connect_object (G_OBJECT (window->preferences), "notify::misc-change-window-icon", G_CALLBACK (thunar_window_update_window_icon), window, G_CONNECT_SWAPPED);
829 
830   /* determine the selected side pane */
831   if (exo_str_is_equal (last_side_pane, g_type_name (THUNAR_TYPE_SHORTCUTS_PANE)))
832     type = THUNAR_TYPE_SHORTCUTS_PANE;
833   else if (exo_str_is_equal (last_side_pane, g_type_name (THUNAR_TYPE_TREE_PANE)))
834     type = THUNAR_TYPE_TREE_PANE;
835   else
836     type = G_TYPE_NONE;
837   thunar_window_install_sidepane (window, type);
838   g_free (last_side_pane);
839 
840   /* synchronise the "directory-specific-settings" property with the global "misc-directory-specific-settings" property */
841   exo_binding_new (G_OBJECT (window->preferences), "misc-directory-specific-settings", G_OBJECT (window), "directory-specific-settings");
842 
843   /* setup a new statusbar */
844   window->statusbar = thunar_statusbar_new ();
845   gtk_widget_set_hexpand (window->statusbar, TRUE);
846   gtk_grid_attach (GTK_GRID (window->view_box), window->statusbar, 0, 2, 1, 1);
847   if (last_statusbar_visible)
848     gtk_widget_show (window->statusbar);
849 
850   if (G_LIKELY (window->view != NULL))
851     thunar_window_binding_create (window, window->view, "statusbar-text", window->statusbar, "text", G_BINDING_SYNC_CREATE);
852 
853   /* ensure that all the view types are registered */
854   g_type_ensure (THUNAR_TYPE_ICON_VIEW);
855   g_type_ensure (THUNAR_TYPE_DETAILS_VIEW);
856   g_type_ensure (THUNAR_TYPE_COMPACT_VIEW);
857 
858   /* load the bookmarks file and monitor */
859   window->bookmarks = NULL;
860   window->bookmark_file = thunar_g_file_new_for_bookmarks ();
861   window->bookmark_monitor = g_file_monitor_file (window->bookmark_file, G_FILE_MONITOR_NONE, NULL, NULL);
862   if (G_LIKELY (window->bookmark_monitor != NULL))
863       g_signal_connect_swapped (window->bookmark_monitor, "changed", G_CALLBACK (thunar_window_update_bookmarks), window);
864 
865   /* initial load of the bookmarks */
866   thunar_window_update_bookmarks (window);
867 }
868 
869 
870 static void
thunar_window_screen_changed(GtkWidget * widget,GdkScreen * old_screen,gpointer userdata)871 thunar_window_screen_changed (GtkWidget *widget,
872                               GdkScreen *old_screen,
873                               gpointer   userdata)
874 {
875   GdkScreen *screen = gdk_screen_get_default ();
876   GdkVisual *visual = gdk_screen_get_rgba_visual (screen);
877 
878   if (visual == NULL || !gdk_screen_is_composited (screen))
879     visual = gdk_screen_get_system_visual (screen);
880 
881   gtk_widget_set_visual (GTK_WIDGET (widget), visual);
882 }
883 
884 
885 /**
886  * thunar_window_select_files:
887  * @window            : a #ThunarWindow instance.
888  * @files_to_selected : a list of #GFile<!---->s
889  *
890  * Visually selects the files, given by the list
891  **/
892 void
thunar_window_select_files(ThunarWindow * window,GList * files_to_selected)893 thunar_window_select_files (ThunarWindow *window,
894                             GList        *files_to_selected)
895 {
896   GList        *thunar_files = NULL;
897   ThunarFolder *thunar_folder;
898 
899   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
900 
901   /* If possible, reload the current directory to make sure new files got added to the view */
902   thunar_folder = thunar_folder_get_for_file (window->current_directory);
903   if (thunar_folder != NULL)
904     {
905       thunar_folder_reload (thunar_folder, FALSE);
906       g_object_unref (thunar_folder);
907     }
908 
909   for (GList *lp = files_to_selected; lp != NULL; lp = lp->next)
910     thunar_files = g_list_append (thunar_files, thunar_file_get (G_FILE (lp->data), NULL));
911   thunar_view_set_selected_files (THUNAR_VIEW (window->view), thunar_files);
912   g_list_free_full (thunar_files, g_object_unref);
913 }
914 
915 
916 
917 static void
thunar_window_create_menu(ThunarWindow * window,ThunarWindowAction action,GCallback cb_update_menu)918 thunar_window_create_menu (ThunarWindow       *window,
919                            ThunarWindowAction  action,
920                            GCallback           cb_update_menu)
921 {
922   GtkWidget *item;
923   GtkWidget *submenu;
924 
925   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
926 
927   item = xfce_gtk_menu_item_new_from_action_entry (get_action_entry (action), G_OBJECT (window), GTK_MENU_SHELL (window->menubar));
928 
929   submenu = g_object_new (THUNAR_TYPE_MENU, "menu-type", THUNAR_MENU_TYPE_WINDOW, "launcher", window->launcher, NULL);
930   gtk_menu_set_accel_group (GTK_MENU (submenu), window->accel_group);
931   gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), GTK_WIDGET (submenu));
932   g_signal_connect_swapped (G_OBJECT (submenu), "show", G_CALLBACK (cb_update_menu), window);
933 }
934 
935 
936 
937 static void
thunar_window_update_file_menu(ThunarWindow * window,GtkWidget * menu)938 thunar_window_update_file_menu (ThunarWindow *window,
939                                 GtkWidget    *menu)
940 {
941   GtkWidget  *item;
942 
943   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
944 
945   thunar_gtk_menu_clean (GTK_MENU (menu));
946   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_NEW_TAB), G_OBJECT (window), GTK_MENU_SHELL (menu));
947   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_NEW_WINDOW), G_OBJECT (window), GTK_MENU_SHELL (menu));
948   xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu));
949   thunar_menu_add_sections (THUNAR_MENU (menu), THUNAR_MENU_SECTION_OPEN
950                                               | THUNAR_MENU_SECTION_SENDTO
951                                               | THUNAR_MENU_SECTION_CREATE_NEW_FILES
952                                               | THUNAR_MENU_SECTION_EMPTY_TRASH
953                                               | THUNAR_MENU_SECTION_CUSTOM_ACTIONS
954                                               | THUNAR_MENU_SECTION_PROPERTIES);
955   xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu));
956   item = xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_DETACH_TAB), G_OBJECT (window), GTK_MENU_SHELL (menu));
957   gtk_widget_set_sensitive (item, gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook)) > 1);
958   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_CLOSE_ALL_WINDOWS), G_OBJECT (window), GTK_MENU_SHELL (menu));
959   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_CLOSE_TAB), G_OBJECT (window), GTK_MENU_SHELL (menu));
960   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_CLOSE_WINDOW), G_OBJECT (window), GTK_MENU_SHELL (menu));
961 
962   gtk_widget_show_all (GTK_WIDGET (menu));
963   thunar_window_redirect_menu_tooltips_to_statusbar (window, GTK_MENU (menu));
964 }
965 
966 
967 
968 static void
thunar_window_update_edit_menu(ThunarWindow * window,GtkWidget * menu)969 thunar_window_update_edit_menu (ThunarWindow *window,
970                                 GtkWidget    *menu)
971 {
972   GtkWidget       *gtk_menu_item;
973   GList           *thunarx_menu_items;
974   GList           *pp, *lp;
975 
976   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
977 
978   thunar_gtk_menu_clean (GTK_MENU (menu));
979   thunar_menu_add_sections (THUNAR_MENU (menu), THUNAR_MENU_SECTION_CUT
980                                               | THUNAR_MENU_SECTION_COPY_PASTE
981                                               | THUNAR_MENU_SECTION_TRASH_DELETE);
982   if (window->view != NULL)
983     {
984       thunar_standard_view_append_menu_item (THUNAR_STANDARD_VIEW (window->view),
985                                              GTK_MENU (menu), THUNAR_STANDARD_VIEW_ACTION_SELECT_ALL_FILES);
986       thunar_standard_view_append_menu_item (THUNAR_STANDARD_VIEW (window->view),
987                                              GTK_MENU (menu), THUNAR_STANDARD_VIEW_ACTION_SELECT_BY_PATTERN);
988       thunar_standard_view_append_menu_item (THUNAR_STANDARD_VIEW (window->view),
989                                              GTK_MENU (menu), THUNAR_STANDARD_VIEW_ACTION_INVERT_SELECTION);
990     }
991   xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu));
992   thunar_menu_add_sections (THUNAR_MENU (menu), THUNAR_MENU_SECTION_DUPLICATE
993                                               | THUNAR_MENU_SECTION_MAKELINK
994                                               | THUNAR_MENU_SECTION_RENAME
995                                               | THUNAR_MENU_SECTION_RESTORE);
996 
997   /* determine the available preferences providers */
998   if (G_LIKELY (window->thunarx_preferences_providers != NULL))
999     {
1000       /* add menu items from all providers */
1001       for (pp = window->thunarx_preferences_providers; pp != NULL; pp = pp->next)
1002         {
1003           /* determine the available menu items for the provider */
1004           thunarx_menu_items = thunarx_preferences_provider_get_menu_items (THUNARX_PREFERENCES_PROVIDER (pp->data), GTK_WIDGET (window));
1005           for (lp = thunarx_menu_items; lp != NULL; lp = lp->next)
1006             {
1007                 gtk_menu_item = thunar_gtk_menu_thunarx_menu_item_new (lp->data, GTK_MENU_SHELL (menu));
1008 
1009                 /* Each thunarx_menu_item will be destroyed together with its related gtk_menu_item */
1010                 g_signal_connect_swapped (G_OBJECT (gtk_menu_item), "destroy", G_CALLBACK (g_object_unref), lp->data);
1011             }
1012 
1013           /* release the list */
1014           g_list_free (thunarx_menu_items);
1015         }
1016     }
1017   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_PREFERENCES), G_OBJECT (window), GTK_MENU_SHELL (menu));
1018   gtk_widget_show_all (GTK_WIDGET (menu));
1019 
1020   thunar_window_redirect_menu_tooltips_to_statusbar (window, GTK_MENU (menu));
1021 }
1022 
1023 
1024 
1025 static void
thunar_window_update_view_menu(ThunarWindow * window,GtkWidget * menu)1026 thunar_window_update_view_menu (ThunarWindow *window,
1027                                 GtkWidget    *menu)
1028 {
1029   GtkWidget  *item;
1030   GtkWidget  *sub_items;
1031   gchar      *last_location_bar;
1032   gchar      *last_side_pane;
1033 
1034   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
1035 
1036   thunar_gtk_menu_clean (GTK_MENU (menu));
1037   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_RELOAD), G_OBJECT (window), GTK_MENU_SHELL (menu));
1038   xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu));
1039   item = xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_LOCATION_SELECTOR_MENU), G_OBJECT (window), GTK_MENU_SHELL (menu));
1040   sub_items =  gtk_menu_new();
1041   gtk_menu_set_accel_group (GTK_MENU (sub_items), window->accel_group);
1042   g_object_get (window->preferences, "last-location-bar", &last_location_bar, NULL);
1043   xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_LOCATION_SELECTOR_PATHBAR), G_OBJECT (window),
1044                                                    exo_str_is_equal (last_location_bar, g_type_name (THUNAR_TYPE_LOCATION_ENTRY)), GTK_MENU_SHELL (sub_items));
1045   xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_LOCATION_SELECTOR_TOOLBAR), G_OBJECT (window),
1046                                                    exo_str_is_equal (last_location_bar, g_type_name (THUNAR_TYPE_LOCATION_BUTTONS)), GTK_MENU_SHELL (sub_items));
1047   g_free (last_location_bar);
1048   gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), GTK_WIDGET (sub_items));
1049   item = xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_SIDE_PANE_MENU), G_OBJECT (window), GTK_MENU_SHELL (menu));
1050   sub_items =  gtk_menu_new();
1051   gtk_menu_set_accel_group (GTK_MENU (sub_items), window->accel_group);
1052   g_object_get (window->preferences, "last-side-pane", &last_side_pane, NULL);
1053   xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_SIDE_PANE_SHORTCUTS), G_OBJECT (window),
1054                                                    exo_str_is_equal (last_side_pane, g_type_name (THUNAR_TYPE_SHORTCUTS_PANE)), GTK_MENU_SHELL (sub_items));
1055   xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_SIDE_PANE_TREE), G_OBJECT (window),
1056                                                    exo_str_is_equal (last_side_pane, g_type_name (THUNAR_TYPE_TREE_PANE)), GTK_MENU_SHELL (sub_items));
1057   g_free (last_side_pane);
1058   gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), GTK_WIDGET (sub_items));
1059   xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_STATUSBAR), G_OBJECT (window),
1060                                                    gtk_widget_get_visible (window->statusbar), GTK_MENU_SHELL (menu));
1061   xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_MENUBAR), G_OBJECT (window),
1062                                                    gtk_widget_get_visible (window->menubar), GTK_MENU_SHELL (menu));
1063   xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu));
1064   xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_SHOW_HIDDEN), G_OBJECT (window),
1065                                                    window->show_hidden, GTK_MENU_SHELL (menu));
1066   xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu));
1067   if (window->view != NULL)
1068     thunar_standard_view_append_menu_items (THUNAR_STANDARD_VIEW (window->view), GTK_MENU (menu), window->accel_group);
1069   xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu));
1070   thunar_window_append_menu_item (window, GTK_MENU_SHELL (menu), THUNAR_WINDOW_ACTION_ZOOM_IN);
1071   thunar_window_append_menu_item (window, GTK_MENU_SHELL (menu), THUNAR_WINDOW_ACTION_ZOOM_OUT);
1072   thunar_window_append_menu_item (window, GTK_MENU_SHELL (menu), THUNAR_WINDOW_ACTION_ZOOM_RESET);
1073   xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu));
1074 
1075   if (window->directory_specific_settings)
1076     {
1077       item = xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_CLEAR_DIRECTORY_SPECIFIC_SETTINGS),
1078                                                        G_OBJECT (window), GTK_MENU_SHELL (menu));
1079       gtk_widget_set_sensitive (item, thunar_file_has_directory_specific_settings (window->current_directory));
1080       xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu));
1081     }
1082 
1083   xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_AS_ICONS),
1084                                                  G_OBJECT (window), window->view_type == THUNAR_TYPE_ICON_VIEW, GTK_MENU_SHELL (menu));
1085   xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_AS_DETAILED_LIST),
1086                                                  G_OBJECT (window), window->view_type == THUNAR_TYPE_DETAILS_VIEW, GTK_MENU_SHELL (menu));
1087   xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_AS_COMPACT_LIST),
1088                                                  G_OBJECT (window), window->view_type == THUNAR_TYPE_COMPACT_VIEW, GTK_MENU_SHELL (menu));
1089 
1090   gtk_widget_show_all (GTK_WIDGET (menu));
1091 
1092   thunar_window_redirect_menu_tooltips_to_statusbar (window, GTK_MENU (menu));
1093 }
1094 
1095 
1096 
1097 static void
thunar_window_update_go_menu(ThunarWindow * window,GtkWidget * menu)1098 thunar_window_update_go_menu (ThunarWindow *window,
1099                               GtkWidget    *menu)
1100 {
1101   gchar                    *icon_name;
1102   const XfceGtkActionEntry *action_entry;
1103   ThunarHistory            *history = NULL;
1104   GtkWidget                *item;
1105 
1106   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
1107 
1108   if (window->view != NULL)
1109     history = thunar_standard_view_get_history (THUNAR_STANDARD_VIEW (window->view));
1110 
1111   thunar_gtk_menu_clean (GTK_MENU (menu));
1112   item = xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_PARENT), G_OBJECT (window), GTK_MENU_SHELL (menu));
1113   gtk_widget_set_sensitive (item, !thunar_g_file_is_root (thunar_file_get_file (window->current_directory)));
1114   item = xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_BACK), G_OBJECT (window), GTK_MENU_SHELL (menu));
1115   if (history != NULL)
1116     gtk_widget_set_sensitive (item, thunar_history_has_back (history));
1117   item = xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_FORWARD), G_OBJECT (window), GTK_MENU_SHELL (menu));
1118   if (history != NULL)
1119     gtk_widget_set_sensitive (item, thunar_history_has_forward (history));
1120   xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu));
1121   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_COMPUTER), G_OBJECT (window), GTK_MENU_SHELL (menu));
1122   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_HOME), G_OBJECT (window), GTK_MENU_SHELL (menu));
1123   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_DESKTOP), G_OBJECT (window), GTK_MENU_SHELL (menu));
1124   if (thunar_g_vfs_is_uri_scheme_supported ("trash"))
1125     {
1126       GFile      *gfile;
1127       ThunarFile *trash_folder;
1128 
1129       /* try to connect to the trash bin */
1130       gfile = thunar_g_file_new_for_trash ();
1131       if (gfile != NULL)
1132         {
1133           trash_folder = thunar_file_get (gfile, NULL);
1134           if (trash_folder != NULL)
1135             {
1136               action_entry = get_action_entry (THUNAR_WINDOW_ACTION_OPEN_TRASH);
1137               if (action_entry != NULL)
1138                 {
1139                   if (thunar_file_get_item_count (trash_folder) > 0)
1140                     icon_name = "user-trash-full";
1141                   else
1142                     icon_name = "user-trash";
1143                   xfce_gtk_image_menu_item_new_from_icon_name (action_entry->menu_item_label_text, action_entry->menu_item_tooltip_text,
1144                                                                action_entry->accel_path, action_entry->callback, G_OBJECT (window), icon_name, GTK_MENU_SHELL (menu));
1145                 }
1146               g_object_unref (trash_folder);
1147             }
1148           g_object_unref (gfile);
1149         }
1150     }
1151   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_TEMPLATES), G_OBJECT (window), GTK_MENU_SHELL (menu));
1152   xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu));
1153   thunar_window_menu_add_bookmarks (window, GTK_MENU_SHELL (menu));
1154   xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu));
1155   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_FILE_SYSTEM), G_OBJECT (window), GTK_MENU_SHELL (menu));
1156   xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu));
1157   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_NETWORK), G_OBJECT (window), GTK_MENU_SHELL (menu));
1158   xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu));
1159   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_LOCATION), G_OBJECT (window), GTK_MENU_SHELL (menu));
1160   gtk_widget_show_all (GTK_WIDGET (menu));
1161 
1162   thunar_window_redirect_menu_tooltips_to_statusbar (window, GTK_MENU (menu));
1163 }
1164 
1165 
1166 
1167 static void
thunar_window_update_help_menu(ThunarWindow * window,GtkWidget * menu)1168 thunar_window_update_help_menu (ThunarWindow *window,
1169                                 GtkWidget    *menu)
1170 {
1171   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
1172 
1173   thunar_gtk_menu_clean (GTK_MENU (menu));
1174   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_CONTENTS), G_OBJECT (window), GTK_MENU_SHELL (menu));
1175   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_ABOUT), G_OBJECT (window), GTK_MENU_SHELL (menu));
1176   gtk_widget_show_all (GTK_WIDGET (menu));
1177 
1178   thunar_window_redirect_menu_tooltips_to_statusbar (window, GTK_MENU (menu));
1179 }
1180 
1181 
1182 
1183 static void
thunar_window_dispose(GObject * object)1184 thunar_window_dispose (GObject *object)
1185 {
1186   ThunarWindow  *window = THUNAR_WINDOW (object);
1187 
1188   /* indicate that history items are out of use */
1189   window->location_toolbar_item_back = NULL;
1190   window->location_toolbar_item_forward = NULL;
1191 
1192   if (window->accel_group != NULL)
1193     {
1194       gtk_accel_group_disconnect (window->accel_group, NULL);
1195       gtk_window_remove_accel_group (GTK_WINDOW (window), window->accel_group);
1196       g_object_unref (window->accel_group);
1197       window->accel_group = NULL;
1198     }
1199 
1200   /* destroy the save geometry timer source */
1201   if (G_UNLIKELY (window->save_geometry_timer_id != 0))
1202     g_source_remove (window->save_geometry_timer_id);
1203 
1204   /* disconnect from the current-directory */
1205   thunar_window_set_current_directory (window, NULL);
1206 
1207   (*G_OBJECT_CLASS (thunar_window_parent_class)->dispose) (object);
1208 }
1209 
1210 
1211 
1212 static void
thunar_window_finalize(GObject * object)1213 thunar_window_finalize (GObject *object)
1214 {
1215   ThunarWindow *window = THUNAR_WINDOW (object);
1216 
1217   /* disconnect from the volume monitor */
1218   g_signal_handlers_disconnect_matched (window->device_monitor, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, window);
1219   g_object_unref (window->device_monitor);
1220 
1221   g_object_unref (window->icon_factory);
1222   g_object_unref (window->launcher);
1223 
1224   if (window->bookmark_file != NULL)
1225     g_object_unref (window->bookmark_file);
1226 
1227   if (window->bookmark_monitor != NULL)
1228     {
1229       g_file_monitor_cancel (window->bookmark_monitor);
1230       g_object_unref (window->bookmark_monitor);
1231     }
1232 
1233   /* release our reference on the provider factory */
1234   g_object_unref (window->provider_factory);
1235 
1236   /* release the preferences reference */
1237   g_object_unref (window->preferences);
1238 
1239   g_closure_invalidate (window->select_files_closure);
1240   g_closure_unref (window->select_files_closure);
1241 
1242   (*G_OBJECT_CLASS (thunar_window_parent_class)->finalize) (object);
1243 }
1244 
1245 
1246 
thunar_window_delete(GtkWidget * widget,GdkEvent * event,gpointer data)1247 static gboolean thunar_window_delete (GtkWidget *widget,
1248                                       GdkEvent  *event,
1249                                       gpointer   data )
1250 {
1251   GtkNotebook *notebook;
1252   gboolean confirm_close_multiple_tabs, do_not_ask_again;
1253   gint response, n_tabs;
1254 
1255    _thunar_return_val_if_fail (THUNAR_IS_WINDOW (widget),FALSE);
1256 
1257   /* if we don't have muliple tabs then just exit */
1258   notebook  = GTK_NOTEBOOK (THUNAR_WINDOW (widget)->notebook);
1259   n_tabs = gtk_notebook_get_n_pages (GTK_NOTEBOOK (THUNAR_WINDOW (widget)->notebook));
1260   if (n_tabs < 2)
1261     return FALSE;
1262 
1263   /* check if the user has disabled confirmation of closing multiple tabs, and just exit if so */
1264   g_object_get (G_OBJECT (THUNAR_WINDOW (widget)->preferences),
1265                 "misc-confirm-close-multiple-tabs", &confirm_close_multiple_tabs,
1266                 NULL);
1267   if(!confirm_close_multiple_tabs)
1268     return FALSE;
1269 
1270   /* ask the user for confirmation */
1271   do_not_ask_again = FALSE;
1272   response = xfce_dialog_confirm_close_tabs (GTK_WINDOW (widget), n_tabs, TRUE, &do_not_ask_again);
1273 
1274   /* if the user requested not to be asked again, store this preference */
1275   if (response != GTK_RESPONSE_CANCEL && do_not_ask_again)
1276     g_object_set (G_OBJECT (THUNAR_WINDOW (widget)->preferences),
1277                   "misc-confirm-close-multiple-tabs", FALSE, NULL);
1278 
1279   if(response == GTK_RESPONSE_YES)
1280     return FALSE;
1281   if(response == GTK_RESPONSE_CLOSE)
1282     gtk_notebook_remove_page (notebook,  gtk_notebook_get_current_page(notebook));
1283   return TRUE;
1284 }
1285 
1286 
1287 
1288 static void
thunar_window_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1289 thunar_window_get_property (GObject    *object,
1290                             guint       prop_id,
1291                             GValue     *value,
1292                             GParamSpec *pspec)
1293 {
1294   ThunarWindow *window = THUNAR_WINDOW (object);
1295 
1296   switch (prop_id)
1297     {
1298     case PROP_CURRENT_DIRECTORY:
1299       g_value_set_object (value, thunar_window_get_current_directory (window));
1300       break;
1301 
1302     case PROP_ZOOM_LEVEL:
1303       g_value_set_enum (value, window->zoom_level);
1304       break;
1305 
1306     default:
1307       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1308       break;
1309     }
1310 }
1311 
1312 
1313 
1314 static void
thunar_window_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1315 thunar_window_set_property (GObject            *object,
1316                             guint               prop_id,
1317                             const GValue       *value,
1318                             GParamSpec         *pspec)
1319 {
1320   ThunarWindow *window = THUNAR_WINDOW (object);
1321 
1322   switch (prop_id)
1323     {
1324     case PROP_CURRENT_DIRECTORY:
1325       thunar_window_set_current_directory (window, g_value_get_object (value));
1326       break;
1327 
1328     case PROP_ZOOM_LEVEL:
1329       thunar_window_set_zoom_level (window, g_value_get_enum (value));
1330       break;
1331 
1332     case PROP_DIRECTORY_SPECIFIC_SETTINGS:
1333       thunar_window_set_directory_specific_settings (window, g_value_get_boolean (value));
1334       break;
1335 
1336     default:
1337       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1338       break;
1339     }
1340 }
1341 
1342 
1343 
1344 static gboolean
thunar_window_reload(ThunarWindow * window,gboolean reload_info)1345 thunar_window_reload (ThunarWindow *window,
1346                       gboolean      reload_info)
1347 {
1348   _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
1349 
1350   /* force the view to reload */
1351   if (G_LIKELY (window->view != NULL))
1352     {
1353       thunar_view_reload (THUNAR_VIEW (window->view), reload_info);
1354       return TRUE;
1355     }
1356 
1357   return FALSE;
1358 }
1359 
1360 
1361 
1362 /**
1363  * thunar_window_has_shortcut_sidepane:
1364  * @window : a #ThunarWindow instance.
1365  *
1366  * Return value: True, if this window is running a shortcut sidepane
1367  **/
1368 gboolean
thunar_window_has_shortcut_sidepane(ThunarWindow * window)1369 thunar_window_has_shortcut_sidepane (ThunarWindow *window)
1370 {
1371   _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
1372 
1373   /* check if a side pane is currently active */
1374   if (G_LIKELY (window->sidepane != NULL))
1375     {
1376       return G_OBJECT_TYPE (window->sidepane) == THUNAR_TYPE_SHORTCUTS_PANE;
1377     }
1378   return FALSE;
1379 }
1380 
1381 
1382 
1383 /**
1384  * thunar_window_get_sidepane:
1385  * @window : a #ThunarWindow instance.
1386  *
1387  * Return value: (transfer none): The #ThunarSidePane of this window, or NULL if not available
1388  **/
thunar_window_get_sidepane(ThunarWindow * window)1389 GtkWidget* thunar_window_get_sidepane (ThunarWindow *window)
1390 {
1391   _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
1392   return GTK_WIDGET (window->sidepane);
1393 }
1394 
1395 
1396 
1397 static gboolean
thunar_window_toggle_sidepane(ThunarWindow * window)1398 thunar_window_toggle_sidepane (ThunarWindow *window)
1399 {
1400   _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
1401 
1402   /* check if a side pane is currently active */
1403   if (G_LIKELY (window->sidepane != NULL))
1404     {
1405       /* determine the currently active side pane type */
1406       window->toggle_sidepane_type = G_OBJECT_TYPE (window->sidepane);
1407       thunar_window_install_sidepane (window, G_TYPE_NONE);
1408     }
1409   else
1410     {
1411       /* check if we have a previously remembered toggle type */
1412       if (window->toggle_sidepane_type == THUNAR_TYPE_TREE_PANE || window->toggle_sidepane_type == THUNAR_TYPE_SHORTCUTS_PANE)
1413           thunar_window_install_sidepane (window, window->toggle_sidepane_type);
1414     }
1415 
1416   return TRUE;
1417 }
1418 
1419 
1420 
1421 static gboolean
thunar_window_zoom_in(ThunarWindow * window)1422 thunar_window_zoom_in (ThunarWindow *window)
1423 {
1424   _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
1425 
1426   /* check if we can still zoom in */
1427   if (G_LIKELY (window->zoom_level < THUNAR_ZOOM_N_LEVELS - 1))
1428     {
1429       thunar_window_set_zoom_level (window, window->zoom_level + 1);
1430       return TRUE;
1431     }
1432 
1433   return FALSE;
1434 }
1435 
1436 
1437 
1438 static gboolean
thunar_window_zoom_out(ThunarWindow * window)1439 thunar_window_zoom_out (ThunarWindow *window)
1440 {
1441   _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
1442 
1443   /* check if we can still zoom out */
1444   if (G_LIKELY (window->zoom_level > 0))
1445     {
1446       thunar_window_set_zoom_level (window, window->zoom_level - 1);
1447       return TRUE;
1448     }
1449 
1450   return FALSE;
1451 }
1452 
1453 
1454 
1455 static gboolean
thunar_window_zoom_reset(ThunarWindow * window)1456 thunar_window_zoom_reset (ThunarWindow *window)
1457 {
1458   _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
1459 
1460   /* tell the view to reset it's zoom level */
1461   if (G_LIKELY (window->view != NULL))
1462     {
1463       thunar_view_reset_zoom_level (THUNAR_VIEW (window->view));
1464       return TRUE;
1465     }
1466 
1467   return FALSE;
1468 }
1469 
1470 
1471 
1472 static gboolean
thunar_window_tab_change(ThunarWindow * window,gint nth)1473 thunar_window_tab_change (ThunarWindow *window,
1474                           gint          nth)
1475 {
1476   _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
1477 
1478   /* Alt+0 is 10th tab */
1479   gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook),
1480                                  nth == -1 ? 9 : nth);
1481 
1482   return TRUE;
1483 }
1484 
1485 
1486 
1487 static void
thunar_window_action_switch_next_tab(ThunarWindow * window)1488 thunar_window_action_switch_next_tab (ThunarWindow *window)
1489 {
1490   gint current_page;
1491   gint new_page;
1492   gint pages;
1493 
1494   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
1495 
1496   current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook));
1497   pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook));
1498   new_page = (current_page + 1) % pages;
1499 
1500   gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), new_page);
1501 }
1502 
1503 
1504 
1505 static void
thunar_window_action_switch_previous_tab(ThunarWindow * window)1506 thunar_window_action_switch_previous_tab (ThunarWindow *window)
1507 {
1508   gint current_page;
1509   gint new_page;
1510   gint pages;
1511 
1512   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
1513 
1514   current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook));
1515   pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook));
1516   new_page = (current_page - 1) % pages;
1517 
1518   gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), new_page);
1519 }
1520 
1521 
1522 
1523 static void
thunar_window_clipboard_manager_changed(GtkWidget * widget)1524 thunar_window_clipboard_manager_changed (GtkWidget *widget)
1525 {
1526   ThunarWindow *window = THUNAR_WINDOW (widget);
1527 
1528   thunar_window_reload (window, FALSE);
1529 }
1530 
1531 
1532 
1533 static void
thunar_window_realize(GtkWidget * widget)1534 thunar_window_realize (GtkWidget *widget)
1535 {
1536   ThunarWindow *window = THUNAR_WINDOW (widget);
1537 
1538   /* let the GtkWidget class perform the realize operation */
1539   (*GTK_WIDGET_CLASS (thunar_window_parent_class)->realize) (widget);
1540 
1541   /* connect to the clipboard manager of the new display and be sure to redraw the window
1542    * whenever the clipboard contents change to make sure we always display up2date state.
1543    */
1544   window->clipboard = thunar_clipboard_manager_get_for_display (gtk_widget_get_display (widget));
1545   g_signal_connect_swapped (G_OBJECT (window->clipboard), "changed",
1546                             G_CALLBACK (thunar_window_clipboard_manager_changed), widget);
1547 }
1548 
1549 
1550 
1551 static void
thunar_window_unrealize(GtkWidget * widget)1552 thunar_window_unrealize (GtkWidget *widget)
1553 {
1554   ThunarWindow *window = THUNAR_WINDOW (widget);
1555 
1556   /* disconnect from the clipboard manager */
1557   g_signal_handlers_disconnect_by_func (G_OBJECT (window->clipboard), thunar_window_clipboard_manager_changed, widget);
1558 
1559   /* let the GtkWidget class unrealize the window */
1560   (*GTK_WIDGET_CLASS (thunar_window_parent_class)->unrealize) (widget);
1561 
1562   /* drop the reference on the clipboard manager, we do this after letting the GtkWidget class
1563    * unrealise the window to prevent the clipboard being disposed during the unrealize  */
1564   g_object_unref (G_OBJECT (window->clipboard));
1565 }
1566 
1567 
1568 
1569 static gboolean
thunar_window_configure_event(GtkWidget * widget,GdkEventConfigure * event)1570 thunar_window_configure_event (GtkWidget         *widget,
1571                                GdkEventConfigure *event)
1572 {
1573   ThunarWindow *window = THUNAR_WINDOW (widget);
1574   GtkAllocation widget_allocation;
1575 
1576   gtk_widget_get_allocation (widget, &widget_allocation);
1577 
1578   /* check if we have a new dimension here */
1579   if (widget_allocation.width != event->width || widget_allocation.height != event->height)
1580     {
1581       /* drop any previous timer source */
1582       if (window->save_geometry_timer_id != 0)
1583         g_source_remove (window->save_geometry_timer_id);
1584 
1585       /* check if we should schedule another save timer */
1586       if (gtk_widget_get_visible (widget))
1587         {
1588           /* save the geometry one second after the last configure event */
1589           window->save_geometry_timer_id = g_timeout_add_seconds_full (G_PRIORITY_LOW, 1, thunar_window_save_geometry_timer,
1590                                                                        window, thunar_window_save_geometry_timer_destroy);
1591         }
1592     }
1593 
1594   /* let Gtk+ handle the configure event */
1595   return (*GTK_WIDGET_CLASS (thunar_window_parent_class)->configure_event) (widget, event);
1596 }
1597 
1598 
1599 
1600 static void
thunar_window_binding_destroyed(gpointer data,GObject * binding)1601 thunar_window_binding_destroyed (gpointer data,
1602                                  GObject  *binding)
1603 {
1604   ThunarWindow *window = THUNAR_WINDOW (data);
1605 
1606   if (window->view_bindings != NULL)
1607     window->view_bindings = g_slist_remove (window->view_bindings, binding);
1608 }
1609 
1610 
1611 
1612 static void
thunar_window_binding_create(ThunarWindow * window,gpointer src_object,const gchar * src_prop,gpointer dst_object,const gchar * dst_prop,GBindingFlags flags)1613 thunar_window_binding_create (ThunarWindow *window,
1614                               gpointer src_object,
1615                               const gchar *src_prop,
1616                               gpointer dst_object,
1617                               const gchar *dst_prop,
1618                               GBindingFlags flags)
1619 {
1620   GBinding *binding;
1621 
1622   _thunar_return_if_fail (G_IS_OBJECT (src_object));
1623   _thunar_return_if_fail (G_IS_OBJECT (dst_object));
1624 
1625   binding = g_object_bind_property (G_OBJECT (src_object), src_prop,
1626                                     G_OBJECT (dst_object), dst_prop,
1627                                     flags);
1628 
1629   g_object_weak_ref (G_OBJECT (binding), thunar_window_binding_destroyed, window);
1630   window->view_bindings = g_slist_prepend (window->view_bindings, binding);
1631 }
1632 
1633 
1634 
1635 static void
thunar_window_notebook_switch_page(GtkWidget * notebook,GtkWidget * page,guint page_num,ThunarWindow * window)1636 thunar_window_notebook_switch_page (GtkWidget    *notebook,
1637                                     GtkWidget    *page,
1638                                     guint         page_num,
1639                                     ThunarWindow *window)
1640 {
1641   GSList        *view_bindings;
1642   ThunarFile    *current_directory;
1643   ThunarHistory *history;
1644 
1645   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
1646   _thunar_return_if_fail (GTK_IS_NOTEBOOK (notebook));
1647   _thunar_return_if_fail (THUNAR_IS_VIEW (page));
1648   _thunar_return_if_fail (window->notebook == notebook);
1649 
1650   /* leave if nothing changed */
1651   if (window->view == page)
1652     return;
1653 
1654   /* Use accelerators only on the current active tab */
1655   if (window->view != NULL)
1656     g_object_set (G_OBJECT (window->view), "accel-group", NULL, NULL);
1657   g_object_set (G_OBJECT (page), "accel-group", window->accel_group, NULL);
1658 
1659   if (G_LIKELY (window->view != NULL))
1660     {
1661       /* disconnect from previous history */
1662       if (window->signal_handler_id_history_changed != 0)
1663         {
1664           history = thunar_standard_view_get_history (THUNAR_STANDARD_VIEW (window->view));
1665           g_signal_handler_disconnect (history, window->signal_handler_id_history_changed);
1666           window->signal_handler_id_history_changed = 0;
1667         }
1668 
1669       /* unset view during switch */
1670       window->view = NULL;
1671     }
1672 
1673   /* disconnect existing bindings */
1674   view_bindings = window->view_bindings;
1675   window->view_bindings = NULL;
1676   g_slist_free_full (view_bindings, g_object_unref);
1677 
1678   /* update the directory of the current window */
1679   current_directory = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (page));
1680   thunar_window_set_current_directory (window, current_directory);
1681 
1682   /* add stock bindings */
1683   thunar_window_binding_create (window, window, "current-directory", page, "current-directory", G_BINDING_DEFAULT);
1684   thunar_window_binding_create (window, page, "loading", window->spinner, "active", G_BINDING_SYNC_CREATE);
1685   thunar_window_binding_create (window, page, "selected-files", window->launcher, "selected-files", G_BINDING_SYNC_CREATE);
1686   thunar_window_binding_create (window, page, "zoom-level", window, "zoom-level", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
1687 
1688   /* connect to the sidepane (if any) */
1689   if (G_LIKELY (window->sidepane != NULL))
1690     {
1691       thunar_window_binding_create (window, page, "selected-files",
1692                                     window->sidepane, "selected-files",
1693                                     G_BINDING_SYNC_CREATE);
1694     }
1695 
1696   /* connect to the statusbar (if any) */
1697   if (G_LIKELY (window->statusbar != NULL))
1698     {
1699       thunar_window_binding_create (window, page, "statusbar-text",
1700                                     window->statusbar, "text",
1701                                     G_BINDING_SYNC_CREATE);
1702     }
1703 
1704   /* activate new view */
1705   window->view = page;
1706   window->view_type = G_TYPE_FROM_INSTANCE (page);
1707 
1708   /* remember the last view type if directory specific settings are not enabled */
1709   if (!window->directory_specific_settings && window->view_type != G_TYPE_NONE)
1710     g_object_set (G_OBJECT (window->preferences), "last-view", g_type_name (window->view_type), NULL);
1711 
1712   /* connect to the new history */
1713   history = thunar_standard_view_get_history (THUNAR_STANDARD_VIEW (window->view));
1714   if (history != NULL)
1715     {
1716       window->signal_handler_id_history_changed = g_signal_connect_swapped (G_OBJECT (history), "history-changed", G_CALLBACK (thunar_window_history_changed), window);
1717       thunar_window_history_changed (window);
1718     }
1719 
1720   /* update the selection */
1721   thunar_standard_view_selection_changed (THUNAR_STANDARD_VIEW (page));
1722 
1723   gtk_widget_grab_focus (page);
1724 }
1725 
1726 
1727 
1728 static void
thunar_window_notebook_show_tabs(ThunarWindow * window)1729 thunar_window_notebook_show_tabs (ThunarWindow *window)
1730 {
1731   gint       n_pages;
1732   gboolean   show_tabs = TRUE;
1733 
1734   /* check if tabs should be visible */
1735   n_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook));
1736   if (n_pages < 2)
1737     {
1738       g_object_get (G_OBJECT (window->preferences),
1739                     "misc-always-show-tabs", &show_tabs, NULL);
1740     }
1741 
1742   /* update visibility */
1743   gtk_notebook_set_show_tabs (GTK_NOTEBOOK (window->notebook), show_tabs);
1744 }
1745 
1746 
1747 
1748 static void
thunar_window_history_changed(ThunarWindow * window)1749 thunar_window_history_changed (ThunarWindow *window)
1750 {
1751   ThunarHistory *history;
1752 
1753   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
1754 
1755   if (window->view == NULL)
1756     return;
1757 
1758   history = thunar_standard_view_get_history (THUNAR_STANDARD_VIEW (window->view));
1759   if (history == NULL)
1760     return;
1761 
1762   if (window->location_toolbar_item_back != NULL)
1763     gtk_widget_set_sensitive (window->location_toolbar_item_back, thunar_history_has_back (history));
1764 
1765   if (window->location_toolbar_item_forward != NULL)
1766     gtk_widget_set_sensitive (window->location_toolbar_item_forward, thunar_history_has_forward (history));
1767 }
1768 
1769 
1770 
1771 static void
thunar_window_notebook_page_added(GtkWidget * notebook,GtkWidget * page,guint page_num,ThunarWindow * window)1772 thunar_window_notebook_page_added (GtkWidget    *notebook,
1773                                    GtkWidget    *page,
1774                                    guint         page_num,
1775                                    ThunarWindow *window)
1776 {
1777   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
1778   _thunar_return_if_fail (GTK_IS_NOTEBOOK (notebook));
1779   _thunar_return_if_fail (THUNAR_IS_VIEW (page));
1780   _thunar_return_if_fail (window->notebook == notebook);
1781 
1782   /* connect signals */
1783   g_signal_connect (G_OBJECT (page), "notify::loading", G_CALLBACK (thunar_window_notify_loading), window);
1784   g_signal_connect_swapped (G_OBJECT (page), "start-open-location", G_CALLBACK (thunar_window_start_open_location), window);
1785   g_signal_connect_swapped (G_OBJECT (page), "change-directory", G_CALLBACK (thunar_window_set_current_directory), window);
1786   g_signal_connect_swapped (G_OBJECT (page), "open-new-tab", G_CALLBACK (thunar_window_notebook_open_new_tab), window);
1787 
1788   /* update tab visibility */
1789   thunar_window_notebook_show_tabs (window);
1790 
1791   /* set default type if not set yet */
1792   if (window->view_type == G_TYPE_NONE)
1793     window->view_type = G_OBJECT_TYPE (page);
1794 }
1795 
1796 
1797 
1798 static void
thunar_window_notebook_page_removed(GtkWidget * notebook,GtkWidget * page,guint page_num,ThunarWindow * window)1799 thunar_window_notebook_page_removed (GtkWidget    *notebook,
1800                                      GtkWidget    *page,
1801                                      guint         page_num,
1802                                      ThunarWindow *window)
1803 {
1804   gint n_pages;
1805 
1806   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
1807   _thunar_return_if_fail (GTK_IS_NOTEBOOK (notebook));
1808   _thunar_return_if_fail (THUNAR_IS_VIEW (page));
1809   _thunar_return_if_fail (window->notebook == notebook);
1810 
1811   /* drop connected signals */
1812   g_signal_handlers_disconnect_matched (page, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, window);
1813 
1814   n_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook));
1815   if (n_pages == 0)
1816     {
1817       /* destroy the window */
1818       gtk_widget_destroy (GTK_WIDGET (window));
1819     }
1820   else
1821     {
1822       /* update tab visibility */
1823       thunar_window_notebook_show_tabs (window);
1824     }
1825 }
1826 
1827 
1828 
1829 static gboolean
thunar_window_notebook_button_press_event(GtkWidget * notebook,GdkEventButton * event,ThunarWindow * window)1830 thunar_window_notebook_button_press_event (GtkWidget      *notebook,
1831                                            GdkEventButton *event,
1832                                            ThunarWindow   *window)
1833 {
1834   gint           page_num = 0;
1835   GtkWidget     *page;
1836   GtkWidget     *label_box;
1837   GtkAllocation  alloc;
1838   gint           x, y;
1839   gboolean       close_tab;
1840 
1841   if ((event->button == 2 || event->button == 3)
1842       && event->type == GDK_BUTTON_PRESS)
1843     {
1844       /* get real window coordinates */
1845       gdk_window_get_position (event->window, &x, &y);
1846       x += event->x;
1847       y += event->y;
1848 
1849       /* lookup the clicked tab */
1850       while ((page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), page_num)) != NULL)
1851         {
1852           label_box = gtk_notebook_get_tab_label (GTK_NOTEBOOK (notebook), page);
1853           gtk_widget_get_allocation (label_box, &alloc);
1854 
1855           if (x >= alloc.x && x < alloc.x + alloc.width
1856               && y >= alloc.y && y < alloc.y + alloc.height)
1857             break;
1858 
1859           page_num++;
1860         }
1861 
1862       /* leave if no tab could be found */
1863       if (page == NULL)
1864         return FALSE;
1865 
1866       if (event->button == 2)
1867         {
1868           /* check if we should close the tab */
1869           g_object_get (window->preferences, "misc-tab-close-middle-click", &close_tab, NULL);
1870           if (close_tab)
1871             gtk_widget_destroy (page);
1872         }
1873       else if (event->button == 3)
1874         {
1875           /* update the current tab before we show the menu */
1876           gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), page_num);
1877 
1878           /* show the tab menu */
1879           thunar_window_notebook_popup_menu (notebook, window);
1880         }
1881 
1882       return TRUE;
1883     }
1884 
1885   return FALSE;
1886 }
1887 
1888 
1889 
1890 static gboolean
thunar_window_notebook_popup_menu(GtkWidget * notebook,ThunarWindow * window)1891 thunar_window_notebook_popup_menu (GtkWidget    *notebook,
1892                                    ThunarWindow *window)
1893 {
1894   GtkWidget *menu;
1895 
1896   menu = gtk_menu_new ();
1897   gtk_menu_set_accel_group (GTK_MENU (menu), window->accel_group);
1898   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_NEW_TAB), G_OBJECT (window), GTK_MENU_SHELL (menu));
1899   xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu));
1900   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_DETACH_TAB), G_OBJECT (window), GTK_MENU_SHELL (menu));
1901   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_SWITCH_PREV_TAB), G_OBJECT (window), GTK_MENU_SHELL (menu));
1902   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_SWITCH_NEXT_TAB), G_OBJECT (window), GTK_MENU_SHELL (menu));
1903   xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu));
1904   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_CLOSE_TAB), G_OBJECT (window), GTK_MENU_SHELL (menu));
1905   gtk_widget_show_all (menu);
1906   thunar_gtk_menu_run (GTK_MENU (menu));
1907   return TRUE;
1908 }
1909 
1910 
1911 
1912 static gpointer
thunar_window_notebook_create_window(GtkWidget * notebook,GtkWidget * page,gint x,gint y,ThunarWindow * window)1913 thunar_window_notebook_create_window (GtkWidget    *notebook,
1914                                       GtkWidget    *page,
1915                                       gint          x,
1916                                       gint          y,
1917                                       ThunarWindow *window)
1918 {
1919   GtkWidget         *new_window;
1920   ThunarApplication *application;
1921   gint               width, height;
1922   GdkMonitor        *monitor;
1923   GdkScreen         *screen;
1924   GdkRectangle       geo;
1925 
1926   _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), NULL);
1927   _thunar_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
1928   _thunar_return_val_if_fail (window->notebook == notebook, NULL);
1929   _thunar_return_val_if_fail (THUNAR_IS_VIEW (page), NULL);
1930 
1931   /* do nothing if this window has only 1 tab */
1932   if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)) < 2)
1933     return NULL;
1934 
1935   /* create new window */
1936   application = thunar_application_get ();
1937   screen = gtk_window_get_screen (GTK_WINDOW (window));
1938   new_window = thunar_application_open_window (application, NULL, screen, NULL, TRUE);
1939   g_object_unref (application);
1940 
1941   /* make sure the new window has the same size */
1942   gtk_window_get_size (GTK_WINDOW (window), &width, &height);
1943   gtk_window_resize (GTK_WINDOW (new_window), width, height);
1944 
1945   /* move the window to the drop position */
1946   if (x >= 0 && y >= 0)
1947     {
1948       /* get the monitor geometry */
1949       monitor = gdk_display_get_monitor_at_point (gdk_display_get_default (), x, y);
1950       gdk_monitor_get_geometry (monitor, &geo);
1951 
1952       /* calculate window position, but keep it on the current monitor */
1953       x = CLAMP (x - width / 2, geo.x, geo.x + geo.width - width);
1954       y = CLAMP (y - height / 2, geo.y, geo.y + geo.height - height);
1955 
1956       /* move the window */
1957       gtk_window_move (GTK_WINDOW (new_window), MAX (0, x), MAX (0, y));
1958     }
1959 
1960   /* insert page in new notebook */
1961   return THUNAR_WINDOW (new_window)->notebook;
1962 }
1963 
1964 
1965 
1966 static GtkWidget*
thunar_window_notebook_insert(ThunarWindow * window,ThunarFile * directory,GType view_type,gint position,ThunarHistory * history)1967 thunar_window_notebook_insert (ThunarWindow  *window,
1968                                ThunarFile    *directory,
1969                                GType          view_type,
1970                                gint           position,
1971                                ThunarHistory *history)
1972 {
1973   GtkWidget      *view;
1974   GtkWidget      *label;
1975   GtkWidget      *label_box;
1976   GtkWidget      *button;
1977   GtkWidget      *icon;
1978 
1979   _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), NULL);
1980   _thunar_return_val_if_fail (THUNAR_IS_FILE (directory), NULL);
1981   _thunar_return_val_if_fail (view_type != G_TYPE_NONE, NULL);
1982   _thunar_return_val_if_fail (history == NULL || THUNAR_IS_HISTORY (history), NULL);
1983 
1984   /* allocate and setup a new view */
1985   view = g_object_new (view_type, "current-directory", directory, NULL);
1986   thunar_view_set_show_hidden (THUNAR_VIEW (view), window->show_hidden);
1987   gtk_widget_show (view);
1988 
1989   /* set the history of the view if a history is provided */
1990   if (history != NULL)
1991     {
1992       /* history only is updated on 'change-directory' signal. */
1993       /* For inserting a new tab, we need to update it manually */
1994       thunar_history_add (history, directory);
1995 
1996       thunar_standard_view_set_history (THUNAR_STANDARD_VIEW (view), history);
1997     }
1998 
1999   label_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
2000 
2001   label = gtk_label_new (NULL);
2002   exo_binding_new (G_OBJECT (view), "display-name", G_OBJECT (label), "label");
2003   exo_binding_new (G_OBJECT (view), "tooltip-text", G_OBJECT (label), "tooltip-text");
2004   gtk_widget_set_has_tooltip (label, TRUE);
2005   gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
2006   gtk_widget_set_margin_start (GTK_WIDGET(label), 3);
2007   gtk_widget_set_margin_end (GTK_WIDGET(label), 3);
2008   gtk_widget_set_margin_top (GTK_WIDGET(label), 3);
2009   gtk_widget_set_margin_bottom (GTK_WIDGET(label), 3);
2010   gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
2011   gtk_label_set_single_line_mode (GTK_LABEL (label), TRUE);
2012   gtk_box_pack_start (GTK_BOX (label_box), label, TRUE, TRUE, 0);
2013   gtk_widget_show (label);
2014 
2015   button = gtk_button_new ();
2016   gtk_box_pack_start (GTK_BOX (label_box), button, FALSE, FALSE, 0);
2017   gtk_widget_set_can_default (button, FALSE);
2018   gtk_widget_set_focus_on_click (button, FALSE);
2019   gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
2020   gtk_widget_set_tooltip_text (button, _("Close tab"));
2021   g_signal_connect_swapped (G_OBJECT (button), "clicked", G_CALLBACK (gtk_widget_destroy), view);
2022   gtk_widget_show (button);
2023 
2024   icon = gtk_image_new_from_icon_name ("window-close", GTK_ICON_SIZE_MENU);
2025   gtk_container_add (GTK_CONTAINER (button), icon);
2026   gtk_widget_show (icon);
2027 
2028   /* insert the new page */
2029   gtk_notebook_insert_page (GTK_NOTEBOOK (window->notebook), view, label_box, position);
2030 
2031   /* set tab child properties */
2032   gtk_container_child_set (GTK_CONTAINER (window->notebook), view, "tab-expand", TRUE, NULL);
2033   gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (window->notebook), view, TRUE);
2034   gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (window->notebook), view, TRUE);
2035 
2036   return view;
2037 }
2038 
2039 
2040 
2041 void
thunar_window_notebook_open_new_tab(ThunarWindow * window,ThunarFile * directory)2042 thunar_window_notebook_open_new_tab (ThunarWindow *window,
2043                                      ThunarFile   *directory)
2044 {
2045   ThunarHistory *history = NULL;
2046   GtkWidget     *view;
2047   gint           page_num;
2048   GType          view_type;
2049 
2050   /* save the history of the current view */
2051   if (THUNAR_IS_STANDARD_VIEW (window->view))
2052     {
2053       history = thunar_standard_view_copy_history (THUNAR_STANDARD_VIEW (window->view));
2054     }
2055 
2056   /* find the correct view type */
2057   view_type = thunar_window_view_type_for_directory (window, directory);
2058 
2059   /* insert the new view */
2060   page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook));
2061   view = thunar_window_notebook_insert (window, directory, view_type, page_num + 1, history);
2062 
2063   /* switch to the new view */
2064   page_num = gtk_notebook_page_num (GTK_NOTEBOOK (window->notebook), view);
2065   gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), page_num);
2066 
2067   /* take focus on the new view */
2068   gtk_widget_grab_focus (view);
2069 }
2070 
2071 
2072 
2073 void
thunar_window_update_directories(ThunarWindow * window,ThunarFile * old_directory,ThunarFile * new_directory)2074 thunar_window_update_directories (ThunarWindow *window,
2075                                   ThunarFile   *old_directory,
2076                                   ThunarFile   *new_directory)
2077 {
2078   GtkWidget  *view;
2079   ThunarFile *directory;
2080   gint        n;
2081   gint        n_pages;
2082   gint        active_page;
2083 
2084   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
2085   _thunar_return_if_fail (THUNAR_IS_FILE (old_directory));
2086   _thunar_return_if_fail (THUNAR_IS_FILE (new_directory));
2087 
2088   n_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook));
2089   if (G_UNLIKELY (n_pages == 0))
2090     return;
2091 
2092   active_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook));
2093 
2094   for (n = 0; n < n_pages; n++)
2095     {
2096       /* get the view */
2097       view = gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->notebook), n);
2098       if (! THUNAR_IS_NAVIGATOR (view))
2099         continue;
2100 
2101       /* get the directory of the view */
2102       directory = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (view));
2103       if (! THUNAR_IS_FILE (directory))
2104         continue;
2105 
2106       /* if it matches the old directory, change to the new one */
2107       if (directory == old_directory)
2108         {
2109           if (n == active_page)
2110             thunar_navigator_change_directory (THUNAR_NAVIGATOR (view), new_directory);
2111           else
2112             thunar_navigator_set_current_directory (THUNAR_NAVIGATOR (view), new_directory);
2113         }
2114     }
2115 }
2116 
2117 
2118 
2119 static void
thunar_window_update_location_bar_visible(ThunarWindow * window)2120 thunar_window_update_location_bar_visible (ThunarWindow *window)
2121 {
2122   gchar *last_location_bar = NULL;
2123 
2124   g_object_get (window->preferences, "last-location-bar", &last_location_bar, NULL);
2125 
2126   if (exo_str_is_equal (last_location_bar, g_type_name (G_TYPE_NONE)))
2127     {
2128       gtk_widget_hide (window->location_toolbar);
2129       gtk_widget_grab_focus (window->view);
2130     }
2131   else
2132     gtk_widget_show (window->location_toolbar);
2133 
2134   g_free (last_location_bar);
2135 }
2136 
2137 
2138 
2139 static void
thunar_window_update_window_icon(ThunarWindow * window)2140 thunar_window_update_window_icon (ThunarWindow *window)
2141 {
2142   gboolean      change_window_icon;
2143   GtkIconTheme *icon_theme;
2144   const gchar  *icon_name = "folder";
2145 
2146   g_object_get (window->preferences, "misc-change-window-icon", &change_window_icon, NULL);
2147 
2148   if (change_window_icon)
2149     {
2150       icon_theme = gtk_icon_theme_get_for_screen (gtk_window_get_screen (GTK_WINDOW (window)));
2151       icon_name = thunar_file_get_icon_name (window->current_directory,
2152                                              THUNAR_FILE_ICON_STATE_DEFAULT,
2153                                              icon_theme);
2154     }
2155 
2156   gtk_window_set_icon_name (GTK_WINDOW (window), icon_name);
2157 }
2158 
2159 
2160 
2161 static void
thunar_window_handle_reload_request(ThunarWindow * window)2162 thunar_window_handle_reload_request (ThunarWindow *window)
2163 {
2164   gboolean result;
2165 
2166   /* force the view to reload */
2167   g_signal_emit (G_OBJECT (window), window_signals[RELOAD], 0, TRUE, &result);
2168 }
2169 
2170 
2171 
2172 static void
thunar_window_install_sidepane(ThunarWindow * window,GType type)2173 thunar_window_install_sidepane (ThunarWindow *window,
2174                                 GType         type)
2175 {
2176   GtkStyleContext *context;
2177 
2178   _thunar_return_if_fail (type == G_TYPE_NONE || g_type_is_a (type, THUNAR_TYPE_SIDE_PANE));
2179   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
2180 
2181   /* drop the previous side pane (if any) */
2182   if (G_UNLIKELY (window->sidepane != NULL))
2183     {
2184       gtk_widget_destroy (window->sidepane);
2185       window->sidepane = NULL;
2186     }
2187 
2188   /* check if we have a new sidepane widget */
2189   if (G_LIKELY (type != G_TYPE_NONE))
2190     {
2191       /* allocate the new side pane widget */
2192       window->sidepane = g_object_new (type, NULL);
2193       gtk_widget_set_size_request (window->sidepane, 0, -1);
2194       exo_binding_new (G_OBJECT (window), "current-directory", G_OBJECT (window->sidepane), "current-directory");
2195       g_signal_connect_swapped (G_OBJECT (window->sidepane), "change-directory", G_CALLBACK (thunar_window_set_current_directory), window);
2196       g_signal_connect_swapped (G_OBJECT (window->sidepane), "open-new-tab", G_CALLBACK (thunar_window_notebook_open_new_tab), window);
2197       context = gtk_widget_get_style_context (window->sidepane);
2198       gtk_style_context_add_class (context, "sidebar");
2199       gtk_paned_pack1 (GTK_PANED (window->paned), window->sidepane, FALSE, FALSE);
2200       gtk_widget_show (window->sidepane);
2201 
2202       /* connect the side pane widget to the view (if any) */
2203       if (G_LIKELY (window->view != NULL))
2204         thunar_window_binding_create (window, window->view, "selected-files", window->sidepane, "selected-files", G_BINDING_SYNC_CREATE);
2205 
2206       /* apply show_hidden config to tree pane */
2207       if (type == THUNAR_TYPE_TREE_PANE)
2208         thunar_side_pane_set_show_hidden (THUNAR_SIDE_PANE (window->sidepane), window->show_hidden);
2209     }
2210 
2211   /* remember the setting */
2212   if (gtk_widget_get_visible (GTK_WIDGET (window)))
2213     g_object_set (G_OBJECT (window->preferences), "last-side-pane", g_type_name (type), NULL);
2214 }
2215 
2216 
2217 
2218 static gchar*
thunar_window_bookmark_get_accel_path(GFile * bookmark_file)2219 thunar_window_bookmark_get_accel_path (GFile *bookmark_file)
2220 {
2221   GChecksum    *checksum;
2222   gchar        *uri;
2223   gchar        *accel_path;
2224   const gchar  *unique_name;
2225 
2226   _thunar_return_val_if_fail (G_IS_FILE (bookmark_file), NULL);
2227 
2228   /* create unique id based on the uri */
2229   uri = g_file_get_uri (bookmark_file);
2230   checksum = g_checksum_new (G_CHECKSUM_MD5);
2231   g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
2232   unique_name = g_checksum_get_string (checksum);
2233   accel_path = g_strconcat("<Actions>/ThunarBookmarks/", unique_name, NULL);
2234 
2235   g_free (uri);
2236   g_checksum_free (checksum);
2237   return accel_path;
2238 }
2239 
2240 
2241 
2242 static void
thunar_window_menu_add_bookmarks(ThunarWindow * window,GtkMenuShell * view_menu)2243 thunar_window_menu_add_bookmarks (ThunarWindow *window,
2244                                   GtkMenuShell *view_menu)
2245 {
2246   GList          *lp;
2247   ThunarBookmark *bookmark;
2248   ThunarFile     *thunar_file;
2249   gchar          *parse_name;
2250   gchar          *accel_path;
2251   gchar          *tooltip;
2252   const gchar    *name;
2253   gchar          *remote_name;
2254   GtkIconTheme   *icon_theme;
2255   const gchar    *icon_name;
2256 
2257   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
2258 
2259   for (lp = window->bookmarks; lp != NULL; lp = lp->next)
2260     {
2261       bookmark = lp->data;
2262       accel_path = thunar_window_bookmark_get_accel_path (bookmark->g_file);
2263       parse_name = g_file_get_parse_name (bookmark->g_file);
2264       tooltip = g_strdup_printf (_("Open the location \"%s\""), parse_name);
2265       g_free (parse_name);
2266 
2267       if (g_file_has_uri_scheme (bookmark->g_file, "file"))
2268         {
2269           /* try to open the file corresponding to the uri */
2270           thunar_file = thunar_file_get (bookmark->g_file, NULL);
2271           if (G_LIKELY (thunar_file != NULL))
2272             {
2273               /* make sure the file refers to a directory */
2274               if (G_UNLIKELY (thunar_file_is_directory (thunar_file)))
2275                 {
2276                   name = bookmark->name;
2277                   if (bookmark->name == NULL)
2278                     name = thunar_file_get_display_name (thunar_file);
2279 
2280                   icon_theme = gtk_icon_theme_get_for_screen (gtk_window_get_screen (GTK_WINDOW (window)));
2281                   icon_name = thunar_file_get_icon_name (thunar_file, THUNAR_FILE_ICON_STATE_DEFAULT, icon_theme);
2282                   xfce_gtk_image_menu_item_new_from_icon_name (name, tooltip, accel_path, G_CALLBACK (thunar_window_action_open_bookmark), G_OBJECT (bookmark->g_file), icon_name, view_menu);
2283                }
2284             g_object_unref (thunar_file);
2285           }
2286         }
2287       else
2288         {
2289           if (bookmark->name == NULL)
2290             remote_name = thunar_g_file_get_display_name_remote (bookmark->g_file);
2291           else
2292             remote_name = g_strdup (bookmark->name);
2293           xfce_gtk_image_menu_item_new_from_icon_name (remote_name, tooltip, accel_path, G_CALLBACK (thunar_window_action_open_bookmark),  G_OBJECT (bookmark->g_file), "folder-remote", view_menu);
2294           g_free (remote_name);
2295         }
2296 
2297       g_free (tooltip);
2298       g_free (accel_path);
2299     }
2300 }
2301 
2302 
2303 
2304 static ThunarBookmark *
thunar_window_bookmark_add(ThunarWindow * window,GFile * g_file,const gchar * name)2305 thunar_window_bookmark_add (ThunarWindow *window,
2306                             GFile        *g_file,
2307                             const gchar  *name)
2308 {
2309   ThunarBookmark *bookmark;
2310 
2311   bookmark = g_slice_new0 (ThunarBookmark);
2312   bookmark->g_file = g_object_ref (g_file);
2313   bookmark->name = g_strdup (name);
2314 
2315   window->bookmarks = g_list_append (window->bookmarks, bookmark);
2316   return bookmark;
2317 }
2318 
2319 
2320 
2321 static void
thunar_window_free_bookmarks(ThunarWindow * window)2322 thunar_window_free_bookmarks (ThunarWindow *window)
2323 {
2324   GList          *lp;
2325   ThunarBookmark *bookmark;
2326 
2327   for (lp = window->bookmarks; lp != NULL; lp = lp->next)
2328     {
2329       bookmark = lp->data;
2330       g_object_unref (bookmark->g_file);
2331       g_free (bookmark->name);
2332       g_slice_free (ThunarBookmark, lp->data);
2333     }
2334   window->bookmarks = NULL;
2335 }
2336 
2337 
2338 
2339 static void
thunar_window_update_bookmark(GFile * g_file,const gchar * name,gint line_num,gpointer user_data)2340 thunar_window_update_bookmark (GFile       *g_file,
2341                                const gchar *name,
2342                                gint         line_num,
2343                                gpointer     user_data)
2344 {
2345   ThunarWindow      *window = THUNAR_WINDOW (user_data);
2346   gchar             *accel_path;
2347   XfceGtkActionEntry entry[1];
2348 
2349   _thunar_return_if_fail (G_IS_FILE (g_file));
2350   _thunar_return_if_fail (name == NULL || g_utf8_validate (name, -1, NULL));
2351   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
2352 
2353   /* Add the bookmark to our internal list of bookmarks */
2354   thunar_window_bookmark_add (window, g_file, name);
2355 
2356   /* Add ref to window to each g_file, will be needed in callback */
2357   g_object_set_data_full (G_OBJECT (g_file), I_("thunar-window"), window, NULL);
2358 
2359   /* Build a minimal XfceGtkActionEntry in order to be able to use the methods below */
2360   accel_path = thunar_window_bookmark_get_accel_path (g_file);
2361   entry[0].accel_path = accel_path;
2362   entry[0].callback = G_CALLBACK (thunar_window_action_open_bookmark);
2363   entry[0].default_accelerator = "";
2364 
2365   /* Add entry, so that the bookmark can loaded/saved to acceels.scm (will be skipped if already available)*/
2366   xfce_gtk_accel_map_add_entries (entry, G_N_ELEMENTS (entry));
2367 
2368   /* Link action with callback */
2369   xfce_gtk_accel_group_disconnect_action_entries (window->accel_group, entry, G_N_ELEMENTS (entry));
2370   xfce_gtk_accel_group_connect_action_entries (window->accel_group, entry, G_N_ELEMENTS (entry), g_file);
2371   g_free (accel_path);
2372 }
2373 
2374 
2375 
2376 static void
thunar_window_update_bookmarks(ThunarWindow * window)2377 thunar_window_update_bookmarks (ThunarWindow *window)
2378 {
2379   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
2380 
2381   thunar_window_free_bookmarks (window);
2382 
2383   /* re-create our internal bookmarks according to the bookmark file */
2384   thunar_util_load_bookmarks (window->bookmark_file,
2385                               thunar_window_update_bookmark,
2386                               window);
2387 }
2388 
2389 
2390 
2391 static void
thunar_window_open_or_launch(ThunarWindow * window,ThunarFile * file)2392 thunar_window_open_or_launch (ThunarWindow *window,
2393                               ThunarFile   *file)
2394 {
2395   GError *error = NULL;
2396 
2397   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
2398   _thunar_return_if_fail (THUNAR_IS_FILE (file));
2399 
2400   if (thunar_file_is_directory (file))
2401     {
2402       /* open the new directory */
2403       thunar_window_set_current_directory (window, file);
2404     }
2405   else
2406     {
2407       /* try to launch the selected file */
2408       if (!thunar_file_launch (file, window, NULL, &error))
2409         {
2410           thunar_dialogs_show_error (window, error, _("Failed to launch \"%s\""),
2411                                      thunar_file_get_display_name (file));
2412           g_error_free (error);
2413         }
2414     }
2415 }
2416 
2417 
2418 
2419 static void
thunar_window_poke_file_finish(ThunarBrowser * browser,ThunarFile * file,ThunarFile * target_file,GError * error,gpointer ignored)2420 thunar_window_poke_file_finish (ThunarBrowser *browser,
2421                                 ThunarFile    *file,
2422                                 ThunarFile    *target_file,
2423                                 GError        *error,
2424                                 gpointer       ignored)
2425 {
2426   _thunar_return_if_fail (THUNAR_IS_WINDOW (browser));
2427   _thunar_return_if_fail (THUNAR_IS_FILE (file));
2428 
2429   if (error == NULL)
2430     {
2431       thunar_window_open_or_launch (THUNAR_WINDOW (browser), target_file);
2432     }
2433   else
2434     {
2435       thunar_dialogs_show_error (GTK_WIDGET (browser), error,
2436                                  _("Failed to open \"%s\""),
2437                                  thunar_file_get_display_name (file));
2438     }
2439 }
2440 
2441 
2442 
2443 static void
thunar_window_start_open_location(ThunarWindow * window,const gchar * initial_text)2444 thunar_window_start_open_location (ThunarWindow *window,
2445                                    const gchar  *initial_text)
2446 {
2447   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
2448 
2449   /* temporary show the location toolbar, even if it is normally hidden */
2450   gtk_widget_show (window->location_toolbar);
2451   thunar_location_bar_request_entry (THUNAR_LOCATION_BAR (window->location_bar), initial_text);
2452 }
2453 
2454 
2455 
2456 static void
thunar_window_action_open_new_tab(ThunarWindow * window,GtkWidget * menu_item)2457 thunar_window_action_open_new_tab (ThunarWindow *window,
2458                                    GtkWidget    *menu_item)
2459 {
2460   /* open new tab with current directory as default */
2461   thunar_window_notebook_open_new_tab (window, thunar_window_get_current_directory (window));
2462 }
2463 
2464 
2465 
2466 static void
thunar_window_action_open_new_window(ThunarWindow * window,GtkWidget * menu_item)2467 thunar_window_action_open_new_window (ThunarWindow *window,
2468                                       GtkWidget    *menu_item)
2469 {
2470   ThunarApplication *application;
2471   ThunarHistory     *history;
2472   ThunarWindow      *new_window;
2473   ThunarFile        *start_file;
2474 
2475   /* popup a new window */
2476   application = thunar_application_get ();
2477   new_window = THUNAR_WINDOW (thunar_application_open_window (application, window->current_directory,
2478                                                               gtk_widget_get_screen (GTK_WIDGET (window)), NULL, TRUE));
2479   g_object_unref (G_OBJECT (application));
2480 
2481   /* if we have no origin view we are done */
2482   if (window->view == NULL)
2483     return;
2484 
2485   /* let the view of the new window inherit the history of the origin view */
2486   history = thunar_standard_view_copy_history (THUNAR_STANDARD_VIEW (window->view));
2487   if (history != NULL)
2488     {
2489       thunar_standard_view_set_history (THUNAR_STANDARD_VIEW (new_window->view), history);
2490       thunar_window_history_changed (new_window);
2491 
2492       /* connect to the new history */
2493       window->signal_handler_id_history_changed = g_signal_connect_swapped (G_OBJECT (history), "history-changed", G_CALLBACK (thunar_window_history_changed), new_window);
2494     }
2495 
2496   /* determine the first visible file in the current window */
2497   if (thunar_view_get_visible_range (THUNAR_VIEW (window->view), &start_file, NULL))
2498     {
2499       /* scroll the new window to the same file */
2500       thunar_window_scroll_to_file (new_window, start_file, FALSE, TRUE, 0.1f, 0.1f);
2501 
2502       /* release the file reference */
2503       g_object_unref (G_OBJECT (start_file));
2504     }
2505 }
2506 
2507 
2508 
2509 static void
thunar_window_action_detach_tab(ThunarWindow * window,GtkWidget * menu_item)2510 thunar_window_action_detach_tab (ThunarWindow *window,
2511                                  GtkWidget    *menu_item)
2512 {
2513   GtkWidget *notebook;
2514   GtkWidget *label;
2515   GtkWidget *view = window->view;
2516 
2517   _thunar_return_if_fail (THUNAR_IS_VIEW (view));
2518   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
2519 
2520   /* create a new window */
2521   notebook = thunar_window_notebook_create_window (window->notebook, view, -1, -1, window);
2522   if (notebook == NULL)
2523     return;
2524 
2525   /* get the current label */
2526   label = gtk_notebook_get_tab_label (GTK_NOTEBOOK (window->notebook), view);
2527   _thunar_return_if_fail (GTK_IS_WIDGET (label));
2528 
2529   /* ref object so they don't destroy when removed from the container */
2530   g_object_ref (label);
2531   g_object_ref (view);
2532 
2533   /* remove view from the current notebook */
2534   gtk_container_remove (GTK_CONTAINER (window->notebook), view);
2535 
2536   /* insert in the new notebook */
2537   gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), view, label, 0);
2538 
2539   /* set tab child properties */
2540   gtk_container_child_set (GTK_CONTAINER (notebook), view, "tab-expand", TRUE, NULL);
2541   gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (notebook), view, TRUE);
2542   gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (notebook), view, TRUE);
2543 
2544   /* release */
2545   g_object_unref (label);
2546   g_object_unref (view);
2547 }
2548 
2549 
2550 
2551 static void
thunar_window_action_close_all_windows(ThunarWindow * window,GtkWidget * menu_item)2552 thunar_window_action_close_all_windows (ThunarWindow *window,
2553                                         GtkWidget    *menu_item)
2554 {
2555   ThunarApplication *application;
2556   GList             *windows;
2557 
2558   /* query the list of currently open windows */
2559   application = thunar_application_get ();
2560   windows = thunar_application_get_windows (application);
2561   g_object_unref (G_OBJECT (application));
2562 
2563   /* destroy all open windows */
2564   g_list_free_full (windows, (GDestroyNotify) gtk_widget_destroy);
2565 }
2566 
2567 
2568 
2569 static void
thunar_window_action_close_tab(ThunarWindow * window,GtkWidget * menu_item)2570 thunar_window_action_close_tab (ThunarWindow *window,
2571                                 GtkWidget    *menu_item)
2572 {
2573   if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook)) == 1)
2574     gtk_widget_destroy (GTK_WIDGET (window));
2575   else if (window->view != NULL)
2576     gtk_widget_destroy (window->view);
2577 }
2578 
2579 
2580 
2581 static void
thunar_window_action_close_window(ThunarWindow * window,GtkWidget * menu_item)2582 thunar_window_action_close_window (ThunarWindow *window,
2583                                    GtkWidget    *menu_item)
2584 {
2585   gtk_widget_destroy (GTK_WIDGET (window));
2586 }
2587 
2588 
2589 
2590 static void
thunar_window_action_preferences(ThunarWindow * window,GtkWidget * menu_item)2591 thunar_window_action_preferences (ThunarWindow *window,
2592                                   GtkWidget    *menu_item)
2593 {
2594   GtkWidget         *dialog;
2595   ThunarApplication *application;
2596 
2597   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
2598 
2599   /* allocate and display a preferences dialog */;
2600   dialog = thunar_preferences_dialog_new (GTK_WINDOW (window));
2601   gtk_widget_show (dialog);
2602 
2603   /* ...and let the application take care of it */
2604   application = thunar_application_get ();
2605   thunar_application_take_window (application, GTK_WINDOW (dialog));
2606   g_object_unref (G_OBJECT (application));
2607 }
2608 
2609 
2610 
2611 static void
thunar_window_action_reload(ThunarWindow * window,GtkWidget * menu_item)2612 thunar_window_action_reload (ThunarWindow *window,
2613                              GtkWidget    *menu_item)
2614 {
2615   gboolean result;
2616 
2617   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
2618 
2619   /* force the view to reload */
2620   g_signal_emit (G_OBJECT (window), window_signals[RELOAD], 0, TRUE, &result);
2621 
2622   /* update the location bar to show the current directory */
2623   if (window->location_bar != NULL)
2624     g_object_notify (G_OBJECT (window->location_bar), "current-directory");
2625 }
2626 
2627 
2628 
2629 static void
thunar_window_action_pathbar_changed(ThunarWindow * window)2630 thunar_window_action_pathbar_changed (ThunarWindow *window)
2631 {
2632   gchar    *last_location_bar;
2633   gboolean  pathbar_checked;
2634 
2635   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
2636 
2637   g_object_get (window->preferences, "last-location-bar", &last_location_bar, NULL);
2638   pathbar_checked = exo_str_is_equal (last_location_bar, g_type_name (THUNAR_TYPE_LOCATION_ENTRY));
2639   g_free (last_location_bar);
2640 
2641   if (pathbar_checked)
2642     g_object_set (window->preferences, "last-location-bar", g_type_name (G_TYPE_NONE), NULL);
2643   else
2644     g_object_set (window->preferences, "last-location-bar", g_type_name (THUNAR_TYPE_LOCATION_ENTRY), NULL);
2645 }
2646 
2647 
2648 
2649 static void
thunar_window_action_toolbar_changed(ThunarWindow * window)2650 thunar_window_action_toolbar_changed (ThunarWindow *window)
2651 {
2652   gchar    *last_location_bar;
2653   gboolean  toolbar_checked;
2654 
2655   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
2656 
2657   g_object_get (window->preferences, "last-location-bar", &last_location_bar, NULL);
2658   toolbar_checked = exo_str_is_equal (last_location_bar, g_type_name (THUNAR_TYPE_LOCATION_BUTTONS));
2659   g_free (last_location_bar);
2660 
2661   if (toolbar_checked)
2662     g_object_set (window->preferences, "last-location-bar", g_type_name (G_TYPE_NONE), NULL);
2663   else
2664     g_object_set (window->preferences, "last-location-bar", g_type_name (THUNAR_TYPE_LOCATION_BUTTONS), NULL);
2665 }
2666 
2667 
2668 
2669 static void
thunar_window_action_shortcuts_changed(ThunarWindow * window)2670 thunar_window_action_shortcuts_changed (ThunarWindow *window)
2671 {
2672   gchar    *last_side_pane;
2673   gboolean  shortcuts_checked;
2674   GType     type = G_TYPE_NONE;
2675 
2676   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
2677 
2678   g_object_get (window->preferences, "last-side-pane", &last_side_pane, NULL);
2679   shortcuts_checked = exo_str_is_equal (last_side_pane, g_type_name (THUNAR_TYPE_SHORTCUTS_PANE));
2680   g_free (last_side_pane);
2681 
2682   if (shortcuts_checked)
2683     type = G_TYPE_NONE;
2684   else
2685     type = THUNAR_TYPE_SHORTCUTS_PANE;
2686 
2687   thunar_window_install_sidepane (window, type);
2688 }
2689 
2690 
2691 
2692 static void
thunar_window_action_tree_changed(ThunarWindow * window)2693 thunar_window_action_tree_changed (ThunarWindow *window)
2694 {
2695   gchar    *last_side_pane;
2696   gboolean  tree_view_checked;
2697   GType     type = G_TYPE_NONE;
2698 
2699   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
2700 
2701   g_object_get (window->preferences, "last-side-pane", &last_side_pane, NULL);
2702   tree_view_checked = exo_str_is_equal (last_side_pane, g_type_name (THUNAR_TYPE_TREE_PANE));
2703   g_free (last_side_pane);
2704 
2705   if (tree_view_checked)
2706     type = G_TYPE_NONE;
2707   else
2708     type = THUNAR_TYPE_TREE_PANE;
2709 
2710   thunar_window_install_sidepane (window, type);
2711 }
2712 
2713 
2714 
2715 static void
thunar_window_action_statusbar_changed(ThunarWindow * window)2716 thunar_window_action_statusbar_changed (ThunarWindow *window)
2717 {
2718   gboolean last_statusbar_visible;
2719 
2720   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
2721 
2722   g_object_get (window->preferences, "last-statusbar-visible", &last_statusbar_visible, NULL);
2723 
2724   gtk_widget_set_visible (window->statusbar, !last_statusbar_visible);
2725 
2726   g_object_set (G_OBJECT (window->preferences), "last-statusbar-visible", !last_statusbar_visible, NULL);
2727 }
2728 
2729 
2730 
2731 static void
thunar_window_action_menubar_update(ThunarWindow * window)2732 thunar_window_action_menubar_update (ThunarWindow *window)
2733 {
2734   gboolean last_menubar_visible;
2735 
2736   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
2737 
2738   g_object_get (window->preferences, "last-menubar-visible", &last_menubar_visible, NULL);
2739 
2740   gtk_widget_set_visible (window->menubar, last_menubar_visible);
2741 }
2742 
2743 
2744 
2745 static void
thunar_window_action_menubar_changed(ThunarWindow * window)2746 thunar_window_action_menubar_changed (ThunarWindow *window)
2747 {
2748   gboolean last_menubar_visible;
2749 
2750   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
2751 
2752   g_object_get (window->preferences, "last-menubar-visible", &last_menubar_visible, NULL);
2753 
2754   gtk_widget_set_visible (window->menubar, !last_menubar_visible);
2755 
2756   g_object_set (G_OBJECT (window->preferences), "last-menubar-visible", !last_menubar_visible, NULL);
2757 }
2758 
2759 
2760 
2761 static void
thunar_window_action_clear_directory_specific_settings(ThunarWindow * window)2762 thunar_window_action_clear_directory_specific_settings (ThunarWindow *window)
2763 {
2764   GType       view_type;
2765   gboolean    result;
2766 
2767   /* clear the settings */
2768   thunar_file_clear_directory_specific_settings (window->current_directory);
2769 
2770   /* get the correct view type for the current directory */
2771   view_type = thunar_window_view_type_for_directory (window, window->current_directory);
2772 
2773   /* force the view to reload so that any changes to the settings are applied */
2774   g_signal_emit (G_OBJECT (window), window_signals[RELOAD], 0, TRUE, &result);
2775 
2776   /* replace the active view with a new one of the correct type */
2777   thunar_window_replace_view (window, window->view, view_type);
2778 }
2779 
2780 
2781 
2782 static void
thunar_window_action_detailed_view(ThunarWindow * window)2783 thunar_window_action_detailed_view (ThunarWindow *window)
2784 {
2785   thunar_window_action_view_changed (window, THUNAR_TYPE_DETAILS_VIEW);
2786 }
2787 
2788 
2789 
2790 static void
thunar_window_action_icon_view(ThunarWindow * window)2791 thunar_window_action_icon_view (ThunarWindow *window)
2792 {
2793   thunar_window_action_view_changed (window, THUNAR_TYPE_ICON_VIEW);
2794 }
2795 
2796 
2797 
2798 static void
thunar_window_action_compact_view(ThunarWindow * window)2799 thunar_window_action_compact_view (ThunarWindow *window)
2800 {
2801   thunar_window_action_view_changed (window, THUNAR_TYPE_COMPACT_VIEW);
2802 }
2803 
2804 
2805 
2806 static void
thunar_window_replace_view(ThunarWindow * window,GtkWidget * view,GType view_type)2807 thunar_window_replace_view (ThunarWindow *window,
2808                             GtkWidget    *view,
2809                             GType         view_type)
2810 {
2811   ThunarFile     *file = NULL;
2812   ThunarFile     *current_directory = NULL;
2813   GtkWidget      *new_view;
2814   ThunarHistory  *history = NULL;
2815   GList          *selected_files = NULL;
2816   gint            page_num;
2817   gboolean        is_current_view;
2818 
2819   _thunar_return_if_fail (view_type != G_TYPE_NONE);
2820 
2821   /* if the view already has the correct type then just return */
2822   if (view != NULL && G_TYPE_FROM_INSTANCE (view) == view_type)
2823     return;
2824 
2825   /* is the view we are replacing the active view?
2826    * (note that this will be true if both view and window->view are NULL) */
2827   is_current_view = (view == window->view);
2828 
2829   /* save some settings from the old view for the new view */
2830   if (view != NULL)
2831     {
2832       /* disconnect from previous history if the old view is the active view */
2833       if (is_current_view && window->signal_handler_id_history_changed != 0)
2834         {
2835           history = thunar_standard_view_get_history (THUNAR_STANDARD_VIEW (view));
2836           g_signal_handler_disconnect (history, window->signal_handler_id_history_changed);
2837           window->signal_handler_id_history_changed = 0;
2838         }
2839 
2840       /* get first visible file in the old view */
2841       if (!thunar_view_get_visible_range (THUNAR_VIEW (view), &file, NULL))
2842         file = NULL;
2843 
2844       /* store the active directory from the old view */
2845       current_directory = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (view));
2846       if (current_directory != NULL)
2847         g_object_ref (current_directory);
2848 
2849       /* remember the file selection from the old view */
2850       selected_files = thunar_g_file_list_copy (thunar_component_get_selected_files (THUNAR_COMPONENT (view)));
2851 
2852       /* save the history of the current view */
2853       history = NULL;
2854       if (THUNAR_IS_STANDARD_VIEW (view))
2855         history = thunar_standard_view_copy_history (THUNAR_STANDARD_VIEW (view));
2856     }
2857 
2858   if (is_current_view)
2859     window->view_type = view_type;
2860 
2861   /* if we have not got a current directory from the old view, use the window's current directory */
2862   if (current_directory == NULL && window->current_directory != NULL)
2863     current_directory = g_object_ref (window->current_directory);
2864 
2865   _thunar_assert (current_directory != NULL);
2866 
2867   /* find where to insert the new view */
2868   if (view != NULL)
2869     page_num = gtk_notebook_page_num (GTK_NOTEBOOK (window->notebook), view);
2870   else
2871     page_num = -1;
2872 
2873   /* insert the new view */
2874   new_view = thunar_window_notebook_insert (window, current_directory, view_type, page_num + 1, history);
2875 
2876   /* if we are replacing the active view, make the new view the active view */
2877   if (is_current_view)
2878     {
2879       /* switch to the new view */
2880       page_num = gtk_notebook_page_num (GTK_NOTEBOOK (window->notebook), new_view);
2881       gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), page_num);
2882 
2883       /* take focus on the new view */
2884       gtk_widget_grab_focus (new_view);
2885     }
2886 
2887   /* scroll to the previously visible file in the old view */
2888   if (G_UNLIKELY (file != NULL))
2889     thunar_view_scroll_to_file (THUNAR_VIEW (new_view), file, FALSE, TRUE, 0.0f, 0.0f);
2890 
2891   /* destroy the old view */
2892   if (view != NULL)
2893     gtk_widget_destroy (view);
2894 
2895   /* restore the file selection */
2896   thunar_component_set_selected_files (THUNAR_COMPONENT (new_view), selected_files);
2897   thunar_g_file_list_free (selected_files);
2898 
2899   /* remember the last view type if this is the active view and directory specific settings are not enabled */
2900   if (is_current_view && !window->directory_specific_settings && gtk_widget_get_visible (GTK_WIDGET (window)) && view_type != G_TYPE_NONE)
2901     g_object_set (G_OBJECT (window->preferences), "last-view", g_type_name (view_type), NULL);
2902 
2903   /* release the file references */
2904   if (G_UNLIKELY (file != NULL))
2905     g_object_unref (G_OBJECT (file));
2906   if (G_UNLIKELY (current_directory != NULL))
2907     g_object_unref (G_OBJECT (current_directory));
2908 
2909   /* connect to the new history if this is the active view */
2910   if (is_current_view)
2911     {
2912       history = thunar_standard_view_get_history (THUNAR_STANDARD_VIEW (new_view));
2913       window->signal_handler_id_history_changed = g_signal_connect_swapped (G_OBJECT (history),
2914                                                                             "history-changed",
2915                                                                             G_CALLBACK (thunar_window_history_changed),
2916                                                                             window);
2917     }
2918 }
2919 
2920 
2921 
2922 static void
thunar_window_action_view_changed(ThunarWindow * window,GType view_type)2923 thunar_window_action_view_changed (ThunarWindow *window,
2924                                    GType         view_type)
2925 {
2926   thunar_window_replace_view (window, window->view, view_type);
2927 
2928   /* if directory specific settings are enabled, save the view type for this directory */
2929   if (window->directory_specific_settings)
2930     thunar_file_set_metadata_setting (window->current_directory, "view-type", g_type_name (view_type));
2931 }
2932 
2933 
2934 
2935 static void
thunar_window_action_go_up(ThunarWindow * window)2936 thunar_window_action_go_up (ThunarWindow *window)
2937 {
2938   ThunarFile *parent;
2939   GError     *error = NULL;
2940 
2941   parent = thunar_file_get_parent (window->current_directory, &error);
2942   if (G_LIKELY (parent != NULL))
2943     {
2944       thunar_window_set_current_directory (window, parent);
2945       g_object_unref (G_OBJECT (parent));
2946     }
2947   else
2948     {
2949       /* the root folder '/' has no parent. In this special case we do not need a dialog */
2950       if (error->code != G_FILE_ERROR_NOENT)
2951         {
2952           thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to open parent folder"));
2953         }
2954       g_error_free (error);
2955     }
2956 }
2957 
2958 
2959 
2960 static void
thunar_window_action_back(ThunarWindow * window)2961 thunar_window_action_back (ThunarWindow *window)
2962 {
2963   ThunarHistory *history;
2964 
2965   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
2966 
2967   history = thunar_standard_view_get_history (THUNAR_STANDARD_VIEW (window->view));
2968   thunar_history_action_back (history);
2969 }
2970 
2971 
2972 
2973 static void
thunar_window_action_forward(ThunarWindow * window)2974 thunar_window_action_forward (ThunarWindow *window)
2975 {
2976   ThunarHistory *history;
2977 
2978   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
2979 
2980   history = thunar_standard_view_get_history (THUNAR_STANDARD_VIEW (window->view));
2981   thunar_history_action_forward (history);
2982 }
2983 
2984 
2985 
2986 static void
thunar_window_action_open_home(ThunarWindow * window)2987 thunar_window_action_open_home (ThunarWindow *window)
2988 {
2989   GFile         *home;
2990   ThunarFile    *home_file;
2991   GError        *error = NULL;
2992 
2993   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
2994 
2995   /* determine the path to the home directory */
2996   home = thunar_g_file_new_for_home ();
2997 
2998   /* determine the file for the home directory */
2999   home_file = thunar_file_get (home, &error);
3000   if (G_UNLIKELY (home_file == NULL))
3001     {
3002       /* display an error to the user */
3003       thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to open the home folder"));
3004       g_error_free (error);
3005     }
3006   else
3007     {
3008       /* open the home folder */
3009       thunar_window_set_current_directory (window, home_file);
3010       g_object_unref (G_OBJECT (home_file));
3011     }
3012 
3013   /* release our reference on the home path */
3014   g_object_unref (home);
3015 }
3016 
3017 
3018 
3019 static gboolean
thunar_window_open_user_folder(ThunarWindow * window,GUserDirectory thunar_user_dir,const gchar * default_name)3020 thunar_window_open_user_folder (ThunarWindow   *window,
3021                                 GUserDirectory  thunar_user_dir,
3022                                 const gchar    *default_name)
3023 {
3024   ThunarFile  *user_file = NULL;
3025   gboolean     result = FALSE;
3026   GError      *error = NULL;
3027   GFile       *home_dir;
3028   GFile       *user_dir;
3029   const gchar *path;
3030   gint         response;
3031   GtkWidget   *dialog;
3032   gchar       *parse_name;
3033 
3034   path = g_get_user_special_dir (thunar_user_dir);
3035   home_dir = thunar_g_file_new_for_home ();
3036 
3037   /* check if there is an entry in user-dirs.dirs */
3038   path = g_get_user_special_dir (thunar_user_dir);
3039   if (G_LIKELY (path != NULL))
3040     {
3041       user_dir = g_file_new_for_path (path);
3042 
3043       /* if equal to home, leave */
3044       if (g_file_equal (user_dir, home_dir))
3045         goto is_homedir;
3046     }
3047   else
3048     {
3049       /* build a name */
3050       user_dir = g_file_resolve_relative_path (home_dir, default_name);
3051     }
3052 
3053   /* try to load the user dir */
3054   user_file = thunar_file_get (user_dir, NULL);
3055 
3056   /* check if the directory exists */
3057   if (G_UNLIKELY (user_file == NULL || !thunar_file_exists (user_file)))
3058     {
3059       /* release the instance if it does not exist */
3060       if (user_file != NULL)
3061         {
3062           g_object_unref (user_file);
3063           user_file = NULL;
3064         }
3065 
3066       /* ask the user to create the directory */
3067       parse_name = g_file_get_parse_name (user_dir);
3068       dialog = gtk_message_dialog_new (GTK_WINDOW (window),
3069                                        GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
3070                                        GTK_MESSAGE_QUESTION,
3071                                        GTK_BUTTONS_YES_NO,
3072                                        _("The directory \"%s\" does not exist. Do you want to create it?"),
3073                                        parse_name);
3074       gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES);
3075       response = gtk_dialog_run (GTK_DIALOG (dialog));
3076       gtk_widget_destroy (dialog);
3077       g_free (parse_name);
3078 
3079       if (response == GTK_RESPONSE_YES
3080           && g_file_make_directory_with_parents (user_dir, NULL, &error))
3081         {
3082           /* try again */
3083           user_file = thunar_file_get (user_dir, &error);
3084         }
3085     }
3086 
3087   if (G_LIKELY (user_file != NULL))
3088     {
3089       /* open the folder */
3090       thunar_window_set_current_directory (window, user_file);
3091       g_object_unref (G_OBJECT (user_file));
3092       result = TRUE;
3093     }
3094   else if (error != NULL)
3095     {
3096       parse_name = g_file_get_parse_name (user_dir);
3097       thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to open directory \"%s\""), parse_name);
3098       g_free (parse_name);
3099       g_error_free (error);
3100     }
3101 
3102   is_homedir:
3103 
3104   g_object_unref (user_dir);
3105   g_object_unref (home_dir);
3106 
3107   return result;
3108 }
3109 
3110 
3111 
3112 static void
thunar_window_action_open_desktop(ThunarWindow * window)3113 thunar_window_action_open_desktop (ThunarWindow *window)
3114 {
3115   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
3116 
3117   thunar_window_open_user_folder (window, G_USER_DIRECTORY_DESKTOP, "Desktop");
3118 }
3119 
3120 
3121 
3122 static void
thunar_window_action_open_computer(ThunarWindow * window)3123 thunar_window_action_open_computer (ThunarWindow *window)
3124 {
3125   GFile         *computer;
3126   ThunarFile    *computer_file;
3127   GError        *error = NULL;
3128 
3129   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
3130 
3131   /* determine the computer location */
3132   computer = g_file_new_for_uri ("computer://");
3133 
3134   /* determine the file for this location */
3135   computer_file = thunar_file_get (computer, &error);
3136   if (G_UNLIKELY (computer_file == NULL))
3137     {
3138       /* display an error to the user */
3139       thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to browse the computer"));
3140       g_error_free (error);
3141     }
3142   else
3143     {
3144       /* open the computer location */
3145       thunar_window_set_current_directory (window, computer_file);
3146       g_object_unref (G_OBJECT (computer_file));
3147     }
3148 
3149   /* release our reference on the location itself */
3150   g_object_unref (computer);
3151 }
3152 
3153 
3154 
3155 static void
thunar_window_action_open_templates(ThunarWindow * window)3156 thunar_window_action_open_templates (ThunarWindow *window)
3157 {
3158   GtkWidget     *dialog;
3159   GtkWidget     *button;
3160   GtkWidget     *label;
3161   GtkWidget     *image;
3162   GtkWidget     *hbox;
3163   GtkWidget     *vbox;
3164   gboolean       show_about_templates;
3165   gboolean       success;
3166 
3167   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
3168 
3169   success = thunar_window_open_user_folder (window, G_USER_DIRECTORY_TEMPLATES, "Templates");
3170 
3171   /* check whether we should display the "About Templates" dialog */
3172   g_object_get (G_OBJECT (window->preferences),
3173                 "misc-show-about-templates", &show_about_templates,
3174                 NULL);
3175 
3176   if (G_UNLIKELY(show_about_templates && success))
3177     {
3178       /* display the "About Templates" dialog */
3179       dialog = gtk_dialog_new_with_buttons (_("About Templates"), GTK_WINDOW (window),
3180                                             GTK_DIALOG_DESTROY_WITH_PARENT,
3181                                             _("_OK"), GTK_RESPONSE_OK,
3182                                             NULL);
3183 
3184       gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
3185 
3186       hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
3187       gtk_container_set_border_width (GTK_CONTAINER (hbox), 8);
3188       gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), hbox, TRUE, TRUE, 0);
3189       gtk_widget_show (hbox);
3190 
3191       image = gtk_image_new_from_icon_name ("dialog-information", GTK_ICON_SIZE_DIALOG);
3192       gtk_widget_set_halign (image, GTK_ALIGN_CENTER);
3193       gtk_widget_set_valign (image, GTK_ALIGN_START);
3194       gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
3195       gtk_widget_show (image);
3196 
3197       vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 18);
3198       gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
3199       gtk_widget_show (vbox);
3200 
3201       label = gtk_label_new (_("All files in this folder will appear in the \"Create Document\" menu."));
3202       gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
3203       gtk_label_set_attributes (GTK_LABEL (label), thunar_pango_attr_list_big_bold ());
3204       gtk_label_set_line_wrap (GTK_LABEL (label), FALSE);
3205       gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
3206       gtk_widget_show (label);
3207 
3208       label = gtk_label_new (_("If you frequently create certain kinds "
3209                              " of documents, make a copy of one and put it in this "
3210                              "folder. Thunar will add an entry for this document in the"
3211                              " \"Create Document\" menu.\n\n"
3212                              "You can then select the entry from the \"Create Document\" "
3213                              "menu and a copy of the document will be created in the "
3214                              "directory you are viewing."));
3215       gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
3216       gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
3217       gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
3218       gtk_widget_show (label);
3219 
3220       button = gtk_check_button_new_with_mnemonic (_("Do _not display this message again"));
3221       exo_mutual_binding_new_with_negation (G_OBJECT (window->preferences), "misc-show-about-templates", G_OBJECT (button), "active");
3222       gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
3223       gtk_widget_show (button);
3224 
3225       gtk_window_set_default_size (GTK_WINDOW (dialog), 600, -1);
3226 
3227       gtk_dialog_run (GTK_DIALOG (dialog));
3228       gtk_widget_destroy (dialog);
3229     }
3230 }
3231 
3232 
3233 
3234 static void
thunar_window_action_open_file_system(ThunarWindow * window)3235 thunar_window_action_open_file_system (ThunarWindow *window)
3236 {
3237   GFile         *root;
3238   ThunarFile    *root_file;
3239   GError        *error = NULL;
3240 
3241   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
3242 
3243   /* determine the path to the root directory */
3244   root = thunar_g_file_new_for_root ();
3245 
3246   /* determine the file for the root directory */
3247   root_file = thunar_file_get (root, &error);
3248   if (G_UNLIKELY (root_file == NULL))
3249     {
3250       /* display an error to the user */
3251       thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to open the file system root folder"));
3252       g_error_free (error);
3253     }
3254   else
3255     {
3256       /* open the root folder */
3257       thunar_window_set_current_directory (window, root_file);
3258       g_object_unref (G_OBJECT (root_file));
3259     }
3260 
3261   /* release our reference on the home path */
3262   g_object_unref (root);
3263 }
3264 
3265 
3266 
3267 static void
thunar_window_action_open_trash(ThunarWindow * window)3268 thunar_window_action_open_trash (ThunarWindow *window)
3269 {
3270   GFile      *trash_bin;
3271   ThunarFile *trash_bin_file;
3272   GError     *error = NULL;
3273 
3274   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
3275 
3276   /* determine the path to the trash bin */
3277   trash_bin = thunar_g_file_new_for_trash ();
3278 
3279   /* determine the file for the trash bin */
3280   trash_bin_file = thunar_file_get (trash_bin, &error);
3281   if (G_UNLIKELY (trash_bin_file == NULL))
3282     {
3283       /* display an error to the user */
3284       thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to display the contents of the trash can"));
3285       g_error_free (error);
3286     }
3287   else
3288     {
3289       /* open the trash folder */
3290       thunar_window_set_current_directory (window, trash_bin_file);
3291       g_object_unref (G_OBJECT (trash_bin_file));
3292     }
3293 
3294   /* release our reference on the trash bin path */
3295   g_object_unref (trash_bin);
3296 }
3297 
3298 
3299 
3300 static void
thunar_window_action_open_network(ThunarWindow * window)3301 thunar_window_action_open_network (ThunarWindow *window)
3302 {
3303   ThunarFile *network_file;
3304   GError     *error = NULL;
3305   GFile      *network;
3306 
3307   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
3308 
3309   /* determine the network root location */
3310   network = g_file_new_for_uri ("network://");
3311 
3312   /* determine the file for this location */
3313   network_file = thunar_file_get (network, &error);
3314   if (G_UNLIKELY (network_file == NULL))
3315     {
3316       /* display an error to the user */
3317       thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to browse the network"));
3318       g_error_free (error);
3319     }
3320   else
3321     {
3322       /* open the network root location */
3323       thunar_window_set_current_directory (window, network_file);
3324       g_object_unref (G_OBJECT (network_file));
3325     }
3326 
3327   /* release our reference on the location itself */
3328   g_object_unref (network);
3329 }
3330 
3331 
3332 
3333 static gboolean
thunar_window_check_uca_key_activation(ThunarWindow * window,GdkEventKey * key_event,gpointer user_data)3334 thunar_window_check_uca_key_activation (ThunarWindow *window,
3335                                         GdkEventKey  *key_event,
3336                                         gpointer      user_data)
3337 {
3338   if (thunar_launcher_check_uca_key_activation (window->launcher, key_event))
3339     return GDK_EVENT_STOP;
3340   return GDK_EVENT_PROPAGATE;
3341 }
3342 
3343 
3344 
3345 static gboolean
thunar_window_propagate_key_event(GtkWindow * window,GdkEvent * key_event,gpointer user_data)3346 thunar_window_propagate_key_event (GtkWindow* window,
3347                                    GdkEvent  *key_event,
3348                                    gpointer   user_data)
3349 {
3350   GtkWidget* focused_widget;
3351 
3352   _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), GDK_EVENT_PROPAGATE);
3353 
3354   focused_widget = gtk_window_get_focus (window);
3355 
3356   /* Turn the accelerator priority around globally,
3357    * so that the focused widget always gets the accels first.
3358    * Implementing this cleanly while maintaining some wanted accels
3359    * (like Ctrl+N and exo accels) is a lot of work. So we resort to
3360    * only priorize GtkEditable, because that is the easiest way to
3361    * fix the right-ahead problem. */
3362   if (focused_widget != NULL && GTK_IS_EDITABLE (focused_widget))
3363     return gtk_window_propagate_key_event (window, (GdkEventKey *) key_event);
3364 
3365   return GDK_EVENT_PROPAGATE;
3366 }
3367 
3368 
3369 
3370 static void
thunar_window_poke_location_finish(ThunarBrowser * browser,GFile * location,ThunarFile * file,ThunarFile * target_file,GError * error,gpointer ignored)3371 thunar_window_poke_location_finish (ThunarBrowser *browser,
3372                                     GFile         *location,
3373                                     ThunarFile    *file,
3374                                     ThunarFile    *target_file,
3375                                     GError        *error,
3376                                     gpointer       ignored)
3377 {
3378   _thunar_return_if_fail (THUNAR_IS_WINDOW (browser));
3379   _thunar_return_if_fail (THUNAR_IS_FILE (file));
3380 
3381   thunar_window_poke_file_finish (browser, file, target_file, error, ignored);
3382 }
3383 
3384 
3385 
3386 static void
thunar_window_action_open_bookmark(GFile * g_file)3387 thunar_window_action_open_bookmark (GFile *g_file)
3388 {
3389   GtkWindow *window;
3390 
3391   window = g_object_get_data (G_OBJECT (g_file), I_("thunar-window"));
3392 
3393   thunar_window_set_current_directory_gfile (THUNAR_WINDOW (window), g_file);
3394 }
3395 
3396 
3397 
3398 static void
thunar_window_action_open_location(ThunarWindow * window)3399 thunar_window_action_open_location (ThunarWindow *window)
3400 {
3401   /* just use the "start-open-location" callback */
3402   thunar_window_start_open_location (window, NULL);
3403 }
3404 
3405 
3406 
3407 static void
thunar_window_action_contents(ThunarWindow * window)3408 thunar_window_action_contents (ThunarWindow *window)
3409 {
3410   /* display the documentation index */
3411   xfce_dialog_show_help (GTK_WINDOW (window), "thunar", NULL, NULL);
3412 }
3413 
3414 
3415 
3416 static void
thunar_window_action_about(ThunarWindow * window)3417 thunar_window_action_about (ThunarWindow *window)
3418 {
3419   /* just popup the about dialog */
3420   thunar_dialogs_show_about (GTK_WINDOW (window), PACKAGE_NAME,
3421                              _("Thunar is a fast and easy to use file manager\n"
3422                                "for the Xfce Desktop Environment."));
3423 }
3424 
3425 
3426 
3427 static void
thunar_window_action_show_hidden(ThunarWindow * window)3428 thunar_window_action_show_hidden (ThunarWindow *window)
3429 {
3430   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
3431 
3432   window->show_hidden = !window->show_hidden;
3433   gtk_container_foreach (GTK_CONTAINER (window->notebook), (GtkCallback) (void (*)(void)) thunar_view_set_show_hidden, GINT_TO_POINTER (window->show_hidden));
3434 
3435   if (G_LIKELY (window->sidepane != NULL))
3436     thunar_side_pane_set_show_hidden (THUNAR_SIDE_PANE (window->sidepane), window->show_hidden);
3437 
3438   g_object_set (G_OBJECT (window->preferences), "last-show-hidden", window->show_hidden, NULL);
3439 }
3440 
3441 
3442 
3443 static void
thunar_window_action_open_file_menu(ThunarWindow * window)3444 thunar_window_action_open_file_menu (ThunarWindow *window)
3445 {
3446   gboolean  ret;
3447   GList    *children;
3448 
3449   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
3450 
3451   /* In case the menubar is hidden, we make it visible (e.g. when F10 is pressed) */
3452   gtk_widget_set_visible (window->menubar, TRUE);
3453 
3454   children = gtk_container_get_children (GTK_CONTAINER (window->menubar));
3455   g_signal_emit_by_name (children->data, "button-press-event", NULL, &ret);
3456   g_list_free (children);
3457   gtk_menu_shell_select_first (GTK_MENU_SHELL (window->menubar), TRUE);
3458 }
3459 
3460 
3461 
3462 static void
thunar_window_current_directory_changed(ThunarFile * current_directory,ThunarWindow * window)3463 thunar_window_current_directory_changed (ThunarFile   *current_directory,
3464                                          ThunarWindow *window)
3465 {
3466   gboolean      show_full_path;
3467   gchar        *parse_name = NULL;
3468   const gchar  *name;
3469 
3470   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
3471   _thunar_return_if_fail (THUNAR_IS_FILE (current_directory));
3472   _thunar_return_if_fail (window->current_directory == current_directory);
3473 
3474   /* get name of directory or full path */
3475   g_object_get (G_OBJECT (window->preferences), "misc-full-path-in-title", &show_full_path, NULL);
3476   if (G_UNLIKELY (show_full_path))
3477     name = parse_name = g_file_get_parse_name (thunar_file_get_file (current_directory));
3478   else
3479     name = thunar_file_get_display_name (current_directory);
3480 
3481   /* set window title */
3482   gtk_window_set_title (GTK_WINDOW (window), name);
3483   g_free (parse_name);
3484 
3485   /* set window icon */
3486   thunar_window_update_window_icon (window);
3487 }
3488 
3489 
3490 
3491 static void
thunar_window_menu_item_selected(ThunarWindow * window,GtkWidget * menu_item)3492 thunar_window_menu_item_selected (ThunarWindow *window,
3493                                   GtkWidget    *menu_item)
3494 {
3495   gchar *tooltip;
3496   gint   id;
3497 
3498   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
3499 
3500   /* we can only display tooltips if we have a statusbar */
3501   if (G_LIKELY (window->statusbar != NULL))
3502     {
3503       tooltip = gtk_widget_get_tooltip_text (menu_item);
3504       if (G_LIKELY (tooltip != NULL))
3505         {
3506           /* push to the statusbar */
3507           id = gtk_statusbar_get_context_id (GTK_STATUSBAR (window->statusbar), "Menu tooltip");
3508           gtk_statusbar_push (GTK_STATUSBAR (window->statusbar), id, tooltip);
3509           g_free (tooltip);
3510         }
3511     }
3512 }
3513 
3514 
3515 
3516 static void
thunar_window_menu_item_deselected(ThunarWindow * window,GtkWidget * menu_item)3517 thunar_window_menu_item_deselected (ThunarWindow *window,
3518                                     GtkWidget    *menu_item)
3519 {
3520   gint id;
3521 
3522   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
3523 
3524   /* we can only undisplay tooltips if we have a statusbar */
3525   if (G_LIKELY (window->statusbar != NULL))
3526     {
3527       /* drop the last tooltip from the statusbar */
3528       id = gtk_statusbar_get_context_id (GTK_STATUSBAR (window->statusbar), "Menu tooltip");
3529       gtk_statusbar_pop (GTK_STATUSBAR (window->statusbar), id);
3530     }
3531 }
3532 
3533 
3534 
3535 static void
thunar_window_notify_loading(ThunarView * view,GParamSpec * pspec,ThunarWindow * window)3536 thunar_window_notify_loading (ThunarView   *view,
3537                               GParamSpec   *pspec,
3538                               ThunarWindow *window)
3539 {
3540   GdkCursor *cursor;
3541 
3542   _thunar_return_if_fail (THUNAR_IS_VIEW (view));
3543   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
3544 
3545   if (gtk_widget_get_realized (GTK_WIDGET (window))
3546       && window->view == GTK_WIDGET (view))
3547     {
3548       /* setup the proper cursor */
3549       if (thunar_view_get_loading (view))
3550         {
3551           cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (view)), GDK_WATCH);
3552           gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), cursor);
3553           g_object_unref (cursor);
3554         }
3555       else
3556         {
3557           gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), NULL);
3558         }
3559     }
3560 }
3561 
3562 
3563 
3564 static void
thunar_window_device_pre_unmount(ThunarDeviceMonitor * device_monitor,ThunarDevice * device,GFile * root_file,ThunarWindow * window)3565 thunar_window_device_pre_unmount (ThunarDeviceMonitor *device_monitor,
3566                                   ThunarDevice        *device,
3567                                   GFile               *root_file,
3568                                   ThunarWindow        *window)
3569 {
3570   _thunar_return_if_fail (THUNAR_IS_DEVICE_MONITOR (device_monitor));
3571   _thunar_return_if_fail (window->device_monitor == device_monitor);
3572   _thunar_return_if_fail (THUNAR_IS_DEVICE (device));
3573   _thunar_return_if_fail (G_IS_FILE (root_file));
3574   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
3575 
3576   /* nothing to do if we don't have a current directory */
3577   if (G_UNLIKELY (window->current_directory == NULL))
3578     return;
3579 
3580   /* check if the file is the current directory or an ancestor of the current directory */
3581   if (g_file_equal (thunar_file_get_file (window->current_directory), root_file)
3582       || thunar_file_is_gfile_ancestor (window->current_directory, root_file))
3583     {
3584       /* change to the home folder */
3585       thunar_window_action_open_home (window);
3586     }
3587 }
3588 
3589 
3590 
3591 static void
thunar_window_device_changed(ThunarDeviceMonitor * device_monitor,ThunarDevice * device,ThunarWindow * window)3592 thunar_window_device_changed (ThunarDeviceMonitor *device_monitor,
3593                               ThunarDevice        *device,
3594                               ThunarWindow        *window)
3595 {
3596   GFile *root_file;
3597 
3598   _thunar_return_if_fail (THUNAR_IS_DEVICE_MONITOR (device_monitor));
3599   _thunar_return_if_fail (window->device_monitor == device_monitor);
3600   _thunar_return_if_fail (THUNAR_IS_DEVICE (device));
3601   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
3602 
3603   if (thunar_device_is_mounted (device))
3604     return;
3605 
3606   root_file = thunar_device_get_root (device);
3607   if (root_file != NULL)
3608     {
3609       thunar_window_device_pre_unmount (device_monitor, device, root_file, window);
3610       g_object_unref (root_file);
3611     }
3612 }
3613 
3614 
3615 
3616 static gboolean
thunar_window_save_paned(ThunarWindow * window)3617 thunar_window_save_paned (ThunarWindow *window)
3618 {
3619   _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
3620 
3621   g_object_set (G_OBJECT (window->preferences), "last-separator-position",
3622                 gtk_paned_get_position (GTK_PANED (window->paned)), NULL);
3623 
3624   /* for button release event */
3625   return FALSE;
3626 }
3627 
3628 
3629 
3630 static gboolean
thunar_window_save_geometry_timer(gpointer user_data)3631 thunar_window_save_geometry_timer (gpointer user_data)
3632 {
3633   GdkWindowState state;
3634   ThunarWindow  *window = THUNAR_WINDOW (user_data);
3635   gboolean       remember_geometry;
3636   gint           width;
3637   gint           height;
3638 
3639 THUNAR_THREADS_ENTER
3640 
3641   /* check if we should remember the window geometry */
3642   g_object_get (G_OBJECT (window->preferences), "misc-remember-geometry", &remember_geometry, NULL);
3643   if (G_LIKELY (remember_geometry))
3644     {
3645       /* check if the window is still visible */
3646       if (gtk_widget_get_visible (GTK_WIDGET (window)))
3647         {
3648           /* determine the current state of the window */
3649           state = gdk_window_get_state (gtk_widget_get_window (GTK_WIDGET (window)));
3650 
3651           /* don't save geometry for maximized or fullscreen windows */
3652           if ((state & (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN)) == 0)
3653             {
3654               /* determine the current width/height of the window... */
3655               gtk_window_get_size (GTK_WINDOW (window), &width, &height);
3656 
3657               /* ...and remember them as default for new windows */
3658               g_object_set (G_OBJECT (window->preferences), "last-window-width", width, "last-window-height", height,
3659                             "last-window-maximized", FALSE, NULL);
3660             }
3661           else
3662             {
3663               /* only store that the window is full screen */
3664               g_object_set (G_OBJECT (window->preferences), "last-window-maximized", TRUE, NULL);
3665             }
3666         }
3667     }
3668 
3669 THUNAR_THREADS_LEAVE
3670 
3671   return FALSE;
3672 }
3673 
3674 
3675 
3676 static void
thunar_window_save_geometry_timer_destroy(gpointer user_data)3677 thunar_window_save_geometry_timer_destroy (gpointer user_data)
3678 {
3679   THUNAR_WINDOW (user_data)->save_geometry_timer_id = 0;
3680 }
3681 
3682 
3683 
3684 /**
3685  * thunar_window_set_zoom_level:
3686  * @window     : a #ThunarWindow instance.
3687  * @zoom_level : the new zoom level for @window.
3688  *
3689  * Sets the zoom level for @window to @zoom_level.
3690  **/
3691 void
thunar_window_set_zoom_level(ThunarWindow * window,ThunarZoomLevel zoom_level)3692 thunar_window_set_zoom_level (ThunarWindow   *window,
3693                               ThunarZoomLevel zoom_level)
3694 {
3695   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
3696   _thunar_return_if_fail (zoom_level < THUNAR_ZOOM_N_LEVELS);
3697 
3698   /* check if we have a new zoom level */
3699   if (G_LIKELY (window->zoom_level != zoom_level))
3700     {
3701       /* remember the new zoom level */
3702       window->zoom_level = zoom_level;
3703 
3704       /* notify listeners */
3705       g_object_notify (G_OBJECT (window), "zoom-level");
3706     }
3707 }
3708 
3709 
3710 
3711 /**
3712  * thunar_window_set_directory_specific_settings:
3713  * @window                      : a #ThunarWindow instance.
3714  * @directory_specific_settings : whether to use directory specific settings in @window.
3715  *
3716  * Toggles the use of directory specific settings in @window according to @directory_specific_settings.
3717  **/
3718 void
thunar_window_set_directory_specific_settings(ThunarWindow * window,gboolean directory_specific_settings)3719 thunar_window_set_directory_specific_settings (ThunarWindow *window,
3720                                                gboolean      directory_specific_settings)
3721 {
3722   GList      *tabs, *lp;
3723   ThunarFile *directory;
3724   GType       view_type;
3725   gchar      *type_name;
3726 
3727   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
3728 
3729   /* reset to the default view type if we are turning directory specific settings off */
3730   if (!directory_specific_settings && window->directory_specific_settings)
3731     {
3732       /* determine the default view type */
3733       g_object_get (G_OBJECT (window->preferences), "default-view", &type_name, NULL);
3734       view_type = g_type_from_name (type_name);
3735       g_free (type_name);
3736 
3737       /* set the last view type */
3738       if (!g_type_is_a (view_type, G_TYPE_NONE) && !g_type_is_a (view_type, G_TYPE_INVALID))
3739         g_object_set (G_OBJECT (window->preferences), "last-view", g_type_name (view_type), NULL);
3740     }
3741 
3742   /* save the setting */
3743   window->directory_specific_settings = directory_specific_settings;
3744 
3745   /* get all of the window's tabs */
3746   tabs = gtk_container_get_children (GTK_CONTAINER (window->notebook));
3747 
3748   /* replace each tab with a tab of the correct view type */
3749   for (lp = tabs; lp != NULL; lp = lp->next)
3750     {
3751       if (!THUNAR_IS_STANDARD_VIEW (lp->data))
3752         continue;
3753 
3754       directory = thunar_navigator_get_current_directory (lp->data);
3755 
3756       if (!THUNAR_IS_FILE (directory))
3757         continue;
3758 
3759       /* find the correct view type for the new view */
3760       view_type = thunar_window_view_type_for_directory (window, directory);
3761 
3762       /* replace the old view with a new one */
3763       thunar_window_replace_view (window, lp->data, view_type);
3764     }
3765 
3766   g_list_free (tabs);
3767 }
3768 
3769 
3770 
3771 /**
3772  * thunar_window_get_current_directory:
3773  * @window : a #ThunarWindow instance.
3774  *
3775  * Queries the #ThunarFile instance, which represents the directory
3776  * currently displayed within @window. %NULL is returned if @window
3777  * is not currently associated with any directory.
3778  *
3779  * Return value: the directory currently displayed within @window or %NULL.
3780  **/
3781 ThunarFile*
thunar_window_get_current_directory(ThunarWindow * window)3782 thunar_window_get_current_directory (ThunarWindow *window)
3783 {
3784   _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), NULL);
3785   return window->current_directory;
3786 }
3787 
3788 
3789 
3790 /**
3791  * thunar_window_set_current_directory:
3792  * @window            : a #ThunarWindow instance.
3793  * @current_directory : the new directory or %NULL.
3794  **/
3795 void
thunar_window_set_current_directory(ThunarWindow * window,ThunarFile * current_directory)3796 thunar_window_set_current_directory (ThunarWindow *window,
3797                                      ThunarFile   *current_directory)
3798 {
3799   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
3800   _thunar_return_if_fail (current_directory == NULL || THUNAR_IS_FILE (current_directory));
3801 
3802   /* check if we already display the requested directory */
3803   if (G_UNLIKELY (window->current_directory == current_directory))
3804     return;
3805 
3806   /* disconnect from the previously active directory */
3807   if (G_LIKELY (window->current_directory != NULL))
3808     {
3809       /* disconnect signals and release reference */
3810       g_signal_handlers_disconnect_by_func (G_OBJECT (window->current_directory), thunar_window_current_directory_changed, window);
3811       g_object_unref (G_OBJECT (window->current_directory));
3812     }
3813 
3814   /* connect to the new directory */
3815   if (G_LIKELY (current_directory != NULL))
3816     {
3817       GType  type;
3818       gchar *type_name;
3819       gint   num_pages;
3820 
3821       /* take a reference on the file */
3822       g_object_ref (G_OBJECT (current_directory));
3823 
3824       num_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook));
3825 
3826       /* if the window is new, get the default-view type and set it as the last-view type (if it is a valid type)
3827        * so that it will be used as the initial view type for directories with no saved directory specific view type */
3828       if (num_pages == 0)
3829         {
3830           /* determine the default view type */
3831           g_object_get (G_OBJECT (window->preferences), "default-view", &type_name, NULL);
3832           type = g_type_from_name (type_name);
3833           g_free (type_name);
3834 
3835           /* set the last view type to the default view type if there is a default view type */
3836           if (!g_type_is_a (type, G_TYPE_NONE) && !g_type_is_a (type, G_TYPE_INVALID))
3837             g_object_set (G_OBJECT (window->preferences), "last-view", g_type_name (type), NULL);
3838         }
3839 
3840       type = thunar_window_view_type_for_directory (window, current_directory);
3841 
3842       if (num_pages == 0) /* create a new view if the window is new */
3843         {
3844           window->current_directory = current_directory;
3845           thunar_window_replace_view (window, window->view, type);
3846         }
3847       else /* change the view type if necessary, and set the current directory */
3848         {
3849           if (window->view != NULL && window->view_type != type)
3850             thunar_window_replace_view (window, window->view, type);
3851 
3852           window->current_directory = current_directory;
3853         }
3854 
3855       /* connect the "changed"/"destroy" signals */
3856       g_signal_connect (G_OBJECT (current_directory), "changed", G_CALLBACK (thunar_window_current_directory_changed), window);
3857 
3858       /* update window icon and title */
3859       thunar_window_current_directory_changed (current_directory, window);
3860 
3861       if (G_LIKELY (window->view != NULL))
3862         {
3863           /* grab the focus to the main view */
3864           gtk_widget_grab_focus (window->view);
3865         }
3866 
3867       thunar_window_history_changed (window);
3868       gtk_widget_set_sensitive (window->location_toolbar_item_parent, !thunar_g_file_is_root (thunar_file_get_file (current_directory)));
3869     }
3870 
3871   /* tell everybody that we have a new "current-directory",
3872    * we do this first so other widgets display the new
3873    * state already while the folder view is loading.
3874    */
3875   g_object_notify (G_OBJECT (window), "current-directory");
3876 }
3877 
3878 
3879 
3880 static void
thunar_window_set_current_directory_gfile(ThunarWindow * window,GFile * current_directory)3881 thunar_window_set_current_directory_gfile (ThunarWindow *window,
3882                                            GFile        *current_directory)
3883 {
3884   ThunarFile *thunar_file;
3885 
3886   /* remote files possibly need to be poked first */
3887   if (g_file_has_uri_scheme (current_directory, "file"))
3888     {
3889       thunar_file = thunar_file_get (current_directory, NULL);
3890       thunar_window_set_current_directory (THUNAR_WINDOW (window), thunar_file);
3891       g_object_unref (thunar_file);
3892     }
3893   else
3894     {
3895       thunar_browser_poke_location (THUNAR_BROWSER (window), current_directory, THUNAR_WINDOW (window),
3896                                     thunar_window_poke_location_finish, NULL);
3897     }
3898 }
3899 
3900 
3901 
3902 /**
3903  * thunar_window_scroll_to_file:
3904  * @window      : a #ThunarWindow instance.
3905  * @file        : a #ThunarFile.
3906  * @select_file : if %TRUE the @file will also be selected.
3907  * @use_align   : %TRUE to use the alignment arguments.
3908  * @row_align   : the vertical alignment.
3909  * @col_align   : the horizontal alignment.
3910  *
3911  * Tells the @window to scroll to the @file
3912  * in the current view.
3913  **/
3914 void
thunar_window_scroll_to_file(ThunarWindow * window,ThunarFile * file,gboolean select_file,gboolean use_align,gfloat row_align,gfloat col_align)3915 thunar_window_scroll_to_file (ThunarWindow *window,
3916                               ThunarFile   *file,
3917                               gboolean      select_file,
3918                               gboolean      use_align,
3919                               gfloat        row_align,
3920                               gfloat        col_align)
3921 {
3922   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
3923   _thunar_return_if_fail (THUNAR_IS_FILE (file));
3924 
3925   /* verify that we have a valid view */
3926   if (G_LIKELY (window->view != NULL))
3927     thunar_view_scroll_to_file (THUNAR_VIEW (window->view), file, select_file, use_align, row_align, col_align);
3928 }
3929 
3930 
3931 
3932 gchar **
thunar_window_get_directories(ThunarWindow * window,gint * active_page)3933 thunar_window_get_directories (ThunarWindow *window,
3934                                gint         *active_page)
3935 {
3936   gint         n;
3937   gint         n_pages;
3938   gchar      **uris;
3939   GtkWidget   *view;
3940   ThunarFile  *directory;
3941 
3942   _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), NULL);
3943 
3944   n_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook));
3945   if (G_UNLIKELY (n_pages == 0))
3946     return NULL;
3947 
3948   /* create array of uris */
3949   uris = g_new0 (gchar *, n_pages + 1);
3950   for (n = 0; n < n_pages; n++)
3951     {
3952       /* get the view */
3953       view = gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->notebook), n);
3954       _thunar_return_val_if_fail (THUNAR_IS_NAVIGATOR (view), FALSE);
3955 
3956       /* get the directory of the view */
3957       directory = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (view));
3958       _thunar_return_val_if_fail (THUNAR_IS_FILE (directory), FALSE);
3959 
3960       /* add to array */
3961       uris[n] = thunar_file_dup_uri (directory);
3962     }
3963 
3964   /* selected tab */
3965   if (active_page != NULL)
3966     *active_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook));
3967 
3968   return uris;
3969 }
3970 
3971 
3972 
3973 gboolean
thunar_window_set_directories(ThunarWindow * window,gchar ** uris,gint active_page)3974 thunar_window_set_directories (ThunarWindow   *window,
3975                                gchar         **uris,
3976                                gint            active_page)
3977 {
3978   ThunarFile *directory;
3979   guint       n;
3980 
3981   _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
3982   _thunar_return_val_if_fail (uris != NULL, FALSE);
3983 
3984   for (n = 0; uris[n] != NULL; n++)
3985     {
3986       /* check if the string looks like an uri */
3987       if (!exo_str_looks_like_an_uri (uris[n]))
3988         continue;
3989 
3990       /* get the file for the uri */
3991       directory = thunar_file_get_for_uri (uris[n], NULL);
3992       if (G_UNLIKELY (directory == NULL))
3993         continue;
3994 
3995       /* open the directory in a new notebook */
3996       if (thunar_file_is_directory (directory))
3997         {
3998           if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook)) == 0)
3999             thunar_window_set_current_directory (window, directory);
4000           else
4001             thunar_window_notebook_open_new_tab (window, directory);
4002         }
4003 
4004       g_object_unref (G_OBJECT (directory));
4005     }
4006 
4007   /* select the page */
4008   gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), active_page);
4009 
4010   /* we succeeded if new pages have been opened */
4011   return gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook)) > 0;
4012 }
4013 
4014 
4015 
4016 /**
4017  * thunar_window_get_action_entry:
4018  * @window  : Instance of a  #ThunarWindow
4019  * @action  : #ThunarWindowAction for which the #XfceGtkActionEntry is requested
4020  *
4021  * returns a reference to the requested #XfceGtkActionEntry
4022  *
4023  * Return value: (transfer none): The reference to the #XfceGtkActionEntry
4024  **/
4025 const XfceGtkActionEntry*
thunar_window_get_action_entry(ThunarWindow * window,ThunarWindowAction action)4026 thunar_window_get_action_entry (ThunarWindow       *window,
4027                                 ThunarWindowAction  action)
4028 {
4029   return get_action_entry (action);
4030 }
4031 
4032 
4033 
4034 /**
4035  * thunar_window_append_menu_item:
4036  * @window  : Instance of a  #ThunarWindow
4037  * @menu    : #GtkMenuShell to which the item should be added
4038  * @action  : #ThunarWindowAction to select which item should be added
4039  *
4040  * Adds the selected, widget specific #GtkMenuItem to the passed #GtkMenuShell
4041  **/
4042 void
thunar_window_append_menu_item(ThunarWindow * window,GtkMenuShell * menu,ThunarWindowAction action)4043 thunar_window_append_menu_item (ThunarWindow       *window,
4044                                 GtkMenuShell       *menu,
4045                                 ThunarWindowAction  action)
4046 {
4047   GtkWidget *item;
4048 
4049   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
4050 
4051   item = xfce_gtk_menu_item_new_from_action_entry (get_action_entry (action), G_OBJECT (window), menu);
4052 
4053   if (action == THUNAR_WINDOW_ACTION_ZOOM_IN)
4054     gtk_widget_set_sensitive (item, G_LIKELY (window->zoom_level < THUNAR_ZOOM_N_LEVELS - 1));
4055   if (action == THUNAR_WINDOW_ACTION_ZOOM_OUT)
4056     gtk_widget_set_sensitive (item, G_LIKELY (window->zoom_level > 0));
4057 }
4058 
4059 
4060 
4061 /**
4062  * thunar_window_get_launcher:
4063  * @window : a #ThunarWindow instance.
4064  *
4065  * Return value: (transfer none): The single #ThunarLauncher of this #ThunarWindow
4066  **/
4067 ThunarLauncher*
thunar_window_get_launcher(ThunarWindow * window)4068 thunar_window_get_launcher (ThunarWindow *window)
4069 {
4070   _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), NULL);
4071 
4072   return window->launcher;
4073 }
4074 
4075 
4076 
4077 static void
thunar_window_redirect_menu_tooltips_to_statusbar_recursive(GtkWidget * menu_item,ThunarWindow * window)4078 thunar_window_redirect_menu_tooltips_to_statusbar_recursive (GtkWidget    *menu_item,
4079                                                              ThunarWindow *window)
4080 {
4081   GtkWidget  *submenu;
4082 
4083   if (GTK_IS_MENU_ITEM (menu_item))
4084     {
4085       submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (menu_item));
4086       if (submenu != NULL)
4087           gtk_container_foreach (GTK_CONTAINER (submenu), (GtkCallback) (void (*)(void)) thunar_window_redirect_menu_tooltips_to_statusbar_recursive, window);
4088 
4089       /* this disables to show the tooltip on hover */
4090       gtk_widget_set_has_tooltip (menu_item, FALSE);
4091 
4092       /* These method will put the tooltip on the statusbar */
4093       g_signal_connect_swapped (G_OBJECT (menu_item), "select", G_CALLBACK (thunar_window_menu_item_selected), window);
4094       g_signal_connect_swapped (G_OBJECT (menu_item), "deselect", G_CALLBACK (thunar_window_menu_item_deselected), window);
4095     }
4096 }
4097 
4098 
4099 
4100 /**
4101  * thunar_window_redirect_menu_tooltips_to_statusbar:
4102  * @window : a #ThunarWindow instance.
4103  * @menu   : #GtkMenu for which all tooltips should be shown in the statusbar
4104  *
4105  * All tooltips of the provided #GtkMenu and any submenu will not be shown directly any more.
4106  * Instead they will be shown in the status bar of the passed #ThunarWindow
4107  **/
4108 void
thunar_window_redirect_menu_tooltips_to_statusbar(ThunarWindow * window,GtkMenu * menu)4109 thunar_window_redirect_menu_tooltips_to_statusbar (ThunarWindow *window, GtkMenu *menu)
4110 {
4111   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
4112   _thunar_return_if_fail (GTK_IS_MENU (menu));
4113 
4114   gtk_container_foreach (GTK_CONTAINER (menu), (GtkCallback) (void (*)(void)) thunar_window_redirect_menu_tooltips_to_statusbar_recursive, window);
4115 }
4116 
4117 
4118 
4119 static gboolean
thunar_window_button_press_event(GtkWidget * view,GdkEventButton * event,ThunarWindow * window)4120 thunar_window_button_press_event (GtkWidget      *view,
4121                                   GdkEventButton *event,
4122                                   ThunarWindow   *window)
4123 {
4124   const XfceGtkActionEntry* action_entry;
4125 
4126   _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
4127 
4128   if (event->type == GDK_BUTTON_PRESS)
4129     {
4130       if (G_UNLIKELY (event->button == 8))
4131         {
4132           action_entry = get_action_entry (THUNAR_WINDOW_ACTION_BACK);
4133           ((void(*)(GtkWindow*))action_entry->callback)(GTK_WINDOW (window));
4134           return GDK_EVENT_STOP;
4135         }
4136       if (G_UNLIKELY (event->button == 9))
4137         {
4138           action_entry = get_action_entry (THUNAR_WINDOW_ACTION_FORWARD);
4139           ((void(*)(GtkWindow*))action_entry->callback)(GTK_WINDOW (window));
4140           return GDK_EVENT_STOP;
4141         }
4142     }
4143 
4144   return GDK_EVENT_PROPAGATE;
4145 }
4146 
4147 
4148 
4149 static gboolean
thunar_window_history_clicked(GtkWidget * button,GdkEventButton * event,GtkWidget * data)4150 thunar_window_history_clicked (GtkWidget      *button,
4151                                GdkEventButton *event,
4152                                GtkWidget      *data)
4153 {
4154   ThunarHistory *history;
4155   ThunarWindow  *window;
4156 
4157   _thunar_return_val_if_fail (THUNAR_IS_WINDOW (data), FALSE);
4158 
4159   window = THUNAR_WINDOW (data);
4160 
4161   if (event->button == 3)
4162     {
4163       history = thunar_standard_view_get_history (THUNAR_STANDARD_VIEW (window->view));
4164 
4165       if (button == window->location_toolbar_item_back)
4166         thunar_history_show_menu (history, THUNAR_HISTORY_MENU_BACK, button);
4167       else if (button == window->location_toolbar_item_forward)
4168         thunar_history_show_menu (history, THUNAR_HISTORY_MENU_FORWARD, button);
4169       else
4170         g_warning ("This button is not able to spawn a history menu");
4171     }
4172 
4173   return FALSE;
4174 }
4175 
4176 
4177 
4178 /**
4179  * thunar_window_view_type_for_directory:
4180  * @window      : a #ThunarWindow instance.
4181  * @directory   : #ThunarFile representing the directory
4182  *
4183  * Return value: the #GType representing the view type which
4184  * @window would use to display @directory.
4185  **/
4186 GType
thunar_window_view_type_for_directory(ThunarWindow * window,ThunarFile * directory)4187 thunar_window_view_type_for_directory (ThunarWindow *window,
4188                                        ThunarFile   *directory)
4189 {
4190   GType  type = G_TYPE_NONE;
4191   gchar *type_name;
4192 
4193   _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), G_TYPE_NONE);
4194   _thunar_return_val_if_fail (THUNAR_IS_FILE (directory), G_TYPE_NONE);
4195 
4196   /* if the  directory has a saved view type and directory specific view types are enabled, we use it */
4197   if (window->directory_specific_settings)
4198     {
4199       const gchar *dir_spec_type_name;
4200 
4201       dir_spec_type_name = thunar_file_get_metadata_setting (directory, "view-type");
4202       if (dir_spec_type_name != NULL)
4203         type = g_type_from_name (dir_spec_type_name);
4204     }
4205 
4206   /* if there is no saved view type for the directory or directory specific view types are not enabled,
4207    * we use the last view type */
4208   if (g_type_is_a (type, G_TYPE_NONE) || g_type_is_a (type, G_TYPE_INVALID))
4209     {
4210       /* determine the last view type */
4211       g_object_get (G_OBJECT (window->preferences), "last-view", &type_name, NULL);
4212       type = g_type_from_name (type_name);
4213       g_free (type_name);
4214     }
4215 
4216   /* fallback view type, in case nothing was set */
4217   if (g_type_is_a (type, G_TYPE_NONE) || g_type_is_a (type, G_TYPE_INVALID))
4218     type = THUNAR_TYPE_ICON_VIEW;
4219 
4220   return type;
4221 }
4222