Fix bugs in shell expansion support.
authorHong Jen Yee (PCMan) <pcman.tw@gmail.com>
Mon, 8 Mar 2010 07:03:35 +0000 (15:03 +0800)
committerHong Jen Yee (PCMan) <pcman.tw@gmail.com>
Tue, 9 Mar 2010 00:35:33 +0000 (08:35 +0800)
Rename autostart.c to xdg-autostart.c to indicate that it's used to handle freedesktop.org autostart spec.
Prevent unnecessary checks in lxsession-logout.

lxsession-logout/lxsession-logout.c
lxsession/Makefile.am
lxsession/autostart.c [deleted file]
lxsession/autostart.h [deleted file]
lxsession/lxsession.c
lxsession/xdg-autostart.c [new file with mode: 0644]
lxsession/xdg-autostart.h [new file with mode: 0644]

index 5d83b1e..176bc99 100644 (file)
@@ -239,7 +239,7 @@ int main(int argc, char * argv[])
     {
         g_print( _("Error: %s\n"), _("LXSession is not running."));
         return 1;
-    }   
+    }
 
     /* Initialize capabilities of the ConsoleKit mechanism. */
     if (dbus_ConsoleKit_CanStop())
@@ -268,22 +268,22 @@ int main(int argc, char * argv[])
 #endif
 
     /* Initialize capabilities of the HAL mechanism. */
-    if (dbus_HAL_CanShutdown())
+    if (!handler_context.shutdown_available && dbus_HAL_CanShutdown())
     {
         handler_context.shutdown_available = TRUE;
         handler_context.shutdown_HAL = TRUE;
     }
-    if (dbus_HAL_CanReboot())
+    if (!handler_context.reboot_available && dbus_HAL_CanReboot())
     {
         handler_context.reboot_available = TRUE;
         handler_context.reboot_HAL = TRUE;
     }
-    if (dbus_HAL_CanSuspend())
+    if (!handler_context.suspend_available && dbus_HAL_CanSuspend())
     {
         handler_context.suspend_available = TRUE;
         handler_context.suspend_HAL = TRUE;
     }
