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

« back to all changes in this revision

Viewing changes to .pc/git-force-toolbr-icons.patch/thunar/thunar-window.c

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

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 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
#include <libxfce4ui/libxfce4ui.h>
 
35
 
 
36
#include <thunar/thunar-application.h>
 
37
#include <thunar/thunar-browser.h>
 
38
#include <thunar/thunar-clipboard-manager.h>
 
39
#include <thunar/thunar-compact-view.h>
 
40
#include <thunar/thunar-details-view.h>
 
41
#include <thunar/thunar-dialogs.h>
 
42
#include <thunar/thunar-shortcuts-pane.h>
 
43
#include <thunar/thunar-gio-extensions.h>
 
44
#include <thunar/thunar-gobject-extensions.h>
 
45
#include <thunar/thunar-gtk-extensions.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-dialog.h>
 
50
#include <thunar/thunar-location-entry.h>
 
51
#include <thunar/thunar-marshal.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-stock.h>
 
59
#include <thunar/thunar-trash-action.h>
 
60
#include <thunar/thunar-tree-pane.h>
 
61
#include <thunar/thunar-window.h>
 
62
#include <thunar/thunar-window-ui.h>
 
63
#include <thunar/thunar-device-monitor.h>
 
64
 
 
65
#include <glib.h>
 
66
 
 
67
 
 
68
 
 
69
/* Property identifiers */
 
70
enum
 
71
{
 
72
  PROP_0,
 
73
  PROP_CURRENT_DIRECTORY,
 
74
  PROP_SHOW_HIDDEN,
 
75
  PROP_UI_MANAGER,
 
76
  PROP_ZOOM_LEVEL,
 
77
};
 
78
 
 
79
/* Signal identifiers */
 
80
enum
 
81
{
 
82
  BACK,
 
83
  RELOAD,
 
84
  TOGGLE_SIDEPANE,
 
85
  TOGGLE_MENUBAR,
 
86
  ZOOM_IN,
 
87
  ZOOM_OUT,
 
88
  ZOOM_RESET,
 
89
  TAB_CHANGE,
 
90
  LAST_SIGNAL,
 
91
};
 
92
 
 
93
 
 
94
 
 
95
static void     thunar_window_dispose                     (GObject                *object);
 
96
static void     thunar_window_finalize                    (GObject                *object);
 
97
static void     thunar_window_get_property                (GObject                *object,
 
98
                                                           guint                   prop_id,
 
99
                                                           GValue                 *value,
 
100
                                                           GParamSpec             *pspec);
 
101
static void     thunar_window_set_property                (GObject                *object,
 
102
                                                           guint                   prop_id,
 
103
                                                           const GValue           *value,
 
104
                                                           GParamSpec             *pspec);
 
105
static gboolean thunar_window_back                        (ThunarWindow           *window);
 
106
static gboolean thunar_window_reload                      (ThunarWindow           *window);
 
107
static gboolean thunar_window_toggle_sidepane             (ThunarWindow           *window);
 
108
static gboolean thunar_window_toggle_menubar              (ThunarWindow           *window);
 
109
static void     thunar_window_toggle_menubar_deactivate   (GtkWidget              *menubar,
 
110
                                                           ThunarWindow           *window);
 
111
static gboolean thunar_window_zoom_in                     (ThunarWindow           *window);
 
112
static gboolean thunar_window_zoom_out                    (ThunarWindow           *window);
 
113
static gboolean thunar_window_zoom_reset                  (ThunarWindow           *window);
 
114
static gboolean thunar_window_tab_change                  (ThunarWindow           *window,
 
115
                                                           gint                    nth);
 
116
static void     thunar_window_realize                     (GtkWidget              *widget);
 
117
static void     thunar_window_unrealize                   (GtkWidget              *widget);
 
118
static gboolean thunar_window_configure_event             (GtkWidget              *widget,
 
119
                                                           GdkEventConfigure      *event);
 
120
static void     thunar_window_notebook_switch_page        (GtkWidget              *notebook,
 
121
                                                           GtkWidget              *page,
 
122
                                                           guint                   page_num,
 
123
                                                           ThunarWindow           *window);
 
124
static void     thunar_window_notebook_page_added         (GtkWidget              *notebook,
 
125
                                                           GtkWidget              *page,
 
126
                                                           guint                   page_num,
 
127
                                                           ThunarWindow           *window);
 
128
static void     thunar_window_notebook_page_removed       (GtkWidget              *notebook,
 
129
                                                           GtkWidget              *page,
 
130
                                                           guint                   page_num,
 
131
                                                           ThunarWindow           *window);
 
132
static gboolean thunar_window_notebook_button_press_event (GtkWidget              *notebook,
 
133
                                                           GdkEventButton         *event,
 
134
                                                           ThunarWindow           *window);
 
135
static gboolean thunar_window_notebook_popup_menu         (GtkWidget              *notebook,
 
136
                                                           ThunarWindow           *window);
 
137
static gpointer thunar_window_notebook_create_window      (GtkWidget              *notebook,
 
138
                                                           GtkWidget              *page,
 
139
                                                           gint                    x,
 
140
                                                           gint                    y,
 
141
                                                           ThunarWindow           *window);
 
142
static void     thunar_window_notebook_insert             (ThunarWindow           *window,
 
143
                                                           ThunarFile             *directory);
 
144
static void     thunar_window_merge_custom_preferences    (ThunarWindow           *window);
 
145
static gboolean thunar_window_bookmark_merge              (gpointer                user_data);
 
146
static void     thunar_window_merge_go_actions            (ThunarWindow           *window);
 
147
static void     thunar_window_install_location_bar        (ThunarWindow           *window,
 
148
                                                           GType                   type);
 
149
static void     thunar_window_install_sidepane            (ThunarWindow           *window,
 
150
                                                           GType                   type);
 
151
static void     thunar_window_start_open_location         (ThunarWindow           *window,
 
152
                                                           const gchar            *initial_text);
 
153
static void     thunar_window_action_open_new_tab         (GtkAction              *action,
 
154
                                                           ThunarWindow           *window);
 
155
static void     thunar_window_action_open_new_window      (GtkAction              *action,
 
156
                                                           ThunarWindow           *window);
 
157
static void     thunar_window_action_empty_trash          (GtkAction              *action,
 
158
                                                           ThunarWindow           *window);
 
159
static void     thunar_window_action_detach_tab           (GtkAction              *action,
 
160
                                                           ThunarWindow           *window);
 
161
static void     thunar_window_action_close_all_windows    (GtkAction              *action,
 
162
                                                           ThunarWindow           *window);
 
163
static void     thunar_window_action_close_tab            (GtkAction              *action,
 
164
                                                           ThunarWindow           *window);
 
165
static void     thunar_window_action_close_window         (GtkAction              *action,
 
166
                                                           ThunarWindow           *window);
 
167
static void     thunar_window_action_preferences          (GtkAction              *action,
 
168
                                                           ThunarWindow           *window);
 
169
static void     thunar_window_action_reload               (GtkAction              *action,
 
170
                                                           ThunarWindow           *window);
 
171
static void     thunar_window_action_pathbar_changed      (GtkToggleAction        *action,
 
172
                                                           ThunarWindow           *window);
 
173
static void     thunar_window_action_toolbar_changed      (GtkToggleAction        *action,
 
174
                                                           ThunarWindow           *window);
 
175
static void     thunar_window_action_shortcuts_changed    (GtkToggleAction        *action,
 
176
                                                           ThunarWindow           *window);
 
177
static void     thunar_window_action_tree_changed         (GtkToggleAction        *action,
 
178
                                                           ThunarWindow           *window);
 
179
static void     thunar_window_action_statusbar_changed    (GtkToggleAction        *action,
 
180
                                                           ThunarWindow           *window);
 
181
static void     thunar_window_action_menubar_changed      (GtkToggleAction        *action,
 
182
                                                           ThunarWindow           *window);
 
183
static void     thunar_window_action_zoom_in              (GtkAction              *action,
 
184
                                                           ThunarWindow           *window);
 
185
static void     thunar_window_action_zoom_out             (GtkAction              *action,
 
186
                                                           ThunarWindow           *window);
 
187
static void     thunar_window_action_zoom_reset           (GtkAction              *action,
 
188
                                                           ThunarWindow           *window);
 
189
static void     thunar_window_action_view_changed         (GtkRadioAction         *action,
 
190
                                                           GtkRadioAction         *current,
 
191
                                                           ThunarWindow           *window);
 
192
static void     thunar_window_action_go_up                (GtkAction              *action,
 
193
                                                           ThunarWindow           *window);
 
194
static void     thunar_window_action_open_home            (GtkAction              *action,
 
195
                                                           ThunarWindow           *window);
 
196
static void     thunar_window_action_open_desktop         (GtkAction              *action,
 
197
                                                           ThunarWindow           *window);
 
198
static void     thunar_window_action_open_templates       (GtkAction              *action,
 
199
                                                           ThunarWindow           *window);
 
200
static void     thunar_window_action_open_file_system     (GtkAction              *action,
 
201
                                                           ThunarWindow           *window);
 
202
static void     thunar_window_action_open_trash           (GtkAction              *action,
 
203
                                                           ThunarWindow           *window);
 
204
static void     thunar_window_action_open_network         (GtkAction              *action,
 
205
                                                           ThunarWindow           *window);
 
206
static void     thunar_window_action_open_bookmark        (GtkAction              *action,
 
207
                                                           ThunarWindow           *window);
 
208
static void     thunar_window_action_open_location        (GtkAction              *action,
 
209
                                                           ThunarWindow           *window);
 
210
static void     thunar_window_action_contents             (GtkAction              *action,
 
211
                                                           ThunarWindow           *window);
 
212
static void     thunar_window_action_about                (GtkAction              *action,
 
213
                                                           ThunarWindow           *window);
 
214
static void     thunar_window_action_show_hidden          (GtkToggleAction        *action,
 
215
                                                           ThunarWindow           *window);
 
216
static void     thunar_window_current_directory_changed   (ThunarFile             *current_directory,
 
217
                                                           ThunarWindow           *window);
 
218
static void     thunar_window_connect_proxy               (GtkUIManager           *manager,
 
219
                                                           GtkAction              *action,
 
220
                                                           GtkWidget              *proxy,
 
221
                                                           ThunarWindow           *window);
 
222
static void     thunar_window_disconnect_proxy            (GtkUIManager           *manager,
 
223
                                                           GtkAction              *action,
 
224
                                                           GtkWidget              *proxy,
 
225
                                                           ThunarWindow           *window);
 
226
static void     thunar_window_menu_item_selected          (GtkWidget              *menu_item,
 
227
                                                           ThunarWindow           *window);
 
228
static void     thunar_window_menu_item_deselected        (GtkWidget              *menu_item,
 
229
                                                           ThunarWindow           *window);
 
230
static void     thunar_window_update_custom_actions       (ThunarView             *view,
 
231
                                                           GParamSpec             *pspec,
 
232
                                                           ThunarWindow           *window);
 
233
static void     thunar_window_notify_loading              (ThunarView             *view,
 
234
                                                           GParamSpec             *pspec,
 
235
                                                           ThunarWindow           *window);
 
236
static void     thunar_window_device_pre_unmount          (ThunarDeviceMonitor    *device_monitor,
 
237
                                                           ThunarDevice           *device,
 
238
                                                           GFile                  *root_file,
 
239
                                                           ThunarWindow           *window);
 
240
static void     thunar_window_device_changed              (ThunarDeviceMonitor    *device_monitor,
 
241
                                                           ThunarDevice           *device,
 
242
                                                           ThunarWindow           *window);
 
243
static gboolean thunar_window_merge_idle                  (gpointer                user_data);
 
244
static void     thunar_window_merge_idle_destroy          (gpointer                user_data);
 
245
static gboolean thunar_window_save_paned                  (ThunarWindow           *window);
 
246
static gboolean thunar_window_save_geometry_timer         (gpointer                user_data);
 
247
static void     thunar_window_save_geometry_timer_destroy (gpointer                user_data);
 
248
static void     thunar_window_set_zoom_level              (ThunarWindow           *window,
 
249
                                                           ThunarZoomLevel         zoom_level);
 
250
 
 
251
 
 
252
 
 
253
struct _ThunarWindowClass
 
254
{
 
255
  GtkWindowClass __parent__;
 
256
 
 
257
  /* internal action signals */
 
258
  gboolean (*back)            (ThunarWindow *window);
 
259
  gboolean (*reload)          (ThunarWindow *window);
 
260
  gboolean (*toggle_sidepane) (ThunarWindow *window);
 
261
  gboolean (*toggle_menubar)  (ThunarWindow *window);
 
262
  gboolean (*zoom_in)         (ThunarWindow *window);
 
263
  gboolean (*zoom_out)        (ThunarWindow *window);
 
264
  gboolean (*zoom_reset)      (ThunarWindow *window);
 
265
  gboolean (*tab_change)      (ThunarWindow *window,
 
266
                               gint          idx);
 
267
};
 
268
 
 
269
struct _ThunarWindow
 
270
{
 
271
  GtkWindow __parent__;
 
272
 
 
273
  /* support for custom preferences actions */
 
274
  ThunarxProviderFactory *provider_factory;
 
275
  guint                   custom_preferences_merge_id;
 
276
 
 
277
  /* UI manager merge ID for go menu actions */
 
278
  guint                   go_items_actions_merge_id;
 
279
 
 
280
  /* UI manager merge ID for the bookmark actions */
 
281
  guint                   bookmark_items_actions_merge_id;
 
282
  GtkActionGroup         *bookmark_action_group;
 
283
  GFile                  *bookmark_file;
 
284
  GFileMonitor           *bookmark_monitor;
 
285
  guint                   bookmark_reload_idle_id;
 
286
 
 
287
  ThunarClipboardManager *clipboard;
 
288
 
 
289
  ThunarPreferences      *preferences;
 
290
 
 
291
  ThunarIconFactory      *icon_factory;
 
292
 
 
293
  GtkActionGroup         *action_group;
 
294
  GtkUIManager           *ui_manager;
 
295
 
 
296
  /* to be able to change folder on "device-pre-unmount" if required */
 
297
  ThunarDeviceMonitor    *device_monitor;
 
298
 
 
299
  /* closures for the menu_item_selected()/menu_item_deselected() callbacks */
 
300
  GClosure               *menu_item_selected_closure;
 
301
  GClosure               *menu_item_deselected_closure;
 
302
 
 
303
  /* custom menu actions for the file menu */
 
304
  GtkActionGroup         *custom_actions;
 
305
  guint                   custom_merge_id;
 
306
 
 
307
  GtkWidget              *table;
 
308
  GtkWidget              *menubar;
 
309
  GtkWidget              *spinner;
 
310
  GtkWidget              *paned;
 
311
  GtkWidget              *sidepane;
 
312
  GtkWidget              *view_box;
 
313
  GtkWidget              *notebook;
 
314
  GtkWidget              *view;
 
315
  GtkWidget              *statusbar;
 
316
 
 
317
  GType                   view_type;
 
318
  GSList                 *view_bindings;
 
319
 
 
320
  /* support for two different styles of location bars */
 
321
  GtkWidget              *location_bar;
 
322
  GtkWidget              *location_toolbar;
 
323
 
 
324
  ThunarLauncher         *launcher;
 
325
 
 
326
  ThunarFile             *current_directory;
 
327
 
 
328
  /* zoom-level support */
 
329
  ThunarZoomLevel         zoom_level;
 
330
 
 
331
  /* menu merge idle source */
 
332
  guint                   merge_idle_id;
 
333
 
 
334
  /* support to remember window geometry */
 
335
  guint                   save_geometry_timer_id;
 
336
 
 
337
  /* support to toggle side pane using F9,
 
338
   * see the toggle_sidepane() function.
 
339
   */
 
340
  GType                   toggle_sidepane_type;
 
341
};
 
342
 
 
343
 
 
344
 
 
345
static GtkActionEntry action_entries[] =
 
346
{
 
347
  { "file-menu", NULL, N_ ("_File"), NULL, },
 
348
  { "new-tab", "tab-new", N_ ("New _Tab"), "<control>T", N_ ("Open a new tab for the displayed location"), G_CALLBACK (thunar_window_action_open_new_tab), },
 
349
  { "new-window", "window-new", N_ ("New _Window"), "<control>N", N_ ("Open a new Thunar window for the displayed location"), G_CALLBACK (thunar_window_action_open_new_window), },
 
350
  { "sendto-menu", NULL, N_ ("_Send To"), NULL, },
 
351
  { "empty-trash", NULL, N_ ("_Empty Trash"), NULL, N_ ("Delete all files and folders in the Trash"), G_CALLBACK (thunar_window_action_empty_trash), },
 
352
  { "detach-tab", NULL, N_ ("Detac_h Tab"), NULL, N_ ("Open current folder in a new window"), G_CALLBACK (thunar_window_action_detach_tab), },
 
353
  { "close-all-windows", NULL, N_ ("Close _All Windows"), "<control><shift>W", N_ ("Close all Thunar windows"), G_CALLBACK (thunar_window_action_close_all_windows), },
 
354
  { "close-tab", GTK_STOCK_CLOSE, N_ ("C_lose Tab"), "<control>W", N_ ("Close this folder"), G_CALLBACK (thunar_window_action_close_tab), },
 
355
  { "close-window", GTK_STOCK_QUIT, N_ ("_Close Window"), "<control>Q", N_ ("Close this window"), G_CALLBACK (thunar_window_action_close_window), },
 
356
  { "edit-menu", NULL, N_ ("_Edit"), NULL, },
 
357
  { "preferences", GTK_STOCK_PREFERENCES, N_ ("Pr_eferences..."), NULL, N_ ("Edit Thunars Preferences"), G_CALLBACK (thunar_window_action_preferences), },
 
358
  { "view-menu", NULL, N_ ("_View"), NULL, },
 
359
  { "reload", GTK_STOCK_REFRESH, N_ ("_Reload"), "<control>R", N_ ("Reload the current folder"), G_CALLBACK (thunar_window_action_reload), },
 
360
  { "view-location-selector-menu", NULL, N_ ("_Location Selector"), NULL, },
 
361
  { "view-side-pane-menu", NULL, N_ ("_Side Pane"), NULL, },
 
362
  { "zoom-in", GTK_STOCK_ZOOM_IN, N_ ("Zoom I_n"), "<control>plus", N_ ("Show the contents in more detail"), G_CALLBACK (thunar_window_action_zoom_in), },
 
363
  { "zoom-out", GTK_STOCK_ZOOM_OUT, N_ ("Zoom _Out"), "<control>minus", N_ ("Show the contents in less detail"), G_CALLBACK (thunar_window_action_zoom_out), },
 
364
  { "zoom-reset", GTK_STOCK_ZOOM_100, N_ ("Normal Si_ze"), "<control>0", N_ ("Show the contents at the normal size"), G_CALLBACK (thunar_window_action_zoom_reset), },
 
365
  { "go-menu", NULL, N_ ("_Go"), NULL, },
 
366
  { "open-parent", GTK_STOCK_GO_UP, N_ ("Open _Parent"), "<alt>Up", N_ ("Open the parent folder"), G_CALLBACK (thunar_window_action_go_up), },
 
367
  { "open-home", GTK_STOCK_HOME, N_ ("_Home"), "<alt>Home", N_ ("Go to the home folder"), G_CALLBACK (thunar_window_action_open_home), },
 
368
  { "open-desktop", THUNAR_STOCK_DESKTOP, N_ ("Desktop"), NULL, N_ ("Go to the desktop folder"), G_CALLBACK (thunar_window_action_open_desktop), },
 
369
  { "open-file-system", GTK_STOCK_HARDDISK, N_ ("File System"), NULL, N_ ("Browse the file system"), G_CALLBACK (thunar_window_action_open_file_system), },
 
370
  { "open-network", GTK_STOCK_NETWORK, N_("B_rowse Network"), NULL, N_ ("Browse local network connections"), G_CALLBACK (thunar_window_action_open_network), },
 
371
  { "open-templates", THUNAR_STOCK_TEMPLATES, N_("T_emplates"), NULL, N_ ("Go to the templates folder"), G_CALLBACK (thunar_window_action_open_templates), },
 
372
  { "open-location", NULL, N_ ("_Open Location..."), "<control>L", N_ ("Specify a location to open"), G_CALLBACK (thunar_window_action_open_location), },
 
373
  { "help-menu", NULL, N_ ("_Help"), NULL, },
 
374
  { "contents", GTK_STOCK_HELP, N_ ("_Contents"), "F1", N_ ("Display Thunar user manual"), G_CALLBACK (thunar_window_action_contents), },
 
375
  { "about", GTK_STOCK_ABOUT, N_ ("_About"), NULL, N_ ("Display information about Thunar"), G_CALLBACK (thunar_window_action_about), },
 
376
};
 
377
 
 
378
static const GtkToggleActionEntry toggle_action_entries[] =
 
379
{
 
380
  { "show-hidden", NULL, N_ ("Show _Hidden Files"), "<control>H", N_ ("Toggles the display of hidden files in the current window"), G_CALLBACK (thunar_window_action_show_hidden), FALSE, },
 
381
  { "view-location-selector-pathbar", NULL, N_ ("_Pathbar Style"), NULL, N_ ("Modern approach with buttons that correspond to folders"), G_CALLBACK (thunar_window_action_pathbar_changed), FALSE, },
 
382
  { "view-location-selector-toolbar", NULL, N_ ("_Toolbar Style"), NULL, N_ ("Traditional approach with location bar and navigation buttons"), G_CALLBACK (thunar_window_action_toolbar_changed), FALSE, },
 
383
  { "view-side-pane-shortcuts", NULL, N_ ("_Shortcuts"), "<control>B", N_ ("Toggles the visibility of the shortcuts pane"), G_CALLBACK (thunar_window_action_shortcuts_changed), FALSE, },
 
384
  { "view-side-pane-tree", NULL, N_ ("_Tree"), "<control>E", N_ ("Toggles the visibility of the tree pane"), G_CALLBACK (thunar_window_action_tree_changed), FALSE, },
 
385
  { "view-statusbar", NULL, N_ ("St_atusbar"), NULL, N_ ("Change the visibility of this window's statusbar"), G_CALLBACK (thunar_window_action_statusbar_changed), FALSE, },
 
386
  { "view-menubar", NULL, N_ ("_Menubar"), "<control>M", N_ ("Change the visibility of this window's menubar"), G_CALLBACK (thunar_window_action_menubar_changed), TRUE, },
 
387
};
 
