Logo Search packages:      
Sourcecode: afterstep version File versions

asapp.c

/****************************************************************************
 *
 * Copyright (c) 1999 Sasha Vasko <sasha at aftercode.net>
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 ****************************************************************************/

#define LOCAL_DEBUG
#include "../configure.h"

#include <stdarg.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>

#include "asapp.h"
#include "afterstep.h"
#include "parser.h"
#include "screen.h"
#include "functions.h"
#include "session.h"
#include "balloon.h"
#include "mystyle.h"
#include "wmprops.h"
#include "../libAfterImage/xpm.h"
#include "../libAfterImage/char2uni.h"


ASProgArgs    as_app_args = {0, NULL, 0, NULL, NULL, NULL, 0, 0};/* some typical progy cmd line options - set by SetMyArgs( argc, argv )*/
ASProgArgs   *MyArgsPtr = &as_app_args ; 
char         *MyName = NULL;                    /* name are we known by */
char          MyClass[MAX_MY_CLASS+1]="unknown";/* application Class name ( Pager, Wharf, etc. ) - set by SetMyClass(char *) */
void        (*MyVersionFunc)   (void) = NULL;
void        (*MyUsageFunc)   (void) = NULL;

char     *as_afterstep_dir_name = AFTER_DIR;
char     *as_save_dir_name      = AFTER_DIR "/" AFTER_SAVE;
char     *as_start_dir_name     = AFTER_DIR "/" START_DIR;
char     *as_share_dir_name     = AFTER_SHAREDIR;

char     *as_background_dir_name = BACK_DIR ;
char     *as_look_dir_name = LOOK_DIR ;
char     *as_theme_dir_name = THEME_DIR ;
char     *as_theme_file_dir_name = THEME_FILE_DIR ;
char     *as_feel_dir_name = FEEL_DIR ;
char     *as_colorscheme_dir_name = COLORSCHEME_DIR;
char     *as_font_dir_name = FONT_DIR ;
char     *as_icon_dir_name = ICON_DIR ;
char     *as_tile_dir_name = TILE_DIR ;


int       fd_width;

unsigned int  nonlock_mods = 0;                          /* a mask for non-locking modifiers */
unsigned int  lock_mods[MAX_LOCK_MODS] = {0};  /* all combinations of lock modifier masks */
/* Now for each display we may have one or several screens ; */
ScreenInfo    *ASDefaultScr;                             /* ScreenInfo for the default screen */
//#define Scr     (*DefaultScr);
int x_fd = 0;                                  /* descriptor of the X Windows connection  */


int SingleScreen = -1 ;                                  /* if >= 0 then [points to the only ScreenInfo structure available */
int PointerScreen = 0;                                   /* screen that currently has pointer */
unsigned int  NumberOfScreens = 0;                 /* number of screens on display */
/* unused - future development : */
ScreenInfo  **all_screens = NULL ;             /* all ScreenInfo structures for NumberOfScreens screens */
ASHashTable  *screens_window_hash =NULL   ;        /* so we can easily track what window is on what screen */
/* end of: unused - future development : */


struct ASFeel *DefaultFeel = NULL;/* unused - future development : */
struct MyLook *DefaultLook = NULL;/* unused - future development : */

void (*CloseOnExec)() = NULL ;

struct ASSession *Session = NULL;          /* filenames of look, feel and background */
struct ASEnvironment *Environment = NULL;

/* names of AS functions - used all over the place  :*/

#define FUNC_TERM(txt,len,func)         {TF_NO_MYNAME_PREPENDING,txt,len,TT_FUNCTION,func,NULL}
#define FUNC_TERM2(flags,txt,len,func)  {TF_NO_MYNAME_PREPENDING|(flags),txt,len,TT_FUNCTION,func,NULL}