-    if (dbus_HAL_CanHibernate())
+    if (!handler_context.hibernate_available && dbus_HAL_CanHibernate())
     {
         handler_context.hibernate_available = TRUE;
         handler_context.hibernate_HAL = TRUE;
index f43f708..9c783d9 100644 (file)
@@ -12,8 +12,8 @@ lxsession_LDADD = $(GLIB_LIBS) -lX11
 lxsession_SOURCES = \
        lxsession.c \
        lxsession.h \
-       autostart.c \
-       autostart.h \
+       xdg-autostart.c \
+       xdg-autostart.h \
        xevent.c \
        xevent.h \
        settings-daemon.c \
diff --git a/lxsession/autostart.c b/lxsession/autostart.c
deleted file mode 100644 (file)
index b7cb42e..0000000
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- *      autostart.c - Handle autostart spec of freedesktop.org
- *
- *      Copyright 2008 PCMan <pcman.tw@gmail.com>
- *
- *      This program is free software; you can redistribute it and/or modify
- *      it under the terms of the GNU General Public License as published by
- *      the Free Software Foundation; either version 2 of the License, or
- *      (at your option) any later version.
- *
- *      This program is distributed in the hope that it will be useful,
- *      but WITHOUT ANY WARRANTY; without even the implied warranty of
- *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *      GNU General Public License for more details.
- *
- *      You should have received a copy of the GNU General Public License
- *      along with this program; if not, write to the Free Software
- *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *      MA 02110-1301, USA.
- */
-
-#include <glib.h>
-#include <stdio.h>
-#include <string.h>
-
-static const char DesktopEntry[] = "Desktop Entry";
-extern const char* de_name; /* defined in lxsession.c */
-
-#if 0
-/*
-* Parse Exec command line of app desktop file, and translate
-* it into a real command which can be passed to g_spawn_command_line_async().
-* file_list is a null-terminated file list containing full
-* paths of the files passed to app.
-* returned char* should be freed when no longer needed.
-*/
-static char* translate_app_exec_to_command_line( VFSAppDesktop* app,
-                                                 GList* file_list )
-{
-    const char* pexec = vfs_app_desktop_get_exec( app );
-    char* file;
-    GList* l;
-    gchar *tmp;
-    GString* cmd = g_string_new("");
-    gboolean add_files = FALSE;
-
-    for( ; *pexec; ++pexec )
-    {
-        if( *pexec == '%' )
-        {
-            ++pexec;
-            switch( *pexec )
-            {
-            case 'U':
-                for( l = file_list; l; l = l->next )
-                {
-                    tmp = g_filename_to_uri( (char*)l->data, NULL, NULL );
-                    file = g_shell_quote( tmp );
-                    g_free( tmp );
-                    g_string_append( cmd, file );
-                    g_string_append_c( cmd, ' ' );
-                    g_free( file );
-                }
-                add_files = TRUE;
-                break;
-            case 'u':
-                if( file_list && file_list->data )
-                {
-                    file = (char*)file_list->data;
-                    tmp = g_filename_to_uri( file, NULL, NULL );
-                    file = g_shell_quote( tmp );
-                    g_free( tmp );
-                    g_string_append( cmd, file );
-                    g_free( file );
-                    add_files = TRUE;
-                }
-                break;
-            case 'F':
-            case 'N':
-                for( l = file_list; l; l = l->next )
-                {
-                    file = (char*)l->data;
-                    tmp = g_shell_quote( file );
-                    g_string_append( cmd, tmp );
-                    g_string_append_c( cmd, ' ' );
-                    g_free( tmp );
-                }
-                add_files = TRUE;
-                break;
-            case 'f':
-            case 'n':
-                if( file_list && file_list->data )
-                {
-                    file = (char*)file_list->data;
-                    tmp = g_shell_quote( file );
-                    g_string_append( cmd, tmp );
-                    g_free( tmp );
-                    add_files = TRUE;
-                }
-                break;
-            case 'D':
-                for( l = file_list; l; l = l->next )
-                {
-                    tmp = g_path_get_dirname( (char*)l->data );
-                    file = g_shell_quote( tmp );
-                    g_free( tmp );
-                    g_string_append( cmd, file );
-                    g_string_append_c( cmd, ' ' );
-                    g_free( file );
-                }
-                add_files = TRUE;
-                break;
-            case 'd':
-                if( file_list && file_list->data )
-                {
-                    tmp = g_path_get_dirname( (char*)file_list->data );
-                    file = g_shell_quote( tmp );
-                    g_free( tmp );
-                    g_string_append( cmd, file );
-                    g_free( tmp );
-                    add_files = TRUE;
-                }
-                break;
-            case 'c':
-                g_string_append( cmd, vfs_app_desktop_get_disp_name( app ) );
-                break;
-            case 'i':
-                /* Add icon name */
-                if( vfs_app_desktop_get_icon_name( app ) )
-                {
-                    g_string_append( cmd, "--icon " );
-                    g_string_append( cmd, vfs_app_desktop_get_icon_name( app ) );
-                }
-                break;
-            case 'k':
-                /* Location of the desktop file */
-                break;
-            case 'v':
-                /* Device name */
-                break;
-            case '%':
-                g_string_append_c ( cmd, '%' );
-                break;
-            case '\0':
-                goto _finish;
-                break;
-            }
-        }
-        else  /* not % escaped part */
-        {
-            g_string_append_c ( cmd, *pexec );
-        }
-    }
-_finish:
-    if( ! add_files )
-    {
-        g_string_append_c ( cmd, ' ' );
-        for( l = file_list; l; l = l->next )
-        {
-            file = (char*)l->data;
-            tmp = g_shell_quote( file );
-            g_string_append( cmd, tmp );
-            g_string_append_c( cmd, ' ' );
-            g_free( tmp );
-        }
-    }
-
-    return g_string_free( cmd, FALSE );
-}
-#endif
-
-static void launch_autostart_file( const char* desktop_id, const char* desktop_file, GKeyFile* kf )
-{
-    if( g_key_file_load_from_file( kf, desktop_file, 0, NULL ) )
-    {
-        char* exec;
-        char** only_show_in, **not_show_in;
-        gsize n;
-
-        if( g_key_file_get_boolean( kf, DesktopEntry, "Hidden", NULL ) )
-            return;
-
-        /* check if this desktop entry is desktop-specific */
-        only_show_in = g_key_file_get_string_list( kf, DesktopEntry, "OnlyShowIn", &n, NULL );
-        if( only_show_in )
-        {
-            /* The format of this list is like:  OnlyShowIn=GNOME;XFCE */
-            int i = 0;
-            for( i = 0; i < n; ++i )
-            {
-                /* Only start this program if we are in the "OnlyShowIn" list */
-                if( 0 == strcmp( de_name, only_show_in[ i ] ) )
-                    break;
-            }
-            if( i >= n )    /* our session name is not found in the list */
-            {
-                g_strfreev( only_show_in );
-                return;   /* read next desktop file */
-            }
-            g_strfreev( only_show_in );
-        }
-               else /* OnlyShowIn and NotShowIn cannot be set at the same time. */
-               {
-                       /* check if this desktop entry is not allowed in our session */
-                       not_show_in = g_key_file_get_string_list( kf, DesktopEntry, "NotShowIn", &n, NULL );
-                       if( not_show_in )
-                       {
-                               /* The format of this list is like:  NotShowIn=KDE;IceWM */
-                               int i = 0;
-                               for( i = 0; i < n; ++i )
-                               {
-                                       /* Only start this program if we are in the "OnlyShowIn" list */
-                                       if( 0 == strcmp( de_name, not_show_in[ i ] ) )
-                                               break;
-                               }
-                               if( i < n )    /* our session name is found in the "NotShowIn" list */
-                               {
-                                       g_strfreev( not_show_in );
-                                       return;   /* read next desktop file */
-                               }
-                               g_strfreev( not_show_in );
-                       }
-               }
-
-        exec = g_key_file_get_string( kf, DesktopEntry, "TryExec", NULL );
-        if( G_UNLIKELY(exec) ) /* If we are asked to tryexec first */
-        {
-            if( ! g_path_is_absolute( exec ) )
-            {
-                char* full = g_find_program_in_path( exec );
-                g_free( exec );
-                exec = full;
-            }
-            /* If we cannot match the TryExec key with an installed executable program */
-            if( ! g_file_test( exec, G_FILE_TEST_IS_EXECUTABLE ) )
-            {
-                g_free( exec );
-                return;   /* bypass this desktop file, and read next */
-            }
-            g_free( exec );
-        }
-
-        /* get the real command line */
-        exec = g_key_file_get_string( kf, DesktopEntry, "Exec", NULL );
-        if( G_LIKELY(exec) )
-        {
-            /* according to the spec, the Exec command line should be translated
-             *  with some rules, but that's normally for file managers who needs to
-             *  pass selected file as arguments. The probability we need this is
-             *  very low, so just omit it.
-             */
-                       
-                       /* FIXME: Exec key should be handled correctly */
-
-            /* launch the program */
-            if( g_spawn_command_line_async( exec, NULL ) )
-            {
-            }
-        }
-    }
-}
-
-static void get_autostart_files_in_dir( GHashTable* hash, const char* de_name, const char* base_dir )
-{
-    char* dir_path = g_build_filename( base_dir, "autostart", NULL );
-    GDir* dir = g_dir_open( dir_path, 0, NULL );
-
-    if( dir )
-    {
-        char *path;
-        const char *name;
-
-        while( (name = g_dir_read_name( dir )) && g_str_has_suffix( name, ".desktop" ) )
-        {
-            path = g_build_filename( dir_path, name, NULL );
-            g_hash_table_replace( hash, g_strdup(name), path );
-        }
-        g_dir_close( dir );
-    }
-    g_free( dir_path );
-}
-
-void handle_autostart( const char* de_name )
-{
-    const char* const *dirs = g_get_system_config_dirs();
-    const char* const *dir;
-    GHashTable* hash = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, g_free );
-
-    /* get system-wide autostart files */
-    for( dir = dirs; *dir; ++dir )
-        get_autostart_files_in_dir( hash, de_name, *dir );
-
-    /* get user-specific autostart files */
-    get_autostart_files_in_dir( hash, de_name, g_get_user_config_dir() );
-
-    if( g_hash_table_size( hash ) > 0 )
-    {
-        GKeyFile* kf = g_key_file_new();
-        g_hash_table_foreach( hash, (GHFunc)launch_autostart_file, kf );
-        g_key_file_free( kf );
-    }
-
-    g_hash_table_destroy( hash );
-}
diff --git a/lxsession/autostart.h b/lxsession/autostart.h
deleted file mode 100644 (file)
index d1168b7..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- *      autostart.h - Handle autostart spec of freedesktop.org
- *
- *      Copyright 2008 PCMan <pcman.tw@gmail.com>
- *
- *      This program is free software; you can redistribute it and/or modify
- *      it under the terms of the GNU General Public License as published by
- *      the Free Software Foundation; either version 2 of the License, or
- *      (at your option) any later version.
- *
- *      This program is distributed in the hope that it will be useful,
- *      but WITHOUT ANY WARRANTY; without even the implied warranty of
- *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *      GNU General Public License for more details.
- *
- *      You should have received a copy of the GNU General Public License
- *      along with this program; if not, write to the Free Software
- *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *      MA 02110-1301, USA.
- */
-
-#ifndef _AUTOSTART_H_
-#define _AUTOSTART_H_
-
-void handle_autostart( const char* session_name );
-
-#endif
index 468bf87..17e3ff7 100644 (file)
@@ -38,7 +38,7 @@
 #include "lxsession.h"
 #include "xevent.h"
 #include "settings-daemon.h"
