Move new lxsession with built-in settings daemon to trunk.
authorHong Jen Yee (PCMan) <pcman.tw@gmail.com>
Sat, 11 Jul 2009 14:26:55 +0000 (14:26 +0000)
committerHong Jen Yee (PCMan) <pcman.tw@gmail.com>
Sat, 11 Jul 2009 14:26:55 +0000 (14:26 +0000)
23 files changed:
AUTHORS
Makefile.am
README
desktop.conf.example [new file with mode: 0644]
images/gnome-session-halt.png [deleted file]
images/gnome-session-logout.png [deleted file]
images/system-log-out.png [new file with mode: 0644]
images/system-shutdown.png [new file with mode: 0644]
lxsession-logout/main.c
lxsession/Makefile.am
lxsession/autostart.c
lxsession/lxsession.c
lxsession/lxsession.h [new file with mode: 0644]
lxsession/settings-daemon.c [new file with mode: 0644]
lxsession/settings-daemon.h [new file with mode: 0644]
lxsession/xevent.c [new file with mode: 0644]
lxsession/xevent.h [new file with mode: 0644]
lxsession/xsettings-common.c [new file with mode: 0644]
lxsession/xsettings-common.h [new file with mode: 0644]
lxsession/xsettings-manager.c [new file with mode: 0644]
lxsession/xsettings-manager.h [new file with mode: 0644]
lxsession/xutils.c [new file with mode: 0644]
lxsession/xutils.h [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
index 4abea3f..3d93edd 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -12,3 +12,6 @@ Copyright (C) 2001 Queen of England
 HAL support of lxsession-logout is taken from xfce4-session.
 Copyright (c) 2003-2006 Benedikt Meurer <benny@xfce.org>
 
+The XSettings-related parts of lxde-settings-daemon use MIT licensed 
+source code from gnome-settings-daemon:
+Copyright (C) 2001 Owen Taylor, Matthias Clasen, Red Hat, Inc.
index e7cc2a8..6e86875 100644 (file)
@@ -1,14 +1,17 @@
+NULL=
+
 SUBDIRS=lxsession lxsession-logout po man
 
 imagedir=$(datadir)/lxsession/images
 image_DATA= \
-       images/gnome-session-halt.png \
+       images/system-shutdown.png \
+       images/system-log-out.png \
        images/gnome-session-hibernate.png \
-       images/gnome-session-logout.png \
        images/gnome-session-reboot.png \
        images/gnome-session-suspend.png \
        images/gnome-session-switch.png
 
 EXTRA_DIST = \
-       autogen.sh \
+       desktop.conf.example \
        $(image_DATA)
+       $(NULL)
diff --git a/README b/README
index 53686aa..dad2a35 100644 (file)
--- a/README
+++ b/README
@@ -1,13 +1,13 @@
-LXSession is the default X11 session manager of LXDE.
+LXSession is the default session manager of LXDE.
 (LXDE: Lightweight X11 Desktop Environment)
 http://lxde.org/
 
-LXSession Lite is the stripped down version without
-the problematic X11 Session Management support.
-
 What's LXSession and who needs this?
 A session manager is used to automatically start a set of applications and
 set up a working desktop environment.
+Besides, LXSession has a built-in lightweight Xsettings daemon, which can 
+configure gtk+ themes, keyboard, and mouse for you on session startup.
+In gnome the Xsettings part is provided by gnome-settings-daemon.
 
 Gnome is bundled with its own gnome-session, KDE brings its own session
 manager, too. XFCE and ROX desktop also have their own session managers,
@@ -62,11 +62,9 @@ NOTE: Restart of gdm might be needed. ( On Debian:  sudo /etc/init.d/gdm restart
 So, what programs will be executed when LXSession starts?
 The window manager, of course, should be the most important one.
 It should be specified in this file:
-/etc/xdg/lxsession/<Name of Your Desktop>/config
-The file is a plain ini file, like this:
-[Session]
-window_manager=openbox
-Just replace 'openbox' with the window manager you like.
+/etc/xdg/lxsession/<Name of Your Desktop>/desktop.conf
+The file is a plain ini file, like the desktop.conf.example
+bundled in this package.
 
 Then, list the other programs you want to execute in this file:
 /etc/xdg/lxsession/<Name of Your Desktop>/autostart
diff --git a/desktop.conf.example b/desktop.conf.example
new file mode 100644 (file)
index 0000000..7e040ff
--- /dev/null
@@ -0,0 +1,37 @@
+[Session]
+window_manager=openbox-lxde
+
+[GTK]
+#iNet/DoubleClickTime=400
+#iNet/DoubleClickDistance
+#iNet/DndDragThreshold
+#iNet/CursorBlink
+#iNet/CursorBlinkTime
+sNet/ThemeName=Clearlooks
+sNet/IconThemeName=nuoveXT2
+sGtk/FontName=Sans 10
+#iGtk/IconSizes
+#sGtk/KeyThemeName
+iGtk/ToolbarStyle=3
+#iGtk/ToolbarIconSize
+#iGtk/IMPreeditStyle
+#iGtk/IMStatusStyle
+iGtk/ButtonImages=1
+iGtk/MenuImages=1
+#sGtk/CursorThemeName=
+iGtk/CursorThemeSize=18
+iXft/Antialias=1
+#iXft/Hinting
+#iXft/HintStyle
+#iXft/RGBA
+#iXft/DPI
+#iGtk/TouchscreenMode
+
+[Mouse]
+AccFactor=20
+AccThreshold=10
+LeftHanded=0
+
+[Keyboard]
+Delay=500
+Interval=30
diff --git a/images/gnome-session-halt.png b/images/gnome-session-halt.png
deleted file mode 100644 (file)
index 865934b..0000000
Binary files a/images/gnome-session-halt.png and /dev/null differ
diff --git a/images/gnome-session-logout.png b/images/gnome-session-logout.png
deleted file mode 100644 (file)
index f8bd027..0000000
Binary files a/images/gnome-session-logout.png and /dev/null differ
diff --git a/images/system-log-out.png b/images/system-log-out.png
new file mode 100644 (file)
index 0000000..f8bd027
Binary files /dev/null and b/images/system-log-out.png differ
diff --git a/images/system-shutdown.png b/images/system-shutdown.png
new file mode 100644 (file)
index 0000000..865934b
Binary files /dev/null and b/images/system-shutdown.png differ
index 8874d4d..4f052ac 100644 (file)
@@ -439,7 +439,7 @@ int main( int argc, char** argv )
 
     if( available_actions & LOGOUT_ACTION_SHUTDOWN )
     {
-        btn = create_dlg_btn(_("Sh_utdown"), "gnome-session-halt", LOGOUT_ACTION_SHUTDOWN );
+        btn = create_dlg_btn(_("Sh_utdown"), "system-shutdown", LOGOUT_ACTION_SHUTDOWN );
         gtk_box_pack_start( GTK_BOX(vbox), btn, FALSE, FALSE, 4 );
     }
     if( available_actions & LOGOUT_ACTION_REBOOT )
@@ -467,7 +467,7 @@ int main( int argc, char** argv )
         gtk_box_pack_start( GTK_BOX(vbox), btn, FALSE, FALSE, 4 );
     }
 
-    btn = create_dlg_btn(_("_Logout"), "gnome-session-logout", GTK_RESPONSE_OK );
+    btn = create_dlg_btn(_("_Logout"), "system-log-out", GTK_RESPONSE_OK );
     gtk_box_pack_start( GTK_BOX(vbox), btn, FALSE, FALSE, 4 );
 
     gtk_window_set_position( GTK_WINDOW(dlg), GTK_WIN_POS_CENTER_ALWAYS );
index c3e96ca..1ec29d4 100644 (file)
@@ -1,11 +1,28 @@
-bin_PROGRAMS=lxsession
+NULL=
+
+bin_PROGRAMS = lxsession
 
 lxsession_CFLAGS = $(GLIB_CFLAGS) \
-                   -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\"
+                               -DPACKAGE_DATA_DIR=\""$(datadir)/lxde"\" \
+                               -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
+                               -Werror-implicit-function-declaration
+                               $(NULL)
 
-lxsession_LDADD = $(GLIB_LIBS)
+lxsession_LDADD = $(GLIB_LIBS) -lX11
 
 lxsession_SOURCES = \
-    lxsession.c \
-    autostart.c \
-    autostart.h
+       lxsession.c \
+       lxsession.h \
+       autostart.c \
+       autostart.h \
+       xevent.c \
+       xevent.h \
+       settings-daemon.c \
+       settings-daemon.h \
+       xsettings-common.h \
+       xsettings-common.c \
+       xsettings-manager.h \
+       xsettings-manager.c \
+       xutils.h \
+       xutils.c \
+       $(NULL)
index bddb1d6..4b353df 100644 (file)
@@ -199,26 +199,28 @@ static void launch_autostart_file( const char* desktop_id, const char* desktop_f
             }
             g_strfreev( only_show_in );
         }
