Move new lxsession with built-in settings daemon to trunk.
[lxde/lxsession.git] / lxsession / autostart.c
1 /*
2 * autostart.c - Handle autostart spec of freedesktop.org
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 #include <glib.h>
23 #include <stdio.h>
24 #include <string.h>
25
26 static const char DesktopEntry[] = "Desktop Entry";
27 extern const char* session_name;
28
29 #if 0
30 /*
31 * Parse Exec command line of app desktop file, and translate
32 * it into a real command which can be passed to g_spawn_command_line_async().
33 * file_list is a null-terminated file list containing full
34 * paths of the files passed to app.
35 * returned char* should be freed when no longer needed.
36 */
37 static char* translate_app_exec_to_command_line( VFSAppDesktop* app,
38 GList* file_list )
39 {
40 const char* pexec = vfs_app_desktop_get_exec( app );
41 char* file;
42 GList* l;
43 gchar *tmp;
44 GString* cmd = g_string_new("");
45 gboolean add_files = FALSE;
46
47 for( ; *pexec; ++pexec )
48 {
49 if( *pexec == '%' )
50 {
51 ++pexec;
52 switch( *pexec )
53 {
54 case 'U':
55 for( l = file_list; l; l = l->next )
56 {
57 tmp = g_filename_to_uri( (char*)l->data, NULL, NULL );
58 file = g_shell_quote( tmp );
59 g_free( tmp );
60 g_string_append( cmd, file );
61 g_string_append_c( cmd, ' ' );
62 g_free( file );
63 }
64 add_files = TRUE;
65 break;
66 case 'u':
67 if( file_list && file_list->data )
68 {
69 file = (char*)file_list->data;
70 tmp = g_filename_to_uri( file, NULL, NULL );
71 file = g_shell_quote( tmp );
72 g_free( tmp );
73 g_string_append( cmd, file );
74 g_free( file );
75 add_files = TRUE;
76 }
77 break;
78 case 'F':
79 case 'N':
80 for( l = file_list; l; l = l->next )
81 {
82 file = (char*)l->data;
83 tmp = g_shell_quote( file );
84 g_string_append( cmd, tmp );
85 g_string_append_c( cmd, ' ' );
86 g_free( tmp );
87 }
88 add_files = TRUE;
89 break;
90 case 'f':
91 case 'n':
92 if( file_list && file_list->data )
93 {
94 file = (char*)file_list->data;
95 tmp = g_shell_quote( file );
96 g_string_append( cmd, tmp );
97 g_free( tmp );
98 add_files = TRUE;
99 }
100 break;
101 case 'D':
102 for( l = file_list; l; l = l->next )
103 {
104 tmp = g_path_get_dirname( (char*)l->data );
105 file = g_shell_quote( tmp );
106 g_free( tmp );
107 g_string_append( cmd, file );
108 g_string_append_c( cmd, ' ' );
109 g_free( file );
110 }
111 add_files = TRUE;
112 break;
113 case 'd':
114 if( file_list && file_list->data )
115 {
116 tmp = g_path_get_dirname( (char*)file_list->data );
117 file = g_shell_quote( tmp );
118 g_free( tmp );
119 g_string_append( cmd, file );
120 g_free( tmp );
121 add_files = TRUE;
122 }
123 break;
124 case 'c':
125 g_string_append( cmd, vfs_app_desktop_get_disp_name( app ) );
126 break;
127 case 'i':
128 /* Add icon name */
129 if( vfs_app_desktop_get_icon_name( app ) )
130 {
131 g_string_append( cmd, "--icon " );
132 g_string_append( cmd, vfs_app_desktop_get_icon_name( app ) );
133 }
134 break;
135 case 'k':
136 /* Location of the desktop file */
137 break;
138 case 'v':
139 /* Device name */
140 break;
141 case '%':
142 g_string_append_c ( cmd, '%' );
143 break;
144 case '\0':
145 goto _finish;
146 break;
147 }
148 }
149 else /* not % escaped part */
150 {
151 g_string_append_c ( cmd, *pexec );
152 }
153 }
154 _finish:
155 if( ! add_files )
156 {
157 g_string_append_c ( cmd, ' ' );
158 for( l = file_list; l; l = l->next )
159 {
160 file = (char*)l->data;
161 tmp = g_shell_quote( file );
162 g_string_append( cmd, tmp );
163 g_string_append_c( cmd, ' ' );
164 g_free( tmp );
165 }
166 }
167
168 return g_string_free( cmd, FALSE );
169 }
170 #endif
171
172 static void launch_autostart_file( const char* desktop_id, const char* desktop_file, GKeyFile* kf )
173 {
174 if( g_key_file_load_from_file( kf, desktop_file, 0, NULL ) )
175 {
176 char* exec;
177 char** only_show_in, **not_show_in;
178 gsize n;
179
180 if( g_key_file_get_boolean( kf, DesktopEntry, "Hidden", NULL ) )
181 return;
182
183 /* check if this desktop entry is desktop-specific */
184 only_show_in = g_key_file_get_string_list( kf, DesktopEntry, "OnlyShowIn", &n, NULL );
185 if( only_show_in )
186 {
187 /* The format of this list is like: OnlyShowIn=GNOME;XFCE */
188 int i = 0;
189 for( i = 0; i < n; ++i )
190 {
191 /* Only start this program if we are in the "OnlyShowIn" list */
192 if( 0 == strcmp( session_name, only_show_in[ i ] ) )
193 break;
194 }
195 if( i >= n ) /* our session name is not found in the list */
196 {
197 g_strfreev( only_show_in );
198 return; /* read next desktop file */
199 }
200 g_strfreev( only_show_in );
201 }
202 else /* OnlyShowIn and NotShowIn cannot be set at the same time. */
203 {
204 /* check if this desktop entry is not allowed in our session */
205 not_show_in = g_key_file_get_string_list( kf, DesktopEntry, "NotShowIn", &n, NULL );
206 if( not_show_in )
207 {
208 /* The format of this list is like: NotShowIn=KDE;IceWM */
209 int i = 0;
210 for( i = 0; i < n; ++i )
211 {
212 /* Only start this program if we are in the "OnlyShowIn" list */
213 if( 0 == strcmp( session_name, not_show_in[ i ] ) )
214 break;
215 }
216 if( i < n ) /* our session name is found in the "NotShowIn" list */
217 {
218 g_strfreev( not_show_in );
219 return; /* read next desktop file */
220 }
221 g_strfreev( not_show_in );
222 }
223 }
224
225 exec = g_key_file_get_string( kf, DesktopEntry, "TryExec", NULL );
226 if( G_UNLIKELY(exec) ) /* If we are asked to tryexec first */
227 {
228 if( ! g_path_is_absolute( exec ) )
229 {
230 char* full = g_find_program_in_path( exec );
231 g_free( exec );
232 exec = full;
233 }
234 /* If we cannot match the TryExec key with an installed executable program */
235 if( ! g_file_test( exec, G_FILE_TEST_IS_EXECUTABLE ) )
236 {
237 g_free( exec );
238 return; /* bypass this desktop file, and read next */
239 }
240 g_free( exec );
241 }
242
243 /* get the real command line */
244 exec = g_key_file_get_string( kf, DesktopEntry, "Exec", NULL );
245 if( G_LIKELY(exec) )
246 {
247 /* according to the spec, the Exec command line should be translated
248 * with some rules, but that's normally for file managers who needs to
249 * pass selected file as arguments. The probability we need this is
250 * very low, so just omit it.
251 */
252
253 /* FIXME: Exec key should be handled correctly */
254
255 /* launch the program */
256 if( g_spawn_command_line_async( exec, NULL ) )
257 {
258 }
259 }
260 }
261 }
262
263 static void get_autostart_files_in_dir( GHashTable* hash, const char* session_name, const char* base_dir )
264 {
265 char* dir_path = g_build_filename( base_dir, "autostart", NULL );
266 GDir* dir = g_dir_open( dir_path, 0, NULL );
267
268 if( dir )
269 {
270 char *path;
271 const char *name;
272
273 while( (name = g_dir_read_name( dir )) && g_str_has_suffix( name, ".desktop" ) )
274 {
275 path = g_build_filename( dir_path, name, NULL );
276 g_hash_table_replace( hash, g_strdup(name), path );
277 }
278 g_dir_close( dir );
279 }
280 g_free( dir_path );
281 }
282
283 void handle_autostart( const char* session_name )
284 {
285 const char* const *dirs = g_get_system_config_dirs();
286 const char* const *dir;
287 GHashTable* hash = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, g_free );
288
289 /* get system-wide autostart files */
290 for( dir = dirs; *dir; ++dir )
291 get_autostart_files_in_dir( hash, session_name, *dir );
292
293 /* get user-specific autostart files */
294 get_autostart_files_in_dir( hash, session_name, g_get_user_config_dir() );
295
296 if( g_hash_table_size( hash ) > 0 )
297 {
298 GKeyFile* kf = g_key_file_new();
299 g_hash_table_foreach( hash, (GHFunc)launch_autostart_file, kf );
300 g_key_file_free( kf );
301 }
302
303 g_hash_table_destroy( hash );
304 }