Move new lxsession with built-in settings daemon to trunk.
[lxde/lxsession.git] / lxsession / lxsession.c
1 /*
2 * lxsession.c
3 *
4 * Copyright 2008 PCMan <pcman.tw@gmail.com>
5 *
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.
10 *
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.
15 *
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
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <glib.h>
28
29 #include <unistd.h>
30 #include <signal.h>
31 #include <sys/types.h>
32 #include <sys/wait.h>
33 #include <string.h>
34 #include <stdlib.h>
35
36 #include "lxsession.h"
37 #include "xevent.h"
38 #include "settings-daemon.h"
39 #include "autostart.h"
40
41
42 static gboolean no_settings = FALSE; /* disable settings daemon */
43 static gboolean reload_settings = FALSE; /* reload settings daemon */
44
45 static GMainLoop* main_loop = NULL;
46 static const char *display_name = NULL;
47 char* window_manager = NULL; /* will be accessed by settings-daemon.c */
48
49 /* name of environment variables */
50 static char sm_env[] = "SESSION_MANAGER";
51 static char display_env[] = "DISPLAY";
52 static char pid_env[] = "_LXSESSION_PID";
53
54 static char prog_name[]="lxsession";
55 static char config_filename[]="config";
56 static char autostart_filename[]="autostart";
57
58 const char *session_name = NULL;
59
60
61 static GPid run_app( const char* cmd );
62 static void run_guarded_app( const char* cmd );
63 static void start_session();
64
65 static void sig_term_handler ( int sig )
66 {
67 g_main_loop_quit(main_loop);
68 }
69
70 void lxsession_quit()
71 {
72 g_main_loop_quit(main_loop);
73 }
74
75 static void register_signals()
76 {
77 /* Ignore SIGPIPE */
78 signal( SIGPIPE, SIG_IGN );
79
80 #if 0
81 action.sa_handler = g_child_watch_signal_handler;
82 sigemptyset (&action.sa_mask);
83 action.sa_flags = SA_RESTART | SA_NOCLDSTOP;
84 sigaction (SIGCHLD, &action, NULL);
85 #endif
86
87 /* If we get a SIGTERM, do logout */
88 signal( SIGTERM, sig_term_handler );
89 }
90
91 GKeyFile* load_session_config( const char* config_filename )
92 {
93 const gchar* const *dirs = g_get_system_config_dirs();
94 const gchar* const *dir;
95 GKeyFile* kf = g_key_file_new();
96 char* filename;
97 gboolean ret;
98
99 /* load user-specific session config */
100 filename = g_build_filename( g_get_user_config_dir(), prog_name, session_name, config_filename, NULL );
101 ret = g_key_file_load_from_file(kf, filename, 0, NULL);
102 g_free( filename );
103
104 if( ! ret ) /* user specific file is not found */
105 {
106 /* load system-wide session config files */
107 for( dir = dirs; *dir; ++dir )
108 {
109 filename = g_build_filename( *dir, prog_name, session_name, config_filename, NULL );
110 ret = g_key_file_load_from_file(kf, filename, 0, NULL);
111 g_free( filename );
112 if(ret)
113 break;
114 }
115 }
116
117 if( G_UNLIKELY(!ret) )
118 {
119 g_key_file_free(kf);
120 return NULL;
121 }
122 return kf;
123 }
124
125 /* Returns pid if succesful, returns -1 if errors happen. */
126 GPid run_app( const char* cmd )
127 {
128 char** argv;
129 int argc;
130 GPid pid = -1;
131 if( g_shell_parse_argv( cmd, &argc, &argv, NULL ) )
132 {
133 g_spawn_async( NULL, argv, NULL,
134 G_SPAWN_DO_NOT_REAP_CHILD|
135 G_SPAWN_SEARCH_PATH|
136 G_SPAWN_STDOUT_TO_DEV_NULL|
137 G_SPAWN_STDERR_TO_DEV_NULL,
138 NULL, NULL, &pid, NULL );
139 }
140 g_strfreev( argv );
141 return pid;
142 }
143
144 static void on_child_exit( GPid pid, gint status, gchar* cmd )
145 {
146 int sig = WTERMSIG( status );
147 /* if the term signal is not SIGTERM or SIGKILL, this might be a crash! */
148 if( sig && sig != SIGTERM && sig != SIGKILL )
149 {
150 run_guarded_app( cmd );
151 }
152 }
153
154 void run_guarded_app( const char* cmd )
155 {
156 GPid pid = run_app( cmd );
157 if( pid > 0 )
158 {
159 g_child_watch_add_full( G_PRIORITY_DEFAULT_IDLE, pid,
160 (GChildWatchFunc)on_child_exit,
161 g_strdup( cmd ), (GDestroyNotify)g_free );
162 }
163 }
164
165 static void load_default_apps( const char* filename )
166 {
167 char buf[1024];
168 int len;
169 FILE* file = fopen( filename, "r" );
170 if( file )
171 {
172 while ( fgets( buf, sizeof(buf) - 2, file ) )
173 {
174 if ( buf[0] == '\0' || buf[0] == '\n' || buf[0] == '#' )
175 continue; /* a comment */
176 len = strlen ( buf );
177 if( buf[ len - 1 ] == '\n' ) /* remove the '\n' at the end of line */
178 {
179 buf[ len ] = '\0';
180 --len;
181 }
182 if( buf[0] == '@' ) /* if the app should be restarted on crash */
183 run_guarded_app( buf + 1 );
184 else
185 g_spawn_command_line_async( buf, NULL );
186 }
187 fclose( file );
188 }
189 }
190
191 /*
192 * system wide default config is /etc/xdg/lxsession/SESSION_NAME/config
193 * system wide default apps are listed in /etc/xdg/lxsession/SESSION_NAME/autostart
194 */
195 void start_session()
196 {
197 FILE *file = NULL;
198 const gchar* const *dirs = g_get_system_config_dirs();
199 const gchar* const *dir;
200 GKeyFile* kf = g_key_file_new();
201 char* filename;
202
203 /* run window manager first */
204 if( G_LIKELY( window_manager ) )
205 run_guarded_app( window_manager );
206
207 /* load system-wide default apps */
208 for( dir = dirs; *dir; ++dir )
209 {
210 filename = g_build_filename( *dir, prog_name, session_name, autostart_filename, NULL );
211 load_default_apps( filename );
212 g_free( filename );
213 }
214 /* load user-specific default apps */
215 filename = g_build_filename( g_get_user_config_dir(), prog_name, session_name, autostart_filename, NULL );
216 load_default_apps( filename );
217 g_free( filename );
218
219 /* Support autostart spec of freedesktop.org */
220 handle_autostart( session_name );
221 }
222
223 static void parse_options(int argc, char** argv)
224 {
225 int i;
226 for ( i = 1; i < argc; ++i )
227 {
228 if ( argv[i][0] == '-' )
229 {
230 switch ( argv[i][1] )
231 {
232 case 'd': /* -display */
233 if ( ++i >= argc ) goto usage;
234 display_name = argv[i];
235 g_setenv( display_env, display_name, TRUE );
236 continue;
237 case 's': /* -session */
238 if ( ++i >= argc ) goto usage;
239 session_name = argv[i];
240 continue;
241 case 'n': /* disable xsettings daemon */
242 no_settings = TRUE;
243 continue;
244 case 'r':
245 if( 0 == strcmp( argv[i]+1, "reload" ) )
246 reload_settings = TRUE;
247 }
248 }
249 usage:
250 fprintf ( stderr,
251 "Usage: lxsession [OPTIONS...]\n"
252 "\t-d name\tspecify name of display (optional)\n"
253 "\t-s name\tspecify name of the desktop session\n"
254 "\t-r\t reload configurations (for Xsettings daemon)\n"
255 "\t-n\t disable Xsettings daemon support\n" );
256 exit(1);
257 }
258 }
259
260 int main(int argc, char** argv)
261 {
262 const char *pid_str;
263 char str[ 16 ];
264 GKeyFile* kf;
265
266 pid_str = g_getenv(pid_env);
267
268 display_name = g_getenv( display_env );
269 if( ! display_name )
270 {
271 display_name = ":0";
272 g_setenv( display_env, display_name, TRUE );
273 }
274
275 parse_options(argc, argv);
276
277 /* initialize X-related stuff and connect to X Display */
278 if( G_UNLIKELY(! xevent_init() ) )
279 return 1;
280
281 /* send command to existing daemon to reload settings */
282 if( G_UNLIKELY( reload_settings ) )
283 {
284 send_internal_command( LXS_RELOAD );
285 return 0;
286 }
287 else if( G_UNLIKELY( !single_instance_check()) )
288 {
289 /* only one instance is allowed for each X. */
290 g_error( "Only one lxsession can be executed at a time." );
291 return 1;
292 }
293
294 /* set pid */
295 g_snprintf( str, 16, "%d", getpid() );
296 g_setenv(pid_env, str, TRUE );
297
298 main_loop = g_main_loop_new( NULL, TRUE );
299
300 /* setup signal handlers */
301 register_signals();
302
303 if ( G_UNLIKELY(!session_name) )
304 session_name = "LXDE";
305
306 g_setenv( "DESKTOP_SESSION", session_name, TRUE );
307
308 /* FIXME: setup locales: LC_ALL, LANG, LANGUAGE?
309 * Is this needed? */
310
311 /* FIXME: load environment variables? */
312
313 /* Load desktop session config file */
314 kf = load_session_config(CONFIG_FILE_NAME);
315 if( !kf )
316 {
317 xevent_finalize();
318 return 1;
319 }
320
321 window_manager = g_key_file_get_string( kf, "Session", "window_manager", NULL );
322
323 if( G_LIKELY(!no_settings) )
324 start_settings_daemon(kf);
325
326 g_key_file_free(kf);
327
328 /* start desktop session and load autostart applications */
329 start_session();
330
331 g_main_loop_run( main_loop );
332 g_main_loop_unref( main_loop );
333
334 xevent_finalize();
335
336 return 0;
337 }