dslinux/user/pixil/sys/pixilwm Makefile applets.c applets.h apps.c apps.h categories.c categories.h clients.c config.c config.h container.c exec.c hardcodedimage.h home.c icons.c inputs.c ipc.c keyb.c main.c nanowm.h powerman.c powerman.h pwroff.h root.c screensaver.c screensaver.h scrib.c sys_menu.c sys_menu.h themes.c themes.h themesconfig.c themetags.h utils.c utils.h wlist.c

amadeus dslinux_amadeus at user.in-berlin.de
Tue Oct 3 13:27:13 CEST 2006


Update of /cvsroot/dslinux/dslinux/user/pixil/sys/pixilwm
In directory antilope:/tmp/cvs-serv11916/sys/pixilwm

Added Files:
	Makefile applets.c applets.h apps.c apps.h categories.c 
	categories.h clients.c config.c config.h container.c exec.c 
	hardcodedimage.h home.c icons.c inputs.c ipc.c keyb.c main.c 
	nanowm.h powerman.c powerman.h pwroff.h root.c screensaver.c 
	screensaver.h scrib.c sys_menu.c sys_menu.h themes.c themes.h 
	themesconfig.c themetags.h utils.c utils.h wlist.c 
Log Message:
adding pristine copy of pixil to HEAD so I can branch from it

--- NEW FILE: screensaver.h ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */

#ifndef SCREENSAVER_H
#define SCREENSAVER_H

void screensaver_init(void);
int screensaver_active(void);

void screensaver_frame(void);
void screensaver_enable(void);
void screensaver_disable(void);

#endif

--- NEW FILE: config.h ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#ifndef SETTINGS_H
#define SETTINGS_H

#include "nano-X.h"

/* These are the default settings */
/* Change them as you see fit     */

#define DEFAULT_WALLPAPER	"cenlogo.gif"
#define DEFAULT_BGCOLOR         COLOR_DESKTOP
#define DEFAULT_ICONCOLOR       COLOR_DESKTOP
#define DEFAULT_ICONTEXT        COLOR_ICONTEXT

#define WALLPAPER_NONE       0x00
#define WALLPAPER_TILED      0x01
#define WALLPAPER_CENTERED   0x02
#define WALLPAPER_FULLSCREEN 0x04
#define WALLPAPER_BOTTOM     0x05

#define WM_BGCOLOR         0
#define WM_ICONCOLOR       1
#define WM_ICONTEXT        2
#define WM_TASKBAR         3
#define WM_DIALOG          5
#define WM_COLOR_SIZE      6


#define DESKTOP_PREFIX   0
#define DESKTOP_IMAGEDIR 1
#define DESKTOP_NXAPPDIR 2
#define DESKTOP_SOUNDDIR 3
#define DESKTOP_THEMEDIR 4

#define WM_DIR_SIZE      5

/* These are functions to get the various window manager settings */

void wm_setColor(int color, GR_COLOR value);
GR_COLOR wm_getColor(int color);
void wm_setDir(int dir, char *value);
const char *wm_getDir(int dir);
int wm_getWallpaper(GR_IMAGE_ID * iid, int *flags);

#endif

--- NEW FILE: config.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


/* For now we try to play nicely with the rest of the system */
/* API that has been established */

#include <pixil_config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>

#include <par/par.h>

#include <nano-X.h>

#include "nanowm.h"
#include "apps.h"
#include "categories.h"
#include "config.h"

#ifdef CONFIG_PIXILWM_THEMES
#include "themes.h"
#endif

#include "applets.h"

/* This local structure maintains our current settings */

static struct
{

    /* Wallpaper settings */

    struct
    {
	GR_IMAGE_ID bgImage;
	int flags;
    }
    wallpaper;

    /* Colors */
    GR_COLOR colorArray[WM_COLOR_SIZE];
    char *dirArray[WM_DIR_SIZE];

    char *theme;
}
wmSettings;

/* These are a series of "default" values */
static const char *defaultDirs[WM_DIR_SIZE] =
    { ".", "./images", "./bin", "./sounds", "./themes" };

static void
strToLower(char *str)
{
    int i;
    for (i = 0; i < strlen(str); i++)
	tolower(str[i]);
}

void
wm_setColor(int color, GR_COLOR value)
{
    wmSettings.colorArray[color] = value;
}

GR_COLOR
wm_getColor(int color)
{
    return (wmSettings.colorArray[color]);
}

void
wm_setDir(int dir, char *value)
{

    if (wmSettings.dirArray[dir]) {
	if (strcmp(wmSettings.dirArray[dir], value) == 0)
	    return;

	free(wmSettings.dirArray[dir]);
	wmSettings.dirArray[dir] = 0;
    }

    wmSettings.dirArray[dir] = strdup(value);
}

inline const char *
wm_getDir(int dir)
{
    if (!wmSettings.dirArray[dir])
	return (defaultDirs[dir]);
    return (wmSettings.dirArray[dir]);
}

int
wm_getWallpaper(GR_IMAGE_ID * iid, int *flags)
{
    if (!wmSettings.wallpaper.bgImage ||
	wmSettings.wallpaper.flags == WALLPAPER_NONE)
	return (0);

    *iid = wmSettings.wallpaper.bgImage;
    *flags = wmSettings.wallpaper.flags;
    return (1);
}

static int
nxLoadDefaults(void)
{

    wmSettings.wallpaper.flags = WALLPAPER_NONE;

    /* NOTE:  The GrGetSysColor here is not freeing its nxAllocReq */

    wm_setColor(WM_BGCOLOR, COLOR_DESKTOP);
    wm_setColor(WM_ICONCOLOR, COLOR_DESKTOP);
    wm_setColor(WM_ICONTEXT, COLOR_ICONTEXT);
    wm_setColor(WM_TASKBAR, COLOR_TASKBAR);
    wm_setColor(WM_DIALOG, COLOR_TASKBAR);

    return (0);
}

static void
getColor(db_handle * db, int index, char *keyword)
{

    int val;
    char *name = alloca(strlen("colors") + strlen(keyword) + 2);

    sprintf(name, "colors.%s", keyword);

    if (par_getScreentopSetting(db, name, &val, sizeof(val)) <= 0) {
	error("Couldn't get the color '%s' from the database.\n", keyword);
	return;
    }

    wm_setColor(index,
		GR_RGB((val >> 16) & 0xFF, (val >> 8) & 0xFF, (val) & 0xFF));
}

static void
getDirectory(db_handle * db, int index, char *keyword)
{

    char str[512];
    int size = par_getScreentopDir(db, keyword, str, sizeof(str));
    if (size > 0)
	wm_setDir(index, str);
    else
	error("Couldn't get the directory '%s' from the database.\n",
	      keyword);
}

static void
nxLoadApplets(db_handle *db) {
  
  itemlist_t *list;
  int i;

  if (par_getList(db, "screentop.settings.applets", &list) <= 0) {
    printf("screentop.settings.applets doesn't exist\n");
    return;
  }

  for(i = 0; i < list->count; i++) {
    char plugin[128];
    char name[64];

    sprintf(name, "screentop.settings.applets.%s", list->list[i]);

    if (db_findNode(db, name, plugin, sizeof(plugin), 0) < 0)
      continue;

    wm_applet_load(plugin);
  }

  par_freeItemList(list);
}
  
static int
nxLoadSettings(db_handle * db)
{

    char in_string[512];
    int style, size;

    /* First get the directories */

    getDirectory(db, DESKTOP_THEMEDIR, "themedir");
    getDirectory(db, DESKTOP_NXAPPDIR, "bindir");
    getDirectory(db, DESKTOP_IMAGEDIR, "icondir");

  /*--- Get the background image and style ---*/

    size =
	par_getScreentopSetting(db, "bgimage", in_string, sizeof(in_string));

    if (size > 0) {
	wmSettings.wallpaper.bgImage = loadIconImage(in_string, 0, 0);

	if (wmSettings.wallpaper.bgImage) {
	    style = WALLPAPER_CENTERED;

	    size = par_getScreentopSetting(db, "bgstyle", in_string,
					   sizeof(in_string));

	    if (size > 0) {
		strToLower(in_string);

		if (!strcmp(in_string, "bottom"))
		    style = WALLPAPER_BOTTOM;
		else if (!strcmp(in_string, "tiled"))
		    style = WALLPAPER_TILED;
		else if (!strcmp(in_string, "fullscreen"))
		    style = WALLPAPER_FULLSCREEN;
	    }
	} else
	    style = WALLPAPER_NONE;

	wmSettings.wallpaper.flags = style;
    }

  /*--- Now load the color settings ---*/

    getColor(db, WM_BGCOLOR, "bgcolor");
    getColor(db, WM_ICONCOLOR, "iconbgcolor");
    getColor(db, WM_ICONTEXT, "iconfgcolor");
    getColor(db, WM_TASKBAR, "taskbar");
    getColor(db, WM_DIALOG, "dialog");

    /* Get the theme information */

#ifdef CONFIG_PIXILWM_THEMES
    if (wm_getDir(DESKTOP_THEMEDIR)) {
	const char *dir = wm_getDir(DESKTOP_THEMEDIR);
	set_activeTheme(createTheme(dir));
    }
#endif

    /* Lastly, load the taskbar applets */
    nxLoadApplets(db);

    return (0);
}

/* Fixme:  How can we handle reloading settings? */

int
nxLoadConfig(void)
{

    db_handle *db = 0;

    /* Load any defaults */
    bzero(&wmSettings, sizeof(wmSettings));
    nxLoadDefaults();

    /* Now, open the PAR and get ready to read! */
    db = db_openDB(db_getDefaultDB(), PAR_DB_MODE_RDONLY);

    if (!db) {
	error("PAR database open returned error %d\n", pardb_errno);
	return (-1);
    }

    /* Now load in steps.  First the settings */
    nxLoadSettings(db);

    /* Next, get the categories and applications */
    nxLoadCategories(db);

    /* Finally, load the input tools */
    nxLoadInputs(db);

    /* We're done, go ahead and close the database */
    db_closeDB(db);
    return (0);
}

--- NEW FILE: applets.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <errno.h>

#include "nanowm.h"
#include "config.h"
#include "applets.h"

static int g_applet_id = 0;
static int g_timer_id = 0;

static int applet_x, applet_y, applet_h;

static applet_t *applet_list = 0;
static applet_events_t *applet_events = 0;
static icon_applet_t *icon_applets = 0;
static applet_timer_t *applet_timers = 0;

void wm_init_applets(void) {
  GR_SCREEN_INFO	si;
  
  GrGetScreenInfo(&si);

  applet_x = 5;  
  applet_y = si.ws_height + 4; 

  applet_h = 13;
}

void wm_applet_handle_event(GR_EVENT *event) {
  GR_WINDOW_ID wid = ((GR_EVENT_GENERAL *) event)->wid;
  applet_events_t *e = applet_events;

  for( ; e; e = e->next) {
    if (e->wid != wid) continue;
    
    if (e->events & GR_EVENTMASK(event->type)) {
      if (e->cb) e->cb(wid, event);
      break;
    }
  }
}

unsigned long wm_applet_handle_timer(unsigned long elapsed) {
  
  applet_timer_t *timer = applet_timers;
  applet_timer_t *prev = 0, *newhead = 0, *newtail = 0;

  if (!timer) return 0;

  while(timer) {
    applet_timer_t *next = timer->next;

    timer->remain -= elapsed;

    if (timer->remain <= 0) {
      if (timer->callback) timer->callback(); /* Fire the callback */
      
      /* Remove this item from the list */
      
      if (!prev) applet_timers = timer->next;
      else prev->next = timer->next;
      
      /* If this item is periodic, then add it to the bottom */
      /* of the new list */

      /* Otherwise, get rid of the record */

      if (timer->type == APPLET_TIMER_PERIODIC) {
	timer->remain = timer->period;
	timer->next = 0;

	if (!newhead) newhead = newtail = timer;
	else {
	  newtail->next = timer;
	  newtail = timer;
	}
      }
      else free(timer);
    } else prev = timer;
    
    timer = next;
  }
  
  if (!applet_timers) applet_timers = newhead;
  else prev->next = newhead;
  
  if (applet_timers) return applet_timers->remain;
  return 0;
}

unsigned long wm_applet_get_timeout(void) {
  return applet_timers ? applet_timers->remain : 0;
}

void wm_applet_del_timer(int applet_id, int timer_id) {
  applet_timer_t *t = applet_timers;
  applet_timer_t *p = 0;

  while(t) {
    applet_timer_t *n = t->next;

    /* Delete the timer, or all the timers for this applet if timer_id is zero */

    if ( (timer_id && t->id == timer_id) || (!timer_id && t->applet_id == applet_id)) {
      if (!p) applet_timers = t->next;
      else p->next = t->next;
      
      free(t);
      if (timer_id) return;
    } else p = t;
	 
    t = n;
  }
}

int wm_applet_add_timer(int applet_id, int type, unsigned long length, applet_timeout_callback cb) {
  
  applet_timer_t *timer = (applet_timer_t *) calloc(1, sizeof(applet_timer_t));

  timer->applet_id = applet_id;
  timer->period = timer->remain = length;
  timer->type = type;
  timer->id = g_timer_id++;
  timer->callback = cb;

  if (!applet_timers) applet_timers = timer;

  else {
    applet_timer_t *t = applet_timers;
    for( ; t->next; t = t->next);
    t->next = timer;
  }

  return timer->id;
}


/* This is a call for a applet to register its window ID plus a list
   of events that it cares about 
*/

int wm_applet_register(int applet_id, GR_WINDOW_ID id, unsigned long events,
		       applet_event_callback cb) {
  
  applet_events_t *e = applet_events;
  applet_events_t *p = 0;

  for( ; e; e = e->next) {
    if (e->wid != id) continue;

    /* if the bit mask is zero, then erase this record */

    if (events == 0) {
      if (!p) applet_events = e->next;
      else p->next = e->next;
      free(e);
      
      return 0;
    }
    
    /* Otherwise, change the events to reflect the new list */
    e->events = events;

    GrSelectEvents(id, events);
    return 0;
  }

  /* Don't let us add a zero event record */
  if (!events) return 0; 

  /* No record was found, so add one */
  e = (applet_events_t *) calloc(1, sizeof(applet_events_t));
  if (!e) return -1;

  e->wid = id;
  e->applet_id = applet_id;
  e->cb = cb;

  e->events = events;

  if (!applet_events) applet_events = e;
  else {
    applet_events_t *t = applet_events;
    for( ; t->next; t = t->next);
    t->next = e;
  }

  GrSelectEvents(id, events);
  return 0;
}

void wm_applet_unregister(int applet_id, GR_WINDOW_ID gid) {
  wm_applet_register(applet_id, gid, 0, 0);
}

int wm_applet_load(char *filename) {
  
  applet_t *applet = 0;
  if (!filename) return -1;
  
  applet = (applet_t *) calloc(1, sizeof(applet_t));
  if (!applet) return -1;

  applet->handle = dlopen(filename, RTLD_LAZY | RTLD_GLOBAL);

  if (!applet->handle) {
    printf("Unable to load applet [%s] [%s]\n", filename, dlerror());
    goto load_error;
  }

  /* Get the hooks for the applet */
  
  applet->init = (int (*)(int, int *, int, int)) 
    dlsym(applet->handle, "applet_init");

  applet->close = (int (*)(void)) 
    dlsym(applet->handle, "applet_close");

  /* Set the applet id */
  applet->applet_id = g_applet_id++;

  /* Initalize the applet */
  if (applet->init(applet->applet_id, &applet_x, applet_y, applet_h))
    goto load_error;

  /* Insert some padding */
  applet_x += 5;

  /* Finally, insert it into the list of applets */

  if (!applet_list) applet_list = applet;

  else {
    applet_t *a = applet_list;
    for( ; a->next; a = a->next);
    a->next = applet;
  }

  return 0;
  
 load_error:
  printf("Error loading the plugin [%s], bailing!\n", filename);

  if (applet->handle) dlclose(applet->handle);
  free(applet);

  return -1;
}

/*** Utility functions ***/

/* These are common functions that can be defined once and used many times */

/* This creates a icon applet (ie, a picture that gets pressed) */
/* and calls a callback when the icon is pressed */

static void icon_applet_draw(icon_applet_t *icon) {

  GR_GC_ID gc = GrNewGC();
  
  GrDrawImageToFit(icon->wid, gc, 0, 0, -1, -1, icon->image);
  GrDestroyGC(gc);
}

 void icon_applet_callback(GR_WINDOW_ID wid, GR_EVENT *event) {
  
  icon_applet_t *i = icon_applets;

  for( ; i; i = i->next) {
    if (i->wid != wid) continue;
    
    if (event->type == GR_EVENT_TYPE_BUTTON_DOWN) {
      if (i->callback) i->callback();
    }
    else if (event->type == GR_EVENT_TYPE_EXPOSURE) {
      icon_applet_draw(i);
    }
    return;
  }
}
  
GR_WINDOW_ID wm_create_icon_applet(int id, int x, int y, int w, int h, char *filename, 
				   void (*callback)(void)) {
  
  icon_applet_t *icon = (icon_applet_t *) calloc(1, sizeof(icon_applet_t));
  if (!icon) return 0;

  if (!icon->image) icon->image = loadIconImage(filename, 0, 0);
  if (!icon->image) goto exit_icon;

  icon->applet_id = id;
  icon->callback = callback;

  icon->wid = GrNewWindowEx(GR_WM_PROPS_NODECORATE, 0, GR_ROOT_WINDOW_ID,
			    x, y, w, h, 0xFFFFFF);

  if (!icon->wid) goto exit_icon;

  if (!icon_applets) icon_applets = icon;

  else {
    icon_applet_t *i = icon_applets;
    for( ; i->next; i = i->next);
    i->next = icon;
  }

  wm_applet_register(id, icon->wid, GR_EVENT_MASK_BUTTON_DOWN | GR_EVENT_MASK_EXPOSURE,
		     icon_applet_callback);

  GrMapWindow(icon->wid);
  return(icon->wid);

 exit_icon:
  if (icon->image) GrFreeImage(icon->image);
  free(icon);

  return 0;
}

void wm_close_icon_applet(int id) {

  icon_applet_t *i = icon_applets;
  icon_applet_t *p = 0;

  while(i) {
    icon_applet_t *n = i->next;
    if (i->applet_id == id) {

      if (!p) icon_applets = i->next;
      else p->next = i->next;

      if (i->image) GrFreeImage(i->image);
      if (i->wid) GrDestroyWindow(i->wid);

      free(i);
      
    }
    else p = i;
    i = n;
  }
}

--- NEW FILE: applets.h ---
#ifndef APPLET_H_
#define APPLET_H_

#include <nano-X.h>
#include "config.h"

typedef void (*applet_event_callback)(GR_WINDOW_ID, GR_EVENT *);
typedef void (*applet_timeout_callback)(void);

#define APPLET_TIMER_ONESHOT  0
#define APPLET_TIMER_PERIODIC 1

typedef struct applet_timer {
  int id;

  int applet_id;
  signed long remain;
  unsigned long period;
  applet_timeout_callback callback;

  int type;

  struct applet_timer *next;
} applet_timer_t;

typedef struct applet_event {
  int applet_id;
  GR_WINDOW_ID wid;

  unsigned long events;
  applet_event_callback cb;
  
  struct applet_event *next;
} applet_events_t;

typedef struct icon_applet {
  unsigned long applet_id;

  GR_WINDOW_ID wid;
  GR_IMAGE_ID image;

  void (*callback) (void);
  struct icon_applet *next;
} icon_applet_t;

typedef struct applet {
  int applet_id;
  void *handle;
  
  int (*init)(int, int *, int, int);
  int (*close)(void);

  struct applet *next;
} applet_t;

int wm_applet_add_timer(int applet_id, int type, unsigned long length, applet_timeout_callback cb);

unsigned long wm_applet_get_timeout(void);
void wm_applet_handle_event(GR_EVENT *event);
unsigned long wm_applet_handle_timer(unsigned long elapsed);
int wm_applet_load(char *filename);

int wm_applet_register(int applet_id, GR_WINDOW_ID id, unsigned long events,
		       applet_event_callback cb);

void wm_applet_del_timer(int applet_id, int timer_id);

#endif


--- NEW FILE: hardcodedimage.h ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */



#ifndef HARDCODEDIMAGE_INCLUDED

#define HARDCODEDIMAGE_INCLUDED	1

#include "device.h"

#ifdef DEFAULT_WALLPAPER
#undef DEFAULT_WALLPAPER
#define DEFAULT_WALLPAPER	"default.gif"
#endif