TermDef       FuncTerms[F_FUNCTIONS_NUM + 1] = {
      FUNC_TERM2 (NEED_NAME, "Nop", 3, F_NOP),   /* Nop      "name"|"" */
      FUNC_TERM2 (NEED_NAME, "Title", 5, F_TITLE),    /* Title    "name"    */
      FUNC_TERM ("Beep", 4, F_BEEP),                     /* Beep               */
      FUNC_TERM ("Quit", 4, F_QUIT),                     /* Quit     ["name"] */
      FUNC_TERM2 (NEED_NAME | NEED_CMD, "Restart", 7, F_RESTART), /* Restart "name" WindowManagerName */
      FUNC_TERM ("Refresh", 7, F_REFRESH),         /* Refresh  ["name"] */
#ifndef NO_VIRTUAL
      FUNC_TERM2 (USES_NUMVALS, "Scroll", 6, F_SCROLL),     /* Scroll     horiz vert */
      FUNC_TERM2 (USES_NUMVALS, "GotoPage", 8, F_GOTO_PAGE),      /* GotoPage   x     y    */
      FUNC_TERM ("TogglePage", 10, F_TOGGLE_PAGE),    /* TogglePage ["name"]   */
#endif
      FUNC_TERM2 (USES_NUMVALS, "CursorMove", 10, F_MOVECURSOR),  /* CursorMove horiz vert */
      FUNC_TERM2 (NEED_WINIFNAME, "WarpFore", 8, F_WARP_F), /* WarpFore ["name" window_name] */
      FUNC_TERM2 (NEED_WINIFNAME, "WarpBack", 8, F_WARP_B), /* WarpBack ["name" window_name] */
      FUNC_TERM2 (NEED_NAME | NEED_WINDOW, "Wait", 4, F_WAIT),    /* Wait      "name" window_name  */
      FUNC_TERM2 (USES_NUMVALS, "Desk", 4, F_DESK),   /* Desk arg1 [arg2] */
      FUNC_TERM2 (USES_NUMVALS, "GotoDeskViewport", 16, F_GOTO_DESKVIEWPORT), /* GotoDeskViewport DESK+VX+VY */
#ifndef NO_WINDOWLIST
      FUNC_TERM2 (USES_NUMVALS, "WindowList", 10, F_WINDOWLIST),  /* WindowList [arg1 arg2] */
#endif
      FUNC_TERM2 (NEED_NAME, "PopUp", 5, F_POPUP),    /* PopUp    "popup_name" [popup_name] */
      FUNC_TERM2 (NEED_NAME, "Function", 8, F_FUNCTION),    /* Function "function_name" [function_name] */
      FUNC_TERM ("MiniPixmap", 10, F_MINIPIXMAP),     /* MiniPixmap "name" */
      FUNC_TERM2 (NEED_NAME | NEED_CMD, "Exec", 4, F_EXEC), /* Exec   "name" command */
      FUNC_TERM2 (NEED_NAME | NEED_CMD, "Module", 6, F_MODULE),   /* Module "name" command */
      FUNC_TERM2 (NEED_NAME | NEED_CMD, "KillModuleByName", 16, F_KILLMODULEBYNAME),      /* KillModuleByName "name" module */
      FUNC_TERM2 (NEED_NAME | NEED_CMD, "QuickRestart", 12, F_QUICKRESTART),  /* QuickRestart "name" what */
      FUNC_TERM2 (NEED_NAME | NEED_CMD, "Background", 10, F_CHANGE_BACKGROUND),     /* Background "name" file_name */
      FUNC_TERM2 (NEED_NAME | NEED_CMD, "ChangeLook", 10, F_CHANGE_LOOK),     /* ChangeLook "name" file_name */
      FUNC_TERM2 (NEED_NAME | NEED_CMD, "ChangeFeel", 10, F_CHANGE_FEEL),     /* ChangeFeel "name" file_name */
    FUNC_TERM2 (NEED_NAME | NEED_CMD, "ChangeTheme", 11, F_CHANGE_THEME), /* ChangeTheme "name" file_name */
    FUNC_TERM2 (NEED_NAME | NEED_CMD, "ChangeThemeFile", 15, F_CHANGE_THEME_FILE), /* "name" file_name */
    FUNC_TERM2 (NEED_NAME | NEED_CMD, "ChangeColorscheme", 17, F_CHANGE_COLORSCHEME), /* ChangeColorscheme "name" file_name */
    FUNC_TERM2 (NEED_NAME | NEED_CMD, "InstallLook", 11, F_INSTALL_LOOK), /*  "name" file_name */
    FUNC_TERM2 (NEED_NAME | NEED_CMD, "InstallFeel", 11, F_INSTALL_FEEL), /*  "name" file_name */
    FUNC_TERM2 (NEED_NAME | NEED_CMD, "InstallBackground", 17, F_INSTALL_BACKGROUND), /* "name" file_name */
    FUNC_TERM2 (NEED_NAME | NEED_CMD, "InstallFont", 11, F_INSTALL_FONT), /* "name" file_name */
    FUNC_TERM2 (NEED_NAME | NEED_CMD, "InstallIcon", 11, F_INSTALL_ICON), /*  "name" file_name */
    FUNC_TERM2 (NEED_NAME | NEED_CMD, "InstallTile", 11, F_INSTALL_TILE), /*  "name" file_name */
    FUNC_TERM2 (NEED_NAME | NEED_CMD, "InstallThemeFile", 12, F_INSTALL_THEME_FILE), /*  "name" file_name */
    FUNC_TERM2 (NEED_NAME | NEED_CMD, "InstallColorscheme", 14, F_INSTALL_COLORSCHEME), /*  "name" file_name */
      FUNC_TERM2 (NEED_NAME | NEED_CMD, "SaveWorkspace", 13, F_SAVE_WORKSPACE), /* SaveWorkspace "name" file_name */
      FUNC_TERM2 (TF_SYNTAX_TERMINATOR, "EndFunction", 11, F_ENDFUNC),
      FUNC_TERM2 (TF_SYNTAX_TERMINATOR, "EndPopup", 8, F_ENDPOPUP),
      FUNC_TERM ("TakeScreenShot", 14, F_TAKE_SCREENSHOT),
      FUNC_TERM2 (NEED_NAME | NEED_CMD, "Test", 4, F_Test),

      /* this functions require window as aparameter */
      FUNC_TERM ("&nonsense&", 10, F_WINDOW_FUNC_START),    /* not really a command */
      FUNC_TERM2 (USES_NUMVALS, "Move", 4, F_MOVE),   /* Move     ["name"] [whereX whereY] */
      FUNC_TERM2 (USES_NUMVALS, "Resize", 6, F_RESIZE),     /* Resize   ["name"] [toWidth toHeight] */
      FUNC_TERM ("Raise", 5, F_RAISE),             /* Raise    ["name"] */
      FUNC_TERM ("Lower", 5, F_LOWER),             /* Lower    ["name"] */
      FUNC_TERM ("RaiseLower", 10, F_RAISELOWER),     /* RaiseLower ["name"] */
      FUNC_TERM ("PutOnTop", 8, F_PUTONTOP),       /* PutOnTop  */
      FUNC_TERM ("PutOnBack", 9, F_PUTONBACK),   /* PutOnBack */
      FUNC_TERM2 (USES_NUMVALS, "SetLayer", 8, F_SETLAYER), /* SetLayer    layer */
      FUNC_TERM2 (USES_NUMVALS, "ToggleLayer", 11, F_TOGGLELAYER),      /* ToggleLayer layer1 layer2 */
      FUNC_TERM ("Shade", 5, F_SHADE),             /* Shade    ["name"] */
      FUNC_TERM ("Delete", 6, F_DELETE),           /* Delete   ["name"] */
      FUNC_TERM ("Destroy", 7, F_DESTROY),         /* Destroy  ["name"] */
      FUNC_TERM ("Close", 5, F_CLOSE),             /* Close    ["name"] */
      FUNC_TERM ("Iconify", 7, F_ICONIFY),         /* Iconify  ["name"] value */
      FUNC_TERM2 (USES_NUMVALS, "Maximize", 8, F_MAXIMIZE), /* Maximize ["name"] [hori vert] */
      FUNC_TERM ("Stick", 5, F_STICK),             /* Stick    ["name"] */
      FUNC_TERM ("Focus", 5, F_FOCUS),             /* Focus */
      FUNC_TERM2 (NEED_WINIFNAME, "ChangeWindowUp", 14, F_CHANGEWINDOW_UP),   /* ChangeWindowUp   ["name" window_name ] */
      FUNC_TERM2 (NEED_WINIFNAME, "ChangeWindowDown", 16, F_CHANGEWINDOW_DOWN),     /* ChangeWindowDown ["name" window_name ] */
    FUNC_TERM2 (NEED_WINIFNAME, "GoToBookmark", 12, F_GOTO_BOOKMARK),   /* GoToBookmark ["name" window_bookmark ] */
      FUNC_TERM ("GetHelp", 7, F_GETHELP),         /* */
      FUNC_TERM ("PasteSelection", 14, F_PASTE_SELECTION),  /* */
      FUNC_TERM2 (USES_NUMVALS, "WindowsDesk", 11, F_CHANGE_WINDOWS_DESK),    /* WindowDesk "name" new_desk */
    FUNC_TERM ("BookmarkWindow", 14, F_BOOKMARK_WINDOW),    /* BookmarkWindow "name" new_bookmark */
    FUNC_TERM ("PinMenu", 7, F_PIN_MENU),    /* PinMenu ["name"] */
      FUNC_TERM ("TakeWindowShot", 14, F_TAKE_WINDOWSHOT),
      FUNC_TERM ("TakeFrameShot", 13, F_TAKE_FRAMESHOT),
      /* end of window functions */
      /* these are commands  to be used only by modules */
      FUNC_TERM ("&nonsense&", 10, F_MODULE_FUNC_START),    /* not really a command */
      FUNC_TERM ("Send_WindowList", 15, F_SEND_WINDOW_LIST),      /* */
      FUNC_TERM ("SET_MASK", 8, F_SET_MASK),       /* SET_MASK  mask lock_mask */
    FUNC_TERM2 (NEED_NAME, "SET_NAME", 8, F_SET_NAME),   /* SET_NAME  name */
      FUNC_TERM ("UNLOCK", 6, F_UNLOCK),           /* UNLOCK    1  */
      FUNC_TERM ("SET_FLAGS", 9, F_SET_FLAGS),   /* SET_FLAGS flags */
      /* these are internal commands */
      FUNC_TERM ("&nonsense&", 10, F_INTERNAL_FUNC_START),  /* not really a command */
      FUNC_TERM ("&raise_it&", 10, F_RAISE_IT),  /* should not be used by user */
    /* wharf functions : */
    {TF_NO_MYNAME_PREPENDING, "Folder", 6, TT_FUNCTION, F_Folder, NULL},
    {TF_NO_MYNAME_PREPENDING | NEED_NAME | NEED_CMD, "Swallow", 7, TT_FUNCTION, F_Swallow, NULL},
    {TF_NO_MYNAME_PREPENDING | NEED_NAME | NEED_CMD, "MaxSwallow", 10, TT_FUNCTION, F_MaxSwallow, NULL},
    {TF_NO_MYNAME_PREPENDING | NEED_NAME | NEED_CMD, "SwallowModule", 13, TT_FUNCTION, F_SwallowModule, NULL},
    {TF_NO_MYNAME_PREPENDING | NEED_NAME | NEED_CMD, "MaxSwallowModule", 16, TT_FUNCTION, F_MaxSwallowModule, NULL},
    FUNC_TERM2 (NEED_NAME | NEED_CMD, "DropExec", 8, F_DropExec),   /* DropExec   "name" command */
    {TF_NO_MYNAME_PREPENDING, "Size", 4, TT_FUNCTION, F_Size, NULL},
    {TF_NO_MYNAME_PREPENDING, "Transient", 9, TT_FUNCTION, F_Transient, NULL},

      {0, NULL, 0, 0, 0}
};