388
 
 
389
 
 
390
 
 
391
static guint window_signals[LAST_SIGNAL];
 
392
 
 
393
 
 
394
 
 
395
G_DEFINE_TYPE_WITH_CODE (ThunarWindow, thunar_window, GTK_TYPE_WINDOW,
 
396
                         G_IMPLEMENT_INTERFACE (THUNAR_TYPE_BROWSER, NULL))
 
397
 
 
398
 
 
399
 
 
400
static void
 
401
thunar_window_class_init (ThunarWindowClass *klass)
 
402
{
 
403
  GtkWidgetClass *gtkwidget_class;
 
404
  GtkBindingSet  *binding_set;
 
405
  GObjectClass   *gobject_class;
 
406
  guint           i;
 
407
 
 
408
  gobject_class = G_OBJECT_CLASS (klass);
 
409
  gobject_class->dispose = thunar_window_dispose;
 
410
  gobject_class->finalize = thunar_window_finalize;
 
411
  gobject_class->get_property = thunar_window_get_property;
 
412
  gobject_class->set_property = thunar_window_set_property;
 
413
 
 
414
  gtkwidget_class = GTK_WIDGET_CLASS (klass);
 
415
  gtkwidget_class->realize = thunar_window_realize;
 
416
  gtkwidget_class->unrealize = thunar_window_unrealize;
 
417
  gtkwidget_class->configure_event = thunar_window_configure_event;
 
418
 
 
419
  klass->back = thunar_window_back;
 
420
  klass->reload = thunar_window_reload;
 
421
  klass->toggle_sidepane = thunar_window_toggle_sidepane;
 
422
  klass->toggle_menubar = thunar_window_toggle_menubar;
 
423
  klass->zoom_in = thunar_window_zoom_in;
 
424
  klass->zoom_out = thunar_window_zoom_out;
 
425
  klass->zoom_reset = thunar_window_zoom_reset;
 
426
  klass->tab_change = thunar_window_tab_change;
 
427
 
 
428
  /**
 
429
   * ThunarWindow:current-directory:
 
430
   *
 
431
   * The directory currently displayed within this #ThunarWindow
 
432
   * or %NULL.
 
433
   **/
 
434
  g_object_class_install_property (gobject_class,
 
435
                                   PROP_CURRENT_DIRECTORY,
 
436
                                   g_param_spec_object ("current-directory",
 
437
                                                        "current-directory",
 
438
                                                        "current-directory",
 
439
                                                        THUNAR_TYPE_FILE,
 
440
                                                        EXO_PARAM_READWRITE));
 
441
 
 
442
  /**
 
443
   * ThunarWindow:show-hidden:
 
444
   *
 
445
   * Whether to show hidden files in the current window.
 
446
   **/
 
447
  g_object_class_install_property (gobject_class,
 
448
                                   PROP_SHOW_HIDDEN,
 
449
                                   g_param_spec_boolean ("show-hidden",
 
450
                                                         "show-hidden",
 
451
                                                         "show-hidden",
 
452
                                                         FALSE,
 
453
                                                         EXO_PARAM_READABLE));
 
454
 
 
455
  /**
 
456
   * ThunarWindow:ui-manager:
 
457
   *
 
458
   * The #GtkUIManager used for this #ThunarWindow. This property
 
459
   * can only be read and is garantied to always contain a valid
 
460
   * #GtkUIManager instance (thus it's never %NULL).
 
461
   **/
 
462
  g_object_class_install_property (gobject_class,
 
463
                                   PROP_UI_MANAGER,
 
464
                                   g_param_spec_object ("ui-manager",
 
465
                                                        "ui-manager",
 
466
                                                        "ui-manager",
 
467
                                                        GTK_TYPE_UI_MANAGER,
 
468
                                                        EXO_PARAM_READABLE));
 
469
 
 
470
  /**
 
471
   * ThunarWindow:zoom-level:
 
472
   *
 
473
   * The #ThunarZoomLevel applied to the #ThunarView currently
 
474
   * shown within this window.
 
475
   **/
 
476
  g_object_class_install_property (gobject_class,
 
477
                                   PROP_ZOOM_LEVEL,
 
478
                                   g_param_spec_enum ("zoom-level",
 
479
                                                      "zoom-level",
 
480
                                                      "zoom-level",
 
481
                                                      THUNAR_TYPE_ZOOM_LEVEL,
 
482
                                                      THUNAR_ZOOM_LEVEL_NORMAL,
 
483
                                                      EXO_PARAM_READWRITE));
 
484
 
 
485
  /**
 
486
   * ThunarWindow::back:
 
487
   * @window : a #ThunarWindow instance.
 
488
   *
 
489
   * Emitted whenever the user requests to go to the
 
490
   * previous visited folder. This is an internal
 
491
   * signal used to bind the action to keys.
 
492
   **/
 
493
  window_signals[BACK] =
 
494
    g_signal_new (I_("back"),
 
495
                  G_TYPE_FROM_CLASS (klass),
 
496
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 
497
                  G_STRUCT_OFFSET (ThunarWindowClass, back),
 
498
                  g_signal_accumulator_true_handled, NULL,
 
499
                  _thunar_marshal_BOOLEAN__VOID,
 
500
                  G_TYPE_BOOLEAN, 0);
 
501
 
 
502
  /**
 
503
   * ThunarWindow::reload:
 
504
   * @window : a #ThunarWindow instance.
 
505
   *
 
506
   * Emitted whenever the user requests to reload the contents
 
507
   * of the currently displayed folder. This is an internal
 
508
   * signal used to bind the action to keys.
 
509
   **/
 
510
  window_signals[RELOAD] =
 
511
    g_signal_new (I_("reload"),
 
512
                  G_TYPE_FROM_CLASS (klass),
 
513
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 
514
                  G_STRUCT_OFFSET (ThunarWindowClass, reload),
 
515
                  g_signal_accumulator_true_handled, NULL,
 
516
                  _thunar_marshal_BOOLEAN__VOID,
 
517
                  G_TYPE_BOOLEAN, 0);
 
518
 
 
519
  /**
 
520
   * ThunarWindow::toggle-sidepane:
 
521
   * @window : a #ThunarWindow instance.
 
522
   *
 
523
   * Emitted whenever the user toggles the visibility of the
 
524
   * sidepane. This is an internal signal used to bind the
 
525
   * action to keys.
 
526
   **/
 
527
  window_signals[TOGGLE_SIDEPANE] =
 
528
    g_signal_new (I_("toggle-sidepane"),
 
529
                  G_TYPE_FROM_CLASS (klass),
 
530
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 
531
                  G_STRUCT_OFFSET (ThunarWindowClass, toggle_sidepane),
 
532
                  g_signal_accumulator_true_handled, NULL,
 
533
                  _thunar_marshal_BOOLEAN__VOID,
 
534
                  G_TYPE_BOOLEAN, 0);
 
535
 
 
536
  /**
 
537
   * ThunarWindow::toggle-sidepane:
 
538
   * @window : a #ThunarWindow instance.
 
539
   *
 
540
   * Emitted whenever the user toggles the visibility of the
 
541
   * sidepane. This is an internal signal used to bind the
 
542
   * action to keys.
 
543
   **/
 
544
  window_signals[TOGGLE_MENUBAR] =
 
545
    g_signal_new (I_("toggle-menubar"),
 
546
                  G_TYPE_FROM_CLASS (klass),
 
547
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 
548
                  G_STRUCT_OFFSET (ThunarWindowClass, toggle_menubar),
 
549
                  g_signal_accumulator_true_handled, NULL,
 
550
                  _thunar_marshal_BOOLEAN__VOID,
 
551
                  G_TYPE_BOOLEAN, 0);
 
552
 
 
553
  /**
 
554
   * ThunarWindow::zoom-in:
 
555
   * @window : a #ThunarWindow instance.
 
556
   *
 
557
   * Emitted whenever the user requests to zoom in. This
 
558
   * is an internal signal used to bind the action to keys.
 
559
   **/
 
560
  window_signals[ZOOM_IN] =
 
561
    g_signal_new (I_("zoom-in"),
 
562
                  G_TYPE_FROM_CLASS (klass),
 
563
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 
564
                  G_STRUCT_OFFSET (ThunarWindowClass, zoom_in),
 
565
                  g_signal_accumulator_true_handled, NULL,
 
566
                  _thunar_marshal_BOOLEAN__VOID,
 
567
                  G_TYPE_BOOLEAN, 0);
 
568
 
 
569
  /**
 
570
   * ThunarWindow::zoom-out:
 
571
   * @window : a #ThunarWindow instance.
 
572
   *
 
573
   * Emitted whenever the user requests to zoom out. This
 
574
   * is an internal signal used to bind the action to keys.
 
575
   **/
 
576
  window_signals[ZOOM_OUT] =
 
577
    g_signal_new (I_("zoom-out"),
 
578
                  G_TYPE_FROM_CLASS (klass),
 
579
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 
580
                  G_STRUCT_OFFSET (ThunarWindowClass, zoom_out),
 
581
                  g_signal_accumulator_true_handled, NULL,
 
582
                  _thunar_marshal_BOOLEAN__VOID,
 
583
                  G_TYPE_BOOLEAN, 0);
 
584
 
 
585
  /**
 
586
   * ThunarWindow::zoom-reset:
 
587
   * @window : a #ThunarWindow instance.
 
588
   *
 
589
   * Emitted whenever the user requests reset the zoom level.
 
590
   * This is an internal signal used to bind the action to keys.
 
591
   **/
 
592
  window_signals[ZOOM_RESET] =
 
593
    g_signal_new (I_("zoom-reset"),
 
594
                  G_TYPE_FROM_CLASS (klass),
 
595
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 
596
                  G_STRUCT_OFFSET (ThunarWindowClass, zoom_reset),
 
597
                  g_signal_accumulator_true_handled, NULL,
 
598
                  _thunar_marshal_BOOLEAN__VOID,
 
599
                  G_TYPE_BOOLEAN, 0);
 
600
 
 
601
  /**
 
602
   * ThunarWindow::tab-chage:
 
603
   * @window : a #ThunarWindow instance.
 
604
   * @idx    : tab index,
 
605
   *
 
606
   * Emitted whenever the user uses a Alt+N combination to
 
607
   * switch tabs.
 
608
   **/
 
609
  window_signals[TAB_CHANGE] =
 
610
    g_signal_new (I_("tab-change"),
 
611
                  G_TYPE_FROM_CLASS (klass),
 
612
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 
613
                  G_STRUCT_OFFSET (ThunarWindowClass, tab_change),
 
614
                  g_signal_accumulator_true_handled, NULL,
 
615
                  _thunar_marshal_BOOLEAN__INT,
 
616
                  G_TYPE_BOOLEAN, 1,
 
617
                  G_TYPE_INT);
 
618
 
 
619
  /* setup the key bindings for the windows */
 
620
  binding_set = gtk_binding_set_by_class (klass);
 
621
  gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "back", 0);
 
622
  gtk_binding_entry_add_signal (binding_set, GDK_F5, 0, "reload", 0);
 
623
  gtk_binding_entry_add_signal (binding_set, GDK_F9, 0, "toggle-sidepane", 0);
 
624
  gtk_binding_entry_add_signal (binding_set, GDK_F10, 0, "toggle-menubar", 0);
 
625
  gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_CONTROL_MASK, "zoom-in", 0);
 
626
  gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, GDK_CONTROL_MASK, "zoom-out", 0);
 
627
  gtk_binding_entry_add_signal (binding_set, GDK_KP_0, GDK_CONTROL_MASK, "zoom-reset", 0);
 
628
  gtk_binding_entry_add_signal (binding_set, GDK_KP_Insert, GDK_CONTROL_MASK, "zoom-reset", 0);
 
629
 
 
630
  /* setup the key bindings for Alt+N */
 
631
  for (i = 0; i < 10; i++)
 
632
    {
 
633
      gtk_binding_entry_add_signal (binding_set, GDK_0 + i, GDK_MOD1_MASK,
 
634
                                    "tab-change", 1, G_TYPE_UINT, i - 1);
 
635
    }
 
636
}
 
637
 
 
638
 
 
639
 
 
640
static inline gint
 
641
view_type2index (GType type)
 
642
{
 
643
  /* this necessary for platforms where sizeof(GType) != sizeof(gint),
 
644
   * see http://bugzilla.xfce.org/show_bug.cgi?id=2726 for details.
 
645
   */
 
646
  if (sizeof (GType) == sizeof (gint))
 
647
    {
 
648
      /* no need to map anything */
 
649
      return (gint) type;
 
650
    }
 
651
  else
 
652
    {
 
653
      /* map from types to unique indices */
 
654
      if (G_LIKELY (type == THUNAR_TYPE_COMPACT_VIEW))
 
655
        return 0;
 
656
      else if (type == THUNAR_TYPE_DETAILS_VIEW)
 
657
        return 1;
 
658
      else
 
659
        return 2;
 
660
    }
 
661
}
 
662
 
 
663
 
 
664
 
 
665
static inline GType
 
666
view_index2type (gint idx)
 
667
{
 
668
  /* this necessary for platforms where sizeof(GType) != sizeof(gint),
 
669
   * see http://bugzilla.xfce.org/show_bug.cgi?id=2726 for details.
 
670
   */
 
671
  if (sizeof (GType) == sizeof (gint))
 
672
    {
 
673
      /* no need to map anything */
 
674
      return (GType) idx;
 
675
    }
 
676
  else
 
677
    {
 
678
      /* map from indices to unique types */
 
679
      switch (idx)
 
680
        {
 
681
        case 0:  return THUNAR_TYPE_COMPACT_VIEW;
 
682
        case 1:  return THUNAR_TYPE_DETAILS_VIEW;
 
683
        default: return THUNAR_TYPE_ICON_VIEW;
 
684
        }
 
685
    }
 
686
}
 
687
 
 
688
 
 
689
 
 
690
static void
 
691
thunar_window_init (ThunarWindow *window)
 
692
{
 
693
  GtkRadioAction *radio_action;
 
694
  GtkAccelGroup  *accel_group;
 
695
  GtkWidget      *label;
 
696
  GtkWidget      *infobar;
 
697
  GtkWidget      *item;
 
698
  GtkAction      *action;
 
699
  gboolean        last_show_hidden;
 
700
  gboolean        last_menubar_visible;
 
701
  GSList         *group;
 
702
  gchar          *last_location_bar;
 
703
  gchar          *last_side_pane;
 
704
  GType           type;
 
705
  gint            last_separator_position;
 
706
  gint            last_window_width;
 
707
  gint            last_window_height;
 
708
  gboolean        last_window_maximized;
 
709
  gboolean        last_statusbar_visible;
 
710
  GtkRcStyle     *style;
 
711
 
 
712
  /* unset the view type */
 
713
  window->view_type = G_TYPE_NONE;
 
714
 
 
715
  /* grab a reference on the provider factory */
 
716
  window->provider_factory = thunarx_provider_factory_get_default ();
 
717
 
 
718
  /* grab a reference on the preferences */
 
719
  window->preferences = thunar_preferences_get ();
 
720
 
 
721
  /* get all properties for init */
 
722
  g_object_get (G_OBJECT (window->preferences),
 
723
                "last-show-hidden", &last_show_hidden,
 
724
                "last-window-width", &last_window_width,
 
725
                "last-window-height", &last_window_height,
 
726
                "last-window-maximized", &last_window_maximized,
 
727
                "last-menubar-visible", &last_menubar_visible,
 
728
                "last-separator-position", &last_separator_position,
 
729
                "last-location-bar", &last_location_bar,
 
730
                "last-side-pane", &last_side_pane,
 
731
                "last-statusbar-visible", &last_statusbar_visible,
 
732
                NULL);
 
733
 
 
734
  /* connect to the volume monitor */
 
735
  window->device_monitor = thunar_device_monitor_get ();
 
736
  g_signal_connect (window->device_monitor, "device-pre-unmount", G_CALLBACK (thunar_window_device_pre_unmount), window);
 
737
  g_signal_connect (window->device_monitor, "device-removed", G_CALLBACK (thunar_window_device_changed), window);
 
738
  g_signal_connect (window->device_monitor, "device-changed", G_CALLBACK (thunar_window_device_changed), window);
 
739
 
 
740
  /* allocate a closure for the menu_item_selected() callback */
 
741
  window->menu_item_selected_closure = g_cclosure_new_object (G_CALLBACK (thunar_window_menu_item_selected), G_OBJECT (window));
 
742
  g_closure_ref (window->menu_item_selected_closure);
 
743
  g_closure_sink (window->menu_item_selected_closure);
 
744
 
 
745
  /* allocate a closure for the menu_item_deselected() callback */
 
746
  window->menu_item_deselected_closure = g_cclosure_new_object (G_CALLBACK (thunar_window_menu_item_deselected), G_OBJECT (window));
 
747
  g_closure_ref (window->menu_item_deselected_closure);
 
748
  g_closure_sink (window->menu_item_deselected_closure);
 
749
  window->icon_factory = thunar_icon_factory_get_default ();
 
750
 
 
751
  /* setup the action group for this window */
 
752
  window->action_group = gtk_action_group_new ("ThunarWindow");
 
753
  gtk_action_group_set_translation_domain (window->action_group, GETTEXT_PACKAGE);
 
754
  gtk_action_group_add_actions (window->action_group, action_entries, G_N_ELEMENTS (action_entries), GTK_WIDGET (window));
 
755
  gtk_action_group_add_toggle_actions (window->action_group, toggle_action_entries, G_N_ELEMENTS (toggle_action_entries), GTK_WIDGET (window));
 
756
 
 
757
  /* initialize the "show-hidden" action using the last value from the preferences */
 
758
  action = gtk_action_group_get_action (window->action_group, "show-hidden");
 
759
  gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), last_show_hidden);
 
760
 
 
761
  /*
 
762
   * add view options
 
763
   */
 
764
  radio_action = gtk_radio_action_new ("view-as-icons", _("View as _Icons"), _("Display folder content in an icon view"),
 
765
                                       NULL, view_type2index (THUNAR_TYPE_ICON_VIEW));
 
766
  gtk_action_group_add_action_with_accel (window->action_group, GTK_ACTION (radio_action), "<control>1");
 
767
  gtk_radio_action_set_group (radio_action, NULL);
 
768
  group = gtk_radio_action_get_group (radio_action);
 
769
  g_object_unref (G_OBJECT (radio_action));
 
770
 
 
771
  radio_action = gtk_radio_action_new ("view-as-detailed-list", _("View as _Detailed List"), _("Display folder content in a detailed list view"),
 
772
                                       NULL, view_type2index (THUNAR_TYPE_DETAILS_VIEW));
 
773
  gtk_action_group_add_action_with_accel (window->action_group, GTK_ACTION (radio_action), "<control>2");
 
774
  gtk_radio_action_set_group (radio_action, group);
 
775
  group = gtk_radio_action_get_group (radio_action);
 
776
  g_object_unref (G_OBJECT (radio_action));
 
777
 
 
778
  radio_action = gtk_radio_action_new ("view-as-compact-list", _("View as _Compact List"), _("Display folder content in a compact list view"),
 
779
                                       NULL, view_type2index (THUNAR_TYPE_COMPACT_VIEW));
 
780
  gtk_action_group_add_action_with_accel (window->action_group, GTK_ACTION (radio_action), "<control>3");
 
781
  gtk_radio_action_set_group (radio_action, group);
 
782
  group = gtk_radio_action_get_group (radio_action);
 
783
  g_object_unref (G_OBJECT (radio_action));
 
784
 
 
785
  window->ui_manager = gtk_ui_manager_new ();
 
786
  g_signal_connect (G_OBJECT (window->ui_manager), "connect-proxy", G_CALLBACK (thunar_window_connect_proxy), window);
 
787
  g_signal_connect (G_OBJECT (window->ui_manager), "disconnect-proxy", G_CALLBACK (thunar_window_disconnect_proxy), window);
 
788
  gtk_ui_manager_insert_action_group (window->ui_manager, window->action_group, 0);
 
789
  gtk_ui_manager_add_ui_from_string (window->ui_manager, thunar_window_ui, thunar_window_ui_length, NULL);
 
790
 
 
791
  accel_group = gtk_ui_manager_get_accel_group (window->ui_manager);
 
792
  gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
 
793
 
 
794
  /* setup the launcher support */
 
795
  window->launcher = thunar_launcher_new ();
 
796
  thunar_launcher_set_widget (window->launcher, GTK_WIDGET (window));
 
797
  thunar_component_set_ui_manager (THUNAR_COMPONENT (window->launcher), window->ui_manager);
 
798
  exo_binding_new (G_OBJECT (window), "current-directory", G_OBJECT (window->launcher), "current-directory");
 
799
  g_signal_connect_swapped (G_OBJECT (window->launcher), "change-directory", G_CALLBACK (thunar_window_set_current_directory), window);
 
800
  g_signal_connect_swapped (G_OBJECT (window->launcher), "open-new-tab", G_CALLBACK (thunar_window_notebook_insert), window);
 
801
 
 
802
  /* determine the default window size from the preferences */
 
803
  gtk_window_set_default_size (GTK_WINDOW (window), last_window_width, last_window_height);
 
804
 
 
805
  /* restore the maxized state of the window */
 
806
  if (G_UNLIKELY (last_window_maximized))
 
807
    gtk_window_maximize (GTK_WINDOW (window));
 
808
 
 
809
  window->table = gtk_table_new (6, 1, FALSE);
 
810
  gtk_container_add (GTK_CONTAINER (window), window->table);
 
811
  gtk_widget_show (window->table);
 
812
 
 
813
  window->menubar = gtk_ui_manager_get_widget (window->ui_manager, "/main-menu");
 
814
  gtk_table_attach (GTK_TABLE (window->table), window->menubar, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
 
815
 
 
816
  /* update menubar visibiliy */
 
817
  action = gtk_action_group_get_action (window->action_group, "view-menubar");
 
818
  g_signal_connect (G_OBJECT (window->menubar), "deactivate", G_CALLBACK (thunar_window_toggle_menubar_deactivate), window);
 
819
  gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), last_menubar_visible);
 
820
 
 
821
  /* append the menu item for the spinner */
 