static MWUCHAR hardcodedimage[] =
    { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0xf0, 0x0, 0x3c, 0x0, 0x84, 0x0,
    0x0, 0xdf, 0xea, 0xf7, 0x0, 0x5a, 0xbf, 0x10, 0x64, 0xc3, 0x20, 0x6f,
    0xc7, 0x30, 0x79, 0xcb, 0x40,
    0x83, 0xcf, 0x50, 0x8e, 0xd3, 0x60, 0x98, 0xd7, 0x70, 0xa2, 0xdb, 0x80,
    0xad, 0xdf, 0x8f, 0xb7,
    0xe3, 0x9f, 0xc1, 0xe7, 0xaf, 0xcb, 0xeb, 0xbf, 0xd6, 0xef, 0xcf, 0xe0,
    0xf3, 0xef, 0xf5, 0xfb,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff,
    0x21, 0xf9, 0x4, 0x1, 0xa, 0x0, 0x1f, 0x0, 0x2c, 0x0, 0x0, 0x0, 0x0, 0xf0,
    0x0, 0x3c, 0x0, 0x0, 0x5,
    0xfe, 0xe0, 0x27, 0x8e, 0x64, 0x69, 0x9e, 0x68, 0xaa, 0xae, 0x6c, 0xeb,
    0xbe, 0x70, 0x2c, 0xcf,
    0x74, 0x6d, 0xdf, 0x78, 0xae, 0xef, 0x7c, 0xef, 0xff, 0xc0, 0xa0, 0x70,
    0x48, 0x2c, 0x1a, 0x8f,
    0xc8, 0xa4, 0x72, 0xc9, 0x6c, 0x3a, 0x9f, 0xd0, 0xa8, 0x74, 0x4a, 0xad,
    0x5a, 0xaf, 0xd8, 0xac,
    0x76, 0xcb, 0xed, 0x7a, 0x49, 0x5, 0x0, 0xe0, 0xf0, 0x2d, 0x9b, 0x97, 0x6,
    0x88, 0x1a, 0x32, 0x6,
    0x16, 0x12, 0x8a, 0x46, 0x83, 0x91, 0x38, 0x10, 0x72, 0x7, 0xc5, 0x79,
    0xef, 0x33, 0x34, 0xe, 0x5,
    0xd, 0x6b, 0x6c, 0x5, 0x3b, 0x5, 0xc, 0x83, 0x89, 0x10, 0xf, 0xb, 0x77,
    0x23, 0x5, 0x8a, 0x8a, 0x85,
    0x23, 0x9, 0x10, 0x64, 0x2f, 0x82, 0x93, 0x95, 0x91, 0x9c, 0x10, 0xd,
    0x94, 0x6a, 0x9, 0x2f, 0x6a,
    0x93, 0x8f, 0x9d, 0xf, 0xd, 0x8, 0x25, 0xb, 0x6b, 0xc, 0x2b, 0x3, 0x6a,
    0x0, 0x55, 0x88, 0xb1, 0x5,
    0x81, 0x83, 0xd, 0xa5, 0x35, 0xb4, 0x10, 0xb, 0x6, 0x3, 0x8f, 0xa, 0xf,
    0x6b, 0x8e, 0x1f, 0x90,
    0x8b, 0x72, 0xc9, 0xca, 0xc5, 0x1f, 0x9b, 0x97, 0x2d, 0x99, 0x22, 0x7,
    0xca, 0xc9, 0x6b, 0xd4, 0x72,
    0x7a, 0x22, 0x9b, 0xa2, 0x2e, 0xa4, 0x25, 0xc7, 0xa8, 0xd, 0x71, 0xd,
    0xc3, 0x6a, 0xf, 0xcf, 0x3,
    0xe5, 0x10, 0xc0, 0x29, 0xac, 0x10, 0x6, 0x53, 0x80, 0xb7, 0xd6, 0xb6,
    0x82, 0xf4, 0x34, 0x4, 0xe,
    0x6a, 0xe, 0xcc, 0x24, 0x3, 0x82, 0xf, 0xc0, 0xa8, 0xf9, 0xd4, 0x62, 0xd3,
    0x83, 0x7e, 0x29, 0xa2,
    0xa5, 0x58, 0xb3, 0x62, 0xdb, 0x28, 0x8, 0xba, 0x8c, 0xd, 0x34, 0x61,
    0x40, 0x9f, 0x37, 0x11, 0x8,
    0xd6, 0x2c, 0x48, 0x1, 0xb, 0x82, 0xab, 0x28, 0xff, 0x6, 0xd6, 0xc3, 0x55,
    0xc0, 0x0, 0x0, 0x92,
    0x31, 0xfe, 0xd2, 0xed, 0x63, 0xc1, 0x80, 0xa0, 0x88, 0x63, 0x2e, 0x1b,
    0xae, 0x39, 0x8, 0xd, 0xa2,
    0xa, 0x86, 0x2a, 0x1c, 0x76, 0xb3, 0x29, 0xd0, 0x13, 0xa, 0x8b, 0x1f,
    0x45, 0x58, 0x5c, 0x87, 0x82,
    0xd5, 0x3, 0x76, 0x50, 0x4c, 0xe, 0x5a, 0x30, 0x40, 0x29, 0xbd, 0x3, 0x27,
    0x5b, 0x21, 0x65, 0x61,
    0x31, 0x60, 0xc1, 0x9e, 0x31, 0x73, 0xe, 0x3a, 0xca, 0x42, 0x21, 0xa,
    0x9c, 0x29, 0x74, 0xb6, 0xb8,
    0x68, 0xca, 0xe7, 0x89, 0x34, 0x6a, 0x7a, 0xf6, 0x42, 0x31, 0x8c, 0xdb,
    0x13, 0x5, 0x6d, 0xa0, 0x2e,
    0x1d, 0x20, 0x57, 0x6a, 0x5d, 0x35, 0x4c, 0x59, 0x6c, 0xb2, 0x34, 0x3,
    0xa6, 0x8b, 0xbd, 0x2b, 0x57,
    0x78, 0x3d, 0x1, 0x16, 0x85, 0x58, 0x16, 0x64, 0x5f, 0x4e, 0xfc, 0x9a,
    0x96, 0x4, 0xaf, 0xa9, 0xda,
    0xd8, 0x44, 0x19, 0x1a, 0x57, 0x5d, 0x2f, 0xba, 0x51, 0xf1, 0x62, 0x9e,
    0xab, 0xa2, 0x9c, 0xac,
    0xbe, 0x8b, 0xf5, 0x7a, 0x54, 0xe7, 0x40, 0x30, 0x4f, 0xc6, 0x10, 0x64,
    0x42, 0x70, 0x8b, 0xf8,
    0xb4, 0x62, 0xb3, 0x84, 0x1b, 0x8f, 0x50, 0xb9, 0xb6, 0xc4, 0xb0, 0x88,
    0x4b, 0x86, 0xae, 0x71,
    0x50, 0x28, 0x81, 0xe5, 0x8d, 0x77, 0x7b, 0x11, 0xf0, 0xbd, 0x14, 0xc5,
    0x31, 0x8, 0xd9, 0x64, 0xf8,
    0x2d, 0xb8, 0x9a, 0x0, 0x69, 0x15, 0x83, 0x4d, 0x14, 0x3e, 0x71, 0x78,
    0x45, 0x62, 0x89, 0xb0, 0xa5,
    0x2f, 0x32, 0xb1, 0x57, 0x97, 0x82, 0xec, 0x4c, 0x74, 0x27, 0xca, 0xd5,
    0x4c, 0xdd, 0x83, 0x4, 0x3,
    0x88, 0x6b, 0x1c, 0x5e, 0x2e, 0x68, 0x89, 0xbd, 0xf0, 0x40, 0x83, 0xf,
    0xbb, 0xfa, 0x83, 0xf3, 0xdd,
    0x9, 0x5d, 0x6b, 0x4f, 0xad, 0xb5, 0xfe, 0xce, 0x88, 0xcb, 0x99, 0x90,
    0x51, 0x6d, 0x25, 0x44, 0xe5,
    0x52, 0x47, 0x90, 0x29, 0xfe, 0x61, 0x4f, 0x27, 0x9e, 0xf4, 0x66, 0x1e,
    0x7a, 0xea, 0x2d, 0x2, 0x61,
    0x7c, 0x27, 0x2c, 0x98, 0xa0, 0xb, 0x1, 0xca, 0xc4, 0xcd, 0x7d, 0x6a,
    0xb8, 0x47, 0x42, 0x74, 0x25,
    0x4c, 0xc7, 0x5d, 0x28, 0xf, 0x1, 0x18, 0x1a, 0x9, 0xf7, 0x71, 0x65, 0xc2,
    0x71, 0x97, 0xb0, 0xc2,
    0xda, 0x12, 0x80, 0x31, 0xe8, 0x11, 0x30, 0x80, 0x9d, 0x97, 0x9e, 0x3a,
    0x2f, 0x9a, 0x30, 0x54, 0xd,
    0xc7, 0xf0, 0x66, 0xcb, 0x8f, 0xb6, 0x40, 0x56, 0x89, 0x5b, 0x1c, 0x12,
    0xf8, 0xa1, 0x7e, 0x21,
    0xca, 0x66, 0x18, 0x89, 0xff, 0x7d, 0x73, 0xa2, 0x7d, 0xee, 0xd0, 0x84,
    0x2, 0x2d, 0x1, 0x41, 0x62,
    0x55, 0x13, 0x4, 0xc8, 0x18, 0x9, 0x53, 0x3, 0xb8, 0x63, 0x8e, 0x2a, 0x9,
    0x0, 0x50, 0x8, 0x3, 0xa5,
    0xa1, 0xc6, 0x9f, 0x7c, 0x9d, 0xbc, 0x38, 0x24, 0x8a, 0xea, 0x6c, 0x54,
    0x2, 0x88, 0x24, 0x88, 0xf8,
    0x1e, 0x93, 0x63, 0xe9, 0x77, 0xc, 0x0, 0x9, 0x24, 0xb0, 0x40, 0x3, 0x99,
    0xe5, 0xc5, 0x51, 0x7b,
    0xfa, 0x3c, 0xc3, 0xc4, 0x82, 0x5a, 0x26, 0xc2, 0xa5, 0x97, 0x92, 0x7d,
    0x60, 0x40, 0x39, 0x39,
    0x8a, 0x30, 0x8, 0x8f, 0xb1, 0xe4, 0x29, 0xa9, 0xa4, 0x11, 0xad, 0xc9,
    0xa6, 0x46, 0x6f, 0x22, 0x19,
    0xa7, 0x92, 0xd4, 0xd1, 0xd9, 0x9a, 0x89, 0x91, 0xa4, 0x72, 0xe1, 0x88,
    0xf8, 0x39, 0x91, 0x65,
    0xa1, 0x9c, 0x9c, 0xf7, 0x41, 0x97, 0x10, 0xf0, 0xf3, 0x1, 0x2f, 0x6a,
    0x5c, 0xf8, 0x28, 0xd, 0x19,
    0x6a, 0x95, 0x63, 0x91, 0x6e, 0x8a, 0x0, 0xe7, 0x8, 0x72, 0x92, 0x50,
    0xdd, 0x4d, 0x44, 0x61, 0xf5,
    0x81, 0x97, 0x59, 0xad, 0x90, 0x19, 0x6e, 0x49, 0x7c, 0x87, 0xea, 0x3e,
    0x79, 0x2e, 0xa8, 0x2a,
    0x30, 0x8b, 0x2a, 0x92, 0xeb, 0xa6, 0x9c, 0xfe, 0xc2, 0x50, 0x2b, 0x7d,
    0x8d, 0x1e, 0x50, 0x9c,
    0xae, 0x9a, 0xf2, 0x5a, 0xed, 0x9c, 0xfe, 0xd5, 0xb9, 0xe2, 0x62, 0x43,
    0x35, 0x6a, 0x5c, 0xaf,
    0x48, 0x64, 0xa6, 0xa5, 0xab, 0xb3, 0x59, 0x4, 0xc0, 0x1d, 0x88, 0x6e,
    0x75, 0xc2, 0x8e, 0xb4, 0x3e,
    0x89, 0x2d, 0xa, 0xda, 0x62, 0xfa, 0xc1, 0xae, 0x8e, 0x7e, 0xeb, 0x2b,
    0x5e, 0xf, 0x8d, 0xb, 0x9b,
    0x3a, 0x82, 0x5a, 0xe7, 0x2f, 0x12, 0xcb, 0x96, 0x69, 0x42, 0x3, 0xa2,
    0x84, 0xc1, 0x20, 0x85, 0x23,
    0x78, 0x9, 0xb1, 0xb5, 0xf6, 0x2e, 0x69, 0xee, 0x7, 0xf9, 0x2, 0xcc, 0xef,
    0x7, 0xe8, 0x46, 0x36,
    0xdf, 0xb9, 0x67, 0x96, 0xe5, 0xd2, 0xa9, 0x8b, 0x20, 0x84, 0x1a, 0x14,
    0xcb, 0x9a, 0x3c, 0x82,
    0xb2, 0xc, 0x26, 0x37, 0x42, 0xc6, 0xd3, 0x52, 0xfc, 0x71, 0xa7, 0x17,
    0x37, 0xb3, 0xd4, 0xc6, 0x1d,
    0x63, 0xf7, 0x19, 0xb, 0x69, 0x28, 0x2c, 0x32, 0x9, 0x19, 0xef, 0x6c,
    0x70, 0xc8, 0x4c, 0xa0, 0xea,
    0xb3, 0x9, 0xf1, 0x72, 0x52, 0xec, 0x7, 0xe5, 0x5c, 0x19, 0xc3, 0xb5,
    0x16, 0xaf, 0x90, 0x34, 0xb2,
    0xde, 0x12, 0x6d, 0x42, 0x47, 0xc1, 0xae, 0xf0, 0x5d, 0xcc, 0xd8, 0x65,
    0x45, 0x6c, 0x9d, 0x56,
    0x2b, 0x81, 0x6a, 0xcd, 0x31, 0xa6, 0x7a, 0x2, 0xcb, 0x35, 0xa7, 0x0,
    0x35, 0xcd, 0x2c, 0xc4, 0x4b,
    0x75, 0xbf, 0x61, 0x17, 0xe8, 0x69, 0xa, 0xc3, 0x14, 0xdc, 0xb5, 0x8e,
    0xfa, 0x2, 0x1b, 0x37, 0xc2,
    0x85, 0xd6, 0x3c, 0xa0, 0x96, 0x6c, 0xad, 0x31, 0xb1, 0x71, 0xc2, 0x32,
    0x97, 0xb6, 0x8, 0xb0, 0xbe,
    0xcd, 0xf1, 0xc1, 0x23, 0xc, 0xa8, 0x22, 0x7d, 0x42, 0xff, 0x6c, 0x2,
    0xc1, 0x43, 0xa3, 0x5c, 0xe8,
    0xd2, 0x2b, 0xa3, 0x8a, 0x2, 0x87, 0xf, 0x28, 0xfe, 0x81, 0x30, 0xfe,
    0x85, 0x8b, 0x76, 0xb8, 0x50,
    0x6b, 0x28, 0x9e, 0xb3, 0x8, 0x51, 0x39, 0x30, 0x2a, 0xc6, 0x6a, 0xd8,
    0x7d, 0xb7, 0x9, 0x24, 0x77,
    0xb, 0x37, 0x14, 0x84, 0x2a, 0xbd, 0x3a, 0xd3, 0x9a, 0x6f, 0x8e, 0x23,
    0xa, 0x8, 0xc, 0x13, 0x53,
    0x8f, 0x40, 0x6, 0x3f, 0x95, 0xa5, 0x2d, 0x58, 0x64, 0x3a, 0xe3, 0x23,
    0x70, 0x9e, 0xe3, 0x21, 0x0,
    0x9f, 0xb0, 0xf6, 0xdf, 0x8f, 0xef, 0x7, 0x45, 0xd9, 0x5b, 0xa9, 0x92,
    0x47, 0x51, 0x46, 0xab, 0x30,
    0x0, 0xac, 0x74, 0x48, 0xba, 0x20, 0x0, 0x10, 0x1f, 0x97, 0xe6, 0xbf,
    0xa3, 0x8f, 0x70, 0x9b, 0xde,
    0x2e, 0x10, 0xa0, 0xae, 0x1c, 0x7b, 0x66, 0x76, 0xf1, 0xda, 0xaf, 0x96,
    0x1a, 0xdb, 0xde, 0x47,
    0xc4, 0x3e, 0xde, 0x0, 0x4, 0xd8, 0xc3, 0x75, 0xd2, 0x9d, 0x78, 0x78,
    0xc2, 0x0, 0xa, 0x10, 0x8f,
    0x39, 0x18, 0x60, 0xb7, 0xfc, 0x5d, 0x83, 0x1a, 0x82, 0x9a, 0x86, 0xeb,
    0x52, 0xe0, 0x1c, 0xc5,
    0x25, 0x3, 0x6, 0x7, 0x80, 0xd5, 0x1a, 0x0, 0xa0, 0x80, 0xdb, 0x19, 0xd0,
    0x65, 0x26, 0x68, 0x89,
    0x1c, 0x54, 0x51, 0x21, 0x39, 0x44, 0xa1, 0x76, 0x8b, 0x50, 0x5, 0xfe,
    0xbe, 0xa7, 0x0, 0x5b, 0xc0,
    0x65, 0x59, 0x10, 0xe0, 0x20, 0x86, 0x80, 0x74, 0xbb, 0x22, 0xb4, 0xd0,
    0x6, 0x3, 0x0, 0x12, 0x1f,
    0x72, 0x20, 0x3e, 0x4f, 0xc4, 0xf0, 0x24, 0x4c, 0x99, 0x7, 0xa, 0x13,
    0xf1, 0xc2, 0x19, 0xfa, 0x70,
    0xa, 0x54, 0x12, 0xa1, 0x65, 0x1a, 0xa6, 0x2e, 0x14, 0x72, 0xed, 0x87,
    0x48, 0xbc, 0x2, 0x2a, 0x9a,
    0x82, 0xa7, 0x1b, 0xcd, 0x44, 0x14, 0xc1, 0x41, 0xd5, 0x85, 0x6a, 0xb8,
    0xc3, 0x2a, 0x5a, 0xf1,
    0x8a, 0x58, 0xcc, 0xa2, 0x16, 0xe9, 0x87, 0x4, 0x60, 0xf0, 0xc2, 0x46,
    0x11, 0x52, 0xfe, 0x55, 0x14,
    0x19, 0xf4, 0xbe, 0xe0, 0x99, 0xf1, 0x8c, 0x68, 0x4c, 0xa3, 0x1a, 0xd7,
    0xc8, 0xc6, 0x36, 0xba,
    0xf1, 0x8d, 0x70, 0x8c, 0xa3, 0x2d, 0xa4, 0x70, 0x80, 0x4, 0x10, 0x0,
    0x51, 0x6d, 0x40, 0x94, 0xaa,
    0x22, 0xd4, 0x89, 0xa3, 0x25, 0xf1, 0x8f, 0x54, 0x8, 0xc9, 0x22, 0xe,
    0xc0, 0xaa, 0x9, 0x12, 0x52,
    0x8f, 0x64, 0xe0, 0x63, 0x22, 0xfc, 0x8, 0xc8, 0x46, 0x42, 0xa1, 0x90,
    0xb1, 0x20, 0x24, 0xac, 0xc6,
    0x0, 0x49, 0x36, 0x24, 0xd2, 0x32, 0xb1, 0x68, 0xe1, 0x2, 0x0, 0xe0, 0x80,
    0x5, 0x4e, 0xe3, 0x1,
    0x0, 0x60, 0xc0, 0xe0, 0x74, 0x95, 0x8c, 0x82, 0x4d, 0xe3, 0x81, 0x24,
    0x40, 0x80, 0xa, 0x1b, 0xc0,
    0x8e, 0x3a, 0x3a, 0x8f, 0x3c, 0x67, 0x4b, 0x6, 0x6, 0x45, 0x60, 0x40,
    0x39, 0xa8, 0xcc, 0x38, 0xc,
    0x0, 0x0, 0x2a, 0x16, 0xd8, 0xc, 0x41, 0x0, 0xa0, 0x11, 0x27, 0xc8, 0x5f,
    0xf8, 0xfe, 0x0, 0x12,
    0x3c, 0x2, 0x82, 0x50, 0xe0, 0xab, 0x64, 0x1e, 0x7, 0xc1, 0xc8, 0x12,
    0x20, 0xa0, 0x34, 0x59, 0x4a,
    0xd0, 0x2, 0x1c, 0x10, 0x9f, 0x3, 0x30, 0x82, 0x30, 0x3f, 0x82, 0x4c, 0xc,
    0x1d, 0xb0, 0x0, 0x0,
    0x7d, 0x46, 0x5b, 0x1c, 0x4, 0x5f, 0x85, 0x1c, 0x80, 0xb9, 0x54, 0xd4,
    0xa3, 0x58, 0x5, 0xf0, 0x91,
    0xe7, 0xde, 0x73, 0xe, 0x11, 0x54, 0xc4, 0x7f, 0x1f, 0x20, 0xa7, 0x23,
    0x7a, 0x67, 0xb7, 0x2, 0x80,
    0xf2, 0x48, 0xe5, 0x2b, 0x42, 0xfe, 0x6, 0x31, 0x6, 0x1d, 0x36, 0xc8,
    0x9f, 0x94, 0x64, 0xc5, 0x11,
    0x5, 0x4, 0x80, 0x51, 0x59, 0xb3, 0x4, 0xe9, 0x40, 0x8, 0x17, 0x19, 0x76,
    0x2, 0x71, 0x6a, 0xd0,
    0x18, 0x91, 0x7b, 0x49, 0x40, 0x3a, 0x57, 0xa1, 0x49, 0x40, 0x62, 0x45,
    0x98, 0x53, 0x41, 0xfe,
    0x96, 0xfa, 0x81, 0x9b, 0x38, 0x7c, 0xc3, 0x69, 0x2f, 0x91, 0xc3, 0x25,
    0xec, 0xe9, 0x80, 0x7c,
    0x1a, 0xc1, 0x9f, 0x3e, 0x22, 0x54, 0x2e, 0xfc, 0xd9, 0x80, 0x5b, 0x52,
    0x47, 0xc, 0x39, 0x82, 0xc3,
    0xc2, 0x72, 0xe4, 0x9, 0x91, 0x56, 0xa8, 0x51, 0x8, 0x70, 0x5, 0x4, 0xb2,
    0x34, 0xac, 0x46, 0x31,
    0x34, 0x1, 0x4b, 0xcb, 0x5, 0x1, 0xe, 0x40, 0xce, 0x15, 0x85, 0xa3, 0xa5,
    0x2e, 0x98, 0x6, 0x34,
    0x68, 0xa, 0xa0, 0x5c, 0x7c, 0xe6, 0xf, 0xc, 0xb5, 0x2, 0x4b, 0x6d, 0xb1,
    0xbe, 0x91, 0x78, 0xa4,
    0x2f, 0x14, 0x4d, 0xa5, 0x1f, 0xc5, 0x19, 0x22, 0xc1, 0x98, 0x6b, 0x35,
    0xa5, 0x61, 0x40, 0x46,
    0x12, 0x4, 0x9, 0x72, 0xea, 0x3, 0x37, 0xb9, 0xd0, 0xd6, 0x11, 0x3, 0xa1,
    0x1c, 0x90, 0x4e, 0x9,
    0x83, 0xb0, 0x80, 0xc, 0x5b, 0xff, 0x10, 0x86, 0x7d, 0x99, 0x34, 0x9,
    0x53, 0xd, 0x4e, 0x4b, 0x4b,
    0x12, 0x3, 0x3a, 0xa0, 0xe, 0x37, 0xd7, 0x8c, 0x18, 0x23, 0x17, 0x6a,
    0xae, 0x5, 0x3c, 0xc0, 0x7a,
    0xf, 0x80, 0x67, 0x54, 0x7b, 0xb9, 0xb0, 0x42, 0x4, 0xf0, 0x95, 0xda,
    0x33, 0x19, 0x37, 0x7d, 0xe5,
    0x3f, 0x48, 0x8, 0x6a, 0xb2, 0xdf, 0xf8, 0x44, 0x18, 0x88, 0xb9, 0x58,
    0x2c, 0xe8, 0xb5, 0x0, 0x77,
    0x99, 0x65, 0xb, 0xec, 0xc9, 0x27, 0x46, 0xe6, 0xf, 0x0, 0x72, 0x8, 0xac,
    0x74, 0xbc, 0x7a, 0x2e,
    0x76, 0xbc, 0xc3, 0xa8, 0xb6, 0x89, 0x8, 0x2c, 0xe7, 0x60, 0xd4, 0x64,
    0x20, 0x4, 0xa8, 0x45, 0x9,
    0x7, 0x6a, 0x4d, 0x16, 0x6, 0x72, 0x92, 0x43, 0xb4, 0x6c, 0xdd, 0xd7,
    0x53, 0xef, 0xca, 0x84, 0xe0,
    0x30, 0x65, 0x1a, 0xeb, 0x54, 0x41, 0x1, 0x5c, 0x1a, 0x43, 0xc5, 0x79,
    0x8e, 0x0, 0xab, 0x2b, 0x5,
    0xb2, 0x47, 0xf0, 0x57, 0x2, 0xe8, 0x56, 0x17, 0xc, 0xce, 0xfb, 0xd1,
    0xff, 0x5c, 0x1a, 0xa4, 0x15,
    0x10, 0x60, 0x8e, 0xc, 0x14, 0xc1, 0x0, 0xd8, 0x61, 0x5d, 0x2f, 0x4, 0xc7,
    0xa5, 0x8e, 0x4c, 0xaf,
    0xf, 0xad, 0xc9, 0x2e, 0xf5, 0xba, 0xf7, 0xbd, 0xf0, 0x8d, 0xaf, 0x7c,
    0xe7, 0x4b, 0xdf, 0xfa, 0xda,
    0xf7, 0xbe, 0xf8, 0xcd, 0xaf, 0x7e, 0xf7, 0xcb, 0xdf, 0xfe, 0xfa, 0xf7,
    0xbf, 0x0, 0xe, 0xb0, 0x80,
    0x7, 0xdc, 0x84, 0x10, 0x0, 0x0, 0x3b
};


#define	SIZE_hardcodedimage	1987



#endif /* ! HARDCODEDIMAGE_INCLUDED */

--- NEW FILE: screensaver.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */

#include <pixil_config.h>
#include <stdio.h>

#include <nano-X.h>
#include <nxcolors.h>

#include "powerman.h"

static int g_active = 0;
static GR_WINDOW_ID swindow = 0;

static void draw_screensaver(void) {
  GR_SCREEN_INFO si;
  GR_GC_ID gc = GrNewGC();

  GrGetScreenInfo(&si);

  GrSetGCForeground(gc, GR_COLOR_BLACK);
  GrFillRect(swindow, gc, 0, 0, si.cols, si.rows);
  
  GrDestroyGC(gc);
}

static int handle_screensaver(void) {
  GR_EVENT event;
  GrGetNextEvent(&event);

  switch(event.type) {
  case GR_EVENT_TYPE_EXPOSURE:
    if (event.exposure.wid == swindow) draw_screensaver();
    break;
  case GR_EVENT_TYPE_SCREENSAVER:
    if (!event.screensaver.activate) return 1;
  }

  return 0;
}

/* Why make a window and raise it - it was either that or copy off
   the root window, suspend all updates, and blank it.  I just think
   this was an easier way to go about it.
*/

static void do_screensaver(void) {
  GR_SCREEN_INFO si;

  GrGetScreenInfo(&si);
  
  if (!swindow)
    swindow = GrNewWindowEx(GR_WM_PROPS_NODECORATE, 0,
			    GR_ROOT_WINDOW_ID, 0, 0, si.cols, si.rows, 
			    GR_COLOR_BLACK);			
  
  GrSelectEvents(swindow, GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_SCREENSAVER);

  /* Turn off the backlight if we can */
  pm_backlight(0);

  GrRaiseWindow(swindow);  /* Raise it to the top */
  GrMapWindow(swindow);

  while(!handle_screensaver());
  GrUnmapWindow(swindow);

  /* Turn back on the backlight */
  pm_backlight(1);
}

void screensaver_init(void) {
	
#ifdef CONFIG_PIXILWM_PM
  pm_init();   /* Do the power management bit */
#else  
  GrSetScreenSaverTimeout(30); /* Set the screensaver timeout */
#endif
}

int screensaver_active(void) { return g_active; }

void screensaver_enable(void) {

  if (g_active) return;
  
#ifdef CONFIG_PIXILWM_PM
  pm_bltimer_off();
  g_active = 1;
#else
  do_screensaver();
#endif
}

void screensaver_disable(void) {
  
  if (!g_active) return;
  
#ifdef CONFIG_PIXILWM_PM
  pm_bltimer_on();
  g_active = 0;
#endif
}

/* Ugly, I know - but this is the best way to do this, I think */

#ifndef CONFIG_PIXILWM_PM

#include <pixlib/pixlib.h>

void pm_backlight(int mode) {

  /* FIXME:  We need a get current level */

  int max = pix_bl_getmxval();
  if (max == -1) return;

  if (mode) 
    pix_bl_ctrl(mode, 0);
  else
    pix_bl_ctrl(mode, max);
}

#endif

--- NEW FILE: Makefile ---
#nanox/pixilwm/Makefile

CFLAGS ?=
CFLAGS += -DVIRTUAL_WINDOWS 

INCLUDES += -I$(BASE_DIR)/sys/pixilwm

INSTALL_SODIR=$(INSTALL_DIR)/share/pixilwm
TARGET=pixilwm

# These are extra targets that are defined locally

TARGET_EXTRAS += applets/date.so

ifeq ($(CONFIG_PIXILWM_PM),y)
TARGET_EXTRAS += applets/backlight.so
TARGET_EXTRAS += applets/battery.so
endif

INSTALL_EXTRAS=inst_applets

ifeq ($(CONFIG_PIXILWM_THEMES),y)
INSTALL_EXTRAS += inst_themes 
endif


OBJS-y =  applets.o main.o wlist.o config.o clients.o container.o 
OBJS-y += inputs.o apps.o home.o root.o categories.o exec.o 
OBJS-y += icons.o screensaver.o

OBJS-$(CONFIG_COLOSSEUM) += ipc.o
OBJS-$(CONFIG_PIXILWM_PM) += powerman.o
OBJS-$(CONFIG_PIXILWM_THEMES) += themes.o themesconfig.o
OBJS-$(CONFIG_PIXILWM_MENUS) += sys_menu.o

OBJS := $(OBJS-y)

LIBS+= -lwm -lpixil -lnano-X  

ifeq ($(CONFIG_PIXILWM_THEMES),y)
LIBS += -lxml
endif

ifeq ($(CONFIG_COLOSSEUM),y)
LIBS+=-lipc
endif

ifeq ($(CONFIG_PAR), y)
LIBS+=-lpar
endif

LIBS+=-ldl
BUILD_CFLAGS=-rdynamic

CLEAN_EXTRAS=clean_themes

include $(BASE_DIR)/Rules.make

clean_themes:
	rm -rf applets/*.o
	rm -rf applets/*.so

inst_themes:
	mkdir -p $(INSTALL_DIR)/share/themes
	cp -r themes/pixil $(INSTALL_DIR)/share/themes

inst_applets:
	mkdir -p $(INSTALL_DIR)/share/pixilwm
	cp applets/*.so $(INSTALL_DIR)/share/pixilwm

applets/backlight.so: applets/backlight.o
	$(CC) -shared -o $@ $<

applets/battery.so: applets/battery.o
	$(CC) -shared -o $@ $< 

applets/date.so: applets/date.o
	$(CC) -shared -o $@ $<




--- NEW FILE: keyb.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "nano-X.h"
#include "apps.h"
#include "nanowm.h"
#define APPICON		"nxkbd.gif"

static GR_IMAGE_ID imageid;
static GR_BOOL appvisible = 0;

static void keyboard_wndproc(win * window, GR_EVENT * ep);

void
keyboard_create()
{
    GR_WINDOW_ID wid;
    APP *p;
    GR_SCREEN_INFO si;

    GrGetScreenInfo(&si);
    wid = GrNewWindowEx(GR_WM_PROPS_NODECORATE, NULL, GR_ROOT_WINDOW_ID,
			si.ws_width - 40, si.ws_height + 2, 20, 20,
			COLOR_TASKBAR);
    add_window(wid, GR_ROOT_WINDOW_ID, 0, keyboard_wndproc);

    p = find_app_flags(FL_KEYBOARD);
    if (p)
	p->m_icon_wid = wid;

    GrSelectEvents(wid, GR_EVENT_MASK_BUTTON_DOWN | GR_EVENT_MASK_EXPOSURE);
    GrMapWindow(wid);
}

static void
keyboard_exposure(win * window, GR_EVENT_EXPOSURE * ep)
{
    GR_GC_ID gc = GrNewGC();

    if (!imageid) {
	char path[256];

	sprintf(path, "%s/%s", get_desktop_config(DESKTOP_IMAGEDIR), APPICON);
	imageid = GrLoadImageFromFile(path, 0);
    }

    GrDrawImageToFit(ep->wid, gc, 0, 0, -1, -1, imageid);

    GrDestroyGC(gc);
}


static void
keyboard_buttondown(win * window, GR_EVENT_BUTTON * ep)
{
    APP *p = find_app_flags(FL_KEYBOARD);

    if (!p) {
	printf("Unable to find the scribble app!\n");
	return;
    }

    if (is_app_running(p)) {
	if (appvisible) {
	    hide_application(p);
	    appvisible = 0;
	} else {
	    show_application(p);
	    appvisible = 1;
	}
    } else {
	launch_application(p);
	appvisible = 1;
    }
}

#ifdef NOTUSED

static void
keyboard_buttondown(win * window, GR_EVENT_BUTTON * ep)
{
    char *kbdArgv[4] = { 0 };	/* Arg vector */
    static char kymap[256] = { 0 },	/* Path to the keymap files */
      kyword[32] =
    {
    0};				/* Keyboard keyword */
    APP *p = find_app_flags(FL_KEYBOARD);
    GR_SCREEN_INFO si;		/* Screen info */

    GrGetScreenInfo(&si);
    if (!p)
	return;

    if (p->m_process_id && p->m_container_wid) {

	appvisible = !appvisible;

	if (appvisible) {
	    GrMapWindow(p->m_container_wid);
	    GrRaiseWindow(p->m_container_wid);
	} else {
	    GrUnmapWindow(p->m_container_wid);
	}
    } else if (!(p->m_process_id = fork())) {
	printf("execing %s\n", p->m_exec);
	/* Set up the keyboard environment for execvp */
	if (!kymap[0] && !kyword[0]) {
	    char cfgpath[255] = { '\0' };	/* Config path */

	    sprintf(cfgpath, "%s", nxGetConfigFile(NX_CONFIG_MAIN));

	    /* Get the path to the keymap files */

	    IniGetString("nxkeyboard", "kymap", "", kymap, sizeof(kymap),
			 cfgpath);
	    IniGetString("nxkeyboard", "kybsize", "", kyword, sizeof(kyword),
			 cfgpath);
	    if (kymap[0] > ' ') {
		memset(cfgpath, 0, sizeof(cfgpath));
		desktop_expand_path(kymap, cfgpath, sizeof(cfgpath));
		memcpy(kymap, cfgpath, strlen(cfgpath));
	    } /* end of if */
	    else {
		/* Get the default path */
		sprintf(kymap, "%s", get_desktop_config(DESKTOP_NXAPPDIR));
		printf("set kymap to %s\n", kymap);
	    }			/* end of else */

	    /* Get the mapset/size variable from the config */
	    if (kyword[0] < ' ') {
		printf("kyword not found\n");
		/* Use the defaults */
		printf("Cols=%d Rows=%d\n", si.cols, si.rows);
		if (si.rows <= 240)
		    sprintf(kyword, "sml");
		else if (si.rows <= 480)
		    sprintf(kyword, "mid");
		else
		    sprintf(kyword, "big");

		printf("kyword set to %s\n", kyword);
	    }			/* end of if */
	}

	/* end of if */
	/* Put the name of the executable in kbdArgv[0] */
	if ((kbdArgv[0] =
	     (char *) calloc(sizeof(char), strlen(p->m_exec) + 1)) == NULL
	    || memcpy(kbdArgv[0], p->m_exec, strlen(p->m_exec)) == NULL) {
	    printf("Error allocating memory for %s\n", p->m_exec);
	} /* end of if */
	else if ((kbdArgv[1] =
		  (char *) calloc(sizeof(char),
				  strlen(kymap) + 1 + 3)) == NULL
		 || !sprintf(kbdArgv[1], "-d%s", kymap)) {
	    printf("Error allocating memory for %s %s\n", p->m_exec, kymap);
	} /* end of else-if */
	else if ((kbdArgv[2] =
		  (char *) calloc(sizeof(char),
				  strlen(kyword) + 1 + 3)) == NULL
		 || !sprintf(kbdArgv[2], "-m%s", kyword)) {
	    printf("Error allocating memory for %s %s -k %s\n", p->m_exec,
		   kymap, kyword);
	} /* end of else-if */
	else {
	    int i = 0;
	    while (kbdArgv[i]) {
		printf("kbdArgv[%d]=%s\n", i, kbdArgv[i]);
		i++;
	    }			/* end of while */
	    execvp(p->m_exec, kbdArgv);
	}			/* end of else */
	exit(0);
    } else {
	g_last_window = p->m_icon_wid;
	LastLaunchedApp = p;
	appvisible = 1;
    }
}
#endif

static void
keyboard_wndproc(win * window, GR_EVENT * ep)
{
    switch (ep->type) {
    case GR_EVENT_TYPE_EXPOSURE:
	keyboard_exposure(window, &ep->exposure);
	break;
    case GR_EVENT_TYPE_BUTTON_DOWN:
	keyboard_buttondown(window, &ep->button);
	break;
    }
}

--- NEW FILE: exec.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>

#include "apps.h"
#include "nanowm.h"

#define ASSOC_FILE "config.magic"

NXLISTHEAD active_list;

static PROCESS *
find_process(int pid)
{
    PNXLIST p = active_list.head;

    for (; p; p = p->next) {
	PROCESS *process = nxItemAddr(p, PROCESS, next);

	if (process->pid == pid)
	    return (process);
    }

    return NULL;
}

void
kill_running_processes()
{
    PNXLIST p = active_list.head;

    while (p) {
	PNXLIST n = p->next;
	PROCESS *process = nxItemAddr(p, PROCESS, next);

	warning("Terminating process %d\n", process->pid);

	kill(process->pid, SIGTERM);
	p = n;
    }
}

