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