l10n: Updates to Spanish (Castilian) (es) translation
[lxde/pcmanfm.git] / src / pcmanfm.c
CommitLineData
b6e3c554
HJYP
1/*
2 * pcmanfm.c
d3451adb 3 *
f0ce8c37 4 * Copyright 2009 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
HJYP
38
39#include <fm-gtk.h>
4d55886c 40#include "app-config.h"
b6e3c554 41#include "main-win.h"
8505a8ef 42#include "desktop.h"
c5fccf1d 43#include "pref.h"
8505a8ef 44
f8f2bfad
HJYP
45static int sock;
46GIOChannel* io_channel = NULL;
47
48gboolean daemon_mode = FALSE;
49
f8f2bfad 50static char** files_to_open = NULL;
f970e846
HJYP
51static char* profile = NULL;
52static char* config_name = NULL;
f8f2bfad
HJYP
53static gboolean no_desktop = FALSE;
54static gboolean show_desktop = FALSE;
55static gboolean desktop_off = FALSE;
56static gboolean desktop_running = FALSE;
57static gboolean new_tab = FALSE;
58static int show_pref = 0;
59static gboolean desktop_pref = FALSE;
60static char* set_wallpaper = NULL;
61static gboolean find_files = FALSE;
62
63static int n_pcmanfm_ref = 0;
64
65static GOptionEntry opt_entries[] =
8505a8ef 66{
f970e846
HJYP
67 { "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 },
68 { "profile", 'p', 0, G_OPTION_ARG_STRING, &profile, N_("Name of config profile"), "<profile name>" },
f8f2bfad
HJYP
69 { "desktop", '\0', 0, G_OPTION_ARG_NONE, &show_desktop, N_("Launch desktop manager"), NULL },
70 { "desktop-off", '\0', 0, G_OPTION_ARG_NONE, &desktop_off, N_("Turn off desktop manager if it's running"), NULL },
f8f2bfad 71 { "daemon-mode", 'd', 0, G_OPTION_ARG_NONE, &daemon_mode, N_("Run PCManFM as a daemon"), NULL },
f8f2bfad 72 { "desktop-pref", '\0', 0, G_OPTION_ARG_NONE, &desktop_pref, N_("Open desktop preference dialog"), NULL },
f970e846
HJYP
73 { "set-wallpaper", 'w', 0, G_OPTION_ARG_FILENAME, &set_wallpaper, N_("Set desktop wallpaper"), N_("<image file>") },
74 { "show-pref", '\0', 0, G_OPTION_ARG_INT, &show_pref, N_("Open preference dialog. 'n' is the number of page you want to show (1, 2, 3...)."), "n" },
f8f2bfad 75 { "find-files", 'f', 0, G_OPTION_ARG_NONE, &find_files, N_("Open Find Files utility"), NULL },
f970e846 76 { "no-desktop", '\0', 0, G_OPTION_ARG_NONE, &no_desktop, N_("No function. Just to be compatible with nautilus"), NULL },
f8f2bfad
HJYP
77 {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &files_to_open, NULL, N_("[FILE1, FILE2,...]")},
78 { NULL }
79};
80
81static gboolean single_instance_check();
82static void single_instance_finalize();
83static void get_socket_name(char* buf, int len);
84static gboolean pcmanfm_run();
85static gboolean on_socket_event(GIOChannel* ioc, GIOCondition cond, gpointer data);
b6e3c554
HJYP
86
87int main(int argc, char** argv)
88{
4d55886c 89 FmConfig* config;
f8f2bfad
HJYP
90 GError* err = NULL;
91
92#ifdef ENABLE_NLS
93 bindtextdomain ( GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR );
94 bind_textdomain_codeset ( GETTEXT_PACKAGE, "UTF-8" );
95 textdomain ( GETTEXT_PACKAGE );
96#endif
97
98 /* initialize GTK+ and parse the command line arguments */
99 if(G_UNLIKELY(!gtk_init_with_args(&argc, &argv, "", opt_entries, GETTEXT_PACKAGE, &err)))
100 {
101 g_printf("%s\n", err->message);
c5fccf1d 102 g_error_free(err);
f8f2bfad
HJYP
103 return 1;
104 }
105
106 /* ensure that there is only one instance of pcmanfm.
107 if there is an existing instance, command line arguments
108 will be passed to the existing instance, and exit() will be called here. */
109 single_instance_check();
110
111 /* intercept signals */
112 signal( SIGPIPE, SIG_IGN );
113 /* signal( SIGHUP, gtk_main_quit ); */
114 signal( SIGINT, gtk_main_quit );
115 signal( SIGTERM, gtk_main_quit );
b6e3c554 116
f970e846
HJYP
117 config = fm_app_config_new(); /* this automatically load libfm config file. */
118 /* load pcmanfm-specific config file */
119 if(profile)
120 config_name = g_strconcat("pcmanfm/", profile, ".conf", NULL);
121 fm_app_config_load_from_file(config, config_name);
122
4d55886c 123 fm_gtk_init(config);
b6e3c554 124
f8f2bfad
HJYP
125 /* the main part */
126 if(pcmanfm_run())
127 {
128 gtk_main();
129 if(desktop_running)
130 fm_desktop_manager_finalize();
f8f2bfad 131 fm_config_save(config, NULL); /* save libfm config */
f970e846 132 fm_app_config_save((FmAppConfig*)config, config_name); /* save pcmanfm config */
f8f2bfad
HJYP
133 }
134 single_instance_finalize();
8505a8ef 135
f8f2bfad
HJYP
136 fm_gtk_finalize();
137 g_object_unref(config);
f8f2bfad
HJYP
138 return 0;
139}
140
141
142inline static GString* args_to_keyfile()
143{
144 int i;
145 GString* buf = g_string_sized_new(1024);
146 g_string_assign(buf, "[a]\n");
147 for(i = 0; i < G_N_ELEMENTS(opt_entries)-1;++i)
148 {
149 GOptionEntry* ent = &opt_entries[i];
150 if(G_LIKELY(*ent->long_name))
151 g_string_append(buf, ent->long_name);
152 else /* G_OPTION_REMAINING */
153 g_string_append(buf, "@");
154 g_string_append_c(buf, '=');
155 switch(ent->arg)
156 {
157 case G_OPTION_ARG_NONE: /* bool */
158 g_string_append_c(buf, *(gboolean*)ent->arg_data ? '1' : '0');
159 break;
160 case G_OPTION_ARG_INT: /* int */
161 g_string_append_printf(buf, "%d", *(gint*)ent->arg_data);
162 break;
163 case G_OPTION_ARG_FILENAME_ARRAY: /* string array */
f970e846 164 case G_OPTION_ARG_STRING_ARRAY:
f8f2bfad
HJYP
165 {
166 char** files = *(char***)ent->arg_data;
167 if(files)
168 {
169 for(;*files;++files)
170 {
171 g_string_append(buf, *files);
172 g_string_append_c(buf, ';');
173 }
174 }
175 }
176 break;
177 case G_OPTION_ARG_FILENAME:
178 case G_OPTION_ARG_STRING: /* string */
179 if(*(gchar**)ent->arg_data)
180 g_string_append(buf, *(gchar**)ent->arg_data);
181 break;
182 }
183 g_string_append_c(buf, '\n');
184 }
185 return buf;
186}
187
188inline static void keyfile_to_args(GString* buf)
189{
190 GKeyFile* kf = g_key_file_new();
191 /* g_debug("\n%s", buf->str); */
192 if(g_key_file_load_from_data(kf, buf->str, buf->len, 0, NULL))
b6e3c554 193 {
f8f2bfad 194 int i;
19abb8bf 195 char*** pstrs;
f8f2bfad
HJYP
196 for(i = 0; i < G_N_ELEMENTS(opt_entries)-1;++i)
197 {
198 GOptionEntry* ent = &opt_entries[i];
199 switch(ent->arg)
200 {
201 case G_OPTION_ARG_NONE: /* bool */
202 *(gboolean*)ent->arg_data = g_key_file_get_boolean(kf, "a", ent->long_name, NULL);
203 break;
204 case G_OPTION_ARG_INT: /* int */
205 *(gint*)ent->arg_data = g_key_file_get_integer(kf, "a", ent->long_name, NULL);
206 break;
207 case G_OPTION_ARG_FILENAME_ARRAY: /* string array */
f970e846 208 case G_OPTION_ARG_STRING_ARRAY:
19abb8bf
HJYP
209 pstrs = (char**)ent->arg_data;
210 if(*pstrs)
211 g_strfreev(*pstrs);
212 *pstrs = g_key_file_get_string_list(kf, "a", *ent->long_name ? *ent->long_name : "@", NULL, NULL);
213 if(*pstrs)
214 {
215 char** strs = *pstrs;
216 char* str = *strs;
217 if(!str || str[0] == '\0')
218 {
219 g_strfreev(strs);
220 *pstrs = NULL;
221 }
222 }
f8f2bfad
HJYP
223 break;
224 case G_OPTION_ARG_FILENAME:
225 case G_OPTION_ARG_STRING: /* string */
226 if(*(char**)ent->arg_data)
227 g_free(*(char**)ent->arg_data);
228 *(char**)ent->arg_data = g_key_file_get_string(kf, "a", ent->long_name, NULL);
19abb8bf
HJYP
229 if(*(char**)ent->arg_data && **(char**)ent->arg_data == '\0')
230 {
231 g_free(*(char**)ent->arg_data);
232 *(char**)ent->arg_data = NULL;
233 }
f8f2bfad
HJYP
234 break;
235 }
236 }
b6e3c554 237 }
f8f2bfad
HJYP
238 g_key_file_free(kf);
239}
8505a8ef 240
f8f2bfad
HJYP
241gboolean on_socket_event( GIOChannel* ioc, GIOCondition cond, gpointer data )
242{
243 int client, r;
244 socklen_t addr_len = 0;
245 struct sockaddr_un client_addr ={ 0 };
246 static char buf[ 1024 ];
247 GString* args;
248 char** file;
b6e3c554 249
f8f2bfad
HJYP
250 if ( cond & G_IO_IN )
251 {
252 client = accept( g_io_channel_unix_get_fd( ioc ), (struct sockaddr *)&client_addr, &addr_len );
253 if ( client != -1 )
254 {
255 args = g_string_sized_new(1024);
256 while( (r = read( client, buf, sizeof(buf) )) > 0 )
257 g_string_append_len( args, buf, r);
258 shutdown( client, 2 );
259 close( client );
260 keyfile_to_args(args);
261 g_string_free( args, TRUE );
262 pcmanfm_run();
263 }
264 }
265 return TRUE;
266}
19fbd668 267
f8f2bfad
HJYP
268void get_socket_name( char* buf, int len )
269{
270 char* dpy = gdk_get_display();
271 g_snprintf( buf, len, "/tmp/.pcmanfm2-socket%s-%s", dpy, g_get_user_name() );
272 g_free( dpy );
273}
8505a8ef 274
f8f2bfad
HJYP
275gboolean single_instance_check()
276{
277 struct sockaddr_un addr;
278 int addr_len;
279 int ret;
280 int reuse;
b6e3c554 281
f8f2bfad
HJYP
282 if((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
283 {
284 ret = 1;
285 goto _exit;
286 }
287
288 /* FIXME: use abstract socket */
289 addr.sun_family = AF_UNIX;
290 get_socket_name(addr.sun_path, sizeof( addr.sun_path ));
291#ifdef SUN_LEN
292 addr_len = SUN_LEN(&addr);
293#else
294 addr_len = strlen( addr.sun_path ) + sizeof( addr.sun_family );
295#endif
296
297 /* try to connect to existing instance */
298 if(connect(sock, (struct sockaddr*)&addr, addr_len) == 0)
299 {
300 /* connected successfully */
301 GString* buf = args_to_keyfile();
302 write(sock, buf->str, buf->len);
303 g_string_free(buf, TRUE);
304
305 shutdown( sock, 2 );
306 close( sock );
307 ret = 0;
308 goto _exit;
309 }
310
311 /* There is no existing server, and we are in the first instance. */
312 unlink( addr.sun_path ); /* delete old socket file if it exists. */
313 reuse = 1;
314 ret = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse) );
315 if(bind(sock, (struct sockaddr*)&addr, addr_len) == -1)
316 {
317 ret = 1;
318 goto _exit;
319 }
320
321 io_channel = g_io_channel_unix_new(sock);
322 g_io_channel_set_encoding(io_channel, NULL, NULL);
323 g_io_channel_set_buffered(io_channel, FALSE);
324 g_io_add_watch(io_channel, G_IO_IN,
325 (GIOFunc)on_socket_event, NULL);
326 if(listen(sock, 5) == -1)
327 {
328 ret = 1;
329 goto _exit;
330 }
d3451adb 331 return TRUE;
f8f2bfad
HJYP
332
333_exit:
334
335 gdk_notify_startup_complete();
336 exit( ret );
337}
338
339void single_instance_finalize()
340{
341 char lock_file[256];
342 shutdown(sock, 2);
343 g_io_channel_unref(io_channel);
344 close(sock);
345 get_socket_name(lock_file, sizeof( lock_file ));
346 unlink(lock_file);
347}
348
349
350gboolean pcmanfm_run()
351{
352 gboolean ret = TRUE;
353 char** file;
354 GtkWidget* w;
355
f8f2bfad
HJYP
356 if(!files_to_open)
357 {
358 /* Launch desktop manager */
359 if(show_desktop)
360 {
361 if(!desktop_running)
362 {
363 fm_desktop_manager_init();
364 desktop_running = TRUE;
365 }
19abb8bf 366 show_desktop = FALSE;
f8f2bfad
HJYP
367 return TRUE;
368 }
369 else if(desktop_off)
370 {
371 if(desktop_running)
372 {
373 desktop_running = FALSE;
374 fm_desktop_manager_finalize();
375 }
19abb8bf 376 desktop_off = FALSE;
f8f2bfad
HJYP
377 return FALSE;
378 }
379 else if(show_pref > 0)
380 {
c5fccf1d
HJYP
381 fm_edit_preference(NULL, show_pref - 1);
382 show_pref = 0;
f8f2bfad
HJYP
383 return TRUE;
384 }
385 else if(desktop_pref)
386 {
c5fccf1d 387 fm_desktop_preference();
19abb8bf 388 desktop_pref = FALSE;
f8f2bfad
HJYP
389 return TRUE;
390 }
391 else if(set_wallpaper)
392 {
f970e846 393 /* g_debug("\'%s\'", set_wallpaper); */
f8f2bfad 394 /* Make sure this is a support image file. */
f970e846 395 if(gdk_pixbuf_get_file_info(set_wallpaper, NULL, NULL))
f8f2bfad 396 {
f970e846
HJYP
397 if(app_config->wallpaper)
398 g_free(app_config->wallpaper);
399 app_config->wallpaper = set_wallpaper;
f8f2bfad 400 set_wallpaper = NULL;
f970e846 401 if(app_config->wallpaper_mode == FM_WP_COLOR)
c5fccf1d 402 app_config->wallpaper_mode = FM_WP_FIT;
f8f2bfad
HJYP
403 fm_config_emit_changed(app_config, "wallpaper");
404 fm_app_config_save(app_config, NULL);
405 }
406 return FALSE;
407 }
408 }
409
410 if(G_UNLIKELY(find_files))
411 {
412 /* FIXME: find files */
413 }
414 else
415 {
416 if(!files_to_open)
417 {
418 FmPath* path;
419 w = fm_main_win_new();
19abb8bf 420 gtk_window_set_default_size(w, app_config->win_width, app_config->win_height);
f8f2bfad
HJYP
421 gtk_widget_show(w);
422 path = fm_path_get_home();
423 fm_main_win_chdir(w, path);
f8f2bfad
HJYP
424 }
425 }
426 return ret;
427}
428
429/* After opening any window/dialog/tool, this should be called. */
430void pcmanfm_ref()
431{
432 ++n_pcmanfm_ref;
433 /* g_debug("ref: %d", n_pcmanfm_ref); */
434}
435
436/* After closing any window/dialog/tool, this should be called.
437 * If the last window is closed and we are not a deamon, pcmanfm will quit.
438 */
439void pcmanfm_unref()
440{
441 --n_pcmanfm_ref;
442 /* g_debug("unref: %d, daemon_mode=%d, desktop_running=%d", n_pcmanfm_ref, daemon_mode, desktop_running); */
443 if( 0 == n_pcmanfm_ref && !daemon_mode && !desktop_running )
444 gtk_main_quit();
b6e3c554 445}