static int
local_parseArgs(char *name, char *argstr, char ***argv)
{
    char **argvptr = 0;

    char *h = argstr;
    char *t = 0;

    int argc = 1;
    int index = 0;

    /* If there are arguments, then count them */

    if (argstr) {
	while ((t = strchr(h, ' '))) {
	    /* Skip to the next empty space */
	    for (; *t == ' ' && *t != 0; t++);

	    if (*t == 0)
		break;

	    argc++;
	    h = t;
	}
    }

    /* Now, allocate the required room */
    *argv = (char **) malloc((argc + 2) * sizeof(char *));

    if (!*argv)
	return (0);

    argvptr = *argv;

    /* First step, add the program name */
    argvptr[0] = (char *) calloc(1, strlen(name) + 1);
    strcpy(argvptr[0], name);

    if (!argstr || !strlen(argstr)) {
	argvptr[1] = (char *) 0;
	return (1);
    }

    /* Now add any args (if they exist) */

    h = argstr;

    while (index < argc) {
	int slen = 0;

	t = strchr(h, ' ');

	if (t)
	    slen = (int) (t - h);
	else
	    slen = strlen(argstr) - (int) (h - argstr);

	argvptr[++index] = (char *) calloc(1, slen + 1);

	/* If there was an error, skip to the next one */

	if (!argvptr[index]) {
	    index--;

	    if (!t)
		break;

	    /* Skip to the next word */
	    for (; *t == ' ' && *t != 0; t++);

	    if (*t == 0)
		break;

	    h = t;
	    continue;
	}

	if (t)
	    strncpy(argvptr[index], h, slen);
	else
	    strcpy(argvptr[index], h);

	if (!t)
	    break;

	/* Skip to the next word */
	for (; *t == ' ' && *t != 0; t++);

	if (*t == 0)
	    break;

	h = t;
	continue;
    }

    /* Add a null pointer to the end */
    argvptr[++index] = (char *) 0;
    return (index);
}

static void
local_freeArgs(int argc, char **argv)
{

    int i;

    for (i = 0; i < argc; i++)
	free(argv[i]);

    free(argv);
}

void
application_handler(int id)
{
    int status;
    int ret;

    while (1) {
	ret = waitpid(-1, &status, WNOHANG);

	if (ret == -1 || ret == 0)
	    break;
	else {
	    PROCESS *proc = find_process(ret);

	    warning("Process %d died with status %d\n", ret, status);

	    if (!proc)
		return;

	    if (proc->app) {
		proc->app->m_process_id = 0;
		proc->app->m_container_wid = 0;

		if (proc->app->m_flags & FL_INPUT)
		    killInput(proc->app);
	    }

	    /* Remove it from the active list */
	    nxListRemove(&active_list, &proc->next);
	}
    }
}

static int
local_spawn(char *exec, char *argstr, char *workdir)
{

    char **argv = 0;
    int pid;

    int argc = local_parseArgs(exec, argstr, &argv);
    if (!argc)
	return (-1);

    if (!(pid = fork())) {
	if (strlen(workdir))
	    if (chdir(workdir))
		error("Unable to switch to working directory '%s'.\n",
		      workdir);

	execvp(exec, argv);
	exit(0);
    }

    local_freeArgs(argc, argv);
    if (pid == -1)
	error("Unable to fork app: %s\n", strerror(errno));

    return (pid);
}

static int
show_window(APP * app)
{
    g_last_app = app;

    container_activate(app->m_container_wid);
    if (isInputVisible() == 0)
	inputResetWorkspace();
    return (0);
}

int
launch_application(APP * app)
{
    int pid;

    /* Check to see if we have a container wid */

    if (app->m_container_wid)
	return (show_window(app));

    /* Don't worry about the process list if we are using ipcActive() */
    if (ipcActive()) {
	pid = ipcSpawnApp(app->m_name, 0);

	if (pid < 0) {
	    error("Problem while spawning '%s' (error code = %d).\n",
		  app->m_name, pid);

	    return (-1);
	}

	app->m_process_id = pid;
    } else {
	PROCESS *proc = nxItemNew(PROCESS);

	pid = local_spawn(app->m_exec, app->m_args, app->m_workdir);

	if (pid < 0) {
	    error("Problem while spawning '%s'.\n", app->m_name, pid);

	    free(proc);
	    return (-1);
	}

	proc->pid = pid;
	proc->app = app;
	app->m_process_id = pid;

	nxListAdd(&active_list, &proc->next);
    }

    return (0);
}

inline void
hide_application(APP * app)
{
    container_hide(app->m_container_wid);
}

void
show_application(APP * app)
{
    if (!app || !app->m_container_wid)
	return;
    container_activate(app->m_container_wid);
}

inline int
is_app_running(APP * app)
{
    return (app->m_process_id || app->m_container_wid);
}

/* File association stuff that may be used in the future? */

#ifdef NOTUSED

#define FILE_ASSOC_COUNT 3

typedef struct
{
    int active;
    int age;
    char application[512];
    char args[256];
}
file_assoc_cache_t;

file_assoc_cache_t file_assoc_cache[FILE_ASSOC_COUNT];

static int
get_new_cache_entry()
{
    int i = 0;
    int use_slot = -1;
    int oldest_slot = -1;
    int oldest_age = 0;

    /* Determine a cache location for this entry. */
    /* Look for an empty entry and age the other entries at the same time */

    for (i = 0; i < FILE_ASSOC_COUNT; i++) {
	if (!file_assoc_cache[i].active) {
	    if (use_slot == -1)
		use_slot = i;
	} else {
	    if (++file_assoc_cache[i].age > oldest_age) {
		oldest_age = file_assoc_cache[i].age;
		oldest_slot = i;
	    }
	}
    }

    if (use_slot == -1)
	use_slot = oldest_slot;

    return (use_slot);
}


/* get_file_association()
   Search the associations file to see if 
   an application has been specified for this file 
*/

static void
assoc_callback(char *key, char *value, int data)
{
    if (!strcmp(key, "app")) {
	strcpy(file_assoc_cache[data].application, value);
	return;
    }

    if (!strcmp(key, "args")) {
	strcpy(file_assoc_cache[data].args, value);
	return;
    }
}

/* Stuff for the future? */

int
get_file_association(char *filename, char *type, app_info_t * ainfo)
{
    char buf[4096];
    int slot;

    char *afile;

    /* Search for the global configuration file and store the location */
    nxLoadConfigFile(ASSOC_FILE, NX_CONFIG_ASSOC);

    afile = nxGetConfigFile(NX_CONFIG_ASSOC);
    if (!afile) {
	printf("Unable to read the file %s\n");
	return (-1);
    }

    slot = get_new_cache_entry();

    bzero(&file_assoc_cache[slot], sizeof(file_assoc_cache_t));

    file_assoc_cache[slot].active = 1;

    if (IniGetString(type, NULL, "", buf, sizeof(buf), afile)) {
	IniEnumKeyValues(buf, assoc_callback, slot);

	/* Now, construct the app info */
	strcpy(ainfo->path, file_assoc_cache[slot].application);

	str_replace_variable("$file", filename, file_assoc_cache[slot].args,
			     ainfo->args, sizeof(ainfo->args));

	return (0);
    }

    return (-1);
}

#endif

--- NEW FILE: categories.h ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#ifndef CATAGORIES_H
#define CATAGORIES_H

typedef struct category_struct
{

    char *title;

    int index;
    int count;

    APP **apps;

    struct category_struct *next;
    struct category_struct *prev;
}
category_t;

/* categories.c */
void nxFreeCategories(void);
int nxLoadCategories(db_handle * db);
int category_getCurrentWin(void);
int category_getCount();
int switchCategory(int index);
category_t *category_getCurrent(void);
int category_setCurrent(int index);
void create_categoryBrowser(void);
void draw_categoryBrowser(GR_REGION_ID r);

#endif

--- NEW FILE: nanowm.h ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */



/* Portions Copyright (C) 2000 Alex Holden <alex at linuxhacker.org> */

#ifndef _NANOWM_H_
#define _NANOWM_H_

#include "apps.h"
#include "categories.h"
#include "sys_menu.h"

#ifdef DEBUG
#define Dprintf printf
#else
#define Dprintf(ignore...)
#endif

#include <par/pardb.h>

typedef struct windowlist *winptr;
typedef void (*wndproc) (struct windowlist * window, GR_EVENT * ep);

struct pos_size
{
    GR_COORD xoff;
    GR_COORD yoff;
    GR_COORD xorig;
    GR_COORD yorig;
    GR_SIZE width;
    GR_SIZE height;
};

/* all root-mapped windows are kept track of with this structure*/
struct windowlist
{
    GR_WINDOW_ID wid;		/* The ID of this window */
    GR_WINDOW_ID pid;		/* The ID of this window's parent */
    GR_WINDOW_ID clientid;	/* clientid for container window */
    GR_BOOL mousedn;		/* TRUE when mouse is down in window */
    GR_COORD x;			/* mouse down coordinates */
    GR_COORD y;
    wndproc proc;		/* callback associated with window */
    struct windowlist *next;	/* The next window in the list */
    int sizing;			/* used during resize handling */
    struct pos_size pos;	/* used during resize/move handling */

    struct
    {
	struct windowlist *next;
	struct windowlist *prev;
    }
    zorder;
};
typedef struct windowlist win;


/* LOGGING MACROS */

#define LOG_ERROR 1
#define LOG_WARNING 2
#define LOG_DEBUG 3

void scrtop_log_message(int level, char *fmt, ...);

#define debug(fmt, args...) scrtop_log_message(LOG_DEBUG, fmt, ## args)
#define warning(fmt, args...) scrtop_log_message(LOG_WARNING, fmt, ## args)
#define error(fmt, args...) scrtop_log_message(LOG_ERROR, fmt, ## args)

/* wlist.c*/
win *find_window(GR_WINDOW_ID wid);
win *add_window(GR_WINDOW_ID wid, GR_WINDOW_ID pid, GR_WINDOW_ID clid,
		wndproc proc);
int remove_window(win * window);
int remove_window_and_children(win * window);
void resize_windows(int width, int height);

int zorder_push(GR_WINDOW_ID id);
GR_WINDOW_ID zorder_peek_top(void);
void zorder_remove(GR_WINDOW_ID id);
void zorder_raise(GR_WINDOW_ID id);


/* main.c*/
typedef void (*scrtop_timer_cb)(void);

void scrtop_register_timer(GR_TIMER_ID id, void (*callback)(void));
void scrtop_unregister_timer(GR_TIMER_ID id);

void timeout_setproc(wndproc proc, win * window);

/* categories.c */
wm_menu_t *create_categoryMenu(int index, char *name);

/* container.c*/
void container_wndproc(win * window, GR_EVENT * ep);
void container_activate(GR_WINDOW_ID wid);
void container_hide(GR_WINDOW_ID wid);

/* clients.c*/
int client_updatemap_new(GR_WINDOW_ID wid);
void setWorkspace(int width, int height);
void getWorkspace(int *width, int *height);

/* apps.c */
void apps_free_memory();

/* root.c */
void root_free_memory();
inline void redraw_root_window();

/* icons.c */
void hide_icon_list(void);
void draw_current_iconlist(GR_REGION_ID r);
GR_WINDOW_ID create_icon_window();

GR_IMAGE_ID loadIconImage(char *filename, char *app, int useDefault);

/* inputs.c */
int nxLoadInputs(db_handle * db);
void createInputButton(void);

/* settings.c */
int nxLoadConfig(void);

/* ipc.c */
void startIPC(void);
void handleIPC(GR_EVENT_FDINPUT * e);
int ipcSpawnApp(char *app, char *str);
int ipcActive(void);
int ipcGetAppName(int processid, char *name, int size);

/* input.c */
void inputResetWorkspace(void);
void hideInputs(void);
int isInputVisible(void);

#endif

--- NEW FILE: clients.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */

/* Portions copyright (C) 2000 Alex Holden <alex at linuxhacker.org> */

#include <pixil_config.h>

#include <stdio.h>
#include <stdlib.h>

#define MWINCLUDECOLORS
#include <nano-X.h>

#include <wm/nxlib.h>
#include "nxdraw.h"

#include "nanowm.h"
#include "apps.h"
#include "categories.h"

#include "themes.h"

/* Where to place the first window on the screen */
#define FIRST_WINDOW_LOCATION 2

/* The distance to leave between windows when deciding where to place */
#define WINDOW_STEP 20

static GR_COORD lastx = FIRST_WINDOW_LOCATION;
static GR_COORD lasty = FIRST_WINDOW_LOCATION;

/* JHC 08/08/01 - Instead of using the previously provided */
/* workspace, we are going to go ahead and use our own variables */
/* so we can increase and shrink it at random */

static int workspaceWidth = 0;
static int workspaceHeight = 0;

void
setWorkspace(int width, int height)
{
    workspaceWidth = width;
    workspaceHeight = height;

    /* Now resize any windows that may be affected */
    resize_windows(workspaceWidth, workspaceHeight);
}

void
getWorkspace(int *width, int *height)
{
    if (width)
	*width = workspaceWidth;
    if (height)
	*height = workspaceHeight;
}

static void client_wndproc(win * window, GR_EVENT * ep);

/*
 * A new client window has been mapped, so we need to reparent and decorate it.
 * Returns -1 on failure or 0 on success.
 */
int
client_updatemap_new(GR_WINDOW_ID wid)
{
    APP *lapp = 0;

    GR_WINDOW_ID pid;
    GR_COORD x, y, width, height, xoffset, yoffset;
    GR_SIZE w, h;
    GR_WM_PROPS style;
    GR_WINDOW_INFO winfo;
    GR_WM_PROPERTIES props;
    static GR_SCREEN_INFO si;

    /* get screen/workspace information */
    if (!si.rows)
	GrGetScreenInfo(&si);

    /* get client window information */
    GrGetWindowInfo(wid, &winfo);
    style = winfo.props;

    /* if not redecorating or not child of root window, return */
    if (winfo.parent != GR_ROOT_WINDOW_ID || (style & GR_WM_PROPS_NODECORATE))
	return 0;

    /* deal with replacing borders with window decorations */
    if (winfo.bordersize) {
	/*
	 * For complex reasons, it's easier to unmap,
	 * remove the borders, and then map again,
	 * rather than try to recalculate the window
	 * position in the server w/o borders.  By
	 * the time we get this event, the window has
	 * already been painted with borders...
	 * This currently causes a screen flicker as
	 * the window is painted twice.  The workaround
	 * is to create the window without borders in
	 * the first place.
	 */
	GrUnmapWindow(wid);

	/* remove client borders, if any */
	props.flags = style | GR_WM_FLAGS_BORDERSIZE;
	props.bordersize = 0;
	GrSetWMProperties(wid, &props);

	/* remap the window without borders, call this routine again */
	GrMapWindow(wid);
	return 0;
    }

    /* if default decoration style asked for, set real draw bits */
    if ((style & GR_WM_PROPS_APPMASK) == GR_WM_PROPS_APPWINDOW) {
	GR_WM_PROPERTIES pr;

	style = (style & ~GR_WM_PROPS_APPMASK) | nxGetDefaultWindowStyle();

	/* A quick hack - if NOAUTORESIZE is enabled */
	/* then clear the NOMOVE flag */

	if (style & GR_WM_PROPS_NOAUTORESIZE)
	    style &= ~GR_WM_PROPS_NOMOVE;

	pr.flags = GR_WM_FLAGS_PROPS;
	pr.props = style;
	GrSetWMProperties(wid, &pr);
    }
#ifdef CONFIG_PIXILWM_THEMES
    if (get_activeTheme())
	themeContainerSize(get_activeTheme(),
			   style, winfo.width, winfo.height,
			   &xoffset, &yoffset, &width, &height);
    else
#endif

	/* determine container size and client child window offsets */
	nxCalcNCSize(style, winfo.width, winfo.height, &xoffset, &yoffset,
		     &width, &height);

    /* determine x,y window location and width,height size */
    if ((style & (GR_WM_PROPS_NOAUTORESIZE | GR_WM_PROPS_MAXIMIZE)) ==
	GR_WM_PROPS_MAXIMIZE) {

	/* force to maximized position */
	x = 0;
	y = 0;
	width = workspaceWidth;
	height = workspaceHeight;
    } else if (style & GR_WM_PROPS_NOAUTOMOVE) {
	x = winfo.x;
	y = winfo.y;
    } else {

	/* We could probably use a more intelligent algorithm here */
	x = lastx + WINDOW_STEP;
	if ((x + width) > si.ws_width)
	    x = FIRST_WINDOW_LOCATION;
	lastx = x;
	y = lasty + WINDOW_STEP;
	if ((y + height) > si.ws_height)
	    y = FIRST_WINDOW_LOCATION;
	lasty = y;
    }

    /* create container window */
    pid = GrNewWindow(GR_ROOT_WINDOW_ID, x, y, width, height,
		      0, LTGRAY, BLACK);

    add_window(pid, GR_ROOT_WINDOW_ID, wid, container_wndproc);

    /* don't erase background of container window */
    props.flags = GR_WM_FLAGS_PROPS;
    props.props = style | GR_WM_PROPS_NOBACKGROUND;
    GrSetWMProperties(pid, &props);

    debug("New client window %d container %d\n", wid, pid);

    GrSelectEvents(pid, GR_EVENT_MASK_CHLD_UPDATE | GR_EVENT_MASK_UPDATE
		   | GR_EVENT_MASK_BUTTON_UP | GR_EVENT_MASK_BUTTON_DOWN
		   | GR_EVENT_MASK_MOUSE_POSITION | GR_EVENT_MASK_EXPOSURE);

    /* reparent client to container window */
    /* must map before reparent (nano-X bug) */

    GrMapWindow(pid);
    GrReparentWindow(wid, pid, xoffset, yoffset);

    /* resize client window to container */

#ifdef CONFIG_PIXILWM_THEMES
    if (get_activeTheme())
	themeClientSize(get_activeTheme(), style, width, height, &w, &h);
    else
#endif
	nxCalcClientSize(style, width, height, NULL, NULL, &w, &h);

    if (w != winfo.width || h != winfo.height)
	GrResizeWindow(wid, w, h);

    /* Get the application record for the new app */

    if (winfo.processid) {
	lapp = find_app_pid(winfo.processid);

	if (!lapp) {
	    char name[32] = { 0 };
	    if (ipcActive()
		&& ipcGetAppName(winfo.processid, name, sizeof(name)) == 0)
		lapp = find_app_name(name);
	}
    }

    if (lapp) {
	lapp->m_container_wid = pid;
	if (lapp->m_flags & FL_INPUT)
	    inputResizeWorkspace(lapp);
	lapp->m_virtual_wid = category_getCurrentWin();

	/* Record this for future HOME actions */
	g_last_app = lapp;
    }
#ifdef NOTUSED
    if (LastLaunchedApp) {
	LastLaunchedApp->m_container_wid = pid;

	if (LastLaunchedApp->m_flags & FL_INPUT)
	    inputResizeWorkspace(LastLaunchedApp);

	LastLaunchedApp->m_virtual_wid = category_getCurrentWin();
	LastLaunchedApp = NULL;
    }
#endif

    /*GrMapWindow(pid); */
    GrSetFocus(wid);		/* force fixed focus */

    /* add client window */
    add_window(wid, pid, 0, client_wndproc);

    /* Push this container window to the very top */
    zorder_push(pid);

#ifdef VIRTUAL_WINDOWS
    /* Redraw the virtual window switcher to handle the missing window */
    /* virtswitch_redraw(); */
#endif

    return 0;
}

/*
 * We've just received an event notifying us that a client window has been
 * unmapped, so we need to destroy all of the decorations.
 */
static void
client_destroy(win * window)
{
    APP *app;
    win *pwin;
    GR_WINDOW_ID pid, zwid;

    debug("Client window %d has been destroyed\n", window->wid);

    if (!(pwin = find_window(window->pid))) {
	error("Couldn't find the parent of window %d.\n", window->wid);
	return;
    }

    pid = pwin->wid;

    /* The client just went away, see if we can clear */
    /* the outstanding values                         */

    app = find_app_container(pid);

    /* If the app exists, then clear the values */

    if (app) {
	app->m_container_wid = 0;
	app->m_process_id = 0;
    } else
	error("No application was associated with container %d.\n", pid);

    /* Remove this window from the zorder */
    zorder_remove(pid);

    /* Activate the next window in the list */
    if ((zwid = zorder_peek_top()))
	container_activate(zwid);

    /* Remove the entire window from the window list */
    remove_window_and_children(pwin);

    debug("Destroying container %d\n", pid);
    GrDestroyWindow(pid);
}

static void
client_update(win * window, GR_EVENT_UPDATE * ep)
{
    switch (ep->utype) {
    case GR_UPDATE_DESTROY:
	client_destroy(window);
	break;
    }
}

static void
client_wndproc(win * window, GR_EVENT * ep)
{
    switch (ep->type) {
    case GR_EVENT_TYPE_CHLD_UPDATE:
	client_update(window, &ep->update);
	break;
    }
}

--- NEW FILE: home.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#include <stdio.h>
#include "nano-X.h"
#include "apps.h"
#include "nanowm.h"
#include "categories.h"

#include "config.h"

#define HOMEICON "home.gif"

static GR_BOOL g_clear_window = 0;

static GR_IMAGE_ID imageid;

static void home_wndproc(win * window, GR_EVENT * ep);

void
home_create(void)
{
    GR_WINDOW_ID wid;
    GR_SCREEN_INFO si;

    GrGetScreenInfo(&si);
    wid = GrNewWindowEx(GR_WM_PROPS_NODECORATE, NULL, GR_ROOT_WINDOW_ID,
			si.ws_width - 62, si.ws_height + 4, 13, 14,
			wm_getColor(WM_TASKBAR));
    add_window(wid, GR_ROOT_WINDOW_ID, 0, home_wndproc);

    GrSelectEvents(wid, GR_EVENT_MASK_BUTTON_DOWN | GR_EVENT_MASK_EXPOSURE);
    GrMapWindow(wid);
}

static void
home_exposure(win * window, GR_EVENT_EXPOSURE * ep)
{
    GR_GC_ID gc = GrNewGC();

    if (!imageid)
	imageid = loadIconImage(HOMEICON, 0, 0);

    GrDrawImageToFit(ep->wid, gc, 0, 0, -1, -1, imageid);
    GrDestroyGC(gc);
}

static void
home_buttondown(win * window, GR_EVENT_BUTTON * ep)
{
    if (g_clear_window && g_last_app) {

	if (!g_last_app->m_container_wid)
	    return;
	container_activate(g_last_app->m_container_wid);

	g_clear_window = 0;

	/* Reset the workspace.  This is a major hack, but the best we can do */
	inputResetWorkspace();
	return;
    }

    /* Make sure we hide all the inputs */
    hideInputs();

#ifdef VIRTUAL_WINDOWS
    app_hide_windows(category_getCurrentWin());
#else
    app_hide_windows();
#endif

    g_clear_window = 1;
}

static void
home_wndproc(win * window, GR_EVENT * ep)
{
    switch (ep->type) {
    case GR_EVENT_TYPE_EXPOSURE:
	home_exposure(window, &ep->exposure);
	break;
    case GR_EVENT_TYPE_BUTTON_DOWN:
	home_buttondown(window, &ep->button);
	break;
    }
}

--- NEW FILE: pwroff.h ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#ifndef _PWROFF_H_
#define _PWROFF_H_

#include <nano-X.h>
#include <pixlib/pixlib.h>
#include <par/par.h>

#define DISABLED 0x00
#define AC_ON    0x01
#define BAT_ON   0x02

#define BL_OFF   0X00
#define BL_ON    0x01

extern void change_bl_state(int final_result);

void suspend_nxscrtop(int id);
void resume_nxscrtop(int id);

/* Power Backlight timer prototypes */
void startBlTimer(void);
void controlBl(int state);
void suspendPwr(void);
void stopPwrTimer(void);

#endif /* _PWROFF_H_ */

--- NEW FILE: scrib.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#include <stdio.h>
#include <unistd.h>
#include "nano-X.h"
#include "apps.h"
#include "nanowm.h"

#define APPICON		"nxscribble.gif"

static GR_IMAGE_ID imageid;
static int appvisible = 0;

static void scribble_wndproc(win * window, GR_EVENT * ep);

void
scribble_create(void)
{
    GR_WINDOW_ID wid;
    APP *p;
    GR_SCREEN_INFO si;

    GrGetScreenInfo(&si);
    wid = GrNewWindowEx(GR_WM_PROPS_NODECORATE, NULL, GR_ROOT_WINDOW_ID,
			si.ws_width - 20, si.ws_height + 2, 20, 20,
			COLOR_TASKBAR);
    add_window(wid, GR_ROOT_WINDOW_ID, 0, scribble_wndproc);

    p = find_app_flags(FL_SCRIBBLE);
    if (p)
	p->m_icon_wid = wid;

    GrSelectEvents(wid, GR_EVENT_MASK_BUTTON_DOWN | GR_EVENT_MASK_EXPOSURE);
    GrMapWindow(wid);
}

static void
scribble_exposure(win * window, GR_EVENT_EXPOSURE * ep)
{
    GR_GC_ID gc = GrNewGC();

    if (!imageid) {
	char path[256];

	sprintf(path, "%s/%s", get_desktop_config(DESKTOP_IMAGEDIR), APPICON);
	imageid = GrLoadImageFromFile(path, 0);
    }

    GrDrawImageToFit(ep->wid, gc, 0, 0, -1, -1, imageid);

    GrDestroyGC(gc);
}

static void
scribble_buttondown(win * window, GR_EVENT_BUTTON * ep)
{
    APP *p = find_app_flags(FL_SCRIBBLE);

    if (!p) {
	printf("Unable to find the scribble app!\n");
	return;
    }

    if (is_app_running(p)) {
	if (appvisible) {
	    hide_application(p);
	    appvisible = 0;
	} else {
	    show_application(p);
	    appvisible = 1;
	}
    } else {
	launch_application(p);
	appvisible = 1;
    }

#ifdef NOTUSED
    if (p->m_process_id && p->m_container_wid) {

	appvisible = !appvisible;

	if (appvisible) {
	    GrMapWindow(p->m_container_wid);
	    GrRaiseWindow(p->m_container_wid);
	} else {
	    GrUnmapWindow(p->m_container_wid);
	}
    } else if (!(p->m_process_id = fork())) {
	printf("execing %s\n", p->m_exec);
	execlp(p->m_exec, p->m_exec, 0);
	exit(0);
    } else {
	g_last_window = p->m_icon_wid;
	LastLaunchedApp = p;
	appvisible = 1;
    }
#endif

}

static void
scribble_wndproc(win * window, GR_EVENT * ep)
{
    switch (ep->type) {
    case GR_EVENT_TYPE_EXPOSURE:
	scribble_exposure(window, &ep->exposure);
	break;
    case GR_EVENT_TYPE_BUTTON_DOWN:
	scribble_buttondown(window, &ep->button);
	break;
    }
}

--- NEW FILE: categories.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */

#include <pixil_config.h>

#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#define MWINCLUDECOLORS

#include <nano-X.h>
#include <par/par.h>

#include "apps.h"
#include "nanowm.h"
#include "categories.h"
#include "config.h"
#include "sys_menu.h"

/* A linked list of categories */
static category_t *categoryList = 0;

/* A pointer to the current list of categories */
static category_t *currentCategory = 0;

static GR_WINDOW_ID cbWindow = 0;
static GR_WINDOW_ID cbPixmap = 0;

int
category_getCount()
{
    int count = 0;

    category_t *ptr = categoryList;
    while (ptr) {
	count++;
	ptr = ptr->next;
    }

    return (count);
}

inline category_t *
category_getCurrent(void)
{
    return (currentCategory);
}

/* Each virtual window is defined by a index */

category_t *
category_getByIndex(int index)
{
    category_t *head = categoryList;

    while (head) {
	if (head->index == index)
	    return (head);
	head = head->next;
    }

    return (0);
}

inline int
category_getCurrentWin(void)
{
    if (currentCategory)
	return (currentCategory->index);
    return (0);
}

category_t *
category_getNext(category_t * cur)
{
    if (!cur)
	return (0);

    if (!cur->next)
	return (categoryList);
    else
	return (cur->next);
}

category_t *
category_getPrev(category_t * cur)
{

    category_t *head = 0;

    if (!cur)
	return (0);

    if (cur->prev)
	return (cur->prev);

    /* We need to find the tail.  A somewhat expensive operation */
    /* But easier than storing the tail */

    head = cur;

    while (head) {
	if (!head->next)
	    return (head);
	head = head->next;
    }

    return (0);
}

/* This just simply sets the current category to the specified index */

int
category_setCurrent(int index)
{

    category_t *head = categoryList;

    while (head) {
	if (head->index == index) {
	    currentCategory = head;
	    return (0);
	}
	head = head->next;
    }

    return (-1);
}

/* What is this used for? */

/*
   Given a name, return the index associated with that catagory
*/

#ifdef NOTUSED
int
get_catagory_index(char *name)
{
    PNXLIST p = catagory_list.head;
    char *dupname,		/* For strdup() of name */
     *dupcat;			/* For strdup() of cat->name */

    for (; p; p = p->next) {
	CATAGORY *cat = nxItemAddr(p, CATAGORY, next);

	if ((dupname = strdup(name)) != NULL &&
	    (dupcat = strdup(cat->name)) != NULL) {
	    /* Make all characters lower case */
	    string_tolower(strlen(dupname), dupname);
	    string_tolower(strlen(dupcat), dupcat);
	    if (!strcmp(dupname, dupcat))
		return (cat->index);

	    free(dupname);
	    free(dupcat);
	} /* end of if */
	else {
	    if (!strcmp(name, cat->name))
		return (cat->index);
	}			/* end of else */
    }

    return (-1);
}
#endif

/* switch_catagory() 
   
   This switches the current catagory to the one specified by index
   Unlike set_current_catagory, this function switches the icon lists,
   hides windows, and redraws the root window 
*/


int
switchCategory(int index)
{
    category_t *new = category_getByIndex(index);
    category_t *old = category_getCurrent();

    if (!new)
	return (-1);
    if (new == old)
	return (0);

    /* First, hide all of the running apps */
    if (old)
	hide_icon_list();

    category_setCurrent(new->index);

    /* Redraw the root window */
    /* This will automatically redraw the new icons */

    redraw_root_window();
    return (0);
}

/* This finds an application in the database, and loads it into memory */
/* Storing the resulting app pointer into the category                 */

static int
loadApplication(db_handle * db, category_t * category, char *app)
{

    /* The database structure */
    app_info_t ainfo;

    if (par_getAppTitle(db, app, ainfo.title, sizeof(ainfo.title)) < 0)
	return (-1);
    if (par_getAppPath(db, app, ainfo.path, sizeof(ainfo.path)) < 0)
	return (-1);

    /* These are not required, but they are nice to have */

    par_getAppIcon(db, app, ainfo.icon, sizeof(ainfo.icon));
    par_getAppWorkDir(db, app, ainfo.workdir, sizeof(ainfo.workdir));
    par_getAppArgs(db, app, ainfo.args, sizeof(ainfo.args));

    /* No flags, this is a normal application */
    ainfo.flags = 0;

    /* Now, add the application */

    if (!apps_add_application(app, &ainfo, &category->apps[category->count])) {
	category->count++;
	return (0);
    } else {
	category->apps[category->count] = 0;
	return (-1);
    }
}