-#include "autostart.h"
+#include "xdg-autostart.h"
 
 
 static gboolean no_settings = FALSE; /* disable settings daemon */
@@ -59,8 +59,7 @@ static char autostart_filename[]="autostart";
 const char *session_name = NULL;
 const char* de_name = NULL;
 
-static GPid run_app( const char* cmd, gboolean shell_expansion );
-static void run_guarded_app( const char* cmd );
+static GPid run_app( const char* cmd, gboolean guarded );
 static void start_session();
 
 static void sig_term_handler ( int sig )
@@ -95,7 +94,7 @@ GKeyFile* load_session_config( const char* config_filename )
     const gchar* const *dir;
     GKeyFile* kf = g_key_file_new();
     char* filename;
-       gboolean ret;
+    gboolean ret;
 
     /* load user-specific session config */
     filename = g_build_filename( g_get_user_config_dir(), prog_name, session_name, config_filename, NULL );
@@ -123,57 +122,34 @@ GKeyFile* load_session_config( const char* config_filename )
        return kf;
 }
 
-/* Returns pid if succesful, returns -1 if errors happen. */
-GPid run_app( const char* cmd, gboolean shell_expansion )
-{
-    GPid pid = -1;
-    if(shell_expansion)
-    {
-        wordexp_t we;
-        if( wordexp(cmd, &we, 0) == 0)
-        {
-            g_spawn_async( NULL, we.we_wordv, NULL,
-                    G_SPAWN_DO_NOT_REAP_CHILD|
-                G_SPAWN_SEARCH_PATH,
-            NULL, NULL, &pid, NULL );
-            wordfree(&we);
-        }
-    }
-    else
-    {
-        int argc;
-        char** argv;
-        if( g_shell_parse_argv( cmd, &argc, &argv, NULL ) )
-        {
-            g_spawn_async( NULL, argv, NULL,
-                    G_SPAWN_DO_NOT_REAP_CHILD|
-                G_SPAWN_SEARCH_PATH,
-            NULL, NULL, &pid, NULL );
-        }
-        g_strfreev( argv );
-    }
-    return pid;
-}
-
 static void on_child_exit( GPid pid, gint status, gchar* cmd )
 {
     int sig = WTERMSIG( status );
     /* if the term signal is not SIGTERM or SIGKILL, this might be a crash! */
     if( sig && sig != SIGTERM && sig != SIGKILL )
-    {
-        run_guarded_app( cmd );
-    }
+        run_app( cmd, TRUE );
 }
 
