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)) |
---|
12 | static 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 | |
---|
33 | extern int StrToXFontStruct(); |
---|
34 | extern int StrToXColor(); |
---|
35 | extern int StrToPixmap(); |
---|
36 | extern int StrToDirection(); |
---|
37 | extern int StrToOrientation(); |
---|
38 | extern int StrToBoolean(); |
---|
39 | extern int StrToJustify(); |
---|
40 | |
---|
41 | int DEBUG = 0; |
---|
42 | |
---|
43 | static XjCallbackProc checkSignals = NULL; |
---|
44 | static XjEventProc eventHandler = NULL; |
---|
45 | |
---|
46 | int global_argc; |
---|
47 | char **global_argv; |
---|
48 | XrmDatabase rdb = NULL; |
---|
49 | |
---|
50 | char *displayName; |
---|
51 | char *programName = NULL; |
---|
52 | char *programClass; |
---|
53 | |
---|
54 | int malloced = 0; |
---|
55 | int lastmallocs = 0; |
---|
56 | int lastbreak = 0; |
---|
57 | int accounting = 1; |
---|
58 | |
---|
59 | static int gotRegisterContextType = 0; |
---|
60 | static XContext registerContext; |
---|
61 | static int gotSelectContextType = 0; |
---|
62 | static XContext selectContext; |
---|
63 | |
---|
64 | #ifndef APPDEFDIR |
---|
65 | #define APPDEFDIR "/usr/lib/X11/app-defaults" |
---|
66 | #endif |
---|
67 | static char *appdefdir = APPDEFDIR; |
---|
68 | |
---|
69 | /* |
---|
70 | static 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 | |
---|
98 | typedef 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 | |
---|
105 | typedef struct _JetResources *JetResourcesPtr; |
---|
106 | |
---|
107 | JetResources startup; |
---|
108 | |
---|
109 | #define offset(field) XjOffset(JetResourcesPtr,field) |
---|
110 | |
---|
111 | static 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 | |
---|
124 | RootClassRec 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 | |
---|
144 | JetClass rootJetClass = (JetClass)&rootClassRec; |
---|
145 | int curID = 0; |
---|
146 | |
---|
147 | typedef struct _alarmEntry { |
---|
148 | XjCallbackProc wakeup; |
---|
149 | caddr_t data; |
---|
150 | struct timeval when; |
---|
151 | struct _alarmEntry *next; |
---|
152 | int id; |
---|
153 | } alarmEntry; |
---|
154 | |
---|
155 | alarmEntry *alarmList = NULL; |
---|
156 | alarmEntry *freeAlarms = NULL; |
---|
157 | |
---|
158 | void XjLoadFromResources(); |
---|
159 | |
---|
160 | void XjExit(exitcode) |
---|
161 | int exitcode; |
---|
162 | { |
---|
163 | /* need to throw in some cleanup code here... */ |
---|
164 | exit(exitcode); |
---|
165 | } |
---|
166 | |
---|
167 | void XjFatalError(message) |
---|
168 | char *message; |
---|
169 | { |
---|
170 | fprintf(stderr, "%s: %s\n", programName, message); |
---|
171 | XjExit(-1); |
---|
172 | } |
---|
173 | |
---|
174 | void XjWarning(string) |
---|
175 | char *string; |
---|
176 | { |
---|
177 | fprintf(stderr, "%s: %s\n", programName, string); |
---|
178 | } |
---|
179 | |
---|
180 | void 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 | |
---|
195 | char *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 | |
---|
230 | char *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 | |
---|
241 | void |
---|
242 | XjFree(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 | /* |
---|
257 | static 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 | |
---|
268 | static 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 | |
---|
306 | unsigned 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 | |
---|
349 | int 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 | |
---|
411 | void 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 | |
---|
433 | void 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 | |
---|
446 | void 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 | |
---|
455 | void 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 | |
---|
464 | void 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 | |
---|
472 | XjCallback *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 | |
---|
587 | XjCallbackRec 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 | |
---|
599 | void 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 | |
---|
676 | void XjSelectInput(display, window, mask) |
---|
677 | Display *display; |
---|
678 | Window window; |
---|
679 | long 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 | |
---|
705 | void XjRegisterWindow(window, jet) |
---|
706 | Window window; |
---|
707 | Jet 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 | |
---|
730 | void XjUnregisterWindow(window, jet) |
---|
731 | Window window; |
---|
732 | Jet jet; |
---|
733 | { |
---|
734 | (void)XDeleteContext(jet->core.display, window, registerContext); |
---|
735 | (void)XDeleteContext(jet->core.display, window, selectContext); |
---|
736 | } |
---|
737 | |
---|
738 | Jet XjCreateRoot(argc, argv, appClass, userFile, appTable, appTableCount) |
---|
739 | int *argc; |
---|
740 | char **argv; |
---|
741 | char *appClass; |
---|
742 | char *userFile; |
---|
743 | XrmOptionDescList appTable; |
---|
744 | int 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 | |
---|
970 | XjCallbackProc read_inputs[MAXSELFD]; |
---|
971 | char *read_args[MAXSELFD]; |
---|
972 | |
---|
973 | void 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 | */ |
---|
986 | XjCallbackProc stdinavail = NULL; |
---|
987 | |
---|
988 | void XjStdinCallback(where) |
---|
989 | XjCallbackProc where; |
---|
990 | { |
---|
991 | XjReadCallback(where, 0, 0); |
---|
992 | } |
---|
993 | |
---|
994 | void XjRegisterEventHandler(where) |
---|
995 | XjEventProc where; |
---|
996 | { |
---|
997 | eventHandler = where; |
---|
998 | } |
---|
999 | |
---|
1000 | static 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 | |
---|
1156 | void XjSetSignalChecker(proc) |
---|
1157 | XjCallbackProc proc; |
---|
1158 | { |
---|
1159 | checkSignals = proc; |
---|
1160 | } |
---|
1161 | |
---|
1162 | void 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 | |
---|
1224 | void 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 | */ |
---|
1258 | void 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 |
---|
1305 | static char resClass[MAX_NAME_LEN], resInstance[MAX_NAME_LEN]; |
---|
1306 | |
---|
1307 | Jet XjFindJet(name, parent) |
---|
1308 | char *name; |
---|
1309 | Jet 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 | |
---|
1322 | void XjLoadFromResources(display, window, classPtr, instPtr, |
---|
1323 | resources, num_resources, destination) |
---|
1324 | Display *display; |
---|
1325 | Window window; |
---|
1326 | char *classPtr, *instPtr; |
---|
1327 | XjResource resources[]; |
---|
1328 | int num_resources; |
---|
1329 | caddr_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 | |
---|
1360 | static void GetVal(src, dst, size) |
---|
1361 | char *src; |
---|
1362 | caddr_t *dst; |
---|
1363 | int size; |
---|
1364 | { |
---|
1365 | memcpy(dst, src, size); |
---|
1366 | } |
---|
1367 | |
---|
1368 | |
---|
1369 | void 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. */ |
---|
1405 | void 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 | } |
---|