/* Load a category from the database */

static int
loadCategory(db_handle * db, char *category, int index)
{

    char *app;
    char *applist;

    int appcount;

    category_t *ptr = 0;

    /* First, allocate a new category structure */

    if (!categoryList) {
	ptr = categoryList = (category_t *) calloc(sizeof(category_t), 1);
    } else {
	category_t *n = categoryList;
	while (n->next)
	    n = n->next;
	ptr = n->next = (category_t *) calloc(sizeof(category_t), 1);
	ptr->prev = n;
    }

    par_getScreentopCategory(db, category, &ptr->title, &applist);

    if (!applist)
	return (0);

    ptr->index = index;

    /* First, get a count of the number of applications in the list */
    app = applist;
    appcount = par_getStringListCount(applist, ' ');

    /* Allocate enough room for the applications */
    ptr->apps = (APP **) malloc(appcount * sizeof(APP *));

    while (app) {
	char *head = par_parseStringList(&app, ' ');
	if (!head)
	    break;
	loadApplication(db, ptr, head);
    }

    /* Clean up after ourselves */
    free(applist);
    return (0);
}

/* Given a database handle, load all of the categories into memory */

int
nxLoadCategories(db_handle * db)
{

    int count, i;
    itemlist_t *categories;

    count = par_getScreentopCatList(db, &categories);

    if (count <= 0)
	return (-1);

    for (i = 0; i < count; i++) {
	char cat[25];
	int size = sizeof(cat);

	bzero(cat, sizeof(cat));

	par_getListItem(categories, i, cat, &size);
	loadCategory(db, cat, i);
    }

    par_freeItemList(categories);
    return (0);
}

void
nxFreeCategories(void)
{

    category_t *head = categoryList;

    while (head) {
	category_t *ptr = head->next;

	/* Free the title */
	if (head->title)
	    free(head->title);

	/* The apps will be freed elsewhere */
	/* Free the app list */
	if (head->apps)
	    free(head->apps);

	free(head);
	head = ptr;
    }

    categoryList = 0;
    currentCategory = 0;
}

/* This is where we draw the category browser */

void
draw_categoryBrowser(GR_REGION_ID r)
{

    GR_WINDOW_INFO winfo;
    GR_GC_ID gc;

    /* Draw as much as we need from the pixmap */

    GrGetWindowInfo(cbWindow, &winfo);

    gc = GrNewGC();

    /* Set the clip region */
    GrSetGCRegion(gc, r);

    GrCopyArea(GR_ROOT_WINDOW_ID, gc,
	       winfo.x, winfo.y, winfo.width, winfo.height,
	       cbPixmap, 0, 0, MWROP_SRCCOPY);

    /* Now, draw the appropriate category name centered within the box */

    if (currentCategory) {
	int x, y;
	int width, height, baseline;
	GR_FONT_ID font = GrCreateFont(GR_FONT_GUI_VAR, 0, NULL);

	GrSetGCForeground(gc, WHITE);
	GrSetGCUseBackground(gc, GR_FALSE);

	GrSetGCFont(gc, font);

	GrGetGCTextSize(gc, currentCategory->title, -1,
			GR_TFASCII | GR_TFTOP, &width, &height, &baseline);

	x = (winfo.width - width) / 2;
	y = (winfo.height - height) / 2;

	GrText(GR_ROOT_WINDOW_ID, gc,
	       winfo.x + x, winfo.y + y, currentCategory->title,
	       -1, GR_TFASCII | GR_TFTOP);

	GrDestroyFont(font);
    }

    GrDestroyGC(gc);
}

static void
cbProc(win * window, GR_EVENT * ep)
{
    GR_WINDOW_INFO winfo;

    category_t *curcat = category_getCurrent();
    category_t *newcat = 0;

    switch (ep->type) {
    case GR_EVENT_TYPE_BUTTON_DOWN:
	GrGetWindowInfo(ep->button.wid, &winfo);

	/* Changed this so if the pointer is on the right half of the window it
	   ** will fetch the next catagory, and if on the left half of the window it
	   ** will fetch the previous catagory --- j webb (01/19/01)
	 */

	if (ep->button.x <= (winfo.width / 2))
	    newcat = category_getPrev(curcat);
	else if (ep->button.x > (winfo.width / 2))
	    newcat = category_getNext(curcat);

	switchCategory(newcat->index);
	break;
    }
}

void
create_categoryBrowser(void)
{

    char file[256];

    GR_SCREEN_INFO si;
    GR_IMAGE_ID bImage = 0;
    GR_GC_ID gc;

    int bWidth = 0, bHeight = 0;

    sprintf(file, "%s/catbrowser.gif", wm_getDir(DESKTOP_IMAGEDIR));

    if (access(file, F_OK) == 0) {
	bImage = GrLoadImageFromFile(file, 0);

	if (bImage) {
	    GR_IMAGE_INFO info;
	    GrGetImageInfo(bImage, &info);
	    bWidth = info.width;
	    bHeight = info.height;
	}
    }

    if (!bImage) {
	bWidth = 80;
	bHeight = 20;
    }

    GrGetScreenInfo(&si);

    /* create an input window */
    cbWindow = GrNewInputWindow(GR_ROOT_WINDOW_ID,
				(si.ws_width - bWidth) / 2, 0,
				bWidth, bHeight);

    cbPixmap = GrNewPixmap(bWidth, bHeight, 0);
    gc = GrNewGC();

    if (bImage) {
	GrSetGCForeground(gc, wm_getColor(WM_BGCOLOR));
	GrFillRect(cbPixmap, gc, 0, 0, bWidth, bHeight);

	/* Now draw the category browser image or (ack!) drawing */
	GrDrawImageToFit(cbPixmap, gc, 0, 0, -1, -1, bImage);
	GrFreeImage(bImage);
    } else {
	GR_POINT points[3];

	GrSetGCForeground(gc, LTGRAY);
	GrFillRect(cbPixmap, gc, 0, 0, bWidth, bHeight);

	GrSetGCForeground(gc, BLACK);
	GrRect(cbPixmap, gc, 0, 0, bWidth, bHeight);

	points[0].x = 1;
	points[0].y = bHeight / 2;
	points[1].x = 10;
	points[1].y = 1;
	points[2].x = 10;
	points[2].y = bHeight - 2;

	GrFillPoly(cbPixmap, gc, 3, points);

	points[0].x = bWidth - 2;
	points[0].y = bHeight / 2;
	points[1].x = bWidth - 10;
	points[1].y = 1;
	points[2].x = bWidth - 10;
	points[2].y = bHeight - 2;

	GrFillPoly(cbPixmap, gc, 3, points);
    }

    GrDestroyGC(gc);

    /* Finally, set up the input window and leave */
    GrSelectEvents(cbWindow,
		   GR_EVENT_MASK_BUTTON_DOWN | GR_EVENT_MASK_BUTTON_UP);
    add_window(cbWindow, GR_ROOT_WINDOW_ID, 0, cbProc);

    GrMapWindow(cbWindow);
}

#ifdef CONFIG_PIXILWM_MENUS

wm_menu_t *
create_categoryMenu(int index, char *name)
{

    int i;
    wm_menu_t *ptr;

    category_t *cat = category_getByIndex(index);

    if (!cat)
	return (0);

    ptr = create_system_menu(cat->count + 1);

    if (!ptr)
	return (0);

    for (i = 0; i < cat->count; i++) {
	APP *p = cat->apps[i];
	if (!p)
	    continue;

	ADD_SYS_MENU_APP(&ptr[i], p->m_icontitle, p->m_exec, p->m_icon_iid);
    }

    ADD_SYS_MENU_END(&ptr[i]);
    strcpy(name, cat->title);

    return (ptr);
}

#endif

--- NEW FILE: wlist.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


/* Portions Copyright (C) 2000 Alex Holden <alex at linuxhacker.org> */

#include <stdio.h>
#include <stdlib.h>
#include "nano-X.h"

#include "nanowm.h"

static win *windows = NULL;
static win *zHead = NULL;

/*
 * Find the windowlist entry for the specified window ID and return a pointer
 * to it, or NULL if it isn't in the list.
 */

win *
find_window(GR_WINDOW_ID wid)
{
    win *w = windows;

    debug("Looking for window %d...\n", wid);

    while (w) {
	if (w->wid == wid) {
	    debug("found it!\n");
	    return w;
	}
	w = w->next;
    }

    debug("Nope, %d is not in the list\n", wid);
    return NULL;
}

/*
 * Add a new entry to the front of the windowlist.
 * Returns -1 on failure or 0 on success.
 */
win *
add_window(GR_WINDOW_ID wid, GR_WINDOW_ID pid, GR_WINDOW_ID clid,
	   wndproc proc)
{
    win *w;

    debug("Adding window %d\n", wid);

    if (!(w = calloc(sizeof(win), 1)))
	return NULL;

    w->pos.xorig = -1;
    w->pos.yorig = -1;
    w->wid = wid;
    w->pid = pid;
    w->clientid = clid;
    w->proc = proc;
    w->mousedn = GR_FALSE;

    w->zorder.next = 0;
    w->zorder.prev = 0;

    w->next = windows;
    windows = w;

    return w;
}

/* This will resize any maximized windows to the specified width and height */
/* I didn't know where else to put this function */

void
resize_windows(int width, int height)
{

    win *w = windows;

    for (w = windows; w; w = w->next) {

	GR_WM_PROPERTIES props;

	/* Only resize the containers */
	if (!w->wid || !w->clientid)
	    continue;

	GrGetWMProperties(w->wid, &props);

	if ((props.props & GR_WM_PROPS_NOAUTORESIZE) ==
	    GR_WM_PROPS_NOAUTORESIZE)
	    continue;

	if ((props.props & GR_WM_PROPS_MAXIMIZE) == GR_WM_PROPS_MAXIMIZE)
	    GrResizeWindow(w->wid, width, height);

    }
}


/*
 * Remove an entry from the windowlist.
 * We must search through the list for it so that we can find the previous
 * entry in the list and fix the next pointer. The alternative is to add a
 * prev pointer to the structure which would increase the memory usage.
 * Returns -1 on failure or 0 on success.
 */
int
remove_window(win * window)
{
    win *w = windows;
    win *prev = NULL;

    while (w) {
	if (w == window) {
	    if (!prev)
		windows = w->next;
	    else
		prev->next = w->next;

	    /* Set the zorder */

	    if (w->zorder.prev)
		w->zorder.prev->zorder.next = w->zorder.next;

	    if (w->zorder.next)
		w->zorder.next->zorder.prev = w->zorder.prev;

	    if (w == zHead)
		zHead = w->zorder.next;

	    free(w);
	    return 0;
	}
	prev = w;
	w = w->next;
    }

    return -1;
}

/*
 * Remove an entry and all it's children from the windowlist.
 * Returns -1 on failure or 0 on success.
 */
int
remove_window_and_children(win * window)
{
    win *t, *w = windows;
    win *prev = NULL;
    GR_WINDOW_ID pid = window->wid;

    debug("Removing window %d and children\n", window->wid);

    while (w) {
	if ((w->pid == pid) || (w == window)) {

	    if (prev)
		prev->next = w->next;
	    else
		windows = w->next;
	    t = w->next;

	    /* Set the zorder */

	    if (w->zorder.prev)
		w->zorder.prev->zorder.next = w->zorder.next;

	    if (w->zorder.next)
		w->zorder.next->zorder.prev = w->zorder.prev;

	    if (w == zHead)
		zHead = w->zorder.next;

	    free(w);
	    w = t;
	    continue;
	}
	prev = w;
	w = w->next;
    }

    return -1;
}

#ifdef ZDEBUG

static void
zorder_print()
{

    win *win = zHead;

    fprintf(stderr, "---- Z-Order List ----\n");

    if (!zHead) {
	fprintf(stderr, "<none>\n");
    } else {
	while (win) {
	    fprintf(stderr, "%p <-- %d --> %p\n",
		    win->zorder.prev, win->wid, win->zorder.next);

	    win = win->zorder.next;
	}
    }

    fprintf(stderr, "-------------\n");
}

#endif

/* Push this window to the top of the zorder */

int
zorder_push(GR_WINDOW_ID id)
{

    win *w = find_window(id);
    if (!w)
	return (-1);

    if (!zHead) {
	zHead = w;
	w->zorder.prev = w->zorder.next = 0;
    }

    else {
	w->zorder.next = zHead;
	w->zorder.prev = 0;

	zHead->zorder.prev = w;
	zHead = w;
    }

#ifdef ZDEBUG
    zorder_print();
#endif

    return (0);
}

/* Get the top window from the zorder */

GR_WINDOW_ID
zorder_peek_top(void)
{

    if (zHead)
	return (zHead->wid);
    else
	return (0);

}

/* Remove an abitrary window from the linked list */

void
zorder_remove(GR_WINDOW_ID id)
{

    win *w = find_window(id);

    if (!w)
	return;

    if (w->zorder.prev)
	w->zorder.prev->zorder.next = w->zorder.next;

    if (w->zorder.next)
	w->zorder.next->zorder.prev = w->zorder.prev;

    if (w == zHead)
	zHead = w->zorder.next;

    w->zorder.prev = w->zorder.next = 0;

#ifdef ZDEBUG
    zorder_print();
#endif

}

void
zorder_raise(GR_WINDOW_ID id)
{

    win *w = find_window(id);
    if (!w)
	return;

    if (w == zHead)
	return;

    /* First, pull it out of the list */

    if (w->zorder.prev)
	w->zorder.prev->zorder.next = w->zorder.next;

    if (w->zorder.next)
	w->zorder.next->zorder.prev = w->zorder.prev;

    /* Now, push it on top */
    w->zorder.next = w->zorder.prev = 0;

    w->zorder.next = zHead;
    zHead->zorder.prev = w;

    zHead = w;

#ifdef ZDEBUG
    zorder_print();
#endif

}

#ifdef NOTUSED

/* Pop the top window from the zorder */
/* And return the new top window      */

GR_WINDOW_ID
zorder_pop(void)
{

    GR_WINDOW_ID ret = 0;
    win *ptr = zHead;

    if (!ptr)
	return (0);

    ret = ptr->wid;
    next = ptr->zorder.next;

    if (next)
	next->zorder.prev = 0;

    zHead = ptr->zorder.next;

    ptr->zorder.next = 0;
    ptr->zorder.prev = 0;


    return (ret);
}

#endif

--- NEW FILE: inputs.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <par/par.h>

#define MWINCLUDECOLORS

#include <nano-X.h>
#include "apps.h"
#include "nanowm.h"
#include "config.h"

typedef struct input_struct
{
    char *title;
    int visible;
    APP *app;
    struct input_struct *next;
}
input_t;

static input_t *inputList = 0;
static input_t *defaultInput = 0;

static GR_WINDOW_ID defaultWid;
static GR_WINDOW_ID menuWid;
static GR_WINDOW_ID menubarWid;

static int menubarVisible = 0;

/* This may be a very stupid idea */

static int defaultWidth = 0;
static int defaultHeight = 0;

static void inputProc(win * window, GR_EVENT * ep);

#ifdef NOTUSED
static input_t *
input_findByWindow(GR_WINDOW_ID wid)
{

    input_t *input = inputList;
    while (input) {
	if (input->wid == wid)
	    return (input);
	input = input->next;
    }

    return (0);
}
#endif

static int
loadInput(db_handle * db, char *input)
{

    par_input_t istruct;
    app_info_t ainfo;

    input_t *ptr;

    bzero(&istruct, sizeof(par_input_t));
    bzero(&ainfo, sizeof(app_info_t));

    par_getScreentopInput(db, input, &istruct);

    /* These are absolutely required */

    if (par_getAppTitle(db, istruct.app, ainfo.title, sizeof(ainfo.title)) <
	0) {
	error("Couldn't find input '%s'.\n", istruct.app);
	return (-1);
    }

    if (par_getAppPath(db, istruct.app, ainfo.path, sizeof(ainfo.path)) < 0) {
	error("Couldn't get a path for input '%s'.\n", istruct.app);
	return (-1);
    }

    /* These are not required, but they are nice to have */

    par_getAppIcon(db, istruct.app, ainfo.icon, sizeof(ainfo.icon));
    par_getAppWorkDir(db, istruct.app, ainfo.workdir, sizeof(ainfo.workdir));
    par_getAppArgs(db, istruct.app, ainfo.args, sizeof(ainfo.args));

    ainfo.flags = FL_INPUT;

    if (!inputList) {
	ptr = inputList = (input_t *) calloc(sizeof(input_t), 1);
    } else {
	input_t *head = inputList;
	while (head->next)
	    head = head->next;
	ptr = head->next = (input_t *) calloc(sizeof(input_t), 1);
    }

    if (!ptr)
	return (-1);
    ptr->next = 0;

    /* Add the application to the list */
    if (apps_add_application(istruct.app, &ainfo, &ptr->app) != 0)
	return (-1);
    if (!ptr->app)
	return (-1);


    /* Set up the icon */
    if (strlen(ainfo.icon)) {
	ptr->app->m_icon_iid = loadIconImage(ainfo.icon, ainfo.path, 1);
    } else {
	ptr->app->m_icon_iid = loadIconImage(istruct.icon, ainfo.path, 1);
    }

    if (!defaultInput)
	defaultInput = ptr;
    return (0);
}

int
nxLoadInputs(db_handle * db)
{

    int i;

    int count;
    itemlist_t *inputs;

    count = par_getScreentopInputList(db, &inputs);
    if (count <= 0)
	return (-1);

    for (i = 0; i < count; i++) {
	char input[25];
	int size = sizeof(input);

	bzero(input, sizeof(input));
	par_getListItem(inputs, i, input, &size);

	if (loadInput(db, input) == -1) {
	}
    }

    par_freeItemList(inputs);
    return (0);
}

void
nxFreeInputs(void)
{

    input_t *head = inputList;

    while (head) {
	input_t *next = head->next;

	if (head->title)
	    free(head->title);

	free(head);
	head = next;
    }
}

static void
drawDefaultButton(GR_WINDOW_ID wid)
{

    int xpos, ypos;

    GR_WINDOW_INFO info;
    GR_IMAGE_INFO iinfo;

    GR_GC_ID gc = GrNewGC();

    GrGetWindowInfo(wid, &info);
    GrSetGCForeground(gc, wm_getColor(WM_TASKBAR));

    GrFillRect(wid, gc, 0, 0, info.width, info.height);

    /* Draw the default image in here */
    if (!defaultInput)
	return;
    if (!defaultInput->app || !defaultInput->app->m_icon_iid)
	return;

    GrGetImageInfo(defaultInput->app->m_icon_iid, &iinfo);

    xpos = (info.width - iinfo.width) / 2;
    ypos = (info.height - iinfo.height) / 2;

    GrDrawImageToFit(wid, gc, xpos, ypos, -1, -1,
		     defaultInput->app->m_icon_iid);

    /* Draw a black border around it for looks */

    GrSetGCForeground(gc, wm_getColor(WM_BGCOLOR));
    GrRect(wid, gc, 0, 0, info.width, info.height - 2);

    GrDestroyGC(gc);
}

static void
drawMenuButton(win * window, GR_EVENT_EXPOSURE * e)
{

    GR_POINT points[3];

    GR_WINDOW_INFO info;
    GR_GC_ID gc = GrNewGC();

    GrGetWindowInfo(e->wid, &info);

    /* This will eventually be an image, but for now, just put a caret.. :) */

    GrSetGCBackground(gc, wm_getColor(WM_TASKBAR));
    GrSetGCForeground(gc, wm_getColor(WM_BGCOLOR));

    points[0].x = 3;
    points[0].y = 11;

    points[1].x = 7;
    points[1].y = 6;

    points[2].x = 12;
    points[2].y = 11;

    GrFillPoly(e->wid, gc, 3, points);

    GrRect(e->wid, gc, 0, 0, info.width, info.height - 2);

    GrDestroyGC(gc);
}

static void
drawMenu(win * window, GR_EVENT_EXPOSURE * e)
{

    input_t *head = inputList;
    int x = 0, y = 0;

    GR_WINDOW_INFO info;
    GR_IMAGE_INFO iinfo;

    GR_GC_ID gc = GrNewGC();

    GrGetWindowInfo(e->wid, &info);
    GrSetGCForeground(gc, wm_getColor(WM_BGCOLOR));

    while (head) {
	int ypos = 0;
	if (!head->app || !head->app->m_icon_iid) {
	    head = head->next;
	    continue;
	}

	GrGetImageInfo(head->app->m_icon_iid, &iinfo);

	x = (info.width - iinfo.width) / 2;
	ypos = y + (20 - iinfo.height) / 2;

	GrDrawImageToFit(e->wid, gc, x, ypos, -1, -1, head->app->m_icon_iid);
	/* GrRect(e->wid, gc, 0, y, info.width, 20); */

	y += 19;
	head = head->next;
    }


    /* GrRect(e->wid, gc, 0, 0, info.width, info.height); */

    GrDestroyGC(gc);
}

void
inputResizeWorkspace(APP * app)
{
    GR_WINDOW_INFO info;
    if (!app)
	return;

    /* Figure out the size of the window */
    GrGetWindowInfo(app->m_container_wid, &info);

    setWorkspace(defaultWidth, defaultHeight - info.height + 1);
}

void
inputResetWorkspace(void)
{
    int cw, ch;
    getWorkspace(&cw, &ch);

    if ((defaultWidth == cw) && (defaultHeight == ch))
	return;

    setWorkspace(defaultWidth, defaultHeight);
}

int
isInputVisible(void)
{
    input_t *input = inputList;

    while (input) {
	if (input->visible)
	    return (1);
	input = input->next;
    }

    return (0);
}

static void
fireInput(input_t * input)
{

    APP *p = 0;
    if (!input)
	return;

    p = input->app;

    if (!p)
	return;

    if (is_app_running(p)) {
	if (input->visible) {
	    hide_application(p);
	    input->visible = 0;
	} else {
	    show_application(p);
	    input->visible = 1;
	}
    } else {
	launch_application(p);
	input->visible = 1;
    }

    if (input->visible)
	inputResizeWorkspace(input->app);
    else
	setWorkspace(defaultWidth, defaultHeight);
}

static void
launchDefault(win * window, GR_EVENT_BUTTON * e)
{
    fireInput(defaultInput);
}

static void
launchInput(win * window, GR_EVENT_BUTTON * e)
{

    input_t *head = inputList;

    int index = e->y / 20;
    int i;

    for (i = 0; i < (index); i++) {
	if (!head)
	    return;
	head = head->next;
    }

    if (head != defaultInput && defaultInput) {

	if (defaultInput->visible)
	    hide_application(defaultInput->app);

	defaultInput->visible = 0;
    }

    /* This is the new default! */
    fireInput(head);

    defaultInput = head;
    drawDefaultButton(defaultWid);
}

/* Called when an input is killed */

void
killInput(APP * app)
{

    int state = 0;
    input_t *head = inputList;

    /* Try to figure out which input this was for */
    while (head) {
	if (head->app == app) {
	    if (head->visible)
		head->visible = 0;
	} else if (head->visible)
	    state = 1;

	head = head->next;
    }

    if (!state)
	setWorkspace(defaultWidth, defaultHeight);
}

/* Hide all the inputs */

void
hideInputs(void)
{

    input_t *head = inputList;

    while (head) {
	if (!head->app) {
	    head = head->next;
	    continue;
	}

	if (head->visible)
	    hide_application(head->app);

	head->visible = 0;

	head = head->next;
    }
}

/* New fangled way to set things up.  We have two buttons - One with */
/* the most current input and one that will bring up the menu        */

void
createInputButton(void)
{

    int count = 0;

    input_t *head = inputList;

    GR_SCREEN_INFO si;
    int x, y;

    GrGetScreenInfo(&si);

    getWorkspace(&defaultWidth, &defaultHeight);

    x = si.ws_width - 46;
    y = si.ws_height + 2;

    while (head) {
	count++;
	head = head->next;
    }

    if (!count) {
	return;
    }

    /* Make the two buttons */

    defaultWid = GrNewWindowEx(GR_WM_PROPS_NODECORATE, NULL,
			       GR_ROOT_WINDOW_ID,
			       x, y, 32, 20, wm_getColor(WM_TASKBAR));

    menuWid = GrNewWindowEx(GR_WM_PROPS_NODECORATE, NULL,
			    GR_ROOT_WINDOW_ID,
			    x + 33, y, 13, 20, wm_getColor(WM_TASKBAR));


    menubarWid = GrNewWindowEx(GR_WM_PROPS_NODECORATE, NULL,
			       GR_ROOT_WINDOW_ID,
			       x + 20, si.ws_height - (20 * count),
			       25, (20 * count) - 1, wm_getColor(WM_TASKBAR));

    GrSelectEvents(menuWid,
		   GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_BUTTON_DOWN);
    GrSelectEvents(defaultWid,
		   GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_BUTTON_DOWN);
    GrSelectEvents(menubarWid,
		   GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_BUTTON_DOWN);

    add_window(defaultWid, GR_ROOT_WINDOW_ID, 0, inputProc);
    add_window(menuWid, GR_ROOT_WINDOW_ID, 0, inputProc);

    add_window(menubarWid, GR_ROOT_WINDOW_ID, 0, inputProc);

    GrMapWindow(defaultWid);
    GrMapWindow(menuWid);
}

#ifdef NOTUSED

/* Currently, the inputs are added as they are found */
/* from right to left (of course this may change)  */

int
createInputs(int start)
{

    int x, y;
    GR_SCREEN_INFO si;

    input_t *head = inputList;

    GrGetScreenInfo(&si);

    x = start;
    y = si.ws_height + 2;

    while (head) {
	if (!head->app || !head->app->m_icon_iid) {
	    head = head->next;
	    continue;
	}

	head->wid = GrNewWindowEx(GR_WM_PROPS_NODECORATE, NULL,
				  GR_ROOT_WINDOW_ID,
				  x, y, 30, 15, wm_getColor(WM_TASKBAR));

	add_window(head->wid, GR_ROOT_WINDOW_ID, 0, input_wndproc);

	GrSelectEvents(head->wid,
		       GR_EVENT_MASK_BUTTON_DOWN | GR_EVENT_MASK_EXPOSURE);

	GrMapWindow(head->wid);

	x -= 20;
	head = head->next;
    }

    return (x);
}

static void
input_exposure(win * window, GR_EVENT_EXPOSURE * ep)
{

    GR_GC_ID gc;
    input_t *input = input_findByWindow(ep->wid);

    if (!input)
	return;
    if (!input->app || !input->app->m_icon_iid)
	return;

    gc = GrNewGC();
    GrDrawImageToFit(ep->wid, gc, 0, 0, -1, -1, input->app->m_icon_iid);
    GrDestroyGC(gc);
}

static void
input_buttondown(win * window, GR_EVENT_BUTTON * ep)
{

    APP *p = 0;
    input_t *input = input_findByWindow(ep->wid);
    if (!input)
	return;

    p = input->app;

    if (!p) {
	return;
    }

    if (is_app_running(p)) {
	if (input->visible) {
	    hide_application(p);
	    input->visible = 0;
	} else {
	    show_application(p);
	    input->visible = 1;
	}
    } else {
	launch_application(p);
	input->visible = 1;
    }
}

#endif

static void
inputProc(win * window, GR_EVENT * ep)
{
    switch (ep->type) {

    case GR_EVENT_TYPE_EXPOSURE:
	if (ep->exposure.wid == defaultWid)
	    drawDefaultButton(ep->exposure.wid);

	if (ep->exposure.wid == menuWid)
	    drawMenuButton(window, &ep->exposure);

	if (ep->exposure.wid == menubarWid)
	    drawMenu(window, &ep->exposure);

	break;

    case GR_EVENT_TYPE_BUTTON_DOWN:

	if (ep->button.wid == menuWid) {

	    if (menubarVisible) {
		GrUnmapWindow(menubarWid);
		menubarVisible = 0;
	    } else {
		GrMapWindow(menubarWid);
		GrRaiseWindow(menubarWid);
		menubarVisible = 1;
	    }
	}

	if (ep->button.wid == defaultWid) {

	    launchDefault(window, &ep->button);
	    if (menubarVisible) {
		GrUnmapWindow(menubarWid);
		menubarVisible = 0;
	    }
	}

	if (ep->button.wid == menubarWid) {
	    launchInput(window, &ep->button);
	    menubarVisible = 0;
	    GrUnmapWindow(menubarWid);
	}

	break;
    }
}

--- NEW FILE: main.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disc1losure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */

#include <pixil_config.h>

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>

#include <fcntl.h>
#include <errno.h>
#include <unistd.h>

#include <nano-X.h>

#include "nanowm.h"
#include "apps.h"
#include "categories.h"
#include "applets.h"

#ifdef CONFIG_PIXILWM_MENUS
#include "sys_menu.h"
#endif

#ifdef CONFIG_PIXILWM_PM
#include "powerman.h"
#endif

#include "screensaver.h"

static scrtop_fire_timer(GR_TIMER_ID id);
static void mainloop(void);

GR_TIMER_ID pwr_timer_id = 0;
char *path = "/tmp/nxscrtop.pid";

/*
 * This the universal, get-outta here function that closes everything down and bails.  
 */

void
close_nxscrtop(int id)
{
    win *window;

    warning("The screentop has been closed.  Freeing resources....\n");

    /* Step 1.  Kill off any outstanding applications that are still running */
    kill_running_processes();

    /* Step 2.  Remove all the windows */
    window = find_window(GR_ROOT_WINDOW_ID);
    remove_window_and_children(window);

    /* Step 3.  Free all the outstanding memory */
    apps_free_memory();
    root_free_memory();
    nxFreeCategories();

    unlink(path);

    exit(0);
}

