source: trunk/athena/lib/Xj/Jets.c @ 20159

Revision 20159, 32.5 KB checked in by rbasch, 21 years ago (diff)
Use stdarg instead of varargs.
Line 
1/*
2 * $Id: Jets.c,v 1.5 2004-02-25 21:21:37 rbasch Exp $
3 *
4 * Copyright 1990, 1991 by the Massachusetts Institute of Technology.
5 *
6 * For copying and distribution information, please see the file
7 * <mit-copyright.h>.
8 *
9 */
10
11#if  (!defined(lint))  &&  (!defined(SABER))
12static char *rcsid =
13"$Id: Jets.c,v 1.5 2004-02-25 21:21:37 rbasch Exp $";
14#endif
15
16#include "mit-copyright.h"
17#include <stdio.h>
18#include <stdlib.h>
19#include <X11/Xos.h>
20#include <ctype.h>
21#include <stdarg.h>
22#include <errno.h>
23#include <sys/time.h>
24#include <sys/types.h>
25#include <sys/resource.h>
26#include <sys/ioctl.h>
27#ifdef HAVE_SYS_FILIO_H
28#include <sys/filio.h>
29#endif
30#include "Jets.h"
31#include "hash.h"
32
33extern int StrToXFontStruct();
34extern int StrToXColor();
35extern int StrToPixmap();
36extern int StrToDirection();
37extern int StrToOrientation();
38extern int StrToBoolean();
39extern int StrToJustify();
40
41int DEBUG = 0;
42
43static XjCallbackProc checkSignals = NULL;
44static XjEventProc eventHandler = NULL;
45
46int global_argc;
47char **global_argv;
48XrmDatabase rdb = NULL;
49
50char *displayName;
51char *programName = NULL;
52char *programClass;
53
54int malloced = 0;
55int lastmallocs = 0;
56int lastbreak = 0;
57int accounting = 1;
58
59static int gotRegisterContextType = 0;
60static XContext registerContext;
61static int gotSelectContextType = 0;
62static XContext selectContext;
63
64#ifndef APPDEFDIR
65#define APPDEFDIR "/usr/lib/X11/app-defaults"
66#endif
67static char *appdefdir = APPDEFDIR;
68
69/*
70static XrmOptionDescRec opTable[] = {
71{"+rv",         "*reverseVideo", XrmoptionNoArg,        (caddr_t) "off"},
72{"+synchronous","*synchronous", XrmoptionNoArg,         (caddr_t) "off"},
73{"-background", "*background",  XrmoptionSepArg,        (caddr_t) NULL},
74{"-bd",         "*borderColor", XrmoptionSepArg,        (caddr_t) NULL},
75{"-bg",         "*background",  XrmoptionSepArg,        (caddr_t) NULL},
76{"-bordercolor","*borderColor", XrmoptionSepArg,        (caddr_t) NULL},
77{"-borderwidth",".borderWidth", XrmoptionSepArg,        (caddr_t) NULL},
78{"-bw",         ".borderWidth", XrmoptionSepArg,        (caddr_t) NULL},
79{"-display",    ".display",     XrmoptionSepArg,        (caddr_t) NULL},
80{"-fg",         "*foreground",  XrmoptionSepArg,        (caddr_t) NULL},
81{"-fn",         "*font",        XrmoptionSepArg,        (caddr_t) NULL},
82{"-font",       "*font",        XrmoptionSepArg,        (caddr_t) NULL},
83{"-foreground", "*foreground",  XrmoptionSepArg,        (caddr_t) NULL},
84{"-geometry",   ".geometry",    XrmoptionSepArg,        (caddr_t) NULL},
85{"-iconic",     ".iconic",      XrmoptionNoArg,         (caddr_t) "on"},
86{"-name",       ".name",        XrmoptionSepArg,        (caddr_t) NULL},
87{"-reverse",    "*reverseVideo", XrmoptionNoArg,        (caddr_t) "on"},
88{"-rv",         "*reverseVideo", XrmoptionNoArg,        (caddr_t) "on"},
89{"-synchronous","*synchronous", XrmoptionNoArg,         (caddr_t) "on"},
90{"-title",      ".title",       XrmoptionSepArg,        (caddr_t) NULL},
91{"-xrm",        NULL,           XrmoptionResArg,        (caddr_t) NULL},
92{"-appdefs",    ".appDefs",     XrmoptionSepArg,        (caddr_t) NULL},
93{"-f",          ".appDefs",     XrmoptionSepArg,        (caddr_t) NULL},
94{"-userdefs",   ".userDefs",    XrmoptionSepArg,        (caddr_t) NULL}
95};
96*/
97
98typedef struct _JetResources {
99  char *appDefs;                /* name of application defaults file to use */
100  char *userDefs;               /* name of user defaults file */
101  char *display;                /* display name */
102  char *name;                   /* application name */
103} JetResources;
104
105typedef struct _JetResources *JetResourcesPtr;
106
107JetResources startup;
108
109#define offset(field) XjOffset(JetResourcesPtr,field)
110
111static XjResource startupResources[] = {
112  { "appDefs", "AppDefs", XjRString, sizeof(char *),
113      offset(appDefs), XjRString, NULL },
114  { "userDefs", "UserDefs", XjRString, sizeof(char *),
115      offset(userDefs), XjRString, NULL },
116  { "display", "Display", XjRString, sizeof(char *),
117      offset(display), XjRString, NULL },
118  { "name", "Name", XjRString, sizeof(char *),
119      offset(name), XjRString, NULL }
120};
121
122#undef offset
123
124RootClassRec rootClassRec = {
125{
126    /* class name */            "Root",
127    /* jet size */              sizeof(RootRec),
128    /* classInitialize */       NULL,
129    /* classInitialized? */     1,
130    /* initialize */            NULL,
131    /* prerealize */            NULL,
132    /* realize */               NULL,
133    /* event */                 NULL,
134    /* expose */                NULL,
135    /* querySize */             NULL,
136    /* move */                  NULL,
137    /* resize */                NULL,
138    /* destroy */               NULL,
139    /* resources */             NULL,
140    /* number of 'em */         0
141  }
142};
143
144JetClass rootJetClass = (JetClass)&rootClassRec;
145int curID = 0;
146
147typedef struct _alarmEntry {
148  XjCallbackProc wakeup;
149  caddr_t data;
150  struct timeval when;
151  struct _alarmEntry *next;
152  int id;
153} alarmEntry;
154
155alarmEntry *alarmList = NULL;
156alarmEntry *freeAlarms = NULL;
157
158void XjLoadFromResources();
159
160void XjExit(exitcode)
161     int exitcode;
162{
163  /*  need to throw in some cleanup code here...  */
164  exit(exitcode);
165}
166
167void XjFatalError(message)
168     char *message;
169{
170  fprintf(stderr, "%s: %s\n", programName, message);
171  XjExit(-1);
172}
173
174void XjWarning(string)
175     char *string;
176{
177  fprintf(stderr, "%s: %s\n", programName, string);
178}
179
180void XjUsage(s)
181     char *s;
182{
183/*
184  struct rusage u;
185
186  getrusage(RUSAGE_SELF, &u);
187
188  fprintf(stdout, "usage: %d %d %d\n",
189          u.ru_ixrss, u.ru_idrss, u.ru_isrss);
190*/
191
192  fprintf(stdout, "usage (%s): %d\n", s, sbrk(0));
193}
194
195char *XjMalloc(size)
196    unsigned size;
197{
198  char *ptr;
199
200#ifdef MEM
201  accounting = 0;
202#endif
203
204  if ((ptr = (char *)malloc(size)) == NULL)
205    {
206      char errtext[100];
207
208      sprintf(errtext, "couldn't malloc %d bytes", size);
209      XjFatalError(errtext);
210    }
211
212#ifdef MEM
213  accounting = 1;
214  malloced += size;
215
216  brake = sbrk(0);
217  if (brake != lastbreak)
218    {
219      fprintf(stdout, "(%d\t%d)\t(%d\t%d)\n",
220              malloced - lastmallocs, brake - lastbreak,
221              malloced, brake);
222      lastmallocs = malloced;
223      lastbreak = brake;
224    }
225#endif
226
227  return(ptr);
228}
229
230char *XjRealloc(ptr, size)
231     char *ptr;
232     unsigned size;
233{
234  if ((ptr = (char *)realloc(ptr, size)) == NULL)
235    XjFatalError("couldn't realloc");
236  /*    fprintf(stderr, "adt: malloc %d\n", size); */
237
238  return(ptr);
239}
240
241void
242XjFree(ptr)
243     char *ptr;
244{
245#ifdef MEM
246  accounting = 0;
247#endif
248  if (ptr != NULL)
249    free(ptr);
250
251#ifdef MEM
252  accounting = 1;
253#endif
254}
255
256/*
257static void printQueue()
258{
259  int count = 0;
260  alarmEntry *ptr;
261
262  for (ptr = alarmList; ptr != NULL; ptr = ptr->next)
263    fprintf(stdout, "%d. %d %d\n", count++,
264            ptr->when.tv_sec, ptr->when.tv_usec);
265}
266*/
267
268static void flushAlarmQueue()
269{
270  int first = 1;
271  struct timeval now;
272  alarmEntry *tmp;
273
274  gettimeofday(&now, NULL);
275
276  /*
277   * Hello? Mr. Jones? You requested a wake-up call.
278   */
279  while ((first && alarmList != NULL) ||
280         (alarmList != NULL &&
281          (now.tv_sec > alarmList->when.tv_sec ||
282           (now.tv_sec == alarmList->when.tv_sec &&
283            now.tv_usec > alarmList->when.tv_usec))))
284    {
285      first = 0;
286
287      /*
288       * The wakeup call may add another time into the queue,
289       * but that's ok because the time must be in the future
290       * (interval is unsigned), and the queue is consistent.
291       */
292      alarmList->wakeup(alarmList->data, alarmList->id);
293
294      tmp = alarmList;
295      alarmList = alarmList->next;
296
297      tmp->next = freeAlarms;
298      freeAlarms = tmp;
299    }
300
301/*  fprintf(stdout, "%d %d\n%d %d\n",
302          alarmList->when.tv_sec, alarmList->when.tv_usec,
303          now.tv_sec, now.tv_usec); */
304}
305
306unsigned long XjRemoveWakeup(id)
307     int id;
308{
309  struct timeval now;
310  alarmEntry *ptr, **last;
311  unsigned long timeleft;
312
313  gettimeofday(&now, NULL);
314
315  last = &alarmList;
316  ptr = alarmList;
317
318  while (ptr != NULL && ptr->id != id)
319    {
320      last = &(ptr->next);
321      ptr = ptr->next;
322    }
323
324  if (ptr == NULL)
325    return 0;
326
327  /*
328   * Work out how much longer we were
329   * supposed to wait
330   */
331  ptr->when.tv_sec -= now.tv_sec;
332  ptr->when.tv_usec -= now.tv_usec;
333
334  if (ptr->when.tv_usec < 0)
335    {
336      ptr->when.tv_usec += 1000000;
337      ptr->when.tv_sec -= 1;
338    }
339
340  timeleft = (ptr->when.tv_sec * 1000) + (ptr->when.tv_usec / 1000);
341
342  *last = ptr->next;
343  ptr->next = freeAlarms;
344  freeAlarms = ptr;
345
346  return timeleft;
347}
348
349int XjAddWakeup(who, data, interval)
350     XjCallbackProc who;
351     caddr_t data;
352     unsigned long interval; /* milliseconds */
353{
354  int i;
355  struct timeval now;
356  alarmEntry *ptr, **lastPtr, *next;
357
358  gettimeofday(&now, NULL);
359
360  /*
361   * Get freeAlarms pointing to something useful.
362   */
363  if (freeAlarms == NULL)
364    {
365      freeAlarms = (alarmEntry *)XjMalloc((unsigned) sizeof(alarmEntry) * 10);
366      for (i = 0; i < 9; i++)
367        freeAlarms[i].next = &freeAlarms[i + 1];
368      freeAlarms[9].next = NULL;
369    }
370
371  /*
372   * Fill in the structure; compute the wakeup time.
373   */
374  next = freeAlarms;
375  freeAlarms = freeAlarms->next;
376
377  next->wakeup = who;
378  next->data = data;
379  next->id = curID;
380  next->when.tv_sec = interval / 1000;
381  next->when.tv_usec = (interval % 1000) * 1000;
382
383  next->when.tv_sec += now.tv_sec;
384  next->when.tv_usec += now.tv_usec;
385  if (next->when.tv_usec >= 1000000)
386    {
387      next->when.tv_usec -= 1000000;
388      next->when.tv_sec += 1;
389    }
390
391  /*
392   * Insert the entry into the list and take it out of the free list.
393   */
394  lastPtr = &alarmList;
395  ptr = alarmList;
396
397  while (ptr != NULL &&
398         (next->when.tv_sec > ptr->when.tv_sec ||
399          (next->when.tv_sec == ptr->when.tv_sec &&
400           next->when.tv_usec > ptr->when.tv_usec)))
401    {
402      lastPtr = &ptr->next;
403      ptr = ptr->next;
404    }
405
406  next->next = ptr;
407  *lastPtr = next;
408  return curID++;
409}
410
411void XjCallCallbacks(info, callback, data)
412     caddr_t info;
413     XjCallback *callback;
414     caddr_t data;
415{
416  int exit = 0;
417
418  for (; callback != NULL && exit == 0; callback = callback->next)
419    switch(callback->argType)
420      {
421      case argInt:
422        exit = callback->proc(info, callback->passInt, data);
423        break;
424      case argString:
425        exit = callback->proc(info, callback->passString, data);
426        break;
427      case argPtr:
428        exit = callback->proc(info, callback->passPtr, data);
429        break;
430      }
431}
432
433void XjQuerySize(jet, size)
434     Jet jet;
435     XjSize *size;
436{
437  if (jet->core.classRec->core_class.querySize != NULL)
438    jet->core.classRec->core_class.querySize(jet, size);
439  else
440    {
441      size->width = -1;
442      size->height = -1;
443    }
444}
445
446void XjMove(jet, x, y)
447     Jet jet;
448     int x, y;
449{
450  if (jet->core.classRec->core_class.move != NULL)
451    if (jet->core.x != x || jet->core.y != y)
452      jet->core.classRec->core_class.move(jet, x, y);
453}
454
455void XjResize(jet, size)
456     Jet jet;
457     XjSize *size;
458{
459  if (jet->core.classRec->core_class.resize != NULL)
460    if (jet->core.width != size->width || jet->core.height != size->height)
461      jet->core.classRec->core_class.resize(jet, size);
462}
463
464void XjExpose(jet, event)
465     Jet jet;
466     XEvent *event;
467{
468  if (jet->core.classRec->core_class.expose != NULL)
469    jet->core.classRec->core_class.expose(jet, event);
470}
471
472XjCallback *XjConvertStringToCallback(address)
473     char **address;
474{
475  char name[50];
476  int type = argInt;
477  char *ptr, *end, *strParam = NULL;
478  int intParam = 0, barfed = 0;
479  XjCallbackProc tmp;
480  XjCallback *ret;
481  char errtext[100];
482
483  if (*address == NULL)
484    return NULL;
485
486  ptr = *address;
487
488  while (isspace(*ptr)) ptr++;
489
490  end = strchr(ptr, '(');
491  if (end == NULL)
492    {
493      /* we don't advance the pointer in this case. */
494      sprintf(errtext, "missing '(' in callback string: %s", ptr);
495      XjWarning(errtext);
496      return NULL;
497    }
498
499  strncpy(name, ptr, end - ptr);
500  name[end - ptr] = '\0';
501
502  tmp = XjGetCallback(name);
503 
504  if (tmp == NULL)
505    {
506      sprintf(errtext, "unregistered callback: %s", name);
507      XjWarning(errtext);
508      barfed = 1;
509    }
510
511  ptr = end + 1;
512  while (isspace(*ptr))
513    ptr++;
514
515  if (isdigit(*ptr)  ||  *ptr == '-')
516    {
517      intParam = atoi(ptr);
518      type = argInt;
519    }
520  else if (*ptr != ')')
521    {
522      char delim = *ptr;
523      ptr++;
524      end = strchr(ptr, delim);
525      if (end == NULL)
526        {
527          sprintf(errtext, "missing close quote in callback string: %s",
528                  *address);
529          XjWarning(errtext);
530          barfed = 1;
531        }
532      else
533        {
534          strParam = XjMalloc((unsigned) (end - ptr + 1));
535          strncpy(strParam, ptr, end - ptr);
536          strParam[end - ptr] = '\0';
537          ptr = end + 1;
538          type = argString;
539        }
540    }
541
542  end = strchr(ptr, ')');
543  if (end == NULL || barfed)
544    {
545      if (!barfed)
546        {
547          sprintf(errtext, "missing close parenthesis in callback string: %s",
548                  *address);
549          XjWarning(errtext);
550        }
551
552      /* bugs in here - if first callback unknown, rest oddly punted */
553
554      if (end != NULL)
555        ptr = end + 1;
556
557      if (type == argString)
558        XjFree(strParam);
559      *address = ptr;
560      return NULL;
561    }
562
563  ptr = end + 1;
564
565  ret = (XjCallback *) XjMalloc((unsigned) sizeof(XjCallback));
566  ret->argType = type;
567  ret->proc = tmp;
568  if (type == argInt)
569    ret->passInt = intParam;
570  else
571    ret->passString = strParam;
572
573  while (isspace(*ptr)) ptr++;
574  if (*ptr == ',')
575    {
576      ptr++;
577      ret->next = XjConvertStringToCallback(&ptr);
578    }
579  else
580    ret->next = NULL;
581
582  *address = ptr;
583  return ret;
584}
585
586
587XjCallbackRec cvt_callbacks[] =
588{
589  { XjRFontStruct, StrToXFontStruct },
590  { XjRColor, StrToXColor },
591  { XjRJustify, StrToJustify },
592  { XjROrientation, StrToOrientation },
593  { XjRDirection, StrToDirection },
594  { XjRBoolean, StrToBoolean },
595  { XjRPixmap, StrToPixmap },
596};
597
598
599void XjFillInValue(display, window, where, resource, type, address)
600     Display *display;
601     Window window;
602     caddr_t where;
603     XjResource *resource;
604     char *type;
605     caddr_t address;
606{
607  /*
608   * Nonconversion
609   */
610  if (!strcmp(type, resource->resource_type))
611    {
612      memcpy(where + resource->resource_offset,
613            &address,
614            (resource->resource_size > sizeof(caddr_t)) ? sizeof(caddr_t) :
615             resource->resource_size);
616      return;
617    }
618
619  if (!strcmp(type, XjRString))
620    {
621      static int init = 1;
622      XjCallbackProc tmp;
623
624      if (init)
625        {
626          XjRegisterCallbacks(cvt_callbacks, XjNumber(cvt_callbacks));
627          init = 0;
628        }
629
630      /*
631       * string to integer conversion
632       */
633      if (!strcmp(resource->resource_type, XjRInt))
634        {
635          *((int *)((char *)where + resource->resource_offset))
636            = atoi(address);
637          return;
638        }
639
640      /*
641       * string to string conversion :)
642       */
643      if (!strcmp(resource->resource_type, XjRString))
644        {
645/*      *(char **)((char *)where + resource->resource_offset) =
646        (address == NULL) ? NULL : XjNewString(address); */
647          *(char **)((char *)where + resource->resource_offset) = address;
648          return;
649        }
650
651      /*
652       * String to Callback conversion
653       */
654      if (!strcmp(resource->resource_type, XjRCallback))
655        {
656          *((XjCallback **)((char *)where + resource->resource_offset)) =
657            XjConvertStringToCallback(&address);
658          return;
659        }
660
661      if ((tmp = XjGetCallback(resource->resource_type)) != NULL)
662        {
663          tmp(display, window, where, resource, type, address);
664          return;
665        }
666    }
667
668  {
669    char errtext[100];
670    sprintf(errtext, "unknown conversion: %s to %s",
671            type, resource->resource_type);
672    XjWarning(errtext);
673  }
674}
675
676void XjSelectInput(display, window, mask)
677Display *display;
678Window window;
679long mask;
680{
681  long previous;
682
683  if (!gotSelectContextType)
684    {
685      selectContext = XUniqueContext();
686      gotSelectContextType = 1;
687    }
688
689  if (XCNOENT != XFindContext(display, window,
690                              selectContext, (caddr_t *)&previous))
691    {
692      XDeleteContext(display, window, selectContext);
693      mask |= previous;
694    }
695
696  if (XCNOMEM == XSaveContext(display, window, selectContext, (caddr_t)mask))
697    {
698      XjFatalError("out of memory in XSaveContext");
699      XjExit(-1);
700    }
701
702  XSelectInput(display, window, mask);
703}
704
705void XjRegisterWindow(window, jet)
706Window window;
707Jet jet;
708{
709  if (!gotRegisterContextType)
710    {
711      registerContext = XUniqueContext();
712      gotRegisterContextType = 1;
713    }
714
715#ifdef DEBUG
716  if (XCNOENT != XFindContext(jet->core.display, window,
717                              registerContext, (caddr_t *)&eventJet))
718    fprintf(stdout, "%s usurped window from %s\n",
719            jet->core.name, eventJet->core.name);
720#endif
721
722  if (XCNOMEM == XSaveContext(jet->core.display, window,
723                              registerContext, (caddr_t) jet))
724    {
725      XjFatalError("out of memory in XSaveContext");
726      XjExit(-1);
727    }
728}
729
730void XjUnregisterWindow(window, jet)
731Window window;
732Jet jet;
733{
734  (void)XDeleteContext(jet->core.display, window, registerContext);
735  (void)XDeleteContext(jet->core.display, window, selectContext);
736}
737
738Jet XjCreateRoot(argc, argv, appClass, userFile, appTable, appTableCount)
739int *argc;
740char **argv;
741char *appClass;
742char *userFile;
743XrmOptionDescList appTable;
744int appTableCount;
745{
746  Display *display;
747  Jet jet;
748  char *display_resources;
749  char *xenvironment;
750  XrmDatabase ad_rdb = NULL, disp_rdb = NULL, user_rdb = NULL, cl_rdb = NULL;
751  int i, screen;
752  char errtext[100];
753
754  /*
755   * We need to keep our own copy of (argc, argv) around...
756   * XrmParseCommand is going to munge the original.
757   */
758  global_argc = *argc;
759  global_argv = (char **)XjMalloc((unsigned) (sizeof(char *) * (*argc + 1)));
760  for (i = 0; i < *argc; i++)
761    global_argv[i] = argv[i];
762
763  /*
764   * We have to parse "-name" ourselves. Sigh. This should be
765   * mentioned in XrmParseCommand documentation. It isn't.
766   */
767  for (i = 1; i < *argc; i++)
768    if (!strcmp("-name", argv[i]))
769      {
770        if (i + 1 < *argc)
771          programName = argv[i + 1];
772        break;
773      }
774
775  if (programName == NULL)
776    {
777      programName = strrchr (argv[0], '/');
778      if (programName)
779        programName++;
780      else
781        programName = argv[0];
782    }
783
784  programClass = XjNewString(appClass);
785
786  XrmInitialize();
787
788  /*
789   * Ok. There are four database sources here. In reverse priority:
790   *
791   *    1. application defaults (can be overriden by user)
792   *    2. user's display resources
793   *    3. user's home directory dotfile
794   *    4. user's command line options
795   */
796
797  /*
798   * Load command-line options into cl_rdb
799   */
800  cl_rdb = XrmGetStringDatabase("");
801/*  XrmParseCommand(&cl_rdb, opTable, XjNumber(opTable), programName,
802                  argc, argv); */
803  XrmParseCommand(&cl_rdb, appTable, appTableCount, programName,
804                  argc, argv);
805
806  /*
807   * Get the -display option out of it, if specified, and open the
808   * display. Might as well do this first, since if it fails everything
809   * else we did was wasting time.
810   */
811
812  rdb = cl_rdb;
813  XjLoadFromResources(NULL, /* this is what we're tring to find out! */
814                      NULL,
815                      programName,
816                      programClass,
817                      startupResources,
818                      XjNumber(startupResources),
819                      (caddr_t) &startup);
820
821  if (startup.name != NULL)
822    programName = startup.name;
823
824  displayName = startup.display;
825
826  /*
827  sprintf(dispRes, "%s.display", programName);
828  sprintf(dispResClass, "%s.Display", programClass);
829
830  if (XrmGetResource(cl_rdb, dispRes, dispResClass, &type, &value))
831    displayName = (char *)(value.addr);
832  */
833
834  if ((display = XOpenDisplay(displayName)) == NULL)
835    {
836      sprintf(errtext, "could not open display %s",
837               (displayName == NULL) ? "(null)" : displayName);
838      XjFatalError(errtext);
839      XjExit(-1);
840    }
841
842  /*
843   * Load display resources into disp_rdb
844   */
845  display_resources = XResourceManagerString(display);
846  if (display_resources != NULL)
847    disp_rdb = XrmGetStringDatabase(display_resources);
848
849  /*
850   * Load application defaults into ad_rdb
851   */
852  xenvironment = startup.appDefs;
853  if (xenvironment != NULL)
854    {
855      ad_rdb = XrmGetFileDatabase(xenvironment);
856      if (ad_rdb == NULL)
857        {
858          sprintf(errtext, "couldn't load %s; trying default", xenvironment);
859          XjWarning(errtext);
860        }
861    }
862
863  if (ad_rdb == NULL) /* fallback */
864    {
865      char *appdefs;
866
867      appdefs = (char *) XjMalloc(strlen(appdefdir) +
868                                  strlen(programClass) + 2);
869      sprintf(appdefs, "%s/%s", appdefdir, programClass);
870      ad_rdb = XrmGetFileDatabase(appdefs);
871      XjFree(appdefs);
872
873      xenvironment = (char *)getenv("XENVIRONMENT");
874      if (xenvironment != NULL)
875        {
876          XrmDatabase env_rdb = NULL;
877
878          env_rdb = XrmGetFileDatabase(xenvironment);
879          if (env_rdb == NULL)
880            {
881              sprintf(errtext, "couldn't load %s", xenvironment);
882              XjWarning(errtext);
883            }
884          else
885            {
886              if (ad_rdb == NULL)
887                ad_rdb = env_rdb;
888              else
889                XrmMergeDatabases(env_rdb, &ad_rdb);
890            }
891        }
892    }
893
894  /*
895   * Load user's defaults into user_rdb
896   */
897  if (startup.userDefs != NULL)
898    userFile = startup.userDefs;
899  if (userFile != NULL)
900    {
901      user_rdb = XrmGetFileDatabase(userFile);
902      if (user_rdb == NULL && startup.userDefs != NULL)
903        {
904          sprintf(errtext, "couldn't load %s", userFile);
905          XjWarning(errtext);
906        }
907    }
908
909  /*
910   * Ok! Now we merge them all together!
911   * rdb = ((((ad_rdb)disp_rdb)user_rdb)cl_rdb)
912   */
913  if (ad_rdb != NULL)
914    rdb = ad_rdb;
915  else
916    {
917      if (disp_rdb != NULL)
918        {
919          rdb = disp_rdb;
920          disp_rdb = NULL;
921        }
922      else
923        {
924          if (user_rdb != NULL)
925            {
926              rdb = user_rdb;
927              user_rdb = NULL;
928            }
929          else
930            if (cl_rdb != NULL)
931              {
932                rdb = cl_rdb;
933                cl_rdb = NULL;
934              }
935        }
936    }
937
938  if (disp_rdb != NULL)
939    XrmMergeDatabases(disp_rdb, &rdb);
940  if (user_rdb != NULL)
941    XrmMergeDatabases(user_rdb, &rdb);
942  if (cl_rdb != NULL)
943    XrmMergeDatabases(cl_rdb, &rdb);
944
945  /*
946   * Create the root jet
947   */
948  screen = DefaultScreen(display);
949
950  jet = (Jet)XjMalloc((unsigned) sizeof(RootRec));
951
952  jet->core.classRec = rootJetClass;
953  jet->core.name = programName;
954  jet->core.display = display;
955  jet->core.window = RootWindow(display, screen);
956  jet->core.parent = NULL;
957  jet->core.sibling = NULL;
958  jet->core.child = NULL;
959
960  /* hmmm... */
961  jet->core.classRec->core_class.className = programClass;
962
963  return jet;
964}
965
966#ifndef MAXSELFD
967#define MAXSELFD 64
968#endif
969
970XjCallbackProc read_inputs[MAXSELFD];
971char *read_args[MAXSELFD];
972
973void XjReadCallback(where, fd, arg)
974     XjCallbackProc where;
975     int fd;
976     char *arg;
977{
978    read_inputs[fd] = where;
979    read_args[fd] = arg;
980}
981
982/*
983 * Hacking this in right now because I don't have
984 * the time right now to code up a general version.
985 */
986XjCallbackProc stdinavail = NULL;
987
988void XjStdinCallback(where)
989     XjCallbackProc where;
990{
991    XjReadCallback(where, 0, 0);
992}
993
994void XjRegisterEventHandler(where)
995     XjEventProc where;
996{
997  eventHandler = where;
998}
999
1000static int waitForSomething(jet)
1001     Jet jet;
1002{
1003  struct timeval now;
1004  struct timeval diff;
1005  static fd_set read, empty;
1006  static int inited = 0;
1007  int loop, nfds = 0;
1008  register int i;
1009  int n;
1010  int bytes = 0;
1011  char errtext[100];
1012
1013  if (!inited)
1014    {
1015      inited = 1;
1016      FD_ZERO(&empty);
1017      FD_ZERO(&read);
1018    }
1019
1020  while (XPending(jet->core.display) == 0)
1021    {
1022      /*
1023       * If bytes is nonzero, the last journey through the loop
1024       * reported activity on some socket. At this point, XPending
1025       * has said that there are no events. It doesn't check if
1026       * the connection was terminated. If the connection has been
1027       * terminated, the socket will be selected for read with no
1028       * data available on it. So we check if the X socket was one
1029       * of the ones selected. If so, and there is no data available
1030       * for reading (the ioctl) on it, it has probably been
1031       * terminated. So we call XNoOp, with the expectation that an
1032       * XIO error will be generated.
1033       */
1034      if (bytes &&
1035          FD_ISSET(ConnectionNumber(jet->core.display), &read))
1036        { /* no errors should be possible in ioctl */
1037          (void)ioctl(ConnectionNumber(jet->core.display),
1038                      FIONREAD,
1039                      &bytes);
1040          if (bytes == 0)
1041            {
1042              XNoOp(jet->core.display); /* should cause XIO */
1043              XSync(jet->core.display, False); /* Yes, I really want this */
1044            }
1045          bytes = 0;
1046        }
1047
1048      loop = 1;
1049      while (alarmList != NULL && loop)
1050        {
1051          gettimeofday(&now, NULL);
1052
1053          diff.tv_sec = alarmList->when.tv_sec - now.tv_sec;
1054          if (alarmList->when.tv_usec < now.tv_usec)
1055            {
1056              diff.tv_sec -= 1;
1057              diff.tv_usec = (1000000 + alarmList->when.tv_usec) - now.tv_usec;
1058            }
1059          else
1060            diff.tv_usec = alarmList->when.tv_usec - now.tv_usec;
1061
1062          if (diff.tv_sec >=0 && diff.tv_usec >=0)
1063            loop = 0;
1064          else
1065            {
1066              flushAlarmQueue();
1067              XFlush(jet->core.display);
1068            }
1069        }
1070
1071      FD_SET(ConnectionNumber(jet->core.display), &read);
1072
1073      nfds = 0;                         /* RESET nfds to zero... */
1074      for (i = 0; i < MAXSELFD; i++)
1075          if (read_inputs[i]) {
1076              FD_SET(i, &read);
1077              nfds = i;
1078          }
1079      if (ConnectionNumber(jet->core.display) > nfds)
1080          nfds = ConnectionNumber(jet->core.display);
1081
1082      nfds++;                           /* indexed based on 1, not 0 */
1083
1084#ifdef notdefined
1085      if (checkSignals != NULL)
1086        checkSignals();         /* this could cause a late wakeup... */
1087#endif
1088
1089      if (checkSignals != NULL  &&  checkSignals())
1090        continue;               /* this could cause a late wakeup... */
1091
1092
1093      if (DEBUG)
1094        {
1095          printf("%d.%3.3d ", diff.tv_sec, diff.tv_usec);
1096          fflush(stdout);
1097        }
1098
1099      if (XPending(jet->core.display))
1100        break;
1101
1102      n = select(nfds, &read, &empty, &empty,
1103                 (alarmList == NULL) ? 0 : &diff);
1104      switch(n)
1105        {
1106        case -1: /* some kind of error */
1107          if (DEBUG)
1108            printf("\nSELECT ERROR= -1\n");
1109          if (errno == EINTR)
1110            break; /* interrupt callback will be called before select */
1111          sprintf(errtext, "%s %d\n\t%s %d\t%s %d\t%s %d\n",
1112                  "unexpected error from select:", errno,
1113                  "timeval.tv_sec =", diff.tv_sec,
1114                  "timeval.tv_usec =", diff.tv_usec,
1115                  "nfds =", nfds);
1116          XjFatalError(errtext);
1117          bytes = 0;
1118          break;
1119
1120        case 0: /* timed out */
1121          if (DEBUG)
1122            {
1123              printf("| ");
1124              fflush(stdout);
1125            }
1126          flushAlarmQueue();
1127          XFlush(jet->core.display);
1128          bytes = 0;
1129          break;
1130
1131        default: /* something must now be pending */
1132          if (DEBUG)
1133            printf("\nn=%d ", n);
1134          for (i = 0; i < MAXSELFD; i++)
1135              if (read_inputs[i] != NULL &&
1136                  FD_ISSET(i, &read))
1137              {
1138                if (DEBUG)
1139                  printf("i=%d", i);
1140                  (*read_inputs[i])(i, read_args[i]);
1141                  FD_CLR(i, &read);
1142              }
1143          if (DEBUG)
1144            {
1145              if (FD_ISSET(ConnectionNumber(jet->core.display), &read))
1146                printf("X active");
1147              printf("\n");
1148            }
1149          bytes = 1;
1150          break;
1151        }
1152    }
1153  return 1;                     /* currently never happens */
1154}
1155
1156void XjSetSignalChecker(proc)
1157     XjCallbackProc proc;
1158{
1159  checkSignals = proc;
1160}
1161
1162void XjEventLoop(jet)
1163     Jet jet;
1164{
1165  XEvent event;
1166  Boolean taken;
1167  Jet eventJet;
1168
1169  while (1)
1170    {
1171      if (waitForSomething(jet) == 0)
1172        return; /* a signal arrived */
1173
1174      XNextEvent(jet->core.display, &event);
1175
1176      if (XCNOENT != XFindContext(jet->core.display, event.xany.window,
1177                                  registerContext, (caddr_t *)&eventJet))
1178        {
1179          /*
1180           * If an event is not taken by its registered owner,
1181           * pass it on to the parent if the window id matches
1182           * the window id of the parent. Note that the registered
1183           * owner will get the event whether the window id matches
1184           * its own or not. The menu code depends on this.
1185           */
1186          if (eventJet->core.classRec->core_class.event != NULL)
1187            { /* Really _should_ be non-NULL. Just check; not sure why */
1188              taken = False;
1189              do
1190                {
1191                  if (eventJet->core.classRec->core_class.event != NULL)
1192                    taken =
1193                      eventJet->core.classRec->
1194                        core_class.event(eventJet, &event);
1195                  if (!taken)
1196                    eventJet = XjParent(eventJet);
1197                }
1198              while (eventJet &&
1199                     (eventJet->core.window == event.xany.window)
1200                     && !taken);
1201
1202              if (!taken)
1203                {
1204                  switch(event.type)
1205                    {
1206                    case MappingNotify:
1207                      XRefreshKeyboardMapping(&(event.xmapping));
1208                      break;
1209                    default:
1210                      if (eventHandler)
1211                        taken = eventHandler(&event);
1212                      break;
1213                    }
1214                }
1215            }
1216        }
1217#ifdef DEBUG
1218      else
1219        fprintf(stderr, "Event on unclaimed window\n");
1220#endif
1221    }
1222}
1223
1224void preRealizeJet(jet)
1225     Jet jet;
1226{
1227  Jet thisJet;
1228
1229  thisJet = jet;
1230
1231  while (thisJet != NULL)
1232    {
1233      while (thisJet->core.child != NULL)
1234        thisJet = thisJet->core.child;
1235
1236      if (thisJet->core.classRec->core_class.preRealize != NULL)
1237        thisJet->core.classRec->core_class.preRealize(thisJet);
1238
1239      while (thisJet != jet && thisJet->core.sibling == NULL)
1240        {
1241          thisJet = XjParent(thisJet);
1242          if (thisJet->core.classRec->core_class.preRealize != NULL)
1243            thisJet->core.classRec->core_class.preRealize(thisJet);
1244        }
1245
1246      if (thisJet != jet /* && thisJet->core.sibling != NULL */)
1247        thisJet = thisJet->core.sibling;
1248      else
1249        thisJet = NULL; /* a hack. :( */
1250    }     
1251}
1252
1253/*
1254 * Of course, this would make a lot more sense if it were recursive,
1255 * but didn't your parents tell you not to curse over and over again?
1256 * Besides, this is a family tree.
1257 */
1258void XjRealizeJet(jet)
1259     Jet jet;
1260{
1261  Jet thisJet;
1262  Jet parentJet, siblingJet;
1263
1264  preRealizeJet(jet);
1265
1266  parentJet = XjParent(jet);    /* cut off from ancestors temporarily */
1267  siblingJet = jet->core.sibling;
1268  XjParent(jet) = NULL;
1269  jet->core.sibling = NULL;
1270
1271  thisJet = jet;
1272  while (thisJet != NULL)
1273    {
1274      /* may get its own window when we realize it */
1275      if (XjParent(thisJet) != NULL)
1276        thisJet->core.window = (XjParent(thisJet))->core.window;
1277
1278      /* first realize the jet we're at */
1279      if (thisJet->core.classRec->core_class.realize != NULL)
1280        thisJet->core.classRec->core_class.realize(thisJet);
1281
1282      /* now locate the next jet... */
1283      /* if this jet has a child, it's next. */
1284      if (thisJet->core.child != NULL)
1285        thisJet = thisJet->core.child;
1286      else
1287        /* no children; siblings next. */
1288        if (thisJet->core.sibling != NULL)
1289          thisJet = thisJet->core.sibling;
1290        else
1291          /* no siblings; aunts & uncles & relatives of grandparents next. */
1292          while ((thisJet = XjParent(thisJet)) != NULL)
1293            if (thisJet->core.sibling != NULL)
1294              {
1295                thisJet = thisJet->core.sibling;
1296                break;
1297              }
1298    }
1299
1300  XjParent(jet) = parentJet;    /* unbastardize. or is that debastardize? */
1301  jet->core.sibling = siblingJet;
1302}
1303
1304#define MAX_NAME_LEN 500
1305static char resClass[MAX_NAME_LEN], resInstance[MAX_NAME_LEN];
1306
1307Jet XjFindJet(name, parent)
1308char *name;
1309Jet parent;
1310{
1311  Jet search;
1312
1313  for (search = parent->core.child;
1314       search != NULL;
1315       search = search->core.sibling)
1316    if (strcmp(name, search->core.name) == 0)
1317      return search;
1318
1319  return NULL;
1320}
1321
1322void XjLoadFromResources(display, window, classPtr, instPtr,
1323                         resources, num_resources, destination)
1324Display *display;
1325Window window;
1326char *classPtr, *instPtr;
1327XjResource resources[];
1328int num_resources;
1329caddr_t destination;
1330{
1331  char *type;
1332  XrmValue value;
1333  int resCount;
1334
1335  for (resCount = 0; resCount < num_resources; resCount++)
1336    {
1337      sprintf(resClass, "%s.%s", classPtr,
1338              resources[resCount].resource_class);
1339
1340      sprintf(resInstance, "%s.%s", instPtr,
1341              resources[resCount].resource_name);
1342
1343      if (XrmGetResource(rdb, resInstance, resClass, &type, &value))
1344        XjFillInValue(display,          /* found it, so load it... */
1345                      window,
1346                      destination,
1347                      &resources[resCount],
1348                      XjRString, value.addr);
1349      else
1350        XjFillInValue(display,          /* didn't find it, load default... */
1351                      window,
1352                      destination,
1353                      &resources[resCount],
1354                      resources[resCount].default_type,
1355                      resources[resCount].default_addr);
1356    }
1357}
1358
1359
1360static void GetVal(src, dst, size)
1361     char *src;
1362     caddr_t *dst;
1363     int size;
1364{
1365  memcpy(dst, src, size);
1366}
1367
1368
1369void XjVaGetValues(Jet jet, char *valName, ...)
1370{
1371  va_list args;
1372  int resCount;
1373  caddr_t val;
1374
1375  va_start(args, valName);
1376
1377  while (NULL != valName)
1378    {
1379      val = va_arg(args, caddr_t);
1380
1381      for (resCount = 0;
1382           resCount < jet->core.classRec->core_class.num_resources;
1383           resCount++)
1384        {
1385          XjResource resource;
1386          resource = jet->core.classRec->core_class.resources[resCount];
1387
1388          if (!strcmp(valName, resource.resource_name))
1389            {
1390              GetVal(((caddr_t)jet) + resource.resource_offset, &val,
1391                     (resource.resource_size > sizeof(caddr_t))
1392                     ? sizeof(caddr_t) : resource.resource_size);
1393              break;
1394            }
1395        }
1396      valName = va_arg(args, char *);
1397    }
1398  val = va_arg(args, caddr_t); /* pop the last one */
1399  va_end(args);
1400}
1401
1402
1403/* this is gross. and there are memory leaks having to do with
1404   resource allocation that need to be plugged up. */
1405void XjDestroyJet(jet)
1406     Jet jet;
1407{
1408  Jet thisJet;
1409  Jet parent, sibling;
1410
1411  /* remove jet from tree */
1412  if ((XjParent(jet))->core.child == jet)
1413    (XjParent(jet))->core.child = jet->core.sibling;
1414  else
1415    {
1416      thisJet = (XjParent(jet))->core.child;
1417      while (thisJet->core.sibling != jet)
1418        thisJet = thisJet->core.sibling;
1419      thisJet->core.sibling = jet->core.sibling;
1420    }
1421
1422  thisJet = jet;
1423
1424  while (thisJet != NULL)
1425    {
1426      while (thisJet->core.child != NULL)
1427        thisJet = thisJet->core.child;
1428
1429      parent = XjParent(thisJet);
1430      sibling = thisJet->core.sibling;
1431      if (thisJet->core.classRec->core_class.destroy != NULL)
1432        thisJet->core.classRec->core_class.destroy(thisJet);
1433      XjFree(thisJet->core.name);
1434      XjFree((char *)thisJet);
1435
1436      while (thisJet != jet && sibling == NULL)
1437        {
1438          thisJet = parent;
1439
1440          parent = XjParent(thisJet);
1441          sibling = thisJet->core.sibling;
1442          if (thisJet->core.classRec->core_class.destroy != NULL)
1443            thisJet->core.classRec->core_class.destroy(thisJet);
1444          XjFree(thisJet->core.name);
1445          XjFree((char *)thisJet);
1446        }
1447
1448      if (thisJet != jet /* && sibling != NULL */)
1449        thisJet = sibling;
1450      else
1451        thisJet = NULL; /* a hack. :( */
1452    }     
1453}
Note: See TracBrowser for help on using the repository browser.