struct SyntaxDef FuncSyntax = {
    '\0',   '\n', FuncTerms,
      0,          ' ',  "",               "\t",
      "AfterStep Function",
      "Functions",
      "built in AfterStep functions",
      NULL, 0
};
SyntaxDef     PopupFuncSyntax = {
      '\n', '\0', FuncTerms,
      0,          ' ',  "\t",       "\t",
    "Popup/Complex function definition",
      "Popup",
      "",   
      NULL, 0
};



struct SyntaxDef     *pFuncSyntax = &FuncSyntax;
struct SyntaxDef     *pPopupFuncSyntax = &PopupFuncSyntax;

TermDef      *
func2fterm (FunctionCode func, int quiet)
{
      register int  i;

      /* in most cases that should work : */
      if( func < F_FUNCTIONS_NUM )
            if (FuncTerms[func].id == func)
                  return &(FuncTerms[func]);

      /* trying fallback if it did not : */
      for (i = 0; i < F_FUNCTIONS_NUM; i++)
            if (FuncTerms[i].id == func)
                  return &(FuncTerms[i]);

      /* something terribly wrong has happened : */
      return NULL;
}

/************************************************************************************/
/* Command Line Processing/ App initialization here :                               */
/************************************************************************************/
void
SetMyClass (const char *app_class)
{
    if( app_class != NULL )
    {
        strncpy( MyClass, (char*)app_class, MAX_MY_CLASS );
        MyClass[MAX_MY_CLASS] = '\0' ;
    }
}

void
SetMyName (char *argv0)
{
      char         *temp = strrchr (argv0, '/');

      /* Save our program name - for error messages */
      MyName = temp ? temp + 1 : argv0;
      set_application_name(argv0);
}

/* If you change/add options please change InitMyApp below and option flags in aftersteplib.h */