int
main(int argc, char *argv[])
{

    pid_t pid = 0;
    int pathfd_;
    char buf[512];
    int ret;

    extern void application_handler(int id);

    /* These are death signals, that indicate that we should close up shop */

    signal(SIGINT, close_nxscrtop);
    signal(SIGTERM, close_nxscrtop);
    signal(SIGHUP, close_nxscrtop);

    memset(buf, 0, sizeof(buf));
    pid = getpid();

    if (!access(path, F_OK)) {
	printf("Warnning - found a stale lockfile.  Deleting it...\n");
	unlink(path);
    }

    pathfd_ = open(path, O_RDWR | O_TRUNC | O_CREAT);
    if (pathfd_ == -1) {
	perror("open(): /tmp/nxscrtop.pid");
	exit(errno);
    }
    sprintf(buf, "%d", pid);
    ret = write(pathfd_, buf, strlen(buf));
    if (-1 == ret) {
	perror("write(): pid");
	exit(errno);
    }
    close(pathfd_);

    /* This is the sigchild handler, useful for when our children die */

    signal(SIGCHLD, application_handler);

    if (GrOpen() < 0) {
	error("Couldn't connect to Nano-X server!\n");
	unlink(path);
	exit(-1);
    }

    GrReqShmCmds(65536L);

    startIPC();
    wm_init_applets();

    nxLoadConfig();

    /* pass errors through main loop, don't exit */
    GrSetErrorHandler(NULL);

    root_create();

    /* Start the screen saver / power management */
    screensaver_init();

    mainloop();

    unlink(path);
    return 0;
}

static void
mainloop(void)
{
    unsigned long timeout = wm_applet_get_timeout();

    GR_EVENT event;
    win *window;

    while (1) {
        unsigned long elapsed = 0;
        struct timeval b, a;
    
        gettimeofday(&b, 0);
        GrGetNextEventTimeout(&event, timeout);
        gettimeofday(&a, 0);

	switch (event.type) {

	    /* all these events share their wid member location */
	case GR_EVENT_TYPE_BUTTON_DOWN:
	case GR_EVENT_TYPE_BUTTON_UP:
	case GR_EVENT_TYPE_KEY_DOWN:
	case GR_EVENT_TYPE_KEY_UP:
	case GR_EVENT_TYPE_EXPOSURE:
	case GR_EVENT_TYPE_UPDATE:
	case GR_EVENT_TYPE_MOUSE_POSITION:
	case GR_EVENT_TYPE_MOUSE_ENTER:
	case GR_EVENT_TYPE_MOUSE_EXIT:
	case GR_EVENT_TYPE_FOCUS_IN:
	case GR_EVENT_TYPE_FOCUS_OUT:
#ifdef MICROWIN_PRE8
	case GR_EVENT_TYPE_BUTTON_LONG_CLICK:
#endif

	    window = find_window(((GR_EVENT_GENERAL *) & event)->wid);

#ifdef CONFIG_PIXILWM_MENUS
	    if (system_menu_active() == GR_TRUE) {
		if (handle_system_menu(&event) == 1)
		    break;
	    }
#endif

	    if (window && window->proc)
		window->proc(window, &event);

	    wm_applet_handle_event(&event);
	    break;

	case GR_EVENT_TYPE_FDINPUT:

	    /* We got a FD input, thats probably a colosseum thing */

	    handleIPC(&event.fdinput);
	    break;

	case GR_EVENT_TYPE_CHLD_UPDATE:
	    window = find_window(((GR_EVENT_UPDATE *) & event)->subwid);

	    /* 
	     * Add unknown newly mapped window to window manager
	     * internal data structures.  This will also create
	     * a new parent container window.
	     */
	    if (!window && event.update.utype == GR_UPDATE_MAP) {
		client_updatemap_new(((GR_EVENT_UPDATE *) & event)->subwid);
	    }

	    if (window && window->proc)
		window->proc(window, &event);

	    break;

	case GR_EVENT_TYPE_TIMER:
	  if (event.timer.tid) scrtop_fire_timer(event.timer.tid);
	  break;

	case GR_EVENT_TYPE_TIMEOUT:
	  /* Handled elsewhere */
	  break;
	  
	case GR_EVENT_TYPE_SCREENSAVER:

	    /* Backlight */
	    if (event.screensaver.activate == GR_TRUE)
	      screensaver_enable();
	    else
	      screensaver_disable();
	    
	    break;
	    
	case GR_EVENT_TYPE_ERROR:
	    error("GrError (%s)", event.error.name);
	    error(nxErrorStrings[event.error.code], event.error.id);
	    break;

	default:
	    warning("Got unexpected event %d\n", event.type);
	    break;
	}


	/* Get the number of elapsed milliseconds for the timer */	
	elapsed = 0;
	
	if (b.tv_usec > a.tv_usec) {
	  if ((a.tv_sec - b.tv_sec) > 0) 
	    elapsed = ((a.tv_sec - b.tv_sec) - 1) * 1000;
	  
	  elapsed += ((1000000 - b.tv_usec) + a.tv_usec) / 1000;
	}
	else {
	  elapsed = (a.tv_sec - b.tv_sec) * 1000;
	  elapsed += (a.tv_usec - b.tv_usec) / 1000;
	}
	
	timeout = wm_applet_handle_timer(elapsed);	
    }
}

struct timer_list {
  GR_TIMER_ID id;
  scrtop_timer_cb callback;
  struct timer_list *next;
};

static struct timer_list *scrtop_timer_list = 0;

void scrtop_register_timer(GR_TIMER_ID id, scrtop_timer_cb callback) {
  struct timer_list *a = 0, *p = 0, *i = 0;

  for(a = scrtop_timer_list; a; p = a, a = a->next) 
    if (a->id == id) return;

  i = (struct timer_list *) calloc(1, sizeof(struct timer_list));
  i->id = id;
  i->callback = callback;

  if (!p) scrtop_timer_list = i;
  else p->next = i;

  return;
}

void scrtop_unregister_timer(GR_TIMER_ID id) {
  struct timer_list *a = 0, *p = 0;

  for(a = scrtop_timer_list; a; p = a, a = a->next) 
    if (a->id == id) {
      if (p) p->next = a->next;
      else scrtop_timer_list = a->next;
      free(a);

      return;
    }
}

static scrtop_fire_timer(GR_TIMER_ID id) {
  struct timer_list *a = 0, *p = 0;
  
  for(a = scrtop_timer_list; a; p = a, a = a->next)
    if (a->id == id) {
      scrtop_timer_cb ptr = a->callback;
      
      if (p) p->next = a->next;
      else scrtop_timer_list = a->next;
      free(a);
      
      if (ptr) ptr();
      return;
    }
}
  
static unsigned char cur_log_level = LOG_WARNING;

void
scrtop_log_message(int level, char *fmt, ...)
{

    va_list ap;

    if (level > cur_log_level)
	return;

    switch (level) {

    case LOG_DEBUG:
	printf("debug: ");
	break;

    case LOG_WARNING:
	printf("Warning: ");
	break;

    case LOG_ERROR:
	printf("Error: ");
	break;
    }

    printf("nxscrtop -- ");

    va_start(ap, fmt);
    vprintf(fmt, ap);
    va_end(ap);
}

--- NEW FILE: ipc.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */

#include <pixil_config.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef CONFIG_COLOSSEUM
#include <ipc/colosseum.h>
#endif

#include <nano-X.h>

#include "nanowm.h"
#include "apps.h"
#include <wm/scrtoplib.h>

#ifdef CONFIG_PIXILWM_PM
#include "powerman.h"
#endif

//extern int check_par_tz_flag;

static int cl_fd = 0;

int
ipcActive(void)
{
    return ((cl_fd > 0) ? 1 : 0);
}

void
startIPC(void)
{
#ifdef CONFIG_COLOSSEUM
    int cl_flags;

    cl_fd = ClRegister("nxscrtop", &cl_flags);

    if (cl_fd <= 0)
	warning("Unable to locate the Colosseum server.\n");
    else
	GrRegisterInput(cl_fd);
#endif
}

int
ipcGetAppName(int processid, char *name, int size)
{
#ifndef CONFIG_COLOSSEUM
  return -1;
#else
    cl_app_info info;

    info.flags = CL_APP_INFO_PID;
    info.processid = processid;

    if (clGetAppInfo(&info) == -1) {
	error("Unable to get information for process '%d'.\n", processid);
	return (-1);
    }

    strncpy(name, info.name, size);
    return (0);
#endif
}

static void
handleAction(scrtop_action * action)
{

    APP *app = find_app_name(action->app);
    win *window;

    if (!app) {
	error("Couldn't locate application '%s'.\n", action->app);
	return;
    }

    if (!app->m_container_wid)
	return;
    window = find_window(app->m_container_wid);

    if (!window) {
	error("Unable to find the window for container %d.\n",
	      app->m_container_wid);
	return;
    }

    switch (action->type) {

    case ACTION_SHOW:
	container_activate(app->m_container_wid);
	break;

    case ACTION_HIDE:
	container_hide(app->m_container_wid);
	break;

    case ACTION_CLOSE:
	window = find_window(app->m_container_wid);
	if (!window || !window->clientid)
	    break;

	GrCloseWindow(window->clientid);
	break;

    default:
	warning("Unknown IPC command %d\n", action->type);
	break;
    }
}

void
handleNAAction(scrtop_action * action)
{
    /*
       ** This function handles the "Non-Application" related actions, i.e. things
       ** that pertain to the screen top only
     */

    switch (action->type) {
#ifdef CONFIG_PIXILWM_PM
    case NA_ACTION_BLON:
      pm_backlight(1);
      break;

    case NA_ACTION_BLOFF:
      pm_backlight(0);
      break;
#endif
    default:
      warning("Unknown NA_ACTION IPC command %d\n", action->type);
      break;
    }				/* end of switch */
}				/* end of handleNAAction() */

void
handleTextIpc(scrtop_message * msg)
{

    char *t_msg;
    char *c = 0;

    t_msg = (char *) malloc(CL_MAX_MSG_LEN);

    if (t_msg == 0)
	return;

    memcpy(t_msg, msg, sizeof(scrtop_message));

    c = strchr(t_msg, '^');

    if (c != 0)
	*c++ = 0;

#ifdef CONFIG_PIXILWM_PM
    if (!(strcmp(t_msg, "sc_power")))
      pm_reload();

    if (!(strcmp(t_msg, "sc_backlite")))
      pm_reload();
#endif

    if (!(strcmp(t_msg, "sc_clock"))) {
	/*
	   ** The user has changed the system time/date (possibly changed the 
	   ** timezone, etc, get values from par and set time accordingly
	 */
      //check_par_tz_flag = 1;
    }
    /* end of if */
    free(t_msg);
}

void
handleIPC(GR_EVENT_FDINPUT * e)
{
#ifdef CONFIG_COLOSSEUM

    scrtop_message msg;
    int size = sizeof(msg);
    int ack = 0;
    unsigned short src = 0;

    /* We have a message waiting for us, lets grab it and do some stuff */

    ack = ClGetMessage(&msg, &size, &src);

    if (ack < 0)
	return;

    if (ack == CL_CLIENT_BROADCAST) {
	handleTextIpc(&msg);
	return;
    }

    switch (GET_CATEGORY(msg.type)) {

    case CATEGORY_ACTION:
	handleAction(&msg.action);
	break;

    case CATEGORY_NA_ACTION:
	handleNAAction(&msg.action);
	break;

    default:
	warning("Unknown IPC message category %d.\n", GET_CATEGORY(msg.type));
	break;
    }
#endif
}

/* Send off an application for the IPC to spawn */

int
ipcSpawnApp(char *app, char *str)
{
#ifdef CONFIG_COLOSSEUM
    if (!cl_fd)
	return (-1);

    return (ClSpawnApp(app, str));
#endif
}

--- NEW FILE: container.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


/* Portions Copyright (C) 2000 Alex Holden <alex at linuxhacker.org> */

#include <pixil_config.h>

#include <stdio.h>
#include <stdlib.h>
#define MWINCLUDECOLORS
#include "nano-X.h"
#include "nxdraw.h"

#include "nanowm.h"
#include "apps.h"
#include "themes.h"

//#define OUTLINE_MOVE 1
//#define OUTLINE_RESIZE 1

static void
container_redraw(win * window)
{
    GR_WINDOW_INFO info;
    GR_WM_PROPERTIES props;
    GR_BOOL active;

    debug("container_exposure window %d\n", window->wid);

    GrGetWindowInfo(window->wid, &info);
    GrGetWMProperties(window->clientid, &props);

    /* Check for invalid window */
    if (props.flags == 0)
	return;

    active = (window->clientid == GrGetFocus());

#ifdef CONFIG_PIXILWM_THEMES
    if (get_activeTheme())
	themeDrawContainer(window->wid, info.width, info.height, props.title,
			   active, props.props, get_activeTheme());
    else
#endif
	nxPaintNCArea(window->wid, info.width, info.height, props.title,
		      active, props.props);

    /* Ack, this was malloced, and it is our responsibility to free it */
    if (props.title)
	free(props.title);
}

static void
container_exposure(win * window, GR_EVENT_EXPOSURE * event)
{
    debug("container_exposure window %d\n", window->wid);
    container_redraw(window);
}

static GR_BOOL
PtInRect(GR_RECT * prc, GR_SIZE x, GR_SIZE y)
{
    return (x >= prc->x && x < (prc->x + prc->width) &&
	    y >= prc->y && y < (prc->y + prc->height));
}

/* NOTE:  This is the non-themed closebox handler */

static int
check_closebox(GR_WINDOW_INFO * info, int ex, int ey)
{

    int cxborder = 0, cyborder = 0;

    GR_RECT r;

    if (info->props & GR_WM_PROPS_BORDER) {
	cxborder = 1;
	cyborder = 1;
    }
    if (info->props & GR_WM_PROPS_APPFRAME) {
	cxborder = CXBORDER;
	cyborder = CYBORDER;
    }

    r.x = info->width - CXCLOSEBOX - cxborder - 2;
    r.y = cyborder + 2;
    r.width = CXCLOSEBOX;
    r.height = CYCLOSEBOX;

    /* Check mousedn in close box */
    return (PtInRect(&r, ex, ey));
}

static int
check_titlebar(GR_WINDOW_INFO * info, int ex, int ey)
{
    GR_RECT r;
    int cxborder = 0, cyborder = 0;

    if (info->props & GR_WM_PROPS_BORDER) {
	cxborder = 1;
	cyborder = 1;
    }
    if (info->props & GR_WM_PROPS_APPFRAME) {
	cxborder = CXBORDER;
	cyborder = CYBORDER;
    }

    r.x = cxborder;
    r.y = cyborder;
    r.width = info->width - cxborder * 2;
    r.height = CYCAPTION;

    /* Check for mousedn in caption box */
    return (PtInRect(&r, ex, ey));
}

static void
container_buttondown(win * window, GR_EVENT_BUTTON * event)
{
    GR_RECT r;

    int ret;
    GR_WINDOW_INFO info;

    struct pos_size *pos = &window->pos;

    debug("container_buttondown window %d\n", window->wid);

    if (window->mousedn)
	return;

    GrGetWindowInfo(window->wid, &info);

    /* Check for close box press */
    if ((info.props & (GR_WM_PROPS_CAPTION | GR_WM_PROPS_CLOSEBOX)) ==
	(GR_WM_PROPS_CAPTION | GR_WM_PROPS_CLOSEBOX)) {

#ifdef CONFIG_PIXILWM_THEMES
	if (get_activeTheme())
	    ret = widgetCheckBounds(get_activeTheme(),
				    info.props, TITLEBAR_WIDGET_CLOSEBUTTON,
				    event->x, event->y,
				    info.width, info.height);
	else
#endif
	    ret = check_closebox(&info, event->x, event->y);

	if (ret) {
	    GrCloseWindow(window->clientid);
	    return;
	}
    }

    /* Set focus on button down */
    GrSetFocus(window->clientid);

    /* check for corner resize */
    r.x = info.width - 5;
    r.y = info.height - 5;
    r.width = 5;
    r.height = 5;

    if ((info.props & GR_WM_PROPS_APPFRAME)
	&& PtInRect(&r, event->x, event->y)) {

	window->sizing = GR_TRUE;
	pos = &window->pos;

	// save off the width/height offset from the window manager
	GrGetWindowInfo(window->clientid, &info);
	pos->xoff = -info.width;
	pos->yoff = -info.height;

	GrGetWindowInfo(window->wid, &info);
	pos->xoff += info.width;
	pos->yoff += info.height;


#ifdef OUTLINE_RESIZE
	// let mouse move know that we havn't drawn the rect yet
	pos->width = -1;
	pos->height = -1;
#endif
	window->mousedn = GR_TRUE;
	return;
    }

    /* if not in caption, return (FIXME, not calc'd exactly) */
    if (!(info.props & GR_WM_PROPS_CAPTION))
	return;

    /* Check the bounds of the whole shooting titlebar */

#ifdef CONFIG_PIXILWM_THEMES
    if (get_activeTheme())
	ret = themeCheckBounds(get_activeTheme(),
			       info.props, COMPONENT_TITLEBAR,
			       event->x, event->y, info.width, info.height);
#endif
    else
	ret = check_titlebar(&info, event->x, event->y);

    if (!ret)
	return;

    /* Raise window if mouse down and allowed */
    if (!(info.props & GR_WM_PROPS_NORAISE)) {
	GrRaiseWindow(window->wid);
	zorder_raise(window->wid);
    }

    /* Don't allow window move if NOMOVE property set */
    if (info.props & GR_WM_PROPS_NOMOVE)
	return;

    window->x = event->x;
    window->y = event->y;

    pos->xoff = event->x;
    pos->yoff = event->y;

#ifdef OUTLINE_MOVE
    pos->xorig = -1;
    pos->yorig = -1;
    pos->width = info.width;
    pos->height = info.height;
#endif
    window->mousedn = GR_TRUE;
}

static void
container_buttonup(win * window, GR_EVENT_BUTTON * event)
{
#if OUTLINE_RESIZE | OUTLINE_MOVE
    GR_GC_ID gc;
#endif
    struct pos_size *pos = &window->pos;

    debug("container_buttonup window %d\n", window->wid);

    if (window->mousedn && !window->sizing &&
	pos->xorig != -1 && pos->yorig != -1) {
#ifdef OUTLINE_MOVE
	gc = GrNewGC();
	GrSetGCMode(gc, GR_MODE_XOR | GR_MODE_EXCLUDECHILDREN);
	GrRect(GR_ROOT_WINDOW_ID, gc, pos->xorig, pos->yorig,
	       pos->width, pos->height);
	GrMoveWindow(window->wid, pos->xorig, pos->yorig);

#endif
    } else if (window->sizing && pos->width != -1 && pos->height != -1) {
	GR_WINDOW_INFO info;

	GrGetWindowInfo(window->wid, &info);

#ifdef OUTLINE_RESIZE
	gc = GrNewGC();
	GrSetGCMode(gc, GR_MODE_XOR | GR_MODE_EXCLUDECHILDREN);

	GrRect(GR_ROOT_WINDOW_ID, gc, info.x, info.y, pos->width,
	       pos->height);
	GrDestroyGC(gc);
#endif
	GrResizeWindow(window->wid, event->rootx - info.x,
		       event->rooty - info.y);
    }

    window->sizing = GR_FALSE;
    window->mousedn = GR_FALSE;
}

static void
container_mousemoved(win * window, GR_EVENT_MOUSE * event)
{
    GR_WINDOW_INFO info;
    struct pos_size *pos;
#if OUTLINE_RESIZE | OUTLINE_MOVE
    GR_GC_ID gc;
#endif
    debug("container_mousemoved window %d\n", window->wid);

    if (!window->mousedn)
	return;

    pos = (struct pos_size *) &window->pos;

    if (window->sizing) {

	GrGetWindowInfo(window->wid, &info);

#ifdef OUTLINE_RESIZE
	gc = GrNewGC();
	GrSetGCMode(gc, GR_MODE_XOR | GR_MODE_EXCLUDECHILDREN);

	// erase old rectangle if necessary
	if (pos->width != -1 && pos->height != -1)
	    GrRect(GR_ROOT_WINDOW_ID, gc, info.x, info.y, pos->width,
		   pos->height);

	// draw new one
	GrRect(GR_ROOT_WINDOW_ID, gc, info.x, info.y,
	       event->rootx - info.x, event->rooty - info.y);

	GrDestroyGC(gc);
	// save this new rectangle's width, height
	// I know, this shouldn't be stored in x/y, but...
	pos->width = event->rootx - info.x;
	pos->height = event->rooty - info.y;
#else
	GrResizeWindow(window->wid, event->rootx - info.x,
		       event->rooty - info.y);
#endif
	return;
    }
#ifdef OUTLINE_MOVE
    gc = GrNewGC();
    GrSetGCMode(gc, GR_MODE_XOR | GR_MODE_EXCLUDECHILDREN);

    if (pos->xorig != -1 && pos->yorig != -1)
	GrRect(GR_ROOT_WINDOW_ID, gc, pos->xorig, pos->yorig,
	       pos->width, pos->height);

    GrRect(GR_ROOT_WINDOW_ID, gc, event->rootx - pos->xoff,
	   event->rooty - pos->yoff, pos->width, pos->height);

    pos->xorig = event->rootx - pos->xoff;
    pos->yorig = event->rooty - pos->yoff;

    GrDestroyGC(gc);
#else
    GrMoveWindow(window->wid, event->rootx - pos->xoff,
		 event->rooty - pos->yoff);
#endif

#ifdef VIRTUAL_WINDOWS
    /* Redraw the window box so it knows whats up */
    /* virtswitch_redraw(); */
#endif
}

static void
container_child_update(win * window, GR_EVENT_UPDATE * ep)
{
    switch (ep->utype) {
    case GR_UPDATE_ACTIVATE:
	container_redraw(window);
	break;
    }
}



static void
container_resize(win * window, GR_EVENT_UPDATE * ep)
{
    int w, h;

    GR_WINDOW_INFO info;
    GrGetWindowInfo(window->wid, &info);

    // calculate new size for the client window


#ifdef CONFIG_PIXILWM_THEMES
    if (get_activeTheme())
	themeClientSize(get_activeTheme(), info.props, ep->width, ep->height,
			&w, &h);
    else
#endif
	nxCalcClientSize(info.props, ep->width, ep->height, NULL, NULL, &w,
			 &h);

    // resize client window
    GrResizeWindow(window->clientid, w, h);
}

static void
container_update(win * window, GR_EVENT_UPDATE * ep)
{
    switch (ep->utype) {
    case GR_UPDATE_SIZE:
	container_resize(window, ep);
	break;
    }
}

void
container_wndproc(win * window, GR_EVENT * ep)
{
    switch (ep->type) {
    case GR_EVENT_TYPE_EXPOSURE:
	container_exposure(window, &ep->exposure);
	break;
    case GR_EVENT_TYPE_BUTTON_DOWN:
	container_buttondown(window, &ep->button);
	break;
    case GR_EVENT_TYPE_BUTTON_UP:
	container_buttonup(window, &ep->button);
	break;
    case GR_EVENT_TYPE_UPDATE:
	container_update(window, &ep->update);
	break;
    case GR_EVENT_TYPE_MOUSE_POSITION:
	container_mousemoved(window, &ep->mouse);
	break;
    case GR_EVENT_TYPE_CHLD_UPDATE:
	container_child_update(window, &ep->update);
	break;
    }
}

/* GLOBAL CONTAINER MANAGMENT */
/* This is an effort to consolidate the various container functions */
/* (map, unmap, etc...) */

/* This activates the given container */
/* By mapping it, raising it and giving it focus */

void
container_activate(GR_WINDOW_ID wid)
{

    GR_WINDOW_INFO info;
    win *window;

    if (wid == 0) {
	debug("Passed 0 to container_set_focus()\n");
	return;
    }

    if (!(window = find_window(wid))) {
	error("Couldn't find window '%d' in the window list\n", wid);
	return;
    }

    GrGetWindowInfo(wid, &info);

    if (!info.mapped) {
	zorder_push(wid);
	GrMapWindow(wid);
    } else {
	zorder_raise(wid);
	GrRaiseWindow(wid);
    }

    if (info.props & GR_WM_PROPS_NOFOCUS)
	return;
    GrSetFocus(window->clientid);
}

/* This hides the specified container */

void
container_hide(GR_WINDOW_ID wid)
{

    if (!wid)
	return;

    /* Pull it out of the visible zorder */
    zorder_remove(wid);

    /* And unmap it */
    GrUnmapWindow(wid);
}

--- NEW FILE: themes.h ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#ifndef _THEMES_H_
#define _THEMES_H_


/* A macro to calculate the correct widget number */

#define COMPONENT_WIDGET(comp, index)  ((comp & 0xFF) << 8 | (index & 0xFF))
#define GET_COMPONENT(item)            ((item >> 8) & 0xFF)
#define GET_WIDGET(item)               (item & 0xFF)

/* The available components */

#define COMPONENT_TITLEBAR    0
#define COMPONENT_LEFT        1
#define COMPONENT_RIGHT       2
#define COMPONENT_BOTTOM      3
#define COMPONENT_TOP         4

#define THEME_COMPONENT_COUNT 5

/* Titlebar widgets */

#define TITLEBAR_WIDGET_CAPTION     COMPONENT_WIDGET(COMPONENT_TITLEBAR, 0)
#define TITLEBAR_WIDGET_CLOSEBUTTON COMPONENT_WIDGET(COMPONENT_TITLEBAR, 1)
#define TITLEBAR_WIDGET_TITLEBAR    COMPONENT_WIDGET(COMPONENT_TITLEBAR, 2)

#define TITLEBAR_WIDGET_COUNT 3
#define BORDER_WIDGET_COUNT   1

#define STATE_ACTIVE     0
#define STATE_INACTIVE   1

typedef struct
{
    int flags;

    char *image;
    GR_COLOR fgcolor;
    GR_COLOR bgcolor;

    GR_WINDOW_ID imageid;

    int imageWidth;
    int imageHeight;
}
widget_state_t;

typedef struct
{

    struct
    {
	int x;
	int y;
	int w;
	int h;
    }
    hotspot;

    struct
    {
	int min;
	int max;
    }
    width;

    struct
    {
	int min;
	int max;
    }
    height;

    widget_state_t states[2];
}
widget_t;

typedef struct
{
    int type;
    int widgetCount;
    widget_t **widgets;
}
component_t;

typedef struct
{

    /* A component is some part of the screen that is made up of different images */
    component_t components[THEME_COMPONENT_COUNT];

    /* This defines how the client is offset from the container */

    struct
    {
	int left;
	int right;
	int top;
	int bottom;
    }
    client;

    GR_FONT_ID font;
}
theme_t;

theme_t *createTheme(const char *directory);

void set_activeTheme(theme_t * theme);
theme_t *get_activeTheme(void);

void themeDrawContainer(GR_DRAW_ID, int, int, GR_CHAR *, GR_BOOL, GR_WM_PROPS,
			theme_t *);
void themeContainerSize(theme_t *, GR_WM_PROPS, int, int, int *, int *, int *,
			int *);
void themeClientSize(theme_t *, GR_WM_PROPS style, int, int, int *clientw,
		     int *);

int widgetCheckBounds(theme_t * theme, GR_WM_PROPS style, int index, int x,
		      int y, int w, int h);
int themeCheckBounds(theme_t * theme, GR_WM_PROPS style, int index, int x,
		     int y, int w, int h);


#endif

--- NEW FILE: utils.h ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#ifndef _UTILS_H_
#define _UTILS_H_

/* dbl linked list data structure*/

typedef struct _nxlist
{				/* LIST must be first decl in struct */
    struct _nxlist *next;	/* next item */
    struct _nxlist *prev;	/* previous item */
}
NXLIST, *PNXLIST;

/* dbl linked list head data structure*/

typedef struct _nxlisthead
{
    struct _nxlist *head;	/* first item */
    struct _nxlist *tail;	/* last item */
}
NXLISTHEAD, *PNXLISTHEAD;

void *nxItemAlloc(unsigned int size);
void nxListAdd(PNXLISTHEAD pHead, PNXLIST pItem);
void nxListInsert(PNXLISTHEAD pHead, PNXLIST pItem);
void nxListInsertAfter(PNXLISTHEAD pHead, PNXLIST pItem, PNXLIST pPrev);


void nxListRemove(PNXLISTHEAD pHead, PNXLIST pItem);

#define nxItemNew(type)	((type *)nxItemAlloc(sizeof(type)))
#define nxItemFree(ptr)	free((void *)ptr)

/* field offset*/
#define NXITEM_OFFSET(type, field)    ((long)&(((type *)0)->field))

/* return base item address from list ptr*/
#define nxItemAddr(p,type,list)	((type *)((long)p - NXITEM_OFFSET(type,list)))

/* calculate container size from client style/size*/
void nxCalcNCSize(GR_WM_PROPS style, GR_SIZE wClient,
		  GR_SIZE hClient, GR_COORD * xCliOffset,
		  GR_COORD * yCliOffset, GR_SIZE * wContainer,
		  GR_SIZE * hContainer);

/* calculate client size from container style/size*/
void nxCalcClientSize(GR_WM_PROPS style, GR_SIZE wContainer,
		      GR_SIZE hContainer, GR_COORD * xCliOffset,
		      GR_COORD * yCliOffset, GR_SIZE * wClient,
		      GR_SIZE * hClient);

/* utility routines*/
void strzcpy(char *dst, char *src, int count);

#endif

--- NEW FILE: apps.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */

#include <pixil_config.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>

#include <unistd.h>

#include "apps.h"
#include "nanowm.h"
#include "categories.h"
#include "config.h"

#ifdef CONFIG_PIXILWM_MENUS
#include "sys_menu.h"
#endif

/* Globals */
APP *g_last_app;		/* The last known application that was started */

/* A local list of applications */
static NXLISTHEAD apphead;

