Add some comments.
[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>
d3451adb 5 *
b6e3c554
HJYP
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
d3451adb 10 *
b6e3c554
HJYP
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
d3451adb 15 *
b6e3c554
HJYP
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21
08e70fea 22#ifdef HAVE_CONFIG_H
b6e3c554 23#include <config.h>
08e70fea
HJYP
24#endif
25
b6e3c554
HJYP
26#include <gtk/gtk.h>
27#include <stdio.h>
f8f2bfad
HJYP
28#include <glib/gi18n.h>
29
30#include <stdlib.h>
31#include <string.h>
32/* socket is used to keep single instance */
33#include <sys/types.h>
34#include <sys/socket.h>
35#include <sys/un.h>
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"
8505a8ef 46
f8f2bfad
HJYP
47static int sock;
48GIOChannel* io_channel = NULL;
49
94435bc3
HJYP
50static int signal_pipe[2] = {-1, -1};
51
f8f2bfad
HJYP
52gboolean daemon_mode = FALSE;
53
f8f2bfad 54static char** files_to_open = NULL;
f970e846
HJYP
55static char* profile = NULL;
56static char* config_name = NULL;
f8f2bfad
HJYP
57static gboolean no_desktop = FALSE;
58static gboolean show_desktop = FALSE;
59static gboolean desktop_off = FALSE;
60static gboolean desktop_running = FALSE;
107cdb22 61/* static gboolean new_tab = FALSE; */
f8f2bfad
HJYP
62static int show_pref = 0;
63static gboolean desktop_pref = FALSE;
64static char* set_wallpaper = NULL;
107cdb22 65static char* wallpaper_mode = NULL;
f8f2bfad 66static gboolean find_files = FALSE;
5b890032 67static char* ipc_cwd = NULL;
f8f2bfad
HJYP
68
69static int n_pcmanfm_ref = 0;
70
71static GOptionEntry opt_entries[] =
8505a8ef 72{
107cdb22 73 /* { "new-tab", 't', 0, G_OPTION_ARG_NONE, &new_tab, N_("Open folders in new tabs of the last used window instead of creating new windows"), NULL }, */
a48f9fc8 74 { "profile", 'p', 0, G_OPTION_ARG_STRING, &profile, N_("Name of configuration profile"), "<profile name>" },
f8f2bfad
HJYP
75 { "desktop", '\0', 0, G_OPTION_ARG_NONE, &show_desktop, N_("Launch desktop manager"), NULL },
76 { "desktop-off", '\0', 0, G_OPTION_ARG_NONE, &desktop_off, N_("Turn off desktop manager if it's running"), NULL },
f8f2bfad 77 { "daemon-mode", 'd', 0, G_OPTION_ARG_NONE, &daemon_mode, N_("Run PCManFM as a daemon"), NULL },
f8f2bfad 78 { "desktop-pref", '\0', 0, G_OPTION_ARG_NONE, &desktop_pref, N_("Open desktop preference dialog"), NULL },
f970e846 79 { "set-wallpaper", 'w', 0, G_OPTION_ARG_FILENAME, &set_wallpaper, N_("Set desktop wallpaper"), N_("<image file>") },
107cdb22 80 { "wallpaper-mode", '\0', 0, G_OPTION_ARG_STRING, &wallpaper_mode, N_("Set mode of desktop wallpaper. <mode>=(color|stretch|fit|center|tile)"), N_("<mode>") },
a48f9fc8 81 { "show-pref", '\0', 0, G_OPTION_ARG_INT, &show_pref, N_("Open preference dialog. 'n' is number of the page you want to show (1, 2, 3...)."), "n" },
1d071341 82 /* { "find-files", 'f', 0, G_OPTION_ARG_NONE, &find_files, N_("Open Find Files utility"), NULL }, */
f970e846 83 { "no-desktop", '\0', 0, G_OPTION_ARG_NONE, &no_desktop, N_("No function. Just to be compatible with nautilus"), NULL },
f8f2bfad
HJYP
84 {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &files_to_open, NULL, N_("[FILE1, FILE2,...]")},
85 { NULL }
86};
87
107cdb22
HJYP
88static const char* valid_wallpaper_modes[] = {"color", "stretch", "fit", "center", "tile"};
89
f8f2bfad
HJYP
90static gboolean single_instance_check();
91static void single_instance_finalize();
92static void get_socket_name(char* buf, int len);
93static gboolean pcmanfm_run();
94static gboolean on_socket_event(GIOChannel* ioc, GIOCondition cond, gpointer data);
b6e3c554 95
94435bc3
HJYP
96/* it's not safe to call gtk+ functions in unix signal handler
97 * since the process is interrupted here and the state of gtk+ is unpredictable. */
98static void unix_signal_handler(int sig_num)
99{
100 /* postpond the signal handling by using a pipe */
101 write(signal_pipe[1], &sig_num, sizeof(sig_num));
102}
103
104static gboolean on_unix_signal(GIOChannel* ch, GIOCondition cond, gpointer user_data)
105{
106 int sig_num;
107 g_io_channel_read_chars(ch, &sig_num, 1, NULL, NULL);
108 switch(sig_num)
109 {
110 case SIGTERM:
111 default:
112 gtk_main_quit();
113 }
114 return TRUE;
115}
116
b6e3c554
HJYP
117int main(int argc, char** argv)
118{
4d55886c 119 FmConfig* config;
f8f2bfad
HJYP
120 GError* err = NULL;
121
122#ifdef ENABLE_NLS
123 bindtextdomain ( GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR );
124 bind_textdomain_codeset ( GETTEXT_PACKAGE, "UTF-8" );
125 textdomain ( GETTEXT_PACKAGE );
126#endif
127
128 /* initialize GTK+ and parse the command line arguments */
129 if(G_UNLIKELY(!gtk_init_with_args(&argc, &argv, "", opt_entries, GETTEXT_PACKAGE, &err)))
130 {
131 g_printf("%s\n", err->message);
c5fccf1d 132 g_error_free(err);
f8f2bfad
HJYP
133 return 1;
134 }
135
136 /* ensure that there is only one instance of pcmanfm.
137 if there is an existing instance, command line arguments
138 will be passed to the existing instance, and exit() will be called here. */
139 single_instance_check();
140
94435bc3
HJYP
141 if(pipe(signal_pipe) == 0)
142 {
143 GIOChannel* ch = g_io_channel_unix_new(signal_pipe[0]);
144 g_io_add_watch(ch, G_IO_IN|G_IO_PRI, (GIOFunc)on_unix_signal, NULL);
145 g_io_channel_unref(ch);
146
147 /* intercept signals */
148 signal( SIGPIPE, SIG_IGN );
149 /* signal( SIGHUP, gtk_main_quit ); */
150 signal( SIGTERM, unix_signal_handler );
151 }
b6e3c554 152
f970e846
HJYP
153 config = fm_app_config_new(); /* this automatically load libfm config file. */
154 /* load pcmanfm-specific config file */
155 if(profile)
156 config_name = g_strconcat("pcmanfm/", profile, ".conf", NULL);
4b3e1fe9 157 fm_app_config_load_from_file(FM_APP_CONFIG(config), config_name);
f970e846 158
94435bc3 159 fm_gtk_init(config);
b6e3c554 160
f8f2bfad
HJYP
161 /* the main part */
162 if(pcmanfm_run())
163 {
71f82759 164 fm_volume_manager_init();
94435bc3 165 gtk_main();
f8f2bfad
HJYP
166 if(desktop_running)
167 fm_desktop_manager_finalize();
f8f2bfad 168 fm_config_save(config, NULL); /* save libfm config */
f970e846 169 fm_app_config_save((FmAppConfig*)config, config_name); /* save pcmanfm config */
71f82759 170 fm_volume_manager_finalize();
f8f2bfad
HJYP
171 }
172 single_instance_finalize();
8505a8ef 173
f8f2bfad
HJYP
174 fm_gtk_finalize();
175 g_object_unref(config);
94435bc3 176 return 0;
f8f2bfad
HJYP
177}
178
7b7d923f 179inline static void buf_append_str(GByteArray* buf, const char* str)
f8f2bfad 180{
7b7d923f
HJYP
181 int len;
182 if(G_LIKELY(str))
183 {
184 len = strlen(str) + 1;
185 g_byte_array_append(buf, (guint8*)&len, sizeof(len));
186 g_byte_array_append(buf, (guint8*)str, len);
187 }
188 else
189 {
190 len = 0;
191 g_byte_array_append(buf, (guint8*)&len, sizeof(len));
192 }
193}
194
195inline static GByteArray* args_to_ipc_buf()
196{
197 int i, len;
198 GByteArray* buf = g_byte_array_sized_new(4096);
5b890032
HJYP
199 /* send our current working dir to existing instance via IPC. */
200 ipc_cwd = g_get_current_dir();
7b7d923f 201 buf_append_str(buf, ipc_cwd);
5b890032 202 g_free(ipc_cwd);
7b7d923f 203
107cdb22 204 /* g_byte_array_append(buf, (guint8*)&new_tab, sizeof(new_tab)); */
7b7d923f
HJYP
205 g_byte_array_append(buf, (guint8*)&show_desktop, sizeof(show_desktop));
206 g_byte_array_append(buf, (guint8*)&desktop_off, sizeof(desktop_off));
207 g_byte_array_append(buf, (guint8*)&desktop_pref, sizeof(desktop_pref));
208 buf_append_str(buf, set_wallpaper);
107cdb22 209 buf_append_str(buf, wallpaper_mode);
7b7d923f
HJYP
210 g_byte_array_append(buf, (guint8*)&show_pref, sizeof(show_pref));
211 g_byte_array_append(buf, (guint8*)&find_files, sizeof(find_files));
212 g_byte_array_append(buf, (guint8*)&no_desktop, sizeof(no_desktop));
213
a1a528d2 214 len = files_to_open ? g_strv_length(files_to_open) : 0;
2b46b521
HJYP
215 g_byte_array_append(buf, (guint8*)&len, sizeof(len));
216 for(i = 0; i < len; ++i)
217 buf_append_str(buf, files_to_open[i]);
7b7d923f 218
f8f2bfad
HJYP
219 return buf;
220}
221
7b7d923f
HJYP
222inline static gboolean buf_read_bool(const char**p)
223{
224 gboolean ret;
225 memcpy(&ret, *p, sizeof(ret));
226 *p += sizeof(ret);
227 return ret;
228}
229
230inline static int buf_read_int(const char**p)
231{
232 int ret;
233 memcpy(&ret, *p, sizeof(ret));
234 *p += sizeof(ret);
235 return ret;
236}
237
238inline static char* buf_read_str(const char**p)
239{
240 char* ret;
241 int len = buf_read_int(p);
242 if(len > 0)
243 {
244 ret = g_malloc(len);
245 memcpy(ret, *p, len);
246 *p += len;
247 }
248 else
249 ret = NULL;
250 return ret;
251}
252
253inline static void ipc_buf_to_args(GByteArray* buf)
f8f2bfad 254{
7b7d923f
HJYP
255 int i, len;
256 char* p = buf->data;
257 char* cwd = buf_read_str(&p);
107cdb22 258 /* new_tab = buf_read_bool(&p); */
7b7d923f
HJYP
259 show_desktop = buf_read_bool(&p);
260 desktop_off = buf_read_bool(&p);
261 desktop_pref = buf_read_bool(&p);
262 g_free(set_wallpaper);
263 set_wallpaper = buf_read_str(&p);
107cdb22
HJYP
264 g_free(wallpaper_mode);
265 wallpaper_mode = buf_read_str(&p);
7b7d923f
HJYP
266 show_pref = buf_read_int(&p);
267 find_files = buf_read_bool(&p);
268 no_desktop = buf_read_bool(&p);
269
270 len = buf_read_int(&p);
107cdb22 271 /* g_debug("len = %d", len); */
7b7d923f 272 if(len > 0)
b6e3c554 273 {
7b7d923f
HJYP
274 files_to_open = g_new(char*, len + 1);
275 for(i = 0; i < len; ++i)
f8f2bfad 276 {
7b7d923f 277 char* file = buf_read_str(&p);
ee12f37e
HJYP
278 char* scheme = g_uri_parse_scheme(file);
279 if(scheme) /* a valid URI */
280 {
281 /* FIXME: should we canonicalize URIs? and how about file:///? */
282 files_to_open[i] = file;
283 g_free(scheme);
284 }
285 else /* a file path */
286 {
287 files_to_open[i] = fm_canonicalize_filename(file, cwd);
288 g_free(file);
289 }
f8f2bfad 290 }
7b7d923f 291 files_to_open[i] = NULL;
b6e3c554 292 }
7b7d923f
HJYP
293 else
294 files_to_open = NULL;
295 g_free(cwd);
f8f2bfad 296}
8505a8ef 297
f8f2bfad
HJYP
298gboolean on_socket_event( GIOChannel* ioc, GIOCondition cond, gpointer data )
299{
300 int client, r;
301 socklen_t addr_len = 0;
302 struct sockaddr_un client_addr ={ 0 };
303 static char buf[ 1024 ];
7b7d923f 304 GByteArray* args;
b6e3c554 305
f8f2bfad
HJYP
306 if ( cond & G_IO_IN )
307 {
308 client = accept( g_io_channel_unix_get_fd( ioc ), (struct sockaddr *)&client_addr, &addr_len );
309 if ( client != -1 )
310 {
7b7d923f 311 args = g_byte_array_sized_new(4096);
f8f2bfad 312 while( (r = read( client, buf, sizeof(buf) )) > 0 )
7b7d923f 313 g_byte_array_append( args, (guint8*)buf, r);
f8f2bfad
HJYP
314 shutdown( client, 2 );
315 close( client );
44409230 316 ipc_buf_to_args(args);
7b7d923f 317 g_byte_array_free( args, TRUE );
f8f2bfad
HJYP
318 pcmanfm_run();
319 }
320 }
321 return TRUE;
322}
19fbd668 323
f8f2bfad
HJYP
324void get_socket_name( char* buf, int len )
325{
326 char* dpy = gdk_get_display();
ab86a7a2 327 g_snprintf( buf, len, "/tmp/.pcmanfm-socket%s-%s", dpy, g_get_user_name() );
f8f2bfad
HJYP
328 g_free( dpy );
329}
8505a8ef 330
f8f2bfad
HJYP
331gboolean single_instance_check()
332{
333 struct sockaddr_un addr;
334 int addr_len;
335 int ret;
336 int reuse;
b6e3c554 337
f8f2bfad
HJYP
338 if((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
339 {
340 ret = 1;
341 goto _exit;
342 }
343
344 /* FIXME: use abstract socket */
345 addr.sun_family = AF_UNIX;
346 get_socket_name(addr.sun_path, sizeof( addr.sun_path ));
347#ifdef SUN_LEN
348 addr_len = SUN_LEN(&addr);
349#else
350 addr_len = strlen( addr.sun_path ) + sizeof( addr.sun_family );
351#endif
352
353 /* try to connect to existing instance */
354 if(connect(sock, (struct sockaddr*)&addr, addr_len) == 0)
355 {
356 /* connected successfully */
7b7d923f
HJYP
357 GByteArray* buf = args_to_ipc_buf();
358 write(sock, buf->data, buf->len);
359 g_byte_array_free(buf, TRUE);
f8f2bfad
HJYP
360
361 shutdown( sock, 2 );
362 close( sock );
363 ret = 0;
364 goto _exit;
365 }
366
367 /* There is no existing server, and we are in the first instance. */
368 unlink( addr.sun_path ); /* delete old socket file if it exists. */
369 reuse = 1;
370 ret = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse) );
371 if(bind(sock, (struct sockaddr*)&addr, addr_len) == -1)
372 {
373 ret = 1;
374 goto _exit;
375 }
376
377 io_channel = g_io_channel_unix_new(sock);
378 g_io_channel_set_encoding(io_channel, NULL, NULL);
379 g_io_channel_set_buffered(io_channel, FALSE);
380 g_io_add_watch(io_channel, G_IO_IN,
381 (GIOFunc)on_socket_event, NULL);
382 if(listen(sock, 5) == -1)
383 {
384 ret = 1;
385 goto _exit;
386 }
d3451adb 387 return TRUE;
f8f2bfad
HJYP
388
389_exit:
390
391 gdk_notify_startup_complete();
392 exit( ret );
393}
394
395void single_instance_finalize()
396{
397 char lock_file[256];
398 shutdown(sock, 2);
399 g_io_channel_unref(io_channel);
400 close(sock);
401 get_socket_name(lock_file, sizeof( lock_file ));
402 unlink(lock_file);
403}
404
ee12f37e
HJYP
405static FmJobErrorAction on_file_info_job_error(FmFileInfoJob* job, GError* err, FmJobErrorSeverity severity, gpointer user_data)
406{
16a17d6b 407 if(err->domain == G_IO_ERROR)
ee12f37e 408 {
16a17d6b
HJYP
409 if(err->code == G_IO_ERROR_NOT_MOUNTED)
410 {
411 if(fm_mount_path(NULL, fm_file_info_job_get_current(job), TRUE))
412 return FM_JOB_RETRY;
413 }
414 else if(err->code == G_IO_ERROR_FAILED_HANDLED)
415 return FM_JOB_CONTINUE;
ee12f37e 416 }
16a17d6b 417 fm_show_error(NULL, err->message);
ee12f37e
HJYP
418 return FM_JOB_CONTINUE;
419}
f8f2bfad
HJYP
420
421gboolean pcmanfm_run()
422{
423 gboolean ret = TRUE;
f8f2bfad 424
f8f2bfad
HJYP
425 if(!files_to_open)
426 {
427 /* Launch desktop manager */
428 if(show_desktop)
429 {
430 if(!desktop_running)
431 {
432 fm_desktop_manager_init();
433 desktop_running = TRUE;
434 }
19abb8bf 435 show_desktop = FALSE;
f8f2bfad
HJYP
436 return TRUE;
437 }
438 else if(desktop_off)
439 {
440 if(desktop_running)
441 {
442 desktop_running = FALSE;
443 fm_desktop_manager_finalize();
444 }
19abb8bf 445 desktop_off = FALSE;
f8f2bfad
HJYP
446 return FALSE;
447 }
448 else if(show_pref > 0)
449 {
c5fccf1d
HJYP
450 fm_edit_preference(NULL, show_pref - 1);
451 show_pref = 0;
f8f2bfad
HJYP
452 return TRUE;
453 }
454 else if(desktop_pref)
455 {
c5fccf1d 456 fm_desktop_preference();
19abb8bf 457 desktop_pref = FALSE;
f8f2bfad
HJYP
458 return TRUE;
459 }
107cdb22 460 else
f8f2bfad 461 {
107cdb22
HJYP
462 gboolean need_to_exit = (wallpaper_mode || set_wallpaper);
463 gboolean wallpaper_changed = FALSE;
464 if(set_wallpaper) /* a new wallpaper is assigned */
465 {
466 /* g_debug("\'%s\'", set_wallpaper); */
467 /* Make sure this is a support image file. */
468 if(gdk_pixbuf_get_file_info(set_wallpaper, NULL, NULL))
469 {
470 if(app_config->wallpaper)
471 g_free(app_config->wallpaper);
472 app_config->wallpaper = set_wallpaper;
473 set_wallpaper = NULL;
474 if(! wallpaper_mode) /* if wallpaper mode is not specified */
475 {
476 /* do not use solid color mode; otherwise wallpaper won't be shown. */
477 if(app_config->wallpaper_mode == FM_WP_COLOR)
478 app_config->wallpaper_mode = FM_WP_FIT;
479 }
480 wallpaper_changed = TRUE;
481 }
482 }
483
484 if(wallpaper_mode)
485 {
486 int i = 0;
487 for(i = 0; i < G_N_ELEMENTS(valid_wallpaper_modes); ++i)
488 {
489 if(strcmp(valid_wallpaper_modes[i], wallpaper_mode) == 0)
490 {
491 if(i != app_config->wallpaper_mode)
492 {
493 app_config->wallpaper_mode = i;
494 wallpaper_changed = TRUE;
495 }
496 break;
497 }
498 }
499 g_free(wallpaper_mode);
500 wallpaper_mode = NULL;
501 }
502
503 if(wallpaper_changed)
f8f2bfad 504 {
4b3e1fe9 505 fm_config_emit_changed(FM_CONFIG(app_config), "wallpaper");
dcecce78 506 fm_app_config_save(app_config, config_name);
f8f2bfad 507 }
107cdb22
HJYP
508
509 if(need_to_exit)
510 return FALSE;
f8f2bfad
HJYP
511 }
512 }
513
514 if(G_UNLIKELY(find_files))
515 {
516 /* FIXME: find files */
517 }
518 else
519 {
df6826e0
HJYP
520 if(files_to_open)
521 {
522 char** filename;
0a053694 523 FmJob* job = fm_file_info_job_new(NULL, 0);
cacf261a 524 FmPath* cwd = NULL;
d951adb8 525 GList* infos;
df6826e0
HJYP
526 for(filename=files_to_open; *filename; ++filename)
527 {
cacf261a
HJYP
528 FmPath* path;
529 if( **filename == '/' || strstr(*filename, ":/") ) /* absolute path or URI */
530 path = fm_path_new(*filename);
0d8dce1a
HJYP
531 else if( strcmp(*filename, "~") == 0 ) /* special case for home dir */
532 {
533 path = fm_path_get_home();
534 fm_main_win_add_win(NULL, path);
535 continue;
536 }
cacf261a
HJYP
537 else /* basename */
538 {
539 if(G_UNLIKELY(!cwd))
540 {
541 /* FIXME: This won't work if those filenames are passed via IPC since the receiving process has different cwd. */
542 char* cwd_str = g_get_current_dir();
543 cwd = fm_path_new(cwd_str);
544 g_free(cwd_str);
545 }
546 path = fm_path_new_relative(cwd, *filename);
547 }
4b3e1fe9 548 fm_file_info_job_add(FM_FILE_INFO_JOB(job), path);
df6826e0
HJYP
549 fm_path_unref(path);
550 }
cacf261a
HJYP
551 if(cwd)
552 fm_path_unref(cwd);
ee12f37e 553 g_signal_connect(job, "error", G_CALLBACK(on_file_info_job_error), NULL);
a48f9fc8 554 fm_job_run_sync_with_mainloop(job);
d951adb8
HJYP
555 infos = fm_list_peek_head_link(FM_FILE_INFO_JOB(job)->file_infos);
556 fm_launch_files_simple(NULL, NULL, infos, pcmanfm_open_folder, NULL);
df6826e0 557 g_object_unref(job);
cacf261a 558 ret = (n_pcmanfm_ref >= 1); /* if there is opened window, return true to run the main loop. */
2b46b521
HJYP
559
560 g_strfreev(files_to_open);
561 files_to_open = NULL;
df6826e0
HJYP
562 }
563 else
f8f2bfad
HJYP
564 {
565 FmPath* path;
5b890032 566 char* cwd = ipc_cwd ? ipc_cwd : g_get_current_dir();
0d8dce1a
HJYP
567 path = fm_path_new(cwd);
568 fm_main_win_add_win(NULL, path);
569 fm_path_unref(path);
570 g_free(cwd);
5b890032 571 ipc_cwd = NULL;
f8f2bfad
HJYP
572 }
573 }
574 return ret;
575}
576
577/* After opening any window/dialog/tool, this should be called. */
578void pcmanfm_ref()
579{
580 ++n_pcmanfm_ref;
581 /* g_debug("ref: %d", n_pcmanfm_ref); */
582}
583
584/* After closing any window/dialog/tool, this should be called.
585 * If the last window is closed and we are not a deamon, pcmanfm will quit.
586 */
587void pcmanfm_unref()
588{
589 --n_pcmanfm_ref;
590 /* g_debug("unref: %d, daemon_mode=%d, desktop_running=%d", n_pcmanfm_ref, daemon_mode, desktop_running); */
591 if( 0 == n_pcmanfm_ref && !daemon_mode && !desktop_running )
592 gtk_main_quit();
b6e3c554 593}
df6826e0
HJYP
594
595gboolean pcmanfm_open_folder(GAppLaunchContext* ctx, GList* folder_infos, gpointer user_data, GError** err)
596{
df6826e0
HJYP
597 GList* l = folder_infos;
598 for(; l; l=l->next)
599 {
600 FmFileInfo* fi = (FmFileInfo*)l->data;
601 fm_main_win_open_in_last_active(fi->path);
602 }
603 return TRUE;
604}
dcecce78
HJYP
605
606void pcmanfm_save_config()
607{
608 fm_config_save(fm_config, NULL);
609 fm_app_config_save(app_config, config_name);
610}
c56a211a
HJYP
611
612void pcmanfm_open_folder_in_terminal(GtkWindow* parent, FmPath* dir)
613{
614 GAppInfo* app;
c56a211a
HJYP
615 char** argv;
616 int argc;
617 if(!fm_config->terminal)
618 {
619 fm_show_error(parent, _("Terminal emulator is not set."));
620 fm_edit_preference(parent, PREF_ADVANCED);
621 return;
622 }
623 if(!g_shell_parse_argv(fm_config->terminal, &argc, &argv, NULL))
624 return;
625 app = g_app_info_create_from_commandline(argv[0], NULL, 0, NULL);
626 g_strfreev(argv);
627 if(app)
628 {
629 GError* err = NULL;
630 GAppLaunchContext* ctx = gdk_app_launch_context_new();
631 char* cwd_str;
632
633 if(fm_path_is_native(dir))
634 cwd_str = fm_path_to_str(dir);
635 else
636 {
637 GFile* gf = fm_path_to_gfile(dir);
638 cwd_str = g_file_get_path(gf);
639 g_object_unref(gf);
640 }
99476ede 641 gdk_app_launch_context_set_screen(GDK_APP_LAUNCH_CONTEXT(ctx), parent ? gtk_widget_get_screen(GTK_WIDGET(parent)) : gdk_screen_get_default());
c56a211a
HJYP
642 gdk_app_launch_context_set_timestamp(GDK_APP_LAUNCH_CONTEXT(ctx), gtk_get_current_event_time());
643 g_chdir(cwd_str); /* FIXME: currently we don't have better way for this. maybe a wrapper script? */
644 g_free(cwd_str);
645 if(!g_app_info_launch(app, NULL, ctx, &err))
646 {
647 fm_show_error(parent, err->message);
648 g_error_free(err);
649 }
650 g_object_unref(ctx);
651 g_object_unref(app);
652 }
653}
7cb06c27
HJYP
654
655/* FIXME: Need to load content of ~/Templates and list available templates in popup menus. */
656void pcmanfm_create_new(GtkWindow* parent, FmPath* cwd, const char* templ)
657{
658 GError* err = NULL;
659 FmPath* dest;
660 char* basename;
661_retry:
662 basename = fm_get_user_input(parent, _("Create New..."), _("Enter a name for the newly created file:"), _("New"));
663 if(!basename)
664 return;
665
666 dest = fm_path_new_child(cwd, basename);
667 g_free(basename);
668
669 if( templ == TEMPL_NAME_FOLDER )
670 {
671 GFile* gf = fm_path_to_gfile(dest);
672 if(!g_file_make_directory(gf, NULL, &err))
673 {
98daf506 674 if(err->domain == G_IO_ERROR && err->code == G_IO_ERROR_EXISTS)
7cb06c27
HJYP
675 {
676 fm_path_unref(dest);
677 g_error_free(err);
678 g_object_unref(gf);
679 err = NULL;
680 goto _retry;
681 }
682 fm_show_error(parent, err->message);
683 g_error_free(err);
684 }
685
686 if(!err) /* select the newly created file */
687 {
688 /*FIXME: this doesn't work since the newly created file will
689 * only be shown after file-created event was fired on its
690 * folder's monitor and after FmFolder handles it in idle
691 * handler. So, we cannot select it since it's not yet in
692 * the folder model now. */
693 /* fm_folder_view_select_file_path(fv, dest); */
694 }
695 g_object_unref(gf);
696 }
697 else if( templ == TEMPL_NAME_BLANK )
698 {
699 GFile* gf = fm_path_to_gfile(dest);
700 GFileOutputStream* f = g_file_create(gf, G_FILE_CREATE_NONE, NULL, &err);
701 if(f)
702 {
703 g_output_stream_close(G_OUTPUT_STREAM(f), NULL, NULL);
704 g_object_unref(f);
705 }
706 else
707 {
98daf506 708 if(err->domain == G_IO_ERROR && err->code == G_IO_ERROR_EXISTS)
7cb06c27
HJYP
709 {
710 fm_path_unref(dest);
711 g_error_free(err);
712 g_object_unref(gf);
713 err = NULL;
714 goto _retry;
715 }
716 fm_show_error(parent, err->message);
717 g_error_free(err);
718 }
719
720 if(!err) /* select the newly created file */
721 {
722 /*FIXME: this doesn't work since the newly created file will
723 * only be shown after file-created event was fired on its
724 * folder's monitor and after FmFolder handles it in idle
725 * handler. So, we cannot select it since it's not yet in
726 * the folder model now. */
727 /* fm_folder_view_select_file_path(fv, dest); */
728 }
729 g_object_unref(gf);
730 }
731 else /* templates in ~/Templates */
732 {
733 FmPath* dir = fm_path_new(g_get_user_special_dir(G_USER_DIRECTORY_TEMPLATES));
734 FmPath* template = fm_path_new_child(dir, templ);
735 fm_copy_file(template, cwd);
736 fm_path_unref(template);
737 }
738 fm_path_unref(dest);
739}