822
  item = gtk_menu_item_new ();
 
823
  gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE);
 
824
  gtk_menu_item_set_right_justified (GTK_MENU_ITEM (item), TRUE);
 
825
  gtk_menu_shell_append (GTK_MENU_SHELL (window->menubar), item);
 
826
  gtk_widget_show (item);
 
827
 
 
828
  /* place the spinner into the menu item */
 
829
  window->spinner = gtk_spinner_new ();
 
830
  gtk_container_add (GTK_CONTAINER (item), window->spinner);
 
831
  exo_binding_new (G_OBJECT (window->spinner), "active",
 
832
                   G_OBJECT (window->spinner), "visible");
 
833
 
 
834
  /* check if we need to add the root warning */
 
835
  if (G_UNLIKELY (geteuid () == 0))
 
836
    {
 
837
      /* add the bar for the root warning */
 
838
      infobar = gtk_info_bar_new ();
 
839
      gtk_info_bar_set_message_type (GTK_INFO_BAR (infobar), GTK_MESSAGE_WARNING);
 
840
      gtk_table_attach (GTK_TABLE (window->table), infobar, 0, 1, 2, 3, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
 
841
      gtk_widget_show (infobar);
 
842
 
 
843
      /* add the label with the root warning */
 
844
      label = gtk_label_new (_("Warning, you are using the root account, you may harm your system."));
 
845
      gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (infobar))), label);
 
846
      gtk_widget_show (label);
 
847
    }
 
848
 
 
849
  window->paned = gtk_hpaned_new ();
 
850
  gtk_container_set_border_width (GTK_CONTAINER (window->paned), 0);
 
851
  gtk_table_attach (GTK_TABLE (window->table), window->paned, 0, 1, 4, 5, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
 
852
  gtk_widget_show (window->paned);
 
853
 
 
854
  /* determine the last separator position and apply it to the paned view */
 
855
  gtk_paned_set_position (GTK_PANED (window->paned), last_separator_position);
 
856
  g_signal_connect_swapped (window->paned, "accept-position", G_CALLBACK (thunar_window_save_paned), window);
 
857
  g_signal_connect_swapped (window->paned, "button-release-event", G_CALLBACK (thunar_window_save_paned), window);
 
858
 
 
859
  window->view_box = gtk_table_new (3, 1, FALSE);
 
860
  gtk_paned_pack2 (GTK_PANED (window->paned), window->view_box, TRUE, FALSE);
 
861
  gtk_widget_show (window->view_box);
 
862
 
 
863
  /* tabs */
 
864
  window->notebook = gtk_notebook_new ();
 
865
  gtk_table_attach (GTK_TABLE (window->view_box), window->notebook, 0, 1, 1, 2, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
 
866
  g_signal_connect (G_OBJECT (window->notebook), "switch-page", G_CALLBACK (thunar_window_notebook_switch_page), window);
 
867
  g_signal_connect (G_OBJECT (window->notebook), "page-added", G_CALLBACK (thunar_window_notebook_page_added), window);
 
868
  g_signal_connect (G_OBJECT (window->notebook), "page-removed", G_CALLBACK (thunar_window_notebook_page_removed), window);
 
869
  g_signal_connect_after (G_OBJECT (window->notebook), "button-press-event", G_CALLBACK (thunar_window_notebook_button_press_event), window);
 
870
  g_signal_connect (G_OBJECT (window->notebook), "popup-menu", G_CALLBACK (thunar_window_notebook_popup_menu), window);
 
871
  g_signal_connect (G_OBJECT (window->notebook), "create-window", G_CALLBACK (thunar_window_notebook_create_window), window);
 
872
  gtk_notebook_set_show_border (GTK_NOTEBOOK (window->notebook), FALSE);
 
873
  gtk_notebook_set_homogeneous_tabs (GTK_NOTEBOOK (window->notebook), TRUE);
 
874
  gtk_notebook_set_scrollable (GTK_NOTEBOOK (window->notebook), TRUE);
 
875
  gtk_container_set_border_width (GTK_CONTAINER (window->notebook), 0);
 
876
  gtk_notebook_set_group_name (GTK_NOTEBOOK (window->notebook), "thunar-tabs");
 
877
  gtk_widget_show (window->notebook);
 
878
 
 
879
  /* drop the notebook borders */
 
880
  style = gtk_rc_style_new ();
 
881
  style->xthickness = style->ythickness = 0;
 
882
  gtk_widget_modify_style (window->notebook, style);
 
883
  g_object_unref (G_OBJECT (style));
 
884
 
 
885
  /* determine the selected location selector */
 
886
  if (exo_str_is_equal (last_location_bar, g_type_name (THUNAR_TYPE_LOCATION_BUTTONS)))
 
887
    type = THUNAR_TYPE_LOCATION_BUTTONS;
 
888
  else if (exo_str_is_equal (last_location_bar, g_type_name (THUNAR_TYPE_LOCATION_ENTRY)))
 
889
    type = THUNAR_TYPE_LOCATION_ENTRY;
 
890
  else
 
891
    type = G_TYPE_NONE;
 
892
  g_free (last_location_bar);
 
893
 
 
894
  /* activate the selected location selector */
 
895
  action = gtk_action_group_get_action (window->action_group, "view-location-selector-pathbar");
 
896
  gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), (type == THUNAR_TYPE_LOCATION_BUTTONS));
 
897
  action = gtk_action_group_get_action (window->action_group, "view-location-selector-toolbar");
 
898
  gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), (type == THUNAR_TYPE_LOCATION_ENTRY));
 
899
 
 
900
  /* determine the selected side pane (FIXME: Should probably be last-shortcuts-visible and last-tree-visible preferences) */
 
901
  if (exo_str_is_equal (last_side_pane, g_type_name (THUNAR_TYPE_SHORTCUTS_PANE)))
 
902
    type = THUNAR_TYPE_SHORTCUTS_PANE;
 
903
  else if (exo_str_is_equal (last_side_pane, g_type_name (THUNAR_TYPE_TREE_PANE)))
 
904
    type = THUNAR_TYPE_TREE_PANE;
 
905
  else
 
906
    type = G_TYPE_NONE;
 
907
  g_free (last_side_pane);
 
908
 
 
909
  /* activate the selected side pane */
 
910
  action = gtk_action_group_get_action (window->action_group, "view-side-pane-shortcuts");
 
911
  gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), (type == THUNAR_TYPE_SHORTCUTS_PANE));
 
912
  action = gtk_action_group_get_action (window->action_group, "view-side-pane-tree");
 
913
  gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), (type == THUNAR_TYPE_TREE_PANE));
 
914
 
 
915
  /* check if we should display the statusbar by default */
 
916
  action = gtk_action_group_get_action (window->action_group, "view-statusbar");
 
917
  gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), last_statusbar_visible);
 
918
 
 
919
  /* connect signal */
 
920
  action = gtk_action_group_get_action (window->action_group, "view-as-icons");
 
921
  g_signal_connect (G_OBJECT (action), "changed", G_CALLBACK (thunar_window_action_view_changed), window);
 
922
 
 
923
  /* schedule asynchronous menu action merging */
 
924
  window->merge_idle_id = g_idle_add_full (G_PRIORITY_LOW + 20, thunar_window_merge_idle, window, thunar_window_merge_idle_destroy);
 
925
}
 
926
 
 
927
 
 
928
 
 
929
static void
 
930
thunar_window_dispose (GObject *object)
 
931
{
 
932
  ThunarWindow *window = THUNAR_WINDOW (object);
 
933
 
 
934
  /* destroy the save geometry timer source */
 
935
  if (G_UNLIKELY (window->save_geometry_timer_id != 0))
 
936
    g_source_remove (window->save_geometry_timer_id);
 
937
 
 
938
  /* destroy the merge idle source */
 
939
  if (G_UNLIKELY (window->merge_idle_id != 0))
 
940
    g_source_remove (window->merge_idle_id);
 
941
 
 
942
  /* un-merge the custom preferences */
 
943
  if (G_LIKELY (window->custom_preferences_merge_id != 0))
 
944
    {
 
945
      gtk_ui_manager_remove_ui (window->ui_manager, window->custom_preferences_merge_id);
 
946
      window->custom_preferences_merge_id = 0;
 
947
    }
 
948
 
 
949
  /* un-merge the go menu actions */
 
950
  if (G_LIKELY (window->go_items_actions_merge_id != 0))
 
951
    {
 
952
      gtk_ui_manager_remove_ui (window->ui_manager, window->go_items_actions_merge_id);
 
953
      window->go_items_actions_merge_id = 0;
 
954
    }
 
955
 
 
956
  /* un-merge the bookmark actions */
 
957
  if (G_LIKELY (window->bookmark_items_actions_merge_id != 0))
 
958
    {
 
959
      gtk_ui_manager_remove_ui (window->ui_manager, window->bookmark_items_actions_merge_id);
 
960
      window->bookmark_items_actions_merge_id = 0;
 
961
    }
 
962
 
 
963
  if (window->bookmark_reload_idle_id != 0)
 
964
    {
 
965
      g_source_remove (window->bookmark_reload_idle_id);
 
966
      window->bookmark_reload_idle_id = 0;
 
967
    }
 
968
 
 
969
  /* disconnect from the current-directory */
 
970
  thunar_window_set_current_directory (window, NULL);
 
971
 
 
972
  (*G_OBJECT_CLASS (thunar_window_parent_class)->dispose) (object);
 
973
}
 
974
 
 
975
 
 
976
 
 
977
static void
 
978
thunar_window_finalize (GObject *object)
 
979
{
 
980
  ThunarWindow *window = THUNAR_WINDOW (object);
 
981
 
 
982
  /* drop our references on the menu_item_selected()/menu_item_deselected() closures */
 
983
  g_closure_unref (window->menu_item_deselected_closure);
 
984
  g_closure_unref (window->menu_item_selected_closure);
 
985
 
 
986
  /* disconnect from the volume monitor */
 
987
  g_signal_handlers_disconnect_matched (window->device_monitor, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, window);
 
988
  g_object_unref (window->device_monitor);
 
989
 
 
990
  /* disconnect from the ui manager */
 
991
  g_signal_handlers_disconnect_matched (window->ui_manager, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, window);
 
992
  g_object_unref (window->ui_manager);
 
993
 
 
994
  /* release the custom actions */
 
995
  if (window->custom_actions != NULL)
 
996
    g_object_unref (window->custom_actions);
 
997
 
 
998
  g_object_unref (window->action_group);
 
999
  g_object_unref (window->icon_factory);
 
1000
  g_object_unref (window->launcher);
 
1001
 
 
1002
  if (window->bookmark_action_group != NULL)
 
1003
    g_object_unref (window->bookmark_action_group);
 
1004
 
 
1005
  if (window->bookmark_file != NULL)
 
1006
    g_object_unref (window->bookmark_file);
 
1007
 
 
1008
  if (window->bookmark_monitor != NULL)
 
1009
    {
 
1010
      g_file_monitor_cancel (window->bookmark_monitor);
 
1011
      g_object_unref (window->bookmark_monitor);
 
1012
    }
 
1013
 
 
1014
  /* release our reference on the provider factory */
 
1015
  g_object_unref (window->provider_factory);
 
1016
 
 
1017
  /* release the preferences reference */
 
1018
  g_object_unref (window->preferences);
 
1019
 
 
1020
  (*G_OBJECT_CLASS (thunar_window_parent_class)->finalize) (object);
 
1021
}
 
1022
 
 
1023
 
 
1024
 
 
1025
static void
 
1026
thunar_window_get_property (GObject    *object,
 
1027
                            guint       prop_id,
 
1028
                            GValue     *value,
 
1029
                            GParamSpec *pspec)
 
1030
{
 
1031
  ThunarWindow *window = THUNAR_WINDOW (object);
 
1032
  GtkAction    *action;
 
1033
 
 
1034
  switch (prop_id)
 
1035
    {
 
1036
    case PROP_CURRENT_DIRECTORY:
 
1037
      g_value_set_object (value, thunar_window_get_current_directory (window));
 
1038
      break;
 
1039
 
 
1040
    case PROP_SHOW_HIDDEN:
 
1041
      action = gtk_action_group_get_action (window->action_group, "show-hidden");
 
1042
      g_value_set_boolean (value, gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
 
1043
      break;
 
1044
 
 
1045
    case PROP_UI_MANAGER:
 
1046
      g_value_set_object (value, window->ui_manager);
 
1047
      break;
 
1048
 
 
1049
    case PROP_ZOOM_LEVEL:
 
1050
      g_value_set_enum (value, window->zoom_level);
 
1051
      break;
 
1052
 
 
1053
    default:
 
1054
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
1055
      break;
 
1056
    }
 
1057
}
 
1058
 
 
1059
 
 
1060
 
 
1061
static void
 
1062
thunar_window_set_property (GObject            *object,
 
1063
                            guint               prop_id,
 
1064
                            const GValue       *value,
 
1065
                            GParamSpec         *pspec)
 
1066
{
 
1067
  ThunarWindow *window = THUNAR_WINDOW (object);
 
1068
 
 
1069
  switch (prop_id)
 
1070
    {
 
1071
    case PROP_CURRENT_DIRECTORY:
 
1072
      thunar_window_set_current_directory (window, g_value_get_object (value));
 
1073
      break;
 
1074
 
 
1075
    case PROP_ZOOM_LEVEL:
 
1076
      thunar_window_set_zoom_level (window, g_value_get_enum (value));
 
1077
      break;
 
1078
 
 
1079
    default:
 
1080
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
1081
      break;
 
1082
    }
 
1083
}
 
1084
 
 
1085
 
 
1086
 
 
1087
static gboolean
 
1088
thunar_window_back (ThunarWindow *window)
 
1089
{
 
1090
  GtkAction   *action;
 
1091
  GdkEvent    *event;
 
1092
  const gchar *accel_path;
 
1093
  GtkAccelKey  key;
 
1094
 
 
1095
  _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
 
1096
 
 
1097
  /* check source event */
 
1098
  event = gtk_get_current_event ();
 
1099
  if (event != NULL
 
1100
      && event->type == GDK_KEY_PRESS)
 
1101
    {
 
1102
      action = thunar_gtk_ui_manager_get_action_by_name (window->ui_manager, "open-parent");
 
1103
      if (G_LIKELY (action != NULL))
 
1104
        {
 
1105
          /* check if the current event (back) is different then the open-parent
 
1106
           * accelerator. this way a user can override the default backspace action
 
1107
           * of back in open-parent, without backspace resulting in a back action
 
1108
           * if open-parent is insensitive in the menu */
 
1109
          accel_path = gtk_action_get_accel_path (action);
 
1110
          if (accel_path != NULL
 
1111
              && gtk_accel_map_lookup_entry (accel_path, &key)
 
1112
              && key.accel_key == ((GdkEventKey *) event)->keyval
 
1113
              && key.accel_mods == 0)
 
1114
            return FALSE;
 
1115
        }
 
1116
    }
 
1117
 
 
1118
  /* activate the "back" action */
 
1119
  action = thunar_gtk_ui_manager_get_action_by_name (window->ui_manager, "back");
 
1120
  if (G_LIKELY (action != NULL))
 
1121
    {
 
1122
      gtk_action_activate (action);
 
1123
      return TRUE;
 
1124
    }
 
1125
 
 
1126
  return FALSE;
 
1127
}
 
1128
 
 
1129
 
 
1130
 
 
1131
static gboolean
 
1132
thunar_window_reload (ThunarWindow *window)
 
1133
{
 
1134
  _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
 
1135
 
 
1136
  /* force the view to reload */
 
1137
  if (G_LIKELY (window->view != NULL))
 
1138
    {
 
1139
      thunar_view_reload (THUNAR_VIEW (window->view));
 
1140
      return TRUE;
 
1141
    }
 
1142
 
 
1143
  return FALSE;
 
1144
}
 
1145
 
 
1146
 
 
1147
 
 
1148
static gboolean
 
1149
thunar_window_toggle_sidepane (ThunarWindow *window)
 
1150
{
 
1151
  GtkAction *action;
 
1152
  gchar     *type_name;
 
1153
 
 
1154
  _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
 
1155
 
 
1156
  /* check if a side pane is currently active */
 
1157
  if (G_LIKELY (window->sidepane != NULL))
 
1158
    {
 
1159
      /* determine the currently active side pane type */
 
1160
      window->toggle_sidepane_type = G_OBJECT_TYPE (window->sidepane);
 
1161
 
 
1162
      /* just reset both side pane actions */
 
1163
      action = gtk_action_group_get_action (window->action_group, "view-side-pane-shortcuts");
 
1164
      gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
 
1165
      action = gtk_action_group_get_action (window->action_group, "view-side-pane-tree");
 
1166
      gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
 
1167
    }
 
1168
  else
 
1169
    {
 
1170
      /* check if we have a previously remembered toggle type */
 
1171
      if (G_UNLIKELY (window->toggle_sidepane_type == G_TYPE_INVALID))
 
1172
        {
 
1173
          /* guess type based on the last-side-pane preference, default to shortcuts */
 
1174
          g_object_get (G_OBJECT (window->preferences), "last-side-pane", &type_name, NULL);
 
1175
          if (exo_str_is_equal (type_name, g_type_name (THUNAR_TYPE_TREE_PANE)))
 
1176
            window->toggle_sidepane_type = THUNAR_TYPE_TREE_PANE;
 
1177
          else
 
1178
            window->toggle_sidepane_type = THUNAR_TYPE_SHORTCUTS_PANE;
 
1179
          g_free (type_name);
 
1180
        }
 
1181
 
 
1182
      /* activate the given side pane */
 
1183
      action = gtk_action_group_get_action (window->action_group, "view-side-pane-shortcuts");
 
1184
      gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), (window->toggle_sidepane_type == THUNAR_TYPE_SHORTCUTS_PANE));
 
1185
      action = gtk_action_group_get_action (window->action_group, "view-side-pane-tree");
 
1186
      gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), (window->toggle_sidepane_type == THUNAR_TYPE_TREE_PANE));
 
1187
    }
 
1188
 
 
1189
  return TRUE;
 
1190
}
 
1191
 
 
1192
 
 
1193
 
 
1194
static gboolean
 
1195
thunar_window_toggle_menubar (ThunarWindow *window)
 
1196
{
 
1197
  _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
 
1198
 
 
1199
  if (!gtk_widget_get_visible (window->menubar))
 
1200
    {
 
1201
      /* temporarily show menu bar */
 
1202
      gtk_widget_show (window->menubar);
 
1203
      return TRUE;
 
1204
    }
 
1205
 
 
1206
  return FALSE;
 
1207
}
 
1208
 
 
1209
 
 
1210
 
 
1211
static void
 
1212
thunar_window_toggle_menubar_deactivate (GtkWidget    *menubar,
 
1213
                                         ThunarWindow *window)
 
1214
{
 
1215
  GtkAction *action;
 
1216
 
 
1217
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
1218
  _thunar_return_if_fail (window->menubar == menubar);
 
1219
 
 
1220
  /* this was a temporarily show, hide the bar */
 
1221
  action = gtk_action_group_get_action (window->action_group, "view-menubar");
 
1222
  if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
 
1223
    gtk_widget_hide (menubar);
 
1224
}
 
1225
 
 
1226
 
 
1227
 
 
1228
static gboolean
 
1229
thunar_window_zoom_in (ThunarWindow *window)
 
1230
{
 
1231
  _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
 
1232
 
 
1233
  /* check if we can still zoom in */
 
1234
  if (G_LIKELY (window->zoom_level < THUNAR_ZOOM_N_LEVELS - 1))
 
1235
    {
 
1236
      thunar_window_set_zoom_level (window, window->zoom_level + 1);
 
1237
      return TRUE;
 
1238
    }
 
1239
 
 
1240
  return FALSE;
 
1241
}
 
1242
 
 
1243
 
 
1244
 
 
1245
static gboolean
 
1246
thunar_window_zoom_out (ThunarWindow *window)
 
1247
{
 
1248
  _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
 
1249
 
 
1250
  /* check if we can still zoom out */
 
1251
  if (G_LIKELY (window->zoom_level > 0))
 
1252
    {
 
1253
      thunar_window_set_zoom_level (window, window->zoom_level - 1);
 
1254
      return TRUE;
 
1255
    }
 
1256
 
 
1257
  return FALSE;
 
1258
}
 
1259
 
 
1260
 
 
1261
 
 
1262
static gboolean
 
1263
thunar_window_zoom_reset (ThunarWindow *window)
 
1264
{
 
1265
  _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
 
1266
 
 
1267
  /* tell the view to reset it's zoom level */
 
1268
  if (G_LIKELY (window->view != NULL))
 
1269
    {
 
1270
      thunar_view_reset_zoom_level (THUNAR_VIEW (window->view));
 
1271
      return TRUE;
 
1272
    }
 
1273
 
 
1274
  return FALSE;
 
1275
}
 
1276
 
 
1277
 
 
1278
 
 
1279
static gboolean
 
1280
thunar_window_tab_change (ThunarWindow *window,
 
1281
                          gint          nth)
 
1282
{
 
1283
  _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
 
1284
 
 
1285
  /* Alt+0 is 10th tab */
 
1286
  gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook),
 
1287
                                 nth == -1 ? 8 : nth);
 
1288
 
 
1289
  return TRUE;
 
1290
}
 
1291
 
 
1292
 
 
1293
 
 
1294
static void
 
1295
thunar_window_realize (GtkWidget *widget)
 
1296
{
 
1297
  ThunarWindow *window = THUNAR_WINDOW (widget);
 
1298
 
 
1299
  /* let the GtkWidget class perform the realize operation */
 
1300
  (*GTK_WIDGET_CLASS (thunar_window_parent_class)->realize) (widget);
 
1301
 
 
1302
  /* connect to the clipboard manager of the new display and be sure to redraw the window
 
1303
   * whenever the clipboard contents change to make sure we always display up2date state.
 
1304
   */
 
1305
  window->clipboard = thunar_clipboard_manager_get_for_display (gtk_widget_get_display (widget));
 
1306
  g_signal_connect_swapped (G_OBJECT (window->clipboard), "changed",
 
1307
                            G_CALLBACK (gtk_widget_queue_draw), widget);
 
1308
}
 
1309
 
 
1310
 
 
1311
 
 
1312
static void
 
1313
thunar_window_unrealize (GtkWidget *widget)
 