static int
searchPath(char *in, char *out, int size, int flags)
{

    char *path;
    char *p, *temp;
    int csize;

    if (!in || !out)
	return (-1);

    if (in[0] == '/') {

	/* Check to see if the file exists */
	if (access(in, flags) != 0)
	    return (-1);
	bzero(out, size);
	csize = (strlen(in) > size ? size : strlen(in));

	strncpy(out, in, csize);
	return (csize);
    }

    if (!(temp = getenv("PATH")))
	return (-1);

    p = path = alloca(strlen(temp) + 1);
    strcpy(path, temp);

    while (p) {
	char *n = strchr(p, ':');
	char *f;

	if (n)
	    *n = 0;
	f = alloca(strlen(p) + strlen(in) + 2);
	if (!f)
	    continue;

	sprintf(f, "%s/%s", p, in);

	if (access(f, flags) == 0) {
	    bzero(out, size);
	    csize = (strlen(in) > size ? size : strlen(f));

	    strncpy(out, f, csize);
	    return (csize);
	}

	if (n)
	    p = n + 1;
	else
	    p = 0;
    }

    return (-1);
}

/* This function takes the passed information and turns it into */
/* something useful We maintain the legacy APP list to avoid    */
/* borking the old launch system.                               */

int
apps_add_application(char *name, app_info_t * app_info, APP ** application)
{

    char filename[512];
    APP *app;
    char *p;

    if (!strlen(app_info->path))
	return (1);

    /* Hmmm... is this really an error, or an annoying warning? */

    if (searchPath(app_info->path, filename, sizeof(filename), X_OK) == -1) {
      //error("Application '%s' does not exist\n", app_info->path);
      return (-1);
    }

    app = nxItemNew(APP);

    if (!app) {
	error("Unable to allocate enough memory\n");
	return (-1);
    }

    strzcpy(app->m_name, name, sizeof(app->m_name));

    /* set application flags */
    app->m_flags = app_info->flags;

    /* Check for virtual window flags */
    app->m_virtual_flags = 0;

    /* set executable path */
    strzcpy(app->m_exec, filename, sizeof(app->m_exec));
    strzcpy(app->m_workdir, app_info->workdir, sizeof(app->m_workdir));

    /* If no working directory was specified, try to develop one from the path */

    if (strlen(app->m_workdir) == 0) {
	char *p = strrchr(filename, '/');
	if (p) {
	    strzcpy(app->m_workdir, filename, (int) (p - filename));
	} else
	    app->m_workdir[0] = 0;
    }

    /* We used to parse the arguments, but that we before we had */
    /* colosseum do most of the heavy lifting                    */

    /* We still keep the legacy code around for backup purposes  */
    /* but to avoid allocating unused memory, we will parse the  */
    /* argc, argv list as each app is executed (see exec.c)      */

    strzcpy(app->m_args, app_info->args, sizeof(app->m_args));

    if (app_info->flags & FL_INPUT) {
	/* Add this application to the main list */
	nxListAdd(&apphead, &app->link);

	/* Save the link for the calling function */
	if (application)
	    *application = app;
	return (0);
    }

    if (strlen(app_info->title))
	strzcpy(app->m_icontitle, app_info->title, sizeof(app->m_icontitle));
    else {
	/* use basename if no title override */
	p = strrchr(app_info->path, '/');
	strzcpy(app->m_icontitle, p ? p + 1 : app_info->path,
		sizeof(app->m_icontitle));
    }

    /* user passed icon, path.gif or default */
    /* This will soon be attacked with some fury */

    app->m_icon_iid = loadIconImage(app_info->icon, filename, 1);

    if (!app->m_icon_iid) {

	warning("Unable to find an icon for '%s'.  Skipping...\n", filename);

	free(app);
	return (-1);		/* Error */
    }

    app->m_process_id = 0;
    app->m_container_wid = 0;

    app->m_icon_wid = create_icon_window();

    /* Add this application to the main list */
    nxListAdd(&apphead, &app->link);

    /* Pass the newly created application back to the calling app */
    if (application)
	*application = app;

    return (0);
}

void
apps_buttondown(GR_WINDOW_ID id)
{
    APP *app;

    if (!(app = find_app_icon(id)))
	return;
    launch_application(app);
}

#ifdef NOTUSED

/* 
 * This hides all of the windows for the given virtual window 
 */


void
app_hide_windows(int virt)
{
    PNXLIST p;

    for (p = apphead.head; p; p = p->next) {
	APP *app = nxItemAddr(p, APP, link);

	if (app->m_container_wid && app->m_virtual_wid == virt)
	    if (!(app->m_virtual_flags & VW_STICKY))	/* Check for stickyness */
		container_hide(app->m_container_wid);
    }
}

/*
 * This will map all the active windows for a given virtual
 * window.  
 * FIXME:  We need a flag to indicate those apps that have been 
 * minimized or otherwise hidden 
 */

void
app_show_windows(int virt, int focus)
{
    PNXLIST p;

    for (p = apphead.head; p; p = p->next) {
	APP *app = nxItemAddr(p, APP, link);

	if (app->m_container_wid && app->m_virtual_wid == virt) {
	    if (!(app->m_virtual_flags & VW_STICKY))
		GrMapWindow(app->m_container_wid);

	    /* If the new window has a stored focus, set it back again */
#ifdef NOTUSED
	    if (focus) {
		win *window = find_window(app->m_container_wid);
		if (window)
		    if (window->clientid == focus)
			GrSetFocus(window->clientid);
	    }
#endif
	}
    }
}

#else /* VIRTUAL_WINDOWS */

void
app_hide_windows()
{
    PNXLIST p;

    for (p = apphead.head; p; p = p->next) {
	APP *app = nxItemAddr(p, APP, link);
	if (app->m_container_wid)
	    container_hide(app->m_container_wid);
    }
}

#endif /* VIRTUAL_WINDOWS */

APP *
find_app_pid(int pid)
{
    PNXLIST p = apphead.head;

    for (; p; p = p->next) {
	APP *app = nxItemAddr(p, APP, link);

	if (app->m_process_id == pid)
	    return app;
    }
    return NULL;
}

APP *
find_app_path(char *path)
{
    PNXLIST p = apphead.head;

    for (; p; p = p->next) {
	APP *app = nxItemAddr(p, APP, link);

	if (!strcmp(path, app->m_exec))
	    return app;
    }
    return NULL;
}

APP *
find_app_flags(int flags)
{
    PNXLIST p = apphead.head;

    for (; p; p = p->next) {
	APP *app = nxItemAddr(p, APP, link);

	if (app->m_flags & flags)
	    return app;
    }
    return NULL;
}

APP *
find_app_icon(GR_WINDOW_ID id)
{
    PNXLIST p = apphead.head;

    for (; p; p = p->next) {
	APP *app = nxItemAddr(p, APP, link);

	if (app->m_icon_wid == id) {
	    return app;
	}
    }
    return NULL;

}

APP *
find_app_container(GR_WINDOW_ID id)
{
    PNXLIST p = apphead.head;

    for (; p; p = p->next) {
	APP *app = nxItemAddr(p, APP, link);

	if (app->m_container_wid == id) {
	    return app;
	}
    }
    return NULL;

}

APP *
find_app_name(char *name)
{
    PNXLIST p = apphead.head;

    for (; p; p = p->next) {
	APP *app = nxItemAddr(p, APP, link);

	if (strcmp(app->m_name, name) == 0) {
	    return app;
	}
    }
    return NULL;

}


/* JHC 11/14 - Added this to allow apps that aren't registered in the normal */
/* manner to run.  */

APP *
apps_add_onetime(char *path)
{
    char *name;

    app_info_t ainfo;

    bzero(&ainfo, sizeof(ainfo));
    strcpy(ainfo.path, path);
    ainfo.flags = FL_NOICON | FL_ONETIME;

    name = strrchr(path, '/');
    if (!name)
	name = path;
    else
	name = name + 1;

    if (apps_add_application(name, &ainfo, 0) == -1)
	return (0);

    return (find_app_path(path));
}

void
apps_free_memory()
{
    /* Only called when we are going down.  */
    /* Free all the memory we have allocated */

    PNXLIST p = apphead.head;
    PNXLIST t;

    while (p) {
	APP *app = nxItemAddr(p, APP, link);
	t = p->next;

	nxListRemove(&apphead, &app->link);
	free(app);

	p = t;
    }
}

#ifdef CONFIG_PIXILWM_MENUS
int
create_apps_menu(wm_menu_t ** data)
{
    int i, index = 0;
    int count = category_getCount();
    wm_menu_t *ptr;

    count++;
    *data = create_system_menu(count);

    if (!*data)
	return (0);
    else
	ptr = *data;

    for (i = 0; i < count; i++) {
	char name[25];

	wm_menu_t *cmenu = create_categoryMenu(i, name);

	if (cmenu)
	    ADD_SYS_MENU_CMENU(&ptr[index++], name, cmenu);
    }

    ADD_SYS_MENU_END(&ptr[index++]);
    return (index);
}

#endif

--- NEW FILE: themetags.h ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


static xml_tag tagsState[] = {
    {"image", 0, 0, data_image, 0},
    {"fgcolor", 0, 0, data_fgcolor, 0},
    {"bgcolor", 0, 0, data_bgcolor, 0}
};

static xml_tag tagsStates[] = {
    {"active", tagsState, active_state_init, 0, 0},
    {"inactive", tagsState, inactive_state_init, 0, 0},
};

static xml_tag tagsComponent[] = {
    {"hotspot", 0, 0, data_hotspot, 0},
    {"width", 0, 0, data_width, 0},
    {"height", 0, 0, data_height, 0},
    {"states", tagsStates, 0, 0, 0}
};

static xml_tag tagsWidget[] = {
    {"widget", tagsComponent, widget_init, 0, 0}
};

static xml_tag tagsClient[] = {
    {"padding", 0, 0, data_padding, 0}
};

static xml_tag themeToplevel[] = {
    {"titlebar", tagsWidget, titlebar_init, 0, 0},
    {"border_left", tagsWidget, border_init, 0, 0},
    {"border_right", tagsWidget, border_init, 0, 0},
    {"border_bottom", tagsWidget, border_init, 0, 0},
    {"border_top", tagsWidget, border_init, 0, 0},
    {"client", tagsClient, 0, 0, 0},
};

--- NEW FILE: themesconfig.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <xml/xml.h>
#include <nano-X.h>

#include "nanowm.h"
#include "themes.h"

/* This is a list of widgets that are accepted by each component  */
/* this gives us the change to be a little more flexable with the */
/* script */

char *titlebarList[] = { "caption", "closebutton", "titlebar", "" };
char *borderList[] = { "border" };

char **widgetList[] = {
    titlebarList,
    borderList,
    borderList,
    borderList,
    borderList
};

/* XML callback functions */

static void *data_image(xml_token * tag, void *data, char *text, int size);
static void *data_fgcolor(xml_token * tag, void *data, char *text, int size);
static void *data_bgcolor(xml_token * tag, void *data, char *text, int size);
static void *data_hotspot(xml_token * tag, void *data, char *text, int size);
static void *data_width(xml_token * tag, void *data, char *text, int size);
static void *data_height(xml_token * tag, void *data, char *text, int size);
static void *data_padding(xml_token * tag, void *data, char *text, int size);

static void *active_state_init(xml_token * tag, void *in);
static void *inactive_state_init(xml_token * tag, void *in);
static void *widget_init(xml_token * tag, void *in);
static void *titlebar_init(xml_token * tag, void *in);
static void *border_init(xml_token * tag, void *in);

#include "themetags.h"

static void *
data_image(xml_token * tag, void *data, char *text, int size)
{
    widget_state_t *state = (widget_state_t *) data;

    state->image = (char *) calloc(size + 1, 1);
    strncpy(state->image, text, size);

    return ((void *) state);
}

static void *
data_fgcolor(xml_token * tag, void *data, char *text, int size)
{
    unsigned long val;

    widget_state_t *state = (widget_state_t *) data;

    xml_parseColor(text, &val, size);

    state->fgcolor = GR_RGB((val >> 16) & 0xFF,
			    (val >> 8) & 0xFF, (val & 0xFF));

    return ((void *) state);
}

static void *
data_bgcolor(xml_token * tag, void *data, char *text, int size)
{

    unsigned long val;
    widget_state_t *state = (widget_state_t *) data;

    xml_parseColor(text, &val, size);

    state->bgcolor = GR_RGB((val >> 16) & 0xFF,
			    (val >> 8) & 0xFF, (val & 0xFF));


    return ((void *) state);
}

static void *
active_state_init(xml_token * tag, void *in)
{
    widget_t *widget = (widget_t *) in;
    widget->states[STATE_ACTIVE].flags = 1;

    return (&widget->states[STATE_ACTIVE]);
}

static void *
inactive_state_init(xml_token * tag, void *in)
{
    widget_t *widget = (widget_t *) in;
    widget->states[STATE_INACTIVE].flags = 1;

    return (&widget->states[STATE_INACTIVE]);
}

static void *
data_hotspot(xml_token * tag, void *data, char *text, int size)
{
    widget_t *widget = (widget_t *) data;
    char *p = text;
    char *tmp;

    /* Figure out where the text ends (hint, its either a < or a \0) */

    while (*p != '<' && *p != 0)
	p++;

    tmp = alloca((int) (p - text) + 2);
    bzero(tmp, (int) (p - text) + 2);

    strncpy(tmp, text, (int) (p - text));

    sscanf(tmp, "%i %i %i %i",
	   &widget->hotspot.x, &widget->hotspot.y,
	   &widget->hotspot.w, &widget->hotspot.h);

    return (data);
}

static void *
data_width(xml_token * tag, void *data, char *text, int size)
{
    widget_t *widget = (widget_t *) data;
    char *p = text;
    char *tmp;

    if (!widget)
	return (0);

    /* Figure out where the text ends (hint, its either a < or a \0) */

    while (*p != '<' && *p != 0)
	p++;

    tmp = alloca((int) (p - text) + 2);
    bzero(tmp, (int) (p - text) + 2);

    strncpy(tmp, text, (int) (p - text));

    /* Parse the string, it should be two integers */
    sscanf(tmp, "%i %i", &widget->width.min, &widget->width.max);

    return (data);
}

static void *
data_height(xml_token * tag, void *data, char *text, int size)
{
    widget_t *widget = (widget_t *) data;

    char *p = text;
    char *tmp;

    if (!widget)
	return (0);

    /* Figure out where the text ends (hint, its either a < or a \0) */

    while (*p != '<' && *p != 0)
	p++;

    tmp = alloca((int) (p - text) + 2);
    bzero(tmp, (int) (p - text) + 2);

    strncpy(tmp, text, (int) (p - text));

    /* Parse the string, it should be two integers */
    sscanf(tmp, "%i %i", &widget->height.min, &widget->height.max);

    return (data);
}

static void *
data_padding(xml_token * tag, void *data, char *text, int size)
{
    theme_t *theme = (theme_t *) data;
    char *p = text;
    char *tmp;

    /* Figure out where the text ends (hint, its either a < or a \0) */
    if (!theme)
	return (0);

    while (*p != '<' && *p != 0)
	p++;

    tmp = alloca((int) (p - text) + 2);
    bzero(tmp, (int) (p - text) + 2);

    strncpy(tmp, text, (int) (p - text));

    sscanf(tmp, "%i %i %i %i",
	   &theme->client.left, &theme->client.right,
	   &theme->client.top, &theme->client.bottom);

    return (data);
}

static void *
widget_init(xml_token * tag, void *in)
{

    component_t *comp = (component_t *) in;
    char **widget_names = widgetList[comp->type];
    xml_prop *prop;

    char *lname = 0;
    int index = 0;

    for (prop = tag->props; prop; prop = prop->next) {
	if (strcmp(prop->keyword, "name") == 0) {
	    lname = prop->value;
	    break;
	}
    }

    if (!lname)
	return (0);

    while (strlen(widget_names[index])) {
	if (strcmp(widget_names[index], lname) == 0)
	    break;
	index++;
    }

    if (!strlen(widget_names[index]))
	return (0);

    /* Actually make the widget */
    comp->widgets[index] = (widget_t *) calloc(sizeof(widget_t), 1);

    /* Init a few of the items */
    comp->widgets[index]->width.min = 0;
    comp->widgets[index]->width.max = -1;

    comp->widgets[index]->height.min = 0;
    comp->widgets[index]->height.max = -1;

    return ((void *) comp->widgets[index]);
}

static void *
titlebar_init(xml_token * tag, void *in)
{

    theme_t *data = (theme_t *) in;
    component_t *comp = &data->components[COMPONENT_TITLEBAR];

    /* Set up the correct number of widgets */

    comp->widgetCount = TITLEBAR_WIDGET_COUNT;
    comp->widgets =
	(widget_t **) calloc(comp->widgetCount * sizeof(widget_t *), 1);
    comp->type = COMPONENT_TITLEBAR;

    return ((void *) comp);
}

static void *
border_init(xml_token * tag, void *in)
{

    component_t *comp;
    theme_t *data = (theme_t *) in;
    int index;

    if (strcmp(tag->tag, "border_left") == 0)
	index = COMPONENT_LEFT;
    else if (strcmp(tag->tag, "border_right") == 0)
	index = COMPONENT_RIGHT;
    else if (strcmp(tag->tag, "border_bottom") == 0)
	index = COMPONENT_BOTTOM;
    else if (strcmp(tag->tag, "border_top") == 0)
	index = COMPONENT_TOP;
    else {
	error("Unknown tag <%s> while parsing the theme file\n", tag->tag);

	return (0);
    }


    comp = &data->components[index];

    /* Set up the correct number of widgets */

    comp->widgetCount = BORDER_WIDGET_COUNT;
    comp->widgets =
	(widget_t **) calloc(comp->widgetCount * sizeof(widget_t *), 1);
    comp->type = index;

    return ((void *) comp);
}

void
freeTheme(theme_t * theme)
{

    int i, w, s;

    /* Go through and check each component */

    for (i = 0; i < THEME_COMPONENT_COUNT; i++) {
	component_t *comp = &theme->components[i];

	if (comp->widgets) {
	    for (w = 0; w < comp->widgetCount; w++)
		if (comp->widgets[w]) {
		    widget_t *widget = comp->widgets[w];

		    for (s = 0; s < 2; s++) {
			if (widget->states[s].image)
			    free(widget->states[s].image);
			if (widget->states[s].imageid)
			    GrDestroyWindow(widget->states[s].imageid);
		    }

		    free(widget);
		    comp->widgets[w] = 0;
		}

	    free(comp->widgets);
	}
    }

    if (theme->font)
	GrDestroyFont(theme->font);
    free(theme);
}

/* Main theme function */

theme_t *
createTheme(const char *directory)
{

    xml_parser engine;
    theme_t *theme;
    int ret;

    char *xmlfile;

    if (!directory)
	return (0);

    xmlfile = alloca(strlen(directory) + strlen("/theme.xml") + 1);
    sprintf(xmlfile, "%s/theme.xml", directory);

    /* Check that we can get to the theme XML file */

    if (access(xmlfile, R_OK)) {
	error("Unable to open the theme definition file '%s'.\n", xmlfile);
	return (0);
    }

    /* Create the theme structure */
    theme = (theme_t *) calloc(sizeof(theme_t), 1);
    if (!theme)
	return (0);

    engine.tags = themeToplevel;

    /* Now, start the parser */
    ret = xml_parseFile(&engine, xmlfile, (void *) theme);

    if (ret) {
	error("Error %d while loading theme '%s'.\n", directory);
	freeTheme(theme);
	return (0);
    }

    theme->font = GrCreateFont(GR_FONT_GUI_VAR, 12, 0);
    return (theme);
}

--- NEW FILE: apps.h ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#ifndef _APPS_H_
#define _APPS_H_

#include <nano-X.h>
#include <par/par.h>
#include <wm/nxlib.h>

#define ICONWIDTH	48
#define ICONHEIGHT	48
#define ICONTEXTHEIGHT	13

#define COLOR_TASKBAR 		GrGetSysColor(GR_COLOR_3DLIGHT)
#define COLOR_TASKBARHILIGHT	GrGetSysColor(GR_COLOR_BTNHIGHLIGHT)
#define COLOR_ICONTEXT		GrGetSysColor(GR_COLOR_ACTIVECAPTIONTEXT)
#define COLOR_DESKTOP 		GrGetSysColor(GR_COLOR_DESKTOP)
#define COLOR_REALDESKTOP 	GR_RGB(1,1,1)

void root_create(void);
void load_applications(char *);
void apps_buttondown(GR_WINDOW_ID id);
void home_create(void);
void date_create(void);
void backlight_create(void);
void scribble_create(void);
void keyboard_create(void);
void battery_create(void);

#ifdef VIRTUAL_WINDOWS
void cat_switch_create(void);
#endif

#define FL_INPUT        0x001
#define FL_NOICON	0x004	/* don't create icon or icon window */
#define FL_ONETIME      0x008	/* Only run once */
#ifdef VIRTUAL_WINDOWS
#define FL_STICKY       0x010
#endif

#ifdef VIRTUAL_WINDOWS
#define VW_STICKY       0x01
#endif


/* desktop and taskbar applications kept here*/
typedef struct
{
    NXLIST link;

    char m_name[30];

    char m_exec[64];		/* executable filename */
    char m_icontitle[64];	/* displayed icon title */
    char m_workdir[64];
    char m_args[64];
    int m_flags;		/* application flags */
    int m_icon_wid;		/* icon input window id */
    int m_icon_iid;		/* icon image id */
    int m_container_wid;	/* container window id */
    int m_process_id;		/* linux process id of running app */
#ifdef VIRTUAL_WINDOWS
    int m_virtual_wid;		/* The current virtual window that this app is associated with */
    int m_virtual_flags;	/* Virtual window flags */
#endif

}
APP;

typedef struct
{
    NXLIST next;
    int pid;
    APP *app;
}
PROCESS;

typedef struct app_info_struct
{
    int flags;

    char title[25];
    char path[128];
    char workdir[128];
    char icon[64];
    char args[64];
}
app_info_t;

extern NXLISTHEAD apphead;

extern APP *g_last_app;

/* Search functions */

APP *find_app_flags(int flags);
APP *find_app_path(char *path);	/* Find a app based on the path */
APP *find_app_pid(int pid);
APP *find_app_name(char *name);
APP *find_app_icon(GR_WINDOW_ID id);
APP *find_app_container(GR_WINDOW_ID id);

/* Old style process handlers */

void application_handler(int id);
APP *apps_add_onetime(char *path);

/* Application list managment */
int apps_add_application(char *, app_info_t * app_info, APP ** application);
int launch_application(APP * app);
void hide_application(APP * app);
void show_application(APP * app);
int is_app_running(APP * app);

/* Window managment */
void app_show_windows(int, int);
void app_hide_windows();

/* Process management */
void kill_running_processes();

/* input.c */

void killInput(APP * app);
void inputResizeWorkspace(APP * app);

#endif

--- NEW FILE: utils.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


/* These are functions that were previously in nxlib that */
/* were pulled over here to help with size considerations */

#include <stdio.h>
#include <stdlib.h>
#include <nano-X.h>
#include <nxdraw.h>
#include "utils.h"

/*
 * Calculate container size and client window offsets from
 * passed client window size and style.
 */

void
nxCalcNCSize(GR_WM_PROPS style, GR_SIZE wClient, GR_SIZE hClient,
	     GR_COORD * xCliOffset, GR_COORD * yCliOffset,
	     GR_SIZE * wContainer, GR_SIZE * hContainer)
{
    GR_SIZE width, height;
    GR_SIZE xoffset, yoffset;

    /* determine container size and client child window offsets */
    if (style & GR_WM_PROPS_APPFRAME) {
	width = wClient + CXFRAME;
	height = hClient + CYFRAME;
	xoffset = CXBORDER;
	yoffset = CYBORDER;
    } else if (style & GR_WM_PROPS_BORDER) {
	width = wClient + 2;
	height = hClient + 2;
	xoffset = 1;
	yoffset = 1;
    } else {
	width = wClient;
	height = hClient;
	xoffset = 0;
	yoffset = 0;
    }
    if (style & GR_WM_PROPS_CAPTION) {
	height += CYCAPTION;
	yoffset += CYCAPTION;
	if (style & GR_WM_PROPS_APPFRAME) {
	    /* extra line under caption with appframe */
	    ++height;
	    ++yoffset;
	}
    }

    if (xCliOffset)
	*xCliOffset = xoffset;
    if (yCliOffset)
	*yCliOffset = yoffset;
    if (wContainer)
	*wContainer = width;
    if (hContainer)
	*hContainer = height;
}

/*
 * Calculate client size window offsets from
 * passed container window size and style.
 */
void
nxCalcClientSize(GR_WM_PROPS style, GR_SIZE wContainer, GR_SIZE hContainer,
		 GR_COORD * xCliOffset, GR_COORD * yCliOffset,
		 GR_SIZE * wClient, GR_SIZE * hClient)
{
    GR_SIZE width, height;
    GR_SIZE xoffset, yoffset;

    /* determine client size and window offsets */
    if (style & GR_WM_PROPS_APPFRAME) {
	width = wContainer - CXFRAME;
	height = hContainer - CYFRAME;
	xoffset = CXBORDER;
	yoffset = CYBORDER;
    } else if (style & GR_WM_PROPS_BORDER) {
	width = wContainer - 2;
	height = hContainer - 2;
	xoffset = 1;
	yoffset = 1;
    } else {
	width = wContainer;
	height = hContainer;
	xoffset = 0;
	yoffset = 0;
    }
    if (style & GR_WM_PROPS_CAPTION) {
	height -= CYCAPTION;
	yoffset += CYCAPTION;
	if (style & GR_WM_PROPS_APPFRAME) {
	    /* extra line under caption with appframe */
	    --height;
	    ++yoffset;
	}
    }

    if (xCliOffset)
	*xCliOffset = xoffset;
    if (yCliOffset)
	*yCliOffset = yoffset;
    if (wClient)
	*wClient = width;
    if (hClient)
	*hClient = height;
}

/******** List Functions ************/

void *
nxItemAlloc(unsigned int size)
{
    return (void *) calloc(size, 1);
}

/* insert at tail of list*/
void
nxListAdd(PNXLISTHEAD pHead, PNXLIST pItem)
{
    if (pHead->tail) {
	pItem->prev = pHead->tail;
	pHead->tail->next = pItem;
    } else
	pItem->prev = NULL;
    pItem->next = NULL;
    pHead->tail = pItem;
    if (!pHead->head)
	pHead->head = pItem;
}

/* insert at head of list*/
void
nxListInsert(PNXLISTHEAD pHead, PNXLIST pItem)
{
    if (pHead->head) {
	pItem->next = pHead->head;
	pHead->head->prev = pItem;
    } else
	pItem->next = NULL;
    pItem->prev = NULL;
    pHead->head = pItem;
    if (!pHead->head)
	pHead->head = pItem;
}

void
nxListRemove(PNXLISTHEAD pHead, PNXLIST pItem)
{
    if (pItem->next)
	pItem->next->prev = pItem->prev;
    if (pItem->prev)
	pItem->prev->next = pItem->next;
    if (pHead->head == pItem)
	pHead->head = pItem->next;
    if (pHead->tail == pItem)
	pHead->tail = pItem->prev;
    pItem->next = pItem->prev = NULL;
}

--- NEW FILE: themes.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


/* VERY SUPER SECRET */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <nano-X.h>

#include "nanowm.h"
#include "themes.h"
#include "config.h"

static theme_t *activeTheme = 0;

static void
getWidgetWidth(theme_t * theme, int item, int state, int *minw, int *maxw)
{

    component_t *component = &theme->components[GET_COMPONENT(item)];
    widget_t *widget = component->widgets[GET_WIDGET(item)];

    if (minw)
	*minw = widget->width.min;
    if (maxw)
	*maxw = widget->width.max;
}

static void
getWidgetHeight(theme_t * theme, int item, int state, int *minh, int *maxh)
{

    component_t *component = &theme->components[GET_COMPONENT(item)];
    widget_t *widget = component->widgets[GET_WIDGET(item)];

    if (minh)
	*minh = widget->height.min;
    if (maxh)
	*maxh = widget->height.max;
}

static void
getWidgetColor(theme_t * theme, int item, int s,
	       GR_COLOR * fgcolor, GR_COLOR * bgcolor)
{

    component_t *component = &theme->components[GET_COMPONENT(item)];
    widget_t *widget = component->widgets[GET_WIDGET(item)];

    widget_state_t *state = &widget->states[s];

    /* If the state isn't set, then default to active (active must exist) */
    if (!state->flags)
	state = &widget->states[STATE_ACTIVE];

    if (bgcolor)
	*bgcolor = state->bgcolor;
    if (fgcolor)
	*fgcolor = state->fgcolor;
}

static void
drawWidget(GR_WINDOW_ID id, GR_GC_ID gc,
	   theme_t * theme, int item, int s, int x, int y, int w, int h)
{

    component_t *component;
    widget_t *widget;
    widget_state_t *state;

    if (!theme) {
	error("Invalid theme specified to drawWidget()\n");
	return;
    }

    if (GET_COMPONENT(item) >= THEME_COMPONENT_COUNT) {
	warning("Component %d does not exist in the current theme\n",
		GET_COMPONENT(item));
	return;
    }

    component = &theme->components[GET_COMPONENT(item)];

    if (!component->widgets) {
	warning("The current theme has no active widgets\n",
		GET_COMPONENT(item));
	return;
    }

    widget = component->widgets[GET_WIDGET(item)];

    if (!widget) {
	warning("Widget %d does not exist in the current theme\n", item);
	return;
    }

    state = &widget->states[s];

    /* If the state isn't set, then default to active (active must exist) */
    if (!state->flags)
	state = &widget->states[STATE_ACTIVE];

    if (state->image && !state->imageid) {

	GR_IMAGE_ID image;
	GR_IMAGE_INFO info;

	char *filename =
	    alloca(strlen(wm_getDir(DESKTOP_THEMEDIR)) +
		   strlen(state->image) + 2);
	sprintf(filename, "%s/%s", wm_getDir(DESKTOP_THEMEDIR), state->image);


	image = GrLoadImageFromFile(filename, 0);

	if (image) {

	    GrGetImageInfo(image, &info);
	    state->imageWidth = info.width;
	    state->imageHeight = info.height;

	    state->imageid =
		GrNewPixmap(state->imageWidth, state->imageHeight, 0);
	    if (state->imageid) {
		GR_GC_ID pgc = GrNewGC();
		GrDrawImageToFit(state->imageid, pgc, 0, 0, -1, -1, image);
		GrDestroyGC(pgc);
		GrFreeImage(image);
	    }
	}
    }

    if (!state->imageid) {
	if (w == -1)
	    w = widget->width.min;
	if (h == -1)
	    h = widget->height.min;
    } else {
	if (w == -1)
	    w = state->imageWidth;
	if (h == -1)
	    h = state->imageHeight;
    }

    /* If no image is available, go for the default colors */

    if (!state->imageid) {
	GrSetGCForeground(gc, state->bgcolor);
	GrFillRect(id, gc, x, y, w, h);
    } else {
	int xpos = x, ypos = y;
	int left = w;

	/* FIXME:  Handle both horizontal and vertical tiling */

	while (left) {
	    int cwidth;

	    if (left < state->imageWidth)
		cwidth = left;
	    else
		cwidth = state->imageWidth;

	    GrCopyArea(id, gc, xpos, ypos, cwidth, h, state->imageid, 0, 0,
		       MWROP_SRCCOPY);

	    xpos += cwidth;
	    left -= cwidth;
	}
    }
}