CommandLineOpts as_standard_cmdl_options[20] =
{
#define  SHOW_VERSION   0
#define  SHOW_CONFIG    1
#define  SHOW_USAGE     2
/* 0*/{"v", "version", "Display version information and stop", NULL, handler_show_info, NULL, SHOW_VERSION  },
/* 1*/{"c", "config",  "Display Config information and stop",  NULL, handler_show_info, NULL, SHOW_CONFIG},
/* 2*/{"h", "help",    "Display uasge information and stop",   NULL, handler_show_info, NULL, SHOW_USAGE},
/* 3*/{NULL,"debug",   "Debugging: Run in Synchronous mode",  NULL, handler_set_flag, &(as_app_args.flags), ASS_Debugging},
/* 4*/{"s", "single",  "Run on single screen only", NULL, handler_set_flag, &(as_app_args.flags), ASS_SingleScreen},
/* 5*/{"r", "restart", "Run as if it was restarted","same as regular startup, only runs RestartFunction\ninstead of InitFunction",
                                                           handler_set_flag, &(as_app_args.flags), ASS_Restarting},
#define OPTION_HAS_ARGS     6
/* 6*/{"d", "display", "Specify what X display we should connect to","Overrides $DISPLAY environment variable",
                                                           handler_set_string, &(as_app_args.display_name), 0, CMO_HasArgs },
/* 7*/{"f", "config-file", "Read all config from requested file","Use it if you want to use .steprc\ninstead of standard config files",
                                                           handler_set_string, &(as_app_args.override_config), 0, CMO_HasArgs },
/* 8*/{"p", "user-dir","Read all the config from requested dir","Use it to override config location\nrequested in compile time" ,
                                                           handler_set_string, &(as_app_args.override_home), 0, CMO_HasArgs },
/* 9*/{"g", "global-dir","Use requested dir as a shared config dir","Use it to override shared config location\nrequested in compile time" ,
                                                           handler_set_string, &(as_app_args.override_share), 0, CMO_HasArgs },
/*10*/{"V", "verbosity-level","Change verbosity of the AfterStep output","0 - will disable any output;\n1 - will allow only error messages;\n5 - both errors and warnings(default)",
                                                           handler_set_int, &(as_app_args.verbosity_level), 0, CMO_HasArgs },
/*11*/{NULL, "window", "Internal Use: Window in which action occured", "interface part which has triggered our startup",
                                                           handler_set_int, &(as_app_args.src_window), 0, CMO_HasArgs },
/*12*/{NULL, "context","Internal Use: Context in which action occured", "interface part which has triggered our startup",
                                                           handler_set_int, &(as_app_args.src_context), 0, CMO_HasArgs },
/*13*/{NULL, "look","Read look config from requested file","Use it if you want to use different look\ninstead of what was selected from the menu",
                                                           handler_set_string, &(as_app_args.override_look), 0, CMO_HasArgs },
/*14*/{NULL, "feel","Read feel config from requested file","Use it if you want to use different feel\ninstead of what was selected from the menu",
                                                           handler_set_string, &(as_app_args.override_feel), 0, CMO_HasArgs },
/*15*/{NULL, "theme","Read theme config from requested file","Use it if you want to use different theme\ninstead of what was selected from the menu",
                                                           handler_set_string, &(as_app_args.override_feel), 0, CMO_HasArgs },
#ifdef DEBUG_TRACE_X
/*16*/{NULL, "trace-func","Debugging: Trace calls to a function with requested name", NULL,
                                                           handler_set_string, &(as_app_args.trace_calls), 0, CMO_HasArgs },
#endif
/*17*/{"l", "log","Save all output into the file instead of printing it to console", NULL,
                                                           handler_set_string, &(as_app_args.log_file), 0, CMO_HasArgs },
/*18*/{"L", "locale","Set language locale to be used while displaying text", NULL,
                                                           handler_set_string, &(as_app_args.locale), 0, CMO_HasArgs },
      {NULL, NULL, NULL, NULL, NULL, NULL, 0 }
};

void
standard_version (void)
{
    if( MyVersionFunc )
        MyVersionFunc();
    else
          printf ("%s version %s\n", MyClass, VERSION);
}

void
print_command_line_opt(const char *prompt, CommandLineOpts *options, ASFlagType mask)
{
    register int i ;
    ASFlagType bit = 0x01;

      if( options == NULL ) 
            options = as_standard_cmdl_options ;
    printf ("%s:\n", prompt);

    for( i = 0 ; options[i].handler != NULL ; i++ )
    {
        if( !get_flags( bit, mask ) )
        {
            if( options[i].short_opt )
                printf( OPTION_SHORT_FORMAT, options[i].short_opt );
            else
                printf( OPTION_NOSHORT_FORMAT);

            if( !get_flags( options[i].flags, CMO_HasArgs ) )
                printf( OPTION_DESCR1_FORMAT_NOVAL, options[i].long_opt, options[i].descr1 );
            else
                printf( OPTION_DESCR1_FORMAT_VAL, options[i].long_opt, options[i].descr1 );

            if( options[i].descr2 )
                  {
                register char *start = options[i].descr2 ;
                        register char *end ;
                        do
                        {
                              end = strchr( start, '\n' );
                              if( end == NULL )
                                    printf(OPTION_DESCR2_FORMAT, start );
                              else
                              {
                                    static char buffer[81];
                                    register int len = (end > start+80 )? 80 : end-start ;
                                    strncpy( buffer, start, len );
                                    buffer[len] = '\0' ;
                                    printf(OPTION_DESCR2_FORMAT, buffer );
                                    start = end+1 ;
                              }
                        }while( end != NULL );
                  }
        }
        bit = bit << 1 ;
    }
}

void
standard_usage()
{
    standard_version();
    if( MyUsageFunc )
        MyUsageFunc();
    else
        printf (OPTION_USAGE_FORMAT "\n", MyName );
    print_command_line_opt("standard_options are :", as_standard_cmdl_options, as_app_args.mask);
}