-
-        /* 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( session_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 );
-        }
+               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( session_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 */
@@ -247,6 +249,8 @@ static void launch_autostart_file( const char* desktop_id, const char* desktop_f
              *  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 ) )
index 1816645..278494f 100644 (file)
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <string.h>
+#include <stdlib.h>
 
+#include "lxsession.h"
+#include "xevent.h"
+#include "settings-daemon.h"
 #include "autostart.h"
 
-typedef struct _ChildWatch
-{
-    GPid pid;
-    gboolean exited;
-    int status;
-    char* cmd;
-}ChildWatch;
-
-#define child_watch_free( cw ) \
-    { \
-        g_free( cw->cmd ); \
-        g_free( cw ); \
-    }
+
+static gboolean no_settings = FALSE; /* disable settings daemon */
+static gboolean reload_settings = FALSE; /* reload settings daemon */
 
 static GMainLoop* main_loop = NULL;
 static const char *display_name = NULL;
-static char* window_manager = NULL;
+char* window_manager = NULL; /* will be accessed by settings-daemon.c */
 
 /* name of environment variables */
 static char sm_env[] = "SESSION_MANAGER";
@@ -63,19 +57,19 @@ static char autostart_filename[]="autostart";
 
 const char *session_name = NULL;
 
-static GSList* child_watches = NULL;
-static int wakeup_pipe[ 2 ];
+
+static GPid run_app( const char* cmd );
+static void run_guarded_app( const char* cmd );
+static void start_session();
 
 static void sig_term_handler ( int sig )
 {
-    /* g_main_loop_quit(main_loop); */
-    close( wakeup_pipe[0] );
+    g_main_loop_quit(main_loop);
 }
 
-static void sig_child_handler( int sig )
+void lxsession_quit()
 {
-    /* notify the main loop that a child process exits */
-    write( wakeup_pipe[1], "X", 1 );
+    g_main_loop_quit(main_loop);
 }
 
 static void register_signals()
@@ -83,35 +77,53 @@ static void register_signals()
     /* Ignore SIGPIPE */
     signal( SIGPIPE, SIG_IGN );
 
-    /* If child process dies, call our handler */
-    signal( SIGCHLD, sig_child_handler );
-
 #if 0
-  action.sa_handler = g_child_watch_signal_handler;
-  sigemptyset (&action.sa_mask);
-  action.sa_flags = SA_RESTART | SA_NOCLDSTOP;
-  sigaction (SIGCHLD, &action, NULL);
+    action.sa_handler = g_child_watch_signal_handler;
+    sigemptyset (&action.sa_mask);
+    action.sa_flags = SA_RESTART | SA_NOCLDSTOP;
+    sigaction (SIGCHLD, &action, NULL);
 #endif
 
     /* If we get a SIGTERM, do logout */
     signal( SIGTERM, sig_term_handler );
 }
 
-static void load_config( GKeyFile* kf, const char* filename )
+GKeyFile* load_session_config( const char* config_filename )
 {
-    if( g_key_file_load_from_file( kf, filename, 0, NULL ) )
-    {
-        char* str;
-        if( str = g_key_file_get_string( kf, "Session", "window_manager", NULL ) )
-        {
-            g_free( window_manager );
-            window_manager = str;
-        }
-    }
+    const gchar* const *dirs = g_get_system_config_dirs();
+    const gchar* const *dir;
+    GKeyFile* kf = g_key_file_new();
+    char* filename;
+       gboolean ret;
+
+    /* load user-specific session config */
+    filename = g_build_filename( g_get_user_config_dir(), prog_name, session_name, config_filename, NULL );
+    ret = g_key_file_load_from_file(kf, filename, 0, NULL);
+    g_free( filename );
+
+       if( ! ret ) /* user specific file is not found */
+       {
+               /* load system-wide session config files */
+               for( dir = dirs; *dir; ++dir )
+               {
+                       filename = g_build_filename( *dir, prog_name, session_name, config_filename, NULL );
+                       ret = g_key_file_load_from_file(kf, filename, 0, NULL);
+                       g_free( filename );
+                       if(ret)
+                               break;
+               }
+       }
+
+       if( G_UNLIKELY(!ret) )
+       {
+               g_key_file_free(kf);
+               return NULL;
+       }
+       return kf;
 }
 
 /* Returns pid if succesful, returns -1 if errors happen. */
-static GPid run_app( const char* cmd )
+GPid run_app( const char* cmd )
 {
     char** argv;
     int argc;
@@ -129,46 +141,24 @@ static GPid run_app( const char* cmd )
     return pid;
 }
 
-static void on_child_exit( ChildWatch* cw )
+static void on_child_exit( GPid pid, gint status, gchar* cmd )
 {
-    int sig = WTERMSIG( cw->status );
+    int sig = WTERMSIG( status );
     /* if the term signal is not SIGTERM or SIGKILL, this might be a crash! */
     if( sig && sig != SIGTERM && sig != SIGKILL )
     {
-        GPid pid = run_app( cw->cmd );
-        if( pid < 0 )   /* error, remove the watch */
-        {
-            child_watches = g_slist_remove( child_watches, cw );
-            child_watch_free( cw );
-        }
-        else
-        {
-            cw->pid = pid;
-            cw->exited = FALSE;
-            cw->status = 0;            
-        }
+        run_guarded_app( cmd );
     }
 }
 
-static void add_child_watch( GPid pid, const char* cmd )
-{
-    ChildWatch* cw = g_new0( ChildWatch, 1 );
-    cw->pid = pid;
-    cw->cmd = g_strdup( cmd );
-    child_watches = g_slist_prepend( child_watches, cw );
-}
-
-static void run_guarded_app( const char* cmd )
+void run_guarded_app( const char* cmd )
 {
     GPid pid = run_app( cmd );
     if( pid > 0 )
     {
-        add_child_watch( pid, cmd );
-        /*
         g_child_watch_add_full( G_PRIORITY_DEFAULT_IDLE, pid,
-                                            (GChildWatchFunc)on_child_exit,
-                                            g_strdup( cmd ), (GDestroyNotify)g_free );
-        */
+                                (GChildWatchFunc)on_child_exit,
+                                g_strdup( cmd ), (GDestroyNotify)g_free );
     }
 }
 
@@ -202,7 +192,7 @@ static void load_default_apps( const char* filename )
  * system wide default config is /etc/xdg/lxsession/SESSION_NAME/config
  * system wide default apps are listed in /etc/xdg/lxsession/SESSION_NAME/autostart
  */
-static void start_session()
+void start_session()
 {
     FILE *file = NULL;
     const gchar* const *dirs = g_get_system_config_dirs();
@@ -210,20 +200,6 @@ static void start_session()
     GKeyFile* kf = g_key_file_new();
     char* filename;
 
-    /* load system-wide session config files */
-    for( dir = dirs; *dir; ++dir )
-    {
-        filename = g_build_filename( *dir, prog_name, session_name, config_filename, NULL );
-        load_config( kf, filename );
-        g_free( filename );
-    }
-    /* load user-specific session config */
-    filename = g_build_filename( g_get_user_config_dir(), prog_name, session_name, config_filename, NULL );
-    load_config( kf, filename );
-    g_free( filename );
-
-    g_key_file_free( kf );
-
     /* run window manager first */
     if( G_LIKELY( window_manager ) )
         run_guarded_app( window_manager );
@@ -244,39 +220,9 @@ static void start_session()
     handle_autostart( session_name );
 }
 