1314
{
 
1315
  ThunarWindow *window = THUNAR_WINDOW (widget);
 
1316
 
 
1317
  /* disconnect from the clipboard manager */
 
1318
  g_signal_handlers_disconnect_by_func (G_OBJECT (window->clipboard), gtk_widget_queue_draw, widget);
 
1319
  g_object_unref (G_OBJECT (window->clipboard));
 
1320
 
 
1321
  /* let the GtkWidget class unrealize the window */
 
1322
  (*GTK_WIDGET_CLASS (thunar_window_parent_class)->unrealize) (widget);
 
1323
}
 
1324
 
 
1325
 
 
1326
 
 
1327
static gboolean
 
1328
thunar_window_configure_event (GtkWidget         *widget,
 
1329
                               GdkEventConfigure *event)
 
1330
{
 
1331
  ThunarWindow *window = THUNAR_WINDOW (widget);
 
1332
 
 
1333
  /* check if we have a new dimension here */
 
1334
  if (widget->allocation.width != event->width || widget->allocation.height != event->height)
 
1335
    {
 
1336
      /* drop any previous timer source */
 
1337
      if (window->save_geometry_timer_id != 0)
 
1338
        g_source_remove (window->save_geometry_timer_id);
 
1339
 
 
1340
      /* check if we should schedule another save timer */
 
1341
      if (gtk_widget_get_visible (widget))
 
1342
        {
 
1343
          /* save the geometry one second after the last configure event */
 
1344
          window->save_geometry_timer_id = g_timeout_add_seconds_full (G_PRIORITY_LOW, 1, thunar_window_save_geometry_timer,
 
1345
                                                                       window, thunar_window_save_geometry_timer_destroy);
 
1346
        }
 
1347
    }
 
1348
 
 
1349
  /* let Gtk+ handle the configure event */
 
1350
  return (*GTK_WIDGET_CLASS (thunar_window_parent_class)->configure_event) (widget, event);
 
1351
}
 
1352
 
 
1353
 
 
1354
 
 
1355
static void
 
1356
thunar_window_binding_destroyed (gpointer data,
 
1357
                                 GObject  *binding)
 
1358
{
 
1359
  ThunarWindow *window = THUNAR_WINDOW (data);
 
1360
 
 
1361
  if (window->view_bindings != NULL)
 
1362
    window->view_bindings = g_slist_remove (window->view_bindings, binding);
 
1363
}
 
1364
 
 
1365
 
 
1366
 
 
1367
static void
 
1368
thunar_window_binding_create (ThunarWindow *window,
 
1369
                              gpointer src_object,
 
1370
                              const gchar *src_prop,
 
1371
                              gpointer dst_object,
 
1372
                              const gchar *dst_prop,
 
1373
                              GBindingFlags flags)
 
1374
{
 
1375
  GBinding *binding;
 
1376
 
 
1377
  _thunar_return_if_fail (G_IS_OBJECT (src_object));
 
1378
  _thunar_return_if_fail (G_IS_OBJECT (dst_object));
 
1379
 
 
1380
  binding = g_object_bind_property (G_OBJECT (src_object), src_prop,
 
1381
                                    G_OBJECT (dst_object), dst_prop,
 
1382
                                    flags);
 
1383
 
 
1384
  g_object_weak_ref (G_OBJECT (binding), thunar_window_binding_destroyed, window);
 
1385
  window->view_bindings = g_slist_prepend (window->view_bindings, binding);
 
1386
}
 
1387
 
 
1388
 
 
1389
 
 
1390
static void
 
1391
thunar_window_notebook_switch_page (GtkWidget    *notebook,
 
1392
                                    GtkWidget    *page,
 
1393
                                    guint         page_num,
 
1394
                                    ThunarWindow *window)
 
1395
{
 
1396
  GtkAction  *action;
 
1397
  GSList     *view_bindings;
 
1398
  ThunarFile *current_directory;
 
1399
 
 
1400
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
1401
  _thunar_return_if_fail (GTK_IS_NOTEBOOK (notebook));
 
1402
  _thunar_return_if_fail (THUNAR_IS_VIEW (page));
 
1403
  _thunar_return_if_fail (window->notebook == notebook);
 
1404
 
 
1405
  /* leave if nothing changed */
 
1406
  if (window->view == page)
 
1407
    return;
 
1408
 
 
1409
  if (G_LIKELY (window->view != NULL))
 
1410
    {
 
1411
      /* unregisters the actions from the ui */
 
1412
      thunar_component_set_ui_manager (THUNAR_COMPONENT (window->view), NULL);
 
1413
 
 
1414
      /* unset view during switch */
 
1415
      window->view = NULL;
 
1416
    }
 
1417
 
 
1418
  /* disconnect existing bindings */
 
1419
  view_bindings = window->view_bindings;
 
1420
  window->view_bindings = NULL;
 
1421
  g_slist_free_full (view_bindings, g_object_unref);
 
1422
 
 
1423
  /* update the directory of the current window */
 
1424
  current_directory = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (page));
 
1425
  thunar_window_set_current_directory (window, current_directory);
 
1426
 
 
1427
  /* activate the selected view */
 
1428
  action = gtk_action_group_get_action (window->action_group, "view-as-icons");
 
1429
  g_signal_handlers_block_by_func (action, thunar_window_action_view_changed, window);
 
1430
  gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), view_type2index (G_OBJECT_TYPE (page)));
 
1431
  g_signal_handlers_unblock_by_func (action, thunar_window_action_view_changed, window);
 
1432
 
 
1433
  /* add stock bindings */
 
1434
  thunar_window_binding_create (window, window, "current-directory", page, "current-directory", G_BINDING_DEFAULT);
 
1435
  thunar_window_binding_create (window, window, "show-hidden", page, "show-hidden", G_BINDING_SYNC_CREATE);
 
1436
  thunar_window_binding_create (window, page, "loading", window->spinner, "active", G_BINDING_SYNC_CREATE);
 
1437
  thunar_window_binding_create (window, page, "selected-files", window->launcher, "selected-files", G_BINDING_SYNC_CREATE);
 
1438
  thunar_window_binding_create (window, page, "zoom-level", window, "zoom-level", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
 
1439
 
 
1440
  /* connect to the location bar (if any) */
 
1441
  if (G_LIKELY (window->location_bar != NULL))
 
1442
    {
 
1443
      thunar_window_binding_create (window, page, "selected-files",
 
1444
                                    window->location_bar, "selected-files",
 
1445
                                    G_BINDING_SYNC_CREATE);
 
1446
    }
 
1447
 
 
1448
  /* connect to the sidepane (if any) */
 
1449
  if (G_LIKELY (window->sidepane != NULL))
 
1450
    {
 
1451
      thunar_window_binding_create (window, page, "selected-files",
 
1452
                                    window->sidepane, "selected-files",
 
1453
                                    G_BINDING_SYNC_CREATE);
 
1454
    }
 
1455
 
 
1456
  /* connect to the statusbar (if any) */
 
1457
  if (G_LIKELY (window->statusbar != NULL))
 
1458
    {
 
1459
      thunar_window_binding_create (window, page, "statusbar-text",
 
1460
                                    window->statusbar, "text",
 
1461
                                    G_BINDING_SYNC_CREATE);
 
1462
    }
 
1463
 
 
1464
  /* activate new view */
 
1465
  window->view = page;
 
1466
 
 
1467
  /* integrate the standard view action in the ui */
 
1468
  thunar_component_set_ui_manager (THUNAR_COMPONENT (page), window->ui_manager);
 
1469
 
 
1470
  /* update the actions */
 
1471
  thunar_standard_view_selection_changed (THUNAR_STANDARD_VIEW (page));
 
1472
 
 
1473
  gtk_widget_grab_focus (page);
 
1474
}
 
1475
 
 
1476
 
 
1477
 
 
1478
static void
 
1479
thunar_window_notebook_show_tabs (ThunarWindow *window)
 
1480
{
 
1481
  gint       n_pages;
 
1482
  gboolean   show_tabs = TRUE;
 
1483
  GtkAction *action;
 
1484
 
 
1485
  /* check if tabs should be visible */
 
1486
  n_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook));
 
1487
  if (n_pages < 2)
 
1488
    {
 
1489
      g_object_get (G_OBJECT (window->preferences),
 
1490
                    "misc-always-show-tabs", &show_tabs, NULL);
 
1491
    }
 
1492
 
 
1493
  /* update visibility */
 
1494
  gtk_notebook_set_show_tabs (GTK_NOTEBOOK (window->notebook), show_tabs);
 
1495
 
 
1496
  /* visibility of the detach action */
 
1497
  action = gtk_action_group_get_action (window->action_group, "detach-tab");
 
1498
  gtk_action_set_visible (action, n_pages > 1);
 
1499
}
 
1500
 
 
1501
 
 
1502
 
 
1503
static void
 
1504
thunar_window_notebook_page_added (GtkWidget    *notebook,
 
1505
                                   GtkWidget    *page,
 
1506
                                   guint         page_num,
 
1507
                                   ThunarWindow *window)
 
1508
{
 
1509
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
1510
  _thunar_return_if_fail (GTK_IS_NOTEBOOK (notebook));
 
1511
  _thunar_return_if_fail (THUNAR_IS_VIEW (page));
 
1512
  _thunar_return_if_fail (window->notebook == notebook);
 
1513
 
 
1514
  /* connect signals */
 
1515
  g_signal_connect (G_OBJECT (page), "notify::loading", G_CALLBACK (thunar_window_notify_loading), window);
 
1516
  g_signal_connect (G_OBJECT (page), "notify::selected-files", G_CALLBACK (thunar_window_update_custom_actions), window);
 
1517
  g_signal_connect_swapped (G_OBJECT (page), "start-open-location", G_CALLBACK (thunar_window_start_open_location), window);
 
1518
  g_signal_connect_swapped (G_OBJECT (page), "change-directory", G_CALLBACK (thunar_window_set_current_directory), window);
 
1519
  g_signal_connect_swapped (G_OBJECT (page), "open-new-tab", G_CALLBACK (thunar_window_notebook_insert), window);
 
1520
 
 
1521
  /* update tab visibility */
 
1522
  thunar_window_notebook_show_tabs (window);
 
1523
 
 
1524
  /* set default type if not set yet */
 
1525
  if (window->view_type == G_TYPE_NONE)
 
1526
    window->view_type = G_OBJECT_TYPE (page);
 
1527
}
 
1528
 
 
1529
 
 
1530
 
 
1531
static void
 
1532
thunar_window_notebook_page_removed (GtkWidget    *notebook,
 
1533
                                     GtkWidget    *page,
 
1534
                                     guint         page_num,
 
1535
                                     ThunarWindow *window)
 
1536
{
 
1537
  gint n_pages;
 
1538
 
 
1539
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
1540
  _thunar_return_if_fail (GTK_IS_NOTEBOOK (notebook));
 
1541
  _thunar_return_if_fail (THUNAR_IS_VIEW (page));
 
1542
  _thunar_return_if_fail (window->notebook == notebook);
 
1543
 
 
1544
  /* drop connected signals */
 
1545
  g_signal_handlers_disconnect_matched (page, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, window);
 
1546
 
 
1547
  /* remove from the ui */
 
1548
  thunar_component_set_ui_manager (THUNAR_COMPONENT (page), NULL);
 
1549
 
 
1550
  n_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook));
 
1551
  if (n_pages == 0)
 
1552
    {
 
1553
      /* destroy the window */
 
1554
      gtk_widget_destroy (GTK_WIDGET (window));
 
1555
    }
 
1556
  else
 
1557
    {
 
1558
      /* update tab visibility */
 
1559
      thunar_window_notebook_show_tabs (window);
 
1560
    }
 
1561
}
 
1562
 
 
1563
 
 
1564
 
 
1565
static void
 
1566
thunar_window_notebook_popup_menu_real (ThunarWindow *window,
 
1567
                                        guint32       timestamp,
 
1568
                                        gint          button)
 
1569
{
 
1570
  GtkWidget *menu;
 
1571
 
 
1572
  /* run the menu on the view's screen (figuring out whether to use the file or the folder context menu) */
 
1573
  menu = gtk_ui_manager_get_widget (window->ui_manager, "/tab-context-menu");
 
1574
  thunar_gtk_menu_run (GTK_MENU (menu), GTK_WIDGET (window),
 
1575
                       NULL, NULL, button, timestamp);
 
1576
}
 
1577
 
 
1578
 
 
1579
 
 
1580
static gboolean
 
1581
thunar_window_notebook_button_press_event (GtkWidget      *notebook,
 
1582
                                           GdkEventButton *event,
 
1583
                                           ThunarWindow   *window)
 
1584
{
 
1585
  gint           page_num = 0;
 
1586
  GtkWidget     *page;
 
1587
  GtkWidget     *label_box;
 
1588
  GtkAllocation  alloc;
 
1589
  gint           x, y;
 
1590
  gboolean       close_tab;
 
1591
 
 
1592
  if ((event->button == 2 || event->button == 3)
 
1593
      && event->type == GDK_BUTTON_PRESS)
 
1594
    {
 
1595
      /* get real window coordinates */
 
1596
      gdk_window_get_position (event->window, &x, &y);
 
1597
      x += event->x;
 
1598
      y += event->y;
 
1599
 
 
1600
      /* lookup the clicked tab */
 
1601
      while ((page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), page_num)) != NULL)
 
1602
        {
 
1603
          label_box = gtk_notebook_get_tab_label (GTK_NOTEBOOK (notebook), page);
 
1604
          gtk_widget_get_allocation (label_box, &alloc);
 
1605
 
 
1606
          if (x >= alloc.x && x < alloc.x + alloc.width
 
1607
              && y >= alloc.y && y < alloc.y + alloc.height)
 
1608
            break;
 
1609
 
 
1610
          page_num++;
 
1611
        }
 
1612
 
 
1613
      /* leave if no tab could be found */
 
1614
      if (page == NULL)
 
1615
        return FALSE;
 
1616
 
 
1617
      if (event->button == 2)
 
1618
        {
 
1619
          /* check if we should close the tab */
 
1620
          g_object_get (window->preferences, "misc-tab-close-middle-click", &close_tab, NULL);
 
1621
          if (close_tab)
 
1622
            gtk_widget_destroy (page);
 
1623
        }
 
1624
      else if (event->button == 3)
 
1625
        {
 
1626
          /* update the current tab before we show the menu */
 
1627
          gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), page_num);
 
1628
 
 
1629
          /* show the tab menu */
 
1630
          thunar_window_notebook_popup_menu_real (window, event->time, event->button);
 
1631
        }
 
1632
 
 
1633
      return TRUE;
 
1634
    }
 
1635
 
 
1636
  return FALSE;
 
1637
}
 
1638
 
 
1639
 
 
1640
 
 
1641
static gboolean
 
1642
thunar_window_notebook_popup_menu (GtkWidget    *notebook,
 
1643
                                   ThunarWindow *window)
 
1644
{
 
1645
  thunar_window_notebook_popup_menu_real (window, gtk_get_current_event_time (), 0);
 
1646
  return TRUE;
 
1647
}
 
1648
 
 
1649
 
 
1650
 
 
1651
static gpointer
 
1652
thunar_window_notebook_create_window (GtkWidget    *notebook,
 
1653
                                      GtkWidget    *page,
 
1654
                                      gint          x,
 
1655
                                      gint          y,
 
1656
                                      ThunarWindow *window)
 
1657
{
 
1658
  GtkWidget         *new_window;
 
1659
  ThunarApplication *application;
 
1660
  gint               width, height;
 
1661
  gint               monitor_num;
 
1662
  GdkScreen         *screen;
 
1663
  GdkRectangle       geo;
 
1664
 
 
1665
  _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), NULL);
 
1666
  _thunar_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
 
1667
  _thunar_return_val_if_fail (window->notebook == notebook, NULL);
 
1668
  _thunar_return_val_if_fail (THUNAR_IS_VIEW (page), NULL);
 
1669
 
 
1670
  /* do nothing if this window has only 1 tab */
 
1671
  if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)) < 2)
 
1672
    return NULL;
 
1673
 
 
1674
  /* create new window */
 
1675
  application = thunar_application_get ();
 
1676
  screen = gtk_window_get_screen (GTK_WINDOW (window));
 
1677
  new_window = thunar_application_open_window (application, NULL, screen, NULL);
 
1678
  g_object_unref (application);
 
1679
 
 
1680
  /* make sure the new window has the same size */
 
1681
  gtk_window_get_size (GTK_WINDOW (window), &width, &height);
 
1682
  gtk_window_resize (GTK_WINDOW (new_window), width, height);
 
1683
 
 
1684
  /* move the window to the drop position */
 
1685
  if (x >= 0 && y >= 0)
 
1686
    {
 
1687
      /* get the monitor geometry */
 
1688
      monitor_num = gdk_screen_get_monitor_at_point (screen, x, y);
 
1689
      gdk_screen_get_monitor_geometry (screen, monitor_num, &geo);
 
1690
 
 
1691
      /* calculate window position, but keep it on the current monitor */
 
1692
      x = CLAMP (x - width / 2, geo.x, geo.x + geo.width - width);
 
1693
      y = CLAMP (y - height / 2, geo.y, geo.y + geo.height - height);
 
1694
 
 
1695
      /* move the window */
 
1696
      gtk_window_move (GTK_WINDOW (new_window), MAX (0, x), MAX (0, y));
 
1697
    }
 
1698
 
 
1699
  /* insert page in new notebook */
 
1700
  return THUNAR_WINDOW (new_window)->notebook;
 
1701
}
 
1702
 
 
1703
 
 
1704
 
 
1705
static void
 
1706
thunar_window_notebook_insert (ThunarWindow *window,
 
1707
                               ThunarFile   *directory)
 
1708
{
 
1709
  GtkWidget  *view;
 
1710
  gint        page_num;
 
1711
  GtkWidget  *label;
 
1712
  GtkWidget  *label_box;
 
1713
  GtkWidget  *button;
 
1714
  GtkWidget  *icon;
 
1715
  GtkRcStyle *style;
 
1716
 
 
1717
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
1718
  _thunar_return_if_fail (THUNAR_IS_FILE (directory));
 
1719
  _thunar_return_if_fail (window->view_type != G_TYPE_NONE);
 
1720
 
 
1721
  /* leave if no directory is set */
 
1722
  if (directory == NULL)
 
1723
    return;
 
1724
 
 
1725
  /* allocate and setup a new view */
 
1726
  view = g_object_new (window->view_type, "current-directory", directory, NULL);
 
1727
  gtk_widget_show (view);
 
1728
 
 
1729
  label_box = gtk_hbox_new (FALSE, 0);
 
1730
 
 
1731
  label = gtk_label_new (NULL);
 
1732
  exo_binding_new (G_OBJECT (view), "display-name", G_OBJECT (label), "label");
 
1733
  exo_binding_new (G_OBJECT (view), "tooltip-text", G_OBJECT (label), "tooltip-text");
 
1734
  gtk_widget_set_has_tooltip (label, TRUE);
 
1735
  gtk_misc_set_alignment (GTK_MISC (label), 0.0f, 0.5f);
 
1736
  gtk_misc_set_padding (GTK_MISC (label), 3, 3);
 
1737
  gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
 
1738
  gtk_label_set_single_line_mode (GTK_LABEL (label), TRUE);
 
1739
  gtk_box_pack_start (GTK_BOX (label_box), label, TRUE, TRUE, 0);
 
1740
  gtk_widget_show (label);
 
1741
 
 
1742
  button = gtk_button_new ();
 
1743
  gtk_box_pack_start (GTK_BOX (label_box), button, FALSE, FALSE, 0);
 
1744
  gtk_widget_set_can_default (button, FALSE);
 
1745
  gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
 
1746
  gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
 
1747
  gtk_widget_set_tooltip_text (button, _("Close tab"));
 
1748
  g_signal_connect_swapped (G_OBJECT (button), "clicked", G_CALLBACK (gtk_widget_destroy), view);
 
1749
  gtk_widget_show (button);
 
1750
 
 
1751
  /* make button a bit smaller */
 
1752
  style = gtk_rc_style_new ();
 
1753
  style->xthickness = style->ythickness = 0;
 
1754
  gtk_widget_modify_style (button, style);
 
1755
  g_object_unref (G_OBJECT (style));
 
1756
 
 
1757
  icon = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
 
1758
  gtk_container_add (GTK_CONTAINER (button), icon);
 
1759
  gtk_widget_show (icon);
 
1760
 
 
1761
  /* insert the new page */
 
1762
  page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook));
 
1763
  page_num = gtk_notebook_insert_page (GTK_NOTEBOOK (window->notebook), view, label_box, page_num + 1);
 
1764
 
 
1765
  /* switch to the new tab*/
 
1766
  gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), page_num);
 
1767
 
 
1768
  /* set tab child properties */
 
1769
  gtk_container_child_set (GTK_CONTAINER (window->notebook), view, "tab-expand", TRUE, NULL);
 
1770
  gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (window->notebook), view, TRUE);
 
1771
  gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (window->notebook), view, TRUE);
 
1772
 
 
1773
  /* take focus on the view */
 
1774
  gtk_widget_grab_focus (view);
 
1775
}
 
1776
 
 
1777
 
 
1778
 
 
1779
static void
 
1780
thunar_window_install_location_bar (ThunarWindow *window,
 
1781
                                    GType         type)
 
