2007-07-11 20:03:18 +04:00
/*
* $ Id $
*
* Evoke , head honcho of everything
* Part of Equinox Desktop Environment ( EDE ) .
* Copyright ( c ) 2000 - 2007 EDE Authors .
*
* This program is licensed under terms of the
* GNU General Public License version 2 or newer .
* See COPYING for details .
*/
# include "Log.h"
2007-07-31 19:37:12 +04:00
# include "Logout.h"
2007-07-11 20:03:18 +04:00
# include "EvokeService.h"
2007-07-30 17:25:13 +04:00
# include "Splash.h"
# include "Spawn.h"
2007-08-06 16:39:15 +04:00
# include "Crash.h"
2007-08-28 19:54:52 +04:00
# include "Autostart.h"
2007-07-30 17:25:13 +04:00
2007-07-11 20:03:18 +04:00
# include <edelib/File.h>
2007-08-31 17:41:27 +04:00
# include <edelib/Regex.h>
2007-07-11 20:03:18 +04:00
# include <edelib/Config.h>
2007-07-31 19:37:12 +04:00
# include <edelib/DesktopFile.h>
# include <edelib/Directory.h>
2007-07-11 20:03:18 +04:00
# include <edelib/StrUtil.h>
2007-07-30 17:25:13 +04:00
# include <edelib/Util.h>
# include <edelib/Debug.h>
2007-08-28 19:54:52 +04:00
# include <edelib/MessageBox.h>
2007-07-31 19:37:12 +04:00
# include <edelib/Nls.h>
2007-07-30 17:25:13 +04:00
2007-07-11 20:03:18 +04:00
# include <sys/types.h> // getpid
# include <unistd.h> //
# include <stdlib.h> // free
2007-07-31 19:37:12 +04:00
# include <string.h> // strdup, memset
2007-08-07 15:54:57 +04:00
# include <errno.h> // error codes
2007-07-11 20:03:18 +04:00
2007-07-30 17:25:13 +04:00
void resolve_path ( const edelib : : String & imgdir , edelib : : String & img , bool have_imgdir ) {
if ( img . empty ( ) )
return ;
const char * im = img . c_str ( ) ;
if ( ! edelib : : file_exists ( im ) & & have_imgdir ) {
img = edelib : : build_filename ( " / " , imgdir . c_str ( ) , im ) ;
im = img . c_str ( ) ;
if ( ! edelib : : file_exists ( im ) ) {
// no file, send then empty
img . clear ( ) ;
}
}
}
2007-08-28 19:54:52 +04:00
char * get_basename ( const char * path ) {
char * p = strrchr ( path , ' / ' ) ;
if ( p )
return ( p + 1 ) ;
return ( char * ) path ;
}
/*
* ' Remove ' duplicate entries by looking at their basename
* ( aka . filename , but ignoring directory path ) . Item is not actually removed from
* the list ( will mess up list pointers , but this can be resolved ) , but data it points
* to is cleared , which is a sort of marker to caller to skip it . Dumb yes , but very simple .
*
* It will use brute force for lookup and ' removal ' and ( hopfully ) it should not have
* a large impact on startup since , afaik , no one keeps hundreds of files in autostart
* directories ( if keeps them , then that issue is not up to this program : - P ) .
*
* Alternative would be to sort items ( by their basename ) and apply consecutive unique on
* them , but . . . is it worth ?
*/
void basename_unique ( StringList & lst ) {
if ( lst . empty ( ) )
return ;
StringListIter first , last , first1 , last1 ;
first = lst . begin ( ) ;
last = lst . end ( ) ;
if ( first = = last )
return ;
const char * p1 , * p2 ;
for ( ; first ! = last ; + + first ) {
for ( first1 = lst . begin ( ) , last1 = lst . end ( ) ; first1 ! = last1 ; + + first1 ) {
p1 = ( * first ) . c_str ( ) ;
p2 = ( * first1 ) . c_str ( ) ;
if ( first ! = first1 & & strcmp ( get_basename ( p1 ) , get_basename ( p2 ) ) = = 0 )
( * first1 ) . clear ( ) ;
}
}
}
2007-07-30 17:25:13 +04:00
int get_int_property_value ( Atom at ) {
Atom real ;
int format ;
unsigned long n , extra ;
unsigned char * prop ;
int status = XGetWindowProperty ( fl_display , RootWindow ( fl_display , fl_screen ) ,
at , 0L , 0x7fffffff , False , XA_CARDINAL , & real , & format , & n , & extra ,
( unsigned char * * ) & prop ) ;
int ret = - 1 ;
if ( status ! = Success & & ! prop )
return ret ;
ret = int ( * ( long * ) prop ) ;
XFree ( prop ) ;
return ret ;
}
int get_string_property_value ( Atom at , char * txt , int txt_len ) {
XTextProperty names ;
XGetTextProperty ( fl_display , RootWindow ( fl_display , fl_screen ) , & names , at ) ;
if ( ! names . nitems | | ! names . value )
return 0 ;
2007-07-11 20:03:18 +04:00
2007-07-30 17:25:13 +04:00
char * * vnames ;
int nsz = 0 ;
if ( ! XTextPropertyToStringList ( & names , & vnames , & nsz ) ) {
XFree ( names . value ) ;
return 0 ;
}
strncpy ( txt , vnames [ 0 ] , txt_len ) ;
2007-09-03 16:24:01 +04:00
txt [ txt_len ] = 0 ;
2007-07-30 17:25:13 +04:00
XFreeStringList ( vnames ) ;
return 1 ;
}
2007-08-06 16:39:15 +04:00
void service_watcher_cb ( int pid , int signum ) {
EvokeService : : instance ( ) - > service_watcher ( pid , signum ) ;
}
2007-07-30 17:25:13 +04:00
EvokeService : : EvokeService ( ) : is_running ( 0 ) , logfile ( NULL ) , pidfile ( NULL ) , lockfile ( NULL ) {
top_win = NULL ;
2007-07-11 20:03:18 +04:00
}
EvokeService : : ~ EvokeService ( ) {
if ( logfile )
delete logfile ;
2007-07-30 17:25:13 +04:00
if ( lockfile ) {
edelib : : file_remove ( lockfile ) ;
free ( lockfile ) ;
}
2007-07-11 20:03:18 +04:00
if ( pidfile ) {
edelib : : file_remove ( pidfile ) ;
free ( pidfile ) ;
}
2007-08-06 16:39:15 +04:00
processes . clear ( ) ;
2007-07-11 20:03:18 +04:00
}
EvokeService * EvokeService : : instance ( void ) {
static EvokeService es ;
return & es ;
}
bool EvokeService : : setup_logging ( const char * file ) {
if ( ! file )
logfile = new DummyLog ( ) ;
else
logfile = new RealLog ( ) ;
if ( ! logfile - > open ( file ) ) {
delete logfile ;
return false ;
}
return true ;
}
2007-07-30 17:25:13 +04:00
bool EvokeService : : setup_pid ( const char * file , const char * lock ) {
2007-07-11 20:03:18 +04:00
if ( ! file )
return false ;
2007-07-30 17:25:13 +04:00
if ( edelib : : file_exists ( lock ) )
return false ;
FILE * l = fopen ( lock , " w " ) ;
if ( ! l )
2007-07-11 20:03:18 +04:00
return false ;
2007-07-30 17:25:13 +04:00
fprintf ( l , " " ) ;
fclose ( l ) ;
lockfile = strdup ( lock ) ;
2007-07-11 20:03:18 +04:00
FILE * f = fopen ( file , " w " ) ;
if ( ! f )
return false ;
fprintf ( f , " %i " , getpid ( ) ) ;
fclose ( f ) ;
pidfile = strdup ( file ) ;
return true ;
}
2007-07-30 17:25:13 +04:00
bool EvokeService : : init_splash ( const char * config , bool no_splash , bool dry_run ) {
2007-07-11 20:03:18 +04:00
edelib : : Config c ;
if ( ! c . load ( config ) )
return false ;
char buff [ 1024 ] ;
2007-07-30 17:25:13 +04:00
bool have_imgdir = false ;
c . get ( " evoke " , " ImagesDirectory " , buff , sizeof ( buff ) ) ;
// no evoke section
if ( c . error ( ) = = edelib : : CONF_ERR_SECTION )
return false ;
edelib : : String imgdir ;
if ( c . error ( ) = = edelib : : CONF_SUCCESS ) {
imgdir = buff ;
have_imgdir = true ;
}
edelib : : String splashimg ;
if ( c . get ( " evoke " , " Splash " , buff , sizeof ( buff ) ) )
splashimg = buff ;
2007-09-03 16:24:01 +04:00
edelib : : String sound ;
if ( c . get ( " evoke " , " Sound " , buff , sizeof ( buff ) ) )
sound = buff ;
2007-07-30 17:25:13 +04:00
// Startup key must exists
2007-07-11 20:03:18 +04:00
if ( ! c . get ( " evoke " , " Startup " , buff , sizeof ( buff ) ) )
return false ;
2007-07-30 17:25:13 +04:00
StringList vs ;
2007-07-11 20:03:18 +04:00
edelib : : stringtok ( vs , buff , " , " ) ;
// nothing, fine, do nothing
unsigned int sz = vs . size ( ) ;
if ( sz = = 0 )
return true ;
EvokeClient ec ;
const char * key_name ;
2007-07-30 17:25:13 +04:00
for ( StringListIter it = vs . begin ( ) ; it ! = vs . end ( ) ; + + it ) {
key_name = ( * it ) . c_str ( ) ;
2007-07-11 20:03:18 +04:00
edelib : : str_trim ( ( char * ) key_name ) ;
// probably listed but not the same key; also Exec value must exists
if ( ! c . get ( key_name , " Exec " , buff , sizeof ( buff ) ) )
continue ;
else
ec . exec = buff ;
2007-07-30 17:25:13 +04:00
if ( c . get ( key_name , " Description " , buff , sizeof ( buff ) ) )
ec . desc = buff ;
2007-07-11 20:03:18 +04:00
if ( c . get ( key_name , " Icon " , buff , sizeof ( buff ) ) )
ec . icon = buff ;
clients . push_back ( ec ) ;
}
2007-07-30 17:25:13 +04:00
/*
* Now , before data is send to Splash , resolve directories
* since Splash expects that .
*/
resolve_path ( imgdir , splashimg , have_imgdir ) ;
for ( ClientListIter it = clients . begin ( ) ; it ! = clients . end ( ) ; + + it )
resolve_path ( imgdir , ( * it ) . icon , have_imgdir ) ;
Splash sp ( no_splash , dry_run ) ;
sp . set_clients ( & clients ) ;
sp . set_background ( & splashimg ) ;
2007-09-03 16:24:01 +04:00
sp . set_sound ( & sound ) ;
2007-07-30 17:25:13 +04:00
sp . run ( ) ;
2007-07-11 20:03:18 +04:00
return true ;
}
2007-07-31 19:37:12 +04:00
/*
* This is implementation of Autostart Spec ( http : //standards.freedesktop.org/autostart-spec/autostart-spec-0.5.html).
* The Autostart Directories are $ XDG_CONFIG_DIRS / autostart .
* If the same filename is located under multiple Autostart Directories
* only the file under the most important directory should be used .
* Example : If $ XDG_CONFIG_HOME is not set the Autostart Directory in the user ' s home
* directory is ~ / . config / autostart /
* Example : If $ XDG_CONFIG_DIRS is not set the system wide Autostart Directory
* is / etc / xdg / autostart /
* Example : If $ XDG_CONFIG_HOME and $ XDG_CONFIG_DIRS are not set and the two
* files / etc / xdg / autostart / foo . desktop and ~ / . config / autostart / foo . desktop exist
* then only the file ~ / . config / autostart / foo . desktop will be used because ~ / . config / autostart /
* is more important than / etc / xdg / autostart /
* If Hidden key is set true in . desktop file , file MUST be ignored .
* OnlyShowIn and NotShowIn ( list of strings identifying desktop environments ) if ( or if not )
* contains environment name , MUST not be started / not started .
* TryExec is same as for . desktop spec .
*/
void EvokeService : : init_autostart ( void ) {
2007-08-28 19:54:52 +04:00
edelib : : String adir = edelib : : user_config_dir ( ) ;
adir + = " /autostart/ " ;
StringList dfiles , sysdirs ;
StringListIter it , it_end ;
edelib : : dir_list ( adir . c_str ( ) , dfiles , true ) ;
edelib : : system_config_dirs ( sysdirs ) ;
if ( ! sysdirs . empty ( ) ) {
for ( it = sysdirs . begin ( ) , it_end = sysdirs . end ( ) ; it ! = it_end ; + + it ) {
* it + = " /autostart/ " ;
// append content
edelib : : dir_list ( ( * it ) . c_str ( ) , dfiles , true , false , false ) ;
}
}
if ( dfiles . empty ( ) )
return ;
/*
* Remove duplicates where first one seen have priority to be keept .
* This way is required by spec .
*
* Also handle this case ( noted in spec ) :
* if $ XDG_CONFIG_HOME / autostart / foo . desktop and $ XDG_CONFIG_DIRS / autostart / foo . desktop
* exists , but $ XDG_CONFIG_HOME / autostart / foo . desktop have ' Hidden = true ' ,
* $ XDG_CONFIG_DIRS / autostart / foo . autostart is ignored too .
*
* Latter is implied via basename_unique ( ) .
*/
basename_unique ( dfiles ) ;
const char * name ;
char buff [ 1024 ] ;
edelib : : DesktopFile df ;
edelib : : String item_name ;
AstartDialog dlg ( dfiles . size ( ) ) ;
for ( it = dfiles . begin ( ) , it_end = dfiles . end ( ) ; it ! = it_end ; + + it ) {
if ( ( * it ) . empty ( ) )
continue ;
name = ( * it ) . c_str ( ) ;
if ( ! edelib : : str_ends ( name , " .desktop " ) )
continue ;
if ( ! df . load ( name ) ) {
EVOKE_LOG ( " Can't load %s. Skipping... \n " , name ) ;
continue ;
}
// If Hidden key is set true in .desktop file, file MUST be ignored.
if ( df . hidden ( ) )
continue ;
if ( df . name ( buff , sizeof ( buff ) ) )
item_name = buff ;
else
item_name = name ;
if ( df . try_exec ( buff , sizeof ( buff ) ) | | df . exec ( buff , sizeof ( buff ) ) )
dlg . add_item ( item_name , buff ) ;
}
if ( dlg . list_size ( ) > 0 )
dlg . run ( ) ;
2007-07-31 19:37:12 +04:00
}
2007-07-11 20:03:18 +04:00
void EvokeService : : setup_atoms ( Display * d ) {
2007-07-30 17:25:13 +04:00
// with them must be send '1' or property will be ignored (except _EDE_EVOKE_SPAWN)
2007-07-11 20:03:18 +04:00
_ede_shutdown_all = XInternAtom ( d , " _EDE_EVOKE_SHUTDOWN_ALL " , False ) ;
2007-07-30 17:25:13 +04:00
_ede_evoke_quit = XInternAtom ( d , " _EDE_EVOKE_QUIT " , False ) ;
2007-07-11 20:03:18 +04:00
_ede_spawn = XInternAtom ( d , " _EDE_EVOKE_SPAWN " , False ) ;
}
2007-07-31 19:37:12 +04:00
void EvokeService : : quit_x11 ( void ) {
2007-08-28 19:54:52 +04:00
int ret = edelib : : ask ( _ ( " Nice quitting is not implemented yet and this will forcefully kill \n all running applications. Make sure to save what needs to be saved. \n So, would you like to continue ? " ) ) ;
2007-07-31 19:37:12 +04:00
if ( ret )
stop ( ) ;
#if 0
/*
* This code is working , but not as I would like to see .
* It will ( mostly ) call XKillClient ( ) for _every_ window
* ( including i . e . buttons in some app ) , and that is not
* nice way to say good bye . This must be implemented in
* wm since it only knows what is actuall window and what not .
* For now quit_x11 ( ) will simply quit itself , quitting X11
* session ( if it holds it ) , which will in turn forcefully kill
* all windows .
*/
Window dummy , * wins ;
Window root = RootWindow ( fl_display , fl_screen ) ;
unsigned int n ;
if ( ! XQueryTree ( fl_display , root , & dummy , & dummy , & wins , & n ) )
return ;
Atom _wm_protocols = XInternAtom ( fl_display , " WM_PROTOCOLS " , False ) ;
Atom _wm_delete_window = XInternAtom ( fl_display , " WM_DELETE_WINDOW " , False ) ;
Atom * protocols ;
int np ;
XEvent ev ;
bool have_quit = 0 ;
for ( unsigned int i = 0 ; i < n ; i + + ) {
if ( wins [ i ] = = root )
continue ;
have_quit = 0 ;
if ( XGetWMProtocols ( fl_display , wins [ i ] , & protocols , & np ) ) {
for ( int j = 0 ; j < np ; j + + ) {
if ( protocols [ j ] = = _wm_delete_window ) {
have_quit = 1 ;
break ;
}
}
}
if ( have_quit ) {
memset ( & ev , 0 , sizeof ( ev ) ) ;
ev . xclient . type = ClientMessage ;
ev . xclient . window = wins [ i ] ;
ev . xclient . message_type = _wm_protocols ;
ev . xclient . format = 32 ;
ev . xclient . data . l [ 0 ] = ( long ) _wm_delete_window ;
ev . xclient . data . l [ 1 ] = ( long ) fl_event_time ;
XSendEvent ( fl_display , wins [ i ] , False , 0L , & ev ) ;
} else {
XKillClient ( fl_display , wins [ i ] ) ;
}
}
XFree ( ( void * ) wins ) ;
stop ( ) ;
# endif
}
2007-08-06 16:39:15 +04:00
/*
* Monitor starting service and report if staring
* failed . Also if one of runned services crashed
* attach gdb on it pid and run backtrace .
*/
void EvokeService : : service_watcher ( int pid , int signum ) {
2007-08-07 15:54:57 +04:00
printf ( " got %i \n " , signum ) ;
if ( signum = = SPAWN_CHILD_CRASHED ) {
2007-08-06 16:39:15 +04:00
EvokeProcess pc ;
2007-08-07 15:54:57 +04:00
2007-08-06 16:39:15 +04:00
if ( find_and_unregister_process ( pid , pc ) ) {
printf ( " %s crashed with core dump \n " , pc . cmd . c_str ( ) ) ;
CrashDialog cdialog ;
cdialog . set_data ( pc . cmd . c_str ( ) ) ;
cdialog . run ( ) ;
return ;
}
2007-08-07 15:54:57 +04:00
} else if ( signum = = SPAWN_CHILD_KILLED ) {
printf ( " child %i killed \n " , pid ) ;
} else {
printf ( " child %i exited with %i \n " , pid , signum ) ;
2007-08-06 16:39:15 +04:00
}
unregister_process ( pid ) ;
}
2007-08-07 15:54:57 +04:00
/*
* Execute program . It ' s return status
* will be reported via service_watcher ( )
*/
2007-08-31 17:41:27 +04:00
void EvokeService : : run_program ( const char * cmd , bool enable_vars ) {
2007-08-07 15:54:57 +04:00
EASSERT ( cmd ! = NULL ) ;
2007-08-31 17:41:27 +04:00
edelib : : String scmd ( cmd ) ;
2007-08-07 15:54:57 +04:00
pid_t child ;
2007-08-31 17:41:27 +04:00
if ( enable_vars & & scmd . length ( ) > 6 ) {
if ( scmd . substr ( 0 , 6 ) = = " $TERM " ) {
char * term = getenv ( " TERM " ) ;
if ( ! term )
term = " xterm " ;
edelib : : String tmp ( term ) ;
tmp + = " -e " ;
tmp + = scmd . substr ( 6 , scmd . length ( ) ) ;
scmd = tmp ;
}
}
int r = spawn_program_with_core ( scmd . c_str ( ) , service_watcher_cb , & child ) ;
2007-08-07 15:54:57 +04:00
if ( r ! = 0 )
2007-08-28 19:54:52 +04:00
edelib : : alert ( " Unable to start %s. Got code %i " , cmd , r ) ;
2007-08-07 15:54:57 +04:00
else
2007-08-31 17:41:27 +04:00
register_process ( scmd . c_str ( ) , child ) ;
}
2007-09-03 16:24:01 +04:00
#if 0
2007-08-31 17:41:27 +04:00
void EvokeService : : heuristic_run_program ( const char * cmd ) {
if ( strncmp ( cmd , " $TERM " , 6 ) = = 0 ) {
run_program ( cmd ) ;
return ;
}
edelib : : String ldd = edelib : : file_path ( " ldd " ) ;
if ( ldd . empty ( ) ) {
run_program ( cmd ) ;
return ;
}
ldd + = " " ;
ldd + = edelib : : file_path ( cmd ) ;
int r = spawn_program ( ldd . c_str ( ) , 0 , 0 , " /tmp/eshrun " ) ;
printf ( " %s \n " , ldd . c_str ( ) ) ;
if ( r ! = 0 ) {
printf ( " spawn %i \n " , r ) ;
return ;
}
sleep ( 1 ) ;
//edelib::File f;
FILE * f = fopen ( " /tmp/eshrun " , " r " ) ;
if ( ! f ) {
puts ( " File::open " ) ;
return ;
} else {
puts ( " opened /tmp/eshrun " ) ;
}
edelib : : Regex rx ;
rx . compile ( " ^ \\ s*libX11 " ) ;
char buff [ 1024 ] ;
bool is_gui = 0 ;
while ( fgets ( buff , sizeof ( buff ) - 1 , f ) ) {
printf ( " checking %s \n " , buff ) ;
if ( rx . match ( buff ) ) {
printf ( " found libX11 \n " ) ;
is_gui = 1 ;
//break;
}
}
fclose ( f ) ;
edelib : : String fcmd ;
if ( ! is_gui ) {
fcmd = " $TERM " ;
fcmd + = cmd ;
} else {
fcmd = cmd ;
}
run_program ( fcmd . c_str ( ) ) ;
2007-08-07 15:54:57 +04:00
}
2007-09-03 16:24:01 +04:00
# endif
2007-08-07 15:54:57 +04:00
2007-08-06 16:39:15 +04:00
void EvokeService : : register_process ( const char * cmd , pid_t pid ) {
EvokeProcess pc ;
pc . cmd = cmd ;
pc . pid = pid ;
printf ( " registering %s with %i \n " , cmd , pid ) ;
processes . push_back ( pc ) ;
}
void EvokeService : : unregister_process ( pid_t pid ) {
if ( processes . empty ( ) )
return ;
ProcessListIter it = processes . begin ( ) ;
ProcessListIter it_end = processes . end ( ) ;
while ( it ! = it_end ) {
if ( ( * it ) . pid = = pid ) {
printf ( " Found %s with pid %i, cleaning... \n " , ( * it ) . cmd . c_str ( ) , pid ) ;
processes . erase ( it ) ;
return ;
}
+ + it ;
}
}
bool EvokeService : : find_and_unregister_process ( pid_t pid , EvokeProcess & pc ) {
if ( processes . empty ( ) )
return 0 ;
ProcessListIter it = processes . begin ( ) ;
ProcessListIter it_end = processes . end ( ) ;
while ( it ! = it_end ) {
if ( ( * it ) . pid = = pid ) {
printf ( " Found %s with pid %i, cleaning... \n " , ( * it ) . cmd . c_str ( ) , pid ) ;
pc . cmd = ( * it ) . cmd ;
pc . pid = pid ;
processes . erase ( it ) ;
return 1 ;
}
+ + it ;
}
return 0 ;
}
2007-07-30 17:25:13 +04:00
int EvokeService : : handle ( const XEvent * ev ) {
logfile - > printf ( " Got event %i \n " , ev - > type ) ;
if ( ev - > type = = MapNotify ) {
if ( top_win ) {
// for splash to keep it at top (working in old edewm)
XRaiseWindow ( fl_display , fl_xid ( top_win ) ) ;
return 1 ;
}
} else if ( ev - > type = = ConfigureNotify ) {
if ( ev - > xconfigure . event = = DefaultRootWindow ( fl_display ) & & top_win ) {
// splash too, but keep window under other wm's
XRaiseWindow ( fl_display , fl_xid ( top_win ) ) ;
return 1 ;
}
} else if ( ev - > type = = PropertyNotify ) {
if ( ev - > xproperty . atom = = _ede_spawn ) {
char buff [ 1024 ] ;
if ( get_string_property_value ( _ede_spawn , buff , sizeof ( buff ) ) ) {
logfile - > printf ( " Got _EVOKE_SPAWN with %s. Starting client... \n " , buff ) ;
2007-08-07 15:54:57 +04:00
run_program ( buff ) ;
2007-08-31 17:41:27 +04:00
//heuristic_run_program(buff);
2007-08-06 16:39:15 +04:00
} else {
logfile - > printf ( " Got _EVOKE_SPAWN with malformed data. Ignoring... \n " ) ;
}
2007-07-30 17:25:13 +04:00
return 1 ;
}
if ( ev - > xproperty . atom = = _ede_evoke_quit ) {
int val = get_int_property_value ( _ede_evoke_quit ) ;
if ( val = = 1 ) {
logfile - > printf ( " Got accepted _EDE_EVOKE_QUIT \n " ) ;
stop ( ) ;
} else
logfile - > printf ( " Got _EDE_EVOKE_QUIT with bad code (%i). Ignoring... \n " , val ) ;
return 1 ;
}
if ( ev - > xproperty . atom = = _ede_shutdown_all ) {
int val = get_int_property_value ( _ede_shutdown_all ) ;
2007-07-31 19:37:12 +04:00
if ( val = = 1 ) {
2007-07-30 17:25:13 +04:00
logfile - > printf ( " Got accepted _EDE_EVOKE_SHUTDOWN_ALL \n " ) ;
2007-07-31 19:37:12 +04:00
int dw = DisplayWidth ( fl_display , fl_screen ) ;
int dh = DisplayHeight ( fl_display , fl_screen ) ;
printf ( " got %i \n " , logout_dialog ( dw , dh ) ) ;
2007-08-07 15:54:57 +04:00
// quit_x11();
2007-07-31 19:37:12 +04:00
} else
2007-07-30 17:25:13 +04:00
logfile - > printf ( " Got _EDE_EVOKE_SHUTDOWN_ALL with bad code (%i). Ignoring... \n " , val ) ;
return 1 ;
}
}
2007-07-11 20:03:18 +04:00
return 0 ;
}