void  handler_show_info( char *argv, void *trg, long param )
{
    switch( param )
    {
        case SHOW_VERSION :
            standard_version();
            break;
        case SHOW_CONFIG  :
            standard_version();
            printf ("BinDir            %s\n", AFTER_BIN_DIR);
            printf ("ManDir            %s\n", AFTER_MAN_DIR);
            printf ("DocDir            %s\n", AFTER_DOC_DIR);
            printf ("ShareDir          %s\n", AFTER_SHAREDIR);
            printf ("AfterDir          %s\n", AFTER_DIR);
            break;
        case SHOW_USAGE   :
            standard_usage();
            break;
    }
    exit (0);
}
void  handler_set_flag( char *argv, void *trg, long param )
{
    register ASFlagType *f = trg ;
    set_flags( *f, param );
}
void  handler_set_string( char *argv, void *trg, long param )
{
    register char **s = trg;
    if( argv )
        *s = argv;
}
void  handler_set_int( char *argv, void *trg, long param )
{
    register int *i = trg ;
    if( argv )
        *i = atoi(argv);
}

int
match_command_line_opt( char *argvi, CommandLineOpts *options )
{
    register char *ptr = argvi;
    register int opt ;

    if( ptr == NULL )
        return -1;
    if( *ptr == '-' )
    {
        ++ptr;
        if( *ptr == '-' )
        {
            ++ptr;
            for( opt = 0 ; options[opt].handler ; ++opt )
                if( strcmp(options[opt].long_opt, ptr ) == 0 )
                    break;
        }else
        {
            for( opt = 0 ; options[opt].handler ; ++opt )
                if( options[opt].short_opt )
                    if( strcmp(options[opt].short_opt, ptr ) == 0 )
                        break;
        }
    }else
        opt = -1;
    if( options[opt].handler == NULL )
        opt = -1;
    return opt;
}

static DeadPipe_handler _as_dead_pipe_handler = NULL ; 

DeadPipe_handler set_DeadPipe_handler( DeadPipe_handler new_handler ) 
{
      DeadPipe_handler old = _as_dead_pipe_handler ; 
      _as_dead_pipe_handler = new_handler ; 
      return old;
}      

void ASDeadPipe( int nonsense ) 
{
      if( _as_dead_pipe_handler )
            _as_dead_pipe_handler(nonsense);
      else
            exit (0);
}      

static char **AS_environ = NULL ; 

void override_environ( char **envp )
{
      AS_environ = envp ;     
}      

void
InitMyApp (  const char *app_class, int argc, char **argv, void (*version_func) (void), void (*custom_usage_func) (void), ASFlagType opt_mask )
{
    /* first of all let's set us some nice signal handlers */
#ifdef HAVE_SIGSEGV_HANDLING
    set_signal_handler (SIGSEGV);
#endif

      set_signal_handler (SIGUSR2);
    signal (SIGPIPE, ASDeadPipe);        /* don't forget DeadPipe should be provided by the app */

    SetMyClass( app_class );
    MyVersionFunc = version_func ;
    MyUsageFunc = custom_usage_func ;

    memset( &as_app_args, 0x00, sizeof(ASProgArgs) );
      as_app_args.locale = mystrdup(AFTER_LOCALE);
      if (strlen(as_app_args.locale) == 0)
      {
            free( as_app_args.locale );
            as_app_args.locale = mystrdup(getenv("LANG"));
      }

    as_app_args.mask = opt_mask ;
#ifndef NO_DEBUG_OUTPUT
    as_app_args.verbosity_level = OUTPUT_VERBOSE_THRESHOLD ;
#else
    as_app_args.verbosity_level = OUTPUT_DEFAULT_THRESHOLD ;
#endif


    ASDefaultScr = safecalloc(1, sizeof(ScreenInfo));

    if( argc > 0 && argv )
    {
        int i ;

            as_app_args.saved_argc = argc ;
            as_app_args.saved_argv = safecalloc( argc, sizeof(char*));
            for( i = 0 ; i < argc ; ++i )
                  as_app_args.saved_argv[i] = argv[i] ;

        SetMyName( argv[0] );

        for( i = 1 ; i < argc ; i++ )
        {
            register int opt ;
            if( (opt = match_command_line_opt( &(argv[i][0]), as_standard_cmdl_options )) < 0 )
                continue;
            if( get_flags( (0x01<<opt), as_app_args.mask) )
                continue;
            if( get_flags( as_standard_cmdl_options[opt].flags, CMO_HasArgs ) )
            {
                        argv[i] = NULL ;
                if( ++i >= argc )
                    continue;
                else
                    as_standard_cmdl_options[opt].handler( argv[i], as_standard_cmdl_options[opt].trg, as_standard_cmdl_options[opt].param );
            }else
                as_standard_cmdl_options[opt].handler( NULL, as_standard_cmdl_options[opt].trg, as_standard_cmdl_options[opt].param );
            argv[i] = NULL ;
        }
    }

    fd_width = get_fd_width ();

    if (FuncSyntax.term_hash == NULL)
            PrepareSyntax (&FuncSyntax);
    set_output_threshold( as_app_args.verbosity_level );
    if(as_app_args.log_file)
            if( freopen( as_app_args.log_file, get_flags( as_app_args.flags, ASS_Restarting)?"a":"w", stderr ) == NULL )
            show_system_error( "failed to redirect output into file \"%s\"", as_app_args.log_file );

      if( as_app_args.locale && strlen(as_app_args.locale) > 0)
      {
            as_set_charset( parse_charset_name( as_app_args.locale ));
#ifdef I18N
            if (strlen(as_app_args.locale) > 0)
                  if (setlocale (LC_CTYPE, as_app_args.locale) == NULL)
                  {
                      show_error ("unable to set locale");
                  }
#endif
      }else
      {
#ifdef I18N
          show_warning ("LANG environment variable is not set - use -L \"locale\" command line option to define locale");
#endif
      }     

#ifdef DEBUG_TRACE_X
    trace_enable_function(as_app_args.trace_calls);
#endif

      asxml_var_insert("minipixmap.width", 48);
      asxml_var_insert("minipixmap.height", 48);

}

