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