1782
{
 
1783
  GtkToolItem *item;
 
1784
  gboolean     small_icons;
 
1785
 
 
1786
  _thunar_return_if_fail (type == G_TYPE_NONE || g_type_is_a (type, THUNAR_TYPE_LOCATION_BAR));
 
1787
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
1788
 
 
1789
  /* drop the previous location bar (if any) */
 
1790
  if (G_UNLIKELY (window->location_bar != NULL))
 
1791
    {
 
1792
      /* check if it was toolbar'ed (and thereby need to be disconnected from the toolbar) */
 
1793
      if (!thunar_location_bar_is_standalone (THUNAR_LOCATION_BAR (window->location_bar)))
 
1794
        {
 
1795
          /* disconnect the toolbar from the window */
 
1796
          gtk_container_remove (GTK_CONTAINER (window->table), window->location_toolbar);
 
1797
          window->location_toolbar = NULL;
 
1798
        }
 
1799
 
 
1800
      /* destroy the location bar */
 
1801
      gtk_widget_destroy (window->location_bar);
 
1802
      window->location_bar = NULL;
 
1803
    }
 
1804
 
 
1805
  /* check if we have a new location bar */
 
1806
  if (G_LIKELY (type != G_TYPE_NONE))
 
1807
    {
 
1808
      /* allocate the new location bar widget */
 
1809
      window->location_bar = g_object_new (type, "ui-manager", window->ui_manager, NULL);
 
1810
      exo_binding_new (G_OBJECT (window), "current-directory", G_OBJECT (window->location_bar), "current-directory");
 
1811
      g_signal_connect_swapped (G_OBJECT (window->location_bar), "change-directory", G_CALLBACK (thunar_window_set_current_directory), window);
 
1812
      g_signal_connect_swapped (G_OBJECT (window->location_bar), "open-new-tab", G_CALLBACK (thunar_window_notebook_insert), window);
 
1813
 
 
1814
      /* connect the location widget to the view (if any) */
 
1815
      if (G_LIKELY (window->view != NULL))
 
1816
        thunar_window_binding_create (window, window->view, "selected-files", window->location_bar, "selected-files", G_BINDING_SYNC_CREATE);
 
1817
 
 
1818
      /* check if the location bar should be placed into a toolbar */
 
1819
      if (!thunar_location_bar_is_standalone (THUNAR_LOCATION_BAR (window->location_bar)))
 
1820
        {
 
1821
          /* setup the toolbar for the location bar */
 
1822
          window->location_toolbar = gtk_ui_manager_get_widget (window->ui_manager, "/location-toolbar");
 
1823
          g_object_get (G_OBJECT (window->preferences), "misc-small-toolbar-icons", &small_icons, NULL);
 
1824
          gtk_toolbar_set_icon_size (GTK_TOOLBAR (window->location_toolbar),
 
1825
                                     small_icons ? GTK_ICON_SIZE_SMALL_TOOLBAR : GTK_ICON_SIZE_LARGE_TOOLBAR);
 
1826
          gtk_table_attach (GTK_TABLE (window->table), window->location_toolbar, 0, 1, 1, 2, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
 
1827
          gtk_widget_show (window->location_toolbar);
 
1828
 
 
1829
          /* add the location bar tool item (destroyed with the location bar) */
 
1830
          item = gtk_tool_item_new ();
 
1831
          gtk_tool_item_set_expand (item, TRUE);
 
1832
          g_signal_connect_object (G_OBJECT (window->location_bar), "destroy", G_CALLBACK (gtk_widget_destroy), item, G_CONNECT_SWAPPED);
 
1833
          gtk_toolbar_insert (GTK_TOOLBAR (window->location_toolbar), item, -1);
 
1834
          gtk_widget_show (GTK_WIDGET (item));
 
1835
 
 
1836
          /* add the location bar itself */
 
1837
          gtk_container_add (GTK_CONTAINER (item), window->location_bar);
 
1838
        }
 
1839
      else
 
1840
        {
 
1841
          /* it's a standalone location bar, just place it above the view */
 
1842
          gtk_table_attach (GTK_TABLE (window->view_box), window->location_bar, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 6);
 
1843
        }
 
1844
 
 
1845
      /* display the new location bar widget */
 
1846
      gtk_widget_show (window->location_bar);
 
1847
    }
 
1848
 
 
1849
  /* remember the setting */
 
1850
  if (gtk_widget_get_visible (GTK_WIDGET (window)))
 
1851
    g_object_set (G_OBJECT (window->preferences), "last-location-bar", g_type_name (type), NULL);
 
1852
}
 
1853
 
 
1854
 
 
1855
 
 
1856
static void
 
1857
thunar_window_install_sidepane (ThunarWindow *window,
 
1858
                                GType         type)
 
1859
{
 
1860
  _thunar_return_if_fail (type == G_TYPE_NONE || g_type_is_a (type, THUNAR_TYPE_SIDE_PANE));
 
1861
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
1862
 
 
1863
  /* drop the previous side pane (if any) */
 
1864
  if (G_UNLIKELY (window->sidepane != NULL))
 
1865
    {
 
1866
      gtk_widget_destroy (window->sidepane);
 
1867
      window->sidepane = NULL;
 
1868
    }
 
1869
 
 
1870
  /* check if we have a new sidepane widget */
 
1871
  if (G_LIKELY (type != G_TYPE_NONE))
 
1872
    {
 
1873
      /* allocate the new side pane widget */
 
1874
      window->sidepane = g_object_new (type, NULL);
 
1875
      gtk_widget_set_size_request (window->sidepane, 0, -1);
 
1876
      thunar_component_set_ui_manager (THUNAR_COMPONENT (window->sidepane), window->ui_manager);
 
1877
      exo_binding_new (G_OBJECT (window), "show-hidden", G_OBJECT (window->sidepane), "show-hidden");
 
1878
      exo_binding_new (G_OBJECT (window), "current-directory", G_OBJECT (window->sidepane), "current-directory");
 
1879
      g_signal_connect_swapped (G_OBJECT (window->sidepane), "change-directory", G_CALLBACK (thunar_window_set_current_directory), window);
 
1880
      g_signal_connect_swapped (G_OBJECT (window->sidepane), "open-new-tab", G_CALLBACK (thunar_window_notebook_insert), window);
 
1881
      gtk_paned_pack1 (GTK_PANED (window->paned), window->sidepane, FALSE, FALSE);
 
1882
      gtk_widget_show (window->sidepane);
 
1883
 
 
1884
      /* connect the side pane widget to the view (if any) */
 
1885
      if (G_LIKELY (window->view != NULL))
 
1886
        thunar_window_binding_create (window, window->view, "selected-files", window->sidepane, "selected-files", G_BINDING_SYNC_CREATE);
 
1887
    }
 
1888
 
 
1889
  /* remember the setting */
 
1890
  if (gtk_widget_get_visible (GTK_WIDGET (window)))
 
1891
    g_object_set (G_OBJECT (window->preferences), "last-side-pane", g_type_name (type), NULL);
 
1892
}
 
1893
 
 
1894
 
 
1895
 
 
1896
static void
 
1897
thunar_window_merge_custom_preferences (ThunarWindow *window)
 
1898
{
 
1899
  GList *providers;
 
1900
  GList *actions;
 
1901
  GList *ap, *pp;
 
1902
 
 
1903
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
1904
  _thunar_return_if_fail (window->custom_preferences_merge_id == 0);
 
1905
 
 
1906
  /* determine the available preferences providers */
 
1907
  providers = thunarx_provider_factory_list_providers (window->provider_factory, THUNARX_TYPE_PREFERENCES_PROVIDER);
 
1908
  if (G_LIKELY (providers != NULL))
 
1909
    {
 
1910
      /* allocate a new merge id from the UI manager */
 
1911
      window->custom_preferences_merge_id = gtk_ui_manager_new_merge_id (window->ui_manager);
 
1912
 
 
1913
      /* add actions from all providers */
 
1914
      for (pp = providers; pp != NULL; pp = pp->next)
 
1915
        {
 
1916
          /* determine the available actions for the provider */
 
1917
          actions = thunarx_preferences_provider_get_actions (THUNARX_PREFERENCES_PROVIDER (pp->data), GTK_WIDGET (window));
 
1918
          for (ap = actions; ap != NULL; ap = ap->next)
 
1919
            {
 
1920
              /* add the action to the action group */
 
1921
              gtk_action_group_add_action (window->action_group, GTK_ACTION (ap->data));
 
1922
 
 
1923
              /* add the action to the UI manager */
 
1924
              gtk_ui_manager_add_ui (window->ui_manager,
 
1925
                                     window->custom_preferences_merge_id,
 
1926
                                     "/main-menu/edit-menu/placeholder-custom-preferences",
 
1927
                                     gtk_action_get_name (GTK_ACTION (ap->data)),
 
1928
                                     gtk_action_get_name (GTK_ACTION (ap->data)),
 
1929
                                     GTK_UI_MANAGER_MENUITEM, FALSE);
 
1930
 
 
1931
              /* release the reference on the action */
 
1932
              g_object_unref (G_OBJECT (ap->data));
 
1933
            }
 
1934
 
 
1935
          /* release the reference on the provider */
 
1936
          g_object_unref (G_OBJECT (pp->data));
 
1937
 
 
1938
          /* release the action list */
 
1939
          g_list_free (actions);
 
1940
        }
 
1941
 
 
1942
      /* release the provider list */
 
1943
      g_list_free (providers);
 
1944
    }
 
1945
}
 
1946
 
 
1947
 
 
1948
 
 
1949
static void
 
1950
thunar_window_bookmark_changed (ThunarWindow *window)
 
1951
{
 
1952
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
1953
 
 
1954
  if (window->bookmark_reload_idle_id == 0)
 
1955
    window->bookmark_reload_idle_id = g_idle_add (thunar_window_bookmark_merge, window);
 
1956
}
 
1957
 
 
1958
 
 
1959
 
 
1960
static void
 
1961
thunar_window_bookmark_release_file (gpointer data)
 
1962
{
 
1963
  ThunarFile *file = THUNAR_FILE (data);
 
1964
 
 
1965
  /* stop watching */
 
1966
  thunar_file_unwatch (file);
 
1967
 
 
1968
  /* disconnect changed and destroy signals */
 
1969
  g_signal_handlers_disconnect_matched (file,
 
1970
                                        G_SIGNAL_MATCH_FUNC, 0,
 
1971
                                        0, NULL,
 
1972
                                        G_CALLBACK (thunar_window_bookmark_changed),
 
1973
                                        NULL);
 
1974
 
 
1975
  g_object_unref (file);
 
1976
}
 
1977
 
 
1978
 
 
1979
 
 
1980
static void
 
1981
thunar_window_bookmark_merge_line (GFile       *file_path,
 
1982
                                   const gchar *name,
 
1983
                                   gint         line_num,
 
1984
                                   gpointer     user_data)
 
1985
{
 
1986
  ThunarWindow *window = THUNAR_WINDOW (user_data);
 
1987
  GtkAction    *action = NULL;
 
1988
  GChecksum    *checksum;
 
1989
  gchar        *uri;
 
1990
  ThunarFile   *file;
 
1991
  gchar        *parse_name;
 
1992
  gchar        *tooltip;
 
1993
  gchar        *remote_name = NULL;
 
1994
  const gchar  *unique_name;
 
1995
  const gchar  *path;
 
1996
  GtkIconTheme *icon_theme;
 
1997
  const gchar  *icon_name;
 
1998
 
 
1999
  _thunar_return_if_fail (G_IS_FILE (file_path));
 
2000
  _thunar_return_if_fail (name == NULL || g_utf8_validate (name, -1, NULL));
 
2001
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
2002
 
 
2003
  /* create unique id based on the uri */
 
2004
  uri = g_file_get_uri (file_path);
 
2005
  checksum = g_checksum_new (G_CHECKSUM_MD5);
 
2006
  g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
 
2007
  unique_name = g_checksum_get_string (checksum);
 
2008
  g_free (uri);
 
2009
 
 
2010
  parse_name = g_file_get_parse_name (file_path);
 
2011
  tooltip = g_strdup_printf (_("Open the location \"%s\""), parse_name);
 
2012
  g_free (parse_name);
 
2013
 
 
2014
  icon_theme = gtk_icon_theme_get_for_screen (gtk_window_get_screen (GTK_WINDOW (window)));
 
2015
 
 
2016
  if (g_file_has_uri_scheme (file_path, "file"))
 
2017
    {
 
2018
      /* try to open the file corresponding to the uri */
 
2019
      file = thunar_file_get (file_path, NULL);
 
2020
      if (G_UNLIKELY (file == NULL))
 
2021
        return;
 
2022
 
 
2023
      /* make sure the file refers to a directory */
 
2024
      if (G_UNLIKELY (thunar_file_is_directory (file)))
 
2025
        {
 
2026
          if (name == NULL)
 
2027
            name = thunar_file_get_display_name (file);
 
2028
 
 
2029
          action = gtk_action_new (unique_name, name, tooltip, NULL);
 
2030
          icon_name = thunar_file_get_icon_name (file, THUNAR_FILE_ICON_STATE_DEFAULT, icon_theme);
 
2031
          gtk_action_set_icon_name (action, icon_name);
 
2032
          g_object_set_data_full (G_OBJECT (action), I_("thunar-file"), file,
 
2033
                                  thunar_window_bookmark_release_file);
 
2034
 
 
2035
          /* watch the file */
 
2036
          thunar_file_watch (file);
 
2037
 
 
2038
          g_signal_connect_swapped (G_OBJECT (file), "destroy",
 
2039
                                    G_CALLBACK (thunar_window_bookmark_changed), window);
 
2040
          g_signal_connect_swapped (G_OBJECT (file), "changed",
 
2041
                                    G_CALLBACK (thunar_window_bookmark_changed), window);
 
2042
        }
 
2043
      else
 
2044
        {
 
2045
          g_object_unref (file);
 
2046
        }
 
2047
 
 
2048
      /* add to the local bookmarks */
 
2049
      path = "/main-menu/go-menu/placeholder-go-local-actions";
 
2050
    }
 
2051
  else
 
2052
    {
 
2053
      if (name == NULL)
 
2054
        {
 
2055
          remote_name = thunar_g_file_get_display_name_remote (file_path);
 
2056
          name = remote_name;
 
2057
        }
 
2058
 
 
2059
      action = gtk_action_new (unique_name, name, tooltip, NULL);
 
2060
      gtk_action_set_icon_name (action, "folder-remote");
 
2061
      g_object_set_data_full (G_OBJECT (action), I_("location-file"),
 
2062
                              g_object_ref (file_path), g_object_unref);
 
2063
 
 
2064
      g_free (remote_name);
 
2065
 
 
2066
      /* add to the remote bookmarks */
 
2067
      path = "/main-menu/go-menu/placeholder-go-remote-actions";
 
2068
    }
 
2069
 
 
2070
  if (G_LIKELY (action != NULL))
 
2071
    {
 
2072
      if (gtk_action_group_get_action (window->bookmark_action_group, unique_name) == NULL)
 
2073
        {
 
2074
          /* connect action */
 
2075
          g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (thunar_window_action_open_bookmark), window);
 
2076
 
 
2077
          /* insert the bookmark in the group */
 
2078
          gtk_action_group_add_action_with_accel (window->bookmark_action_group, action, NULL);
 
2079
 
 
2080
          /* add the action to the UI manager */
 
2081
          gtk_ui_manager_add_ui (window->ui_manager,
 
2082
                                 window->bookmark_items_actions_merge_id,
 
2083
                                 path,
 
2084
                                 unique_name, unique_name,
 
2085
                                 GTK_UI_MANAGER_MENUITEM, FALSE);
 
2086
        }
 
2087
 
 
2088
      g_object_unref (action);
 
2089
    }
 
2090
 
 
2091
  g_checksum_free (checksum);
 
2092
  g_free (tooltip);
 
2093
}
 
2094
 
 
2095
 
 
2096
 
 
2097
static gboolean
 
2098
thunar_window_bookmark_merge (gpointer user_data)
 
2099
{
 
2100
  ThunarWindow *window = THUNAR_WINDOW (user_data);
 
2101
 
 
2102
  _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
 
2103
 
 
2104
  GDK_THREADS_ENTER ();
 
2105
 
 
2106
  /* remove old actions */
 
2107
  if (window->bookmark_items_actions_merge_id != 0)
 
2108
    {
 
2109
      gtk_ui_manager_remove_ui (window->ui_manager, window->bookmark_items_actions_merge_id);
 
2110
      gtk_ui_manager_ensure_update (window->ui_manager);
 
2111
    }
 
2112
 
 
2113
  /* drop old bookmarks action group */
 
2114
  if (window->bookmark_action_group != NULL)
 
2115
    {
 
2116
      gtk_ui_manager_remove_action_group (window->ui_manager, window->bookmark_action_group);
 
2117
      g_object_unref (window->bookmark_action_group);
 
2118
    }
 
2119
 
 
2120
  /* lazy initialize the bookmarks */
 
2121
  if (window->bookmark_file == NULL)
 
2122
    {
 
2123
      window->bookmark_file = thunar_g_file_new_for_bookmarks ();
 
2124
      window->bookmark_monitor = g_file_monitor_file (window->bookmark_file, G_FILE_MONITOR_NONE, NULL, NULL);
 
2125
      if (G_LIKELY (window->bookmark_monitor != NULL))
 
2126
        {
 
2127
          g_signal_connect_swapped (window->bookmark_monitor, "changed",
 
2128
                                    G_CALLBACK (thunar_window_bookmark_changed), window);
 
2129
        }
 
2130
    }
 
2131
 
 
2132
  /* generate a new merge id */
 
2133
  window->bookmark_items_actions_merge_id = gtk_ui_manager_new_merge_id (window->ui_manager);
 
2134
 
 
2135
  /* create a new action group */
 
2136
  window->bookmark_action_group = gtk_action_group_new ("ThunarBookmarks");
 
2137
  gtk_ui_manager_insert_action_group (window->ui_manager, window->bookmark_action_group, -1);
 
2138
 
 
2139
  /* collect bookmarks */
 
2140
  thunar_util_load_bookmarks (window->bookmark_file,
 
2141
                              thunar_window_bookmark_merge_line,
 
2142
                              window);
 
2143
 
 
2144
  window->bookmark_reload_idle_id = 0;
 
2145
 
 
2146
  GDK_THREADS_LEAVE ();
 
2147
 
 
2148
  return FALSE;
 
2149
}
 
2150
 
 
2151
 
 
2152
 
 
2153
static void
 
2154
thunar_window_merge_go_actions (ThunarWindow *window)
 
2155
{
 
2156
  GtkAction *action;
 
2157
 
 
2158
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
2159
  _thunar_return_if_fail (window->go_items_actions_merge_id == 0);
 
2160
 
 
2161
  /* setup the "open-trash" action */
 
2162
  if (thunar_g_vfs_is_uri_scheme_supported ("trash"))
 
2163
    {
 
2164
      /* allocate a new merge id from the UI manager */
 
2165
      window->go_items_actions_merge_id = gtk_ui_manager_new_merge_id (window->ui_manager);
 
2166
 
 
2167
      /* add the trash action to the action group */
 
2168
      action = thunar_trash_action_new ();
 
2169
      g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (thunar_window_action_open_trash), window);
 
2170
      gtk_action_group_add_action_with_accel (window->action_group, action, NULL);
 
2171
 
 
2172
      /* add the action to the UI manager */
 
2173
      gtk_ui_manager_add_ui (window->ui_manager,
 
2174
                             window->go_items_actions_merge_id,
 
2175
                             "/main-menu/go-menu/placeholder-go-items-actions",
 
2176
                             gtk_action_get_name (GTK_ACTION (action)),
 
2177
                             gtk_action_get_name (GTK_ACTION (action)),
 
2178
                             GTK_UI_MANAGER_MENUITEM, FALSE);
 
2179
 
 
2180
      g_object_unref (action);
 
2181
    }
 
2182
 
 
2183
  /* setup visibility of the "open-network" action */
 
2184
  action = gtk_action_group_get_action (window->action_group, "open-network");
 
2185
  gtk_action_set_visible (action, thunar_g_vfs_is_uri_scheme_supported ("network"));
 
2186
}
 
2187
 
 
2188
 
 
2189
 
 
2190
static void
 
2191
thunar_window_open_or_launch (ThunarWindow *window,
 
2192
                              ThunarFile   *file)
 
2193
{
 
2194
  GError *error = NULL;
 
2195
 
 
2196
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
2197
  _thunar_return_if_fail (THUNAR_IS_FILE (file));
 
2198
 
 
2199
  if (thunar_file_is_directory (file))
 
2200
    {
 
2201
      /* open the new directory */
 
2202
      thunar_window_set_current_directory (window, file);
 
2203
    }
 
2204
  else
 
2205
    {
 
2206
      /* try to launch the selected file */
 
2207
      if (!thunar_file_launch (file, window, NULL, &error))
 
2208
        {
 
2209
          thunar_dialogs_show_error (window, error, _("Failed to launch \"%s\""),
 
2210
                                     thunar_file_get_display_name (file));
 
2211
          g_error_free (error);
 
2212
        }
 
2213
    }
 
2214
}
 
2215
 
 
2216
 
 
2217
 
 
2218
static void
 
2219
thunar_window_poke_file_finish (ThunarBrowser *browser,
 
2220
                                ThunarFile    *file,
 
2221
                                ThunarFile    *target_file,
 
2222
                                GError        *error,
 
2223
                                gpointer       ignored)
 
2224
{
 
2225
  _thunar_return_if_fail (THUNAR_IS_WINDOW (browser));
 
2226
  _thunar_return_if_fail (THUNAR_IS_FILE (file));
 
2227
 
 
2228
  if (error == NULL)
 
2229
    {
 
2230
      thunar_window_open_or_launch (THUNAR_WINDOW (browser), target_file);
 
2231
    }
 
2232
  else
 
2233
    {
 
2234
      thunar_dialogs_show_error (GTK_WIDGET (browser), error,
 
2235
                                 _("Failed to open \"%s\""),
 
2236
                                 thunar_file_get_display_name (file));
 
2237
    }
 
2238
}
 
2239
 
 
2240
 
 
2241
 
 
2242
static void
 
2243
thunar_window_start_open_location (ThunarWindow *window,
 
2244
                                   const gchar  *initial_text)
 
2245
{
 
2246
  ThunarFile *selected_file;
 
2247
  GtkWidget  *dialog;
 
2248
 
 
2249
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
2250
 
 
2251
  /* bring up the "Open Location"-dialog if the window has no location bar or the location bar
 
2252
   * in the window does not support text entry by the user.
 
2253
   */
 
2254
  if (window->location_bar == NULL || !thunar_location_bar_accept_focus (THUNAR_LOCATION_BAR (window->location_bar), initial_text))
 
2255
    {
 
2256
      /* allocate the "Open Location" dialog */
 
2257
      dialog = thunar_location_dialog_new ();
 
2258
      gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
 
2259
      gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
 
2260
      gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window));
 
2261
      thunar_location_dialog_set_working_directory (THUNAR_LOCATION_DIALOG (dialog),
 
2262
                                                    thunar_window_get_current_directory (window));
 