void
free_func_hash ()
{
      if (FuncSyntax.term_hash)
      {
        FreeSyntaxHash (&FuncSyntax);
      }
}

/*********** end command line parsing **************************/

ASEnvironment *
make_default_environment()
{
      ASEnvironment *e = safecalloc( 1, sizeof(ASEnvironment) );
      static const char *default_pixmap_path_format =
            "%s/desktop/icons/:"
            "%s/desktop/icons/:"
            "%s/desktop/:"
            "%s/desktop/:"
            "%s/desktop/buttons/:"
            "%s/desktop/buttons/:"
            "%s/backgrounds/:"
            "%s/backgrounds/:"
            "%s" ;

      static const char *default_font_path_format =
            "%s/desktop/fonts/:"
            "%s/desktop/fonts/:"
            "/usr/share/fonts/default/TrueType/:"
            "%s" ;

      static const char *default_cursor_path_format =
            "%s/desktop/cursors:"
            "%s/desktop/cursors";

      e->desk_scale = 24 ;
      e->desk_pages_h = 2 ;
      e->desk_pages_v = 2 ;
      e->module_path = mystrdup( AFTER_BIN_DIR );
      e->icon_path = mystrdup( DEFAULT_ICON_DIR );
      e->pixmap_path = safemalloc( strlen((char*)default_pixmap_path_format)+
                                     strlen(AFTER_DIR)*4+
                                                 strlen(AFTER_SHAREDIR)*4 +
                                                 strlen(DEFAULT_PIXMAP_DIR) + 1);
      sprintf( e->pixmap_path, default_pixmap_path_format,
                               AFTER_DIR,
                                           AFTER_SHAREDIR,
                                           AFTER_DIR,
                                           AFTER_SHAREDIR,
                                           AFTER_DIR,
                                           AFTER_SHAREDIR,
                                           AFTER_DIR,
                                           AFTER_SHAREDIR,
                                           DEFAULT_PIXMAP_DIR );

      e->font_path = safemalloc(   strlen((char*)default_font_path_format)+
                                                 strlen(AFTER_DIR)+
                                                 strlen(AFTER_SHAREDIR) +
                                                 strlen(DEFAULT_TTF_DIR) + 1);
      sprintf( e->font_path, default_font_path_format,
                               AFTER_DIR,
                                           AFTER_SHAREDIR,
                                           DEFAULT_TTF_DIR );

      e->cursor_path = safemalloc( strlen((char*)default_cursor_path_format)+
                                                 strlen(AFTER_DIR)+
                                                 strlen(AFTER_SHAREDIR) + 1);
      sprintf( e->cursor_path, default_cursor_path_format,
                               AFTER_DIR,
                                           AFTER_SHAREDIR );
      return e;
}

void
destroy_asenvironment( ASEnvironment **penv )
{
      if( penv )
      {
            ASEnvironment *e = *penv ;
            if( e )
            {
                  if( e->module_path )
                        free( e->module_path );
                  if( e->audio_path )
                        free( e->audio_path );
                  if( e->icon_path )
                        free( e->icon_path );
                  if( e->pixmap_path )
                        free( e->pixmap_path );
                  if( e->font_path )
                        free( e->font_path );
                  if( e->cursor_path )
                        free( e->cursor_path );

                  free( e ) ;
                  *penv = NULL ;
            }
      }
}

void
InitSession()
{
    /* initializing our dirs names */
    Session = GetNCASSession(ASDefaultScr, as_app_args.override_home, as_app_args.override_share);
    if( as_app_args.override_config )
        set_session_override( Session, as_app_args.override_config, 0 );
    if( as_app_args.override_look )
        set_session_override( Session, as_app_args.override_look, F_CHANGE_LOOK );
    if( as_app_args.override_feel )
        set_session_override( Session, as_app_args.override_feel, F_CHANGE_FEEL );
}


void
FreeMyAppResources()
{
      
    balloon_init (True);
    mystyle_destroy_all();
    destroy_image_manager( ASDefaultScr->image_manager, False );
    destroy_font_manager( ASDefaultScr->font_manager, False );
    clientprops_cleanup ();
    destroy_wmprops (ASDefaultScr->wmprops, False);
    wmprops_cleanup ();
    free_func_hash();
    purge_asimage_registry();
      asxml_var_cleanup();
      custom_color_cleanup();
    build_xpm_colormap( NULL );
    flush_ashash_memory_pool();
    destroy_screen_gcs(ASDefaultScr);
      if( ASDefaultScr->RootImage ) 
      {     
            safe_asimage_destroy( ASDefaultScr->RootImage );
            ASDefaultScr->RootImage = NULL ;
      }
      destroy_asvisual( ASDefaultScr->asv, False );
    flush_asbidirlist_memory_pool();
    free( as_app_args.saved_argv );
    destroy_assession( Session );
      destroy_asenvironment( &Environment );
      is_executable_in_path ( NULL );
#ifdef XSHMIMAGE
      flush_shm_cache();
#endif
      free( ASDefaultScr );
      flush_default_asstorage();

}


/************ child process spawning ***************************/
/***********************************************************************
 *  Procedure:
 *  general purpose child launcher - spawn child.
 *  Pass along all the cmd line args if needed.
 *  returns PID of the spawned process
 ************************************************************************/
static int        as_singletons[MAX_SINGLETONS_NUM];
static Bool       as_init_singletons = True;

void
as_sigchild_handler (int signum)
{
      int           pid;
      int status ;

      signal (SIGCHLD, as_sigchild_handler);
      DEBUG_OUT("Entering SigChild_handler(%lu)", time (NULL));
      if( as_init_singletons )
            return;
      while ((pid = WAIT_CHILDREN (&status)) > 0 )
      {
            register int i ;
            LOCAL_DEBUG_OUT( "pid = %d", pid );
            for( i = 0; i < MAX_SINGLETONS_NUM ; i++ )
                  if( pid == as_singletons[i] )
                  {
                        as_singletons[i] = 0 ;
                        break;
                  }
      }
      DEBUG_OUT("Exiting SigChild_handler(%lu)", time (NULL));
}

