1 /*
2 * pcmanfm.c
3 *
4 * Copyright 2009 - 2010 Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
5 * Copyright 2012-2015 Andriy Grytsenko (LStranger) <andrej@rep.kiev.ua>
6 * Copyright 2020 Mamoru TASAKA <mtasaka@fedoraproject.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21 * MA 02110-1301, USA.
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <gtk/gtk.h>
29 #include <gdk/gdkx.h>
30 #include <stdio.h>
31 #include <glib/gi18n.h>
32
33 #include <stdlib.h>
34 #include <string.h>
35 /* socket is used to keep single instance */
36 #include <sys/types.h>
37 #include <signal.h>
38 #include <unistd.h> /* for getcwd */
39
40 #include <libfm/fm-gtk.h>
41 #include "app-config.h"
42 #include "main-win.h"
43 #include "desktop.h"
44 #include "volume-manager.h"
45 #include "pref.h"
46 #include "pcmanfm.h"
47 #include "single-inst.h"
48
49 static int signal_pipe[2] = {-1, -1};
50 static gboolean daemon_mode = FALSE;
51 static gboolean first_run = TRUE;
52 static guint save_config_idle = 0;
53
54 static char** files_to_open = NULL;
55 static int n_files_to_open = 0;
56 static char* profile = NULL;
57 static gboolean no_desktop = FALSE;
58 static gboolean show_desktop = FALSE;
59 static gboolean desktop_off = FALSE;
60 static gboolean desktop_running = FALSE;
61 static gboolean one_screen = FALSE;
62 /* static gboolean new_tab = FALSE; */
63 static gint show_pref = -1;
64 static gboolean desktop_pref = FALSE;
65 static char* set_wallpaper = NULL;
66 static char* wallpaper_mode = NULL;
67 static gboolean new_win = FALSE;
68 #if FM_CHECK_VERSION(1, 0, 2)
69 static gboolean find_files = FALSE;
70 #endif
71 static char* ipc_cwd = NULL;
72 static char* window_role = NULL;
73
74 static int n_pcmanfm_ref = 0;
75
76 static GOptionEntry opt_entries[] =
77 {
78 /* options only acceptable by first pcmanfm instance. These options are not passed through IPC */
79 { "profile", 'p', 0, G_OPTION_ARG_STRING, &profile, N_("Name of configuration profile"), N_("PROFILE") },
80 { "daemon-mode", 'd', 0, G_OPTION_ARG_NONE, &daemon_mode, N_("Run PCManFM as a daemon"), NULL },
81 { "no-desktop", '\0', 0, G_OPTION_ARG_NONE, &no_desktop, N_("No function. Just to be compatible with nautilus"), NULL },
82
83 /* options that are acceptable for every instance of pcmanfm and will be passed through IPC. */
84 { "desktop", '\0', 0, G_OPTION_ARG_NONE, &show_desktop, N_("Launch desktop manager"), NULL },
85 { "desktop-off", '\0', 0, G_OPTION_ARG_NONE, &desktop_off, N_("Turn off desktop manager if it's running"), NULL },
86 { "desktop-pref", '\0', 0, G_OPTION_ARG_NONE, &desktop_pref, N_("Open desktop preference dialog"), NULL },
87 { "one-screen", '\0', 0, G_OPTION_ARG_NONE, &one_screen, N_("Use --desktop option only for one screen"), NULL },
88 { "set-wallpaper", 'w', 0, G_OPTION_ARG_FILENAME, &set_wallpaper, N_("Set desktop wallpaper from image FILE"), N_("FILE") },
89 /* don't translate list of modes in description, please */
90 { "wallpaper-mode", '\0', 0, G_OPTION_ARG_STRING, &wallpaper_mode, N_("Set mode of desktop wallpaper. MODE=(color|stretch|fit|crop|center|tile|screen)"), N_("MODE") },
91 { "show-pref", '\0', 0, G_OPTION_ARG_INT, &show_pref, N_("Open Preferences dialog on the page N"), N_("N") },
92 { "new-win", 'n', 0, G_OPTION_ARG_NONE, &new_win, N_("Open new window"), NULL },
93 #if FM_CHECK_VERSION(1, 0, 2)
94 { "find-files", 'f', 0, G_OPTION_ARG_NONE, &find_files, N_("Open a Find Files window"), NULL },
95 #endif
96 { "role", '\0', 0, G_OPTION_ARG_STRING, &window_role, N_("Window role for usage by window manager"), N_("ROLE") },
97 {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &files_to_open, NULL, N_("[FILE1, FILE2,...]")},
98 { NULL }
99 };
100
101 static gboolean pcmanfm_run(gint screen_num);
102
103 /* it's not safe to call gtk+ functions in unix signal handler
104 * since the process is interrupted here and the state of gtk+ is unpredictable. */
unix_signal_handler(int sig_num)105 static void unix_signal_handler(int sig_num)
106 {
107 /* postpond the signal handling by using a pipe */
108 if (write(signal_pipe[1], &sig_num, sizeof(sig_num)) != sizeof(sig_num)) {
109 g_critical("cannot bounce the signal, stop");
110 exit(2);
111 }
112 }
113
on_unix_signal(GIOChannel * ch,GIOCondition cond,gpointer user_data)114 static gboolean on_unix_signal(GIOChannel* ch, GIOCondition cond, gpointer user_data)
115 {
116 int sig_num;
117 GIOStatus status;
118 gsize got;
119
120 while(1)
121 {
122 status = g_io_channel_read_chars(ch, (gchar*)&sig_num, sizeof(sig_num),
123 &got, NULL);
124 if(status == G_IO_STATUS_AGAIN) /* we read all the pipe */
125 {
126 g_debug("got G_IO_STATUS_AGAIN");
127 return TRUE;
128 }
129 if(status != G_IO_STATUS_NORMAL || got != sizeof(sig_num)) /* broken pipe */
130 {
131 g_debug("signal pipe is broken");
132 gtk_main_quit();
133 return FALSE;
134 }
135 g_debug("got signal %d from pipe", sig_num);
136 switch(sig_num)
137 {
138 case SIGTERM:
139 default:
140 gtk_main_quit();
141 return FALSE;
142 }
143 }
144 return TRUE;
145 }
146
single_inst_cb(const char * cwd,int screen_num)147 static void single_inst_cb(const char* cwd, int screen_num)
148 {
149 g_free(ipc_cwd);
150 ipc_cwd = g_strdup(cwd);
151
152 if(files_to_open)
153 {
154 int i;
155 n_files_to_open = g_strv_length(files_to_open);
156 /* canonicalize filename if needed. */
157 for(i = 0; i < n_files_to_open; ++i)
158 {
159 char* file = files_to_open[i];
160 char* scheme = g_uri_parse_scheme(file);
161 g_debug("file: %s", file);
162 if(scheme) /* a valid URI */
163 {
164 g_free(scheme);
165 }
166 else /* a file path */
167 {
168 files_to_open[i] = fm_canonicalize_filename(file, cwd);
169 g_free(file);
170 }
171 }
172 }
173 pcmanfm_run(screen_num);
174 }
175
176 #if FM_CHECK_VERSION(1, 2, 0)
177 /* ---- statusbar plugins support ---- */
178 FM_MODULE_DEFINE_TYPE(tab_page_status, FmTabPageStatusInit, 1)
179
180 GList *_tab_page_modules = NULL;
181
fm_module_callback_tab_page_status(const char * name,gpointer init,int ver)182 static gboolean fm_module_callback_tab_page_status(const char *name, gpointer init, int ver)
183 {
184 /* add module callbacks into own data list */
185 if (((FmTabPageStatusInit*)init)->sel_message == NULL)
186 return FALSE;
187 if (((FmTabPageStatusInit*)init)->init && !((FmTabPageStatusInit*)init)->init())
188 return FALSE;
189 _tab_page_modules = g_list_append(_tab_page_modules, init);
190 return TRUE;
191 }
192 #endif
193
on_config_changed(FmAppConfig * cfg,gpointer _unused)194 static void on_config_changed(FmAppConfig *cfg, gpointer _unused)
195 {
196 pcmanfm_save_config(FALSE);
197 }
198
main(int argc,char ** argv)199 int main(int argc, char** argv)
200 {
201 FmConfig* config;
202 GError* err = NULL;
203 SingleInstData inst;
204 #if FM_CHECK_VERSION(1, 2, 0)
205 GList *l;
206 #endif
207
208 #ifdef ENABLE_NLS
209 bindtextdomain ( GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR );
210 bind_textdomain_codeset ( GETTEXT_PACKAGE, "UTF-8" );
211 textdomain ( GETTEXT_PACKAGE );
212 #endif
213
214 /* initialize GTK+ and parse the command line arguments */
215 if(G_UNLIKELY(!gtk_init_with_args(&argc, &argv, " ", opt_entries, GETTEXT_PACKAGE, &err)))
216 {
217 g_printf("%s\n", err->message);
218 g_error_free(err);
219 return 1;
220 }
221
222 /* ensure that there is only one instance of pcmanfm. */
223 inst.prog_name = "pcmanfm";
224 inst.cb = single_inst_cb;
225 inst.opt_entries = opt_entries + 3;
226 inst.screen_num = gdk_x11_get_default_screen();
227 switch(single_inst_init(&inst))
228 {
229 case SINGLE_INST_CLIENT: /* we're not the first instance. */
230 single_inst_finalize(&inst);
231 gdk_notify_startup_complete();
232 return 0;
233 case SINGLE_INST_ERROR: /* error happened. */
234 single_inst_finalize(&inst);
235 return 1;
236 case SINGLE_INST_SERVER: ; /* FIXME */
237 }
238
239 if(pipe(signal_pipe) == 0)
240 {
241 GIOChannel* ch = g_io_channel_unix_new(signal_pipe[0]);
242 g_io_add_watch(ch, G_IO_IN|G_IO_PRI, (GIOFunc)on_unix_signal, NULL);
243 g_io_channel_set_encoding(ch, NULL, NULL);
244 g_io_channel_unref(ch);
245
246 /* intercept signals */
247 // signal( SIGPIPE, SIG_IGN );
248 signal( SIGHUP, unix_signal_handler );
249 signal( SIGTERM, unix_signal_handler );
250 signal( SIGINT, unix_signal_handler );
251 }
252
253 config = fm_app_config_new(); /* this automatically load libfm config file. */
254
255 fm_gtk_init(config);
256
257 #if FM_CHECK_VERSION(1, 2, 0)
258 /* register our modules */
259 fm_modules_add_directory(PACKAGE_MODULES_DIR);
260 fm_module_register_tab_page_status();
261 #endif
262
263 #if FM_CHECK_VERSION(1, 0, 2)
264 # if !FM_CHECK_VERSION(1, 2, 0)
265 /* the sort_by value isn't loaded with LibFM 1.1.x so we need a workaround */
266 /* a little trick to initialize FmFolderModel class */
267 gpointer null_model = fm_folder_model_new(NULL, FALSE);
268 g_object_unref(null_model);
269 # endif
270 #endif
271
272 /* load pcmanfm-specific config file */
273 fm_app_config_load_from_profile(FM_APP_CONFIG(config), profile);
274 g_signal_connect(config, "changed::saved_search", G_CALLBACK(on_config_changed), NULL);
275
276 /* the main part */
277 if(pcmanfm_run(gdk_screen_get_number(gdk_screen_get_default())))
278 {
279 first_run = FALSE;
280 fm_volume_manager_init();
281 #if !GTK_CHECK_VERSION(3, 6, 0)
282 GDK_THREADS_ENTER();
283 #endif
284 gtk_main();
285 /* g_debug("main loop ended"); */
286 #if !GTK_CHECK_VERSION(3, 6, 0)
287 GDK_THREADS_LEAVE();
288 #endif
289
290 if(save_config_idle)
291 {
292 pcmanfm_save_config(TRUE);
293 g_source_remove(save_config_idle);
294 save_config_idle = 0;
295 }
296 fm_volume_manager_finalize();
297 }
298
299 #if FM_CHECK_VERSION(1, 2, 0)
300 for (l = _tab_page_modules; l; l = l->next)
301 if (((FmTabPageStatusInit*)l->data)->finalize)
302 ((FmTabPageStatusInit*)l->data)->finalize();
303 fm_module_unregister_type("tab_page_status");
304 g_list_free(_tab_page_modules);
305 _tab_page_modules = NULL;
306 #endif
307
308 single_inst_finalize(&inst);
309 fm_gtk_finalize();
310
311 g_object_unref(config);
312 return 0;
313 }
314
reset_options(void)315 static gboolean reset_options(void)
316 {
317 show_desktop = FALSE;
318 desktop_off = FALSE;
319 desktop_pref = FALSE;
320 one_screen = FALSE;
321 g_free(set_wallpaper);
322 set_wallpaper = NULL;
323 g_free(wallpaper_mode);
324 wallpaper_mode = NULL;
325 show_pref = -1;
326 new_win = FALSE;
327 #if FM_CHECK_VERSION(1, 0, 2)
328 find_files = FALSE;
329 #endif
330 g_free(window_role);
331 window_role = NULL;
332 g_strfreev(files_to_open);
333 files_to_open = NULL;
334 return TRUE;
335 }
336
pcmanfm_run(gint screen_num)337 gboolean pcmanfm_run(gint screen_num)
338 {
339 FmMainWin *win = NULL;
340 gboolean ret = TRUE;
341
342 if(!files_to_open)
343 {
344 /* FIXME: use screen number from client and pointer position */
345 FmDesktop *desktop = fm_desktop_get(screen_num, 0);
346
347 /* Launch desktop manager */
348 if(show_desktop)
349 {
350 if(!desktop_running)
351 {
352 fm_desktop_manager_init(one_screen ? screen_num : -1);
353 desktop_running = TRUE;
354 }
355 return reset_options();
356 }
357 else if(desktop_off)
358 {
359 if(desktop_running)
360 {
361 desktop_running = FALSE;
362 fm_desktop_manager_finalize();
363 }
364 reset_options();
365 return FALSE;
366 }
367 else if(show_pref > 0)
368 {
369 fm_edit_preference(GTK_WINDOW(desktop), show_pref - 1);
370 return reset_options();
371 }
372 else if(desktop == NULL)
373 {
374 /* ignore desktop-oriented commands if no desktop support */
375 if (desktop_pref || wallpaper_mode || set_wallpaper)
376 {
377 /* FIXME: add "on this X screen/monitor" into diagnostics */
378 fm_show_error(NULL, NULL, _("Desktop manager is not active."));
379 reset_options();
380 return FALSE;
381 }
382 }
383 else if(desktop_pref)
384 {
385 fm_desktop_preference(NULL, desktop);
386 return reset_options();
387 }
388 else if(wallpaper_mode || set_wallpaper)
389 {
390 gboolean wallpaper_changed = FALSE;
391 if(set_wallpaper) /* a new wallpaper is assigned */
392 {
393 /* g_debug("\'%s\'", set_wallpaper); */
394 /* Make sure this is a support image file. */
395 if(gdk_pixbuf_get_file_info(set_wallpaper, NULL, NULL))
396 {
397 if(desktop->conf.wallpaper)
398 g_free(desktop->conf.wallpaper);
399 desktop->conf.wallpaper = set_wallpaper;
400 if(! wallpaper_mode) /* if wallpaper mode is not specified */
401 {
402 /* do not use solid color mode; otherwise wallpaper won't be shown. */
403 if(desktop->conf.wallpaper_mode == FM_WP_COLOR)
404 desktop->conf.wallpaper_mode = FM_WP_FIT;
405 }
406 wallpaper_changed = TRUE;
407 set_wallpaper = NULL;
408 }
409 }
410
411 if(wallpaper_mode)
412 {
413 FmWallpaperMode mode = fm_app_wallpaper_get_mode_by_name(wallpaper_mode);
414
415 if (mode != (FmWallpaperMode)-1
416 && mode != desktop->conf.wallpaper_mode)
417 {
418 desktop->conf.wallpaper_mode = mode;
419 wallpaper_changed = TRUE;
420 }
421 }
422
423 if(wallpaper_changed)
424 fm_desktop_wallpaper_changed(desktop);
425
426 reset_options();
427 return FALSE;
428 }
429 }
430
431 if(files_to_open)
432 {
433 char** filename;
434 FmPath* cwd = NULL;
435 GList* paths = NULL;
436 for(filename=files_to_open; *filename; ++filename)
437 {
438 FmPath* path;
439 if( **filename == '/') /* absolute path */
440 path = fm_path_new_for_path(*filename);
441 else if(strstr(*filename, ":/") ) /* URI */
442 path = fm_path_new_for_uri(*filename);
443 else if( strcmp(*filename, "~") == 0 ) /* special case for home dir */
444 {
445 path = fm_path_get_home();
446 win = fm_main_win_add_win(NULL, path);
447 if(new_win && window_role)
448 gtk_window_set_role(GTK_WINDOW(win), window_role);
449 continue;
450 }
451 else /* basename */
452 {
453 if(G_UNLIKELY(!cwd))
454 {
455 char* cwd_str = ipc_cwd ? ipc_cwd : g_get_current_dir();
456 cwd = fm_path_new_for_str(cwd_str);
457 g_free(cwd_str);
458 }
459 path = fm_path_new_relative(cwd, *filename);
460 }
461 paths = g_list_append(paths, path);
462 }
463 if(cwd)
464 fm_path_unref(cwd);
465 fm_launch_paths_simple(NULL, NULL, paths, pcmanfm_open_folder, NULL);
466 g_list_foreach(paths, (GFunc)fm_path_unref, NULL);
467 g_list_free(paths);
468 ret = (n_pcmanfm_ref >= 1); /* if there is opened window, return true to run the main loop. */
469 }
470 else
471 {
472 if(first_run && daemon_mode)
473 {
474 /* If the function is called the first time and we're in daemon mode,
475 * don't open any folder.
476 * Checking if pcmanfm_run() is called the first time is needed to fix
477 * #3397444 - pcmanfm dont show window in daemon mode if i call 'pcmanfm' */
478 pcmanfm_ref();
479 }
480 #if FM_CHECK_VERSION(1, 0, 2)
481 else if (G_LIKELY(!find_files || n_pcmanfm_ref < 1))
482 #else
483 else
484 #endif
485 {
486 /* If we're not in daemon mode, or pcmanfm_run() is called because another
487 * instance send signal to us, open cwd by default. */
488 FmPath* path;
489 char* cwd = ipc_cwd ? ipc_cwd : g_get_current_dir();
490 path = fm_path_new_for_path(cwd);
491 win = fm_main_win_add_win(NULL, path);
492 if(new_win && window_role)
493 gtk_window_set_role(GTK_WINDOW(win), window_role);
494 fm_path_unref(path);
495 g_free(cwd);
496 ipc_cwd = NULL;
497 }
498 }
499
500 #if FM_CHECK_VERSION(1, 0, 2)
501 /* we got a reference at this point so we can open a search dialog */
502 if (ret && find_files)
503 fm_launch_search_simple(GTK_WINDOW(win), NULL, NULL,
504 pcmanfm_open_folder, NULL);
505 #endif
506 reset_options();
507 return ret;
508 }
509
510 /* After opening any window/dialog/tool, this should be called. */
pcmanfm_ref()511 void pcmanfm_ref()
512 {
513 ++n_pcmanfm_ref;
514 /* g_debug("ref: %d", n_pcmanfm_ref); */
515 }
516
517 /* After closing any window/dialog/tool, this should be called.
518 * If the last window is closed and we are not a deamon, pcmanfm will quit.
519 */
pcmanfm_unref()520 void pcmanfm_unref()
521 {
522 --n_pcmanfm_ref;
523 /* g_debug("unref: %d, daemon_mode=%d, desktop_running=%d", n_pcmanfm_ref, daemon_mode, desktop_running); */
524 if( 0 == n_pcmanfm_ref )
525 gtk_main_quit();
526 }
527
move_window_to_desktop(FmMainWin * win,FmDesktop * desktop)528 static void move_window_to_desktop(FmMainWin* win, FmDesktop* desktop)
529 {
530 GdkScreen* screen = gtk_widget_get_screen(GTK_WIDGET(desktop));
531 Atom atom;
532 char* atom_name = "_NET_WM_DESKTOP";
533 XClientMessageEvent xev;
534
535 gtk_window_set_screen(GTK_WINDOW(win), screen);
536 if(!XInternAtoms(gdk_x11_get_default_xdisplay(), &atom_name, 1, False, &atom))
537 {
538 /* g_debug("cannot get Atom for _NET_WM_DESKTOP"); */
539 return;
540 }
541 xev.type = ClientMessage;
542 xev.window = GDK_WINDOW_XID(gtk_widget_get_window(GTK_WIDGET(win)));
543 xev.message_type = atom;
544 xev.format = 32;
545 xev.data.l[0] = desktop->cur_desktop;
546 xev.data.l[1] = 0;
547 xev.data.l[2] = 0;
548 xev.data.l[3] = 0;
549 xev.data.l[4] = 0;
550 /* g_debug("moving window to current desktop"); */
551 XSendEvent(gdk_x11_get_default_xdisplay(), GDK_ROOT_WINDOW(), False,
552 (SubstructureNotifyMask | SubstructureRedirectMask),
553 (XEvent *) &xev);
554 }
555
pcmanfm_open_folder(GAppLaunchContext * ctx,GList * folder_infos,gpointer user_data,GError ** err)556 gboolean pcmanfm_open_folder(GAppLaunchContext* ctx, GList* folder_infos, gpointer user_data, GError** err)
557 {
558 GList* l = folder_infos;
559 gboolean use_new_win = new_win;
560
561 /* for desktop folder open it in new win if set in config */
562 if (!use_new_win && user_data && FM_IS_DESKTOP(user_data))
563 use_new_win = app_config->desktop_folder_new_win;
564 if(use_new_win)
565 {
566 FmMainWin *win = fm_main_win_add_win(NULL,
567 fm_file_info_get_path((FmFileInfo*)l->data));
568 if(window_role)
569 gtk_window_set_role(GTK_WINDOW(win), window_role);
570 new_win = FALSE;
571 l = l->next;
572 }
573 for(; l; l=l->next)
574 {
575 FmFileInfo* fi = (FmFileInfo*)l->data;
576 fm_main_win_open_in_last_active(fm_file_info_get_path(fi));
577 }
578 if(user_data && FM_IS_DESKTOP(user_data))
579 move_window_to_desktop(fm_main_win_get_last_active(), user_data);
580 return TRUE;
581 }
582
on_save_config_idle(gpointer user_data)583 static gboolean on_save_config_idle(gpointer user_data)
584 {
585 pcmanfm_save_config(TRUE);
586 save_config_idle = 0;
587 return FALSE;
588 }
589
pcmanfm_save_config(gboolean immediate)590 void pcmanfm_save_config(gboolean immediate)
591 {
592 if(immediate)
593 {
594 fm_config_save(fm_config, NULL);
595 fm_app_config_save_profile(app_config, profile);
596 }
597 else
598 {
599 /* install an idle handler to save the config file. */
600 if( 0 == save_config_idle)
601 save_config_idle = gdk_threads_add_idle_full(G_PRIORITY_LOW, (GSourceFunc)on_save_config_idle, NULL, NULL);
602 }
603 }
604
pcmanfm_can_open_path_in_terminal(FmPath * dir)605 gboolean pcmanfm_can_open_path_in_terminal(FmPath* dir)
606 {
607 GFile *gf;
608 char *wd;
609
610 if (fm_path_is_native(dir))
611 return TRUE;
612 gf = fm_path_to_gfile(dir);
613 wd = g_file_get_path(gf);
614 g_object_unref(gf);
615 g_free(wd);
616 return (wd != NULL);
617 }
618
pcmanfm_open_folder_in_terminal(GtkWindow * parent,FmPath * dir)619 void pcmanfm_open_folder_in_terminal(GtkWindow* parent, FmPath* dir)
620 {
621 #if !FM_CHECK_VERSION(1, 2, 0)
622 GAppInfo* app;
623 char** argv;
624 int argc;
625 #endif
626
627 if(!fm_config->terminal)
628 {
629 fm_show_error(parent, NULL, _("Terminal emulator is not set."));
630 fm_edit_preference(parent, PREF_ADVANCED);
631 return;
632 }
633 #if FM_CHECK_VERSION(1, 2, 0)
634 else
635 {
636 #else
637 if(!g_shell_parse_argv(fm_config->terminal, &argc, &argv, NULL))
638 return;
639 app = g_app_info_create_from_commandline(argv[0], NULL, 0, NULL);
640 g_strfreev(argv);
641 if(app)
642 {
643 GdkAppLaunchContext* ctx = gdk_app_launch_context_new();
644 char* old_cwd = g_get_current_dir();
645 const char *old_pwd = g_getenv("PWD");
646 #endif
647 GError* err = NULL;
648 char* cwd_str;
649
650 if(fm_path_is_native(dir))
651 cwd_str = fm_path_to_str(dir);
652 else
653 {
654 GFile* gf = fm_path_to_gfile(dir);
655 cwd_str = g_file_get_path(gf);
656 g_object_unref(gf);
657 }
658 #if FM_CHECK_VERSION(1, 2, 0)
659 if (!fm_terminal_launch(cwd_str, &err))
660 #else
661 /* this is a bit dirty to manipulate environment but what else to do? */
662 g_setenv("PWD", cwd_str, TRUE);
663 gdk_app_launch_context_set_screen(ctx, parent ? gtk_widget_get_screen(GTK_WIDGET(parent)) : gdk_screen_get_default());
664 gdk_app_launch_context_set_timestamp(ctx, gtk_get_current_event_time());
665 g_chdir(cwd_str); /* FIXME: currently we don't have better way for this. maybe a wrapper script? */
666 g_free(cwd_str);
667
668 if(!g_app_info_launch(app, NULL, G_APP_LAUNCH_CONTEXT(ctx), &err))
669 #endif
670 {
671 fm_show_error(parent, NULL, err->message);
672 g_error_free(err);
673 }
674 #if FM_CHECK_VERSION(1, 2, 0)
675 g_free(cwd_str);
676 #else
677 g_object_unref(ctx);
678 g_object_unref(app);
679
680 /* switch back to old cwd and fix #3114626 - PCManFM 0.9.9 Umount partitions problem */
681 g_chdir(old_cwd); /* This is really dirty, but we don't have better solution now. */
682 g_free(old_cwd);
683 if (old_pwd)
684 g_setenv("PWD", old_pwd, TRUE);
685 else
686 g_unsetenv("PWD");
687 #endif
688 }
689 }
690
691 char* pcmanfm_get_profile_dir(gboolean create)
692 {
693 char* dir = g_build_filename(g_get_user_config_dir(), "pcmanfm", profile ? profile : "default", NULL);
694 if(create)
695 g_mkdir_with_parents(dir, 0700);
696 return dir;
697 }
698