2263
      thunar_location_dialog_set_selected_file (THUNAR_LOCATION_DIALOG (dialog),
 
2264
                                                thunar_window_get_current_directory (window));
 
2265
 
 
2266
      /* setup the initial text (if any) */
 
2267
      if (G_UNLIKELY (initial_text != NULL))
 
2268
        {
 
2269
          /* show, grab focus, set text and move cursor to the end */
 
2270
          gtk_widget_show_now (dialog);
 
2271
          gtk_widget_grab_focus (THUNAR_LOCATION_DIALOG (dialog)->entry);
 
2272
          gtk_entry_set_text (GTK_ENTRY (THUNAR_LOCATION_DIALOG (dialog)->entry), initial_text);
 
2273
          gtk_editable_set_position (GTK_EDITABLE (THUNAR_LOCATION_DIALOG (dialog)->entry), -1);
 
2274
        }
 
2275
 
 
2276
      /* run the dialog */
 
2277
      if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
 
2278
        {
 
2279
          /* be sure to hide the location dialog first */
 
2280
          gtk_widget_hide (dialog);
 
2281
 
 
2282
          /* check if we have a new directory or a file to launch */
 
2283
          selected_file = thunar_location_dialog_get_selected_file (THUNAR_LOCATION_DIALOG (dialog));
 
2284
          if (selected_file != NULL)
 
2285
            {
 
2286
              thunar_browser_poke_file (THUNAR_BROWSER (window), selected_file, window,
 
2287
                                        thunar_window_poke_file_finish, NULL);
 
2288
            }
 
2289
        }
 
2290
 
 
2291
      /* destroy the dialog */
 
2292
      gtk_widget_destroy (dialog);
 
2293
    }
 
2294
}
 
2295
 
 
2296
 
 
2297
 
 
2298
static void
 
2299
thunar_window_action_open_new_tab (GtkAction    *action,
 
2300
                                   ThunarWindow *window)
 
2301
{
 
2302
  /* insert new tab with current directory as default */
 
2303
  thunar_window_notebook_insert (window, thunar_window_get_current_directory (window));
 
2304
}
 
2305
 
 
2306
 
 
2307
 
 
2308
static void
 
2309
thunar_window_action_open_new_window (GtkAction    *action,
 
2310
                                      ThunarWindow *window)
 
2311
{
 
2312
  ThunarApplication *application;
 
2313
  ThunarFile        *start_file;
 
2314
  GtkWidget         *new_window;
 
2315
 
 
2316
  /* popup a new window */
 
2317
  application = thunar_application_get ();
 
2318
  new_window = thunar_application_open_window (application, window->current_directory,
 
2319
                                               gtk_widget_get_screen (GTK_WIDGET (window)), NULL);
 
2320
  g_object_unref (G_OBJECT (application));
 
2321
 
 
2322
  /* determine the first visible file in the current window */
 
2323
  if (window->view != NULL && thunar_view_get_visible_range (THUNAR_VIEW (window->view), &start_file, NULL))
 
2324
    {
 
2325
      /* scroll the new window to the same file */
 
2326
      thunar_window_scroll_to_file (THUNAR_WINDOW (new_window), start_file, FALSE, TRUE, 0.1f, 0.1f);
 
2327
 
 
2328
      /* release the file reference */
 
2329
      g_object_unref (G_OBJECT (start_file));
 
2330
    }
 
2331
}
 
2332
 
 
2333
 
 
2334
 
 
2335
static void
 
2336
thunar_window_action_empty_trash (GtkAction    *action,
 
2337
                                  ThunarWindow *window)
 
2338
{
 
2339
  ThunarApplication *application;
 
2340
 
 
2341
  /* launch the operation */
 
2342
  application = thunar_application_get ();
 
2343
  thunar_application_empty_trash (application, GTK_WIDGET (window), NULL);
 
2344
  g_object_unref (G_OBJECT (application));
 
2345
}
 
2346
 
 
2347
 
 
2348
 
 
2349
static void
 
2350
thunar_window_action_detach_tab (GtkAction    *action,
 
2351
                                 ThunarWindow *window)
 
2352
{
 
2353
  GtkWidget *notebook;
 
2354
  GtkWidget *label;
 
2355
  GtkWidget *view = window->view;
 
2356
 
 
2357
  _thunar_return_if_fail (THUNAR_IS_VIEW (view));
 
2358
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
2359
 
 
2360
  /* create a new window */
 
2361
  notebook = thunar_window_notebook_create_window (window->notebook, view, -1, -1, window);
 
2362
  if (notebook == NULL)
 
2363
    return;
 
2364
 
 
2365
  /* get the current label */
 
2366
  label = gtk_notebook_get_tab_label (GTK_NOTEBOOK (window->notebook), view);
 
2367
  _thunar_return_if_fail (GTK_IS_WIDGET (label));
 
2368
 
 
2369
  /* ref object so they don't destroy when removed from the container */
 
2370
  g_object_ref (label);
 
2371
  g_object_ref (view);
 
2372
 
 
2373
  /* remove view from the current notebook */
 
2374
  gtk_container_remove (GTK_CONTAINER (window->notebook), view);
 
2375
 
 
2376
  /* insert in the new notebook */
 
2377
  gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), view, label, 0);
 
2378
 
 
2379
  /* set tab child properties */
 
2380
  gtk_container_child_set (GTK_CONTAINER (notebook), view, "tab-expand", TRUE, NULL);
 
2381
  gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (notebook), view, TRUE);
 
2382
  gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (notebook), view, TRUE);
 
2383
 
 
2384
  /* release */
 
2385
  g_object_unref (label);
 
2386
  g_object_unref (view);
 
2387
}
 
2388
 
 
2389
 
 
2390
 
 
2391
static void
 
2392
thunar_window_action_close_all_windows (GtkAction    *action,
 
2393
                                        ThunarWindow *window)
 
2394
{
 
2395
  ThunarApplication *application;
 
2396
  GList             *windows;
 
2397
 
 
2398
  /* query the list of currently open windows */
 
2399
  application = thunar_application_get ();
 
2400
  windows = thunar_application_get_windows (application);
 
2401
  g_object_unref (G_OBJECT (application));
 
2402
 
 
2403
  /* destroy all open windows */
 
2404
  g_list_free_full (windows, (GDestroyNotify) gtk_widget_destroy);
 
2405
}
 
2406
 
 
2407
 
 
2408
 
 
2409
static void
 
2410
thunar_window_action_close_tab (GtkAction    *action,
 
2411
                                ThunarWindow *window)
 
2412
{
 
2413
  if (window->view != NULL)
 
2414
    gtk_widget_destroy (window->view);
 
2415
}
 
2416
 
 
2417
 
 
2418
 
 
2419
static void
 
2420
thunar_window_action_close_window (GtkAction    *action,
 
2421
                                   ThunarWindow *window)
 
2422
{
 
2423
  gtk_widget_destroy (GTK_WIDGET (window));
 
2424
}
 
2425
 
 
2426
 
 
2427
 
 
2428
static void
 
2429
thunar_window_action_preferences (GtkAction    *action,
 
2430
                                  ThunarWindow *window)
 
2431
{
 
2432
  GtkWidget         *dialog;
 
2433
  ThunarApplication *application;
 
2434
 
 
2435
  _thunar_return_if_fail (GTK_IS_ACTION (action));
 
2436
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
2437
 
 
2438
  /* allocate and display a preferences dialog */;
 
2439
  dialog = thunar_preferences_dialog_new (GTK_WINDOW (window));
 
2440
  gtk_widget_show (dialog);
 
2441
 
 
2442
  /* ...and let the application take care of it */
 
2443
  application = thunar_application_get ();
 
2444
  thunar_application_take_window (application, GTK_WINDOW (dialog));
 
2445
  g_object_unref (G_OBJECT (application));
 
2446
}
 
2447
 
 
2448
 
 
2449
 
 
2450
static void
 
2451
thunar_window_action_reload (GtkAction    *action,
 
2452
                             ThunarWindow *window)
 
2453
{
 
2454
  gboolean result;
 
2455
 
 
2456
  _thunar_return_if_fail (GTK_IS_ACTION (action));
 
2457
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
2458
 
 
2459
  /* force the view to reload */
 
2460
  g_signal_emit (G_OBJECT (window), window_signals[RELOAD], 0, &result);
 
2461
}
 
2462
 
 
2463
 
 
2464
 
 
2465
static void
 
2466
thunar_window_action_pathbar_changed (GtkToggleAction *action,
 
2467
                                      ThunarWindow    *window)
 
2468
{
 
2469
  GtkAction *other_action;
 
2470
  GType      type;
 
2471
 
 
2472
  _thunar_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
 
2473
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
2474
 
 
2475
  /* determine the new type of location bar */
 
2476
  type = gtk_toggle_action_get_active (action) ? THUNAR_TYPE_LOCATION_BUTTONS : G_TYPE_NONE;
 
2477
 
 
2478
  /* install the new location bar */
 
2479
  thunar_window_install_location_bar (window, type);
 
2480
 
 
2481
  /* check if we actually installed anything */
 
2482
  if (G_LIKELY (type != G_TYPE_NONE))
 
2483
    {
 
2484
      /* reset the state of the toolbar action (without firing the handler) */
 
2485
      other_action = gtk_action_group_get_action (window->action_group, "view-location-selector-toolbar");
 
2486
      g_signal_handlers_block_by_func (G_OBJECT (other_action), thunar_window_action_toolbar_changed, window);
 
2487
      gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (other_action), FALSE);
 
2488
      g_signal_handlers_unblock_by_func (G_OBJECT (other_action), thunar_window_action_toolbar_changed, window);
 
2489
    }
 
2490
}
 
2491
 
 
2492
 
 
2493
 
 
2494
static void
 
2495
thunar_window_action_toolbar_changed (GtkToggleAction *action,
 
2496
                                      ThunarWindow    *window)
 
2497
{
 
2498
  GtkAction *other_action;
 
2499
  GType      type;
 
2500
 
 
2501
  _thunar_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
 
2502
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
2503
 
 
2504
  /* determine the new type of location bar */
 
2505
  type = gtk_toggle_action_get_active (action) ? THUNAR_TYPE_LOCATION_ENTRY : G_TYPE_NONE;
 
2506
 
 
2507
  /* install the new location bar */
 
2508
  thunar_window_install_location_bar (window, type);
 
2509
 
 
2510
  /* check if we actually installed anything */
 
2511
  if (G_LIKELY (type != G_TYPE_NONE))
 
2512
    {
 
2513
      /* reset the state of the pathbar action (without firing the handler) */
 
2514
      other_action = gtk_action_group_get_action (window->action_group, "view-location-selector-pathbar");
 
2515
      g_signal_handlers_block_by_func (G_OBJECT (other_action), thunar_window_action_pathbar_changed, window);
 
2516
      gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (other_action), FALSE);
 
2517
      g_signal_handlers_unblock_by_func (G_OBJECT (other_action), thunar_window_action_pathbar_changed, window);
 
2518
    }
 
2519
}
 
2520
 
 
2521
 
 
2522
 
 
2523
static void
 
2524
thunar_window_action_shortcuts_changed (GtkToggleAction *action,
 
2525
                                        ThunarWindow    *window)
 
2526
{
 
2527
  GtkAction *other_action;
 
2528
  GType      type;
 
2529
 
 
2530
  /* determine the new type of side pane */
 
2531
  type = gtk_toggle_action_get_active (action) ? THUNAR_TYPE_SHORTCUTS_PANE : G_TYPE_NONE;
 
2532
 
 
2533
  /* install the new sidepane */
 
2534
  thunar_window_install_sidepane (window, type);
 
2535
 
 
2536
  /* check if we actually installed anything */
 
2537
  if (G_LIKELY (type != G_TYPE_NONE))
 
2538
    {
 
2539
      /* reset the state of the tree pane action (without firing the handler) */
 
2540
      other_action = gtk_action_group_get_action (window->action_group, "view-side-pane-tree");
 
2541
      g_signal_handlers_block_by_func (G_OBJECT (other_action), thunar_window_action_tree_changed, window);
 
2542
      gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (other_action), FALSE);
 
2543
      g_signal_handlers_unblock_by_func (G_OBJECT (other_action), thunar_window_action_tree_changed, window);
 
2544
    }
 
2545
}
 
2546
 
 
2547
 
 
2548
 
 
2549
static void
 
2550
thunar_window_action_tree_changed (GtkToggleAction *action,
 
2551
                                   ThunarWindow    *window)
 
2552
{
 
2553
  GtkAction *other_action;
 
2554
  GType      type;
 
2555
 
 
2556
  /* determine the new type of side pane */
 
2557
  type = gtk_toggle_action_get_active (action) ? THUNAR_TYPE_TREE_PANE : G_TYPE_NONE;
 
2558
 
 
2559
  /* install the new sidepane */
 
2560
  thunar_window_install_sidepane (window, type);
 
2561
 
 
2562
  /* check if we actually installed anything */
 
2563
  if (G_LIKELY (type != G_TYPE_NONE))
 
2564
    {
 
2565
      /* reset the state of the shortcuts pane action (without firing the handler) */
 
2566
      other_action = gtk_action_group_get_action (window->action_group, "view-side-pane-shortcuts");
 
2567
      g_signal_handlers_block_by_func (G_OBJECT (other_action), thunar_window_action_shortcuts_changed, window);
 
2568
      gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (other_action), FALSE);
 
2569
      g_signal_handlers_unblock_by_func (G_OBJECT (other_action), thunar_window_action_shortcuts_changed, window);
 
2570
    }
 
2571
}
 
2572
 
 
2573
 
 
2574
 
 
2575
static void
 
2576
thunar_window_action_statusbar_changed (GtkToggleAction *action,
 
2577
                                        ThunarWindow    *window)
 
2578
{
 
2579
  gboolean active;
 
2580
 
 
2581
  _thunar_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
 
2582
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
2583
 
 
2584
  /* determine the new state of the action */
 
2585
  active = gtk_toggle_action_get_active (action);
 
2586
 
 
2587
  /* check if we should drop the statusbar */
 
2588
  if (!active && window->statusbar != NULL)
 
2589
    {
 
2590
      /* just get rid of the statusbar */
 
2591
      gtk_widget_destroy (window->statusbar);
 
2592
      window->statusbar = NULL;
 
2593
    }
 
2594
  else if (active && window->statusbar == NULL)
 
2595
    {
 
2596
      /* setup a new statusbar */
 
2597
      window->statusbar = thunar_statusbar_new ();
 
2598
      gtk_table_attach (GTK_TABLE (window->view_box), window->statusbar, 0, 1, 2, 3, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
 
2599
      gtk_widget_show (window->statusbar);
 
2600
 
 
2601
      /* connect to the view (if any) */
 
2602
      if (G_LIKELY (window->view != NULL))
 
2603
        thunar_window_binding_create (window, window->view, "statusbar-text", window->statusbar, "text", G_BINDING_SYNC_CREATE);
 
2604
    }
 
2605
 
 
2606
  /* remember the setting */
 
2607
  if (gtk_widget_get_visible (GTK_WIDGET (window)))
 
2608
    g_object_set (G_OBJECT (window->preferences), "last-statusbar-visible", active, NULL);
 
2609
}
 
2610
 
 
2611
 
 
2612
 
 
2613
static void
 
2614
thunar_window_action_menubar_changed (GtkToggleAction *action,
 
2615
                                      ThunarWindow    *window)
 
2616
{
 
2617
  gboolean active;
 
2618
 
 
2619
  _thunar_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
 
2620
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
2621
 
 
2622
  /* determine the new state of the action */
 
2623
  active = gtk_toggle_action_get_active (action);
 
2624
 
 
2625
  /* show or hide the bar */
 
2626
  gtk_widget_set_visible (window->menubar, active);
 
2627
 
 
2628
  /* remember the setting */
 
2629
  if (gtk_widget_get_visible (GTK_WIDGET (window)))
 
2630
    g_object_set (G_OBJECT (window->preferences), "last-menubar-visible", active, NULL);
 
2631
}
 
2632
 
 
2633
 
 
2634
 
 
2635
static void
 
2636
thunar_window_action_zoom_in (GtkAction    *action,
 
2637
                              ThunarWindow *window)
 
2638
{
 
2639
  gboolean result;
 
2640
 
 
2641
  _thunar_return_if_fail (GTK_IS_ACTION (action));
 
2642
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
2643
 
 
2644
  /* increase the zoom level */
 
2645
  g_signal_emit (G_OBJECT (window), window_signals[ZOOM_IN], 0, &result);
 
2646
}
 
2647
 
 
2648
 
 
2649
 
 
2650
static void
 
2651
thunar_window_action_zoom_out (GtkAction    *action,
 
2652
                               ThunarWindow *window)
 
2653
{
 
2654
  gboolean result;
 
2655
 
 
2656
  _thunar_return_if_fail (GTK_IS_ACTION (action));
 
2657
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
2658
 
 
2659
  /* decrease the zoom level */
 
2660
  g_signal_emit (G_OBJECT (window), window_signals[ZOOM_OUT], 0, &result);
 
2661
}
 
2662
 
 
2663
 
 
2664
 
 
2665
static void
 
2666
thunar_window_action_zoom_reset (GtkAction    *action,
 
2667
                                 ThunarWindow *window)
 
2668
{
 
2669
  gboolean result;
 
2670
 
 
2671
  _thunar_return_if_fail (GTK_IS_ACTION (action));
 
2672
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
2673
 
 
2674
  /* reset zoom level */
 
2675
  g_signal_emit (G_OBJECT (window), window_signals[ZOOM_RESET], 0, &result);
 
2676
}
 
2677
 
 
2678
 
 
2679
 
 
2680
static void
 
2681
thunar_window_action_view_changed (GtkRadioAction *action,
 
2682
                                   GtkRadioAction *current,
 
2683
                                   ThunarWindow   *window)
 
2684
{
 
2685
  ThunarFile *file = NULL;
 
2686
  ThunarFile *current_directory = NULL;
 
2687
  GtkWidget  *old_view;
 
2688
 
 
2689
  /* drop the previous view (if any) */
 
2690
  old_view = window->view;
 
2691
  if (G_LIKELY (window->view != NULL))
 
2692
    {
 
2693
      /* get first visible file in the previous view */
 
2694
      if (!thunar_view_get_visible_range (THUNAR_VIEW (window->view), &file, NULL))
 
2695
        file = NULL;
 
2696
 
 
2697
      /* store the active directory */
 
2698
      current_directory = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (window->view));
 
2699
      if (current_directory != NULL)
 
2700
        g_object_ref (current_directory);
 
2701
 
 
2702
      /* update the UI (else GtkUIManager will crash on merging) */
 
2703
      gtk_ui_manager_ensure_update (window->ui_manager);
 
2704
    }
 
2705
 
 
2706
  /* determine the new type of view */
 
2707
  window->view_type = view_index2type (gtk_radio_action_get_current_value (action));
 
2708
 
 
2709
  /* always open a new directory */
 
2710
  if (current_directory == NULL && window->current_directory != NULL)
 
2711
    current_directory = g_object_ref (window->current_directory);
 
2712
 
 
2713
  /* allocate a new view of the requested type */
 
2714
  if (G_LIKELY (window->view_type != G_TYPE_NONE))
 
2715
    {
 
2716
      /* create new page */
 
2717
      if (current_directory != NULL)
 
2718
        thunar_window_notebook_insert (window, current_directory);
 
2719
 
 
2720
      /* scroll to the previously visible file in the old view */
 
2721
      if (G_UNLIKELY (file != NULL))
 
2722
        thunar_view_scroll_to_file (THUNAR_VIEW (window->view), file, FALSE, TRUE, 0.0f, 0.0f);
 
2723
    }
 
2724
  else
 
2725
    {
 
2726
      /* this should not happen under normal conditions */
 
2727
      window->view = NULL;
 
2728
    }
 
2729
 
 
2730
  /* destroy the old view */
 
2731
  if (old_view != NULL)
 
2732
    gtk_widget_destroy (old_view);
 
2733
 
 
2734
  /* remember the setting */
 
2735
  if (gtk_widget_get_visible (GTK_WIDGET (window)))
 
2736
    g_object_set (G_OBJECT (window->preferences), "last-view", g_type_name (window->view_type), NULL);
 
2737
 
 
2738
  /* release the file references */
 
2739
  if (G_UNLIKELY (file != NULL))
 
2740
    g_object_unref (G_OBJECT (file));
 
2741
  if (G_UNLIKELY (current_directory != NULL))
 
2742
    g_object_unref (G_OBJECT (current_directory));
 
2743
}
 
2744
 
 
2745
 
 
2746
 
 
2747
static void
 
2748
thunar_window_action_go_up (GtkAction    *action,
 
2749
                            ThunarWindow *window)
 
2750
{
 
2751
  ThunarFile *parent;
 
2752
  GError     *error = NULL;
 
2753
 
 
2754
  parent = thunar_file_get_parent (window->current_directory, &error);
 
2755
  if (G_LIKELY (parent != NULL))
 
2756
    {
 
2757
      thunar_window_set_current_directory (window, parent);
 
2758
      g_object_unref (G_OBJECT (parent));
 
2759
    }
 
2760
  else
 
2761
    {
 
2762
      thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to open parent folder"));
 
2763
      g_error_free (error);
 
2764
    }
 
2765
}
 
2766
 
 
2767
 
 
2768
 
 
2769
static void
 
2770
thunar_window_action_open_home (GtkAction    *action,
 
2771
                                ThunarWindow *window)
 
2772
{
 
2773
  GFile         *home;
 
2774
  ThunarFile    *home_file;
 
2775
  GError        *error = NULL;
 
2776
 
 
2777
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
2778
 
 
2779
  /* determine the path to the home directory */
 
2780
  home = thunar_g_file_new_for_home ();
 
2781
 
 
2782
  /* determine the file for the home directory */
 
2783
  home_file = thunar_file_get (home, &error);
 
2784
  if (G_UNLIKELY (home_file == NULL))
 
2785
    {
 
2786
      /* display an error to the user */
 
2787
      thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to open the home folder"));
 
2788
      g_error_free (error);
 
2789
    }
 
2790
  else
 
2791
    {
 
2792
      /* open the home folder */
 
2793
      thunar_window_set_current_directory (window, home_file);
 
2794
      g_object_unref (G_OBJECT (home_file));
 
2795
    }
 
2796
 
 
2797
  /* release our reference on the home path */
 
2798
  g_object_unref (home);
 
2799
}
 