/* GLOBAL FUNCTIONS */

void
set_activeTheme(theme_t * theme)
{
    activeTheme = theme;
}
inline theme_t *
get_activeTheme(void)
{
    return (activeTheme);
}


static void
drawTitlebar(theme_t * theme, GR_DRAW_ID id, GR_GC_ID gc, int w, int h,
	     GR_CHAR * title, GR_BOOL active, GR_WM_PROPS props)
{


    int themeState = active ? STATE_ACTIVE : STATE_INACTIVE;
    int x = 0, y = 0;

    int captionWidth = 0;
    int closeWidth = 0;
    int paddingWidth = 0;

    /* Calculate the various sizes */

    if (title != 0) {
	int strw, strh, strb;
	int minw, maxw;

	getWidgetWidth(theme, TITLEBAR_WIDGET_CAPTION, themeState, &minw,
		       &maxw);

	GrSetGCFont(gc, theme->font);
	GrGetGCTextSize(gc, title, -1, GR_TFTOP, &strw, &strh, &strb);

	/* Now, figure out the size */
	if (strw < minw)
	    captionWidth = minw;
	else if (strw > maxw)
	    captionWidth = maxw;
	else
	    captionWidth = strw + 5;	/* Padding */
    }

    /* Close box */
    if ((props & GR_WM_PROPS_CLOSEBOX) == GR_WM_PROPS_CLOSEBOX) {
	int minw, maxw;

	getWidgetWidth(theme, TITLEBAR_WIDGET_CLOSEBUTTON, themeState, &minw,
		       &maxw);
	closeWidth = minw;
    }

    paddingWidth = w - (captionWidth + closeWidth);

    if (title != 0) {
	GR_COLOR fgcolor;

	getWidgetColor(theme, TITLEBAR_WIDGET_CAPTION, themeState, &fgcolor,
		       0);
	drawWidget(id, gc, theme, TITLEBAR_WIDGET_CAPTION, themeState, x, y,
		   captionWidth, -1);

	GrSetGCForeground(gc, fgcolor);
	GrSetGCUseBackground(gc, GR_FALSE);

	/* FIXME:  Text pos should be configurable */
	GrText(id, gc, x + 4, y, title, -1, GR_TFASCII | GR_TFTOP);
    }

    if (props & GR_WM_PROPS_CLOSEBOX)
	drawWidget(id, gc, theme, TITLEBAR_WIDGET_CLOSEBUTTON, themeState,
		   x + w - closeWidth, y, closeWidth, -1);

    if (paddingWidth)
	drawWidget(id, gc, theme, TITLEBAR_WIDGET_TITLEBAR, themeState,
		   x + captionWidth, y, paddingWidth, -1);
}

static void
drawBorder(theme_t * theme, GR_DRAW_ID id, GR_GC_ID gc, int cw, int ch,
	   GR_BOOL active, GR_WM_PROPS style, int item)
{

    int themeState = active ? STATE_ACTIVE : STATE_INACTIVE;
    int x, y, w, h;
    int tbarh;

    int widget = COMPONENT_WIDGET(item, 0);

    if ((style & GR_WM_PROPS_CAPTION) == GR_WM_PROPS_CAPTION)
	getWidgetHeight(theme, TITLEBAR_WIDGET_CAPTION, 0, 0, &tbarh);
    else
	tbarh = 0;

    switch (item) {

    case COMPONENT_TOP:
	x = 0;
	y = 0;
	w = cw - (theme->client.left - theme->client.right);
	h = theme->client.top;
	break;

    case COMPONENT_LEFT:
	x = 0;
	y = tbarh;
	w = theme->client.left;
	h = ch - tbarh;
	break;

    case COMPONENT_RIGHT:
	x = cw - theme->client.right;
	y = tbarh;
	w = theme->client.right;
	h = ch - tbarh;
	break;

    case COMPONENT_BOTTOM:
	x = theme->client.left;
	y = ch - theme->client.right;
	w = cw - (theme->client.left - theme->client.right);
	h = theme->client.bottom;
	break;
    }

    drawWidget(id, gc, theme, widget, themeState, x, y, w, h);
}

void
themeDrawContainer(GR_DRAW_ID id, int w, int h, GR_CHAR * title,
		   GR_BOOL active, GR_WM_PROPS props, theme_t * theme)
{

    GR_GC_ID gc;

    gc = GrNewGC();

    /* first draw the titlebar (if we have it) */

    if ((props & GR_WM_PROPS_CAPTION) == GR_WM_PROPS_CAPTION) {
	drawTitlebar(theme, id, gc, w, h, title, active, props);
    } else {
	drawBorder(theme, id, gc, w, h, active, props, COMPONENT_TOP);
    }

    /* Now draw the other three borders */
    if ((props & GR_WM_PROPS_BORDER) == GR_WM_PROPS_BORDER) {

	drawBorder(theme, id, gc, w, h, active, props, COMPONENT_LEFT);

	drawBorder(theme, id, gc, w, h, active, props, COMPONENT_RIGHT);

	drawBorder(theme, id, gc, w, h, active, props, COMPONENT_BOTTOM);
    }

    GrDestroyGC(gc);
}

void
themeContainerSize(theme_t * theme,
		   GR_WM_PROPS style, int clientw, int clienth,
		   int *xoff, int *yoff, int *containerw, int *containerh)
{

    int tbarh;

    if ((style & GR_WM_PROPS_CAPTION) == GR_WM_PROPS_CAPTION)
	getWidgetHeight(theme, TITLEBAR_WIDGET_CAPTION, 0, 0, &tbarh);
    else
	tbarh = theme->client.top;

    if ((style & GR_WM_PROPS_BORDER) == GR_WM_PROPS_BORDER) {
	*containerw = clientw + theme->client.left + theme->client.right;
	*containerh = clienth + tbarh + theme->client.bottom;
	*xoff = theme->client.left;
    } else {
	*containerw = clientw;
	*containerh = clienth + tbarh;
	*xoff = 0;
    }

    *yoff = tbarh;
}

void
themeClientSize(theme_t * theme, GR_WM_PROPS style, int containerw,
		int containerh, int *clientw, int *clienth)
{

    int tbarh;

    if ((style & GR_WM_PROPS_CAPTION) == GR_WM_PROPS_CAPTION)
	getWidgetHeight(theme, TITLEBAR_WIDGET_CAPTION, 0, 0, &tbarh);
    else
	tbarh = theme->client.top;

    if ((style & GR_WM_PROPS_BORDER) == GR_WM_PROPS_BORDER) {
	*clientw = containerw - (theme->client.left + theme->client.right);
	*clienth = containerh - (tbarh + theme->client.bottom);
    } else {
	*clientw = containerw;
	*clienth = containerh - tbarh;
    }
}

static void
themeGetWidgetOffset(theme_t * theme, GR_WM_PROPS style,
		     int index, int w, int h, int *x, int *y)
{

    int cl, cr, ct, cb;
    component_t *component = &theme->components[GET_COMPONENT(index)];
    widget_t *widget = component->widgets[GET_WIDGET(index)];

    if ((style & GR_WM_PROPS_BORDER) == GR_WM_PROPS_BORDER) {
	cr = w - theme->client.right;
	cl = theme->client.left;

	if ((style & GR_WM_PROPS_CAPTION) == GR_WM_PROPS_CAPTION)
	    ct = 0;
	else
	    ct = theme->client.top;

	cb = h - theme->client.bottom;
    } else {
	cl = 0;
	cr = w;
	ct = 0;
	cb = h;
    }

    switch (index) {
    case TITLEBAR_WIDGET_CLOSEBUTTON:
	*x = cr - widget->width.min;
	*y = ct;
	break;
    }
}

static GR_BOOL
PtInRect(GR_RECT * prc, GR_SIZE x, GR_SIZE y)
{
    return (x >= prc->x && x < (prc->x + prc->width) &&
	    y >= prc->y && y < (prc->y + prc->height));
}

int
widgetCheckBounds(theme_t * theme, GR_WM_PROPS style, int index, int x, int y,
		  int w, int h)
{

    component_t *component = &theme->components[GET_COMPONENT(index)];
    widget_t *widget = component->widgets[GET_WIDGET(index)];

    int xpos, ypos;

    themeGetWidgetOffset(theme, style, index, w, h, &xpos, &ypos);

    if (widget->hotspot.w || widget->hotspot.h) {
	GR_RECT r;
	r.x = xpos + widget->hotspot.x;
	r.y = ypos + widget->hotspot.y;
	r.width = widget->hotspot.w;
	r.height = widget->hotspot.h;

	return (PtInRect(&r, x, y));
    }

    return (0);
}

int
themeCheckBounds(theme_t * theme, GR_WM_PROPS style, int index, int x, int y,
		 int w, int h)
{

    GR_RECT r;
    int th;

    switch (index) {
    case COMPONENT_TITLEBAR:
	getWidgetHeight(theme, TITLEBAR_WIDGET_CAPTION, 0, 0, &th);
	r.x = 0;
	r.y = 0;
	r.width = w;
	r.height = th;
	break;

    default:
	return (0);
    }
    return (PtInRect(&r, x, y));
}

--- NEW FILE: sys_menu.h ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#ifndef SYS_MENU_H
#define SYS_MENU_H

#include <nano-X.h>

#define MENU_DIR_DOWN      0x01
#define MENU_DIR_UP        0x02
#define MENU_DIR_BEST      0x03

#define MENU_TYPE_REGULAR  0x00
#define MENU_TYPE_SEP      0x01
#define MENU_TYPE_CHECK    0x02
#define MENU_TYPE_APP      0x03
#define MENU_TYPE_CMENU    0x04
#define MENU_TYPE_END      0x05

typedef void (MENU_CALLBACK) (void *);

typedef struct
{
    char value[24];
    int type;
    void *action;
    void *cbdata;
    GR_BOOL checked;
    GR_IMAGE_ID icon;
}
wm_menu_t;

GR_BOOL system_menu_active();
int handle_system_menu(GR_EVENT * ep);
int open_system_menu(GR_WINDOW_ID parent, int x, int y,
		     int dir, wm_menu_t * menudata);

wm_menu_t *create_system_menu(int);
void destroy_system_menu(wm_menu_t *);

inline void sys_menu_add_item(wm_menu_t *, int, char *,
			      void *, void *, int, GR_IMAGE_ID iid);

/* Defined in virtwin.c */
wm_menu_t *create_catagory_menu(int index, char *name);

/* Defined in apps.c */
int create_apps_menu(wm_menu_t **);

/* Macros that abstract creating menu items */

#define ADD_SYS_MENU_REGULAR(ptr, value, action, data, icon) \
(sys_menu_add_item(ptr, MENU_TYPE_REGULAR, (char *) value, (void *) action, (void *) data, 0, icon))

#define ADD_SYS_MENU_SEP(ptr) (sys_menu_add_item(ptr, MENU_TYPE_SEP, 0, 0, 0, 0, 0))

#define ADD_SYS_MENU_CHECK(ptr, value, action, data, checked) \
(sys_menu_add_item(ptr, MENU_TYPE_CHECK, (char *) value, (void *) action, (void *) data, checked, 0))

#define ADD_SYS_MENU_APP(ptr, value, path, icon) \
(sys_menu_add_item(ptr, MENU_TYPE_APP, (char *) value, (void *) path, 0, 0, icon))

#define ADD_SYS_MENU_CMENU(ptr, value, menu) \
(sys_menu_add_item(ptr, MENU_TYPE_CMENU, (char *) value, (void *) menu, 0, 0, 0))

#define ADD_SYS_MENU_END(ptr) (sys_menu_add_item(ptr, MENU_TYPE_END, 0, 0, 0, 0,0))


#endif

--- NEW FILE: powerman.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */

#include <pixil_config.h>
#include <stdio.h>

#include <string.h>
#include <stdlib.h>
#include <nano-X.h>

#include <pixlib/pixlib.h>
#ifdef CONFIG_PAR
#include <par/par.h>
#endif

#include "powerman.h"

static GR_TIMER_ID pm_timer_id = 0;

struct {
  struct {
    int power;
    int bl_timeout;
    int bl_level;
    int bl_set;
    int power_timeout;
  } ac, bat;
} settings;

static int pm_bl_state = 1;

static void pm_do_callback(int type, void *data);

GR_TIMER_ID pm_get_timer_id(void) { return  pm_timer_id; }

static void set_pm_timer(int timeout) {
  if (pm_timer_id) return;
  pm_timer_id = GrCreateTimer(1, timeout);
  scrtop_register_timer(pm_timer_id, pm_suspend);
}

static void stop_bl_timer(void) {
  GrSetScreenSaverTimeout(0);
}

/* We have two levels of timers.  The first level is the backlight,
   triggered after N seconds of inactivity (aka the SCREENSAVER) 

   The second is the power managment timer, which is started after
   the screensaver fires.  The interesting here is if the 
*/

static void pm_first_timer(void) {
  
  int state = pix_pwr_onBattery();
 int timeout = 0;

  if (state == AC_ON) {    
    if (settings.ac.bl_timeout > 0)
      timeout = settings.ac.bl_timeout;
    else if (settings.ac.power && settings.ac.power_timeout > 0)
      timeout = settings.ac.power_timeout;
  }
  else if (state == BAT_ON) {
    if (settings.ac.bl_timeout > 0)
      timeout = settings.bat.bl_timeout;
    else if (settings.bat.power && settings.bat.power_timeout > 0)
      timeout = settings.bat.power_timeout;
  }

  GrSetScreenSaverTimeout(timeout);
}

static void pm_second_timer(void) {
  
  int state = pix_pwr_onBattery();
  int timeout = -1;

  if (pm_timer_id) return;

  if (state == AC_ON) {
    if (settings.ac.power && settings.ac.power_timeout > 0) {
      timeout = settings.ac.power_timeout;
      timeout -= (settings.ac.bl_timeout > 0) ? settings.ac.bl_timeout : 0;
    }
  }
  else if (state == BAT_ON) {
    if (settings.bat.power && settings.bat.power_timeout > 0) {
      timeout = settings.bat.power_timeout;
      timeout -= (settings.bat.bl_timeout > 0) ? settings.bat.bl_timeout : 0;
    }
  }

  /* If no timeout, then don't bother */
  /* If the timeout is zero, then suspend immediately */
  /* Otherwise, set the timer to fire at the appropriate time */

  if (timeout == -1) return;
  else if (timeout == 0) 
    pm_suspend();
  else
    pm_timer_id = GrCreateTimer(1, timeout);
}
    
static void pm_stop_timer(void) {
  if (pm_timer_id) GrDestroyTimer(pm_timer_id);
  scrtop_unregister_timer(pm_timer_id);

  pm_timer_id = 0;

  GrSetScreenSaverTimeout(0);
}

static void
pm_read_settings(void) {

  db_handle *db;
  db = db_openDB(db_getDefaultDB(), PAR_DB_MODE_RDONLY);
  if (!db) return;
 
  memset(&settings, 0, sizeof(settings));

  par_getGlobalPref(db, "power", "ac_off", PAR_BOOL, 
		    &settings.ac.power, sizeof(settings.ac.power));
  par_getGlobalPref(db, "power", "ac_offval", PAR_INT, 
		    &settings.ac.power_timeout, sizeof(settings.ac.power_timeout));

  par_getGlobalPref(db, "backlight", "ac_wakeup", PAR_BOOL, 
		    &settings.ac.bl_set, sizeof(settings.ac.bl_set));

  par_getGlobalPref(db, "backlight", "ac_timeout", PAR_INT, 
		    &settings.ac.bl_timeout, sizeof(settings.ac.bl_timeout));

  par_getGlobalPref(db, "backlight", "ac_level", PAR_INT, 
		    &settings.ac.bl_level, sizeof(settings.ac.bl_level));

  par_getGlobalPref(db, "power", "bat_off", PAR_BOOL, 
		    &settings.bat.power, sizeof(settings.bat.power));
  par_getGlobalPref(db, "power", "bat_offval", PAR_INT, 
		    &settings.bat.power_timeout, sizeof(settings.bat.power_timeout));

  par_getGlobalPref(db, "backlight", "bat_wakeup", PAR_BOOL, 
		    &settings.bat.bl_set, sizeof(settings.bat.bl_set));

  par_getGlobalPref(db, "backlight", "bat_timeout", PAR_INT, 
		    &settings.bat.bl_timeout, sizeof(settings.bat.bl_timeout));
  par_getGlobalPref(db, "backlight", "bat_level", PAR_INT, 
		    &settings.bat.bl_level, sizeof(settings.bat.bl_level));

  db_closeDB(db);
}

/* Called to reload the settings and restart the timers */

void pm_reload(void) {
  pm_stop_timer();     /* Stop both timers */
  pm_read_settings();
  pm_first_timer();    /* Set up the first tier timer */
}

void 
pm_init(void) {  
  pm_read_settings();
  pm_first_timer();   /* Set up the first tier timer */

  /* Start off in the default state */
  pm_backlight(pm_bl_state);
}

void
pm_suspend(void) {    

  int state = pix_pwr_onBattery();

  printf("Suspending the screentop - see you on the flip side\n");
  pm_stop_timer();    /* Stop both timers */

  pix_pwr_suspend();   /* At this point the power should be suspended */  
  pm_first_timer();   /* Start the first tier timer again */
}

void pm_backlight(int mode) {

  int state = pix_pwr_onBattery();
  int level, blto, max, val;

  switch(state) {
  case AC_ON:
    level = settings.ac.bl_level;
    blto = settings.ac.bl_timeout;
    break;

  case BAT_ON:
    level = settings.bat.bl_level;
    blto = settings.ac.bl_timeout;
    break;

  default:  /* No APM or error */
    goto do_callback;
  }
    
  max = pix_bl_getmxval();
  val = (((level * max) << 4) / 100) >> 4;
  
  if (mode == BL_ON) { 
    if (blto > 0) pm_first_timer();   
  }
  else if (mode == BL_OFF) {
    stop_bl_timer();
  }

  /* Set the value */
  pix_bl_ctrl(mode, val);

 do_callback:
  pm_bl_state = mode;
  pm_do_callback(PM_CALLBACK_BL, (void *) mode);
}

void pm_bl_toggle(void) {
  pm_backlight(!pm_bl_state);
}

int pm_get_bl_state(void) { return pm_bl_state; }
  
/* Fired when the screen saver timer expires */

void pm_bltimer_off(void) {

  int state = pix_pwr_onBattery();

  if (state == -1) return;

  if (state == AC_ON && settings.ac.bl_timeout <= 0)
      return;

  if (state == BAT_ON && settings.bat.bl_timeout <= 0)
    return;
  
  pm_backlight(0);  /* Turn off the backlight */

  pm_second_timer();   /* Set up the second tier timer */
}

/* Fired when the screen saver timer returns */

void pm_bltimer_on(void) {

  int state = pix_pwr_onBattery();

  /* Stop the second tier timer */

  if (pm_timer_id) {
    GrDestroyTimer(pm_timer_id);
    scrtop_unregister_timer(pm_timer_id);

    pm_timer_id = 0;
  }

  if (state == -1) return;

  if (pm_get_bl_state()) return;  /* Its already on */

  if (state == AC_ON && !settings.ac.bl_set)
    return; 

   if (state == AC_ON && !settings.bat.bl_set)
     return;

   pm_backlight(1);  /* Turn it back on */
}

struct pm_cb_list {
  pm_callback cb;
  struct pm_cb_list *next;
};

struct pm_cb_list *cblist[1] = {0};

/* Set up a function to be called when a particular power management event happens */

void pm_register_callback(int type, pm_callback cb) {
  struct pm_cb_list *l = (struct pm_cb_list *) calloc(1, sizeof(struct pm_cb_list));
  l->cb = cb;

  if (!cblist[type])
    cblist[type] = l;
  else {
    struct pm_cb_list *a = cblist[type];
    for(; a->next; a=a->next);
    a->next = l;
  }
}

void pm_unregister_callback(int type, pm_callback cb) {
  struct pm_cb_list *l = cblist[type];
  struct pm_cb_list *prev = 0;

  for(; l; l = l->next) {
    if (l->cb == cb) {
      if (prev) prev->next = l->next;
      else cblist[type] = l->next;

      free(l);
      return;
    }
    
    prev = l;
  }
}

/* Actually do the callbacks based on the given type and the given data */

static void pm_do_callback(int type, void *data) {
  struct pm_cb_list *l = cblist[type];
  for(; l; l = l->next)
    if (l->cb) l->cb(type, data);
}


    
    


--- NEW FILE: root.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */

#include <pixil_config.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pixlib/pixlib.h>

#include "nano-X.h"
#include "apps.h"
#include "nanowm.h"
#include "config.h"
#include "categories.h"

#ifdef CONFIG_PIXILWM_MENUS
#include "sys_menu.h"
#endif

/* External functions called from within */


static GR_SCREEN_INFO si;

static void root_wndproc(win * window, GR_EVENT * ep);
static void root_prepare_background(void);
static void root_redraw();

#ifdef CONFIG_PIXILWM_MENUS

static void
root_reset(void *foo)
{
    /* wm_load_config_settings(); */
    root_prepare_background();
    root_redraw();
}

static wm_menu_t *root_sys_menu = 0;
static wm_menu_t *apps_sys_menu = 0;

void close_nxscrtop(int);

static void
shutdown_cb(void *foo)
{
    close_nxscrtop(0);
}

#endif

void
root_create(void)
{
    GR_SCREEN_INFO si;
    GR_WM_PROPERTIES props;

#ifdef CONFIG_PIXILWM_MENUS
    int i = 0;
#endif

    /* add root window */
    add_window(GR_ROOT_WINDOW_ID, GR_ROOT_WINDOW_ID, 0, root_wndproc);

    /*
     * update and child update events must be set to hook
     * top level window mappings
     */

    GrSelectEvents(GR_ROOT_WINDOW_ID, GR_EVENT_MASK_CHLD_UPDATE |
		   GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_BUTTON_DOWN |
		   GR_EVENT_MASK_FDINPUT |
		   GR_EVENT_MASK_SCREENSAVER | GR_EVENT_MASK_TIMER | 
		   GR_EVENT_MASK_KEY_DOWN | GR_EVENT_MASK_KEY_UP);

    /* Platform specfic stuff */
    /* Ipaq: Grab the "power button" */

#ifdef CONFIG_PLATFORM_IPAQ
    GrGrabKey(GR_ROOT_WINDOW_ID, MWKEY_SUSPEND, GR_GRAB_HOTKEY_EXCLUSIVE);
#endif

    /* Zaurus:  Grab the Cancel button */
#ifdef CONFIG_PLATFORM_ZAURUS
    GrGrabKey(GR_ROOT_WINDOW_ID, MWKEY_ESCAPE, GR_GRAB_HOTKEY_EXCLUSIVE);
#endif

    /* Cache the background for speed */

    root_prepare_background();
    GrGetScreenInfo(&si);

    /* Step 1 - Get inital variables for the workspace width and height */
    setWorkspace(si.ws_width, si.ws_height);

    /* Step 2 - Make the input button */
    createInputButton();

    /* Step 3 - create the home button which aleways exists */
    home_create();

#ifdef NOTUSED
    date_create();

#ifdef CONFIG_PIXILWM_PM
    backlight_create();
#endif

    /* JHC - quick hack - we only bring up the battery if 
       APM is available
     */

#ifdef CONFIG_PIXILWM_PM
    if (!access("/proc/apm", R_OK))
	battery_create();
#endif
#endif

    /* Step 4 - Create the category browser */
    category_setCurrent(0);

#ifdef VIRTUAL_WINDOWS
    create_categoryBrowser();
#endif

    /* Step 5 - Set up the root window and get ready to draw! */
    props.flags = GR_WM_FLAGS_BACKGROUND;
    props.background = wm_getColor(WM_BGCOLOR);
    GrSetWMProperties(GR_ROOT_WINDOW_ID, &props);

    root_redraw();

#ifdef CONFIG_PIXILWM_MENUS

    /* Step 6 - Create the system menu (if applicable) */

    root_sys_menu = create_system_menu(6);

    if (create_apps_menu(&apps_sys_menu)) {
	ADD_SYS_MENU_CMENU(&root_sys_menu[0], "Quick Run...", apps_sys_menu);
	ADD_SYS_MENU_SEP(&root_sys_menu[1]);
	i = 2;
    } else {
	i = 0;
    }

    ADD_SYS_MENU_REGULAR(&root_sys_menu[i++], "Reset ScreenTop", root_reset,
			 0, 0);
    ADD_SYS_MENU_REGULAR(&root_sys_menu[i++], "About...", 0, 0, 0);
    ADD_SYS_MENU_REGULAR(&root_sys_menu[i++], "Shutdown", shutdown_cb, 0, 0);
    ADD_SYS_MENU_END(&root_sys_menu[i++]);
#endif

    /* Step 7 - There is no step 7 :) */

}

/* The following are special caching     */
/* routines to make the background image */
/* rendering run faster                  */

static GR_IMAGE_ID lastBGImage = 0;
static GR_WINDOW_ID lastBGPixmap = 0;
static int lastBGWidth = 0;
static int lastBGHeight = 0;

static void
root_prepare_background(void)
{
    GR_GC_ID gc = GrNewGC();
    GR_IMAGE_INFO iinfo;
    GR_IMAGE_ID iid;
    int style = 0;
    int wpactive = wm_getWallpaper(&iid, &style);
    int xpos, ypos, wi, hi;
    if (!si.rows)
	GrGetScreenInfo(&si);

    if (!wpactive || lastBGImage == iid)
	return;

    GrGetImageInfo(iid, &iinfo);

    /* Remove the last cached BG */

    if (lastBGPixmap)
	GrDestroyWindow(lastBGPixmap);

    /* Figure out the size of the cached pixmap */

    if (style == WALLPAPER_TILED || style == WALLPAPER_FULLSCREEN) {
	lastBGPixmap = GrNewPixmap(si.ws_width, si.ws_height, NULL);
	lastBGWidth = si.ws_width;
	lastBGHeight = si.ws_height;
    } else {			/* CENTERED */

	lastBGPixmap = GrNewPixmap(iinfo.width, iinfo.height, NULL);
	lastBGWidth = iinfo.width;
	lastBGHeight = iinfo.height;
    }

    GrSetGCForeground(gc, wm_getColor(WM_BGCOLOR));
    GrFillRect(lastBGPixmap, gc, 0, 0, lastBGWidth, lastBGHeight);

    lastBGImage = iid;


    /* Now draw into the pixmap.  If it is fullscreen or centered,
       thats trival.  Tiled is a little more bad */

    switch (style) {
    case WALLPAPER_TILED:

	for (ypos = 0; ypos < si.ws_height; ypos += iinfo.width)
	    for (xpos = 0; xpos < si.ws_width; xpos += iinfo.height) {
		if (si.ws_width - xpos < iinfo.width)
		    wi = si.ws_width - xpos;
		else
		    wi = iinfo.width;

		if (si.ws_height - ypos < iinfo.height)
		    hi = si.ws_height - ypos;
		else
		    hi = iinfo.height;

		GrDrawImageToFit(lastBGPixmap, gc, xpos, ypos, wi, hi, iid);
	    }

	break;

    case WALLPAPER_FULLSCREEN:
    case WALLPAPER_CENTERED:
    default:
	GrDrawImageToFit(lastBGPixmap, gc, 0, 0, -1, -1, iid);
	break;
    }

    GrDestroyGC(gc);
}

static void
root_draw_background(GR_WINDOW_ID wid, GR_REGION_ID r)
{
    GR_GC_ID gc = GrNewGC();
    GR_IMAGE_ID iid;
    int style = 0;

    int wpactive = wm_getWallpaper(&iid, &style);

    /* Set the clip region */
    GrSetGCRegion(gc, r);

    if (!si.rows)
	GrGetScreenInfo(&si);

    /* First, draw the background (if it is visible) */

    if (!wpactive || style == WALLPAPER_BOTTOM || style == WALLPAPER_CENTERED
	|| !lastBGPixmap) {
	GrSetGCForeground(gc, wm_getColor(WM_BGCOLOR));
	GrFillRect(wid, gc, 0, 0, si.ws_width, si.ws_height);
    }

    /* Now draw the wall paper */
    if (wpactive && lastBGPixmap) {
	int xpos, ypos, wi, hi;

	switch (style) {
	case WALLPAPER_TILED:
	case WALLPAPER_FULLSCREEN:
	    GrCopyArea(wid, gc, 0, 0, si.ws_width, si.ws_height,
		       lastBGPixmap, 0, 0, MWROP_SRCCOPY);

	    break;

	case WALLPAPER_BOTTOM:
	    xpos = (si.ws_width - lastBGWidth) / 2;
	    ypos = (si.ws_height - lastBGHeight);
	    wi = lastBGWidth;
	    hi = lastBGHeight;

	    GrCopyArea(wid, gc, xpos, ypos, wi, hi,
		       lastBGPixmap, 0, 0, MWROP_SRCCOPY);
	    break;

	case WALLPAPER_CENTERED:
	default:
	    xpos = (si.ws_width - lastBGWidth) / 2;
	    ypos = (si.ws_height - lastBGHeight) / 2;
	    wi = lastBGWidth;
	    hi = lastBGHeight;

	    GrCopyArea(wid, gc, xpos, ypos, wi, hi,
		       lastBGPixmap, 0, 0, MWROP_SRCCOPY);
	    break;
	}
    }

    GrDestroyGC(gc);
}