-static void dispatch_child_watches()
-{
-    GSList* l;
-    ChildWatch* cw;
-    int status;
-
-    for( l = child_watches; l; l = l->next )
-    {
-        cw = (ChildWatch*)l->data;
-        if (waitpid (cw->pid, &status, WNOHANG) > 0)
-        {
-            cw->status = status;
-            cw->exited = TRUE;
-            on_child_exit( cw );
-        }
-    }
-}
-
-int main(int argc, char** argv)
+static void parse_options(int argc, char** argv)
 {
-    const char *pid_str;
-    char str[ 16 ];
     int  i;
-
-    pid_str = g_getenv(pid_env);
-
-    display_name = g_getenv( display_env );
-    if( ! display_name )
-    {
-        display_name = ":0";
-        g_setenv( display_env, display_name, TRUE );
-    }
-
     for ( i = 1; i < argc; ++i )
     {
         if ( argv[i][0] == '-' )
@@ -288,75 +234,104 @@ int main(int argc, char** argv)
                 display_name = argv[i];
                 g_setenv( display_env, display_name, TRUE );
                 continue;
-
             case 's':     /* -session */
                 if ( ++i >= argc ) goto usage;
                 session_name = argv[i];
                 continue;
-
-            case 'e':
-                if( 0 == strcmp( argv[i]+1, "exit" ) )
-                {
-                    if( pid_str ) /* _LXSESSION_PID has been set */
-                    {
-                        GPid pid = atoi( pid_str );
-                        kill( pid, SIGTERM );
-                        return 0;
-                    }
-                    else
-                    {
-                        g_print( "Error: LXSession is not running.\n" );
-                        return 1;
-                    }
-                }
+            case 'n': /* disable xsettings daemon */
+                               no_settings = TRUE;
+                continue;
+            case 'r':
+                if( 0 == strcmp( argv[i]+1, "reload" ) )
+                    reload_settings = TRUE;
             }
         }
-
 usage:
         fprintf ( stderr,
-                  "Usage: lxsession [-display display] [-session session_name] [-exit]\n" );
-        return 1;
+                  "Usage:  lxsession [OPTIONS...]\n"
+                                 "\t-d name\tspecify name of display (optional)\n"
+                                 "\t-s name\tspecify name of the desktop session\n"
+                                 "\t-r\t reload configurations (for Xsettings daemon)\n"
+                                 "\t-n\t disable Xsettings daemon support\n" );
+        exit(1);
     }
+}
+
+int main(int argc, char** argv)
+{
+    const char *pid_str;
+    char str[ 16 ];
+       GKeyFile* kf;
+
+    pid_str = g_getenv(pid_env);
 
-    if( G_UNLIKELY( pid_str ) ) /* _LXSESSION_PID has been set */
+    display_name = g_getenv( display_env );
+    if( ! display_name )
     {
-        g_error("LXSession is already running\n");
-        return 1;
+        display_name = ":0";
+        g_setenv( display_env, display_name, TRUE );
     }
 
-    if( pipe( wakeup_pipe ) < 0 )
-        return 1;
+    parse_options(argc, argv);
 
-    /*
-     *  NOTE:
-     *  g_main_loop has some weird problems when child watch is the only event source.
-     *  It seems that in this situation glib does busy loop. (Not yet fully confirmed.)
-     *  To prevent this, I handle this myself with pipe and don't use main loop provided by glib.
-     */
-    /* main_loop = g_main_loop_new( NULL, TRUE ); */
+    /* initialize X-related stuff and connect to X Display */
+    if( G_UNLIKELY(! xevent_init() ) )
+        return 1;
 
+    /* send command to existing daemon to reload settings */
+    if( G_UNLIKELY( reload_settings ) )
+    {
+        send_internal_command( LXS_RELOAD );
+        return 0;
+    }
+       else if( G_UNLIKELY( !single_instance_check()) )
+       {
+               /* only one instance is allowed for each X. */
+               g_error( "Only one lxsession can be executed at a time." );
+               return 1;
+       }
+
+    /* set pid */
     g_snprintf( str, 16, "%d", getpid() );
     g_setenv(pid_env, str, TRUE );
 
+    main_loop = g_main_loop_new( NULL, TRUE );
+
+       /* setup signal handlers */
     register_signals();
 
-    if ( !session_name )
+    if ( G_UNLIKELY(!session_name) )
         session_name = "LXDE";
 
     g_setenv( "DESKTOP_SESSION", session_name, TRUE );
 
+    /* FIXME: setup locales: LC_ALL, LANG, LANGUAGE?
+        * Is this needed? */
+
+    /* FIXME: load environment variables? */
+
+       /* Load desktop session config file */
+       kf = load_session_config(CONFIG_FILE_NAME);
+       if( !kf )
+       {
+               xevent_finalize();
+               return 1;
+       }
+
+       window_manager = g_key_file_get_string( kf, "Session", "window_manager", NULL );
+
+    if( G_LIKELY(!no_settings) )
+        start_settings_daemon(kf);
+
+       g_key_file_free(kf);
+
+    /* start desktop session and load autostart applications */
     start_session();
 
-    /*
     g_main_loop_run( main_loop );
     g_main_loop_unref( main_loop );
-     */
-
-    while( read( wakeup_pipe[0], str, 16 ) > 0 )
-        dispatch_child_watches();
 
-    /* close( wakeup_pipe[0] ); */
-    close( wakeup_pipe[1] );
+       xevent_finalize();
 
     return 0;
 }