2800
 
 
2801
 
 
2802
 
 
2803
static gboolean
 
2804
thunar_window_open_user_folder (GtkAction      *action,
 
2805
                                ThunarWindow   *window,
 
2806
                                GUserDirectory  thunar_user_dir,
 
2807
                                const gchar    *default_name)
 
2808
{
 
2809
  ThunarFile  *user_file = NULL;
 
2810
  gboolean     result = FALSE;
 
2811
  GError      *error = NULL;
 
2812
  GFile       *home_dir;
 
2813
  GFile       *user_dir;
 
2814
  const gchar *path;
 
2815
  gint         response;
 
2816
  GtkWidget   *dialog;
 
2817
  gchar       *parse_name;
 
2818
 
 
2819
  path = g_get_user_special_dir (thunar_user_dir);
 
2820
  home_dir = thunar_g_file_new_for_home ();
 
2821
 
 
2822
  /* check if there is an entry in user-dirs.dirs */
 
2823
  path = g_get_user_special_dir (thunar_user_dir);
 
2824
  if (G_LIKELY (path != NULL))
 
2825
    {
 
2826
      user_dir = g_file_new_for_path (path);
 
2827
 
 
2828
      /* if equal to home, leave */
 
2829
      if (g_file_equal (user_dir, home_dir))
 
2830
        goto is_homedir;
 
2831
    }
 
2832
  else
 
2833
    {
 
2834
      /* build a name */
 
2835
      user_dir = g_file_resolve_relative_path (home_dir, default_name);
 
2836
    }
 
2837
 
 
2838
  /* try to load the user dir */
 
2839
  user_file = thunar_file_get (user_dir, NULL);
 
2840
 
 
2841
  /* check if the directory exists */
 
2842
  if (G_UNLIKELY (user_file == NULL || !thunar_file_exists (user_file)))
 
2843
    {
 
2844
      /* release the instance if it does not exist */
 
2845
      if (user_file != NULL)
 
2846
        {
 
2847
          g_object_unref (user_file);
 
2848
          user_file = NULL;
 
2849
        }
 
2850
 
 
2851
      /* ask the user to create the directory */
 
2852
      parse_name = g_file_get_parse_name (user_dir);
 
2853
      dialog = gtk_message_dialog_new (GTK_WINDOW (window),
 
2854
                                       GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
 
2855
                                       GTK_MESSAGE_QUESTION,
 
2856
                                       GTK_BUTTONS_YES_NO,
 
2857
                                       _("The directory \"%s\" does not exist. Do you want to create it?"),
 
2858
                                       parse_name);
 
2859
      gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES);
 
2860
      response = gtk_dialog_run (GTK_DIALOG (dialog));
 
2861
      gtk_widget_destroy (dialog);
 
2862
      g_free (parse_name);
 
2863
 
 
2864
      if (response == GTK_RESPONSE_YES
 
2865
          && g_file_make_directory_with_parents (user_dir, NULL, &error))
 
2866
        {
 
2867
          /* try again */
 
2868
          user_file = thunar_file_get (user_dir, &error);
 
2869
        }
 
2870
    }
 
2871
 
 
2872
  if (G_LIKELY (user_file != NULL))
 
2873
    {
 
2874
      /* open the folder */
 
2875
      thunar_window_set_current_directory (window, user_file);
 
2876
      g_object_unref (G_OBJECT (user_file));
 
2877
      result = TRUE;
 
2878
    }
 
2879
  else if (error != NULL)
 
2880
    {
 
2881
      parse_name = g_file_get_parse_name (user_dir);
 
2882
      thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to open directory \"%s\""), parse_name);
 
2883
      g_free (parse_name);
 
2884
      g_error_free (error);
 
2885
    }
 
2886
 
 
2887
  is_homedir:
 
2888
 
 
2889
  g_object_unref (user_dir);
 
2890
  g_object_unref (home_dir);
 
2891
 
 
2892
  return result;
 
2893
}
 
2894
 
 
2895
 
 
2896
 
 
2897
static void
 
2898
thunar_window_action_open_desktop (GtkAction     *action,
 
2899
                                   ThunarWindow  *window)
 
2900
{
 
2901
  _thunar_return_if_fail (GTK_IS_ACTION (action));
 
2902
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
2903
 
 
2904
  thunar_window_open_user_folder (action, window,
 
2905
                                  G_USER_DIRECTORY_DESKTOP,
 
2906
                                  "Desktop");
 
2907
}
 
2908
 
 
2909
 
 
2910
 
 
2911
static void
 
2912
thunar_window_action_open_templates (GtkAction    *action,
 
2913
                                     ThunarWindow *window)
 
2914
{
 
2915
  GtkWidget     *dialog;
 
2916
  GtkWidget     *button;
 
2917
  GtkWidget     *label;
 
2918
  GtkWidget     *image;
 
2919
  GtkWidget     *hbox;
 
2920
  GtkWidget     *vbox;
 
2921
  gboolean       show_about_templates;
 
2922
  gboolean       success;
 
2923
 
 
2924
  _thunar_return_if_fail (GTK_IS_ACTION (action));
 
2925
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
2926
 
 
2927
  success = thunar_window_open_user_folder (action,window,
 
2928
                                            G_USER_DIRECTORY_TEMPLATES,
 
2929
                                            "Templates");
 
2930
 
 
2931
  /* check whether we should display the "About Templates" dialog */
 
2932
  g_object_get (G_OBJECT (window->preferences),
 
2933
                "misc-show-about-templates", &show_about_templates,
 
2934
                NULL);
 
2935
 
 
2936
  if (G_UNLIKELY(show_about_templates && success))
 
2937
    {
 
2938
      /* display the "About Templates" dialog */
 
2939
      dialog = gtk_dialog_new_with_buttons (_("About Templates"), GTK_WINDOW (window),
 
2940
                                            GTK_DIALOG_DESTROY_WITH_PARENT
 
2941
                                            | GTK_DIALOG_NO_SEPARATOR,
 
2942
                                            GTK_STOCK_OK, GTK_RESPONSE_OK,
 
2943
                                            NULL);
 
2944
 
 
2945
      gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
 
2946
 
 
2947
      hbox = gtk_hbox_new (FALSE, 6);
 
2948
      gtk_container_set_border_width (GTK_CONTAINER (hbox), 8);
 
2949
      gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, TRUE, TRUE, 0);
 
2950
      gtk_widget_show (hbox);
 
2951
 
 
2952
      image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG);
 
2953
      gtk_misc_set_alignment (GTK_MISC (image), 0.5f, 0.0f);
 
2954
      gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
 
2955
      gtk_widget_show (image);
 
2956
 
 
2957
      vbox = gtk_vbox_new (FALSE, 18);
 
2958
      gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
 
2959
      gtk_widget_show (vbox);
 
2960
 
 
2961
      label = gtk_label_new (_("All files in this folder will appear in the \"Create Document\" menu."));
 
2962
      gtk_misc_set_alignment (GTK_MISC (label), 0.0f, 0.5f);
 
2963
      gtk_label_set_attributes (GTK_LABEL (label), thunar_pango_attr_list_big_bold ());
 
2964
      gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
 
2965
      gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
 
2966
      gtk_widget_show (label);
 
2967
 
 
2968
      label = gtk_label_new (_("If you frequently create certain kinds "
 
2969
                             " of documents, make a copy of one and put it in this "
 
2970
                             "folder. Thunar will add an entry for this document in the"
 
2971
                             " \"Create Document\" menu.\n\n"
 
2972
                             "You can then select the entry from the \"Create Document\" "
 
2973
                             "menu and a copy of the document will be created in the "
 
2974
                             "directory you are viewing."));
 
2975
      gtk_misc_set_alignment (GTK_MISC (label), 0.0f, 0.5f);
 
2976
      gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
 
2977
      gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
 
2978
      gtk_widget_show (label);
 
2979
 
 
2980
      button = gtk_check_button_new_with_mnemonic (_("Do _not display this message again"));
 
2981
      exo_mutual_binding_new_with_negation (G_OBJECT (window->preferences), "misc-show-about-templates", G_OBJECT (button), "active");
 
2982
      gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
 
2983
      gtk_widget_show (button);
 
2984
 
 
2985
      gtk_dialog_run (GTK_DIALOG (dialog));
 
2986
      gtk_widget_destroy (dialog);
 
2987
    }
 
2988
}
 
2989
 
 
2990
 
 
2991
 
 
2992
static void
 
2993
thunar_window_action_open_file_system (GtkAction    *action,
 
2994
                                       ThunarWindow *window)
 
2995
{
 
2996
  GFile         *root;
 
2997
  ThunarFile    *root_file;
 
2998
  GError        *error = NULL;
 
2999
 
 
3000
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
3001
 
 
3002
  /* determine the path to the root directory */
 
3003
  root = thunar_g_file_new_for_root ();
 
3004
 
 
3005
  /* determine the file for the root directory */
 
3006
  root_file = thunar_file_get (root, &error);
 
3007
  if (G_UNLIKELY (root_file == NULL))
 
3008
    {
 
3009
      /* display an error to the user */
 
3010
      thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to open the file system root folder"));
 
3011
      g_error_free (error);
 
3012
    }
 
3013
  else
 
3014
    {
 
3015
      /* open the root folder */
 
3016
      thunar_window_set_current_directory (window, root_file);
 
3017
      g_object_unref (G_OBJECT (root_file));
 
3018
    }
 
3019
 
 
3020
  /* release our reference on the home path */
 
3021
  g_object_unref (root);
 
3022
}
 
3023
 
 
3024
 
 
3025
 
 
3026
static void
 
3027
thunar_window_action_open_trash (GtkAction    *action,
 
3028
                                 ThunarWindow *window)
 
3029
{
 
3030
  GFile      *trash_bin;
 
3031
  ThunarFile *trash_bin_file;
 
3032
  GError     *error = NULL;
 
3033
 
 
3034
  _thunar_return_if_fail (GTK_IS_ACTION (action));
 
3035
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
3036
 
 
3037
  /* determine the path to the trash bin */
 
3038
  trash_bin = thunar_g_file_new_for_trash ();
 
3039
 
 
3040
  /* determine the file for the trash bin */
 
3041
  trash_bin_file = thunar_file_get (trash_bin, &error);
 
3042
  if (G_UNLIKELY (trash_bin_file == NULL))
 
3043
    {
 
3044
      /* display an error to the user */
 
3045
      thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to display the contents of the trash can"));
 
3046
      g_error_free (error);
 
3047
    }
 
3048
  else
 
3049
    {
 
3050
      /* open the trash folder */
 
3051
      thunar_window_set_current_directory (window, trash_bin_file);
 
3052
      g_object_unref (G_OBJECT (trash_bin_file));
 
3053
    }
 
3054
 
 
3055
  /* release our reference on the trash bin path */
 
3056
  g_object_unref (trash_bin);
 
3057
}
 
3058
 
 
3059
 
 
3060
 
 
3061
static void
 
3062
thunar_window_action_open_network (GtkAction    *action,
 
3063
                                   ThunarWindow *window)
 
3064
{
 
3065
  ThunarFile *network_file;
 
3066
  GError     *error = NULL;
 
3067
  GFile      *network;
 
3068
 
 
3069
  _thunar_return_if_fail (GTK_IS_ACTION (action));
 
3070
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
3071
 
 
3072
  /* determine the network root location */
 
3073
  network = g_file_new_for_uri ("network://");
 
3074
 
 
3075
  /* determine the file for this location */
 
3076
  network_file = thunar_file_get (network, &error);
 
3077
  if (G_UNLIKELY (network_file == NULL))
 
3078
    {
 
3079
      /* display an error to the user */
 
3080
      thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to browse the network"));
 
3081
      g_error_free (error);
 
3082
    }
 
3083
  else
 
3084
    {
 
3085
      /* open the network root location */
 
3086
      thunar_window_set_current_directory (window, network_file);
 
3087
      g_object_unref (G_OBJECT (network_file));
 
3088
    }
 
3089
 
 
3090
  /* release our reference on the location itself */
 
3091
  g_object_unref (network);
 
3092
}
 
3093
 
 
3094
 
 
3095
 
 
3096
static void
 
3097
thunar_window_poke_location_finish (ThunarBrowser *browser,
 
3098
                                    GFile         *location,
 
3099
                                    ThunarFile    *file,
 
3100
                                    ThunarFile    *target_file,
 
3101
                                    GError        *error,
 
3102
                                    gpointer       ignored)
 
3103
{
 
3104
  _thunar_return_if_fail (THUNAR_IS_WINDOW (browser));
 
3105
  _thunar_return_if_fail (THUNAR_IS_FILE (file));
 
3106
 
 
3107
  thunar_window_poke_file_finish (browser, file, target_file, error, ignored);
 
3108
}
 
3109
 
 
3110
 
 
3111
 
 
3112
static void
 
3113
thunar_window_action_open_bookmark (GtkAction    *action,
 
3114
                                    ThunarWindow *window)
 
3115
{
 
3116
  ThunarFile *local_file;
 
3117
  GFile      *remote_file;
 
3118
 
 
3119
  /* try to open the local file */
 
3120
  local_file = g_object_get_data (G_OBJECT (action), I_("thunar-file"));
 
3121
  if (local_file != NULL)
 
3122
    {
 
3123
      thunar_window_set_current_directory (window, local_file);
 
3124
      return;
 
3125
    }
 
3126
 
 
3127
  /* try to the remote file */
 
3128
  remote_file = g_object_get_data (G_OBJECT (action), I_("location-file"));
 
3129
  if (remote_file != NULL)
 
3130
    {
 
3131
      thunar_browser_poke_location (THUNAR_BROWSER (window), remote_file, window,
 
3132
                                    thunar_window_poke_location_finish, NULL);
 
3133
    }
 
3134
}
 
3135
 
 
3136
 
 
3137
 
 
3138
static void
 
3139
thunar_window_action_open_location (GtkAction    *action,
 
3140
                                    ThunarWindow *window)
 
3141
{
 
3142
  /* just use the "start-open-location" callback */
 
3143
  thunar_window_start_open_location (window, NULL);
 
3144
}
 
3145
 
 
3146
 
 
3147
 
 
3148
static void
 
3149
thunar_window_action_contents (GtkAction    *action,
 
3150
                               ThunarWindow *window)
 
3151
{
 
3152
  /* display the documentation index */
 
3153
  xfce_dialog_show_help (GTK_WINDOW (window), "thunar", NULL, NULL);
 
3154
}
 
3155
 
 
3156
 
 
3157
 
 
3158
static void
 
3159
thunar_window_action_about (GtkAction    *action,
 
3160
                            ThunarWindow *window)
 
3161
{
 
3162
  /* just popup the about dialog */
 
3163
  thunar_dialogs_show_about (GTK_WINDOW (window), PACKAGE_NAME,
 
3164
                             _("Thunar is a fast and easy to use file manager\n"
 
3165
                               "for the Xfce Desktop Environment."));
 
3166
}
 
3167
 
 
3168
 
 
3169
 
 
3170
static void
 
3171
thunar_window_action_show_hidden (GtkToggleAction *action,
 
3172
                                  ThunarWindow    *window)
 
3173
{
 
3174
  _thunar_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
 
3175
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
3176
 
 
3177
  /* just emit the "notify" signal for the "show-hidden"
 
3178
   * signal and the view will automatically sync its state.
 
3179
   */
 
3180
  g_object_notify (G_OBJECT (window), "show-hidden");
 
3181
 
 
3182
  if (gtk_widget_get_visible (GTK_WIDGET (window)))
 
3183
    g_object_set (G_OBJECT (window->preferences), "last-show-hidden",
 
3184
                  gtk_toggle_action_get_active (action), NULL);
 
3185
}
 
3186
 
 
3187
 
 
3188
 
 
3189
static void
 
3190
thunar_window_current_directory_changed (ThunarFile   *current_directory,
 
3191
                                         ThunarWindow *window)
 
3192
{
 
3193
  GtkIconTheme *icon_theme;
 
3194
  GtkAction    *action;
 
3195
  const gchar  *icon_name;
 
3196
  gchar        *title;
 
3197
  gboolean      show_full_path;
 
3198
  gchar        *parse_name = NULL;
 
3199
  const gchar  *name;
 
3200
 
 
3201
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
3202
  _thunar_return_if_fail (THUNAR_IS_FILE (current_directory));
 
3203
  _thunar_return_if_fail (window->current_directory == current_directory);
 
3204
 
 
3205
  /* update the "Empty Trash" action */
 
3206
  action = gtk_action_group_get_action (window->action_group, "empty-trash");
 
3207
  gtk_action_set_sensitive (action, (thunar_file_get_item_count (current_directory) > 0));
 
3208
  gtk_action_set_visible (action, (thunar_file_is_root (current_directory) && thunar_file_is_trashed (current_directory)));
 
3209
 
 
3210
  /* get name of directory or full path */
 
3211
  g_object_get (G_OBJECT (window->preferences), "misc-full-path-in-title", &show_full_path, NULL);
 
3212
  if (G_UNLIKELY (show_full_path))
 
3213
    name = parse_name = g_file_get_parse_name (thunar_file_get_file (current_directory));
 
3214
  else
 
3215
    name = thunar_file_get_display_name (current_directory);
 
3216
 
 
3217
  /* set window title */
 
3218
  title = g_strdup_printf ("%s - %s", name, _("File Manager"));
 
3219
  gtk_window_set_title (GTK_WINDOW (window), title);
 
3220
  g_free (title);
 
3221
  g_free (parse_name);
 
3222
 
 
3223
  /* set window icon */
 
3224
  icon_theme = gtk_icon_theme_get_for_screen (gtk_window_get_screen (GTK_WINDOW (window)));
 
3225
  icon_name = thunar_file_get_icon_name (current_directory,
 
3226
                                         THUNAR_FILE_ICON_STATE_DEFAULT,
 
3227
                                         icon_theme);
 
3228
  gtk_window_set_icon_name (GTK_WINDOW (window), icon_name);
 
3229
}
 
3230
 
 
3231
 
 
3232
 
 
3233
static void
 
3234
thunar_window_connect_proxy (GtkUIManager *manager,
 
3235
                             GtkAction    *action,
 
3236
                             GtkWidget    *proxy,
 
3237
                             ThunarWindow *window)
 
3238
{
 
3239
  /* we want to get informed when the user hovers a menu item */
 
3240
  if (GTK_IS_MENU_ITEM (proxy))
 
3241
    {
 
3242
      g_signal_connect_closure (G_OBJECT (proxy), "select", window->menu_item_selected_closure, FALSE);
 
3243
      g_signal_connect_closure (G_OBJECT (proxy), "deselect", window->menu_item_deselected_closure, FALSE);
 
3244
    }
 
3245
}
 
3246
 
 
3247
 
 
3248
 
 
3249
static void
 
3250
thunar_window_disconnect_proxy (GtkUIManager *manager,
 
3251
                                GtkAction    *action,
 
3252
                                GtkWidget    *proxy,
 
3253
                                ThunarWindow *window)
 
3254
{
 
3255
  /* undo what we did in connect_proxy() */
 
3256
  if (GTK_IS_MENU_ITEM (proxy))
 
3257
    {
 
3258
      g_signal_handlers_disconnect_matched (G_OBJECT (proxy), G_SIGNAL_MATCH_CLOSURE, 0, 0, window->menu_item_selected_closure, NULL, NULL);
 
3259
      g_signal_handlers_disconnect_matched (G_OBJECT (proxy), G_SIGNAL_MATCH_CLOSURE, 0, 0, window->menu_item_deselected_closure, NULL, NULL);
 
3260
    }
 
3261
}
 
3262
 
 
3263
 
 
3264
 
 
3265
static void
 
3266
thunar_window_menu_item_selected (GtkWidget    *menu_item,
 
3267
                                  ThunarWindow *window)
 
3268
{
 
3269
  GtkAction   *action;
 
3270
  const gchar *tooltip;
 
3271
  gint         id;
 
3272
  gchar       *short_tip = NULL;
 
3273
  gchar       *p;
 
3274
 
 
3275
  /* we can only display tooltips if we have a statusbar */
 
3276
  if (G_LIKELY (window->statusbar != NULL))
 
3277
    {
 
3278
      /* determine the action for the menu item */
 
3279
      action = gtk_widget_get_action (menu_item);
 
3280
      if (G_UNLIKELY (action == NULL))
 
3281
        return;
 
3282
 
 
3283
      /* determine the tooltip from the action */
 
3284
      tooltip = gtk_action_get_tooltip (action);
 
3285
      if (G_LIKELY (tooltip != NULL))
 
3286
        {
 
3287
          /* check if there is a new line in the tooltip */
 
3288
          p = strchr (tooltip, '\n');
 
3289
          if (p != NULL)
 
3290
            {
 
3291
              short_tip = g_strndup (tooltip, p - tooltip);
 
3292
              tooltip = short_tip;
 
3293
            }
 
3294
 
 
3295
          /* push to the statusbar */
 
3296
          id = gtk_statusbar_get_context_id (GTK_STATUSBAR (window->statusbar), "Menu tooltip");
 
3297
          gtk_statusbar_push (GTK_STATUSBAR (window->statusbar), id, tooltip);
 
3298
          g_free (short_tip);
 
3299
        }
 
3300
    }
 
3301
}
 
3302
 
 
3303
 
 
3304
 
 
3305
static void
 
3306
thunar_window_menu_item_deselected (GtkWidget    *menu_item,
 
3307
                                    ThunarWindow *window)
 
3308
{
 
3309
  gint id;
 
3310
 
 
3311
  /* we can only undisplay tooltips if we have a statusbar */
 
3312
  if (G_LIKELY (window->statusbar != NULL))
 
3313
    {
 
3314
      /* drop the last tooltip from the statusbar */
 
3315
      id = gtk_statusbar_get_context_id (GTK_STATUSBAR (window->statusbar), "Menu tooltip");
 
3316
      gtk_statusbar_pop (GTK_STATUSBAR (window->statusbar), id);
 
3317
    }
 
3318
}
 
3319
 
 
3320
 
 
3321
 
 
3322
static void
 
3323
thunar_window_update_custom_actions (ThunarView   *view,
 
3324
                                     GParamSpec   *pspec,
 
3325
                                     ThunarWindow *window)
 