/*
 * This should return 0 if process of running external app to draw background completed or killed.
 * otherwise it returns > 0
 */
int
check_singleton_child (int singleton_id, Bool kill_it_to_death)
{
      int           i;
      int           pid, status;

      if( as_init_singletons || singleton_id < 0 )
            return -1 ;

      if( singleton_id >= MAX_SINGLETONS_NUM )
            singleton_id = MAX_SINGLETONS_NUM-1;

      DEBUG_OUT("CheckingForDrawChild(%lu)....",time (NULL));
      if ( (pid = as_singletons[singleton_id]) > 0)
      {
            DEBUG_OUT("checking on singleton child #%d started with PID (%d)", singleton_id, pid);
            if (kill_it_to_death)
            {
                  kill (pid, SIGTERM);
                  for (i = 0; i < 100; i++)              /* give it 10 sec to terminate */
                  {
                        sleep_a_millisec (100);
                        if ( WAIT_CHILDREN (&status) == pid || as_singletons[singleton_id] <= 0 )
                              break;
                  }
                  if (i >= 100)
                        kill (pid, SIGKILL);  /* no more mercy */
                  as_singletons[singleton_id] = 0 ;
            }
      } else if (as_singletons[singleton_id] < 0)
            as_singletons[singleton_id] = 0;

      DEBUG_OUT ("Done(%lu). Child PID on exit = %d.", time (NULL), as_singletons[singleton_id]);
      return as_singletons[singleton_id];
}