diff --git a/lxsession/lxsession.h b/lxsession/lxsession.h
new file mode 100644 (file)
index 0000000..5ecf960
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ *      lxsession.h
+ *      
+ *      Copyright 2009 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 __LXSESSION_H__
+#define __LXSESSION_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define CONFIG_FILE_NAME       "desktop.conf"
+
+GKeyFile* load_session_config( const char* config_filename );
+void lxsession_quit();
+
+G_END_DECLS
+
+#endif
diff --git a/lxsession/settings-daemon.c b/lxsession/settings-daemon.c
new file mode 100644 (file)
index 0000000..4541d23
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ *      lxde-settings.c - XSettings daemon of LXDE
+ *
+ *      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 <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <locale.h>
+
+#include "lxsession.h"
+#include "xevent.h"
+#include "xsettings-manager.h"
+#include "xutils.h"
+
+#include <X11/XKBlib.h>
+
+static XSettingsManager **managers = NULL;
+
+static void terminate_cb (void *data)
+{
+       gboolean *terminated = data;
+
+       if (*terminated)
+               return;
+
+       *terminated = TRUE;
+       exit( 0 );
+//     gtk_main_quit ();
+}
+
+static void merge_xrdb(const char* content, int len)
+{
+    char* argv[] = { "xrdb", "-merge", "-", NULL };
+    GPid pid;
+    int stdi, status;
+    if( g_spawn_async_with_pipes(NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
+                        NULL, NULL, &pid, &stdi, NULL, NULL, NULL ) )
+    {
+        write( stdi, content, len < 0 ? strlen(content) : len );
+        close(stdi);
+        waitpid( pid, &status, 0 );
+    }
+}
+
+
+/* This function is taken from Gnome's control-center 2.6.0.3 (gnome-settings-mouse.c) and was modified*/
+#define DEFAULT_PTR_MAP_SIZE 128
+static void set_left_handed_mouse( gboolean mouse_left_handed )
+{
+    unsigned char *buttons;
+    gint n_buttons, i;
+    gint idx_1 = 0, idx_3 = 1;
+
+    buttons = g_alloca (DEFAULT_PTR_MAP_SIZE);
+    n_buttons = XGetPointerMapping (dpy, buttons, DEFAULT_PTR_MAP_SIZE);
+    if (n_buttons > DEFAULT_PTR_MAP_SIZE)
+    {
+        buttons = g_alloca (n_buttons);
+        n_buttons = XGetPointerMapping (dpy, buttons, n_buttons);
+    }
+
+    for (i = 0; i < n_buttons; i++)
+    {
+        if (buttons[i] == 1)
+            idx_1 = i;
+        else if (buttons[i] == ((n_buttons < 3) ? 2 : 3))
+            idx_3 = i;
+    }
+
+    if ((mouse_left_handed && idx_1 < idx_3) ||
+        (!mouse_left_handed && idx_1 > idx_3))
+    {
+        buttons[idx_1] = ((n_buttons < 3) ? 2 : 3);
+        buttons[idx_3] = 1;
+        XSetPointerMapping (dpy, buttons, n_buttons);
+    }
+}
+
+static void configure_input(GKeyFile* kf)
+{
+    XKeyboardControl values;
+
+    /* Mouse settings */
+    int accel_factor, accel_threshold, delay, interval;
+    gboolean left_handed, beep;
+
+    accel_factor = g_key_file_get_integer(kf, "Mouse", "AccFactor", NULL);
+    accel_threshold = g_key_file_get_integer(kf, "Mouse", "AccThreshold", NULL);
+    if( accel_factor || accel_threshold )
+    {
+        XChangePointerControl(dpy, accel_factor != 0, accel_threshold != 0,
+                                 accel_factor, 10, accel_threshold);
+    }
+
+    left_handed = g_key_file_get_integer(kf, "Mouse", "LeftHanded", NULL);
+    set_left_handed_mouse(left_handed);
+
+    /* Keyboard settings */
+    if(XkbGetAutoRepeatRate(dpy, XkbUseCoreKbd, &delay, &interval))
+    {
+        int val;
+        val = g_key_file_get_integer(kf, "Keyboard", "Delay", NULL);
+        if(val > 0)
+            delay = val;
+        val = g_key_file_get_integer(kf, "Keyboard", "Interval", NULL);
+        if(val > 0)
+            interval = val;
+        if( val > 0 )
+        {
+            XkbSetAutoRepeatRate(dpy, XkbUseCoreKbd, delay, interval);
+        }
+    }
+
+    beep = g_key_file_get_integer(kf, "Keyboard", "Beep", NULL);
+    values.bell_percent = beep ? -1 : 0;
+    XChangeKeyboardControl(dpy, KBBellPercent, &values);
+}
+
+static void load_settings( GKeyFile* kf )
+{
+       gboolean ret;
+       char* file;
+    GString* buf;
+    char* str;
+    int val;
+
+       int i;
+       const char group[] = "GTK";
+       char** keys, **key;
+
+       /* Mouse cursor (does this work?) */
+       str = g_key_file_get_string( kf, group, "sGtk/CursorThemeName", NULL);
+       val = g_key_file_get_integer(kf, group, "iGtk/CursorThemeSize", NULL);
+       if(str || val > 0)
+       {
+               buf = g_string_sized_new(100);
+               if(str)
+               {
+                       if(*str)
+                               g_string_append_printf(buf, "Xcursor.theme:%s\n", str);
+                       g_free(str);
+               }
+               g_string_append(buf, "Xcursor.theme_core:true\n");
+               if(val > 0)
+                       g_string_append_printf(buf, "Xcursor.size:%d\n", val);
+               merge_xrdb( buf->str, buf->len );
+               g_string_free(buf, TRUE);
+       }
+
+       /* Load mouse and keyboard settings */
+       configure_input(kf);
+
+       /* Load GTK+ settings */
+       keys = g_key_file_get_keys( kf, group, NULL, NULL );
+       for( key = keys; *key; ++key )
+       {
+               const char* name = *key + 1;
+
+               switch( **key )
+               {
+                       case 's':       /* string */
+                       {
+                               str = g_key_file_get_string( kf, group, *key, NULL );
+                               if( str )
+                               {
+                                       for( i = 0; managers[i]; ++i )
+                                               xsettings_manager_set_string( managers [i], name, str );
+                                       g_free( str );
+                               }
+                               else
+                               {
+                                       for( i = 0; managers[i]; ++i )
+                                               xsettings_manager_delete_setting( managers[i], name );
+                               }
+                               break;
+                       }
+                       case 'i':       /* integer */
+                       {
+                               val = g_key_file_get_integer( kf, group, *key, NULL );
+                               for( i = 0; managers[i]; ++i )
+                                       xsettings_manager_set_int( managers [i], name, val );
+                               break;
+                       }
+                       case 'c':       /* color */
+                       {
+                               gsize len = 0;
+                               int* vals = g_key_file_get_integer_list( kf, group, *key, &len, NULL );
+                               if( vals && len >= 3 )
+                               {
+                                       XSettingsColor color;
+                                       color.red = (gushort)vals[0];
+                                       color.green = (gushort)vals[1];
+                                       color.blue = (gushort)vals[2];
+                                       color.alpha = (gushort)( len >3 ? vals[3] : 65535 );
+                                       for( i = 0; managers[i]; ++i )
+                                               xsettings_manager_set_color( managers [i], name, &color );
+                               }
+                               else
+                               {
+                                       for( i = 0; managers[i]; ++i )
+                                               xsettings_manager_delete_setting( managers[i], name );
+                               }
+                               g_free( vals );
+                               break;
+                       }
+               }
+       }
+
+       for( i = 0; managers[i]; ++i )
+               xsettings_manager_notify( managers [i] );
+}
+
+static gboolean create_xsettings_managers()
+{
+       int n_screens = ScreenCount(dpy);
+       int i;
+       gboolean terminated = FALSE;
+
+       if (xsettings_manager_check_running( dpy, n_screens) )
+       {
+               g_error ("You can only run one xsettings manager at a time; exiting\n");
+               return FALSE;
+       }
+
+       managers = g_new (XSettingsManager *, n_screens + 1);
+       for( i = 0; i < n_screens; ++i )
+       {
+               Screen *screen;
+               screen = ScreenOfDisplay( dpy, i );
+               managers [i] = xsettings_manager_new ( dpy, i, terminate_cb, &terminated);
+               if(!managers [i])
+               {
+                       g_error("Could not create xsettings manager for screen %d!\n", i);
+                       return FALSE;
+               }
+               XSelectInput( dpy, RootWindow(dpy, i), SubstructureNotifyMask | PropertyChangeMask );
+       }
+       managers [i] = NULL;
+
+       return TRUE;
+}
+
+gboolean start_settings_daemon(GKeyFile* kf)
+{
+       if( ! create_xsettings_managers() )
+               return FALSE;
+
+       load_settings(kf);
+
+       /* sync with X11 to prevent some racing conditions:
+        * For example: if gtk+ applications are started before
+        * XSETTINGS properties are properly set on root window,
+        * they cannot correctly use settings from Xsettings daemon. */
+       XSync(dpy, FALSE);
+
+       return TRUE;
+}
+
+void settings_manager_selection_clear( XEvent* evt )
+{
+       XSettingsManager**mgr;
+       for( mgr = managers; *mgr; ++mgr )
+       {
+               if( xsettings_manager_get_window( *mgr ) == evt->xany.window )
+                       xsettings_manager_process_event( *mgr, evt );
+       }
+}
+
+void settings_deamon_reload()
+{
+       GKeyFile* kf = load_session_config(CONFIG_FILE_NAME);
+       if(kf)
+       {
+               load_settings(kf);
+       }
+}
diff --git a/lxsession/settings-daemon.h b/lxsession/settings-daemon.h
new file mode 100644 (file)
index 0000000..1607bae
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ *      settings-daemon.h - LXDE settings daemon
+ *
+ *      Copyright 2009 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 __SETTINGS_DAEMON_H__
+#define __SETTINGS_DAEMON_H__
+
+#include <glib.h>
+#include <X11/Xlib.h>
+
+gboolean start_settings_daemon(GKeyFile* kf);
+
+void settings_deamon_reload();
+
+/* called by x11_event_dispatch() */
+void settings_manager_selection_clear( XEvent* evt );
+
+#endif
diff --git a/lxsession/xevent.c b/lxsession/xevent.c
new file mode 100644 (file)
index 0000000..27e4b68
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ *      xevent.c
+ *      
+ *      Copyright 2009 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 "xevent.h"
+
+#include <string.h>
+
+#include <X11/X.h>
+#include <X11/Xproto.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+#include "lxsession.h"
+#include "settings-daemon.h"
+
+Display* dpy = NULL;
+
+static Atom CMD_ATOM; /* for private client message */
+static GSource* source = NULL; /* main loop event source for X11 events */
+
+typedef struct _X11Source
+{
+       GSource source;
+       GPollFD poll_fd;
+}X11Source;
+
+static gboolean x11_event_prepare(GSource *source, gint *timeout);
+static gboolean x11_event_check(GSource *source);
+static gboolean x11_event_dispatch(GSource *source, GSourceFunc  callback, gpointer user_data);
+
+static GSourceFuncs event_funcs = 
+{
+       x11_event_prepare,
+       x11_event_check,
+       x11_event_dispatch,
+       NULL
+};
+
+void send_internal_command( int cmd )
+{
+       Window root = DefaultRootWindow(dpy);
+    XEvent ev;
+
+       memset(&ev, 0, sizeof(ev) );
+       ev.xclient.type = ClientMessage;
+       ev.xclient.window = root;
+       ev.xclient.message_type = CMD_ATOM;
+       ev.xclient.format = 8;
+
+       ev.xclient.data.l[0] = cmd;
+
+       XSendEvent(dpy, root, False,
+                          SubstructureRedirectMask|SubstructureNotifyMask, &ev);
+       XSync(dpy, False);
+}
+
+gboolean xevent_init()
+{
+       X11Source* xsource;
+       int fd;
+
+       dpy = XOpenDisplay( g_getenv("DISPLAY") );
+       if( ! dpy )
+               return FALSE;
+
+       /* according to the spec, private Atoms should prefix their names with _. */
+       CMD_ATOM = XInternAtom( dpy, "_LXSESSION", False );
+
+       fd = ConnectionNumber(dpy); /* fd of XDisplay connection */
+       if( G_UNLIKELY(fd == -1) )
+               return FALSE;
+
+       /* set up main loop event source for XDisplay */
+       source = g_source_new (&event_funcs, sizeof(X11Source));
+       xsource = (X11Source*)source;
+       xsource->poll_fd.fd = fd;
+       xsource->poll_fd.events = G_IO_IN;
+
+       g_source_add_poll(source, &xsource->poll_fd);
+       g_source_set_can_recurse(source, TRUE);
+       g_source_attach(source, NULL);
+
+       return TRUE;
+}
+
+gboolean single_instance_check()
+{
+       /* NOTE: this is a hack to do single instance */
+       XGrabServer( dpy );
+       if( XGetSelectionOwner( dpy, CMD_ATOM ) )
+       {
+               XUngrabServer( dpy );
+               XCloseDisplay( dpy );
+               return FALSE;
+       }
+       XSetSelectionOwner( dpy, CMD_ATOM, DefaultRootWindow( dpy ), CurrentTime );
+       XUngrabServer( dpy );
+       return TRUE;
+}
+
+gboolean x11_event_prepare(GSource *source, gint *timeout)
+{
+       *timeout = -1;
+       return XPending(dpy) ? TRUE : FALSE;
+}
+
+gboolean x11_event_check(GSource *source)
+{
+       X11Source *xsource = (X11Source*)source;
+       if(xsource->poll_fd.revents & G_IO_IN)
+               return XPending(dpy) ? TRUE : FALSE;
+       return FALSE;
+}
+
+gboolean x11_event_dispatch(GSource *source, GSourceFunc  callback, gpointer user_data)
+{
+       while( XPending(dpy) )
+       {
+               XEvent evt;
+               XNextEvent( dpy, &evt );
+               if( evt.type == ClientMessage )
+               {
+                       if(evt.xproperty.atom == CMD_ATOM)
+                       {
+                               int cmd = evt.xclient.data.b[0];
+                               switch( cmd )
+                               {
+                               case LXS_RELOAD:        /* reload all settings */
+                                       settings_deamon_reload();
+                                       break;
+                               case LXS_EXIT:
+                                       lxsession_quit();
+                                       break;
+                               }
+                       }
+               }
+               else if( evt.type ==  SelectionClear )
+               {
+                       settings_manager_selection_clear( &evt );
+               }
+       }
+       return TRUE;
+}
+
+void xevent_finalize()
+{
+       if(source)
+       {
+               g_source_destroy(source);
+               g_source_unref(source);
+       }
+
+       XGrabServer( dpy );
+       XSetSelectionOwner( dpy, CMD_ATOM, DefaultRootWindow( dpy ), None );
+       XUngrabServer( dpy );
+
+       XCloseDisplay( dpy );
+}
+
diff --git a/lxsession/xevent.h b/lxsession/xevent.h
new file mode 100644 (file)
index 0000000..46283f6
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ *      xevent.h
+ *      
+ *      Copyright 2009 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 __XEVENT_H__
+#define __XEVENT_H__
+
+#include <glib.h>
+#include <X11/Xlib.h>
+
+G_BEGIN_DECLS
+
+extern Display* dpy;
+
+typedef enum{
+       LXS_RELOAD,
+       LXS_EXIT,
+       LXS_LAST_CMD
+}LXS_CMD;
+
+gboolean xevent_init();
+gboolean single_instance_check();
+void xevent_finalize();
+
+void send_internal_command( int cmd );
+
+G_END_DECLS
+
+#endif
diff --git a/lxsession/xsettings-common.c b/lxsession/xsettings-common.c
new file mode 100644 (file)
index 0000000..992175a
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Copyright © 2001 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  Red Hat makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author:  Owen Taylor, Red Hat, Inc.
+ */
+#include "string.h"
+#include "stdlib.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xmd.h>           /* For CARD32 */
+
+#include "xsettings-common.h"
+
+XSettingsSetting *
+xsettings_setting_copy (XSettingsSetting *setting)
+{
+  XSettingsSetting *result;
+  size_t str_len;
+  
+  result = malloc (sizeof *result);
+  if (!result)
+    return NULL;
+
+  str_len = strlen (setting->name);
+  result->name = malloc (str_len + 1);
+  if (!result->name)
+    goto err;
+
+  memcpy (result->name, setting->name, str_len + 1);
+
+  result->type = setting->type;
+
+  switch (setting->type)
+    {
+    case XSETTINGS_TYPE_INT:
+      result->data.v_int = setting->data.v_int;
+      break;
+    case XSETTINGS_TYPE_COLOR:
+      result->data.v_color = setting->data.v_color;
+      break;
+    case XSETTINGS_TYPE_STRING:
+      str_len = strlen (setting->data.v_string);
+      result->data.v_string = malloc (str_len + 1);
+      if (!result->data.v_string)
+       goto err;
+
+      memcpy (result->data.v_string, setting->data.v_string, str_len + 1);
+      break;
+    }
+
+  result->last_change_serial = setting->last_change_serial;
+
+  return result;
+
+ err:
+  if (result->name)
+    free (result->name);
+  free (result);
+  
+  return NULL;
+}
+
+XSettingsList *
+xsettings_list_copy (XSettingsList *list)
+{
+  XSettingsList *new = NULL;
+  XSettingsList *old_iter = list;
+  XSettingsList *new_iter = NULL;
+
+  while (old_iter)
+    {
+      XSettingsList *new_node;
+
+      new_node = malloc (sizeof *new_node);
+      if (!new_node)
+       goto error;
+
+      new_node->setting = xsettings_setting_copy (old_iter->setting);
+      if (!new_node->setting)
+       {
+         free (new_node);
+         goto error;
+       }
+
+      if (new_iter)
+       new_iter->next = new_node;
+      else
+       new = new_node;
+
+      new_iter = new_node;
+      
+      old_iter = old_iter->next;
+    }
+
+  return new;
+
+ error:
+  xsettings_list_free (new);
+  return NULL;
+}
+
+int
+xsettings_setting_equal (XSettingsSetting *setting_a,
+                        XSettingsSetting *setting_b)
+{
+  if (setting_a->type != setting_b->type)
+    return 0;
+
+  if (strcmp (setting_a->name, setting_b->name) != 0)
+    return 0;
+
+  switch (setting_a->type)
+    {
+    case XSETTINGS_TYPE_INT:
+      return setting_a->data.v_int == setting_b->data.v_int;
+    case XSETTINGS_TYPE_COLOR:
+      return (setting_a->data.v_color.red == setting_b->data.v_color.red &&
+             setting_a->data.v_color.green == setting_b->data.v_color.green &&
+             setting_a->data.v_color.blue == setting_b->data.v_color.blue &&
+             setting_a->data.v_color.alpha == setting_b->data.v_color.alpha);
+    case XSETTINGS_TYPE_STRING:
+      return strcmp (setting_a->data.v_string, setting_b->data.v_string) == 0;
+    }
+
+  return 0;
+}
+
+void
+xsettings_setting_free (XSettingsSetting *setting)
+{
+  if (setting->type == XSETTINGS_TYPE_STRING)
+    free (setting->data.v_string);
+  
+  if (setting->name)
+    free (setting->name);
+
+  free (setting);
+}
+
+void
+xsettings_list_free (XSettingsList *list)
+{
+  while (list)
+    {
+      XSettingsList *next = list->next;
+
+      xsettings_setting_free (list->setting);
+      free (list);
+
+      list = next;
+    }
+}
+
+XSettingsResult
+xsettings_list_insert (XSettingsList    **list,
+                      XSettingsSetting  *setting)
+{
+  XSettingsList *node;
+  XSettingsList *iter;
+  XSettingsList *last = NULL;
+
+  node = malloc (sizeof *node);
+  if (!node)
+    return XSETTINGS_NO_MEM;
+  node->setting = setting;
+
+  iter = *list;
+  while (iter)
+    {
+      int cmp = strcmp (setting->name, iter->setting->name);
+
+      if (cmp < 0)
+       break;
+      else if (cmp == 0)
+       {
+         free (node);
+         return XSETTINGS_DUPLICATE_ENTRY;
+       }
+
+      last = iter;
+      iter = iter->next;
+    }
+  
+  if (last)
+    last->next = node;
+  else
+    *list = node;
+  
+  node->next = iter;
+  
+  return XSETTINGS_SUCCESS;
+}
+
+XSettingsResult
+xsettings_list_delete (XSettingsList **list,
+                      const char     *name)
+{
+  XSettingsList *iter;
+  XSettingsList *last = NULL;
+
+  iter = *list;
+  while (iter)
+    {
+      if (strcmp (name, iter->setting->name) == 0)
+       {
+         if (last)
+           last->next = iter->next;
+         else
+           *list = iter->next;
+  
+         xsettings_setting_free (iter->setting);
+         free (iter);
+
+         return XSETTINGS_SUCCESS;
+       }
+
+      last = iter;
+      iter = iter->next;
+    }
+
+  return XSETTINGS_FAILED;
+}
+
+XSettingsSetting *
+xsettings_list_lookup (XSettingsList *list,
+                      const char    *name)
+{
+  XSettingsList *iter;
+
+  iter = list;
+  while (iter)
+    {
+      if (strcmp (name, iter->setting->name) == 0)
+       return iter->setting;
+
+      iter = iter->next;
+    }
+
+  return NULL;
+}
+
+char
+xsettings_byte_order (void)
+{
+  CARD32 myint = 0x01020304;
+  return (*(char *)&myint == 1) ? MSBFirst : LSBFirst;
+}
diff --git a/lxsession/xsettings-common.h b/lxsession/xsettings-common.h
new file mode 100644 (file)
index 0000000..e3af4a6
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright © 2001 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  Red Hat makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author:  Owen Taylor, Red Hat, Inc.
+ */
+#ifndef XSETTINGS_COMMON_H
+#define XSETTINGS_COMMON_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct _XSettingsBuffer  XSettingsBuffer;
+typedef struct _XSettingsColor   XSettingsColor;
+typedef struct _XSettingsList    XSettingsList;
+typedef struct _XSettingsSetting XSettingsSetting;
+
+/* Types of settings possible. Enum values correspond to
+ * protocol values.
+ */
+typedef enum 
+{
+  XSETTINGS_TYPE_INT     = 0,
+  XSETTINGS_TYPE_STRING  = 1,
+  XSETTINGS_TYPE_COLOR   = 2
+} XSettingsType;
+
+typedef enum
+{
+  XSETTINGS_SUCCESS,
+  XSETTINGS_NO_MEM,
+  XSETTINGS_ACCESS,
+  XSETTINGS_FAILED,
+  XSETTINGS_NO_ENTRY,
+  XSETTINGS_DUPLICATE_ENTRY
+} XSettingsResult;
+
+struct _XSettingsBuffer
+{
+  char byte_order;
+  size_t len;
+  unsigned char *data;
+  unsigned char *pos;
+};
+
+struct _XSettingsColor
+{
+  unsigned short red, green, blue, alpha;
+};
+
+struct _XSettingsList
+{
+  XSettingsSetting *setting;
+  XSettingsList *next;
+};
+
+struct _XSettingsSetting
+{
+  char *name;
+  XSettingsType type;
+  
+  union {
+    int v_int;
+    char *v_string;
+    XSettingsColor v_color;
+  } data;
+
+  unsigned long last_change_serial;
+};
+
+XSettingsSetting *xsettings_setting_copy  (XSettingsSetting *setting);
+void              xsettings_setting_free  (XSettingsSetting *setting);
+int               xsettings_setting_equal (XSettingsSetting *setting_a,
+                                          XSettingsSetting *setting_b);
+
+void              xsettings_list_free   (XSettingsList     *list);
+XSettingsList    *xsettings_list_copy   (XSettingsList     *list);
+XSettingsResult   xsettings_list_insert (XSettingsList    **list,
+                                        XSettingsSetting  *setting);
+XSettingsSetting *xsettings_list_lookup (XSettingsList     *list,
+                                        const char        *name);
+XSettingsResult   xsettings_list_delete (XSettingsList    **list,
+                                        const char        *name);
+
+char xsettings_byte_order (void);
+
+#define XSETTINGS_PAD(n,m) ((n + m - 1) & (~(m-1)))
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* XSETTINGS_COMMON_H */
diff --git a/lxsession/xsettings-manager.c b/lxsession/xsettings-manager.c
new file mode 100644 (file)
index 0000000..6578ce1
--- /dev/null
@@ -0,0 +1,424 @@
+/*
+ * Copyright © 2001 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  Red Hat makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author:  Owen Taylor, Red Hat, Inc.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <X11/Xmd.h>           /* For CARD16 */
+
+#include "xsettings-manager.h"
+
+struct _XSettingsManager
+{
+  Display *display;
+  int screen;
+
+  Window window;
+  Atom manager_atom;
+  Atom selection_atom;
+  Atom xsettings_atom;
+
+  XSettingsTerminateFunc terminate;
+  void *cb_data;
+
+  XSettingsList *settings;
+  unsigned long serial;
+};
+
+static XSettingsList *settings;
+
+typedef struct 
+{
+  Window window;
+  Atom timestamp_prop_atom;
+} TimeStampInfo;
+
+static Bool
+timestamp_predicate (Display *display,
+                    XEvent  *xevent,
+                    XPointer arg)
+{
+  TimeStampInfo *info = (TimeStampInfo *)arg;
+
+  if (xevent->type == PropertyNotify &&
+      xevent->xproperty.window == info->window &&
+      xevent->xproperty.atom == info->timestamp_prop_atom)
+    return True;
+
+  return False;
+}
+
+/**
+ * get_server_time:
+ * @display: display from which to get the time
+ * @window: a #Window, used for communication with the server.
+ *          The window must have PropertyChangeMask in its
+ *          events mask or a hang will result.
+ * 
+ * Routine to get the current X server time stamp. 
+ * 
+ * Return value: the time stamp.
+ **/
+static Time
+get_server_time (Display *display,
+                Window   window)
+{
+  unsigned char c = 'a';
+  XEvent xevent;
+  TimeStampInfo info;
+
+  info.timestamp_prop_atom = XInternAtom  (display, "_TIMESTAMP_PROP", False);
+  info.window = window;
+
+  XChangeProperty (display, window,
+                  info.timestamp_prop_atom, info.timestamp_prop_atom,
+                  8, PropModeReplace, &c, 1);
+
+  XIfEvent (display, &xevent,
+           timestamp_predicate, (XPointer)&info);
+
+  return xevent.xproperty.time;
+}
+
+Bool
+xsettings_manager_check_running (Display *display,
+                                int      screen)
+{
+  char buffer[256];
+  Atom selection_atom;
+  
+  sprintf(buffer, "_XSETTINGS_S%d", screen);
+  selection_atom = XInternAtom (display, buffer, False);
+
+  if (XGetSelectionOwner (display, selection_atom))
+    return True;
+  else
+    return False;
+}
+
+XSettingsManager *
+xsettings_manager_new (Display                *display,
+                      int                     screen,
+                      XSettingsTerminateFunc  terminate,
+                      void                   *cb_data)
+{
+  XSettingsManager *manager;
+  Time timestamp;
+  XClientMessageEvent xev;
+
+  char buffer[256];
+  
+  manager = malloc (sizeof *manager);
+  if (!manager)
+    return NULL;
+
+  manager->display = display;
+  manager->screen = screen;
+
+  sprintf(buffer, "_XSETTINGS_S%d", screen);
+  manager->selection_atom = XInternAtom (display, buffer, False);
+  manager->xsettings_atom = XInternAtom (display, "_XSETTINGS_SETTINGS", False);
+  manager->manager_atom = XInternAtom (display, "MANAGER", False);
+
+  manager->terminate = terminate;
+  manager->cb_data = cb_data;
+
+  manager->settings = NULL;
+  manager->serial = 0;
+
+  manager->window = XCreateSimpleWindow (display,
+                                        RootWindow (display, screen),
+                                        0, 0, 10, 10, 0,
+                                        WhitePixel (display, screen),
+                                        WhitePixel (display, screen));
+
+  XSelectInput (display, manager->window, PropertyChangeMask);
+  timestamp = get_server_time (display, manager->window);
+
+  XSetSelectionOwner (display, manager->selection_atom,
+                     manager->window, timestamp);
+
+  /* Check to see if we managed to claim the selection. If not,
+   * we treat it as if we got it then immediately lost it
+   */
+
+  if (XGetSelectionOwner (display, manager->selection_atom) ==
+      manager->window)
+    {
+      xev.type = ClientMessage;
+      xev.window = RootWindow (display, screen);
+      xev.message_type = manager->manager_atom;
+      xev.format = 32;
+      xev.data.l[0] = timestamp;
+      xev.data.l[1] = manager->selection_atom;
+      xev.data.l[2] = manager->window;
+      xev.data.l[3] = 0;       /* manager specific data */
+      xev.data.l[4] = 0;       /* manager specific data */
+      
+      XSendEvent (display, RootWindow (display, screen),
+                 False, StructureNotifyMask, (XEvent *)&xev);
+    }
+  else
+    {
+      manager->terminate (manager->cb_data);
+    }
+  
+  return manager;
+}
+
+void
+xsettings_manager_destroy (XSettingsManager *manager)
+{
+  XDestroyWindow (manager->display, manager->window);
+  
+  xsettings_list_free (manager->settings);
+  free (manager);
+}
+
+Window
+xsettings_manager_get_window (XSettingsManager *manager)
+{
+  return manager->window;
+}
+
+Bool
+xsettings_manager_process_event (XSettingsManager *manager,
+                                XEvent           *xev)
+{
+  if (xev->xany.window == manager->window &&
+      xev->xany.type == SelectionClear &&
+      xev->xselectionclear.selection == manager->selection_atom)
+    {
+      manager->terminate (manager->cb_data);
+      return True;
+    }
+
+  return False;
+}
+
+XSettingsResult
+xsettings_manager_delete_setting (XSettingsManager *manager,
+                                  const char       *name)
+{
+  return xsettings_list_delete (&settings, name);
+}
+
+XSettingsResult
+xsettings_manager_set_setting (XSettingsManager *manager,
+                              XSettingsSetting *setting)
+{
+  XSettingsSetting *old_setting = xsettings_list_lookup (settings, setting->name);
+  XSettingsSetting *new_setting;
+  XSettingsResult result;
+
+  if (old_setting)
+    {
+      if (xsettings_setting_equal (old_setting, setting))
+       return XSETTINGS_SUCCESS;
+
+      xsettings_list_delete (&settings, setting->name);
+    }
+
+  new_setting = xsettings_setting_copy (setting);
+  if (!new_setting)
+    return XSETTINGS_NO_MEM;
+  
+  new_setting->last_change_serial = manager->serial;
+  
+  result = xsettings_list_insert (&settings, new_setting);
+  
+  if (result != XSETTINGS_SUCCESS)
+    xsettings_setting_free (new_setting);
+
+  return result;
+}
+
+XSettingsResult
+xsettings_manager_set_int (XSettingsManager *manager,
+                          const char       *name,
+                          int               value)
+{
+  XSettingsSetting setting;
+
+  setting.name = (char *)name;
+  setting.type = XSETTINGS_TYPE_INT;
+  setting.data.v_int = value;
+
+  return xsettings_manager_set_setting (manager, &setting);
+}
+
+XSettingsResult
+xsettings_manager_set_string (XSettingsManager *manager,
+                             const char       *name,
+                             const char       *value)
+{
+  XSettingsSetting setting;
+
+  setting.name = (char *)name;
+  setting.type = XSETTINGS_TYPE_STRING;
+  setting.data.v_string = (char *)value;
+
+  return xsettings_manager_set_setting (manager, &setting);
+}
+
+XSettingsResult
+xsettings_manager_set_color (XSettingsManager *manager,
+                            const char       *name,
+                            XSettingsColor   *value)
+{
+  XSettingsSetting setting;
+
+  setting.name = (char *)name;
+  setting.type = XSETTINGS_TYPE_COLOR;
+  setting.data.v_color = *value;
+
+  return xsettings_manager_set_setting (manager, &setting);
+}
+
+static size_t
+setting_length (XSettingsSetting *setting)
+{
+  size_t length = 8;   /* type + pad + name-len + last-change-serial */
+  length += XSETTINGS_PAD (strlen (setting->name), 4);
+
+  switch (setting->type)
+    {
+    case XSETTINGS_TYPE_INT:
+      length += 4;
+      break;
+    case XSETTINGS_TYPE_STRING:
+      length += 4 + XSETTINGS_PAD (strlen (setting->data.v_string), 4);
+      break;
+    case XSETTINGS_TYPE_COLOR:
+      length += 8;
+      break;
+    }
+
+  return length;
+}
+
+static void
+setting_store (XSettingsSetting *setting,
+              XSettingsBuffer *buffer)
+{
+  size_t string_len;
+  size_t length;
+
+  *(buffer->pos++) = setting->type;
+  *(buffer->pos++) = 0;
+
+  string_len = strlen (setting->name);
+  *(CARD16 *)(buffer->pos) = string_len;
+  buffer->pos += 2;
+
+  length = XSETTINGS_PAD (string_len, 4);
+  memcpy (buffer->pos, setting->name, string_len);
+  length -= string_len;
+  buffer->pos += string_len;
+  
+  while (length > 0)
+    {
+      *(buffer->pos++) = 0;
+      length--;
+    }
+
+  *(CARD32 *)(buffer->pos) = setting->last_change_serial;
+  buffer->pos += 4;
+
+  switch (setting->type)
+    {
+    case XSETTINGS_TYPE_INT:
+      *(CARD32 *)(buffer->pos) = setting->data.v_int;
+      buffer->pos += 4;
+      break;
+    case XSETTINGS_TYPE_STRING:
+      string_len = strlen (setting->data.v_string);
+      *(CARD32 *)(buffer->pos) = string_len;
+      buffer->pos += 4;
+      
+      length = XSETTINGS_PAD (string_len, 4);
+      memcpy (buffer->pos, setting->data.v_string, string_len);
+      length -= string_len;
+      buffer->pos += string_len;
+      
+      while (length > 0)
+       {
+         *(buffer->pos++) = 0;
+         length--;
+       }
+      break;
+    case XSETTINGS_TYPE_COLOR:
+      *(CARD16 *)(buffer->pos) = setting->data.v_color.red;
+      *(CARD16 *)(buffer->pos + 2) = setting->data.v_color.green;
+      *(CARD16 *)(buffer->pos + 4) = setting->data.v_color.blue;
+      *(CARD16 *)(buffer->pos + 6) = setting->data.v_color.alpha;
+      buffer->pos += 8;
+      break;
+    }
+}
+
+XSettingsResult
+xsettings_manager_notify (XSettingsManager *manager)
+{
+  XSettingsBuffer buffer;
+  XSettingsList *iter;
+  int n_settings = 0;
+
+  buffer.len = 12;             /* byte-order + pad + SERIAL + N_SETTINGS */
+
+  iter = settings;
+  while (iter)
+    {
+      buffer.len += setting_length (iter->setting);
+      n_settings++;
+      iter = iter->next;
+    }
+
+  buffer.data = buffer.pos = malloc (buffer.len);
+  if (!buffer.data)
+    return XSETTINGS_NO_MEM;
+
+  *buffer.pos = xsettings_byte_order ();
+
+  buffer.pos += 4;
+  *(CARD32 *)buffer.pos = manager->serial++;
+  buffer.pos += 4;
+  *(CARD32 *)buffer.pos = n_settings;
+  buffer.pos += 4;
+
+  iter = settings;
+  while (iter)
+    {
+      setting_store (iter->setting, &buffer);
+      iter = iter->next;
+    }
+
+  XChangeProperty (manager->display, manager->window,
+                  manager->xsettings_atom, manager->xsettings_atom,
+                  8, PropModeReplace, buffer.data, buffer.len);
+
+  free (buffer.data);
+
+  return XSETTINGS_SUCCESS;
+}
+
diff --git a/lxsession/xsettings-manager.h b/lxsession/xsettings-manager.h
new file mode 100644 (file)
index 0000000..f309768
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright © 2001 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  Red Hat makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author:  Owen Taylor, Red Hat, Inc.
+ */
+#ifndef XSETTINGS_MANAGER_H
+#define XSETTINGS_MANAGER_H
+
+#include <X11/Xlib.h>
+#include "xsettings-common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct _XSettingsManager XSettingsManager;
+
+typedef void (*XSettingsTerminateFunc)  (void *cb_data);
+
+Bool xsettings_manager_check_running (Display *display,
+                                     int      screen);
+
+XSettingsManager *xsettings_manager_new (Display                *display,
+                                        int                     screen,
+                                        XSettingsTerminateFunc  terminate,
+                                        void                   *cb_data);
+
+void   xsettings_manager_destroy       (XSettingsManager *manager);
+Window xsettings_manager_get_window    (XSettingsManager *manager);
+Bool   xsettings_manager_process_event (XSettingsManager *manager,
+                                       XEvent           *xev);
+
+XSettingsResult xsettings_manager_delete_setting (XSettingsManager *manager,
+                                                  const char       *name);
+XSettingsResult xsettings_manager_set_setting    (XSettingsManager *manager,
+                                                  XSettingsSetting *setting);
+XSettingsResult xsettings_manager_set_int        (XSettingsManager *manager,
+                                                  const char       *name,
+                                                  int               value);
+XSettingsResult xsettings_manager_set_string     (XSettingsManager *manager,
+                                                  const char       *name,
+                                                  const char       *value);
+XSettingsResult xsettings_manager_set_color      (XSettingsManager *manager,
+                                                  const char       *name,
+                                                  XSettingsColor   *value);
+XSettingsResult xsettings_manager_notify         (XSettingsManager *manager);
+
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* XSETTINGS_MANAGER_H */
diff --git a/lxsession/xutils.c b/lxsession/xutils.c
new file mode 100644 (file)
index 0000000..4e48b98
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright © 2004 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  Red Hat makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author:  Matthias Clasen, Red Hat, Inc.
+ */
+
+#include <stdlib.h>
+
+#include "xutils.h"
+
+Atom XA_ATOM_PAIR;
+Atom XA_CLIPBOARD_MANAGER;
+Atom XA_CLIPBOARD;
+Atom XA_DELETE;
+Atom XA_INCR;
+Atom XA_INSERT_PROPERTY;
+Atom XA_INSERT_SELECTION;
+Atom XA_MANAGER;
+Atom XA_MULTIPLE;
+Atom XA_NULL;
+Atom XA_SAVE_TARGETS;
+Atom XA_TARGETS;
+Atom XA_TIMESTAMP;
+
+unsigned long SELECTION_MAX_SIZE = 0;
+
+
+void
+init_atoms (Display *display)
+{
+  unsigned long max_request_size;
+  
+  if (SELECTION_MAX_SIZE > 0)
+    return;
+
+  XA_ATOM_PAIR = XInternAtom (display, "ATOM_PAIR", False);
+  XA_CLIPBOARD_MANAGER = XInternAtom (display, "CLIPBOARD_MANAGER", False);
+  XA_CLIPBOARD = XInternAtom (display, "CLIPBOARD", False);
+  XA_DELETE = XInternAtom (display, "DELETE", False);
+  XA_INCR = XInternAtom (display, "INCR", False);
+  XA_INSERT_PROPERTY = XInternAtom (display, "INSERT_PROPERTY", False);
+  XA_INSERT_SELECTION = XInternAtom (display, "INSERT_SELECTION", False);
+  XA_MANAGER = XInternAtom (display, "MANAGER", False);
+  XA_MULTIPLE = XInternAtom (display, "MULTIPLE", False);
+  XA_NULL = XInternAtom (display, "NULL", False);
+  XA_SAVE_TARGETS = XInternAtom (display, "SAVE_TARGETS", False);
+  XA_TARGETS = XInternAtom (display, "TARGETS", False);
+  XA_TIMESTAMP = XInternAtom (display, "TIMESTAMP", False);
+  
+  max_request_size = XExtendedMaxRequestSize (display);
+  if (max_request_size == 0)
+    max_request_size = XMaxRequestSize (display);
+  
+  SELECTION_MAX_SIZE = max_request_size - 100;
+  if (SELECTION_MAX_SIZE > 262144)
+    SELECTION_MAX_SIZE =  262144;
+}
+
+typedef struct 
+{
+  Window window;
+  Atom timestamp_prop_atom;
+} TimeStampInfo;
+
+static Bool
+timestamp_predicate (Display *display,
+                    XEvent  *xevent,
+                    XPointer arg)
+{
+  TimeStampInfo *info = (TimeStampInfo *)arg;
+
+  if (xevent->type == PropertyNotify &&
+      xevent->xproperty.window == info->window &&
+      xevent->xproperty.atom == info->timestamp_prop_atom)
+    return True;
+
+  return False;
+}
+
+Time
+get_server_time (Display *display,
+                Window   window)
+{
+  unsigned char c = 'a';
+  XEvent xevent;
+  TimeStampInfo info;
+
+  info.timestamp_prop_atom = XInternAtom  (display, "_TIMESTAMP_PROP", False);
+  info.window = window;
+
+  XChangeProperty (display, window,
+                  info.timestamp_prop_atom, info.timestamp_prop_atom,
+                  8, PropModeReplace, &c, 1);
+
+  XIfEvent (display, &xevent,
+           timestamp_predicate, (XPointer)&info);
+
+  return xevent.xproperty.time;
+}
+
diff --git a/lxsession/xutils.h b/lxsession/xutils.h
new file mode 100644 (file)
index 0000000..143fe44
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2004 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  Red Hat makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author:  Matthias Clasen, Red Hat, Inc.
+ */
+#ifndef X_UTILS_H
+#define X_UTILS_H
+
+#include <X11/Xlib.h>
+
+
+extern Atom XA_ATOM_PAIR;
+extern Atom XA_CLIPBOARD_MANAGER;
+extern Atom XA_CLIPBOARD;
+extern Atom XA_DELETE;
+extern Atom XA_INCR;
+extern Atom XA_INSERT_PROPERTY;
+extern Atom XA_INSERT_SELECTION;
+extern Atom XA_MANAGER;
+extern Atom XA_MULTIPLE;
+extern Atom XA_NULL;
+extern Atom XA_SAVE_TARGETS;
+extern Atom XA_TARGETS;
+extern Atom XA_TIMESTAMP;
+
+extern unsigned long SELECTION_MAX_SIZE;
+
+void init_atoms      (Display *display);
+
+Time get_server_time (Display *display,
+                     Window   window);
+
+#endif /* X_UTILS_H */