-void run_guarded_app( const char* cmd )
+/* Returns pid if succesful, returns -1 if errors happen. */
+GPid run_app( const char* cmd, gboolean guarded )
 {
-    GPid pid = run_app( cmd, TRUE );
-    if( pid > 0 )
+    GPid pid = -1;
+    wordexp_t we;
+    GSpawnFlags flags = guarded ? G_SPAWN_DO_NOT_REAP_CHILD|G_SPAWN_SEARCH_PATH : G_SPAWN_SEARCH_PATH;
+
+    if( wordexp(cmd, &we, 0) == 0)
+    {
+        g_spawn_async( NULL, we.we_wordv, NULL, flags, NULL, NULL, &pid, NULL );
+        wordfree(&we);
+    }
+
+    if(guarded && pid > 0)
     {
         g_child_watch_add_full( G_PRIORITY_DEFAULT_IDLE, pid,
                                 (GChildWatchFunc)on_child_exit,
                                 g_strdup( cmd ), (GDestroyNotify)g_free );
     }
+    return pid;
 }
 
 static void load_default_apps( const char* filename )
@@ -190,18 +166,16 @@ static void load_default_apps( const char* filename )
             len = strlen ( buf );
             if( buf[ len - 1 ] == '\n' ) /* remove the '\n' at the end of line */
             {
-                buf[ len ] = '\0';
                 --len;
+                buf[ len ] = '\0';
             }
             switch(buf[0])
             {
             case '@': /* if the app should be restarted on crash */
-                run_guarded_app( buf + 1 );
-                break;
-            case '#': /* skip comments */
+                run_app( buf + 1, TRUE );
                 break;
             default: /* just run the program */
-                g_spawn_command_line_async( buf, NULL );
+                run_app( buf, FALSE );
             }
         }
         fclose( file );