int
spawn_child( const char *cmd, int singleton_id, int screen, Window w, int context, Bool do_fork, Bool pass_args, ... )
{
    int pid = 0;

    if( cmd == NULL )
        return 0;
      if( as_init_singletons )
      {
            register int i ;
            for( i = 0; i < MAX_SINGLETONS_NUM ; i++ )
                  as_singletons[i] = 0 ;
            signal (SIGCHLD, as_sigchild_handler);
            as_init_singletons = False ;
      }

      if( singleton_id >= 0 )
      {
            if( singleton_id >= MAX_SINGLETONS_NUM )
                  singleton_id = MAX_SINGLETONS_NUM-1;
            if( as_singletons[singleton_id] > 0 )
                  check_singleton_child( singleton_id, True );
      }

    if( do_fork )
        pid = fork();

    if( pid != 0 )
      {
            /* there is a possibility of the race condition here
             * but it really is not worse the trouble to try and avoid it.
             */
      if( singleton_id >= 0 )
                  as_singletons[singleton_id] = pid ;
          return pid;
      }else
    {/* we get here only in child process. We now need to spawn new proggy here: */
        int len;
        char *display = mystrdup(XDisplayString (dpy));
            char **envp ; 
        register char *ptr ;

        char *cmdl;
        char *arg, *screen_str = NULL, *w_str = NULL, *context_str = NULL ;
            int env_s = 0;
            char **envvars = AS_environ ; 
            int font_path_slot = -1, image_path_slot = -1 ;

        va_list ap;
            LOCAL_DEBUG_OUT( "dpy = %p, DisplayString = \"%s\"", dpy, display );
            LOCAL_DEBUG_OUT( "pid(%d), entered child process to spawn ...", pid );

#if HAVE_DECL_ENVIRON
            if( envvars == NULL ) 
            {
                  envvars = environ ;
            }      
#else
/* how the hell could we get environment otherwise ? */
#endif
            if( envvars ) 
            {
                  int font_path_len = strlen(ASFONT_PATH_ENVVAR);
                  int image_path_len = strlen(ASIMAGE_PATH_ENVVAR);
                  for( env_s = 0  ; envvars[env_s] != NULL ; ++env_s )
                  {
                        if( font_path_slot < 0 && strlen(envvars[env_s]) > font_path_len ) 
                              if(strncmp(envvars[env_s], ASFONT_PATH_ENVVAR, font_path_len)==0)
                                    font_path_slot = env_s ; 
                        if( image_path_slot < 0 && strlen(envvars[env_s]) > image_path_len) 
                              if(strncmp(envvars[env_s], ASIMAGE_PATH_ENVVAR, image_path_len)==0)
                                    image_path_slot = env_s ;
                  }     
            }
            if( font_path_slot < 0 ) 
                  ++env_s ;
            if( image_path_slot  < 0 ) 
                  ++env_s ;
            envp = safecalloc( env_s+2, sizeof(char*));

            /* environment variabless to pass to child process */
            if( envvars ) 
                  for( env_s = 0  ; envvars[env_s] != NULL ; ++env_s )
                        envp[env_s] = envvars[env_s] ;      
        
            envp[env_s] = safemalloc(8+strlen(display)+1);
            sprintf( envp[env_s], "DISPLAY=%s", display );
            ++env_s ;
            if( Environment ) 
            {
                  if( Environment->pixmap_path != NULL ) 
                  {     
                        int slot_no = image_path_slot ; 
                        if( slot_no < 0 ) 
                              slot_no = env_s++ ; 
                              
                        envp[slot_no] = safemalloc(strlen( ASIMAGE_PATH_ENVVAR ) + 1 + strlen(Environment->pixmap_path)+1) ;
                        sprintf( envp[slot_no], "%s=%s", ASIMAGE_PATH_ENVVAR, Environment->pixmap_path );
                  }
                  if( Environment->font_path ) 
                  {     
                        int slot_no = font_path_slot ; 
                        if( slot_no < 0 ) 
                              slot_no = env_s++ ; 
                        envp[slot_no] = safemalloc(strlen( ASFONT_PATH_ENVVAR ) + 1 + strlen(Environment->font_path)+1) ;
                        sprintf( envp[slot_no], "%s=%s", ASFONT_PATH_ENVVAR, Environment->font_path );
                  }
            }      
                  
        len = strlen((char*)cmd);
        if( pass_args )
        {
            register int i = 0 ;

            while( display[i] ) ++i;

            while( i > 0 && isdigit(display[--i]) );
            if( display[i] == '.' )
                display[i+1] = '\0' ;

            if( screen >= 0 )
                screen_str = string_from_int( screen );
            if( w != None )
                w_str = string_from_int( w );
            if( context != C_NO_CONTEXT )
                context_str = string_from_int( context );

            len += 1+2+1+strlen( display );
            if( screen_str )
                len += strlen(screen_str);
            len += 3 ;                         /* for "-s " */
            if ( get_flags( as_app_args.flags, ASS_Debugging) )
                len += 8 ;
            if ( get_flags( as_app_args.flags, ASS_Restarting) )
                len += 3 ;
            if ( as_app_args.override_config )
                len += 4+strlen(as_app_args.override_config);
            if ( as_app_args.override_home )
                len += 4+strlen(as_app_args.override_home);
            if ( as_app_args.override_share )
                len += 4+strlen(as_app_args.override_share);

                  if ( as_app_args.locale )
                len += 4+strlen(as_app_args.locale);

            if( as_app_args.verbosity_level != OUTPUT_DEFAULT_THRESHOLD )
                len += 4+32 ;
#ifdef DEBUG_TRACE_X
            if( as_app_args.trace_calls )
                len += 13+strlen( as_app_args.trace_calls );
#endif
            if( w_str )
                len += 1+8+1+strlen(w_str);
            if( context_str )
                len += 1+9+1+strlen(context_str);
        }
        /* now we want to append arbitrary number of arguments to the end of command line : */
        va_start( ap, pass_args );
        while( (arg = va_arg(ap,char*)) != NULL )
            len += 1+strlen(arg);
        va_end(ap);

        len+=4;

        ptr = cmdl = safemalloc( len );
        strcpy( cmdl, (char*)cmd );
        while(*ptr) ptr++;
        if( pass_args )
        {
            ptr += sprintf( ptr, " -d %s%s -s", display, screen_str?screen_str:"" );
            if ( get_flags( as_app_args.flags, ASS_Debugging) )
            {
                strcpy( ptr, " --debug");
                ptr+=8 ;
            }
            if ( get_flags( as_app_args.flags, ASS_Restarting) )
            {
                strcpy( ptr, " -r");
                ptr += 3 ;
            }
            if ( as_app_args.override_config )
                ptr += sprintf( ptr, " -f %s", as_app_args.override_config );
            if ( as_app_args.override_home )
                ptr += sprintf( ptr, " -p %s", as_app_args.override_home );
            if ( as_app_args.override_share )
                ptr += sprintf( ptr, " -g %s", as_app_args.override_share );
            if( as_app_args.verbosity_level != OUTPUT_DEFAULT_THRESHOLD )
                ptr += sprintf( ptr, " -V %d", as_app_args.verbosity_level );
LOCAL_DEBUG_OUT( "len = %d, cmdl = \"%s\" strlen = %d, locale = \"%s\", ptr-cmdl = %d", len, cmdl, strlen(cmdl), as_app_args.locale, ptr-cmdl );
                  if( as_app_args.locale && as_app_args.locale[0] && !isspace(as_app_args.locale[0]))
                ptr += sprintf( ptr, " -L %s", as_app_args.locale );
                  
#ifdef DEBUG_TRACE_X
            if( as_app_args.trace_calls )
                ptr += sprintf( ptr, " --trace-func %s", as_app_args.trace_calls );
#endif
            if( w_str )
                ptr += sprintf( ptr, " --window %s", w_str );
            if( context_str )
                ptr += sprintf( ptr, " --context %s", context_str );
        }
        
            va_start( ap, pass_args );
        while( (arg = va_arg(ap,char*)) != NULL )
        {
            *(ptr++) = ' ';
            strcpy( ptr, arg );
            while(*ptr) ptr++;
LOCAL_DEBUG_OUT( "len = %d, cmdl = \"%s\" strlen = %d", len, cmdl, strlen(cmdl) );
        
            }
        va_end(ap);
        if( do_fork )
        {
            int i = ptr-cmdl;
            while( --i >= 0 ) if( !isspace(cmdl[i]) ) break;
            do_fork = ( i < 0 || cmdl[i] != '&' );
        }
            strcpy (ptr, do_fork?" &\n":"\n");

LOCAL_DEBUG_OUT( "len = %d, cmdl = \"%s\" strlen = %d", len, cmdl, strlen(cmdl) );
#if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
            {
                  FILE *fff = fopen ("/tmp/afterstep.exec.log", "a");
                  if( fff ) 
                  {
                        fprintf( fff, "%s:%ld: [%s]", MyName, time(NULL), cmdl );
                        fclose(fff);
                  }
            }     
#endif                     
     
        LOCAL_DEBUG_OUT("execle(\"%s\")", cmdl );
        /* fprintf( stderr, "len=%d: execl(\"%s\")", len, cmdl ); */

        /* CYGWIN does not handle close-on-exec gracefully - whave to do it ourselves : */
        if( CloseOnExec )
            CloseOnExec();

            {
                  const char     *shell;
                  char *argv0 ;

            if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
                        shell = mystrdup("/bin/sh");

                  parse_file_name(shell, NULL, &argv0);
            /* argv0 = basename(shell); */

            execle (shell, argv0 , "-c", cmdl, (char *)0, envp);
            }

        if( screen >= 0 )
            show_error( "failed to start %s on the screen %d", cmd, screen );
        else
            show_error( "failed to start %s", cmd );
        show_system_error( " complete command line: \"%s\"\n", cmdl );
        exit(128);
    }
}
/************ end child process spawning ***************************/


Generated by  Doxygen 1.6.0   Back to index