Logo Search packages:      
Sourcecode: adesklets version File versions

adesklets.c

/*--- adesklets.c --------------------------------------------------------------
Copyright (C) 2004, 2005 Sylvain Fourmanoit <syfou@users.sourceforge.net>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies of the Software and its documentation and acknowledgment shall be
given in the documentation and software packages that this Software was
used.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.   
------------------------------------------------------------------------------*/
#include "adesklets.h"              /* Application main header */

/*----------------------------------------------------------------------------*/
#define welcome(stream) fprintf(stream,\
                               "%s\n[%s]\n",WELCOME_LINE_1,WELCOME_LINE_2)

/*----------------------------------------------------------------------------*/
t_adesklets adesklets = {
  0,                          /* pid_t ppid */
  NULL,                             /* Display * display */
  NULL,                             /* Visual * visual */
  0,                          /* Window root */
  0,                          /* Window window  */
  0,                                /* int depth */
  0,                                    /* int transparency */
  X_DISPLAY_SUPPORT,                    /* int background_grab */
  -1,                                   /* int user_background_image */
  0,                                    /* int managed */
  BASE_EVENT_MASK,                  /* long event_mask */
  0,                                    /* long user_event_mask */
  NULL,                             /* cfgfile_item * params */
  NULL,                             /* vector * menus  */
  NULL,                                 /* vector * images */
  NULL,                             /* vector * fonts */
  NULL,                             /* vector * color_ranges */
  NULL,                             /* vector * color_modifiers */
  NULL,                             /* vector * imlib_filters */
  NULL,                                 /* vector * polygons */
  NULL,                                 /* vector * variables */
  "",                                   /* char * lock_filename */
  NULL,                             /* FILE * lock */
  0,                          /* int quit_flag */
  0,                          /* int restart_flag */
  0                           /* int user_quit_flag */
};

/*----------------------------------------------------------------------------*/
/* Termination handler prototype for adesklets_free() 
 */
void termination_handler(int);

/*----------------------------------------------------------------------------*/
/* Reinstate the menus in pristine state: only one default menu with two
   or three  items: Move (if applicable), Restart (if applicable) 
   and Quit - all managed internally.
   If an already filled menu could not get reset, returns 0 instead 
   of the successful 1.
 */
int
adesklets_menus_reset(void)
{
  int result=0;
  xmenu * menu;

  if (adesklets.menus)
    adesklets.menus=vector_free(adesklets.menus);
  if (!adesklets.menus)
    if ((adesklets.menus=vector_init())) {
      adesklets.menus->vector_free_item=xmenu_vector_free_item;
      menu=xmenu_init();
#ifndef X_DISPLAY_MISSING
      //      if(!xwindow_window_managed(adesklets.display,adesklets.window))
      if (!adesklets.managed)
#endif
      xmenu_push_item(menu,"Move");
      /* A lock file is needed if we want
       the restart mechanism to work */
      if (adesklets.lock) xmenu_push_item(menu,"Restart");
      xmenu_push_item(menu,"Quit");
      vector_push(adesklets.menus,menu);
      result=1;
    }
  return result;
}

/*----------------------------------------------------------------------------*/
/* Recompute the background image based on present main window 
   width and height. Also create or resize foreground image as needed.
   Returns 1 if both final and background images were dutifully produced,
   0 otherwise.
*/
int 
adesklets_images_reset_background(int force_size, ...)
{
  int i, j, old_width, old_height, foreground_active, background_active;
  uint width, height;
  int * pos;
  vector * index;
  va_list ap;
    Imlib_Image image;

  /* Get window dimension by all means necessary */
  if (force_size) {
      va_start(ap,force_size);
      width=va_arg(ap,uint);
      height=va_arg(ap,uint);
      va_end(ap);
  } else
#ifndef X_DISPLAY_MISSING
    if (!xwindow_window_size(adesklets.display,adesklets.window,&width,&height))
#endif
      width=height=1;

  /* Save context states */
  xwindow_context_save(IMLIB_BLEND|IMLIB_COLOR|IMLIB_IMAGE);

  /* Record if Imlib's context image has to be changed at the end */
  image=imlib_context_get_image();
  foreground_active=(image && image==adesklets.images->content[0]);
  background_active=(image && image==adesklets.images->content[1]);
  
  /* Determine what images to resize */
  if ((index=vector_init())) {
    /* Always resize foreground */
    if((pos=malloc(sizeof(int)))) {
      *pos=0;
      vector_push(index,pos);
    }
    /* Resize background when:
       - We do not have X support
       - We have X support, but there is no X connection or no window
       - We have X support, there is a valid X connection and window,
         but we do not grab the background
     */
    if(!X_DISPLAY_SUPPORT || 
       !adesklets.background_grab || 
       !adesklets.display || !adesklets.window) {
      if((pos=malloc(sizeof(int)))) {
      *pos=1;
      vector_push(index,pos);
      }
    }
    /* Resize user selected background when:
       - It exists
     */
    if(adesklets.user_background_image!=-1) {
      if ((pos=malloc(sizeof(int)))) {
      *pos=adesklets.user_background_image;
      vector_push(index,pos);
      }
    }
  }
  
  /* Create/update image(s) */
  for(j=0;index && j<index->pos;++j) {
    i=*((int*)index->content[j]);
    if (!adesklets.images->content[i]) {
      /* Create new final window image */
      if ((adesklets.images->content[i]=imlib_create_image(width,height))) {
      /* Select it */
      imlib_context_set_image(adesklets.images->content[i]);
      
      /* Make sure it has an alpha channel */
      imlib_image_set_has_alpha(1);
      
      /* Fill image with transparent black for foreground, 
       and opaque black for background, if applicable */
      imlib_context_set_blend(0);
      imlib_context_set_color(0, 0, 0, (i==0)?0:255);
      imlib_image_fill_rectangle(0,0,width,height);
      }
    } else {
      /* Update (by resizing image) */
      imlib_context_set_image(adesklets.images->content[i]);
      old_width=imlib_image_get_width();
      old_height=imlib_image_get_height();
      if((width!=old_width || height!=old_height) &&
       (image=imlib_create_image(width,height))){
      /* Need resizing */
      imlib_context_set_image(image);
      
      /* Make sure it has an alpha channel */
      imlib_image_set_has_alpha(1);
      
      /* Fill image with opaque black */
      imlib_context_set_blend(0);
      imlib_context_set_color(0,0,0,255);
      imlib_image_fill_rectangle(0,0,width,height);
      
      /* Finally, copy the original foreground image, with scaling */
      imlib_blend_image_onto_image(adesklets.images->content[i],1,
                             0,0,old_width,old_height,
                             0,0,width,height);
      
      /* Clean up : free original image */
      imlib_context_set_image(adesklets.images->content[i]);
      imlib_free_image();
      adesklets.images->content[i]=image;
      }
    }
  }

#ifndef X_DISPLAY_MISSING
  if(adesklets.background_grab && adesklets.display && adesklets.window) {
    /* If it exists, free background image */
    adesklets.images->content[1]=
      image_vector_free_item(adesklets.images->content[1]);
    
    /* Create new background image */
    adesklets.images->content[1]=
      xwindow_grab_background(adesklets.display,adesklets.params->scr,
                        adesklets.window);
    if (adesklets.user_event_mask&BackgroundGrabMask)
      event("backgroundgrab\n");
  }
#endif
  /* Free index, if applicable */
  vector_free(index);

  /* Switch back to original context */
  xwindow_context_restore();
  
  /* Modify active image if it was originally set on foreground */
  if(foreground_active) imlib_context_set_image(adesklets.images->content[0]);
  if(background_active) imlib_context_set_image(adesklets.images->content[1]);

  return adesklets.images->content[0] && adesklets.images->content[1];
}

/*----------------------------------------------------------------------------*/
/* Reinstate the image vector in pristine state, 
   including the regeneration of final and background image.
   Take care of dangling context image, if applicable. 
   Returns 1 if successful, 0 in case of failure. 
*/
int 
adesklets_images_reset(void)
{
  int result=0;
  if (adesklets.images)
    adesklets.images=vector_free(adesklets.images);
  if (!adesklets.images)
    if((adesklets.images=vector_init())) {
      adesklets.images->vector_free_item=image_vector_free_item;
      adesklets.user_background_image=-1;
      /* Recreate Final window and background images */
      if((result=adesklets_images_reset_background(0))) {
      adesklets.images->pos=2;
      /* Reset current image if useful */
      if (imlib_context_get_image()!=adesklets.images->content[0] &&
          imlib_context_get_image()!=adesklets.images->content[1])
        imlib_context_set_image(adesklets.images->content[0]);
      }
    }
  return result;
}

/*----------------------------------------------------------------------------*/
/* Set/Reset main window. Also call adesklets_menu_reset and
   adeslets_images_reset as needed. */
int
adesklets_window_reset(int managed)
{
  int result=0;
#ifndef X_DISPLAY_MISSING
  int mapped;
  uint width, height;
  XWindowAttributes attr;
  XTextProperty text_prop_name;
  Atom atom;
  const char * name = PACKAGE;
  const long valuemask = CWBackPixmap;

  /* Determine if the old window was mapped, then destroy it as needed */
  if(adesklets.display) {
    if(adesklets.window) {
      mapped=(XGetWindowAttributes(adesklets.display,
                           adesklets.window,&attr))?
      (attr.map_state!=IsUnmapped):0;
      XDestroyWindow(adesklets.display,adesklets.window);
    } else 
      mapped=0;

    /* Determine new window dimensions */
    width=(adesklets.window)?attr.width:1;
    height=(adesklets.window)?attr.height:1;

    xwindow_error_reset();
    /* Create main desklet window */
    adesklets.root=(managed)?
      RootWindow(adesklets.display,adesklets.params->scr):
      xwindow_get_root_window(adesklets.display,
                        adesklets.params->scr);

    adesklets.window=
      XCreateWindow(adesklets.display,
                adesklets.root,
                adesklets.params->x, adesklets.params->y, 
                width, height, 0,
                DefaultDepth(adesklets.display,
                         adesklets.params->scr),
                InputOutput,
                adesklets.visual,
                (managed)?valuemask:(valuemask|CWOverrideRedirect),
                &XDefaultWindowAttributes);

    if (xwindow_error_check()) {
      /* Set this window size */
      xwindow_resize_window(adesklets.display,adesklets.window,
                      adesklets.params,width,height,1);
      /* Set this window event mask */
      XSelectInput(adesklets.display,adesklets.window,adesklets.event_mask);

      /* Set this window as imlib2's default drawable */
      imlib_context_set_drawable(adesklets.window);
      
      /* Set window stacking order, and various properties if applicable */
      if(managed) {
      XRaiseWindow(adesklets.display,adesklets.window);
      /* Window name */
      if (XmbTextListToTextProperty(adesklets.display,
                              (char**)&name,1,
                              XCompoundTextStyle,
                              &text_prop_name)==Success)
        XSetWMName(adesklets.display, adesklets.window, &text_prop_name);
      
      /* Window delete protocol registration */
      if ((atom=XInternAtom(adesklets.display,
                        "WM_DELETE_WINDOW",False))!=None)
        XSetWMProtocols(adesklets.display, 
                    adesklets.window, &atom, 1);
      }
      else
      XLowerWindow(adesklets.display,adesklets.window);
      
      /* Map the window if needed */
      if (mapped) XMapWindow(adesklets.display,adesklets.window);
      
      /* Eventually add capture of PropertyNotify on root window:
       used for dynamic background reinitialisation */
      XSelectInput(adesklets.display,
               adesklets.root, 
               ((adesklets.background_grab)?PropertyChangeMask:0));

      /* Store new value */
      adesklets.managed = managed;

      result=1;
    } else
      adesklets.window=(Window)0;
  } else
    adesklets.window=(Window)0;
#endif
  return result;
}