static void
root_exposure(win * window, GR_EVENT_EXPOSURE * ep)
{
    GR_GC_ID gc = GrNewGC();
    GR_REGION_ID r;
    GR_RECT rc;


    if (!si.rows)
	GrGetScreenInfo(&si);

    /* 
     * Create clip region based on exposed rectangle.
     * This keeps flicker way down.
     */
    r = GrNewRegion();
    rc.x = ep->x;
    rc.y = ep->y;
    rc.width = ep->width;
    rc.height = ep->height;
    GrUnionRectWithRegion(r, &rc);
    GrSetGCRegion(gc, r);

    /* draw taskbar */
    GrSetGCForeground(gc, wm_getColor(WM_TASKBAR));

    GrFillRect(ep->wid, gc, 0, si.ws_height, si.ws_width,
	       si.vs_height - si.ws_height);

    /* draw background (but only the rectangle) */
    root_draw_background(ep->wid, r);

    /* Draw the current list of icons */
    draw_current_iconlist(r);

    /* Draw the category browser */
    draw_categoryBrowser(r);

    GrDestroyGC(gc);
    GrDestroyRegion(r);
}

static void
root_redraw()
{
    GR_EVENT_EXPOSURE expose;
    GR_WINDOW_INFO info;

    /* dummy full area expose event */
    GrGetWindowInfo(GR_ROOT_WINDOW_ID, &info);
    expose.type = GR_EVENT_TYPE_EXPOSURE;
    expose.wid = GR_ROOT_WINDOW_ID;
    expose.x = 0;
    expose.y = 0;
    expose.width = info.width;
    expose.height = info.height;
    root_exposure(0, &expose);
}

inline void
redraw_root_window()
{
    root_redraw();
}

#ifdef CONFIG_PLATFORM_ZAURUS

static GR_TIMER_ID suspend_timer_id = 0;

static void handle_zaurus_suspend(void) {
  suspend_timer_id = 0;
  pm_suspend();
}

#endif

static void
root_wndproc(win * window, GR_EVENT * ep)
{
    switch (ep->type) {
    case GR_EVENT_TYPE_EXPOSURE:
	root_exposure(window, &ep->exposure);
	break;

    case GR_EVENT_TYPE_KEY_DOWN:
#ifdef CONFIG_PLATFORM_ZAURUS
      if (ep->keystroke.ch == MWKEY_ESCAPE) {
	/* The key must be pressed for 4 seconds before the suspend happens */
	suspend_timer_id = GrCreateTimer(GR_ROOT_WINDOW_ID, 4000);
	
	if (suspend_timer_id) 
	  scrtop_register_timer(suspend_timer_id, handle_zaurus_suspend);      
      }
#endif
      break;

    case GR_EVENT_TYPE_KEY_UP:
#ifdef CONFIG_PLATFORM_ZAURUS
      /* If the key is released before the timer, then get rid of the timer */

      if (ep->keystroke.ch == MWKEY_ESCAPE) {
	if (suspend_timer_id) {
	  GrDestroyTimer(suspend_timer_id);
	  
	  scrtop_unregister_timer(suspend_timer_id);
	  suspend_timer_id = 0;
	}
      }
#endif
      
#ifdef CONFIG_PLATFORM_IPAQ
	if (ep->keystroke.ch == MWKEY_SUSPEND)
	   pm_suspend();
#endif

	break;

#ifdef CONFIG_PIXILWM_MENUS
#ifdef NOTUSED
    case GR_EVENT_TYPE_BUTTON_LONG_CLICK:
#endif
    case GR_EVENT_TYPE_BUTTON_DOWN:
	if (ep->button.buttons & GR_BUTTON_R) {
	    open_system_menu(GR_ROOT_WINDOW_ID,
			     ep->button.x, ep->button.y, MENU_DIR_BEST,
			     root_sys_menu);
	}

	break;
#endif
    }
}

void
root_free_memory()
{

#ifdef CONFIG_PIXILWM_MENUS
    destroy_system_menu(root_sys_menu);
#endif

}

--- NEW FILE: sys_menu.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MWINCLUDECOLORS
#include <nano-X.h>

#include "nanowm.h"
#include "apps.h"
#include "sys_menu.h"

/* Drawing defines */

#define XPADDING 3

typedef struct wm_menu_st
{
    GR_WINDOW_ID wid;
    GR_WINDOW_ID pid;
    GR_COLOR bcolor;
    GR_COLOR tcolor;
    wm_menu_t *data;
    struct wm_menu_st *next;
    unsigned char selected;
    unsigned char btndown;

    unsigned char icon_align;
}
wm_menu_struct;

static wm_menu_struct *wm_menu_head = 0;
static wm_menu_struct *wm_menu_active = 0;

static GR_FONT_ID sys_fontid = 0;

static int YITEMSIZE = 0;

/* Forward declarations */
void menu_wndproc(win *, GR_EVENT *);
static void close_menu(wm_menu_struct *);

static wm_menu_struct *
create_new_menu(GR_WINDOW_ID parent, wm_menu_t * data,
		int x, int y, int dir, GR_COLOR bcolor, GR_COLOR tcolor)
{
    int use_icon = 0;

    int count = 0;
    int xsize = 0, ysize = 0;
    win *window;
    GR_WINDOW_INFO winfo;
    GR_GC_ID gc;
    wm_menu_struct *ptr;

    if (!data)
	return (0);

    GrGetWindowInfo(parent, &winfo);

    /* Ok, first of all determine the size of the window */

    gc = GrNewGC();
    GrSetGCFont(gc, sys_fontid);

    for (count = 0; data[count].type != MENU_TYPE_END; count++) {
	int wi, hi, ba;

	if (data[count].icon)
	    use_icon = 1;

	if (data[count].type == MENU_TYPE_SEP)
	    ysize += 6;
	else {
	    ysize += YITEMSIZE + 2;

	    GrGetGCTextSize(gc, (void *) data[count].value,
			    strlen(data[count].value), 0, &wi, &hi, &ba);

	    if (data[count].icon)
		wi += YITEMSIZE;

	    if (wi > xsize) {
		switch (data[count].type) {
		case MENU_TYPE_CHECK:
		case MENU_TYPE_CMENU:
		    xsize = wi + 10 + XPADDING;
		    break;
		default:
		    xsize = wi + (XPADDING * 2);
		    if (data[count].icon)
			xsize += YITEMSIZE;
		    break;
		}
	    }
	}
    }

    /* Put some padding around it */
    xsize += 4;

    if (ysize > winfo.height)
	return (0);

    GrDestroyGC(gc);

    /* Now, figure out which direction the sucker should point */
    if (dir == MENU_DIR_BEST) {
	/* We would prefer to go down, but if there is no room */
	if ((winfo.height - y) < ysize)
	    dir = MENU_DIR_UP;
	else
	    dir = MENU_DIR_DOWN;
    }

    /* Adjust the X and Y to fit into the screen */
    if ((winfo.width - x) < xsize)
	x = winfo.width - xsize;

    /* Reposition the menu if needed to fit it in the window */

    if (dir == MENU_DIR_DOWN) {
	if ((winfo.height - y) < ysize)
	    y = winfo.height - ysize;
    } else {
	if ((y < ysize))
	    y = 0;
	else
	    y = y - ysize;
    }

    /* Ok, lets start allocating some room, eh? */
    ptr = (wm_menu_struct *) malloc(sizeof(wm_menu_struct));

    if (!ptr)
	return (0);

    ptr->data = data;
    ptr->selected = -1;
    ptr->btndown = 0;
    ptr->bcolor = bcolor;
    ptr->tcolor = tcolor;
    ptr->next = 0;
    ptr->pid = parent;
    ptr->icon_align = use_icon;

    /* Now, do the window stuff */
    ptr->wid = GrNewWindowEx(GR_WM_PROPS_NODECORATE,
			     NULL, parent, x, y, xsize, ysize, bcolor);

    GrSelectEvents(ptr->wid,
		   GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_BUTTON_DOWN |
		   GR_EVENT_MASK_BUTTON_UP);

    window = add_window(ptr->wid, parent, 0, menu_wndproc);
    GrMapWindow(ptr->wid);

    return (ptr);
}

/* 
 * This is the routine that actually handles the drawing for a given 
 * menu and wid
 */

static void
draw_menu(GR_WINDOW_ID wid, wm_menu_t * data, int selected,
	  GR_COLOR back, GR_COLOR text, int icon_align)
{
    GR_GC_ID gc = GrNewGC();
    GR_WINDOW_INFO winfo;
    int i, ypos, xpos;

    int menu_width;

    GrGetWindowInfo(wid, &winfo);
    GrRaiseWindow(wid);		/* Always raise system menus to the top */

    menu_width = winfo.width - 2;

    ypos = 0;

    /* The main loop */
    for (i = 0; data[i].type != MENU_TYPE_END; i++) {
	GrSetGCBackground(gc, back);
	GrSetGCForeground(gc, text);

	/* Now, based on each menu type, do the drawing */
	switch (data[i].type) {
	case MENU_TYPE_SEP:
	    /* Seperator line 2 pixels thick spanning entire window */
	    /* FIXME:  This should come out of PAR */

	    GrSetGCForeground(gc, MWRGB(0x00, 0x66, 0xCC));
	    GrLine(wid, gc, 2, ypos + 2, winfo.width - 4, ypos + 2);
	    GrLine(wid, gc, 2, ypos + 4, winfo.width - 4, ypos + 4);

	    GrSetGCForeground(gc, text);
	    GrLine(wid, gc, 2, ypos + 3, winfo.width - 4, ypos + 3);

	    ypos += 6;
	    break;

	case MENU_TYPE_CHECK:
	    /* Check box with a indicator before the text */

#ifdef NOTUSED
	    if (data[i].checked == GR_TRUE)
		GrFillEllipse(wid, gc, 5, ypos + (YITEMSIZE / 2), 3, 3);	/* Filled */
	    else
		GrEllipse(wid, gc, 5, ypos + (YITEMSIZE / 2), 3, 3);	/* Empty */
#endif

	    if (data[i].checked == GR_TRUE)
		GrFillRect(wid, gc, 4, ypos + 6, 4, 4);
#ifdef NOTUSED
	    else
		GrRect(wid, gc, 4, ypos + 6, 4, 4);
#endif

	    GrSetGCFont(gc, sys_fontid);
	    GrText(wid, gc, 10, ypos + 1, data[i].value, -1, GR_TFTOP);

	    ypos += YITEMSIZE + 2;
	    break;

	case MENU_TYPE_CMENU:
	    {
		GR_POINT points[] = {
		    {winfo.width - 10, ypos + 2}
		    ,
		    {winfo.width - 3, ypos + (YITEMSIZE / 2)}
		    ,
		    {winfo.width - 10, ypos + YITEMSIZE - 1}
		};

		/* The parent of a cascading menu.  Arrow after the text */

		GrSetGCFont(gc, sys_fontid);
		GrText(wid, gc, 1 + XPADDING, ypos + 1,
		       data[i].value, -1, GR_TFTOP);

		GrSetGCForeground(gc, text);
		GrFillPoly(wid, gc, 3, points);

		GrSetGCForeground(gc, GRAY);
		GrPoly(wid, gc, 3, points);

		ypos += YITEMSIZE + 2;
		break;
	    }

	case MENU_TYPE_APP:
	case MENU_TYPE_REGULAR:	/* These differ only by callback */

	    if (i == selected) {
		GrFillRect(wid, gc, 1, ypos, winfo.width - 2, YITEMSIZE + 1);

		GrSetGCForeground(gc, back);
		GrSetGCBackground(gc, text);

	    }

	    if (icon_align)
		xpos = YITEMSIZE + XPADDING;
	    else
		xpos = 1 + XPADDING;

	    if (data[i].icon)
		GrDrawImageToFit(wid, gc, 1, ypos + 1, YITEMSIZE,
				 YITEMSIZE, data[i].icon);

	    GrSetGCFont(gc, sys_fontid);

	    GrText(wid, gc, xpos, ypos + 1, data[i].value, -1, GR_TFTOP);

	    ypos += YITEMSIZE + 2;
	    break;
	}
    }

    /* Finally, draw a border around the window */
    GrSetGCForeground(gc, text);
    GrRect(wid, gc, 0, 0, winfo.width, winfo.height);

    GrDestroyGC(gc);
}

static int
get_item_pos(wm_menu_t * data, int selected)
{
    int ypos = 0;
    int i;

    for (i = 0; data[i].type != MENU_TYPE_END; i++) {
	if (i == selected)
	    return (ypos);

	switch (data[i].type) {
	case MENU_TYPE_SEP:
	    ypos += 6;
	    break;

	default:
	    ypos += YITEMSIZE + 2;
	}
    }

    return (0);
}

static int
check_mouse_pos(wm_menu_t * data, int x, int y)
{
    int i;
    int ypos = 0;

    for (i = 0; data[i].type != MENU_TYPE_END; i++)
	switch (data[i].type) {
	case MENU_TYPE_SEP:
	    /* Ignore seperators */
	    ypos += 6;
	    break;

	case MENU_TYPE_CMENU:
	case MENU_TYPE_APP:
	case MENU_TYPE_REGULAR:
	case MENU_TYPE_CHECK:
	    /* All these have the same ysize */
	    if (y >= ypos && y <= ypos + YITEMSIZE)
		return (i);

	    ypos += YITEMSIZE + 2;
	    break;
	}

    return (-1);
}

static void
expose_menu(GR_WINDOW_ID wid)
{
    wm_menu_struct *menu_ptr;

    if (!wm_menu_head)
	return;

    menu_ptr = wm_menu_head;

    /* Now go through and draw all of the active menus */

    while (menu_ptr) {
	/* Only draw those menus that require it */

	if (menu_ptr->wid == wid)
	    draw_menu(menu_ptr->wid, menu_ptr->data, menu_ptr->selected,
		      menu_ptr->bcolor, menu_ptr->tcolor,
		      menu_ptr->icon_align);

	menu_ptr = menu_ptr->next;
    }
}

static int
menu_buttonup(GR_EVENT_BUTTON * ep)
{
    int i;
    void *data;
    GR_WINDOW_INFO winfo;
    MENU_CALLBACK *cb;
    int ypos;

    if (!wm_menu_active)
	return (0);

    if (!wm_menu_active->btndown)
	return (0);

    /* Reset the buttondown flag */
    wm_menu_active->btndown = 0;

    /* Get the current menu selection */
    i = wm_menu_active->selected;

#ifdef SYSTEM_SOUNDS
    if (wm_menu_active->data[i].type != MENU_TYPE_SEP)
	play_sound(SOUND_CLICKED);
#endif

    switch (wm_menu_active->data[i].type) {
    case MENU_TYPE_REGULAR:
    case MENU_TYPE_CHECK:
	/* Do a callback */
	cb = (MENU_CALLBACK *) wm_menu_active->data[i].action;
	data = wm_menu_active->data[i].cbdata;

	/* Close the menu before we do the callback, just to be safe */
	close_menu(wm_menu_head);

	if (cb)
	    cb(data);

	return (1);

    case MENU_TYPE_APP:
	/* Do an app */
	if (wm_menu_active->data[i].action) {
	    APP *app;

	    /* Editorial:  I don't like this, but it seems to be the best way */
	    if (!
		(app =
		 find_app_path((char *) wm_menu_active->data[i].action)))
		app =
		    apps_add_onetime((char *) wm_menu_active->data[i].action);

	    if (app)
		launch_application(app);
	}

	close_menu(wm_menu_head);
	return (1);

    case MENU_TYPE_CMENU:
	/* Do a new child menu */
	/* Get some stats */

	GrGetWindowInfo(wm_menu_active->wid, &winfo);

	ypos = get_item_pos(wm_menu_active->data, wm_menu_active->selected);

	/* Make a new menu! */
	wm_menu_active->next =
	    create_new_menu(wm_menu_active->pid,
			    (wm_menu_t *) wm_menu_active->data[i].action,
			    winfo.x + winfo.width + 2, winfo.y + ypos,
			    MENU_DIR_BEST, WHITE, MWRGB(0x00, 0x66, 0xCC));

	if (wm_menu_active->next)
	    wm_menu_active = wm_menu_active->next;

	return (1);
    }

    return (0);
}

static int
menu_buttondown(GR_EVENT_BUTTON * ep)
{
    int ret;
    int backtrack = 0;

    if (!wm_menu_active)
	return (0);

    if (ep->wid != wm_menu_active->wid) {
	wm_menu_struct *ptr = wm_menu_head;

	/* Look to see if the click was anywhere in the tree */
	while (ptr) {
	    if (ptr->wid == ep->wid) {
		close_menu(ptr->next);
		wm_menu_active = ptr;
		backtrack = 1;
		break;
	    }
	    ptr = ptr->next;
	}

	if (!ptr) {
	    /* Close all of the menus */
	    close_menu(wm_menu_head);
	    return (1);
	}
    }

    ret = check_mouse_pos(wm_menu_active->data, ep->x, ep->y);

    if (ret != -1 && !backtrack) {
	wm_menu_active->selected = ret;
	wm_menu_active->btndown = 1;
	expose_menu(wm_menu_active->wid);
    }

    return (1);
}

static void
close_menu(wm_menu_struct * ptr)
{
    wm_menu_struct *mptr = wm_menu_head;
    wm_menu_struct *pptr = 0;

    if (!ptr && !wm_menu_head)
	return;

    mptr = wm_menu_head;

    while (mptr && mptr != ptr) {
	pptr = mptr;
	mptr = mptr->next;
    }

    if (!mptr)			/* Couldn't find it! */
	return;

    if (pptr) {
	pptr->next = 0;
	wm_menu_active = pptr;
    } else {
	wm_menu_head = 0;
	wm_menu_active = 0;
    }

    while (mptr) {
	win *window;

	/* If we didn't allocate it, why do we try to free it? */

	/* if (mptr->data)
	   free(mptr->data);
	 */

	window = find_window(mptr->wid);
	remove_window(window);
	GrDestroyWindow(mptr->wid);

	pptr = mptr;
	mptr = mptr->next;
	free(pptr);
    }
}

int
handle_system_menu(GR_EVENT * ep)
{
    switch (ep->type) {
    case GR_EVENT_TYPE_EXPOSURE:
	expose_menu(ep->exposure.wid);
	return (0);

    case GR_EVENT_TYPE_BUTTON_DOWN:
	return (menu_buttondown(&ep->button));

    case GR_EVENT_TYPE_BUTTON_UP:
	return (menu_buttonup(&ep->button));
    }

    return (0);
}

void
menu_wndproc(win * window, GR_EVENT * ep)
{
    handle_system_menu(ep);
}

GR_BOOL
system_menu_active()
{
    if (wm_menu_active)
	return (1);
    else
	return (0);
}

int
open_system_menu(GR_WINDOW_ID parent, int x, int y,
		 int dir, wm_menu_t * menudata)
{
    GR_FONT_INFO finfo;

    if (wm_menu_head) {
	printf("Only one menu at a time!\n");
	return (0);
    }

    /* Allocate the font if not already done */

    if (!sys_fontid) {
	sys_fontid = GrCreateFont(GR_FONT_GUI_VAR, 0, 0);
	GrGetFontInfo(sys_fontid, &finfo);

	YITEMSIZE = finfo.height + 2;
    }

    wm_menu_head = create_new_menu(parent,
				   (wm_menu_t *) menudata,
				   x, y, dir, WHITE, MWRGB(0x00, 0x66, 0xCC));

#ifdef SYSTEM_SOUNDS
    play_sound(SOUND_MENU_OPENED);
#endif

    if (!wm_menu_head)
	return (0);
    else {
	wm_menu_active = wm_menu_head;
	return (1);
    }
}

void
destroy_system_menu(wm_menu_t * menu)
{
    int i;

    if (!menu)
	return;

    /* Go through and free as much as possible */

    for (i = 0; menu[i].type != MENU_TYPE_END; i++) {
	if (menu[i].type == MENU_TYPE_CMENU)
	    if (menu[i].action)
		destroy_system_menu(menu[i].action);
    }

    free(menu);
}

wm_menu_t *
create_system_menu(int size)
{
    return ((wm_menu_t *) malloc(size * sizeof(wm_menu_t)));
}


/* This is a simple utility function that will fill in a particular entry */
/* in the wm_menu_t structure.  This is defined inline for speed          */

/* There are macros in sys_menu.h that abstract this for each menu type   */

inline void
sys_menu_add_item(wm_menu_t * ptr, int tp, char *value, void *action,
		  void *data, int checked, GR_IMAGE_ID iid)
{
    ptr->type = tp;

    if (value) {
	strncpy(ptr->value, value, 24);

	if (strlen(value) > 24)
	    ptr->value[24] = 0;
    } else
	ptr->value[0] = 0;

    ptr->action = action;
    ptr->cbdata = data;
    ptr->checked = checked;
    ptr->icon = iid;
}

--- NEW FILE: icons.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "apps.h"
#include "nanowm.h"
#include "categories.h"
#include "config.h"

#define XOFFSET 20
#define YOFFSET 30
#define XSPACING (ICONWIDTH+20)
#define YSPACING (ICONHEIGHT+ICONTEXTHEIGHT+20)

#define DEFAULT_ICON	"generic_app.gif"

GR_IMAGE_ID
loadIconImage(char *filename, char *app, int useDefault)
{

    GR_IMAGE_ID ret;

    char *f = 0;
    char *d = 0;
    char *basename = 0;

    if (filename && filename[0] != 0x0) {

	/* Append the path if nessesary */

	if (filename[0] != '/') {
	    f = alloca(strlen(wm_getDir(DESKTOP_IMAGEDIR)) +
		       strlen(filename) + 2);
	    if (!f)
		return (0);

	    sprintf(f, "%s/%s", wm_getDir(DESKTOP_IMAGEDIR), filename);

	    /* Check if the file exists */
	    if (access(f, F_OK) != 0) {
		warning("image '%s' does not exist.\n", f);
		goto useDefault;
	    }
	    ret = GrLoadImageFromFile(f, 0);
	    if (ret == 0)
		goto useDefault;
	    return ret;
	}

	if (access(filename, F_OK) != 0) {
	    warning("image '%s' does not exist.\n", filename);
	    goto useDefault;
	}

	/* Use the absolute path that was passed in */
	error("returning GrLoadImageFromFile() 2\n");
	ret = GrLoadImageFromFile(filename, 0);
	if (ret == 0)
	    goto useDefault;
	return ret;
    }

    /* Otherwise, we will use the basename of the application */

    if (!app)
	return (0);

    basename = strrchr(app, '/');
    if (!basename)
	basename = app;
    else
	basename = basename + 1;

    f = alloca(strlen(wm_getDir(DESKTOP_IMAGEDIR)) + strlen(basename) + 2);
    if (!f)
	return (0);

    sprintf(f, "%s/%s", wm_getDir(DESKTOP_IMAGEDIR), basename);

    if (access(f, F_OK) == 0)
	return (GrLoadImageFromFile(f, 0));
    warning("image '%s' does not exist.\n", filename);

  useDefault:
    if (!useDefault)
	return (0);

    /* If we get this far, then we need use the default icon */
    d = alloca(strlen(wm_getDir(DESKTOP_IMAGEDIR)) + strlen(DEFAULT_ICON) +
	       2);
    if (!d)
	return (0);

    sprintf(d, "%s/%s", wm_getDir(DESKTOP_IMAGEDIR), DEFAULT_ICON);

    ret = GrLoadImageFromFile(d, 0);

    if (!ret)
	error("Unable to load a default icon for app '%s'.\n", app);

    return (ret);
}

void
hide_icon_list(void)
{
    int i;

    category_t *cat = (category_t *) category_getCurrent();

    if (!cat)
	return;
    for (i = 0; i < cat->count; i++)
	GrUnmapWindow(cat->apps[i]->m_icon_wid);
}

/* Where size is the maximum width of the label (in pixels) */

void
drawLabel(GR_GC_ID gc, char *label, int x, int y, int icon)
{

    int dy = y;
    int size = icon + 20;

    char *p = alloca(strlen(label) + 1);
    if (!p)
	return;

    strcpy(p, label);

    while (1) {
	int w, h, b;
	char *n;

	GrGetGCTextSize(gc, p, -1, GR_TFASCII | GR_TFTOP, &w, &h, &b);

	/* if it fits, then go with it */

	if (w <= size) {
	    int dx = x + ((icon - w) / 2);
	    GrText(GR_ROOT_WINDOW_ID, gc, dx, dy, p, -1,
		   GR_TFASCII | GR_TFTOP);
	    return;
	}

	/* Look for a break in the text */
	n = strchr(p, ' ');
	if (n)
	    *n = 0;

	GrGetGCTextSize(gc, p, -1, GR_TFASCII | GR_TFTOP, &w, &h, &b);

	if (w < size) {
	    int dx = x + ((icon - w) / 2);

	    GrText(GR_ROOT_WINDOW_ID, gc, dx, dy, p, -1,
		   GR_TFASCII | GR_TFTOP);

	    dy += h;
	    p = n + 1;
	} else {		/* Truncate it */
	    int avg = w / strlen(p);
	    int delta = (w - size) / avg;
	    int pos = strlen(p) - (delta + 4);
	    int dx, i;

	    /* We need to cut off delta + 4 chars */
	    for (i = pos; i < pos + 3; i++)
		p[i] = '.';

	    p[i] = 0;

	    GrGetGCTextSize(gc, p, -1, GR_TFASCII | GR_TFTOP, &w, &h, &b);
	    dx = x + ((icon - w) / 2);

	    GrText(GR_ROOT_WINDOW_ID, gc, dx, dy, p, -1,
		   GR_TFASCII | GR_TFTOP);
	    return;
	}
    }
}

/* The passed GC is appropriately clipped */

void
draw_current_iconlist(GR_REGION_ID r)
{
    int i;
    GR_GC_ID gc;

    GR_IMAGE_INFO iinfo;

    int xpos = XOFFSET;
    int ypos = YOFFSET;

    GR_FONT_ID fnt = GrCreateFont(GR_FONT_GUI_VAR, 0, NULL);
    GR_SCREEN_INFO si;

    category_t *cat = (category_t *) category_getCurrent();

    if (!cat)
	return;

    gc = GrNewGC();
    GrGetScreenInfo(&si);

    /* Set the clip region */
    GrSetGCRegion(gc, r);

    GrSetGCForeground(gc, wm_getColor(WM_ICONTEXT));

    /* If we have a background color for the icon, then use it, otherwise */
    /* don't use the background */

    if (wm_getColor(WM_ICONCOLOR) >= 0)
	GrSetGCBackground(gc, wm_getColor(WM_ICONCOLOR));
    else
	GrSetGCUseBackground(gc, 0);

    GrSetGCFont(gc, fnt);

    for (i = 0; i < cat->count; i++) {
	APP *cur = cat->apps[i];

	if (!cur->m_icon_iid)
	    continue;
	if (cur->m_flags & FL_INPUT)
	    continue;

	GrMoveWindow(cur->m_icon_wid, xpos, ypos);
	GrMapWindow(cur->m_icon_wid);

	GrGetImageInfo(cur->m_icon_iid, &iinfo);
	if ((iinfo.width > ICONWIDTH) || (iinfo.height > ICONHEIGHT)) {
	    GrDrawImageToFit(GR_ROOT_WINDOW_ID, gc, xpos, ypos,
			     ICONWIDTH, ICONHEIGHT, cur->m_icon_iid);
	} else {
	    GrDrawImageToFit(GR_ROOT_WINDOW_ID, gc,
			     // xpos, ypos, 
			     xpos + ((ICONWIDTH - iinfo.width) / 2),
			     ypos + (ICONHEIGHT - iinfo.height),
			     // ICONWIDTH, ICONHEIGHT, 
			     iinfo.width, iinfo.width, cur->m_icon_iid);
	}
	drawLabel(gc, cur->m_icontitle, xpos, ypos + ICONHEIGHT + 5,
		  ICONWIDTH);

	if (xpos + XSPACING + XSPACING > si.ws_width) {
	    xpos = 20;
	    ypos += YSPACING;
	} else
	    xpos += XSPACING;
    }

    GrDestroyFont(fnt);
    GrDestroyGC(gc);
}

static void
icon_handler(win * window, GR_EVENT * ep)
{
    switch (ep->type) {
    case GR_EVENT_TYPE_BUTTON_DOWN:
	apps_buttondown(window->wid);
	break;
    }
}

GR_WINDOW_ID
create_icon_window()
{
    GR_WINDOW_ID wid = GrNewInputWindow(GR_ROOT_WINDOW_ID, 20, 20,
					ICONWIDTH,
					ICONHEIGHT + ICONTEXTHEIGHT);

    add_window(wid, GR_ROOT_WINDOW_ID, 0, icon_handler);

    GrSelectEvents(wid, GR_EVENT_MASK_BUTTON_DOWN | GR_EVENT_MASK_BUTTON_UP);

    return (wid);
}

--- NEW FILE: powerman.h ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */

#ifndef POWERMAN_H_
#define POWERMAN_H_

#define BL_OFF 0
#define BL_ON  1

#define DISABLED -1
#define AC_ON     0
#define BAT_ON    1

/* General functions */

void pm_init(void);
void pm_reload(void);

/* Callback functions */

#define PM_CALLBACK_BL 0x0

typedef void (*pm_callback)(int, void *);

void pm_register_callback(int type, pm_callback cb);
void pm_unregister_callback(int type, pm_callback cb);

/* APM functions */
GR_TIMER_ID pm_get_timer_id(void);
void pm_suspend(void);

/* Backlight functions */

void pm_backlight(int mode);

void pm_bltimer_on(void);
void pm_bltimer_off(void);

int pm_get_bl_status(void);
void pm_bl_toggle(void);

#endif




More information about the dslinux-commit mailing list