@@ -209,7 +183,7 @@ static void load_default_apps( const char* filename )
 }
 
 /*
- * system wide default config is /etc/xdg/lxsession/SESSION_NAME/config
+ * system wide default config is /etc/xdg/lxsession/SESSION_NAME/desktop.conf
  * system wide default apps are listed in /etc/xdg/lxsession/SESSION_NAME/autostart
  */
 void start_session()
@@ -222,7 +196,7 @@ void start_session()
 
     /* run window manager first */
     if( G_LIKELY( window_manager ) )
-        run_guarded_app( window_manager );
+        run_app( window_manager, TRUE );
 
     /* load system-wide default apps */
     for( dir = dirs; *dir; ++dir )
@@ -237,7 +211,7 @@ void start_session()
     g_free( filename );
 
     /* Support autostart spec of freedesktop.org */
-    handle_autostart( session_name );
+    xdg_autostart( session_name );
 }
 
 static void parse_options(int argc, char** argv)
diff --git a/lxsession/xdg-autostart.c b/lxsession/xdg-autostart.c
new file mode 100644 (file)
index 0000000..01513a6
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ *      autostart.c - Handle autostart spec of freedesktop.org
+ *
+ *      Copyright 2008 PCMan <pcman.tw@gmail.com>
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *      MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "xdg-autostart.h"
+
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+
+static const char DesktopEntry[] = "Desktop Entry";
+extern const char* de_name; /* defined in lxsession.c */
+
+#if 0
+/*
+* Parse Exec command line of app desktop file, and translate
+* it into a real command which can be passed to g_spawn_command_line_async().
+* file_list is a null-terminated file list containing full
+* paths of the files passed to app.
+* returned char* should be freed when no longer needed.
+*/
+static char* translate_app_exec_to_command_line( VFSAppDesktop* app,
+                                                 GList* file_list )
+{
+    const char* pexec = vfs_app_desktop_get_exec( app );
+    char* file;
+    GList* l;
+    gchar *tmp;
+    GString* cmd = g_string_new("");
+    gboolean add_files = FALSE;
+
+    for( ; *pexec; ++pexec )
+    {
+        if( *pexec == '%' )
+        {
+            ++pexec;
+            switch( *pexec )
+            {
+            case 'U':
+                for( l = file_list; l; l = l->next )
+                {
+                    tmp = g_filename_to_uri( (char*)l->data, NULL, NULL );
+                    file = g_shell_quote( tmp );
+                    g_free( tmp );
+                    g_string_append( cmd, file );
+                    g_string_append_c( cmd, ' ' );
+                    g_free( file );
+                }
+                add_files = TRUE;
+                break;
+            case 'u':
+                if( file_list && file_list->data )
+                {
+                    file = (char*)file_list->data;
+                    tmp = g_filename_to_uri( file, NULL, NULL );
+                    file = g_shell_quote( tmp );
+                    g_free( tmp );
+                    g_string_append( cmd, file );
+                    g_free( file );
+                    add_files = TRUE;
+                }
+                break;
+            case 'F':
+            case 'N':
+                for( l = file_list; l; l = l->next )
+                {
+                    file = (char*)l->data;
+                    tmp = g_shell_quote( file );
+                    g_string_append( cmd, tmp );
+                    g_string_append_c( cmd, ' ' );
+                    g_free( tmp );
+                }
+                add_files = TRUE;
+                break;
+            case 'f':
+            case 'n':
+                if( file_list && file_list->data )
+                {
+                    file = (char*)file_list->data;
+                    tmp = g_shell_quote( file );
+                    g_string_append( cmd, tmp );
+                    g_free( tmp );
+                    add_files = TRUE;
+                }
+                break;
+            case 'D':
+                for( l = file_list; l; l = l->next )
+                {
+                    tmp = g_path_get_dirname( (char*)l->data );
+                    file = g_shell_quote( tmp );
+                    g_free( tmp );
+                    g_string_append( cmd, file );
+                    g_string_append_c( cmd, ' ' );
+                    g_free( file );
+                }
+                add_files = TRUE;
+                break;
+            case 'd':
+                if( file_list && file_list->data )
+                {
+                    tmp = g_path_get_dirname( (char*)file_list->data );
+                    file = g_shell_quote( tmp );
+                    g_free( tmp );
+                    g_string_append( cmd, file );
+                    g_free( tmp );
+                    add_files = TRUE;
+                }
+                break;
+            case 'c':
+                g_string_append( cmd, vfs_app_desktop_get_disp_name( app ) );
+                break;
+            case 'i':
+                /* Add icon name */
+                if( vfs_app_desktop_get_icon_name( app ) )
+                {
+                    g_string_append( cmd, "--icon " );
+                    g_string_append( cmd, vfs_app_desktop_get_icon_name( app ) );
+                }
+                break;
+            case 'k':
+                /* Location of the desktop file */
+                break;
+            case 'v':
+                /* Device name */
+                break;
+            case '%':
+                g_string_append_c ( cmd, '%' );
+                break;
+            case '\0':
+                goto _finish;
+                break;
+            }
+        }
+        else  /* not % escaped part */
+        {
+            g_string_append_c ( cmd, *pexec );
+        }
+    }
+_finish:
+    if( ! add_files )
+    {
+        g_string_append_c ( cmd, ' ' );
+        for( l = file_list; l; l = l->next )
+        {
+            file = (char*)l->data;
+            tmp = g_shell_quote( file );
+            g_string_append( cmd, tmp );
+            g_string_append_c( cmd, ' ' );
+            g_free( tmp );
+        }
+    }
+
+    return g_string_free( cmd, FALSE );
+}
+#endif
+
+static void launch_autostart_file( const char* desktop_id, const char* desktop_file, GKeyFile* kf )
+{
+    if( g_key_file_load_from_file( kf, desktop_file, 0, NULL ) )
+    {
+        char* exec;
+        char** only_show_in, **not_show_in;
+        gsize n;
+
+        if( g_key_file_get_boolean( kf, DesktopEntry, "Hidden", NULL ) )
+            return;
+
+        /* check if this desktop entry is desktop-specific */
+        only_show_in = g_key_file_get_string_list( kf, DesktopEntry, "OnlyShowIn", &n, NULL );
+        if( only_show_in )
+        {
+            /* The format of this list is like:  OnlyShowIn=GNOME;XFCE */
+            int i = 0;
+            for( i = 0; i < n; ++i )
+            {
+                /* Only start this program if we are in the "OnlyShowIn" list */
+                if( 0 == strcmp( de_name, only_show_in[ i ] ) )
+                    break;
+            }
+            if( i >= n )    /* our session name is not found in the list */
+            {
+                g_strfreev( only_show_in );
+                return;   /* read next desktop file */
+            }
+            g_strfreev( only_show_in );
+        }
+               else /* OnlyShowIn and NotShowIn cannot be set at the same time. */
+               {
+                       /* check if this desktop entry is not allowed in our session */
+                       not_show_in = g_key_file_get_string_list( kf, DesktopEntry, "NotShowIn", &n, NULL );
+                       if( not_show_in )
+                       {
+                               /* The format of this list is like:  NotShowIn=KDE;IceWM */
+                               int i = 0;
+                               for( i = 0; i < n; ++i )
+                               {
+                                       /* Only start this program if we are in the "OnlyShowIn" list */
+                                       if( 0 == strcmp( de_name, not_show_in[ i ] ) )
+                                               break;
+                               }
+                               if( i < n )    /* our session name is found in the "NotShowIn" list */
+                               {
+                                       g_strfreev( not_show_in );
+                                       return;   /* read next desktop file */
+                               }
+                               g_strfreev( not_show_in );
+                       }
+               }
+
+        exec = g_key_file_get_string( kf, DesktopEntry, "TryExec", NULL );
+        if( G_UNLIKELY(exec) ) /* If we are asked to tryexec first */
+        {
+            if( ! g_path_is_absolute( exec ) )
+            {
+                char* full = g_find_program_in_path( exec );
+                g_free( exec );
+                exec = full;
+            }
+            /* If we cannot match the TryExec key with an installed executable program */
+            if( ! g_file_test( exec, G_FILE_TEST_IS_EXECUTABLE ) )
+            {
+                g_free( exec );
+                return;   /* bypass this desktop file, and read next */
+            }
+            g_free( exec );
+        }
+
+        /* get the real command line */
+        exec = g_key_file_get_string( kf, DesktopEntry, "Exec", NULL );
+        if( G_LIKELY(exec) )
+        {
+            /* according to the spec, the Exec command line should be translated
+             *  with some rules, but that's normally for file managers who needs to
+             *  pass selected file as arguments. The probability we need this is
+             *  very low, so just omit it.
+             */
+
+                       /* FIXME: Exec key should be handled correctly */
+
+            /* launch the program */
+            if( g_spawn_command_line_async( exec, NULL ) )
+            {
+            }
+        }
+    }
+}
+
+static void get_autostart_files_in_dir( GHashTable* hash, const char* de_name, const char* base_dir )
+{
+    char* dir_path = g_build_filename( base_dir, "autostart", NULL );
+    GDir* dir = g_dir_open( dir_path, 0, NULL );
+
+    if( dir )
+    {
+        char *path;
+        const char *name;
+
+        while( (name = g_dir_read_name( dir )) && g_str_has_suffix( name, ".desktop" ) )
+        {
+            path = g_build_filename( dir_path, name, NULL );
+            g_hash_table_replace( hash, g_strdup(name), path );
+        }
+        g_dir_close( dir );
+    }
+    g_free( dir_path );
+}
+
+void xdg_autostart( const char* de_name )
+{
+    const char* const *dirs = g_get_system_config_dirs();
+    const char* const *dir;
+    GHashTable* hash = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, g_free );
+
+    /* get system-wide autostart files */
+    for( dir = dirs; *dir; ++dir )
+        get_autostart_files_in_dir( hash, de_name, *dir );
+
+    /* get user-specific autostart files */
+    get_autostart_files_in_dir( hash, de_name, g_get_user_config_dir() );
+
+    if( g_hash_table_size( hash ) > 0 )
+    {
+        GKeyFile* kf = g_key_file_new();
+        g_hash_table_foreach( hash, (GHFunc)launch_autostart_file, kf );
+        g_key_file_free( kf );
+    }
+
+    g_hash_table_destroy( hash );
+}
diff --git a/lxsession/xdg-autostart.h b/lxsession/xdg-autostart.h
new file mode 100644 (file)
index 0000000..c1c3287
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ *      autostart.h - Handle autostart spec of freedesktop.org
+ *
+ *      Copyright 2008 PCMan <pcman.tw@gmail.com>
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *      MA 02110-1301, USA.
+ */
+
+#ifndef _XDG_AUTOSTART_H_
+#define _XDG_AUTOSTART_H_
+
+void xdg_autostart( const char* session_name );
+
+#endif