1 /* This file contains the top level routines that manipulate whole
2 * windows and what not. It's the main initialization stuff, etc.
3 *
4 *
5 * This code is under the GNU Copyleft.
6 *
7 * Dominic Giampaolo
8 * dbg@sgi.com
9 */
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include "xstuff.h"
13 #include "libsx.h"
14 #include "libsx_private.h"
15
16
17 /*
18 * External prototypes.
19 */
20 extern void SetOkay(); /* from Dialog.c */
21 extern void PositionPopup(Widget w); /* from Dialog.c */
22 extern void libsx_done_with_text(Widget w, XEvent *xev, String *parms,
23 Cardinal *num_parms);/* from string_entry.c */
24
25
26 /* internal protos */
27 static Bool is_expose_event(Display *d, XEvent *xev, char *blorg);
28
29
30
31 /*
32 * Private static variables.
33 */
34 static WindowState *lsx_windows = NULL,
35 empty_window = { 0, 0, 0, NULL, NULL, NULL, NULL, 0,},
36 *orig_window = NULL,
37 *new_curwin = NULL;
38
39 static char *app_name="";
40 static Display *base_display=NULL;
41
42
43 /*
44 * Global Variables for all of libsx (but not for user applications).
45 *
46 * We initialize lsx_curwin to point to the static empty_window so that
47 * if other functions get called before OpenDisplay(), they won't core
48 * dump, and will fail gracefully instead.
49 */
50 WindowState *lsx_curwin = &empty_window;
51 XtAppContext lsx_app_con;
52
53
54
55
56 /*
57 * These are some internal actions and resources so that dialog boxes
58 * and string entry widgets work they way god intended them to work
59 * (i.e. pressing the return key in one gives the text you typed to
60 * the application).
61 */
62 static XtActionsRec actions_table[] =
63 {
64 { "set-okay", SetOkay },
65 { "done_with_text", libsx_done_with_text }
66 };
67
68
69 static String fallback_resources[] =
70 {
71 "*Dialog*label.resizable: True",
72 "*Dialog*Text.resizable: True",
73 "*Dialog.Text.translations: #override <Key>Return: set-okay()\\n\
74 <Key>Linefeed: set-okay()",
75 NULL
76 };
77
78
79
80 /*
81 *
82 * This is the function that gets everything started.
83 *
84 */
_OpenDisplay(int argc,char ** argv,Display * dpy,Arg * wargs,int arg_cnt)85 int _OpenDisplay(int argc, char **argv, Display *dpy, Arg *wargs, int arg_cnt)
86 {
87 static char *dummy_argv[] = { "Untitled", NULL };
88 static int dummy_argc = 1;
89 static int already_called = FALSE;
90
91 if (already_called) /* must have been called a second time */
92 return FALSE;
93 already_called = TRUE;
94
95 if (argv == NULL)
96 {
97 argv = dummy_argv;
98 argc = dummy_argc;
99 }
100
101
102 /*
103 * First create the window state.
104 */
105 lsx_curwin = (WindowState *)calloc(sizeof(WindowState), 1);
106 if (lsx_curwin == NULL)
107 return FALSE;
108
109 /* open the display stuff */
110 if (dpy == NULL)
111 lsx_curwin->toplevel = XtAppInitialize(&lsx_app_con, argv[0], NULL, 0,
112 &argc, argv, fallback_resources,
113 wargs, arg_cnt);
114 else
115 lsx_curwin->toplevel = XtAppCreateShell (argv[0], argv[0],
116 applicationShellWidgetClass,
117 dpy, wargs, arg_cnt);
118
119
120 if (lsx_curwin->toplevel == NULL)
121 {
122 free(lsx_curwin);
123 return FALSE;
124 }
125
126 app_name = argv[0]; /* save this for later */
127
128
129 XtAppAddActions(lsx_app_con, actions_table, XtNumber(actions_table));
130
131 lsx_curwin->form_widget = XtCreateManagedWidget("form", formWidgetClass,
132 lsx_curwin->toplevel,NULL,0);
133
134 if (lsx_curwin->form_widget == NULL)
135 {
136 XtDestroyWidget(lsx_curwin->toplevel);
137 free(lsx_curwin);
138 lsx_curwin = &empty_window;
139 return FALSE;
140 }
141 lsx_curwin->toplevel_form = lsx_curwin->form_widget;
142
143
144 lsx_curwin->next = lsx_windows; /* link it in to the list */
145 lsx_windows = lsx_curwin;
146
147 /* save these values for later */
148 lsx_curwin->display = (Display *)XtDisplay(lsx_curwin->toplevel);
149 lsx_curwin->screen = DefaultScreen(lsx_curwin->display);
150 orig_window = lsx_curwin;
151 base_display = lsx_curwin->display;
152
153 return argc;
154 } /* end of OpenDisplay() */
155
156
157
OpenDisplay(int argc,char ** argv)158 int OpenDisplay(int argc, char **argv)
159 {
160 return _OpenDisplay(argc, argv, NULL, NULL, 0);
161 }
162
163
164
165 #ifdef OPENGL_SUPPORT
166
OpenGLDisplay(int argc,char ** argv,int * attributes)167 int OpenGLDisplay(int argc, char **argv, int *attributes)
168 {
169 int xargc, cnt, i, retval, count;
170 char **xargv;
171 Arg args[5];
172 Display *dpy;
173 XVisualInfo *xvi;
174 GLXContext cx;
175 XVisualInfo vinfo;
176 XVisualInfo *vinfo_list; /* returned list of visuals */
177 Colormap colormap; /* created colormap */
178 Widget top;
179
180
181 /*
182 * First we copy the command line arguments
183 */
184 xargc = argc;
185 xargv = (char **)malloc(argc * sizeof (char *));
186 for(i=0; i < xargc; i++)
187 xargv[i] = strdup(argv[i]);
188
189
190 /*
191 * The following creates a _dummy_ toplevel widget so we can
192 * retrieve the appropriate visual resource.
193 */
194 cnt = 0;
195 top = XtAppInitialize(&lsx_app_con, xargv[0], NULL, 0, &xargc, xargv,
196 (String *)NULL, args, cnt);
197 if (top == NULL)
198 return 0;
199
200 dpy = XtDisplay(top);
201
202 /*
203 * Check if the server supports GLX. If not, crap out.
204 */
205 if (glXQueryExtension(dpy, NULL, NULL) == GL_FALSE)
206 {
207 XtDestroyWidget(top);
208 return FALSE;
209 }
210
211
212 xvi = glXChooseVisual(dpy, DefaultScreen(dpy), attributes);
213 if (xvi == NULL)
214 {
215 XtDestroyWidget(top);
216 return 0;
217 }
218
219 cx = glXCreateContext(dpy, xvi, 0, GL_TRUE);
220 if (cx == NULL)
221 {
222 XtDestroyWidget(top);
223 return 0;
224 }
225
226 cnt = 0;
227 XtSetArg(args[cnt], XtNvisual, xvi->visual); cnt++;
228
229 /*
230 * Now we create an appropriate colormap. We could
231 * use a default colormap based on the class of the
232 * visual; we could examine some property on the
233 * rootwindow to find the right colormap; we could
234 * do all sorts of things...
235 */
236 colormap = XCreateColormap (dpy,
237 RootWindowOfScreen(XtScreen (top)),
238 xvi->visual,
239 AllocNone);
240 XtSetArg(args[cnt], XtNcolormap, colormap); cnt++;
241
242 /*
243 * Now find some information about the visual.
244 */
245 vinfo.visualid = XVisualIDFromVisual(xvi->visual);
246 vinfo_list = XGetVisualInfo(dpy, VisualIDMask, &vinfo, &count);
247 if (vinfo_list && count > 0)
248 {
249 XtSetArg(args[cnt], XtNdepth, vinfo_list[0].depth);
250 cnt++;
251 XFree((XPointer) vinfo_list);
252 }
253
254 XtDestroyWidget(top);
255
256 /*
257 * Free up the copied version of the command line arguments
258 */
259 for(i=0; i < xargc; i++)
260 if (xargv[i])
261 free(xargv[i]);
262 free(xargv);
263
264
265 retval = _OpenDisplay(argc, argv, dpy, args, cnt);
266
267 if (retval > 0)
268 {
269 lsx_curwin->xvi = xvi;
270 lsx_curwin->gl_context = cx;
271 lsx_curwin->cmap = colormap;
272 }
273
274 return retval;
275 }
276
277 #endif /* OPENGL_SUPPORT */
278
279
280
ShowDisplay(void)281 void ShowDisplay(void)
282 {
283 XEvent xev;
284
285 if (lsx_curwin->toplevel == NULL || lsx_curwin->window_shown == TRUE)
286 return;
287
288 XtRealizeWidget(lsx_curwin->toplevel);
289
290 if (XtIsTransientShell(lsx_curwin->toplevel)) /* do popups differently */
291 {
292 PositionPopup(lsx_curwin->toplevel);
293 XtPopup(lsx_curwin->toplevel, XtGrabExclusive);
294
295 lsx_curwin->window = (Window )XtWindow(lsx_curwin->toplevel);
296 lsx_curwin->window_shown = TRUE;
297
298 return;
299 }
300
301 /*
302 * wait until the window is _really_ on screen
303 */
304 while(!XtIsRealized(lsx_curwin->toplevel))
305 ;
306
307 /*
308 * Now make sure it is really on the screen.
309 */
310 XPeekIfEvent(XtDisplay(lsx_curwin->toplevel), &xev, is_expose_event, NULL);
311
312
313 SetDrawArea(lsx_curwin->last_draw_widget);
314
315 lsx_curwin->window = (Window )XtWindow(lsx_curwin->toplevel);
316 lsx_curwin->window_shown = TRUE;
317 } /* end of ShowDisplay() */
318
319
320
is_expose_event(Display * d,XEvent * xev,char * blorg)321 static Bool is_expose_event(Display *d, XEvent *xev, char *blorg)
322 {
323 if (xev->type == Expose)
324 return TRUE;
325 else
326 return FALSE;
327 }
328
329
MainLoop(void)330 void MainLoop(void)
331 {
332 if (lsx_curwin->toplevel == NULL)
333 return;
334
335 /* in case the user forgot to map the display, do it for them */
336 if (lsx_curwin->window_shown == FALSE)
337 {
338 ShowDisplay();
339 GetStandardColors();
340 }
341
342
343 if (XtIsTransientShell(lsx_curwin->toplevel)) /* handle popups differently */
344 {
345 WindowState *curwin = lsx_curwin;
346
347 while (curwin->window_shown == TRUE) /* while window is still open */
348 {
349 XEvent event;
350
351 XtAppNextEvent(lsx_app_con, &event);
352 XtDispatchEvent(&event);
353 }
354
355 /*
356 * Ok, at this point the popup was just closed, so now CloseWindow()
357 * stored some info for us in the global variable new_curwin (which
358 * we use to change lsx_curwin (after free'ing what lsx_curwin used
359 * to point to)..
360 */
361 free(lsx_curwin);
362 lsx_curwin = new_curwin;
363 new_curwin = NULL;
364
365 return;
366 }
367 else
368 XtAppMainLoop(lsx_app_con);
369 }
370
371
SyncDisplay(void)372 void SyncDisplay(void)
373 {
374 if (lsx_curwin->display)
375 XSync(lsx_curwin->display, FALSE);
376 }
377
378
379
380
381
AddTimeOut(unsigned long interval,void (* func)(),void * data)382 void AddTimeOut(unsigned long interval, void (*func)(), void *data)
383 {
384 if (lsx_curwin->toplevel && func)
385 XtAppAddTimeOut(lsx_app_con, interval, (XtTimerCallbackProc)func, data);
386 }
387
388
AddReadCallback(int fd,IOCallback func,void * data)389 void AddReadCallback(int fd, IOCallback func, void *data)
390 {
391 XtInputMask mask = XtInputReadMask;
392
393 XtAppAddInput(lsx_app_con, fd, (XtPointer)mask,
394 (XtInputCallbackProc)func, data);
395 }
396
397
AddWriteCallback(int fd,IOCallback func,void * data)398 void AddWriteCallback(int fd, IOCallback func, void *data)
399 {
400 XtInputMask mask = XtInputWriteMask;
401
402 XtAppAddInput(lsx_app_con, fd, (XtPointer)mask,
403 (XtInputCallbackProc)func, data);
404 }
405
406
407
MakeWindow(char * window_name,char * display_name,int exclusive)408 Widget MakeWindow(char *window_name, char *display_name, int exclusive)
409 {
410 WindowState *win=NULL;
411 Display *d=NULL;
412 Arg wargs[20];
413 int n=0;
414 Visual *vis;
415 Colormap cmap;
416 char *argv[5];
417 int argc;
418
419 if (lsx_curwin->display == NULL) /* no other windows open yet... */
420 return NULL;
421
422 win = (WindowState *)calloc(sizeof(WindowState), 1);
423 if (win == NULL)
424 return NULL;
425
426
427 /*
428 * Setup a phony argv/argc to appease XtOpenDisplay().
429 */
430 if (window_name)
431 argv[0] = window_name;
432 else
433 argv[0] = app_name;
434 argv[1] = NULL;
435 argc = 1;
436
437 if (display_name != NULL)
438 d = XtOpenDisplay(lsx_app_con, display_name, app_name, app_name, NULL, 0,
439 &argc, argv);
440 else
441 d = base_display;
442 if (d == NULL)
443 {
444 free(win);
445 return NULL;
446 }
447
448 win->display = d;
449
450
451 cmap = DefaultColormap(d, DefaultScreen(d));
452 vis = DefaultVisual(d, DefaultScreen(d));
453
454
455 n=0;
456 XtSetArg(wargs[n], XtNtitle, app_name); n++;
457 XtSetArg(wargs[n], XtNiconName, app_name); n++;
458 XtSetArg(wargs[n], XtNcolormap, cmap); n++;
459 XtSetArg(wargs[n], XtNvisual, vis); n++;
460
461 if (exclusive == FALSE)
462 {
463 win->toplevel = XtAppCreateShell(argv[0], app_name,
464 topLevelShellWidgetClass, d, wargs, n);
465 }
466 else
467 {
468 win->toplevel = XtCreatePopupShell(argv[0], transientShellWidgetClass,
469 lsx_curwin->toplevel, NULL, 0);
470 }
471
472 if (win->toplevel == NULL)
473 {
474 if (d != base_display)
475 XtCloseDisplay(d);
476 free(win);
477 return NULL;
478 }
479
480
481 win->form_widget = XtCreateManagedWidget("form", formWidgetClass,
482 win->toplevel, NULL, 0);
483 if (win->form_widget == NULL)
484 {
485 XtDestroyWidget(win->toplevel);
486 if (d != base_display)
487 XtCloseDisplay(d);
488 free(win);
489 return NULL;
490 }
491 win->toplevel_form = win->form_widget;
492
493
494 win->screen = DefaultScreen(win->display);
495
496 /*
497 * Now link in the new window into the window list and make it
498 * the current window.
499 */
500 win->next = lsx_windows;
501 lsx_windows = win;
502 lsx_curwin = win;
503
504 return win->toplevel; /* return a handle to the user */
505 }
506
507
508
MakeForm(Widget parent,int where1,Widget from1,int where2,Widget from2)509 Widget MakeForm(Widget parent, int where1, Widget from1,
510 int where2, Widget from2)
511 {
512 Widget form;
513
514 if (lsx_curwin->toplevel == NULL)
515 return NULL;
516
517 if (parent == TOP_LEVEL_FORM)
518 parent = lsx_curwin->toplevel_form;
519 else if (strcmp(XtName(parent), "form") != 0) /* parent not a form widget */
520 return NULL;
521
522 form = XtCreateManagedWidget("form", formWidgetClass,
523 parent, NULL, 0);
524 if (form == NULL)
525 return NULL;
526
527 SetWidgetPos(form, where1, from1, where2, from2);
528
529 lsx_curwin->form_widget = form;
530
531 return form;
532 }
533
534
SetForm(Widget form)535 void SetForm(Widget form)
536 {
537 if (lsx_curwin->toplevel == NULL)
538 return;
539
540 if (form == TOP_LEVEL_FORM)
541 lsx_curwin->form_widget = lsx_curwin->toplevel_form;
542 else
543 lsx_curwin->form_widget = form;
544 }
545
546
547
SetCurrentWindow(Widget w)548 void SetCurrentWindow(Widget w)
549 {
550 WindowState *win;
551
552 if (w == ORIGINAL_WINDOW)
553 {
554 if (orig_window)
555 lsx_curwin = orig_window;
556 else if (lsx_windows) /* hmm, don't have orig_window */
557 lsx_curwin = lsx_windows;
558 else
559 lsx_curwin = &empty_window; /* hmm, don't have anything left */
560
561 SetDrawArea(lsx_curwin->last_draw_widget);
562 return;
563 }
564
565 for(win=lsx_windows; win; win=win->next)
566 if (win->toplevel == w && win->display == XtDisplay(w))
567 break;
568
569 if (win == NULL)
570 return;
571
572 lsx_curwin = win;
573 SetDrawArea(lsx_curwin->last_draw_widget);
574 }
575
576
CloseWindow(void)577 void CloseWindow(void)
578 {
579 WindowState *tmp;
580 int is_transient;
581
582 if (lsx_curwin->toplevel == NULL)
583 return;
584
585 is_transient = XtIsTransientShell(lsx_curwin->toplevel);
586
587 XtDestroyWidget(lsx_curwin->toplevel);
588
589 if (lsx_curwin->display != base_display)
590 {
591 FreeFont(lsx_curwin->font);
592 XtCloseDisplay(lsx_curwin->display);
593 }
594
595
596 /*
597 * if the window to delete is not at the head of the list, find
598 * it in the list of available windows.
599 * else, just assign tmp to the head of the list.
600 */
601 if (lsx_curwin != lsx_windows)
602 for(tmp=lsx_windows; tmp && tmp->next != lsx_curwin; tmp=tmp->next)
603 ;
604 else
605 tmp = lsx_windows;
606
607 if (tmp == NULL) /* bogus window deletion... */
608 {
609 return;
610 }
611 else if (lsx_curwin == lsx_windows) /* delete head of list */
612 {
613 lsx_windows = lsx_curwin->next;
614 tmp = lsx_windows;
615 }
616 else
617 {
618 tmp->next = lsx_curwin->next;
619 }
620
621 if (lsx_curwin == orig_window)
622 orig_window = NULL;
623
624 if (is_transient)
625 {
626 lsx_curwin->window_shown = FALSE;
627
628 /*
629 * Store tmp in a global so MainLoop() can change lsx_curwin
630 * to what it should be after it frees everything.
631 */
632 new_curwin = tmp;
633 }
634 else /* it's a normal window, so get rid of it completely */
635 {
636 free(lsx_curwin);
637 lsx_curwin = tmp;
638 }
639
640 }
641
642
643
Beep(void)644 void Beep(void)
645 {
646 XBell(lsx_curwin->display, 100);
647 }
648