/*----------------------------------------------------------------------------*/
/* Reste to nothing the vector of fonts, color_ranges and color_modifiers. 
   Returns 1 if successful, 0 otherwise.
*/
#define ADESKLETS_RESET_FUNCTION(name)\
int \
adesklets_ ## name ## s_reset(void)\
{\
  int result=0;\
  if(adesklets.name ## s)\
    adesklets.name ## s=vector_free(adesklets.name ## s);\
  if(!adesklets.name ## s) {\
    if((adesklets.name ## s=vector_init())) {\
      adesklets.name## s->vector_free_item=\
      name ## _vector_free_item;\
      imlib_context_set_ ## name(NULL);\
      result=1;\
    }\
  }\
  return result;\
}

ADESKLETS_RESET_FUNCTION(font)
ADESKLETS_RESET_FUNCTION(color_range)
ADESKLETS_RESET_FUNCTION(color_modifier)
ADESKLETS_RESET_FUNCTION(filter)
#undef ADESKLETS_RESET_FUNCTION

/*----------------------------------------------------------------------------*/
/* Reset to nothing a generic vector of something; you need
   to provide a reference to the vector and another to a 
   vector_free_item_func function
*/
int
adesklets_generic_reset(vector ** vec, vector_free_item_func func)
{
  int result=0;
  if(*vec)
    *vec=vector_free(*vec);
  if(!(*vec)) {
    if((*vec=vector_init())) {
      (*vec)->vector_free_item=func;
      result=1;
    }
  }
  return result;
}

/*----------------------------------------------------------------------------*/
/* Generate placeholder function using preceeding generic function
*/
#define ADESKLETS_RESET_FUNCTION(name) \
int \
adesklets_ ## name ## s_reset(void) \
{ \
  return adesklets_generic_reset(&adesklets.name ## s,\
                                 name ## _vector_free_item);\
}

ADESKLETS_RESET_FUNCTION(polygon)
ADESKLETS_RESET_FUNCTION(variable)
#undef ADESKLETS_RESET_FUNCTION

/*----------------------------------------------------------------------------*/
/* Wrapper for xmenu_fire() that intercepts non-maskable events
   from default menu ("Move", "Restart" and "Quit" events)
*/
int
adesklets_menu_fire(int index, char ** return_str)
{
#ifndef X_DISPLAY_MISSING
  int result=0;
  if(index>=0 && index<adesklets.menus->pos) {
    *return_str=xmenu_fire(adesklets.display,adesklets.params->scr,
                     adesklets.window, 
                     adesklets.images->content[
                        (adesklets.user_background_image==-1)?
                        1:adesklets.user_background_image],
                     adesklets.images->content[0],
                     adesklets.transparency,
                     MENU(index));
    /* Intercept default actions move and quit on the way back */ 
    if(index==0 && *return_str) {
      /* For move: verify the main window is not managed,
       to avoid false move due to user-added "Move" */
      if (
#ifndef X_DISPLAY_MISSING
        !adesklets.managed && 
#endif
        strcmp(*return_str,"Move")==0) {
      if(xwindow_move_window(adesklets.display,
                         adesklets.root, adesklets.window,
                         adesklets.params)) {
        XMapWindow(adesklets.display,adesklets.window);
        if(!adesklets.params->no_update)
          cfgfile_update(adesklets.params);
      }
      *return_str=NULL;
      } else {
      /* For restart: verify there is a lock file open,
         to avoid false restart due to user-added "Restart"
         item in default menu */
      if(adesklets.lock && strcmp(*return_str,"Restart")==0) {
        debug("Restart!\n");
        adesklets.restart_flag=1;
        *return_str=NULL;
      } else {
        if(strcmp(*return_str,"Quit")==0) {
          adesklets.user_quit_flag=adesklets.quit_flag=1;
          debug("Quit!\n");
          *return_str=NULL;
        }
      }
      }
    }
    result=1;
  }
  return result;
#else
  return 0;
#endif
}

/*----------------------------------------------------------------------------*/
/* Return 1 if current image is potentially shown on screen, 0 otherwise.
   Mainly used to determine needs for screen updates */
int
image_is_shown()
{
  Imlib_Image image;
  image = imlib_context_get_image();

  return (image==adesklets.images->content[0]) ||
    (adesklets.transparency &&
     ((adesklets.user_background_image!=-1 && 
       image==adesklets.images->content[adesklets.user_background_image]) ||
      (image==adesklets.images->content[1])));
}

/*----------------------------------------------------------------------------*/
void usage(const char * name)
{
  printf("Usage: %s [OPTIONS] [script_id]\n", name);
  printf("adesklets interpreter and desklets launcher\n\
\n\
Options:\n\
  -h, --help                  Display this help message\n\
  -v, --version               Get package version\n\
  -f, --file                  In interpreter mode, use file as\n\
                        input stream instead of stdin\n\n"); 
}

/*----------------------------------------------------------------------------*/
int
adesklets_init(int argc, char ** argv)
{
  int pos=1, result=0;
  char * adesklets_id;
  char str[CFGFILE_NAME_SIZE];
  FILE * file;
  struct flock lock;
  struct sigaction new_action, old_action;

  const char * OPTIONS[] = {"-h", "--help", "-f", "--file", "-v", "--version" };

  /* Seek --help string: otherwise, it is either a script name of junk */
  if(argc>=2) {
    if(strncmp(argv[1],OPTIONS[0],strlen(OPTIONS[0]))==0 ||
       strncmp(argv[1],OPTIONS[1],strlen(OPTIONS[1]))==0) {
      usage(argv[0]); 
      return 0;
    } else {
      if (strncmp(argv[1],OPTIONS[4],strlen(OPTIONS[4]))==0 ||
        strncmp(argv[1],OPTIONS[5],strlen(OPTIONS[5]))==0) {
      printf("%s %s\n",PACKAGE,VERSION);
      return 0;
      } else {
      if (strncmp(argv[1],OPTIONS[2],strlen(OPTIONS[2]))==0 ||
          strncmp(argv[1],OPTIONS[3],strlen(OPTIONS[3]))==0) {
        if(argc>=3) {
          if (!((file=fopen(argv[2],"r"))&&
              dup2(fileno(file),fileno(stdin))>=0)) {
            welcome(stderr);
            fprintf(stderr,"Could not open file '%s' for reading\n",
                  argv[2]);
            return 0;
          }
        } else {
          usage(argv[0]);
          return 0;
        }
        pos+=2;
      }
      }
    }
  }

  /* Get original parent process id */
  adesklets.ppid=getppid();

  /* Get desklet ID from environment */
  adesklets_id = getenv("ADESKLETS_ID");

  /* Set stdout and stderr to be unbuffered: this is needed 
     for proper pipe operation. stderr is always 
     unbuffered */
  if (setvbuf(stdout,NULL,_IONBF,0)!=0) {
    fprintf(stderr,"Could not remove stdout buffer\n");
    return 0;
  }
  if (setvbuf(stderr,NULL,_IONBF,0)!=0) {
    fprintf(stderr,"Could not remove stderr buffer\n");
    return 0;
  }

  /* Determine if interactive use */
  command.interactive=isatty(fileno(stdin));

   /* Retrieve all parameters from config file */
  adesklets.params = cfgfile_getinfo((!command.interactive)?argv[pos]:NULL,
                             ((uint)(adesklets_id)?
                              atoi(adesklets_id):-1));

  /* Make sure ADESKLETS_ID is set in current environment */
  if(!adesklets_id)
    if (sprintf(str,"%u",adesklets.params->id)>0)
      setenv("ADESKLETS_ID",str,1);

  /* If interactive use, print welcome message */
  if(command.interactive) {
    welcome(stdout);
    printf("Press TAB for hints.\n");
  /* But if not, build and acquire lock file name */
  } else if (adesklets_valid_desklet(argv[pos],0)) {
    strncpy(str,argv[1],CFGFILE_NAME_SIZE-1);
    str[CFGFILE_NAME_SIZE-1]=0;
    if (snprintf(adesklets.lock_filename,CFGFILE_NAME_SIZE-1,
             "%s/%s_uid%u_%s_%u.lock",
             LOCKFILES_DIR,
             PACKAGE,
             getuid(),
             (char*)basename(str),
             adesklets.params->id)<CFGFILE_NAME_SIZE)
      adesklets.lock_filename[CFGFILE_NAME_SIZE-1]=0;
      /* Now, lock the file: this will wait forever */
      if ((adesklets.lock=fdopen(open(adesklets.lock_filename,
                              O_CREAT|O_TRUNC|O_WRONLY,
                              S_IRUSR|S_IWUSR),
                         "w"))) {
      lock.l_type=F_WRLCK;
      lock.l_whence=SEEK_SET;
      lock.l_start=0;
      lock.l_len=0;
      debug("Lock file: acquiring %s\n",adesklets.lock_filename);
      TRY_RESET;
      TRY(fcntl(fileno(adesklets.lock),F_SETLKW,&lock));
      if (TRY_SUCCESS) {
        /* Write PPID and PID to lock file */
        fprintf(adesklets.lock,"%d %d\n",adesklets.ppid,getpid());
        fflush(adesklets.lock);
      } else {
        debug("Lock file: could not get lock\n");
        fclose(adesklets.lock);
        adesklets.lock=NULL;
      }
      }
  }

  /* Force config file entry removal (or, at least, no registration)
     at next update if invalid */
  adesklets.params->no_update=!
    adesklets_valid_desklet(adesklets.params->applet,1);

#ifndef X_DISPLAY_MISSING
  /* Perform X Windows initialisation */
  if ((adesklets.display=XOpenDisplay(NULL))) {
    /* Correct screen determination */
    adesklets.params->scr=(adesklets.params->scr>=0 &&
                     adesklets.params->scr<
                     ScreenCount(adesklets.display))?
                             adesklets.params->scr:
                             DefaultScreen(adesklets.display);

    /* X related imlib2 settings */
    adesklets.visual=imlib_get_best_visual(adesklets.display,
                                 adesklets.params->scr,
                                 &adesklets.depth);
    imlib_context_set_display(adesklets.display);
    imlib_context_set_visual(adesklets.visual);
    imlib_context_set_colormap(DefaultColormap(adesklets.display,
                                     adesklets.params->scr));

    /* Create main desklet window: managed if interactive, 
       unmanaged if not */
    adesklets_window_reset(command.interactive);
    /* Install custom error handler */
    XSetErrorHandler(xwindow_non_fatal_error_handler);
  }
#ifdef DEBUG
  else
    debug("Could not connect to X server '%s'\n",XDisplayName(NULL));
#endif
#endif

  /* Locate true type fonts system-wide */
  xwindow_locate_truetype_fonts();
      
  /* Various Others imlib2 settings */
  imlib_set_cache_size(2048*1024);
  imlib_set_font_cache_size(512*1024);
  imlib_set_color_usage(128);
  imlib_context_set_dither(1);
  imlib_context_set_blend(1);
  imlib_context_set_color(255,255,255,255);

  /* Set events in proper echo mode: no echo if interactive, echo otherwise. */
  events_echo=!command.interactive;

  /* Initial settings */
  if (adesklets_menus_reset()) {
    if (adesklets_images_reset()) {
      if (adesklets_fonts_reset()) {
      if (adesklets_color_ranges_reset()) {
        if (adesklets_color_modifiers_reset()) {
          if (adesklets_filters_reset()) {
            if (adesklets_polygons_reset()) {
            if (adesklets_variables_reset()) {
              /* Setup command interpreter */
              if(command_interpreter_reset()) {
#ifdef FORCE_EXTENDED_CHARACTERS_INPUT
              rl_variable_bind("input-meta", "on");
              rl_variable_bind("convert-meta", "off");
              rl_variable_bind("output-meta", "on");
#endif
                /* Finally, set up event handler. This code snipset
                   was copied verbatim from the GNU C Library
                   Reference Manual (sigaction Function 
                   Example section) */
                new_action.sa_handler = termination_handler;
                sigemptyset (&new_action.sa_mask);
                new_action.sa_flags = 0;
                sigaction (SIGINT, NULL, &old_action);
                if (old_action.sa_handler != SIG_IGN)
                  sigaction (SIGINT, &new_action, NULL);
                sigaction (SIGHUP, NULL, &old_action);
                if (old_action.sa_handler != SIG_IGN)
                  sigaction (SIGHUP, &new_action, NULL);
                sigaction (SIGTERM, NULL, &old_action);
                if (old_action.sa_handler != SIG_IGN)
                  sigaction (SIGTERM, &new_action, NULL);
                /* If applicable, make an initial setup of
                   config file, just in case */
                if (X_DISPLAY_SUPPORT && 
                  adesklets.display && adesklets.window)
                  cfgfile_update(adesklets.params);
                result=1;
                event("ready!\n");
              } else
                fprintf(stderr, "Cannot initialize command interpreter\n");
            } else 
              fprintf(stderr, "Cannot initialize variables\n");
            } else
            fprintf(stderr, "Cannot initialize imlib polygons\n");
          } else
            fprintf(stderr, "Cannot initialize imlib filters\n");
        } else
          fprintf(stderr, "Cannot initialize imlib color modifiers\n");
      } else 
        fprintf(stderr, "Cannot initialize imlib color ranges\n");
      } else
      fprintf(stderr, "Cannot initialize imlib fonts\n");
    } else
      fprintf(stderr, "Cannot initialize imlib images\n");
  } else
    fprintf(stderr, "Cannot initialize menus\n");

  return result;
}

/*----------------------------------------------------------------------------*/
void
adesklets_events_loop(void)
{
  char *menu_str;
  var_item * variable;
  char ** list;
  int x,y,i,j,k;
  uint width, height;
#ifndef X_DISPLAY_MISSING
  long mask;
#endif
  double angle;
  struct timespec sleep_time;
  command_enum command_type;
  vector * params;
#ifndef X_DISPLAY_MISSING
  XEvent ev;
#endif
#ifdef HAVE_READLINE_HISTORY_H
  HIST_ENTRY ** history;
  FILE * file;
#endif
#ifdef HAVE_ICONV_H
  iconv_t cd;
#endif
  Imlib_Updates updates;
  Imlib_Image image;
  Imlib_Color color;
  Imlib_Font font;
  Imlib_Color_Range color_range;
  Imlib_Color_Modifier color_modifier;
  Imlib_Filter filter;
  ImlibPolygon polygon;
  Imlib_Load_Error error;
  DATA32 * data;
  DATA8  * tables[4];

  debug("---------------------------------------------------------------\n");
  do {
    updates = imlib_updates_init();
    if (command.ready) {
      if (command.line) {
      command.message_out=0;
      variable_expansion(adesklets.variables,&command.line);
      params=command_splitter(command.line,&command_type);
      
      if (!command.recording || 
          command_type==CMD_PLAY ||
          command_type==CMD_START_RECORDING ||
          command_type==CMD_STOP_RECORDING) {
      switch(command_type) {
      case CMD_TIME_GATE:
        /* NOTE : for semi-automated generation of an adesklets' 
           API for scripting languages, you should include
           a prototype declaration similar to this one
           in a comment (multi-lines comments allowed)
           directly below case declaration. Look at protoize.sh
           for further details. Commands that are also
           Imlib2 primitives do not need to have prototypes 
           most of the time.

           prototype(double gate) */
        if (command.replay_pos) {
          if (params->pos>=2) {
            angle=atof(params->content[1]);           
#ifndef X_DISPLAY_MISSING
            if (command.replay_abort_on_events) {
            sleep_time.tv_sec=0; sleep_time.tv_nsec=X_POLLING_PERIOD/10;
            while (angle>command_gate_chronometer())
              if (adesklets.display && adesklets.window && 
                  (XCheckWindowEvent(adesklets.display,
                               adesklets.root,
                               PropertyChangeMask, &ev) || 
                   XCheckWindowEvent(adesklets.display,adesklets.window,
                               adesklets.event_mask,&ev) ||
                   XCheckTypedWindowEvent(adesklets.display,adesklets.window,
                                    ClientMessage,&ev))) {
                XPutBackEvent(adesklets.display,&ev);
                break;
              } else
                nanosleep(&sleep_time,NULL);
            } else {
#endif
            if ((angle-=command_gate_chronometer())>0) {
              sleep_time.tv_sec=(time_t)angle;
              sleep_time.tv_nsec=(long)((angle-floor(angle))*1E9);
              /*
              debug("Sleep time: %f, or %d %d\n",
                  angle,sleep_time.tv_sec,sleep_time.tv_nsec);
              */
              nanosleep(&sleep_time,NULL);
            }
#ifndef X_DISPLAY_MISSING
            }
#endif
          } else
            command_error("time gate not given\n");
        } else
          command_error("ignoring timer gate, interpreter not replaying\n");
        break;
      case CMD_HELP:
        /* prototype([const char * command]) */
        if(params->pos>=2) {
          for(i=0;
            COMMANDS[i].name && 
              strcmp(params->content[1],COMMANDS[i].name);
            ++i);
          if (COMMANDS[i].name)
            command_ok("%s - %s\n",COMMANDS[i].name, COMMANDS[i].doc);
          else
            command_error("no help on '%s'\n", (char*)params->content[1]);
        } else {
          for(i=0;COMMANDS[i].name;++i)
           command_printf("%-25s -\t%s\n",COMMANDS[i].name, COMMANDS[i].doc);
        }
        break;
      case CMD_PING:
        /* prototype(void) */
        command_ok("pong!\n");
        break;
      case CMD_PAUSE:
        /* prototype([int delay]) */
        i=(params->pos>=2)?
          (((i=atoi(params->content[1]))>0)?i:5):5;
        debug("Pausing for %d seconds.\n",i);
        sleep(i);
        break;
      case CMD_VERSION:
        /* prototype(void) */
        command_ok("%s %s\n",PACKAGE,VERSION);
        break;
      case CMD_GET_ID:
        /* prototype(void) */
        command_ok("adesklets id %u\n", adesklets.params->id);
        break;
      case CMD_HISTORY:
        /* prototype([const char * filename]) */
#ifdef HAVE_READLINE_HISTORY_H
        if ((history=history_list())) {
          for(i=0;history[i];++i);
         command_printf("%d commands in history\n",i);
          if((file=(params->pos>=2)?
            fopen(command_subsplitter(command.line,1),"w"):stdout)) {
            for(i=0;history[i];++i)
            if (params->pos>=2 || !command.interactive)
              fprintf(file,"%s\n",history[i]->line);
            else
              fprintf(file,"%d\t%s\n",i,history[i]->line);
            if(file!=stdout) fclose(file);
          } else
            command_error("could not open output file for writing\n");
        } else
          command_error("could not retrieve history list\n");
#else
        command_error("history support not compiled in\n");
#endif
        break;
      case CMD_SET:
        /* prototype([const * char name, const * char value]) */
        if ((i=params->pos)>1) {
          /* Verify variable name does not include a dollar character */
          for(j=0;
            ((char*)params->content[1])[j] && 
              ((char*)params->content[1])[j]!='$';
            ++j);
          if (j==strlen((char*)params->content[1])) {
            /* First, search for existing variable */
            variable=(var_item*)
            vector_find(adesklets.variables,(uint*)&j,
                      variable_search_func,(void*)params->content[1]);

            /* Then, if it exists, just delete it */
            if (variable)
            vector_delete(adesklets.variables,(uint)j);
            else 
            if (i==2)
              command_error("variable '%s' does not exist\n",
                        params->content[1]);

            if (i>2) {
            /* Then, set it back if there is a new content */
            vector_push(adesklets.variables,
                      (void*)variable_create(
                         (char*)params->content[1],
                         (char*)command_subsplitter(command.line,2)));
            }
          } else
            command_error("variable name contains '$'\n");
        } else {
          /* Print out all variables */
         command_printf("%d variable(s)\n", adesklets.variables->pos);
          for (i=0;i<adesklets.variables->pos;++i)
           command_printf("%s=%s\n",
                 ((var_item*)adesklets.variables->content[i])->name,
                 ((var_item*)adesklets.variables->content[i])->value);
        }
        break;
      case CMD_UNSET_ALL:
        /* prototype(void) */
        adesklets_variables_reset();
        break;
      case CMD_ECHO:
        /* prototype(const char * string) */
        break;
      case CMD_START_RECORDING:
        /* prototype(void) */
#ifdef HAVE_READLINE_HISTORY_H
        /* This is a special case: you have to make sure to abort
           current macro recording if called recursively from direct mode.

           But this is not enough: you also need to ckeck we are not inside
           a replay loop (indirect mode) because it would still be possible 
           to insert hidden calls to 'start_recording' inside a macro using 
           textual expansion (text variables) */
        if (!command.recording && !command.replay_pos)
          command.recording=history_size()+1;
        else {
          /* In non interactive mode, purge newly created history
             entries */
          if (command.recording && !command.interactive)
            for(i=history_size()-1;i>=command.recording-1;--i)
            free_history_entry(remove_history(i));
          command.recording=command.replay_pos=0;
          command_error("cannot call this while already recording or \
replaying, aborded\n");
        }
#else
        command_error("compiled without GNU history support\n");
#endif
        break;
      case CMD_STOP_RECORDING:
        /* prototype(void) */
#ifdef HAVE_READLINE_HISTORY_H
        if (!command.replay_pos) {
          if (command.recording) {
            --command.recording;
            j=history_size()-1;
            if(!command.interactive)
            /* In case of non interactive use, remove
               the reference to the 'stop_record' command */
            free_history_entry(remove_history(j));
            if (command.recording!=j)
            command_ok("recorded_commands %d %d\n",
                     command.recording,
                     j-1);
            else
            command_error("no command recorded\n");
          } else
            command_error("no recording taking place right now\n");
        } else
          command_error("cannot call stop while replaying, replay aborded\n");
        command.recording=0;
#else
        command_error("compiled without GNU history support\n");
#endif
        break;
      case CMD_PLAY_GET_ABORT_ON_EVENTS:
        /* prototype(void) */
        command_ok("abort_on_event %d\n",command.replay_abort_on_events);
        break;
      case CMD_PLAY_SET_ABORT_ON_EVENTS:
        /* prototype(bool abort) */
        if (!command.replay_pos) {
          if (params->pos>=2)
            command.replay_abort_on_events=atoi((char*)params->content[1]);
          else
            command_error("abort on event value not given\n");
        } else
          command_error("cannot be called inside a replay\n");
        break;
      case CMD_PLAY:
        /* prototype(int beginning, int end) */
#ifdef HAVE_READLINE_HISTORY_H
        if (!command.recording && !command.replay_pos) {
          if (params->pos>=3) {
            if (((i=atoi(params->content[1]))<(j=history_size())) &&
              ((k=atoi(params->content[2]))<j)) {
            if (i>=0 && k>=0 && (i<=k)) {
              gettimeofday(&command.replay_time,NULL);
              command.replay_pos=i+1;
              command.replay_stop=k;
              events_delay=1;
            } else
              command_error("invalid limits\n");
            } else
            command_error("limits out of range\n");
          } else 
            command_error("missing start and stop limits\n");
        } else {
          command.recording=command.replay_pos=0;
          command_error("cannot call this now, aborded\n");
        }
#else
        command_error("compiled without GNU history support\n");
#endif
        break;
      case CMD_CONTEXT_GET_DITHER:
        command_ok("context dither %hhu\n",imlib_context_get_dither());
        break;
      case CMD_CONTEXT_GET_ANTI_ALIAS:
        command_ok("context antialias %hhu\n",imlib_context_get_anti_alias());
        break;
      case CMD_CONTEXT_GET_BLEND:
        command_ok("context blend %hhu\n",imlib_context_get_blend());
        break;
      case CMD_CONTEXT_GET_OPERATION:
        i=imlib_context_get_operation();
        command_ok("context operation %d (%s)\n", 
                 i, OPERATIONS[i]);
        break;
      case CMD_CONTEXT_GET_CLIPRECT:
        /* prototype(void) */
        imlib_context_get_cliprect(&x,&y,&i,&j);
        command_ok("context cliprect %d %d %d %d\n",x,y,i,j); 
        break;
      case CMD_CONTEXT_GET_IMAGE:
        image=imlib_context_get_image();
        for(i=0;i<adesklets.images->pos;++i)
          if(adesklets.images->content[i]==image)
            command_ok("context image %d\n",i);
        break;
      case CMD_CONTEXT_GET_FONT:
         if ((font=imlib_context_get_font())) {
          for(i=0;i<adesklets.fonts->pos;++i)
            if(adesklets.fonts->content[i]==font)
            command_ok("context font %d\n",i);
        } else
            command_ok("context font -1 (unset)\n");
         break;
      case CMD_CONTEXT_GET_COLOR_RANGE:
        if ((color_range=imlib_context_get_color_range())) {
          for(i=0;i<adesklets.color_ranges->pos;++i)
            if(adesklets.color_ranges->content[i]==color_range)
            command_ok("context colorrange %d\n",i);
        } else
            command_ok("context colorrange -1 (unset)\n");
        break;
      case CMD_CONTEXT_GET_COLOR_MODIFIER:
        if ((color_modifier=imlib_context_get_color_modifier())) {
          for(i=0;i<adesklets.color_modifiers->pos;++i)
            if(adesklets.color_modifiers->content[i]==color_modifier)
            command_ok("context colormodifier %d\n",i);
        } else
            command_ok("context colormodifier -1 (unset)\n");
        break;
      case CMD_CONTEXT_GET_FILTER:
        if ((filter=imlib_context_get_filter())) {
          for(i=0;i<adesklets.filters->pos;++i)
            if(adesklets.filters->content[i]==filter)
            command_ok("context filter %d\n",i);
        } else
            command_ok("context filter -1 (unset)\n");
        break;
      case CMD_CONTEXT_GET_COLOR:
        /* prototype(void) */
        imlib_context_get_color(&x,&y,&i,&j);
        command_ok("context color %hhu %hhu %hhu %hhu\n",
                 x&255,y&255,i&255,j&255);
        break;
      case CMD_CONTEXT_GET_ANGLE:
        angle=imlib_context_get_angle();
        command_ok("context angle %4.2f\n",angle);
        break;
      case CMD_CONTEXT_GET_DIRECTION:
        i=imlib_context_get_direction();
        command_ok("context direction %d (%s)\n",
                 i, DIRECTIONS[i]);
        break;
      case CMD_CONTEXT_SET_DITHER:
        /* prototype(bool dither) */
        if (params->pos>=2)
          imlib_context_set_dither((char)atoi(params->content[1]));
        else
          command_error("dither value not given\n");
        break;
      case CMD_CONTEXT_SET_ANTI_ALIAS:
        /* prototype(bool anti_alias) */
        if (params->pos>=2)
          imlib_context_set_anti_alias((char)atoi(params->content[1]));
        else
          command_error("anti alias value not given\n");
        break;
      case CMD_CONTEXT_SET_BLEND:
        /* prototype(bool blend) */
        if (params->pos>=2)
          imlib_context_set_blend((char)atoi(params->content[1]));
        else
          command_error("blend value not given\n");
        break;
      case CMD_CONTEXT_SET_OPERATION:
        /* prototype(enum OPERATIONS operation) */
         if(params->pos>=2) {
          for(i=0;OPERATIONS[i];++i)
            if(strncmp(OPERATIONS[i],params->content[1],
                   strlen(params->content[1]))==0)
            break;
          imlib_context_set_operation((OPERATIONS[i])?
                              i:((j=atoi(params->content[1])))<4?j:0);
         } else
          command_error("operation not given\n");
         break;
      case CMD_CONTEXT_SET_CLIPRECT:
        if (params->pos>=5) {
          if ((x=atoi((char*)params->content[1]))>=0 &&
            (y=atoi((char*)params->content[2]))>=0 &&
            (i=atoi((char*)params->content[3]))>=0 &&
            (j=atoi((char*)params->content[4]))>=0) {
            imlib_context_set_cliprect(x,y,i,j);
          } else
            command_error("clipping rectangle coordinates out of range\n");
        } else
          command_error("clipping rectangle description not given\n");
        break;
      case CMD_CONTEXT_SET_IMAGE:
        if (params->pos>=2) {
          if ((i=atoi((char*)params->content[1]))>=0 && 
            i<adesklets.images->pos) {
            imlib_context_set_image(adesklets.images->content[i]);
          } else
            command_error("image ID %d out of range\n",i);
        } else
          command_error("image ID not given\n");
        break;
      case CMD_CONTEXT_SET_FONT:
        /* prototype([int font]) */
        j=0;
        if (params->pos>=2) {
          if ((i=atoi((char*)params->content[1]))>=0 && 
            i<adesklets.fonts->pos) {
            imlib_context_set_font(adesklets.fonts->content[i]);
          } else {
            if(i==-1) {
            j=1;
            imlib_context_set_font(NULL);
            } else
            command_error("font ID %d out of range\n",i);
          }
        } else {
          j=1;
          imlib_context_set_font(NULL);
        }
        if(j) command_ok("context font unset\n");
        break;
      case CMD_CONTEXT_SET_COLOR_RANGE:
        /* prototype([int color_range]) */
        j=0;
        if (params->pos>=2) {
          if ((i=atoi((char*)params->content[1]))>=0 && 
            i<adesklets.color_ranges->pos) {
            imlib_context_set_color_range(adesklets.color_ranges->content[i]);
          } else {
            if(i==-1) {
            j=1;
            imlib_context_set_color_range(NULL);
            } else
            command_error("color range ID %d out of range\n",i);
          }
        } else {
          j=1;
          imlib_context_set_color_range(NULL);
        }
        if(j) command_ok("context color range unset\n");
        break;
      case CMD_CONTEXT_SET_COLOR_MODIFIER:
        /* prototype([int color_modifier]) */
        j=0;
        if (params->pos>=2) {
          if ((i=atoi((char*)params->content[1]))>=0 && 
            i<adesklets.color_modifiers->pos) {
            imlib_context_set_color_modifier(
               adesklets.color_modifiers->content[i]);
          } else {
            if(i==-1) {
            j=1;
            imlib_context_set_color_modifier(NULL);
            } else
            command_error("color modifier ID %d out of range\n",i);
          }
        } else {
          j=1;
          imlib_context_set_color_modifier(NULL);
        }
        if(j) command_ok("context color modifier unset\n");
        break;
      case CMD_CONTEXT_SET_FILTER:
        /* prototype([int filter]) */
        j=0;
        if (params->pos>=2) {
          if ((i=atoi((char*)params->content[1]))>=0 && 
            i<adesklets.filters->pos) {
            imlib_context_set_filter(adesklets.filters->content[i]);
          } else {
            if(i==-1) {
            j=1;
            imlib_context_set_filter(NULL);
            } else
            command_error("filter ID %d out of range\n",i);
          }
        } else {
          j=1;
          imlib_context_set_filter(NULL);
        }
        if(j) command_ok("context filter unset\n");
        break;
      case CMD_CONTEXT_SET_COLOR:
        if (params->pos>=5)
          imlib_context_set_color(atoi(params->content[1]),
                            atoi(params->content[2]),
                            atoi(params->content[3]),
                            atoi(params->content[4]));
        else
          command_error("color RGBA description not given\n"); 
        break;
      case CMD_CONTEXT_SET_ANGLE:
        if (params->pos>=2) {
          imlib_context_set_angle(atof(params->content[1]));
        } else
          command_error("angle not given\n");
        break;
      case CMD_CONTEXT_SET_DIRECTION:
        /* prototype(enum DIRECTIONS direction) */
        if(params->pos>=2) {
          for(i=0;DIRECTIONS[i];++i)
            if(strncmp(DIRECTIONS[i],params->content[1],
                   strlen(params->content[1]))==0)
            break;
          imlib_context_set_direction((DIRECTIONS[i])?
                              i:((j=atoi(params->content[1])))<5?j:0);
        } else
          command_error("direction not given\n");
        break;
      case CMD_ADD_COLOR_TO_COLOR_RANGE:
        if(imlib_context_get_color_range()) {
          i=(params->pos>=2)?atoi(params->content[1]):0;
          imlib_add_color_to_color_range(i);
        } else
          command_error("no color range selected\n");
        break;
      case CMD_BLEND_IMAGE_ONTO_IMAGE:
        if (params->pos>=11) {
          if((i=atoi((char*)params->content[1]))>=0 && 
             i<adesklets.images->pos) {
            imlib_blend_image_onto_image(adesklets.images->content[i],
                                 atoi(params->content[2]),
                                 atoi(params->content[3]),
                                 atoi(params->content[4]),
                                 atoi(params->content[5]),
                                 atoi(params->content[6]),
                                 atoi(params->content[7]),
                                 atoi(params->content[8]),
                                 atoi(params->content[9]),
                                 atoi(params->content[10]));
            if (image_is_shown())
            updates = imlib_update_append_rect(updates,
                                       atoi(params->content[7]),
                                       atoi(params->content[8]),
                                       atoi(params->content[9]),
                                       atoi(params->content[10]));
          } else
            command_error("image ID %d out of range\n",i);
        } else
          command_error("not enough parameters given - need ten\n");
        break;
      case CMD_BLEND_IMAGE_ONTO_IMAGE_AT_ANGLE:
        if (params->pos>=11) {
          if((i=atoi((char*)params->content[1]))>=0 && 
             i<adesklets.images->pos) {
            imlib_blend_image_onto_image_at_angle(
                adesklets.images->content[i],
            atoi(params->content[2]),
            atoi(params->content[3]),
            atoi(params->content[4]),
            atoi(params->content[5]),
            atoi(params->content[6]),
            atoi(params->content[7]),
            atoi(params->content[8]),
            atoi(params->content[9]),
            atoi(params->content[10]));
            if (image_is_shown())
            /* We do not bother: we update everything */
            updates = imlib_update_append_rect(updates,
                                       0,0,
                                       imlib_image_get_width(),
                                       imlib_image_get_height());
          } else
            command_error("image ID %d out of range\n",i);
        } else
          command_error("not enough parameters given - need ten\n");      
        break;
      case CMD_BLEND_IMAGE_ONTO_IMAGE_SKEWED:
        if (params->pos>=12) {
          if((i=atoi((char*)params->content[1]))>=0 && 
             i<adesklets.images->pos) {
           imlib_blend_image_onto_image_skewed(adesklets.images->content[i],
                                     atoi(params->content[2]),
                                     atoi(params->content[3]),
                                     atoi(params->content[4]),
                                     atoi(params->content[5]),
                                     atoi(params->content[6]),
                                     atoi(params->content[7]),
                                     atoi(params->content[8]),
                                     atoi(params->content[9]),
                                     atoi(params->content[10]),
                                     atoi(params->content[11]),
                                     atoi(params->content[12]));
           if (image_is_shown())
             /* We do not bother: we update everything */
             updates = imlib_update_append_rect(updates,
                                      0,0,
                                      imlib_image_get_width(),
                                      imlib_image_get_height());
          } else 
            command_error("image ID %d out of range\n",i);
        } else 
          command_error("not enough parameters given - need twelve\n");
        break;
      case CMD_APPLY_FILTER:
        /* WARNING: there is a initialisation bug in imlib2 prior 
           version 1.2.0 (cvs of 11/20/04) that sets the dynamic filters 
           never to work if an image loader is not used
           at least once before (this has to do with
           lt_dlinit() being called at the wrong place...). 
           We can do nothing about this: upgrade your imlib2 lib! 

           prototype(const char * script)
        */
        if(params->pos>=2) {
          menu_str=command_subsplitter(command.line,1);
          if(!strstr(menu_str,"[]")) {
            imlib_apply_filter(menu_str);
            if (image_is_shown())
            updates=imlib_update_append_rect(updates,0,0,
                                     imlib_image_get_width(),
                                     imlib_image_get_height());
          }
          else
            command_error("variadic filters forbidden\n");
        } else
          command_error("filter description not given\n");
        
          /*
          "tint(x=0,y=0,w=100,h=100,alpha=100,red=155,green=25,blue=25);"
          */
        break;
      case CMD_GET_TEXT_SIZE:
        /* prototype(const char * text) */
        if(imlib_context_get_font()) {
          if(params->pos>=2) {
            menu_str=dupstr_utf8(command_subsplitter(command.line,1));
            imlib_get_text_size(menu_str,
                          &i,&j);
            free(menu_str);
            command_ok("text size %d %d\n",i,j);
          } else
            command_error("text string not given or blank\n");
        } else
          command_error("no font selected.\n");
        break;
      case CMD_GET_TEXT_ADVANCE:
        /* prototype(const char * text) */
        if(imlib_context_get_font()) {
          if(params->pos>=2) {
            menu_str=dupstr_utf8(command_subsplitter(command.line,1));
            imlib_get_text_advance(menu_str,&i,&j);
            free(menu_str);
            command_ok("text advance %d %d\n",i,j);
          } else
            command_error("text string not given or blank\n");
        } else
          command_error("no font selected.\n");
        break;
      case CMD_TEXT_DRAW:
        if(imlib_context_get_font()) {
          if(params->pos>=4) {
            menu_str=dupstr_utf8(command_subsplitter(command.line,3));
            imlib_text_draw(atoi(params->content[1]),
                        atoi(params->content[2]),
                        menu_str);    
            if (image_is_shown()) {
            imlib_get_text_size(menu_str,&x,&y);
            updates = imlib_update_append_rect(updates,
                                       atoi(params->content[1]),
                                       atoi(params->content[2]),
                                       x,y);
            }
            free(menu_str);
          } else
            command_error("text string not given or blank\n");
        } else
          command_error("no font selected.\n");
        break;
      case CMD_MODIFY_COLOR_MODIFIER_GAMMA:
        if(imlib_context_get_color_modifier()) {
          if(params->pos>=2) {
            imlib_modify_color_modifier_gamma(atof(params->content[1]));
          } else
            command_error("gamma value not given\n");
        } else
          command_error("no context color modifier selected\n");
        break;
      case CMD_MODIFY_COLOR_MODIFIER_BRIGHTNESS:
         if(imlib_context_get_color_modifier()) {
          if(params->pos>=2) {
            imlib_modify_color_modifier_brightness(atof(params->content[1]));
          } else
            command_error("brightness value not given\n");
        } else
          command_error("no context color modifier selected\n");
        break;
      case CMD_MODIFY_COLOR_MODIFIER_CONTRAST:
        if(imlib_context_get_color_modifier()) {
          if(params->pos>=2) {
            imlib_modify_color_modifier_contrast(atof(params->content[1]));
          } else
            command_error("contrast value not given\n");
        } else
          command_error("no context color modifier selected\n");
        break;
      case CMD_GET_COLOR_MODIFIER_TABLES:
        /* prototype(void) */
        /* Throw all 1024 table entries in RGBA orders */
        if(imlib_context_get_color_modifier()) {
          if((tables[0]=(DATA8*)malloc(sizeof(DATA8)*256))&&
             (tables[1]=(DATA8*)malloc(sizeof(DATA8)*256))&&
             (tables[2]=(DATA8*)malloc(sizeof(DATA8)*256))&&
             (tables[3]=(DATA8*)malloc(sizeof(DATA8)*256))) {
            imlib_get_color_modifier_tables(tables[0],tables[1],
                                    tables[2],tables[3]);
            for(i=0;i<4;++i)
            for(j=0;j<256;++j)
             command_printf("%hhu ", tables[i][j]);
           command_printf("\n");
          } else
            command_error("memory allocation problem\n");
          for(i=0;i<4;++i)
            if(tables[i]) free(tables[i]);
        } else
          command_error("no context color modifier selected\n");
        break;
        break;
      case CMD_SET_COLOR_MODIFIER_TABLES:
        /* prototype(unsigned char * table) */
        if(imlib_context_get_color_modifier()) {
          if (params->pos==1025) {
             if((tables[0]=(DATA8*)malloc(sizeof(DATA8)*256))&&
              (tables[1]=(DATA8*)malloc(sizeof(DATA8)*256))&&
              (tables[2]=(DATA8*)malloc(sizeof(DATA8)*256))&&
              (tables[3]=(DATA8*)malloc(sizeof(DATA8)*256))) {
             for(i=0;i<4;++i)
               for(j=0;j<256;++j)
                 tables[i][j]=(DATA8)atoi(params->content[(i*256)+j+1]);
             imlib_set_color_modifier_tables(tables[0],tables[1],
                                      tables[2],tables[3]);
             command_ok("set_color_modifier_tables\n");
             } else
             command_error("memory allocation problem");
             for(i=0;i<4;++i)
             if(tables[i]) free(tables[i]);
          } else
            command_error("Invalid number of entries - need 1024\n");
        } else
          command_error("no context color modifier selected\n");
        break;
      case CMD_GET_COLOR_MODIFIER_VALUE:
        /* prototype(enum RGBA_TABLES table, int index) */
        /* NOTE: this is not an original imlib2 function.
                 it was included as a convenience for
               interactive use. */
        if(imlib_context_get_color_modifier()) {
          if (params->pos>=3) {
            for(i=0;RGBA_TABLES[i];++i)
            if(strncmp(RGBA_TABLES[i],
                     params->content[1],
                     strlen(params->content[1]))==0)
              break;
            i=(RGBA_TABLES[i])?i:atoi(params->content[1])%4;
            
            if((j=atoi(params->content[2]))<256 && j>=0) {
            if((tables[0]=(DATA8*)malloc(sizeof(DATA8)*256))&&
               (tables[1]=(DATA8*)malloc(sizeof(DATA8)*256))&&
               (tables[2]=(DATA8*)malloc(sizeof(DATA8)*256))&&
               (tables[3]=(DATA8*)malloc(sizeof(DATA8)*256))) {
              imlib_get_color_modifier_tables(tables[0],tables[1],
                                      tables[2],tables[3]);
              command_ok("value %s %hhu\n",
                       RGBA_TABLES[i],
                       (char)tables[i][j]&255);
       
            } else
            command_error("memory allocation problem\n");
            for(i=0;i<4;++i)
              if(tables[i]) free(tables[i]);
            } else
            command_error("index value %d out of range\n",j);
          } else
            command_error("parameters not given - need two\n");
        } else 
          command_error("no context color modifier selected\n");
        break;
      case CMD_SET_COLOR_MODIFIER_VALUE:
        /* prototype(enum RGBA_TABLES table, int index, int value) */
        /* NOTE: this is not an original imlib2 function.
                 it was included as a convenience for
               interactive use. */
        if(imlib_context_get_color_modifier()) {
          if (params->pos>=4) {
            for(i=0;RGBA_TABLES[i];++i)
            if(strncmp(RGBA_TABLES[i],
                     params->content[1],
                     strlen(params->content[1]))==0)
              break;
            i=(RGBA_TABLES[i])?i:atoi(params->content[1])%4;
            
            if((j=atoi(params->content[2]))<256 && j>=0) {
            if ((x=atoi(params->content[3]))<256 && x>=0) {
              if((tables[0]=(DATA8*)malloc(sizeof(DATA8)*256))&&
                 (tables[1]=(DATA8*)malloc(sizeof(DATA8)*256))&&
                 (tables[2]=(DATA8*)malloc(sizeof(DATA8)*256))&&
                 (tables[3]=(DATA8*)malloc(sizeof(DATA8)*256))) {
                imlib_get_color_modifier_tables(tables[0],tables[1],
                                        tables[2],tables[3]);
                tables[i][j]=x;
                imlib_set_color_modifier_tables(tables[0],tables[1],
                                        tables[2],tables[3]);
              } else
                command_error("memory allocation problem\n");
              for(i=0;i<4;++i)
                if(tables[i]) free(tables[i]);
            } else
              command_error("value %d out of range\n",x);
            } else
            command_error("index value %d out of range\n",j);
          } else
            command_error("parameters not given - need three\n");
        } else 
          command_error("no context color modifier selected\n");
        break;
      case CMD_APPLY_COLOR_MODIFIER:
        if(imlib_context_get_color_modifier()) {
          imlib_apply_color_modifier();
          if(image_is_shown())
            updates=imlib_update_append_rect(updates,0,0,
                                     imlib_image_get_width(),
                                     imlib_image_get_height());
        } else
          command_error("no context color modifier selected\n");
        break;
      case CMD_APPLY_COLOR_MODIFIER_TO_RECTANGLE:
        if(imlib_context_get_color_modifier()) {
          if (params->pos>=5) {
            imlib_apply_color_modifier_to_rectangle(
               (x=atoi(params->content[1])),
             (y=atoi(params->content[2])),
             (i=atoi(params->content[3])),
             (j=atoi(params->content[4])));
            if (image_is_shown())
            updates=imlib_update_append_rect(updates,x,y,i,j);
          } else
            command_error("rectangles coordinates not given\n");
        } else
          command_error("no context color modifier selected\n");
        break;
      case CMD_LOAD_IMAGE_WITHOUT_CACHE:
        if (params->pos>=2) {
          menu_str=command_subsplitter(command.line,1);
          if ((image=imlib_load_image_without_cache(menu_str))) {
            if (vector_push(adesklets.images,image))
            command_ok("new image %d\n",adesklets.images->pos-1);
            else
            command_error("memory allocation problem\n");
          } else
            command_error("could not load image '%s'\n", menu_str);
        } else 
          command_error("image file name not given\n");
        break;
      case CMD_LOAD_IMAGE:
        if (params->pos>=2) {
          menu_str=command_subsplitter(command.line,1);
          if ((image=imlib_load_image_with_error_return(menu_str,&error))) {
            if (vector_push(adesklets.images,image))
            command_ok("new image %d\n",adesklets.images->pos-1);
            else
            command_error("memory allocation problem\n");
          } else
            command_error("could not load image '%s' - %s\n",
                      menu_str,LOAD_ERRORS[(int)error]);
        } else 
          command_error("image file name not given\n");
          break;
      case CMD_SAVE_IMAGE:
        if (params->pos>=2) {
          menu_str=command_subsplitter(command.line,1);
          imlib_save_image_with_error_return(menu_str,&error);
          if(error!=IMLIB_LOAD_ERROR_NONE)
            command_error("%s\n",LOAD_ERRORS[(int)error]);
        } else
          command_error("image file name not given\n");
        break;
      case CMD_CREATE_IMAGE:
        if (params->pos>=3) {
          if((i=atoi(params->content[1]))>0 && 
             (j=atoi(params->content[2]))>0) {
            if((image=imlib_create_image(i,j))) {
            xwindow_context_save(IMLIB_IMAGE|IMLIB_BLEND|IMLIB_COLOR);
            imlib_context_set_image(image);
            imlib_image_set_has_alpha(1);
            imlib_context_set_blend(0);
            imlib_context_set_color(0,0,0,0);
            imlib_image_fill_rectangle(0,0,i,j);
            xwindow_context_restore();
            if (vector_push(adesklets.images,image)) 
              command_ok("new image %d\n",adesklets.images->pos-1);
            else
              command_error("memory allocation problem\n");
            } else
            command_error("imlib image allocation error\n");
          } else
            command_error("image dimensions out of range\n");
        } else
          command_error("image dimensions were not given\n");
        break;
      case CMD_CREATE_IMAGE_USING_DATA:
        /* This uses imlib_create_image_using_copied_data(),
           so DATA * data can be freed afterward.
           As in CMD_IMAGE_GET_DATA, data is expected to be 
           RGBA ordered. */
        if (params->pos>=3) {
          if ((width=atoi(params->content[1]))>0 &&
            (height=atoi(params->content[2]))>0) {
            if(width*height*4==params->pos-3) {
            if((data=(DATA32*)malloc(sizeof(DATA32)*width*height))) {
              for(i=0;i<width*height;++i)
                data[i]=
                  ((atoi((char*)params->content[i*4+3])&255)<<16)|
                  ((atoi((char*)params->content[i*4+4])&255)<<8)|
                  ((atoi((char*)params->content[i*4+5])&255)<<0)|
                  ((atoi((char*)params->content[i*4+6])&255)<<24);
              if ((image=imlib_create_image_using_copied_data(width,
                                                  height,
                                                  data))) {
                xwindow_context_save(IMLIB_IMAGE);
                imlib_context_set_image(image);
                imlib_image_set_has_alpha(1);
                xwindow_context_restore();
                if(vector_push(adesklets.images,image))
                  command_ok("new image %d\n",adesklets.images->pos-1);
                else
                  command_error("memory allocation problem");
              } else
                command_error("imlib image allocation error\n");
              free(data);
            }
            else
              command_error("memory allocation problem\n");
            } else
            command_error("image dimensions and data lenght mismatch\n");
          } else
            command_error("image dimensions out of range\n");
        } else
          command_error("image dimensions were not given\n");
        break;
      case CMD_CLONE_IMAGE:    
          if((image=imlib_clone_image())) {
            if (vector_push(adesklets.images,image))
            command_ok("cloned image %d\n",adesklets.images->pos-1);
            else
            command_error("memory allocation problem");
          } else
            command_error("imlib image allocation error\n");
        break;
      case CMD_FREE_IMAGE:
        /* This does not react as imlib_free_image: 
           - image ID has to be given
           - If current context image is freed, context
           is put back on foreground image 
           - If image corresponding to user_background_image
           is freed, user_background_image is reset.

           prototype(int image)
        */
        if(params->pos>=2) {
          if((i=atoi((char*)params->content[1]))<adesklets.images->pos && 
             i>=0) {
            if(i>=2) {
            j=(imlib_context_get_image()==adesklets.images->content[i]); 
              if (vector_delete(adesklets.images,i)) {
                if(i==adesklets.user_background_image) {
                  adesklets.user_background_image=-1;
                  xwindow_context_save(IMLIB_IMAGE);
                  imlib_context_set_image(adesklets.images->content[0]);
                  updates=imlib_update_append_rect(updates,0,0,
                                           imlib_image_get_width(),
                                           imlib_image_get_height());
                  xwindow_context_restore();
                }
                else
                  if(i<adesklets.user_background_image)
                  --adesklets.user_background_image;
                if (j) 
                  imlib_context_set_image(adesklets.images->content[0]);
              } else
                command_error("memory desallocation problem\n");
            } else
            command_error("it is forbidden to unload image %d\n",i);
          } else
            command_error("image ID %d out of range\n",i);
        } else
          command_error("image ID not given\n");
        break;
      case CMD_LOAD_FONT:
        if(params->pos>=2) {
          if (strlen(params->content[1])>=3 &&
            index(params->content[1],'/')) {
            if ((font=imlib_load_font(params->content[1]))) {
            if(vector_push(adesklets.fonts,font))
              command_ok("new font %d\n", adesklets.fonts->pos-1);
            else
              command_error("memory allocation problem");
            } else
            command_error("font '%s' could not be loaded\n",
                        (char*)params->content[1]);
          } else
            command_error(
               "font description incorrect - should be `name/size'\n");
        } else
          command_error("font description not given\n");
        break;
      case CMD_FREE_FONT:
         /* This does not react as imlib_free_font: 
           - font ID has to be given
           - If current font  is freed, context
           is put back on NULL 
           
           prototype(int font)
        */
        if(params->pos>=2) {
          if((i=atoi((char*)params->content[1]))
             <adesklets.fonts->pos && 
             i>=0) {
            j=(imlib_context_get_font()==
             adesklets.fonts->content[i]);
            if (vector_delete(adesklets.fonts,i)) {
            if (j) 
              imlib_context_set_font(NULL);
            } else
            command_error("memory desallocation problem\n");
          } else
            command_error("font ID %d out of range\n",i);
        } else
          command_error("font ID not given\n");
        break;
      case CMD_LIST_FONTS:
        /* prototype(void) */
        list=imlib_list_fonts(&j);
       command_printf("%d fonts found\n",j);
        for(i=0;i<j;++i)
         command_printf("%s ",list[i]);
       command_printf("\n");
        imlib_free_font_list(list,j);
        break;
      case CMD_LIST_FONT_PATH:
        /* prototype(void) */
        list=imlib_list_font_path(&j);
       command_printf("%d font_path found\n",j);
        for(i=0;i<j;++i)
         command_printf("%s\n",list[i]);
        break;
      case CMD_ADD_PATH_TO_FONT_PATH:
        if(params->pos>=2) {
          imlib_add_path_to_font_path(command_subsplitter(command.line,1));
        } else
          command_error("font path not given\n");
        break;
      case CMD_REMOVE_PATH_FROM_FONT_PATH:
        if(params->pos>=2) {
          imlib_remove_path_from_font_path(
             command_subsplitter(command.line,1));
          debug("%s\n",command_subsplitter(command.line,1));
        } else
          command_error("font path not given\n");
        break;
      case CMD_CREATE_COLOR_RANGE:
        if((color_range=imlib_create_color_range())) {
          if(vector_push(adesklets.color_ranges,color_range))
            command_ok("new colorrange %d\n",adesklets.color_ranges->pos-1);
          else
            command_error("memory allocation problem\n");
        } else 
          command_error("imlib allocation problem\n");
        break;
      case CMD_FREE_COLOR_RANGE:
        /* This does not react as imlib_free_color_range: 
           - color_range ID has to be given
           - If current color range is freed, context
           is put back on NULL 

           prototype(int color_range)
        */
        if(params->pos>=2) {
          if((i=atoi((char*)params->content[1]))
             <adesklets.color_ranges->pos && 
             i>=0) {
            j=(imlib_context_get_color_range()==
             adesklets.color_ranges->content[i]);
            if (vector_delete(adesklets.color_ranges,i)) {
            if (j) 
              imlib_context_set_color_range(NULL);
            } else
            command_error("memory desallocation problem\n");
          } else
            command_error("color range ID %d out of range\n",i);
        } else
          command_error("color range ID not given\n");
        break;
      case CMD_CREATE_FILTER:
        /* prototype(void) */
        if((filter=imlib_create_filter(0))) {
          if(vector_push(adesklets.filters,filter))
            command_ok("new filter %d\n",adesklets.filters->pos-1);
          else
            command_error("memory allocation problem\n");
        } else 
          command_error("imlib allocation problem\n");
        break;
      case CMD_FREE_FILTER:
        /* This does not react as imlib_free_filter: 
           - filter ID has to be given
           - If current filter is freed, context
           is put back on NULL
           
           prototype(int filter)
        */
        if(params->pos>=2) {
          if((i=atoi((char*)params->content[1]))
             <adesklets.filters->pos && 
             i>=0) {
            j=(imlib_context_get_filter()==
             adesklets.filters->content[i]);
            if (vector_delete(adesklets.filters,i)) {
            if (j) 
              imlib_context_set_filter(NULL);
            } else
            command_error("memory desallocation problem\n");
          } else
            command_error("filter ID %d out of range\n",i);
        } else
          command_error("filter ID not given\n");
        break;
      case CMD_CREATE_COLOR_MODIFIER:
        if((color_modifier=imlib_create_color_modifier())) {
          if(vector_push(adesklets.color_modifiers,color_modifier))
            command_ok("new colormodifier %d\n",
                   adesklets.color_modifiers->pos-1);
          else
            command_error("memory allocation problem\n");
        } else 
          command_error("imlib allocation problem\n");
        break;
      case CMD_FREE_COLOR_MODIFIER:
        /* This does not react as imlib_free_color_modifier: 
           - color_range ID has to be given
           - If current color modifier is freed, context
           is put back on NULL 

           prototype(int color_modifier)
        */
        if(params->pos>=2) {
          if((i=atoi((char*)params->content[1]))
             <adesklets.color_modifiers->pos && 
             i>=0) {
            j=(imlib_context_get_color_modifier()==
             adesklets.color_modifiers->content[i]);
            if (vector_delete(adesklets.color_modifiers,i)) {
            if (j) 
              imlib_context_set_color_modifier(NULL);
            } else
            command_error("memory desallocation problem\n");
          } else
            command_error("color modifier ID %d out of range\n",i);
        } else
          command_error("color modifier ID not given\n");
        break;
      case CMD_POLYGON_NEW:
        if((polygon=imlib_polygon_new())) {
          if(vector_push(adesklets.polygons,polygon))
            command_ok("new polygon %d\n",adesklets.polygons->pos-1);
          else
            command_error("memory allocation problem\n");
        } else
          command_error("imlib allocation problem\n");
        break;
      case CMD_POLYGON_FREE:
        if(params->pos>=2) {
          if((i=atoi(params->content[1]))>=0 &&
             i<adesklets.polygons->pos) {
            if(!vector_delete(adesklets.polygons,i))
            command_error("memory desallocation problem\n");
          } else
            command_error("polygon ID %d out of range\n",i);
        } else
          command_error("polygon ID not given\n");
        break;
      case CMD_POLYGON_ADD_POINT:
        if(params->pos>=4) {
          if((i=atoi(params->content[1]))>=0 && i<adesklets.polygons->pos) {
            imlib_polygon_add_point(adesklets.polygons->content[i],
                              atoi(params->content[2]),
                              atoi(params->content[3]));
          } else
            command_error("polygon ID %d out of range\n",i);
        } else
          command_error("not enough parameters given - need 3\n");
        break;
      case CMD_IMAGES_RESET_ALL:
        /* prototype(void) */
        adesklets_images_reset();
        break;
      case CMD_IMAGES_INFO:
        /* prototype(void) */
        xwindow_context_save(IMLIB_IMAGE);
       command_printf("%d images\n",adesklets.images->pos);
        for(i=0;i<adesklets.images->pos;++i) {
          imlib_context_set_image(adesklets.images->content[i]);
         command_printf("id %d width %d height %d alpha %hhu filename %s\n",
               i, 
               imlib_image_get_width(), imlib_image_get_height(),
               imlib_image_has_alpha(), imlib_image_get_filename());
        }
        xwindow_context_restore();
        break;
      case CMD_FONTS_RESET_ALL:
        /* prototype(void) */
        adesklets_fonts_reset();
        break;
      case CMD_FONTS_INFO:
        /* prototype(void) */
       command_printf("%d fonts\n",adesklets.fonts->pos);
        break;
      case CMD_COLOR_RANGES_RESET_ALL:
        /* prototype(void) */
        adesklets_color_ranges_reset();
        break;
      case CMD_COLOR_RANGES_INFO:
        /* prototype(void) */
       command_printf("%d color ranges\n",adesklets.color_ranges->pos);
        break;
      case CMD_COLOR_MODIFIERS_RESET_ALL:
        /* prototype(void) */
        adesklets_color_modifiers_reset();
        break;
      case CMD_COLOR_MODIFIERS_INFO:
        /* prototype(void) */
       command_printf("%d color modifiers\n",adesklets.color_modifiers->pos);
        break;
      case CMD_FILTERS_RESET_ALL:
        /* prototype(void) */
        adesklets_filters_reset();
        break;
      case CMD_FILTERS_INFO:
        /* prototype(void) */
       command_printf("%d filters\n",adesklets.filters->pos);
        break;
      case CMD_POLYGONS_RESET_ALL:
        /* prototype(void) */
        adesklets_polygons_reset();
        break;
      case CMD_POLYGONS_INFO:
        /* prototype(void) */
       command_printf("%d polygons\n",adesklets.polygons->pos);
        break;
      case CMD_IMAGE_HAS_ALPHA:
        command_ok("image alpha %hhu\n",imlib_image_has_alpha());
        break;
      case CMD_IMAGE_GET_WIDTH:
        command_ok("image width %d\n",imlib_image_get_width());
        break;
      case CMD_IMAGE_GET_HEIGHT:
        command_ok("image height %d\n",imlib_image_get_height());
        break;
      case CMD_IMAGE_GET_FILENAME:
        command_ok("image filename %s\n",imlib_image_get_filename());
        break;
      case CMD_IMAGE_GET_DATA:
        /* This uses imlib_image_get_data_for_reading_only(),
           so there is no need to invalidate image. Print final result
           in rgba format */
        if((data=imlib_image_get_data_for_reading_only())) {
          width=imlib_image_get_width();
          height=imlib_image_get_height();
         command_printf("image data - %d %d\n",width,height);
          for(i=0;i<width*height;++i)
           command_printf("%hhu %hhu %hhu %hhu ",
                 ((data[i]&(255<<16))>>16),
                 ((data[i]&(255<<8))>>8),
                 (data[i]&255),
                 ((data[i]&(255<<24))>>24));
         command_printf("\n");
        } else
          command_error("imlib data fetch problem\n");
        break;
      case CMD_IMAGE_QUERY_PIXEL:
        /* prototype(int x, int y) */
        if (params->pos>=2) {
          imlib_image_query_pixel(atoi(params->content[1]),
                            atoi(params->content[2]),
                            &color);
          command_ok("pixel value %hhu %hhu %hhu %hhu\n",
                   (char)color.red&255,(char)color.green&255,
                   (char)color.blue&255,(char)color.alpha&255);
        } else
          command_error("pixel coordinates not given\n");
        break;
      case CMD_IMAGE_SET_HAS_ALPHA:
        /* prototype(bool has_alpha) */
        if (params->pos>=2)
          imlib_image_set_has_alpha((char)atoi(params->content[1]));
        else
          command_error("alpha value not given\n");
        break;
      case CMD_IMAGE_SET_CHANGES_ON_DISK:
        /* prototype(void) */
        imlib_image_set_changes_on_disk();
        break;
      case CMD_IMAGE_SET_FORMAT:
        if (params->pos>=2)
          imlib_image_set_format(params->content[1]);
        else
          command_error("format string not given\n");
        break;
      case CMD_IMAGE_FILTER_RECURSE:
        /* prototype(void) */
        if(imlib_context_get_filter()) {
          for(i=0,j=imlib_image_get_width();i<j;++i) {
            imlib_image_filter();
#ifdef DEBUG
            if(i%(j/10)==(j/10)-1)
            debug("We are %d0 percents through.\n", (i+1)*10/j);
#endif
          }
          if(image_is_shown())
            updates=imlib_update_append_rect(updates,0,0,
                                     imlib_image_get_width(),
                                     imlib_image_get_height());
        }
        else
          command_error("no filter selected\n");
        break;
      case CMD_IMAGE_DRAW_LINE:
        if(params->pos>=5) {
          imlib_image_draw_line(atoi(params->content[1]),
                          atoi(params->content[2]),
                          atoi(params->content[3]),
                          atoi(params->content[4]),0);
          if (image_is_shown())
            updates = imlib_update_append_rect(updates,
                                     atoi(params->content[1]),
                                     atoi(params->content[2]),
                                     atoi(params->content[3])-
                                     atoi(params->content[1]),
                                     atoi(params->content[4])-
                                     atoi(params->content[2]));
        } else
          command_error("line coordinates not given\n");
        break;
      case CMD_IMAGE_DRAW_RECTANGLE:
        if(params->pos>=5) {
          imlib_image_draw_rectangle(atoi(params->content[1]),
                               atoi(params->content[2]),
                               atoi(params->content[3]),
                               atoi(params->content[4]));
          if (image_is_shown())
            updates = imlib_update_append_rect(updates,
                                     atoi(params->content[1]),
                                     atoi(params->content[2]),
                                     atoi(params->content[3]),
                                     atoi(params->content[4]));
        } else 
          command_error("rectangle description not given\n");
        break;
      case CMD_IMAGE_FILL_RECTANGLE:
        if(params->pos>=5) {
          imlib_image_fill_rectangle(atoi(params->content[1]),
                               atoi(params->content[2]),
                               atoi(params->content[3]),
                               atoi(params->content[4]));
          if (image_is_shown())
            updates = imlib_update_append_rect(updates,
                                     atoi(params->content[1]),
                                     atoi(params->content[2]),
                                     atoi(params->content[3]),
                                     atoi(params->content[4]));
        } else 
          command_error("rectangle description not given\n");
        break;
      case CMD_IMAGE_FILL_COLOR_RANGE_RECTANGLE:
        if (imlib_context_get_color_range()) {
          if(params->pos>=6) {
            imlib_image_fill_color_range_rectangle(atoi(params->content[1]),
                                         atoi(params->content[2]),
                                         atoi(params->content[3]),
                                         atoi(params->content[4]),
                                         atof(params->content[5]));
            if (image_is_shown())
            updates = imlib_update_append_rect(updates,
                                     atoi(params->content[1]),
                                     atoi(params->content[2]),
                                     atoi(params->content[3]),
                                     atoi(params->content[4]));
          } else
            command_error("not enough parameters given - need five\n");
        } else
          command_error("no color range selected\n");
        break;
      case CMD_IMAGE_DRAW_ELLIPSE:
        if(params->pos>=5) {
          imlib_image_draw_ellipse(atoi(params->content[1]),
                             atoi(params->content[2]),
                             atoi(params->content[3]),
                             atoi(params->content[4]));
          if (image_is_shown())
            updates = imlib_update_append_rect(updates,
                                     atoi(params->content[1])-
                                     atoi(params->content[3]),
                                     atoi(params->content[2])-
                                     atoi(params->content[4]),
                                     2*atoi(params->content[3]),
                                     2*atoi(params->content[4]));
        } else 
          command_error("ellipse description not given\n");
        break;
      case CMD_IMAGE_FILL_ELLIPSE:
        if(params->pos>=5) {
          imlib_image_fill_ellipse(atoi(params->content[1]),
                             atoi(params->content[2]),
                             atoi(params->content[3]),
                             atoi(params->content[4]));
          if (image_is_shown())
            updates = imlib_update_append_rect(updates,
                                     atoi(params->content[1])-
                                     atoi(params->content[3]),
                                     atoi(params->content[2])-
                                     atoi(params->content[4]),
                                     2*atoi(params->content[3]),
                                     2*atoi(params->content[4]));
        } else 
          command_error("ellipse description not given\n");
        break;
      case CMD_IMAGE_COPY_ALPHA_TO_IMAGE:
        if(params->pos>=4) {
           if((i=atoi(params->content[1]))>=0 &&
             i<adesklets.images->pos) {
             imlib_image_copy_alpha_to_image(adesklets.images->content[i],
                                     atoi(params->content[2]),
                                     atoi(params->content[3]));
             if(image_is_shown()) {
             xwindow_context_save(IMLIB_IMAGE);
             imlib_context_set_image(adesklets.images->content[i]);
             updates = imlib_update_append_rect(updates,
                                        atoi(params->content[2]),
                                        atoi(params->content[3]),
                                        imlib_image_get_width(),
                                        imlib_image_get_height());
             xwindow_context_restore();
             }
           } else
             command_error("image ID out of range\n");
        } else
          command_error("parameters not given\n");
        break;
      case CMD_IMAGE_COPY_ALPHA_RECTANGLE_TO_IMAGE:
        if(params->pos>=8) {
          if((i=atoi(params->content[1]))>=0 &&
             i<adesklets.images->pos) {
            imlib_image_copy_alpha_rectangle_to_image(
               adesklets.images->content[i],
             atoi(params->content[2]),
             atoi(params->content[3]),
             atoi(params->content[4]),
             atoi(params->content[5]),
             atoi(params->content[6]),
             atoi(params->content[7]));

            if(image_is_shown())
            updates= imlib_update_append_rect(updates,
                                      atoi(params->content[6]),
                                      atoi(params->content[7]),
                                      atoi(params->content[4]),
                                      atoi(params->content[5]));
          } else
            command_error("image ID out of range\n");
        } else
          command_error("parameters not given - need height\n");
        break;
      case CMD_IMAGE_DRAW_POLYGON:
        if (params->pos>=3) {
          if ((i=atoi(params->content[1]))>=0 && i<adesklets.polygons->pos) {
            imlib_image_draw_polygon(adesklets.polygons->content[i],
                               ((char*)params->content[2])[0]);
            if(image_is_shown()) {
            imlib_polygon_get_bounds(adesklets.polygons->content[i],
                               &x, &y, &i, &j);
            updates= imlib_update_append_rect(updates,x,y,i-x,j-y);
            }
          } else
            command_error("polygon ID %d out of range\n",i);
        } else
          command_error("parameters not given\n");
        break;
      case CMD_IMAGE_FILL_POLYGON:
        if (params->pos>=2) {
          if ((i=atoi(params->content[1]))>=0 && i<adesklets.polygons->pos) {
            imlib_image_fill_polygon(adesklets.polygons->content[i]);
            if(image_is_shown()) {
            imlib_polygon_get_bounds(adesklets.polygons->content[i],
                               &x, &y, &i, &j);
            updates= imlib_update_append_rect(updates,x,y,i-x,j-y);
            }
          } else
            command_error("polygon ID %d out of range\n",i);
        } else
          command_error("polygon ID not given\n");
        break;
      case CMD_IMAGE_FLIP_HORIZONTAL:
        imlib_image_flip_horizontal();
        if (image_is_shown())
          updates=imlib_update_append_rect(updates,0,0,
                                   imlib_image_get_width(),
                                   imlib_image_get_height());
        break;
      case CMD_IMAGE_FLIP_VERTICAL:
        imlib_image_flip_vertical();
        if (image_is_shown())
          updates=imlib_update_append_rect(updates,0,0,
                                   imlib_image_get_width(),
                                   imlib_image_get_height());
        break;
      case CMD_IMAGE_FLIP_DIAGONAL:
        if(((image=imlib_context_get_image()))!=
           adesklets.images->content[0] && 
           image != adesklets.images->content[1] &&
           (adesklets.user_background_image==-1 || 
            image != adesklets.images->content[
                               adesklets.user_background_image]))
          imlib_image_flip_diagonal();
        else
          command_error("operation forbidden on this image\n");
        break;
      case CMD_IMAGE_ORIENTATE:
        if (params->pos>=2) {
          if((i=atoi(params->content[1])%4)%2==0 ||
             (((image=imlib_context_get_image())!=
             adesklets.images->content[0] && 
             image != adesklets.images->content[1])))
            imlib_image_orientate(i);
          else
            command_error("operation forbidden on this image\n");
        } else
          command_error("orientation not given\n");
        break;
      case CMD_IMAGE_BLUR:
        if (params->pos>=2) {
          imlib_image_blur(atof(params->content[1]));
          updates=imlib_update_append_rect(updates,0,0,
                                   imlib_image_get_width(),
                                   imlib_image_get_height());
        } else
          command_error("Blur radius not given\n");
        break;
      case CMD_IMAGE_SHARPEN:
        if (params->pos>=2) {
          imlib_image_sharpen(atof(params->content[1]));
          updates=imlib_update_append_rect(updates,0,0,
                                   imlib_image_get_width(),
                                   imlib_image_get_height());
        } else
          command_error("Sharpen radius not given\n");
        break;
#define FILTER_SET(op)\
if(imlib_context_get_filter()) {\
  if (params->pos>=7)\
    imlib_filter_set ## op(atoi(params->content[1]),\
                            atoi(params->content[2]),\
                            atoi(params->content[3]),\
                            atoi(params->content[4]),\
                            atoi(params->content[5]),\
                            atoi(params->content[6]));\
  else\
    command_error("missing parameters - need six\n");\
} else\
  command_error("no filter selected\n")
      case CMD_FILTER_SET:
        /* prototype(int xoff, int yoff, int a, int r, int g, int b) */
        FILTER_SET( );
        break;
      case CMD_FILTER_SET_RED:
        /* prototype(int xoff, int yoff, int a, int r, int g, int b) */
        FILTER_SET(_red);
        break;
      case CMD_FILTER_SET_GREEN:
        /* prototype(int xoff, int yoff, int a, int r, int g, int b) */
        FILTER_SET(_green);
        break;
      case CMD_FILTER_SET_BLUE:
        /* prototype(int xoff, int yoff, int a, int r, int g, int b) */
        FILTER_SET(_blue);
        break;
      case CMD_FILTER_SET_ALPHA:
        /* prototype(int xoff, int yoff, int a, int r, int g, int b) */
        FILTER_SET(_alpha);
        break;
#undef FILTER_SET
#define FILTER_SET(op)\
if(imlib_context_get_filter()) {\
  if (params->pos>=5)\
    imlib_filter_ ## op(atoi(params->content[1]),\
                        atoi(params->content[2]),\
                        atoi(params->content[3]),\
                        atoi(params->content[4]));\
  else\
    command_error("missing parameters - need four\n");\
} else\
  command_error("no filter selected\n")
      case CMD_FILTER_CONSTANTS:
        /* prototype(int a, int r, int g, int b) */
        FILTER_SET(constants);
        break;
      case CMD_FILTER_DIVISORS:
        /* prototype(int a, int r, int g, int b) */
        FILTER_SET(divisors);
        break;
#undef FILTER_SET
      case CMD_MENU_FIRE:
        /* prototype(int menu) */
#ifndef X_DISPLAY_MISSING
        if (adesklets.display && adesklets.window) {
          if(params->pos>=2) {
            i=atoi((char*)params->content[1]);
            if (adesklets_menu_fire(i,(char**)&menu_str)) {
            if (adesklets.user_event_mask&MenuFireMask)
              event("menufire %d %s\n",i,menu_str);
            } else 
            command_error("menu fire error\n");
          }
          else
            command_error("menu ID not given\n");
        } else
#endif
          command_error("X connection or window missing\n");
          break;
      case CMD_MENU_RESET_ALL:
        /* prototype(void) */
        if (!adesklets_menus_reset())
          command_error("internal consistency problem with menu\n");
        break;
      case CMD_MENU_ADD_MENU:
        /* prototype(void) */
        if (!vector_push(adesklets.menus,xmenu_init()))
          command_error("could not add a new menu\n");
        else
          command_ok("new menu %d\n",adesklets.menus->pos-1);
        break;
      case CMD_MENU_ADD_SUBMENU:
        /* prototype(const char * submenu) */
        if (params->pos>=2) {
          if (!xmenu_push_submenu(MENU(adesklets.menus->pos-1),
                           command.line+1+
                           strlen(COMMANDS[CMD_MENU_ADD_SUBMENU].name)))
            command_error("could not create submenu\n");
          /*
          if ((menu_str=dupstr_utf8(command_subsplitter(command.line,1)))) {
            if (!xmenu_push_submenu(MENU(adesklets.menus->pos-1),menu_str)) 
            command_error("could not create submenu\n");
            free(menu_str);
          }
          */
        } else
          command_error("submenu description not given\n");
        break;
      case CMD_MENU_ADD_ITEM:
        /* prototype(const char * add_item) */
        if(params->pos>=2) {
          if(!xmenu_push_item(MENU(adesklets.menus->pos-1),
                        command.line+1+
                        strlen(COMMANDS[CMD_MENU_ADD_ITEM].name)))
             command_error("could not create item\n");
        } else
          command_error("item description not given\n");
        break;
      case CMD_MENU_ADD_SEPARATOR:
        /* prototype(void) */
        if(!xmenu_push_item(MENU(adesklets.menus->pos-1),"-"))
          command_error("could not add separator\n");
        break;
      case CMD_MENU_END_SUBMENU:
        /* prototype(void) */
        if(!xmenu_end_submenu(MENU(adesklets.menus->pos-1)))
          command_error("could not end submenu\n");
        break;
      case CMD_EVENT_CATCH:
        /* prototype(voidvoid) */
#ifndef X_DISPLAY_MISSING
        if (adesklets.display && adesklets.window) {
          if(params->pos>=2) {
            for(i=0;X_WINDOW_EVENTS[i].name;++i)
            if(strncmp(X_WINDOW_EVENTS[i].name,params->content[1],
                     strlen(X_WINDOW_EVENTS[i].name))==0)
              break;
            adesklets.user_event_mask|=
            X_WINDOW_EVENTS[(X_WINDOW_EVENTS[i].name)?
                        i:atoi(params->content[1])%i].mask;
            adesklets.event_mask=(BASE_EVENT_MASK)|
            (adesklets.user_event_mask&
            ~(BackgroundGrabMask|MenuFireMask));
            XSelectInput(adesklets.display,adesklets.window,
                     adesklets.event_mask);
          } else
            command_error("event to catch not given\n");
        } else
#endif
          command_error("X connection or window missing\n");
        break;
      case CMD_EVENT_UNCATCH:
        /* prototype(voidvoid) */
#ifndef X_DISPLAY_MISSING
        if(adesklets.display && adesklets.window) {
          if(params->pos>=2) {
            for(i=0;X_WINDOW_EVENTS[i].name;++i)
            if(strncmp(X_WINDOW_EVENTS[i].name,params->content[1],
                     strlen(X_WINDOW_EVENTS[i].name))==0)
              break;
            mask=X_WINDOW_EVENTS[(X_WINDOW_EVENTS[i].name)?
                           i:atoi(params->content[1])%i].mask;
            /* If event was already selected, purge all remaining
             events of that type if applicable */
            if(mask!=BackgroundGrabMask &&
             mask!=MenuFireMask &&
             (adesklets.event_mask&mask) && 
             !((BASE_EVENT_MASK)&mask))
            while(XCheckWindowEvent(adesklets.display,
                              adesklets.window,mask,&ev));
            adesklets.user_event_mask&=~mask;
            adesklets.event_mask=(BASE_EVENT_MASK)|
            (adesklets.user_event_mask
            &~(BackgroundGrabMask|MenuFireMask));
            XSelectInput(adesklets.display,adesklets.window,
                     adesklets.event_mask);
          } else
            command_error("event to uncatch not given\n");
        } else
#endif
          command_error("X connection or window missing\n");
        break;
      case CMD_EVENTS_RESET_ALL:
        /* prototype(voidvoid) */
#ifndef X_DISPLAY_MISSING
        if(adesklets.display && adesklets.window) {
          XSelectInput(adesklets.display,adesklets.window,
                   BASE_EVENT_MASK);
          while(XCheckWindowEvent(adesklets.display,adesklets.window,
                            adesklets.user_event_mask&
                              ~(BASE_EVENT_MASK)&~BackgroundGrabMask&
                            ~MenuFireMask,
                            &ev));
          adesklets.user_event_mask=0;
          adesklets.event_mask=BASE_EVENT_MASK;
        } else
#endif
          command_error("X connection or window missing\n");
        break;
      case CMD_EVENTS_INFO:
        /* prototype(void) */
#ifndef X_DISPLAY_MISSING
        if (adesklets.display && adesklets.window) {
          for(i=0,j=0;X_WINDOW_EVENTS[i].name;++i)
            if(adesklets.user_event_mask&X_WINDOW_EVENTS[i].mask)
            ++j;
         command_printf("%d events caught\n",j);
          for(i=0;X_WINDOW_EVENTS[i].name;++i)
            if(adesklets.user_event_mask&X_WINDOW_EVENTS[i].mask)
      command_printf("%d (%s)\n",i , X_WINDOW_EVENTS[i].name);
        } else
#endif
          command_error("X connection or window missing\n");
        break;
      case CMD_EVENTS_GET_ECHO:
        /* prototype(void) */
        command_ok("events echo %d\n", events_echo);
        break;
      case CMD_EVENTS_SET_ECHO:
        /* prototype(voidvoid) */
        if(params->pos>=2) {
          if (events_echo!=(i=atoi(params->content[1]))) {
            events_echo=i;
            if(i)
            events_purge();
          }
        }
        else
          command_error("echo value not given\n");
        break;
      case CMD_EVENTS_GET_SEND_SIGUSR1:
        /* prototype(void) */
        command_ok("events send_sigusr1 %d\n",(events_ppid)?1:0);
        break;
      case CMD_EVENTS_SET_SEND_SIGUSR1:
        /* prototype(voidvoid) */
        if (params->pos>=2)
          events_ppid=(atoi(params->content[1]))?adesklets.ppid:0;
        else
          command_error("send SIGUSR1 status not given\n");
        break;
      case CMD_EVENTS_PURGE:
        /* prototype(voidvoid) */
        command_printf("%d events to purge\n",(events)?events->pos:0);
        events_purge();
        break;
      case CMD_WINDOW_RESET:
        /* prototype(enum WINDOW_MANAGER manager) */
        if(params->pos>=2) {
          for(i=0;WINDOW_MANAGER[i];++i)
            if(strncmp(WINDOW_MANAGER[i],params->content[1],
                   strlen(params->content[1]))==0)
            break;
          if (adesklets_window_reset((WINDOW_MANAGER[i])?i:
                               atoi(params->content[1]))) {
            if (adesklets_menus_reset()) {
            if (!adesklets_images_reset_background(0))
                command_error("could not reset background images\n");
            } else
            command_error("could not reset menus\n");     
          } else
            command_error("could not reset main window\n");
        } else
          command_error("Window manager status not given\n");
        break;
      case CMD_WINDOW_SHOW:
        /* prototype(void) */
#ifndef X_DISPLAY_MISSING
        if (adesklets.display && adesklets.window) {
          if (!XMapWindow(adesklets.display,adesklets.window))
            command_error("could not map the window\n");
        } else
#endif
          command_error("X connection or window missing\n");
        break;
      case CMD_WINDOW_HIDE:
        /* prototype(void) */
#ifndef X_DISPLAY_MISSING
        if (adesklets.display && adesklets.window) {
          if(!XUnmapWindow(adesklets.display,adesklets.window))
            command_error("could not unmap the window\n");
        } else
#endif
          command_error("X connection or window missing\n");
        break;
      case CMD_WINDOW_RESIZE:
        /* prototype(int width, int height) */
        if (params->pos>=3) {
          if((i=atoi(params->content[1]))>0 &&
             (j=atoi(params->content[2]))>0) {
#ifndef X_DISPLAY_MISSING
            if (adesklets.display && adesklets.window) {
            if (!xwindow_resize_window(adesklets.display,adesklets.window,
                                 adesklets.params,i,j,0))
              command_error("did not resize window\n");
            } else {
#endif
            if (!adesklets_images_reset_background(1,i,j))
              command_error("no window, and could not resize images\n");
#ifndef X_DISPLAY_MISSING
            }
#endif
          } else command_error("resize out of range\n");
        } else command_error("resize dimensions no given\n");
        break;
      case CMD_WINDOW_GET_TRANSPARENCY:
        /* prototype(void) */
        command_ok("window transparency %d\n",adesklets.transparency);
        break;
      case CMD_WINDOW_GET_BACKGROUND_GRAB:
        /* prototype(void) */
        if(X_DISPLAY_SUPPORT && adesklets.display && adesklets.window)
          command_ok("window backgroundgrab %d\n",adesklets.background_grab);
        else
          command_error(
            "background grab irrelevant - no X window connection or window\n");
        break;
      case CMD_WINDOW_GET_BACKGROUND_IMAGE:
        /* prototype(void) */
        if(X_DISPLAY_SUPPORT && adesklets.display && adesklets.window)
          command_ok("background image %d\n",
                   (adesklets.user_background_image!=-1)?
                   adesklets.user_background_image:1);
        else
          command_error(
                "background window irrelevant - no X window connection or window\n");   
        break;
      case CMD_WINDOW_GET_MANAGED_STATUS:
        /* prototype(void) */
#ifndef X_DISPLAY_MISSING
        if(adesklets.display && adesklets.window) {
          command_ok("window managedstatus %d (%s)\n",
                   adesklets.managed, 
                   WINDOW_MANAGER[adesklets.managed]);
        } else
           command_error("X connection or window missing\n");
#else
        command_error("X connection or window missing\n");
#endif
        break;
      case CMD_WINDOW_SET_TRANSPARENCY:
        /* prototype(bool transparency) */
        if (params->pos>=2) {
          i=atoi((char*)params->content[1]);
          if (adesklets.transparency!=i) {
            adesklets.transparency=i;
            /* If there is a chance, invalidate the entire window */
#ifndef X_DISPLAY_MISSING
            xwindow_window_size(adesklets.display,adesklets.window,
                          &width,&height);            
            updates = imlib_update_append_rect(updates,
                                     0,0,(int)width,(int)height);
#endif
          }
        } else command_error("transparency value not given\n");
        break;
      case CMD_WINDOW_SET_BACKGROUND_GRAB:
        /* prototype(bool grab) */
        if (params->pos>=2) {
          if (adesklets.background_grab!=(i=atoi(params->content[1]))) {
            if ((adesklets.background_grab=i))
            adesklets_images_reset_background(0);
            else {
            xwindow_context_save(IMLIB_IMAGE|IMLIB_BLEND|IMLIB_COLOR);
            imlib_context_set_image(adesklets.images->content[1]);
            imlib_context_set_color(0,0,0,255);
            imlib_context_set_blend(0);
            imlib_image_fill_rectangle(0,0,
                                 imlib_image_get_width(),
                                 imlib_image_get_height());
            xwindow_context_restore();
            }

#ifndef X_DISPLAY_MISSING           
            xwindow_window_size(adesklets.display,adesklets.window,
                          &width,&height);            
            updates = imlib_update_append_rect(updates,
                                     0,0,(int)width,(int)height);
#endif
          }
        } else
          command_error("background grab value not given\n");
        break;
      case CMD_WINDOW_SET_BACKGROUND_IMAGE:
        /* prototype(int image) */
        if (X_DISPLAY_SUPPORT && adesklets.display && adesklets.window) {
          if(params->pos>=2) {
            if((i=atoi(params->content[1]))>=0 && i<adesklets.images->pos) {
            if(i!=0) {
              xwindow_context_save(IMLIB_IMAGE);
              imlib_context_set_image(adesklets.images->content[0]);
              j=imlib_image_get_width();
              k=imlib_image_get_height();
              if(i!=1) {
                imlib_context_set_image(adesklets.images->content[i]);
                x=imlib_image_get_width();
                y=imlib_image_get_height();
                if (x==j && y==k) {
                  adesklets.user_background_image=i;
                  updates = imlib_update_append_rect(updates,
                                           0,0,x,y);
                }
                else
                  command_error("incorrect dimensions image\n");            
              } else {
                /* Drop silently reset to actual foreground */
                adesklets.user_background_image=-1;
                updates = imlib_update_append_rect(updates,
                                           0,0,j,k);
              }
              xwindow_context_restore();
            } else
              command_error(
                  "foreground image cannot be selected as background\n");
            } else
            command_error("image ID %d out of range\n",i);
          } else
            command_error("background image ID not given\n");
        } else
          command_error(
              "background window irrelevant - no X window connection or window\n");
        break;
      case CMD_SCREEN_GET_WIDTH:
        /* prototype(void) */
#ifndef X_DISPLAY_MISSING
        if (adesklets.display) {
          command_ok("screen width %d\n",
                   WidthOfScreen(ScreenOfDisplay(adesklets.display,
                                         adesklets.params->scr)));
        } else
          command_error("X connection missing\n");
#else
         command_error("X connection missing\n");
#endif
        break;
      case CMD_SCREEN_GET_HEIGHT:
        /* prototype(void) */
#ifndef X_DISPLAY_MISSING
        if(adesklets.display) {
          command_ok("screen height %d\n",
                   HeightOfScreen(ScreenOfDisplay(adesklets.display,
                                          adesklets.params->scr)));
        } else
          command_error("X connection missing\n");
#else
        command_error("X connection missing\n");
#endif
        break;
      case CMD_SCREEN_GET_DEPTH:
        /* prototype(void) */
        if(adesklets.display)
          command_ok("screen depth %d\n",adesklets.depth);
        else
          command_error("X connection missing\n");
        break;
      case CMD_GET_CHARSET:
        /* prototype(void) */
#ifdef HAVE_ICONV_H
        if (command.from_page)
          command_ok("charset %s\n",command.from_page);
        else
#endif
          command_ok("charset -1 (unset)\n");
        break;
      case CMD_SET_CHARSET:
        /* prototype(const char * charset) */
#ifdef HAVE_ICONV_H
        if (params->pos>=2) {
          if ((cd=iconv_open("UTF8",params->content[1]))!=(iconv_t)(-1)) {
            if (command.cd) { 
            iconv_close(command.cd); 
            command.cd=NULL; 
            }
            if (command.from_page) { 
            free(command.from_page); 
            command.from_page=NULL;
            }
            command.from_page=dupstr(params->content[1]);
            command.cd=cd;
          } else
            command_error("could not establish conversion from '%s' to 'UTF8'\n",
                      params->content[1]);
        } else {
          if (command.cd) {
            iconv_close(command.cd);
            command.cd=NULL;
          }
          if (command.from_page) { 
            free(command.from_page); 
            command.from_page=NULL;
          }
          command_ok("charset -1 (unset)\n");
        }
#else
        command_error("charset conversion not compiled in\n");
#endif
        break;
      case CMD_CHARSET_STATUS:
        /* prototype(void) */
#ifdef HAVE_ICONV_H
        command_ok("charset_status 1\n");
#else
        command_ok("charset_status 0 (charset conversion not compiled in)\n");
#endif
        break;
      case CMD_X_STATUS:
        /* prototype(void) */
#ifndef X_DISPLAY_MISSING
        command_ok("x_status %d (%s%s')\n",(adesklets.display)?1:0,
                 (adesklets.display)?"connected to '":"disconnected from '",
                 XDisplayName(NULL));
#else
        command_ok("x_status 0 (X Window support not compiled in)\n");
#endif
        break;
      case CMD_QUIT:
        /* prototype(void) */
        command_ok("quitting...\n");
        adesklets.quit_flag=1;
        break;
      default:
        if(blank_line(command.line))
          command.message_out=1;
        else
          command_error("syntax error\n");
      } /* switch(command_type) */
      } /* if command.recording */
      if (!command.message_out) command_ok("%s\n",command.line);
      vector_free(params);
      free(command.line);
      command.ready=0; ++command.rank;
      if (command.interactive && !command.replay_pos &&
          !adesklets.quit_flag && !adesklets.restart_flag) 
        command_interpreter_reset();
      } else {printf("\n"); adesklets.quit_flag=1;} /* if (command.line) */
    } /* if(command.ready) */

#ifndef X_DISPLAY_MISSING
    while(adesklets.display && adesklets.window && 
        (XCheckWindowEvent(adesklets.display,
                       adesklets.root,
                       PropertyChangeMask, &ev) || 
         XCheckWindowEvent(adesklets.display,adesklets.window,
                       adesklets.event_mask,&ev) ||
         XCheckTypedWindowEvent(adesklets.display,adesklets.window,
                          ClientMessage,&ev))) {
      switch(ev.type) {
      case Expose:
      /* Refresh updates list */
      updates = imlib_update_append_rect(updates,
                                 ev.xexpose.x,ev.xexpose.y,
                                 ev.xexpose.width,ev.xexpose.height);
      break;
      case PropertyNotify:
      /* This event is generated from root window only:
         we use it to check for dynamic root window background change,
         as enlightment has used it for years. Look at
         xwindow_updated_background() for details */
      if (ev.xproperty.atom != None &&
          ev.xproperty.atom == XInternAtom (adesklets.display, 
                                    "_XROOTPMAP_ID", True) &&
          adesklets.background_grab &&
          xwindow_updated_background(adesklets.display,
                               ev.xproperty.window,
                               ev.xproperty.atom))
        /* Recompute the background images */
        adesklets_images_reset_background(0);

        /* Because the setting of background_pixmap as ParentRelative
           on the main window, there is no need to invalidate 
           it here: an Expose event will be automatically generated. */
      break;
      case ButtonPress:
      /* Fire default menu on left button click */
      if(ev.xbutton.button==3) {
        if (adesklets_menu_fire(0,&menu_str) &&
            (adesklets.user_event_mask&MenuFireMask))
          event("menufire 0 %s\n",menu_str);
      } else
        if(adesklets.user_event_mask&ButtonPressMask)
          event("buttonpress %d %d %d\n",
              ev.xbutton.x,ev.xbutton.y,ev.xbutton.button);
          
      break;
      case ButtonRelease:
      if(ev.xbutton.button!=3)
        event("buttonrelease %d %d %d\n",
            ev.xbutton.x,ev.xbutton.y,ev.xbutton.button);
      break;
      case MotionNotify:
      event("motionnotify %d %d\n",
            ev.xmotion.x, ev.xmotion.y);
      break;
      case EnterNotify:
      event("enternotify %d %d\n",
            ev.xcrossing.x, ev.xcrossing.y);
      break;
      case LeaveNotify:
      event("leavenotify %d %d\n",
            ev.xcrossing.x, ev.xcrossing.y);
      break;
      case ConfigureNotify:
      if (ev.xconfigure.window==adesklets.window)
        if (xwindow_window_moved_or_resized(ev.xconfigure.x,
                                    ev.xconfigure.y,
                                    ev.xconfigure.width,
                                    ev.xconfigure.height))
          adesklets_images_reset_background(0);
      break;
      case ClientMessage:
      /* Since we register only one protocol (WM_WINDOW_DELETE),
         there is no need for further checks */
      debug("Message from window manager: quitting!\n");
      adesklets.user_quit_flag=adesklets.quit_flag=1;
      break;
      default:
      /* Untreated cases */
      break;
      }
    } 
    
    /* Now, performs main window updates as needed */
    xwindow_update_window(adesklets.window, &updates,
                    adesklets.images->content[
                       (adesklets.user_background_image!=-1)?
                       adesklets.user_background_image:1],
                    adesklets.images->content[0],
                    adesklets.transparency);
#endif
    if(updates) imlib_updates_free(updates);

  } while(!adesklets.quit_flag && !adesklets.restart_flag &&
        (command_replayer() || command_interpreter()));
}

/*----------------------------------------------------------------------------*/
int adesklets_free(void)
{
  int i, fd_null;
  struct flock lock;

  debug("---------------------------------------------------------------\n");
   /* Ultimate update : take care of potential applet removal 
      if user asked for it. */
  adesklets.params->no_update|=adesklets.user_quit_flag;
  cfgfile_update(adesklets.params);

  /* X Windows cleanup */
#ifndef X_DISPLAY_MISSING
  if(adesklets.display) {
    if(adesklets.window) {
      XUnmapWindow(adesklets.display,adesklets.window);
      XDestroyWindow(adesklets.display,adesklets.window);
    }
    XCloseDisplay(adesklets.display);
  }
#endif

  /* For terminal reset, if it was not cleanly performed
     (will happen when quitting from the default left click
      menu, for instance) */
  rl_callback_handler_remove();

  /* Send SIGTERM notification signal to parent process:
     in all case but restart, adesklets do not 
     go further to ensure parent termination. */
  kill(adesklets.ppid,SIGTERM);
    
  /* if Lock exist: handle possible restart */
  if(adesklets.lock) {
    if(adesklets.restart_flag) {      
      /* Wait for adesklets parent process to exit 
       SIGKILL_TIMEOUT seconds, then send a SIGKILL. */
      for(i=0;i<SIGKILL_TIMEOUT && adesklets.ppid==getppid();++i)
      sleep(1);
      if (i==SIGKILL_TIMEOUT) kill(adesklets.ppid,SIGKILL);
      while(adesklets.ppid==getppid()) sleep(1);
      if (fork()==0) {
      /* Redirect stdout and stderr to /dev/null to avoid
         output buffer overflow */
      if ((fd_null=open("/dev/null",O_WRONLY))>=0) {
        dup2(fd_null,1);
        dup2(fd_null,2);
        close(fd_null);
      }
      execl(adesklets.params->applet,
            adesklets.params->applet,
            NULL);
      /* debug("Restart: could not exec `%s'",adesklets.params->applet); */
      exit(EXIT_FAILURE);
      }
    }

    /* Release the lock */
    lock.l_type=F_UNLCK;
    lock.l_whence=SEEK_SET;
    lock.l_start=0;
    lock.l_len=0;
    fcntl(fileno(adesklets.lock),F_SETLK,&lock);
    fclose(adesklets.lock);

    /* Try to unlink the lock file:
       thanks to POSIX, this will fail gracefully 
       if a process is still using the file */
    unlink(adesklets.lock_filename);
  }
  
  /* Free structures */
  if(events) vector_free(events);
  adesklets.menus=vector_free(adesklets.menus);
  adesklets.images=vector_free(adesklets.images);
  adesklets.fonts=vector_free(adesklets.fonts);
  adesklets.color_ranges=vector_free(adesklets.color_ranges);
  adesklets.color_modifiers=vector_free(adesklets.color_modifiers);
  adesklets.filters=vector_free(adesklets.filters);
  adesklets.polygons=vector_free(adesklets.polygons);
  adesklets.variables=vector_free(adesklets.variables);

  return !adesklets.menus && 
    !adesklets.images &&
    !adesklets.fonts &&
    !adesklets.color_ranges &&
    !adesklets.color_modifiers &&
    !adesklets.filters &&
    !adesklets.polygons &&
    !adesklets.variables;
}
    
/*----------------------------------------------------------------------------*/
/* Signal wrapper for adesklets_free()
*/
void 
termination_handler(int signum)
{
  exit((adesklets_free())?EXIT_SUCCESS:EXIT_FAILURE);
}

/*----------------------------------------------------------------------------*/
/* Since we cannot verify if applet is a script of a binary without trying
   to execute it, we require it to have both read and execute permissions for 
   the current user... Better _portable_ solution is welcomed.
*/
int 
adesklets_valid_desklet(char * applet, int register_flag)
{
  int result = 0;

  if(applet)
    if((register_flag && applet[0]=='/') || !register_flag)
      result=(access(applet,R_OK|X_OK)==0);
  return result;
}

/*----------------------------------------------------------------------------*/
/* Our image generator function (have a look at command.c) */
char *
image_generator(const char * text, int state)
{
  return generic_index_generator(text,state,adesklets.images->pos);
}

/*----------------------------------------------------------------------------*/
/* Our font name generator function (have a look at command.c) */
char * 
base_font_generator(const char * text, int state) 
{
  char * result;
  static int number;
  static char ** fonts;
  
  if (!state) {
    fonts=imlib_list_fonts(&number);
  }
  if(!(result=generic_generator(text,state,fonts,number))) {
    imlib_free_font_list(fonts,number);
  }
  return result;
}

/*----------------------------------------------------------------------------*/
char *
base_font_path_generator(const char * text, int state)
{
  static int number;
  static char ** font_path;
  
  if (!state) {
    font_path=imlib_list_font_path(&number);
  }
  return generic_generator(text,state,font_path,number);
}

/*----------------------------------------------------------------------------*/
char * 
font_generator (const char * text, int state)
{
  return generic_index_generator(text,state,adesklets.fonts->pos);
}

/*----------------------------------------------------------------------------*/
char * 
font_generator_with_null (const char * text, int state)
{
  return generic_index_generator_with_null(text,state,adesklets.fonts->pos);
}

/*----------------------------------------------------------------------------*/
/* Our menu generator function (have a look at command.c) */
char *
menu_generator(const char * text, int state)
{
  return generic_index_generator(text,state,adesklets.menus->pos);
}

/*----------------------------------------------------------------------------*/
/* Our color ranges generator function (have a look at command.c) */
char *
color_range_generator(const char * text, int state)
{
  return generic_index_generator(text,state,adesklets.color_ranges->pos);
}

/*----------------------------------------------------------------------------*/
/* Our color ranges generator function (have a look at command.c) */
char *
color_range_generator_with_null(const char * text, int state)
{
  return generic_index_generator_with_null(text,state,
                                 adesklets.color_ranges->pos);
}

/*----------------------------------------------------------------------------*/
/* Our color modifiers generator function (have a look at command.c) */
char *
color_modifier_generator(const char * text, int state)
{
  return generic_index_generator(text,state,adesklets.color_modifiers->pos);
}

/*----------------------------------------------------------------------------*/
/* Our color modifiers generator function (have a look at command.c) */
char *
color_modifier_generator_with_null(const char * text, int state)
{
  return generic_index_generator_with_null(text,state,
                                 adesklets.color_modifiers->pos);
}

/*----------------------------------------------------------------------------*/
/* Our filters generator function (have a look at command.c) */
char *
filter_generator(const char * text, int state)
{
  return generic_index_generator(text,state,adesklets.filters->pos);
}

/*----------------------------------------------------------------------------*/
/* Our filters generator function (have a look at command.c) */
char *
filter_generator_with_null(const char * text, int state)
{
  return generic_index_generator_with_null(text,state,
                                 adesklets.filters->pos);
}

/*----------------------------------------------------------------------------*/
/* Our polygon generator function (have a look at command.c) */
char *
polygon_generator(const char * text, int state)
{
  return generic_index_generator(text,state,adesklets.polygons->pos);
}

/*----------------------------------------------------------------------------*/
/* We have to put this generator here because variables vector is part of
   the adesklets structure */
char *
variable_generator(const char * text, int state)
{
  static int list_index, len;
  char * name;

  if(!state) {
    list_index=0;
    len=strlen(text);
  }
    
  while (list_index<adesklets.variables->pos) {
    name=((var_item*)adesklets.variables->content[list_index])->name;
    ++list_index;
    if(strncmp(name,text,len)==0)
      return dupstr(name);
  }

  return NULL;
}

/*----------------------------------------------------------------------------*/

/* Generic generator mecanism: used for different wrappers.*/
/*
char * generic_generator(const char * text, int state, 
                   char ** names, int number)
{
  static int list_index, len;
  char * name;

  if(!state) {
    list_index=0;
    len=strlen(text);
  }
  
  while((number==-1 || list_index<number) &&
      (name=names[list_index])) {
    ++list_index;
    if(strncmp(name,text,len)==0)
      return(dupstr(name));
  }
  
 return NULL;
}
*/

Generated by  Doxygen 1.6.0   Back to index