1 | /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ |
---|
2 | |
---|
3 | /* |
---|
4 | * Nautilus |
---|
5 | * |
---|
6 | * Copyright (C) 1999, 2000 Red Hat, Inc. |
---|
7 | * Copyright (C) 2000, 2001 Eazel, Inc. |
---|
8 | * |
---|
9 | * Nautilus is free software; you can redistribute it and/or |
---|
10 | * modify it under the terms of the GNU General Public License as |
---|
11 | * published by the Free Software Foundation; either version 2 of the |
---|
12 | * License, or (at your option) any later version. |
---|
13 | * |
---|
14 | * Nautilus is distributed in the hope that it will be useful, |
---|
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
17 | * General Public License for more details. |
---|
18 | * |
---|
19 | * You should have received a copy of the GNU General Public License |
---|
20 | * along with this program; if not, write to the Free Software |
---|
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
---|
22 | * |
---|
23 | * Authors: Elliot Lee <sopwith@redhat.com>, |
---|
24 | * Darin Adler <darin@bentspoon.com> |
---|
25 | * |
---|
26 | */ |
---|
27 | |
---|
28 | #include <config.h> |
---|
29 | #include "nautilus-application.h" |
---|
30 | |
---|
31 | #include "file-manager/fm-desktop-icon-view.h" |
---|
32 | #include "file-manager/fm-icon-view.h" |
---|
33 | #include "file-manager/fm-list-view.h" |
---|
34 | #include "file-manager/fm-search-list-view.h" |
---|
35 | #include "nautilus-desktop-window.h" |
---|
36 | #include "nautilus-first-time-druid.h" |
---|
37 | #include "nautilus-main.h" |
---|
38 | #include "nautilus-shell-interface.h" |
---|
39 | #include "nautilus-shell.h" |
---|
40 | #include <bonobo/bonobo-main.h> |
---|
41 | #include <bonobo/bonobo-object.h> |
---|
42 | #include <dirent.h> |
---|
43 | #include <eel/eel-gtk-macros.h> |
---|
44 | #include <eel/eel-stock-dialogs.h> |
---|
45 | #include <eel/eel-string-list.h> |
---|
46 | #include <eel/eel-string.h> |
---|
47 | #include <eel/eel-vfs-extensions.h> |
---|
48 | #include <eel/eel-gtk-extensions.h> |
---|
49 | #include <gdk/gdkx.h> |
---|
50 | #include <gtk/gtksignal.h> |
---|
51 | #include <libgnome/gnome-config.h> |
---|
52 | #include <libgnome/gnome-i18n.h> |
---|
53 | #include <libgnome/gnome-util.h> |
---|
54 | #include <libgnomeui/gnome-client.h> |
---|
55 | #include <libgnomeui/gnome-messagebox.h> |
---|
56 | #include <libgnomeui/gnome-stock-icons.h> |
---|
57 | #include <libgnomevfs/gnome-vfs-mime-handlers.h> |
---|
58 | #include <libgnomevfs/gnome-vfs-ops.h> |
---|
59 | #include <libgnomevfs/gnome-vfs-utils.h> |
---|
60 | #include <libnautilus-private/nautilus-file-utilities.h> |
---|
61 | #include <libnautilus-private/nautilus-global-preferences.h> |
---|
62 | #include <libnautilus-private/nautilus-icon-factory.h> |
---|
63 | #include <libnautilus-private/nautilus-metafile-factory.h> |
---|
64 | #include <libnautilus-private/nautilus-sound.h> |
---|
65 | #include <libnautilus-private/nautilus-bonobo-extensions.h> |
---|
66 | #include <libnautilus-private/nautilus-undo-manager.h> |
---|
67 | #include <libnautilus-private/nautilus-volume-monitor.h> |
---|
68 | #include <libnautilus-private/nautilus-authn-manager.h> |
---|
69 | #include <bonobo-activation/bonobo-activation.h> |
---|
70 | |
---|
71 | /* Needed for the is_kdesktop_present check */ |
---|
72 | #include <gdk/gdkx.h> |
---|
73 | #include <X11/Xlib.h> |
---|
74 | |
---|
75 | #define FACTORY_IID "OAFIID:Nautilus_Factory" |
---|
76 | #define SEARCH_LIST_VIEW_IID "OAFIID:Nautilus_File_Manager_Search_List_View" |
---|
77 | #define SHELL_IID "OAFIID:Nautilus_Shell" |
---|
78 | |
---|
79 | /* Keeps track of all the desktop windows. */ |
---|
80 | static GList *nautilus_application_desktop_windows; |
---|
81 | |
---|
82 | /* Keeps track of all the nautilus windows. */ |
---|
83 | static GList *nautilus_application_window_list; |
---|
84 | |
---|
85 | static gboolean need_to_show_first_time_druid (void); |
---|
86 | static void desktop_changed_callback (gpointer user_data); |
---|
87 | static void desktop_location_changed_callback (gpointer user_data); |
---|
88 | static void volume_mounted_callback (NautilusVolumeMonitor *monitor, |
---|
89 | NautilusVolume *volume, |
---|
90 | NautilusApplication *application); |
---|
91 | static void volume_unmounted_callback (NautilusVolumeMonitor *monitor, |
---|
92 | NautilusVolume *volume, |
---|
93 | NautilusApplication *application); |
---|
94 | static void update_session (gpointer callback_data); |
---|
95 | static void init_session (void); |
---|
96 | static gboolean is_kdesktop_present (void); |
---|
97 | |
---|
98 | BONOBO_CLASS_BOILERPLATE (NautilusApplication, nautilus_application, |
---|
99 | BonoboGenericFactory, BONOBO_GENERIC_FACTORY_TYPE) |
---|
100 | |
---|
101 | static CORBA_Object |
---|
102 | create_object (PortableServer_Servant servant, |
---|
103 | const CORBA_char *iid, |
---|
104 | CORBA_Environment *ev) |
---|
105 | { |
---|
106 | BonoboObject *object; |
---|
107 | FMDirectoryView *directory_view; |
---|
108 | NautilusApplication *application; |
---|
109 | |
---|
110 | if (strcmp (iid, NAUTILUS_ICON_VIEW_IID) == 0) { |
---|
111 | directory_view = FM_DIRECTORY_VIEW (g_object_new (fm_icon_view_get_type (), NULL)); |
---|
112 | object = BONOBO_OBJECT (fm_directory_view_get_nautilus_view (directory_view)); |
---|
113 | } else if (strcmp (iid, NAUTILUS_DESKTOP_ICON_VIEW_IID) == 0) { |
---|
114 | directory_view = FM_DIRECTORY_VIEW (g_object_new (fm_desktop_icon_view_get_type (), NULL)); |
---|
115 | object = BONOBO_OBJECT (fm_directory_view_get_nautilus_view (directory_view)); |
---|
116 | } else if (strcmp (iid, NAUTILUS_LIST_VIEW_IID) == 0) { |
---|
117 | directory_view = FM_DIRECTORY_VIEW (g_object_new (fm_list_view_get_type (), NULL)); |
---|
118 | object = BONOBO_OBJECT (fm_directory_view_get_nautilus_view (directory_view)); |
---|
119 | } else if (strcmp (iid, SEARCH_LIST_VIEW_IID) == 0) { |
---|
120 | directory_view = FM_DIRECTORY_VIEW (g_object_new (fm_search_list_view_get_type (), NULL)); |
---|
121 | object = BONOBO_OBJECT (fm_directory_view_get_nautilus_view (directory_view)); |
---|
122 | } else if (strcmp (iid, SHELL_IID) == 0) { |
---|
123 | application = NAUTILUS_APPLICATION (bonobo_object_from_servant (servant)); |
---|
124 | object = BONOBO_OBJECT (nautilus_shell_new (application)); |
---|
125 | } else if (strcmp (iid, METAFILE_FACTORY_IID) == 0) { |
---|
126 | object = BONOBO_OBJECT (nautilus_metafile_factory_get_instance ()); |
---|
127 | } else { |
---|
128 | object = CORBA_OBJECT_NIL; |
---|
129 | } |
---|
130 | |
---|
131 | return CORBA_Object_duplicate (BONOBO_OBJREF (object), ev); |
---|
132 | } |
---|
133 | |
---|
134 | GList * |
---|
135 | nautilus_application_get_window_list (void) |
---|
136 | { |
---|
137 | return nautilus_application_window_list; |
---|
138 | } |
---|
139 | |
---|
140 | static void |
---|
141 | nautilus_application_instance_init (NautilusApplication *application) |
---|
142 | { |
---|
143 | /* Create an undo manager */ |
---|
144 | application->undo_manager = nautilus_undo_manager_new (); |
---|
145 | |
---|
146 | /* Watch for volume mounts so we can restore open windows */ |
---|
147 | g_signal_connect_object (nautilus_volume_monitor_get (), "volume_mounted", |
---|
148 | G_CALLBACK (volume_mounted_callback), application, 0); |
---|
149 | |
---|
150 | /* Watch for volume unmounts so we can close open windows */ |
---|
151 | g_signal_connect_object (nautilus_volume_monitor_get (), "volume_unmounted", |
---|
152 | G_CALLBACK (volume_unmounted_callback), application, 0); |
---|
153 | } |
---|
154 | |
---|
155 | NautilusApplication * |
---|
156 | nautilus_application_new (void) |
---|
157 | { |
---|
158 | NautilusApplication *application; |
---|
159 | |
---|
160 | application = g_object_new (NAUTILUS_TYPE_APPLICATION, NULL); |
---|
161 | |
---|
162 | bonobo_generic_factory_construct_noreg (BONOBO_GENERIC_FACTORY (application), |
---|
163 | FACTORY_IID, |
---|
164 | NULL); |
---|
165 | |
---|
166 | return application; |
---|
167 | } |
---|
168 | |
---|
169 | static void |
---|
170 | nautilus_application_destroy (BonoboObject *object) |
---|
171 | { |
---|
172 | NautilusApplication *application; |
---|
173 | |
---|
174 | application = NAUTILUS_APPLICATION (object); |
---|
175 | |
---|
176 | nautilus_bookmarks_exiting (); |
---|
177 | |
---|
178 | bonobo_object_unref (application->undo_manager); |
---|
179 | |
---|
180 | EEL_CALL_PARENT (BONOBO_OBJECT_CLASS, destroy, (object)); |
---|
181 | } |
---|
182 | |
---|
183 | static gboolean |
---|
184 | check_required_directories (NautilusApplication *application) |
---|
185 | { |
---|
186 | char *user_directory; |
---|
187 | char *desktop_directory; |
---|
188 | EelStringList *directories; |
---|
189 | char *directories_as_string; |
---|
190 | char *error_string; |
---|
191 | char *dialog_title; |
---|
192 | GtkDialog *dialog; |
---|
193 | int failed_count; |
---|
194 | |
---|
195 | g_assert (NAUTILUS_IS_APPLICATION (application)); |
---|
196 | |
---|
197 | user_directory = nautilus_get_user_directory (); |
---|
198 | desktop_directory = nautilus_get_desktop_directory (); |
---|
199 | |
---|
200 | directories = eel_string_list_new (TRUE); |
---|
201 | |
---|
202 | if (!g_file_test (user_directory, G_FILE_TEST_IS_DIR)) { |
---|
203 | eel_string_list_insert (directories, user_directory); |
---|
204 | } |
---|
205 | g_free (user_directory); |
---|
206 | |
---|
207 | if (!g_file_test (desktop_directory, G_FILE_TEST_IS_DIR)) { |
---|
208 | eel_string_list_insert (directories, desktop_directory); |
---|
209 | } |
---|
210 | g_free (desktop_directory); |
---|
211 | |
---|
212 | failed_count = eel_string_list_get_length (directories); |
---|
213 | |
---|
214 | if (failed_count != 0) { |
---|
215 | directories_as_string = eel_string_list_as_string (directories, "\n", EEL_STRING_LIST_ALL_STRINGS); |
---|
216 | |
---|
217 | if (failed_count == 1) { |
---|
218 | dialog_title = g_strdup (_("Couldn't Create Required Folder")); |
---|
219 | error_string = g_strdup_printf (_("Nautilus could not create the required folder \"%s\". " |
---|
220 | "Before running Nautilus, please create this folder, or " |
---|
221 | "set permissions such that Nautilus can create it."), |
---|
222 | directories_as_string); |
---|
223 | } else { |
---|
224 | dialog_title = g_strdup (_("Couldn't Create Required Folders")); |
---|
225 | error_string = g_strdup_printf (_("Nautilus could not create the following required folders:\n\n" |
---|
226 | "%s\n\n" |
---|
227 | "Before running Nautilus, please create these folders, or " |
---|
228 | "set permissions such that Nautilus can create them."), |
---|
229 | directories_as_string); |
---|
230 | } |
---|
231 | |
---|
232 | dialog = eel_show_error_dialog (error_string, dialog_title, NULL); |
---|
233 | /* We need the main event loop so the user has a chance to see the dialog. */ |
---|
234 | nautilus_main_event_loop_register (GTK_OBJECT (dialog)); |
---|
235 | |
---|
236 | g_free (directories_as_string); |
---|
237 | g_free (error_string); |
---|
238 | g_free (dialog_title); |
---|
239 | } |
---|
240 | |
---|
241 | eel_string_list_free (directories); |
---|
242 | |
---|
243 | return failed_count == 0; |
---|
244 | } |
---|
245 | |
---|
246 | static int |
---|
247 | nautilus_strv_length (const char * const *strv) |
---|
248 | { |
---|
249 | const char * const *p; |
---|
250 | |
---|
251 | for (p = strv; *p != NULL; p++) { } |
---|
252 | return p - strv; |
---|
253 | } |
---|
254 | |
---|
255 | static Nautilus_URIList * |
---|
256 | nautilus_make_uri_list_from_shell_strv (const char * const *strv) |
---|
257 | { |
---|
258 | int length, i; |
---|
259 | Nautilus_URIList *uri_list; |
---|
260 | char *translated_uri; |
---|
261 | |
---|
262 | length = nautilus_strv_length (strv); |
---|
263 | |
---|
264 | uri_list = Nautilus_URIList__alloc (); |
---|
265 | uri_list->_maximum = length; |
---|
266 | uri_list->_length = length; |
---|
267 | uri_list->_buffer = CORBA_sequence_Nautilus_URI_allocbuf (length); |
---|
268 | for (i = 0; i < length; i++) { |
---|
269 | translated_uri = eel_make_uri_from_shell_arg (strv[i]); |
---|
270 | uri_list->_buffer[i] = CORBA_string_dup (translated_uri); |
---|
271 | g_free (translated_uri); |
---|
272 | translated_uri = NULL; |
---|
273 | } |
---|
274 | CORBA_sequence_set_release (uri_list, CORBA_TRUE); |
---|
275 | |
---|
276 | return uri_list; |
---|
277 | } |
---|
278 | |
---|
279 | static void |
---|
280 | migrate_old_nautilus_files (void) |
---|
281 | { |
---|
282 | char *new_desktop_dir, *np; |
---|
283 | char *old_desktop_dir, *op; |
---|
284 | char *old_desktop_dir_new_name; |
---|
285 | struct stat buf; |
---|
286 | DIR *dir; |
---|
287 | struct dirent *de; |
---|
288 | |
---|
289 | old_desktop_dir = g_strconcat (g_get_home_dir (), "/.nautilus/desktop", NULL); |
---|
290 | if (stat (old_desktop_dir, &buf) == -1) { |
---|
291 | g_free (old_desktop_dir); |
---|
292 | return; |
---|
293 | } |
---|
294 | if (!S_ISLNK (buf.st_mode)){ |
---|
295 | dir = opendir (old_desktop_dir); |
---|
296 | if (dir == NULL) { |
---|
297 | g_free (old_desktop_dir); |
---|
298 | return; |
---|
299 | } |
---|
300 | |
---|
301 | new_desktop_dir = nautilus_get_desktop_directory (); |
---|
302 | |
---|
303 | while ((de = readdir (dir)) != NULL){ |
---|
304 | if (de->d_name [0] == '.'){ |
---|
305 | if (de->d_name [0] == 0) |
---|
306 | continue; |
---|
307 | |
---|
308 | if (de->d_name [1] == '.' && de->d_name [2] == 0) |
---|
309 | continue; |
---|
310 | } |
---|
311 | |
---|
312 | op = g_strconcat (old_desktop_dir, "/", de->d_name, NULL); |
---|
313 | np = g_strconcat (new_desktop_dir, "/", de->d_name, NULL); |
---|
314 | |
---|
315 | rename (op, np); |
---|
316 | |
---|
317 | g_free (op); |
---|
318 | g_free (np); |
---|
319 | } |
---|
320 | |
---|
321 | closedir (dir); |
---|
322 | |
---|
323 | g_free (new_desktop_dir); |
---|
324 | } |
---|
325 | |
---|
326 | /* In case we miss something */ |
---|
327 | old_desktop_dir_new_name = g_strconcat (old_desktop_dir, "-old", NULL); |
---|
328 | rename (old_desktop_dir, old_desktop_dir_new_name); |
---|
329 | g_free (old_desktop_dir_new_name); |
---|
330 | |
---|
331 | g_free (old_desktop_dir); |
---|
332 | } |
---|
333 | |
---|
334 | static gint |
---|
335 | create_starthere_link_callback (gpointer data) |
---|
336 | { |
---|
337 | char *desktop_path; |
---|
338 | char *desktop_link_file; |
---|
339 | char *cmd; |
---|
340 | |
---|
341 | /* Create default services icon on the desktop */ |
---|
342 | desktop_path = nautilus_get_desktop_directory (); |
---|
343 | desktop_link_file = g_build_filename (desktop_path, |
---|
344 | "starthere.desktop", |
---|
345 | NULL); |
---|
346 | |
---|
347 | cmd = g_strconcat ("/bin/cp ", |
---|
348 | NAUTILUS_DATADIR, |
---|
349 | "/starthere-link.desktop ", |
---|
350 | desktop_link_file, |
---|
351 | NULL); |
---|
352 | |
---|
353 | if (system (cmd) != 0) { |
---|
354 | g_warning ("Failed to execute command '%s'\n", cmd); |
---|
355 | } |
---|
356 | |
---|
357 | g_free (desktop_path); |
---|
358 | g_free (desktop_link_file); |
---|
359 | g_free (cmd); |
---|
360 | |
---|
361 | return FALSE; |
---|
362 | } |
---|
363 | |
---|
364 | static void |
---|
365 | finish_startup (NautilusApplication *application) |
---|
366 | { |
---|
367 | /* initialize the sound machinery */ |
---|
368 | nautilus_sound_init (); |
---|
369 | |
---|
370 | /* initialize URI authentication manager */ |
---|
371 | nautilus_authentication_manager_init (); |
---|
372 | |
---|
373 | /* Make the desktop work with old Nautilus. */ |
---|
374 | migrate_old_nautilus_files (); |
---|
375 | } |
---|
376 | |
---|
377 | void |
---|
378 | nautilus_application_startup (NautilusApplication *application, |
---|
379 | gboolean kill_shell, |
---|
380 | gboolean restart_shell, |
---|
381 | gboolean no_default_window, |
---|
382 | gboolean no_desktop, |
---|
383 | gboolean do_first_time_druid_check, |
---|
384 | const char *geometry, |
---|
385 | const char *urls[]) |
---|
386 | { |
---|
387 | CORBA_Environment ev; |
---|
388 | Nautilus_Shell shell; |
---|
389 | Bonobo_RegistrationResult result; |
---|
390 | const char *message, *detailed_message; |
---|
391 | GtkDialog *dialog; |
---|
392 | Nautilus_URIList *url_list; |
---|
393 | const CORBA_char *corba_geometry; |
---|
394 | int num_failures; |
---|
395 | |
---|
396 | num_failures = 0; |
---|
397 | |
---|
398 | /* Check the user's ~/.nautilus directories and post warnings |
---|
399 | * if there are problems. |
---|
400 | */ |
---|
401 | if (!kill_shell && !check_required_directories (application)) { |
---|
402 | return; |
---|
403 | } |
---|
404 | |
---|
405 | /* Run the first time startup druid if needed. */ |
---|
406 | if (do_first_time_druid_check && need_to_show_first_time_druid ()) { |
---|
407 | /* Do this at idle time, once nautilus has initialized |
---|
408 | * itself. Otherwise we may spawn a second nautilus |
---|
409 | * process when looking for a metadata factory.. |
---|
410 | */ |
---|
411 | g_idle_add (create_starthere_link_callback, NULL); |
---|
412 | nautilus_set_first_time_file_flag (); |
---|
413 | } |
---|
414 | |
---|
415 | CORBA_exception_init (&ev); |
---|
416 | |
---|
417 | /* Start up the factory. */ |
---|
418 | while (TRUE) { |
---|
419 | /* Try to register the file manager view factory. */ |
---|
420 | result = nautilus_bonobo_activation_register_for_display |
---|
421 | (FACTORY_IID, BONOBO_OBJREF (application)); |
---|
422 | |
---|
423 | switch (result) { |
---|
424 | case Bonobo_ACTIVATION_REG_SUCCESS: |
---|
425 | /* We are registered and all is right with the world. */ |
---|
426 | finish_startup (application); |
---|
427 | case Bonobo_ACTIVATION_REG_ALREADY_ACTIVE: |
---|
428 | /* Another copy of nautilus already is running and registered. */ |
---|
429 | message = NULL; |
---|
430 | detailed_message = NULL; |
---|
431 | break; |
---|
432 | case Bonobo_ACTIVATION_REG_NOT_LISTED: |
---|
433 | /* Can't register myself due to trouble locating the |
---|
434 | * Nautilus_Shell.server file. This has happened when you |
---|
435 | * launch Nautilus with an LD_LIBRARY_PATH that |
---|
436 | * doesn't include the directory containing the oaf |
---|
437 | * library. It could also happen if the |
---|
438 | * Nautilus_Shell.server file was not present for some |
---|
439 | * reason. Sometimes killing oafd and gconfd fixes |
---|
440 | * this problem but we don't exactly understand why, |
---|
441 | * since neither of the above causes explain it. |
---|
442 | */ |
---|
443 | message = _("Nautilus can't be used now. " |
---|
444 | "Running the command \"bonobo-slay\"" |
---|
445 | " from the console may fix the problem. If not," |
---|
446 | " you can try rebooting the computer or" |
---|
447 | " installing Nautilus again."); |
---|
448 | /* FIXME bugzilla.gnome.org 42536: The guesses and stuff here are lame. */ |
---|
449 | detailed_message = _("Nautilus can't be used now. " |
---|
450 | "Running the command \"bonobo-slay\" " |
---|
451 | "from the console may fix the problem. If not, " |
---|
452 | "you can try rebooting the computer or " |
---|
453 | "installing Nautilus again.\n\n" |
---|
454 | "Bonobo couldn't locate the Nautilus_shell.server file. " |
---|
455 | "One cause of this seems to be an LD_LIBRARY_PATH " |
---|
456 | "that does not include the bonobo-activation library's directory. " |
---|
457 | "Another possible cause would be bad install " |
---|
458 | "with a missing Nautilus_Shell.server file.\n\n" |
---|
459 | "Running \"bonobo-slay\" will kill all " |
---|
460 | "Bonobo Activation and GConf processes, which may be needed by " |
---|
461 | "other applications.\n\n" |
---|
462 | "Sometimes killing bonobo-activation-server and gconfd fixes " |
---|
463 | "the problem, but we don't know why.\n\n" |
---|
464 | "We have also seen this error when a faulty " |
---|
465 | "version of bonobo-activation was installed."); |
---|
466 | break; |
---|
467 | default: |
---|
468 | /* This should never happen. */ |
---|
469 | g_warning ("bad error code from bonobo_activation_active_server_register"); |
---|
470 | case Bonobo_ACTIVATION_REG_ERROR: |
---|
471 | /* Some misc. error (can never happen with current |
---|
472 | * version of bonobo-activation). Show dialog and terminate the |
---|
473 | * program. |
---|
474 | */ |
---|
475 | /* FIXME bugzilla.gnome.org 42537: Looks like this does happen with the |
---|
476 | * current OAF. I guess I read the code wrong. Need to figure out when and make a |
---|
477 | * good message. |
---|
478 | */ |
---|
479 | message = _("Nautilus can't be used now, due to an unexpected error."); |
---|
480 | detailed_message = _("Nautilus can't be used now, due to an unexpected error " |
---|
481 | "from Bonobo when attempting to register the file manager view server."); |
---|
482 | break; |
---|
483 | } |
---|
484 | |
---|
485 | /* Get the shell object. */ |
---|
486 | if (message == NULL) { |
---|
487 | shell = bonobo_activation_activate_from_id (SHELL_IID, 0, NULL, NULL); |
---|
488 | if (!CORBA_Object_is_nil (shell, &ev)) { |
---|
489 | break; |
---|
490 | } |
---|
491 | |
---|
492 | /* If we couldn't find ourselves it's a bad problem so |
---|
493 | * we better stop looping. |
---|
494 | */ |
---|
495 | if (result == Bonobo_ACTIVATION_REG_SUCCESS) { |
---|
496 | /* FIXME bugzilla.gnome.org 42538: When can this happen? */ |
---|
497 | message = _("Nautilus can't be used now, due to an unexpected error."); |
---|
498 | detailed_message = _("Nautilus can't be used now, due to an unexpected error " |
---|
499 | "from Bonobo when attempting to locate the factory." |
---|
500 | "Killing bonobo-activation-server and restarting Nautilus may help fix the problem."); |
---|
501 | } else { |
---|
502 | num_failures++; |
---|
503 | if (num_failures > 20) { |
---|
504 | message = _("Nautilus can't be used now, due to an unexpected error."); |
---|
505 | detailed_message = _("Nautilus can't be used now, due to an unexpected error " |
---|
506 | "from Bonobo when attempting to locate the shell object. " |
---|
507 | "Killing bonobo-activation-server and restarting Nautilus may help fix the problem."); |
---|
508 | |
---|
509 | } |
---|
510 | } |
---|
511 | } |
---|
512 | |
---|
513 | if (message != NULL) { |
---|
514 | dialog = eel_show_error_dialog_with_details (message, NULL, detailed_message, NULL); |
---|
515 | /* We need the main event loop so the user has a chance to see the dialog. */ |
---|
516 | nautilus_main_event_loop_register (GTK_OBJECT (dialog)); |
---|
517 | goto out; |
---|
518 | } |
---|
519 | } |
---|
520 | |
---|
521 | if (kill_shell) { |
---|
522 | Nautilus_Shell_quit (shell, &ev); |
---|
523 | } else if (restart_shell) { |
---|
524 | Nautilus_Shell_restart (shell, &ev); |
---|
525 | } else { |
---|
526 | /* If KDE desktop is running, then force no_desktop */ |
---|
527 | if (is_kdesktop_present ()) { |
---|
528 | no_desktop = TRUE; |
---|
529 | } |
---|
530 | |
---|
531 | if (!no_desktop && eel_preferences_get_boolean (NAUTILUS_PREFERENCES_SHOW_DESKTOP)) { |
---|
532 | Nautilus_Shell_start_desktop (shell, &ev); |
---|
533 | } |
---|
534 | |
---|
535 | /* Monitor the preference to show or hide the desktop */ |
---|
536 | eel_preferences_add_callback_while_alive (NAUTILUS_PREFERENCES_SHOW_DESKTOP, |
---|
537 | desktop_changed_callback, |
---|
538 | application, |
---|
539 | G_OBJECT (application)); |
---|
540 | |
---|
541 | /* Monitor the preference to have the desktop */ |
---|
542 | /* point to the Unix home folder */ |
---|
543 | eel_preferences_add_callback_while_alive (NAUTILUS_PREFERENCES_DESKTOP_IS_HOME_DIR, |
---|
544 | desktop_location_changed_callback, |
---|
545 | NULL, |
---|
546 | G_OBJECT (application)); |
---|
547 | |
---|
548 | /* CORBA C mapping doesn't allow NULL to be passed |
---|
549 | for string parameters */ |
---|
550 | corba_geometry = (geometry != NULL) ? geometry : ""; |
---|
551 | |
---|
552 | /* Create the other windows. */ |
---|
553 | if (urls != NULL) { |
---|
554 | url_list = nautilus_make_uri_list_from_shell_strv (urls); |
---|
555 | Nautilus_Shell_open_windows (shell, url_list, corba_geometry, &ev); |
---|
556 | CORBA_free (url_list); |
---|
557 | } else if (!no_default_window) { |
---|
558 | Nautilus_Shell_open_default_window (shell, corba_geometry, &ev); |
---|
559 | } |
---|
560 | |
---|
561 | /* Add ourselves to the session */ |
---|
562 | init_session (); |
---|
563 | } |
---|
564 | |
---|
565 | /* We're done with the shell now, so let it go. */ |
---|
566 | /* HACK: Don't bother releasing the shell in the case where we |
---|
567 | * just told it to quit -- that just leads to hangs and does |
---|
568 | * no good. We could probably fix this in some fancier way if |
---|
569 | * we could figure out a better lifetime rule. |
---|
570 | */ |
---|
571 | if (!(kill_shell || restart_shell)) { |
---|
572 | bonobo_object_release_unref (shell, NULL); |
---|
573 | } |
---|
574 | |
---|
575 | out: |
---|
576 | CORBA_exception_free (&ev); |
---|
577 | } |
---|
578 | |
---|
579 | static void |
---|
580 | nautilus_application_create_desktop_windows (NautilusApplication *application) |
---|
581 | { |
---|
582 | static gboolean create_in_progress = FALSE; |
---|
583 | GdkDisplay *display; |
---|
584 | NautilusDesktopWindow *window; |
---|
585 | int screens, i; |
---|
586 | |
---|
587 | g_return_if_fail (nautilus_application_desktop_windows == NULL); |
---|
588 | g_return_if_fail (NAUTILUS_IS_APPLICATION (application)); |
---|
589 | |
---|
590 | if (create_in_progress) { |
---|
591 | return; |
---|
592 | } |
---|
593 | |
---|
594 | create_in_progress = TRUE; |
---|
595 | |
---|
596 | display = gdk_display_get_default (); |
---|
597 | screens = gdk_display_get_n_screens (display); |
---|
598 | |
---|
599 | for (i = 0; i < screens; i++) { |
---|
600 | window = nautilus_desktop_window_new (application, |
---|
601 | gdk_display_get_screen (display, i)); |
---|
602 | /* We realize it immediately so that the NAUTILUS_DESKTOP_WINDOW_ID |
---|
603 | property is set so gnome-settings-daemon doesn't try to set the |
---|
604 | background. And we do a gdk_flush() to be sure X gets it. */ |
---|
605 | gtk_widget_realize (GTK_WIDGET (window)); |
---|
606 | gdk_flush (); |
---|
607 | |
---|
608 | nautilus_application_desktop_windows = |
---|
609 | g_list_prepend (nautilus_application_desktop_windows, window); |
---|
610 | } |
---|
611 | |
---|
612 | create_in_progress = FALSE; |
---|
613 | } |
---|
614 | |
---|
615 | void |
---|
616 | nautilus_application_open_desktop (NautilusApplication *application) |
---|
617 | { |
---|
618 | if (nautilus_application_desktop_windows == NULL) { |
---|
619 | nautilus_application_create_desktop_windows (application); |
---|
620 | } |
---|
621 | } |
---|
622 | |
---|
623 | void |
---|
624 | nautilus_application_close_desktop (void) |
---|
625 | { |
---|
626 | if (nautilus_application_desktop_windows != NULL) { |
---|
627 | g_list_foreach (nautilus_application_desktop_windows, |
---|
628 | (GFunc) gtk_widget_destroy, NULL); |
---|
629 | g_list_free (nautilus_application_desktop_windows); |
---|
630 | nautilus_application_desktop_windows = NULL; |
---|
631 | } |
---|
632 | } |
---|
633 | |
---|
634 | void |
---|
635 | nautilus_application_close_all_windows (void) |
---|
636 | { |
---|
637 | while (nautilus_application_window_list != NULL) { |
---|
638 | nautilus_window_close (NAUTILUS_WINDOW (nautilus_application_window_list->data)); |
---|
639 | } |
---|
640 | } |
---|
641 | |
---|
642 | static void |
---|
643 | nautilus_application_destroyed_window (GtkObject *object, NautilusApplication *application) |
---|
644 | { |
---|
645 | nautilus_application_window_list = g_list_remove (nautilus_application_window_list, object); |
---|
646 | } |
---|
647 | |
---|
648 | static gboolean |
---|
649 | nautilus_window_delete_event_callback (GtkWidget *widget, |
---|
650 | GdkEvent *event, |
---|
651 | gpointer user_data) |
---|
652 | { |
---|
653 | NautilusWindow *window; |
---|
654 | |
---|
655 | window = NAUTILUS_WINDOW (widget); |
---|
656 | nautilus_window_close (window); |
---|
657 | |
---|
658 | return TRUE; |
---|
659 | } |
---|
660 | |
---|
661 | static gboolean |
---|
662 | save_window_geometry_timeout (gpointer callback_data) |
---|
663 | { |
---|
664 | NautilusWindow *window; |
---|
665 | |
---|
666 | window = NAUTILUS_WINDOW (callback_data); |
---|
667 | |
---|
668 | nautilus_window_save_geometry (window); |
---|
669 | |
---|
670 | window->save_geometry_timeout_id = 0; |
---|
671 | return FALSE; |
---|
672 | } |
---|
673 | |
---|
674 | static gboolean |
---|
675 | nautilus_window_configure_event_callback (GtkWidget *widget, |
---|
676 | GdkEventConfigure *event, |
---|
677 | gpointer callback_data) |
---|
678 | { |
---|
679 | NautilusWindow *window; |
---|
680 | char *geometry_string; |
---|
681 | |
---|
682 | window = NAUTILUS_WINDOW (widget); |
---|
683 | |
---|
684 | /* Only save the geometry if the user hasn't resized the window |
---|
685 | * for half a second. Otherwise delay the callback another half second. |
---|
686 | */ |
---|
687 | if (window->save_geometry_timeout_id != 0) { |
---|
688 | g_source_remove (window->save_geometry_timeout_id); |
---|
689 | } |
---|
690 | if (GTK_WIDGET_VISIBLE (GTK_WIDGET (window)) && !NAUTILUS_IS_DESKTOP_WINDOW (window)) { |
---|
691 | |
---|
692 | geometry_string = eel_gtk_window_get_geometry_string (GTK_WINDOW (window)); |
---|
693 | |
---|
694 | /* If the last geometry is NULL the window must have just |
---|
695 | * been shown. No need to save geometry to disk since it |
---|
696 | * must be the same. |
---|
697 | */ |
---|
698 | if (window->last_geometry == NULL) { |
---|
699 | window->last_geometry = geometry_string; |
---|
700 | return FALSE; |
---|
701 | } |
---|
702 | |
---|
703 | /* Don't save geometry if it's the same as before. */ |
---|
704 | if (!strcmp (window->last_geometry, geometry_string)) { |
---|
705 | g_free (geometry_string); |
---|
706 | return FALSE; |
---|
707 | } |
---|
708 | |
---|
709 | g_free (window->last_geometry); |
---|
710 | window->last_geometry = geometry_string; |
---|
711 | |
---|
712 | window->save_geometry_timeout_id = |
---|
713 | g_timeout_add (500, save_window_geometry_timeout, window); |
---|
714 | } |
---|
715 | |
---|
716 | return FALSE; |
---|
717 | } |
---|
718 | |
---|
719 | static gboolean |
---|
720 | nautilus_window_unrealize_event_callback (GtkWidget *widget, |
---|
721 | GdkEvent *event, |
---|
722 | gpointer callback_data) |
---|
723 | { |
---|
724 | NautilusWindow *window; |
---|
725 | |
---|
726 | window = NAUTILUS_WINDOW (widget); |
---|
727 | |
---|
728 | if (window->save_geometry_timeout_id != 0) { |
---|
729 | g_source_remove (window->save_geometry_timeout_id); |
---|
730 | window->save_geometry_timeout_id = 0; |
---|
731 | nautilus_window_save_geometry (window); |
---|
732 | } |
---|
733 | |
---|
734 | return FALSE; |
---|
735 | } |
---|
736 | |
---|
737 | NautilusWindow * |
---|
738 | nautilus_application_create_window (NautilusApplication *application, |
---|
739 | GdkScreen *screen) |
---|
740 | { |
---|
741 | NautilusWindow *window; |
---|
742 | |
---|
743 | g_return_val_if_fail (NAUTILUS_IS_APPLICATION (application), NULL); |
---|
744 | |
---|
745 | window = NAUTILUS_WINDOW (gtk_widget_new (nautilus_window_get_type (), |
---|
746 | "app", application, |
---|
747 | "app_id", "nautilus", |
---|
748 | "screen", screen, |
---|
749 | NULL)); |
---|
750 | |
---|
751 | g_signal_connect (window, "delete_event", |
---|
752 | G_CALLBACK (nautilus_window_delete_event_callback), NULL); |
---|
753 | |
---|
754 | g_signal_connect_object (window, "destroy", |
---|
755 | G_CALLBACK (nautilus_application_destroyed_window), application, 0); |
---|
756 | |
---|
757 | g_signal_connect (window, "configure_event", |
---|
758 | G_CALLBACK (nautilus_window_configure_event_callback), NULL); |
---|
759 | |
---|
760 | g_signal_connect (window, "unrealize", |
---|
761 | G_CALLBACK (nautilus_window_unrealize_event_callback), NULL); |
---|
762 | |
---|
763 | nautilus_application_window_list = g_list_prepend (nautilus_application_window_list, window); |
---|
764 | |
---|
765 | /* Do not yet show the window. It will be shown later on if it can |
---|
766 | * successfully display its initial URI. Otherwise it will be destroyed |
---|
767 | * without ever having seen the light of day. |
---|
768 | */ |
---|
769 | |
---|
770 | return window; |
---|
771 | } |
---|
772 | |
---|
773 | /* callback for changing the directory the desktop points to */ |
---|
774 | static void |
---|
775 | desktop_location_changed_callback (gpointer user_data) |
---|
776 | { |
---|
777 | if (nautilus_application_desktop_windows != NULL) { |
---|
778 | g_list_foreach (nautilus_application_desktop_windows, |
---|
779 | (GFunc) nautilus_desktop_window_update_directory, NULL); |
---|
780 | } |
---|
781 | } |
---|
782 | |
---|
783 | /* callback for showing or hiding the desktop based on the user's preference */ |
---|
784 | static void |
---|
785 | desktop_changed_callback (gpointer user_data) |
---|
786 | { |
---|
787 | NautilusApplication *application; |
---|
788 | |
---|
789 | application = NAUTILUS_APPLICATION (user_data); |
---|
790 | if ( eel_preferences_get_boolean (NAUTILUS_PREFERENCES_SHOW_DESKTOP)) { |
---|
791 | nautilus_application_open_desktop (application); |
---|
792 | } else { |
---|
793 | nautilus_application_close_desktop (); |
---|
794 | } |
---|
795 | |
---|
796 | /* Can't make this function just watch the preference |
---|
797 | * itself changing since ordering is important |
---|
798 | */ |
---|
799 | update_session (gnome_master_client ()); |
---|
800 | } |
---|
801 | |
---|
802 | /* |
---|
803 | * need_to_show_first_time_druid |
---|
804 | * |
---|
805 | * Determine whether Nautilus needs to show the first time druid. |
---|
806 | * |
---|
807 | * Note that the flag file indicating whether the druid has been |
---|
808 | * presented is: ~/.nautilus/first-time-flag. |
---|
809 | * |
---|
810 | * Another alternative could be to use preferences to store this flag |
---|
811 | * However, there because of bug 41229 this is not yet possible. |
---|
812 | * |
---|
813 | * Also, for debugging purposes, it is convenient to have just one file |
---|
814 | * to kill in order to test the startup druid: |
---|
815 | * |
---|
816 | * rm -f ~/.nautilus/first-time-flag |
---|
817 | * |
---|
818 | * In order to accomplish the same thing with preferences, you would have |
---|
819 | * to either kill ALL your preferences or spend time digging in ~/.gconf |
---|
820 | * xml files finding the right one. |
---|
821 | */ |
---|
822 | static gboolean |
---|
823 | need_to_show_first_time_druid (void) |
---|
824 | { |
---|
825 | gboolean result; |
---|
826 | char *user_directory; |
---|
827 | char *druid_flag_file_name; |
---|
828 | |
---|
829 | user_directory = nautilus_get_user_directory (); |
---|
830 | |
---|
831 | druid_flag_file_name = g_strconcat (user_directory, "/first-time-flag", NULL); |
---|
832 | result = !g_file_test (druid_flag_file_name, G_FILE_TEST_EXISTS); |
---|
833 | g_free (druid_flag_file_name); |
---|
834 | |
---|
835 | /* we changed the name of the flag for version 1.0, so we should |
---|
836 | * check for and delete the old one, if the new one didn't exist |
---|
837 | */ |
---|
838 | if (result) { |
---|
839 | druid_flag_file_name = g_strconcat (user_directory, "/first-time-wizard-flag", NULL); |
---|
840 | unlink (druid_flag_file_name); |
---|
841 | g_free (druid_flag_file_name); |
---|
842 | } |
---|
843 | g_free (user_directory); |
---|
844 | return result; |
---|
845 | } |
---|
846 | |
---|
847 | /* Apps like redhat-config-packages that are using the CD-ROM |
---|
848 | * directly, can grab ownership of the _NAUTILUS_DISABLE_MOUNT_WINDOW |
---|
849 | * selection to temporarily disable the new window behavior. |
---|
850 | */ |
---|
851 | static gboolean |
---|
852 | check_mount_window_disabled (void) |
---|
853 | { |
---|
854 | Atom selection_atom = gdk_x11_get_xatom_by_name ("_NAUTILUS_DISABLE_MOUNT_WINDOW"); |
---|
855 | |
---|
856 | if (XGetSelectionOwner (GDK_DISPLAY(), selection_atom) != None) |
---|
857 | return TRUE; |
---|
858 | else |
---|
859 | return FALSE; |
---|
860 | } |
---|
861 | |
---|
862 | static void |
---|
863 | volume_mounted_callback (NautilusVolumeMonitor *monitor, NautilusVolume *volume, |
---|
864 | NautilusApplication *application) |
---|
865 | { |
---|
866 | NautilusWindow *window; |
---|
867 | char *uri; |
---|
868 | |
---|
869 | if (volume == NULL || application == NULL) { |
---|
870 | return; |
---|
871 | } |
---|
872 | |
---|
873 | /* Open a window to the CD if the user has set that preference. */ |
---|
874 | if (nautilus_volume_get_device_type (volume) == NAUTILUS_DEVICE_CDROM_DRIVE |
---|
875 | && eel_gconf_get_boolean( "/apps/magicdev/do_fileman_window") |
---|
876 | && !check_mount_window_disabled ()) { |
---|
877 | window = nautilus_application_create_window (application, gdk_screen_get_default ()); |
---|
878 | uri = gnome_vfs_get_uri_from_local_path (nautilus_volume_get_mount_path (volume)); |
---|
879 | nautilus_window_go_to (window, uri); |
---|
880 | g_free (uri); |
---|
881 | } |
---|
882 | } |
---|
883 | |
---|
884 | static gboolean |
---|
885 | window_can_be_closed (NautilusWindow *window) |
---|
886 | { |
---|
887 | if (!NAUTILUS_IS_DESKTOP_WINDOW (window)) { |
---|
888 | return TRUE; |
---|
889 | } |
---|
890 | |
---|
891 | return FALSE; |
---|
892 | } |
---|
893 | |
---|
894 | static gboolean |
---|
895 | is_last_closable_window (NautilusWindow *window) |
---|
896 | { |
---|
897 | GList *node, *window_list; |
---|
898 | |
---|
899 | window_list = nautilus_application_get_window_list (); |
---|
900 | |
---|
901 | for (node = window_list; node != NULL; node = node->next) { |
---|
902 | if (window != NAUTILUS_WINDOW (node->data) && window_can_be_closed (NAUTILUS_WINDOW (node->data))) { |
---|
903 | return FALSE; |
---|
904 | } |
---|
905 | } |
---|
906 | |
---|
907 | return TRUE; |
---|
908 | } |
---|
909 | |
---|
910 | |
---|
911 | /* Called whenever a volume is unmounted. Check and see if there are any windows open |
---|
912 | * displaying contents on the volume. If there are, close them. |
---|
913 | * It would also be cool to save open window and position info. |
---|
914 | */ |
---|
915 | static void |
---|
916 | volume_unmounted_callback (NautilusVolumeMonitor *monitor, NautilusVolume *volume, |
---|
917 | NautilusApplication *application) |
---|
918 | { |
---|
919 | GList *window_list, *node, *close_list; |
---|
920 | NautilusWindow *window; |
---|
921 | char *uri; |
---|
922 | char *path; |
---|
923 | |
---|
924 | close_list = NULL; |
---|
925 | |
---|
926 | /* Check and see if any of the open windows are displaying contents from the unmounted volume */ |
---|
927 | window_list = nautilus_application_get_window_list (); |
---|
928 | |
---|
929 | /* Construct a list of windows to be closed. Do not add the non-closable windows to the list. */ |
---|
930 | for (node = window_list; node != NULL; node = node->next) { |
---|
931 | window = NAUTILUS_WINDOW (node->data); |
---|
932 | if (window != NULL && window_can_be_closed (window)) { |
---|
933 | uri = nautilus_window_get_location (window); |
---|
934 | path = gnome_vfs_get_local_path_from_uri (uri); |
---|
935 | if (eel_str_has_prefix (path, nautilus_volume_get_mount_path (volume))) { |
---|
936 | close_list = g_list_prepend (close_list, window); |
---|
937 | } |
---|
938 | g_free (path); |
---|
939 | g_free (uri); |
---|
940 | } |
---|
941 | } |
---|
942 | |
---|
943 | /* Handle the windows in the close list. */ |
---|
944 | for (node = close_list; node != NULL; node = node->next) { |
---|
945 | window = NAUTILUS_WINDOW (node->data); |
---|
946 | if (is_last_closable_window (window)) { |
---|
947 | /* Don't close the last or only window. Try to redirect to the default home directory. */ |
---|
948 | nautilus_window_go_home (window); |
---|
949 | } else { |
---|
950 | nautilus_window_close (window); |
---|
951 | } |
---|
952 | } |
---|
953 | |
---|
954 | g_list_free (close_list); |
---|
955 | } |
---|
956 | |
---|
957 | |
---|
958 | static void |
---|
959 | removed_from_session (GnomeClient *client, gpointer data) |
---|
960 | { |
---|
961 | nautilus_main_event_loop_quit (); |
---|
962 | } |
---|
963 | |
---|
964 | static gint |
---|
965 | save_session (GnomeClient *client, gint phase, GnomeSaveStyle save_style, gint shutdown, |
---|
966 | GnomeInteractStyle interact_style, gint fast, gpointer data) |
---|
967 | { |
---|
968 | NautilusWindow *window; |
---|
969 | GList *l; |
---|
970 | static char *clone_argv[] = { "nautilus", "--no-default-window" }; |
---|
971 | char **restart_argv; |
---|
972 | int argc; |
---|
973 | int i; |
---|
974 | int num_windows; |
---|
975 | |
---|
976 | num_windows = g_list_length (nautilus_application_window_list); |
---|
977 | if (num_windows > 0) { |
---|
978 | argc = 1 + num_windows; |
---|
979 | i = 0; |
---|
980 | restart_argv = g_new (char *, argc); |
---|
981 | restart_argv[i++] = g_strdup ("nautilus"); |
---|
982 | for (l = nautilus_application_window_list; l != NULL; l = l->next) { |
---|
983 | window = NAUTILUS_WINDOW (l->data); |
---|
984 | restart_argv[i++] = nautilus_window_get_location (window); |
---|
985 | } |
---|
986 | |
---|
987 | gnome_client_set_restart_command (client, argc, restart_argv); |
---|
988 | |
---|
989 | for (i = 0; i < argc; i++) { |
---|
990 | g_free (restart_argv[i]); |
---|
991 | } |
---|
992 | g_free (restart_argv); |
---|
993 | } else { |
---|
994 | gnome_client_set_restart_command (client, |
---|
995 | G_N_ELEMENTS (clone_argv), |
---|
996 | clone_argv); |
---|
997 | } |
---|
998 | |
---|
999 | return TRUE; |
---|
1000 | } |
---|
1001 | |
---|
1002 | static void |
---|
1003 | set_session_restart (GnomeClient *client, gboolean restart) |
---|
1004 | { |
---|
1005 | gnome_client_set_priority (client, 40); |
---|
1006 | |
---|
1007 | if (restart && g_getenv ("NAUTILUS_DEBUG") == NULL) { |
---|
1008 | /* Don't respawn in debug mode */ |
---|
1009 | gnome_client_set_restart_style (client, GNOME_RESTART_IMMEDIATELY); |
---|
1010 | } else { |
---|
1011 | gnome_client_set_restart_style (client, GNOME_RESTART_IF_RUNNING); |
---|
1012 | } |
---|
1013 | } |
---|
1014 | |
---|
1015 | static void |
---|
1016 | update_session (gpointer callback_data) |
---|
1017 | { |
---|
1018 | set_session_restart (callback_data, |
---|
1019 | eel_preferences_get_boolean (NAUTILUS_PREFERENCES_ADD_TO_SESSION) |
---|
1020 | /* Only ever add ourselves to the session |
---|
1021 | * if we have a desktop window. Prevents the |
---|
1022 | * session thrashing that's seen otherwise |
---|
1023 | */ |
---|
1024 | && nautilus_application_desktop_windows != NULL); |
---|
1025 | } |
---|
1026 | |
---|
1027 | static void |
---|
1028 | init_session (void) |
---|
1029 | { |
---|
1030 | GnomeClient *client; |
---|
1031 | |
---|
1032 | client = gnome_master_client (); |
---|
1033 | |
---|
1034 | g_signal_connect (client, "save_yourself", |
---|
1035 | G_CALLBACK (save_session), NULL); |
---|
1036 | |
---|
1037 | g_signal_connect (client, "die", |
---|
1038 | G_CALLBACK (removed_from_session), NULL); |
---|
1039 | |
---|
1040 | eel_preferences_add_callback |
---|
1041 | (NAUTILUS_PREFERENCES_ADD_TO_SESSION, |
---|
1042 | update_session, client); |
---|
1043 | |
---|
1044 | update_session (client); |
---|
1045 | } |
---|
1046 | |
---|
1047 | #ifdef UGLY_HACK_TO_DETECT_KDE |
---|
1048 | |
---|
1049 | static gboolean |
---|
1050 | get_self_typed_prop (Window xwindow, |
---|
1051 | Atom atom, |
---|
1052 | gulong *val) |
---|
1053 | { |
---|
1054 | Atom type; |
---|
1055 | int format; |
---|
1056 | gulong nitems; |
---|
1057 | gulong bytes_after; |
---|
1058 | gulong *num; |
---|
1059 | int err; |
---|
1060 | |
---|
1061 | gdk_error_trap_push (); |
---|
1062 | type = None; |
---|
1063 | XGetWindowProperty (gdk_display, |
---|
1064 | xwindow, |
---|
1065 | atom, |
---|
1066 | 0, G_MAXLONG, |
---|
1067 | False, atom, &type, &format, &nitems, |
---|
1068 | &bytes_after, (guchar **)&num); |
---|
1069 | |
---|
1070 | err = gdk_error_trap_pop (); |
---|
1071 | if (err != Success) { |
---|
1072 | return FALSE; |
---|
1073 | } |
---|
1074 | |
---|
1075 | if (type != atom) { |
---|
1076 | return FALSE; |
---|
1077 | } |
---|
1078 | |
---|
1079 | if (val) |
---|
1080 | *val = *num; |
---|
1081 | |
---|
1082 | XFree (num); |
---|
1083 | |
---|
1084 | return TRUE; |
---|
1085 | } |
---|
1086 | |
---|
1087 | static gboolean |
---|
1088 | has_wm_state (Window xwindow) |
---|
1089 | { |
---|
1090 | return get_self_typed_prop (xwindow, |
---|
1091 | XInternAtom (gdk_display, "WM_STATE", False), |
---|
1092 | NULL); |
---|
1093 | } |
---|
1094 | |
---|
1095 | static gboolean |
---|
1096 | look_for_kdesktop_recursive (Window xwindow) |
---|
1097 | { |
---|
1098 | |
---|
1099 | Window ignored1, ignored2; |
---|
1100 | Window *children; |
---|
1101 | unsigned int n_children; |
---|
1102 | unsigned int i; |
---|
1103 | gboolean retval; |
---|
1104 | |
---|
1105 | /* If WM_STATE is set, this is a managed client, so look |
---|
1106 | * for the class hint and end recursion. Otherwise, |
---|
1107 | * this is probably just a WM frame, so keep recursing. |
---|
1108 | */ |
---|
1109 | if (has_wm_state (xwindow)) { |
---|
1110 | XClassHint ch; |
---|
1111 | |
---|
1112 | gdk_error_trap_push (); |
---|
1113 | ch.res_name = NULL; |
---|
1114 | ch.res_class = NULL; |
---|
1115 | |
---|
1116 | XGetClassHint (gdk_display, xwindow, &ch); |
---|
1117 | |
---|
1118 | gdk_error_trap_pop (); |
---|
1119 | |
---|
1120 | if (ch.res_name) |
---|
1121 | XFree (ch.res_name); |
---|
1122 | |
---|
1123 | if (ch.res_class) { |
---|
1124 | if (strcmp (ch.res_class, "kdesktop") == 0) { |
---|
1125 | XFree (ch.res_class); |
---|
1126 | return TRUE; |
---|
1127 | } |
---|
1128 | else |
---|
1129 | XFree (ch.res_class); |
---|
1130 | } |
---|
1131 | |
---|
1132 | return FALSE; |
---|
1133 | } |
---|
1134 | |
---|
1135 | retval = FALSE; |
---|
1136 | |
---|
1137 | gdk_error_trap_push (); |
---|
1138 | |
---|
1139 | XQueryTree (gdk_display, |
---|
1140 | xwindow, |
---|
1141 | &ignored1, &ignored2, &children, &n_children); |
---|
1142 | |
---|
1143 | if (gdk_error_trap_pop ()) { |
---|
1144 | return FALSE; |
---|
1145 | } |
---|
1146 | |
---|
1147 | i = 0; |
---|
1148 | while (i < n_children) { |
---|
1149 | if (look_for_kdesktop_recursive (children[i])) { |
---|
1150 | retval = TRUE; |
---|
1151 | break; |
---|
1152 | } |
---|
1153 | |
---|
1154 | ++i; |
---|
1155 | } |
---|
1156 | |
---|
1157 | if (children) |
---|
1158 | XFree (children); |
---|
1159 | |
---|
1160 | return retval; |
---|
1161 | } |
---|
1162 | #endif /* UGLY_HACK_TO_DETECT_KDE */ |
---|
1163 | |
---|
1164 | static gboolean |
---|
1165 | is_kdesktop_present (void) |
---|
1166 | { |
---|
1167 | #ifdef UGLY_HACK_TO_DETECT_KDE |
---|
1168 | /* FIXME this is a pretty lame hack, should be replaced |
---|
1169 | * eventually with e.g. a requirement that desktop managers |
---|
1170 | * support a manager selection, ICCCM sec 2.8 |
---|
1171 | */ |
---|
1172 | return look_for_kdesktop_recursive (GDK_ROOT_WINDOW ()); |
---|
1173 | #else |
---|
1174 | return FALSE; |
---|
1175 | #endif |
---|
1176 | } |
---|
1177 | |
---|
1178 | static void |
---|
1179 | nautilus_application_class_init (NautilusApplicationClass *class) |
---|
1180 | { |
---|
1181 | BONOBO_OBJECT_CLASS (class)->destroy = nautilus_application_destroy; |
---|
1182 | BONOBO_GENERIC_FACTORY_CLASS (class)->epv.createObject = create_object; |
---|
1183 | } |
---|