3326
{
 
3327
  ThunarFile *folder;
 
3328
  GList      *selected_files;
 
3329
  GList      *actions = NULL;
 
3330
  GList      *lp;
 
3331
  GList      *providers;
 
3332
  GList      *tmp;
 
3333
 
 
3334
  _thunar_return_if_fail (THUNAR_IS_VIEW (view));
 
3335
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
3336
 
 
3337
  /* leave if the signal is emitted from a non-active tab */
 
3338
  if (!gtk_widget_get_realized (GTK_WIDGET (window))
 
3339
      || window->view != GTK_WIDGET (view))
 
3340
    return;
 
3341
 
 
3342
  /* load the menu provides from the provider factory */
 
3343
  providers = thunarx_provider_factory_list_providers (window->provider_factory,
 
3344
                                                       THUNARX_TYPE_MENU_PROVIDER);
 
3345
  if (G_LIKELY (providers != NULL))
 
3346
    {
 
3347
      /* grab a reference to the current directory of the window */
 
3348
      folder = thunar_window_get_current_directory (window);
 
3349
 
 
3350
      /* get a list of selected files */
 
3351
      selected_files = thunar_component_get_selected_files (THUNAR_COMPONENT (view));
 
3352
 
 
3353
      /* load the actions offered by the menu providers */
 
3354
      for (lp = providers; lp != NULL; lp = lp->next)
 
3355
        {
 
3356
          if (G_LIKELY (selected_files != NULL))
 
3357
            {
 
3358
              tmp = thunarx_menu_provider_get_file_actions (lp->data,
 
3359
                                                            GTK_WIDGET (window),
 
3360
                                                            selected_files);
 
3361
            }
 
3362
          else if (G_LIKELY (folder != NULL))
 
3363
            {
 
3364
              tmp = thunarx_menu_provider_get_folder_actions (lp->data,
 
3365
                                                              GTK_WIDGET (window),
 
3366
                                                              THUNARX_FILE_INFO (folder));
 
3367
            }
 
3368
          else
 
3369
            {
 
3370
              tmp = NULL;
 
3371
            }
 
3372
 
 
3373
          actions = g_list_concat (actions, tmp);
 
3374
          g_object_unref (G_OBJECT (lp->data));
 
3375
        }
 
3376
      g_list_free (providers);
 
3377
    }
 
3378
 
 
3379
  /* remove previously inserted menu actions from the UI manager */
 
3380
  if (window->custom_merge_id != 0)
 
3381
    {
 
3382
      gtk_ui_manager_remove_ui (window->ui_manager, window->custom_merge_id);
 
3383
      gtk_ui_manager_ensure_update (window->ui_manager);
 
3384
      window->custom_merge_id = 0;
 
3385
    }
 
3386
 
 
3387
  /* drop any previous custom action group */
 
3388
  if (window->custom_actions != NULL)
 
3389
    {
 
3390
      gtk_ui_manager_remove_action_group (window->ui_manager, window->custom_actions);
 
3391
      g_object_unref (window->custom_actions);
 
3392
      window->custom_actions = NULL;
 
3393
    }
 
3394
 
 
3395
  /* add the actions specified by the menu providers */
 
3396
  if (G_LIKELY (actions != NULL))
 
3397
    {
 
3398
      /* allocate the action group and the merge id for the custom actions */
 
3399
      window->custom_actions = gtk_action_group_new ("ThunarActions");
 
3400
      window->custom_merge_id = gtk_ui_manager_new_merge_id (window->ui_manager);
 
3401
      gtk_ui_manager_insert_action_group (window->ui_manager, window->custom_actions, -1);
 
3402
 
 
3403
      /* add the actions to the UI manager */
 
3404
      for (lp = actions; lp != NULL; lp = lp->next)
 
3405
        {
 
3406
          /* add the action to the action group */
 
3407
          gtk_action_group_add_action_with_accel (window->custom_actions,
 
3408
                                                  GTK_ACTION (lp->data),
 
3409
                                                  NULL);
 
3410
 
 
3411
          /* add to the file context menu */
 
3412
          gtk_ui_manager_add_ui (window->ui_manager,
 
3413
                                 window->custom_merge_id,
 
3414
                                 "/main-menu/file-menu/placeholder-custom-actions",
 
3415
                                 gtk_action_get_name (GTK_ACTION (lp->data)),
 
3416
                                 gtk_action_get_name (GTK_ACTION (lp->data)),
 
3417
                                 GTK_UI_MANAGER_MENUITEM, FALSE);
 
3418
 
 
3419
          /* release the reference on the action */
 
3420
          g_object_unref (G_OBJECT (lp->data));
 
3421
        }
 
3422
 
 
3423
      /* cleanup */
 
3424
      g_list_free (actions);
 
3425
    }
 
3426
}
 
3427
 
 
3428
 
 
3429
 
 
3430
static void
 
3431
thunar_window_notify_loading (ThunarView   *view,
 
3432
                              GParamSpec   *pspec,
 
3433
                              ThunarWindow *window)
 
3434
{
 
3435
  GdkCursor *cursor;
 
3436
 
 
3437
  _thunar_return_if_fail (THUNAR_IS_VIEW (view));
 
3438
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
3439
 
 
3440
  if (gtk_widget_get_realized (GTK_WIDGET (window))
 
3441
      && window->view == GTK_WIDGET (view))
 
3442
    {
 
3443
      /* setup the proper cursor */
 
3444
      if (thunar_view_get_loading (view))
 
3445
        {
 
3446
          cursor = gdk_cursor_new (GDK_WATCH);
 
3447
          gdk_window_set_cursor (GTK_WIDGET (window)->window, cursor);
 
3448
          gdk_cursor_unref (cursor);
 
3449
        }
 
3450
      else
 
3451
        {
 
3452
          gdk_window_set_cursor (GTK_WIDGET (window)->window, NULL);
 
3453
        }
 
3454
    }
 
3455
}
 
3456
 
 
3457
 
 
3458
 
 
3459
static void
 
3460
thunar_window_device_pre_unmount (ThunarDeviceMonitor *device_monitor,
 
3461
                                  ThunarDevice        *device,
 
3462
                                  GFile               *root_file,
 
3463
                                  ThunarWindow        *window)
 
3464
{
 
3465
  GtkAction *action;
 
3466
 
 
3467
  _thunar_return_if_fail (THUNAR_IS_DEVICE_MONITOR (device_monitor));
 
3468
  _thunar_return_if_fail (window->device_monitor == device_monitor);
 
3469
  _thunar_return_if_fail (THUNAR_IS_DEVICE (device));
 
3470
  _thunar_return_if_fail (G_IS_FILE (root_file));
 
3471
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
3472
 
 
3473
  /* nothing to do if we don't have a current directory */
 
3474
  if (G_UNLIKELY (window->current_directory == NULL))
 
3475
    return;
 
3476
 
 
3477
  /* check if the file is the current directory or an ancestor of the current directory */
 
3478
  if (thunar_file_is_gfile_ancestor (window->current_directory, root_file))
 
3479
    {
 
3480
      /* change to the home folder */
 
3481
      action = gtk_action_group_get_action (window->action_group, "open-home");
 
3482
      if (G_LIKELY (action != NULL))
 
3483
        gtk_action_activate (action);
 
3484
    }
 
3485
}
 
3486
 
 
3487
 
 
3488
 
 
3489
static void
 
3490
thunar_window_device_changed (ThunarDeviceMonitor *device_monitor,
 
3491
                              ThunarDevice        *device,
 
3492
                              ThunarWindow        *window)
 
3493
{
 
3494
  GFile *root_file;
 
3495
 
 
3496
  _thunar_return_if_fail (THUNAR_IS_DEVICE_MONITOR (device_monitor));
 
3497
  _thunar_return_if_fail (window->device_monitor == device_monitor);
 
3498
  _thunar_return_if_fail (THUNAR_IS_DEVICE (device));
 
3499
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
3500
 
 
3501
  if (thunar_device_is_mounted (device))
 
3502
    return;
 
3503
 
 
3504
  root_file = thunar_device_get_root (device);
 
3505
  if (root_file != NULL)
 
3506
    {
 
3507
      thunar_window_device_pre_unmount (device_monitor, device, root_file, window);
 
3508
      g_object_unref (root_file);
 
3509
    }
 
3510
}
 
3511
 
 
3512
 
 
3513
 
 
3514
static gboolean
 
3515
thunar_window_merge_idle (gpointer user_data)
 
3516
{
 
3517
  ThunarWindow *window = THUNAR_WINDOW (user_data);
 
3518
 
 
3519
  /* merge custom preferences from the providers */
 
3520
  GDK_THREADS_ENTER ();
 
3521
  thunar_window_merge_custom_preferences (window);
 
3522
  thunar_window_merge_go_actions (window);
 
3523
  GDK_THREADS_LEAVE ();
 
3524
 
 
3525
  thunar_window_bookmark_merge (window);
 
3526
 
 
3527
  return FALSE;
 
3528
}
 
3529
 
 
3530
 
 
3531
 
 
3532
static void
 
3533
thunar_window_merge_idle_destroy (gpointer user_data)
 
3534
{
 
3535
  THUNAR_WINDOW (user_data)->merge_idle_id = 0;
 
3536
}
 
3537
 
 
3538
 
 
3539
 
 
3540
static gboolean
 
3541
thunar_window_save_paned (ThunarWindow *window)
 
3542
{
 
3543
  _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
 
3544
 
 
3545
  g_object_set (G_OBJECT (window->preferences), "last-separator-position",
 
3546
                gtk_paned_get_position (GTK_PANED (window->paned)), NULL);
 
3547
 
 
3548
  /* for button release event */
 
3549
  return FALSE;
 
3550
}
 
3551
 
 
3552
 
 
3553
 
 
3554
static gboolean
 
3555
thunar_window_save_geometry_timer (gpointer user_data)
 
3556
{
 
3557
  GdkWindowState state;
 
3558
  ThunarWindow  *window = THUNAR_WINDOW (user_data);
 
3559
  gboolean       remember_geometry;
 
3560
  gint           width;
 
3561
  gint           height;
 
3562
 
 
3563
  GDK_THREADS_ENTER ();
 
3564
 
 
3565
  /* check if we should remember the window geometry */
 
3566
  g_object_get (G_OBJECT (window->preferences), "misc-remember-geometry", &remember_geometry, NULL);
 
3567
  if (G_LIKELY (remember_geometry))
 
3568
    {
 
3569
      /* check if the window is still visible */
 
3570
      if (gtk_widget_get_visible (GTK_WIDGET (window)))
 
3571
        {
 
3572
          /* determine the current state of the window */
 
3573
          state = gdk_window_get_state (GTK_WIDGET (window)->window);
 
3574
 
 
3575
          /* don't save geometry for maximized or fullscreen windows */
 
3576
          if ((state & (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN)) == 0)
 
3577
            {
 
3578
              /* determine the current width/height of the window... */
 
3579
              gtk_window_get_size (GTK_WINDOW (window), &width, &height);
 
3580
 
 
3581
              /* ...and remember them as default for new windows */
 
3582
              g_object_set (G_OBJECT (window->preferences), "last-window-width", width, "last-window-height", height,
 
3583
                            "last-window-maximized", FALSE, NULL);
 
3584
            }
 
3585
          else
 
3586
            {
 
3587
              /* only store that the window is full screen */
 
3588
              g_object_set (G_OBJECT (window->preferences), "last-window-maximized", TRUE, NULL);
 
3589
            }
 
3590
        }
 
3591
    }
 
3592
 
 
3593
  GDK_THREADS_LEAVE ();
 
3594
 
 
3595
  return FALSE;
 
3596
}
 
3597
 
 
3598
 
 
3599
 
 
3600
static void
 
3601
thunar_window_save_geometry_timer_destroy (gpointer user_data)
 
3602
{
 
3603
  THUNAR_WINDOW (user_data)->save_geometry_timer_id = 0;
 
3604
}
 
3605
 
 
3606
 
 
3607
 
 
3608
/**
 
3609
 * thunar_window_set_zoom_level:
 
3610
 * @window     : a #ThunarWindow instance.
 
3611
 * @zoom_level : the new zoom level for @window.
 
3612
 *
 
3613
 * Sets the zoom level for @window to @zoom_level.
 
3614
 **/
 
3615
void
 
3616
thunar_window_set_zoom_level (ThunarWindow   *window,
 
3617
                              ThunarZoomLevel zoom_level)
 
3618
{
 
3619
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
3620
  _thunar_return_if_fail (zoom_level < THUNAR_ZOOM_N_LEVELS);
 
3621
 
 
3622
  /* check if we have a new zoom level */
 
3623
  if (G_LIKELY (window->zoom_level != zoom_level))
 
3624
    {
 
3625
      /* remember the new zoom level */
 
3626
      window->zoom_level = zoom_level;
 
3627
 
 
3628
      /* notify listeners */
 
3629
      g_object_notify (G_OBJECT (window), "zoom-level");
 
3630
    }
 
3631
 
 
3632
  /* update the "Zoom In" and "Zoom Out" actions */
 
3633
  thunar_gtk_action_group_set_action_sensitive (window->action_group, "zoom-in", (zoom_level < THUNAR_ZOOM_N_LEVELS - 1));
 
3634
  thunar_gtk_action_group_set_action_sensitive (window->action_group, "zoom-out", (zoom_level > 0));
 
3635
}
 
3636
 
 
3637
 
 
3638
 
 
3639
/**
 
3640
 * thunar_window_get_current_directory:
 
3641
 * @window : a #ThunarWindow instance.
 
3642
 *
 
3643
 * Queries the #ThunarFile instance, which represents the directory
 
3644
 * currently displayed within @window. %NULL is returned if @window
 
3645
 * is not currently associated with any directory.
 
3646
 *
 
3647
 * Return value: the directory currently displayed within @window or %NULL.
 
3648
 **/
 
3649
ThunarFile*
 
3650
thunar_window_get_current_directory (ThunarWindow *window)
 
3651
{
 
3652
  _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), NULL);
 
3653
  return window->current_directory;
 
3654
}
 
3655
 
 
3656
 
 
3657
 
 
3658
/**
 
3659
 * thunar_window_set_current_directory:
 
3660
 * @window            : a #ThunarWindow instance.
 
3661
 * @current_directory : the new directory or %NULL.
 
3662
 **/
 
3663
void
 
3664
thunar_window_set_current_directory (ThunarWindow *window,
 
3665
                                     ThunarFile   *current_directory)
 
3666
{
 
3667
  GType       type;
 
3668
  GtkAction  *action;
 
3669
  gchar      *type_name;
 
3670
 
 
3671
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
3672
  _thunar_return_if_fail (current_directory == NULL || THUNAR_IS_FILE (current_directory));
 
3673
 
 
3674
  /* check if we already display the requested directory */
 
3675
  if (G_UNLIKELY (window->current_directory == current_directory))
 
3676
    return;
 
3677
 
 
3678
  /* disconnect from the previously active directory */
 
3679
  if (G_LIKELY (window->current_directory != NULL))
 
3680
    {
 
3681
      /* disconnect signals and release reference */
 
3682
      g_signal_handlers_disconnect_by_func (G_OBJECT (window->current_directory), thunar_window_current_directory_changed, window);
 
3683
      g_object_unref (G_OBJECT (window->current_directory));
 
3684
    }
 
3685
 
 
3686
  /* activate the new directory */
 
3687
  window->current_directory = current_directory;
 
3688
 
 
3689
  /* connect to the new directory */
 
3690
  if (G_LIKELY (current_directory != NULL))
 
3691
    {
 
3692
      /* take a reference on the file and connect the "changed"/"destroy" signals */
 
3693
      g_signal_connect (G_OBJECT (current_directory), "changed", G_CALLBACK (thunar_window_current_directory_changed), window);
 
3694
      g_object_ref (G_OBJECT (current_directory));
 
3695
 
 
3696
      /* create a new view if the window is new */
 
3697
      if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook)) == 0)
 
3698
        {
 
3699
          /* determine the last selected view if we don't have a valid default */
 
3700
          g_object_get (G_OBJECT (window->preferences), "last-view", &type_name, NULL);
 
3701
          type = g_type_from_name (type_name);
 
3702
 
 
3703
          /* activate the selected view */
 
3704
          action = gtk_action_group_get_action (window->action_group, "view-as-icons");
 
3705
          g_signal_handlers_block_by_func (action, thunar_window_action_view_changed, window);
 
3706
          gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), view_type2index (g_type_is_a (type, THUNAR_TYPE_VIEW) ? type : THUNAR_TYPE_ICON_VIEW));
 
3707
          thunar_window_action_view_changed (GTK_RADIO_ACTION (action), GTK_RADIO_ACTION (action), window);
 
3708
          g_signal_handlers_unblock_by_func (action, thunar_window_action_view_changed, window);
 
3709
        }
 
3710
 
 
3711
      /* update window icon and title */
 
3712
      thunar_window_current_directory_changed (current_directory, window);
 
3713
 
 
3714
      /* grab the focus to the main view */
 
3715
      if (G_LIKELY (window->view != NULL))
 
3716
        gtk_widget_grab_focus (window->view);
 
3717
    }
 
3718
 
 
3719
  /* enable the 'Open new window' action if we have a valid directory */
 
3720
  thunar_gtk_action_group_set_action_sensitive (window->action_group, "new-window", (current_directory != NULL));
 
3721
  thunar_gtk_action_group_set_action_sensitive (window->action_group, "new-tab", (current_directory != NULL));
 
3722
 
 
3723
  /* enable the 'Up' action if possible for the new directory */
 
3724
  thunar_gtk_action_group_set_action_sensitive (window->action_group, "open-parent", (current_directory != NULL
 
3725
                                                && thunar_file_has_parent (current_directory)));
 
3726
 
 
3727
  /* tell everybody that we have a new "current-directory",
 
3728
   * we do this first so other widgets display the new
 
3729
   * state already while the folder view is loading.
 
3730
   */
 
3731
  g_object_notify (G_OBJECT (window), "current-directory");
 
3732
}
 
3733
 
 
3734
 
 
3735
 
 
3736
/**
 
3737
 * thunar_window_scroll_to_file:
 
3738
 * @window      : a #ThunarWindow instance.
 
3739
 * @file        : a #ThunarFile.
 
3740
 * @select_file : if %TRUE the @file will also be selected.
 
3741
 * @use_align   : %TRUE to use the alignment arguments.
 
3742
 * @row_align   : the vertical alignment.
 
3743
 * @col_align   : the horizontal alignment.
 
3744
 *
 
3745
 * Tells the @window to scroll to the @file
 
3746
 * in the current view.
 
3747
 **/
 
3748
void
 
3749
thunar_window_scroll_to_file (ThunarWindow *window,
 
3750
                              ThunarFile   *file,
 
3751
                              gboolean      select_file,
 
3752
                              gboolean      use_align,
 
3753
                              gfloat        row_align,
 
3754
                              gfloat        col_align)
 
3755
{
 
3756
  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
3757
  _thunar_return_if_fail (THUNAR_IS_FILE (file));
 
3758
 
 
3759
  /* verify that we have a valid view */
 
3760
  if (G_LIKELY (window->view != NULL))
 
3761
    thunar_view_scroll_to_file (THUNAR_VIEW (window->view), file, select_file, use_align, row_align, col_align);
 
3762
}
 
3763
 
 
3764
 
 
3765
 
 
3766
gchar **
 
3767
thunar_window_get_directories (ThunarWindow *window,
 
3768
                               gint         *active_page)
 
3769
{
 
3770
  gint         n;
 
3771
  gint         n_pages;
 
3772
  gchar      **uris;
 
3773
  GtkWidget   *view;
 
3774
  ThunarFile  *directory;
 
3775
 
 
3776
  _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), NULL);
 
3777
 
 
3778
  n_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook));
 
3779
  if (G_UNLIKELY (n_pages == 0))
 
3780
    return NULL;
 
3781
 
 
3782
  /* create array of uris */
 
3783
  uris = g_new0 (gchar *, n_pages + 1);
 
3784
  for (n = 0; n < n_pages; n++)
 
3785
    {
 
3786
      /* get the view */
 
3787
      view = gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->notebook), n);
 
3788
      _thunar_return_val_if_fail (THUNAR_IS_NAVIGATOR (view), FALSE);
 
3789
 
 
3790
      /* get the directory of the view */
 
3791
      directory = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (view));
 
3792
      _thunar_return_val_if_fail (THUNAR_IS_FILE (directory), FALSE);
 
3793
 
 
3794
      /* add to array */
 
3795
      uris[n] = thunar_file_dup_uri (directory);
 
3796
    }
 
3797
 
 
3798
  /* selected tab */
 
3799
  if (active_page != NULL)
 
3800
    *active_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook));
 
3801
 
 
3802
  return uris;
 
3803
}
 
3804
 
 
3805
 
 
3806
 
 
3807
gboolean
 
3808
thunar_window_set_directories (ThunarWindow   *window,
 
3809
                               gchar         **uris,
 
3810
                               gint            active_page)
 
3811
{
 
3812
  ThunarFile *directory;
 
3813
  guint       n;
 
3814
 
 
3815
  _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
 
3816
  _thunar_return_val_if_fail (uris != NULL, FALSE);
 
3817
 
 
3818
  for (n = 0; uris[n] != NULL; n++)
 
3819
    {
 
3820
      /* check if the string looks like an uri */
 
3821
      if (!exo_str_looks_like_an_uri (uris[n]))
 
3822
        continue;
 
3823
 
 
3824
      /* get the file for the uri */
 
3825
      directory = thunar_file_get_for_uri (uris[n], NULL);
 
3826
      if (G_UNLIKELY (directory == NULL))
 
3827
        continue;
 
3828
 
 
3829
      /* open the directory in a new notebook */
 
3830
      if (thunar_file_is_directory (directory))
 
3831
        {
 
3832
          if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook)) == 0)
 
3833
            thunar_window_set_current_directory (window, directory);
 
3834
          else
 
3835
            thunar_window_notebook_insert (window, directory);
 
3836
        }
 
3837
 
 
3838
      g_object_unref (G_OBJECT (directory));
 
3839
    }
 
3840
 
 
3841
  /* select the page */
 
3842
  gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), active_page);
 
3843
 
 
3844
  /* we succeeded if new pages have been opened */
 
3845
  return gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook)) > 0;
 
3846
}