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