/* This file contains the top level routines that manipulate whole * windows and what not. It's the main initialization stuff, etc. * * * This code is under the GNU Copyleft. * * Dominic Giampaolo * dbg@sgi.com */ #include #include #include "xstuff.h" #include "libsx.h" #include "libsx_private.h" /* * External prototypes. */ extern void SetOkay(); /* from Dialog.c */ extern void PositionPopup(Widget w); /* from Dialog.c */ extern void libsx_done_with_text(Widget w, XEvent *xev, String *parms, Cardinal *num_parms);/* from string_entry.c */ /* internal protos */ static Bool is_expose_event(Display *d, XEvent *xev, char *blorg); /* * Private static variables. */ static WindowState *lsx_windows = NULL, empty_window = { 0, 0, 0, NULL, NULL, NULL, NULL, 0,}, *orig_window = NULL, *new_curwin = NULL; static char *app_name=""; static Display *base_display=NULL; /* * Global Variables for all of libsx (but not for user applications). * * We initialize lsx_curwin to point to the static empty_window so that * if other functions get called before OpenDisplay(), they won't core * dump, and will fail gracefully instead. */ WindowState *lsx_curwin = &empty_window; XtAppContext lsx_app_con; /* * These are some internal actions and resources so that dialog boxes * and string entry widgets work they way god intended them to work * (i.e. pressing the return key in one gives the text you typed to * the application). */ static XtActionsRec actions_table[] = { { "set-okay", SetOkay }, { "done_with_text", libsx_done_with_text } }; static String fallback_resources[] = { "*Dialog*label.resizable: True", "*Dialog*Text.resizable: True", "*Dialog.Text.translations: #override Return: set-okay()\\n\ Linefeed: set-okay()", NULL }; /* * * This is the function that gets everything started. * */ int _OpenDisplay(int argc, char **argv, Display *dpy, Arg *wargs, int arg_cnt) { static char *dummy_argv[] = { "Untitled", NULL }; static int dummy_argc = 1; static int already_called = FALSE; if (already_called) /* must have been called a second time */ return FALSE; already_called = TRUE; if (argv == NULL) { argv = dummy_argv; argc = dummy_argc; } /* * First create the window state. */ lsx_curwin = (WindowState *)calloc(sizeof(WindowState), 1); if (lsx_curwin == NULL) return FALSE; /* open the display stuff */ if (dpy == NULL) lsx_curwin->toplevel = XtAppInitialize(&lsx_app_con, argv[0], NULL, 0, &argc, argv, fallback_resources, wargs, arg_cnt); else lsx_curwin->toplevel = XtAppCreateShell (argv[0], argv[0], applicationShellWidgetClass, dpy, wargs, arg_cnt); if (lsx_curwin->toplevel == NULL) { free(lsx_curwin); return FALSE; } app_name = argv[0]; /* save this for later */ XtAppAddActions(lsx_app_con, actions_table, XtNumber(actions_table)); lsx_curwin->form_widget = XtCreateManagedWidget("form", formWidgetClass, lsx_curwin->toplevel,NULL,0); if (lsx_curwin->form_widget == NULL) { XtDestroyWidget(lsx_curwin->toplevel); free(lsx_curwin); lsx_curwin = &empty_window; return FALSE; } lsx_curwin->toplevel_form = lsx_curwin->form_widget; lsx_curwin->next = lsx_windows; /* link it in to the list */ lsx_windows = lsx_curwin; /* save these values for later */ lsx_curwin->display = (Display *)XtDisplay(lsx_curwin->toplevel); lsx_curwin->screen = DefaultScreen(lsx_curwin->display); orig_window = lsx_curwin; base_display = lsx_curwin->display; return argc; } /* end of OpenDisplay() */ int OpenDisplay(int argc, char **argv) { return _OpenDisplay(argc, argv, NULL, NULL, 0); } #ifdef OPENGL_SUPPORT int OpenGLDisplay(int argc, char **argv, int *attributes) { int xargc, cnt, i, retval, count; char **xargv; Arg args[5]; Display *dpy; XVisualInfo *xvi; GLXContext cx; XVisualInfo vinfo; XVisualInfo *vinfo_list; /* returned list of visuals */ Colormap colormap; /* created colormap */ Widget top; /* * First we copy the command line arguments */ xargc = argc; xargv = (char **)malloc(argc * sizeof (char *)); for(i=0; i < xargc; i++) xargv[i] = strdup(argv[i]); /* * The following creates a _dummy_ toplevel widget so we can * retrieve the appropriate visual resource. */ cnt = 0; top = XtAppInitialize(&lsx_app_con, xargv[0], NULL, 0, &xargc, xargv, (String *)NULL, args, cnt); if (top == NULL) return 0; dpy = XtDisplay(top); /* * Check if the server supports GLX. If not, crap out. */ if (glXQueryExtension(dpy, NULL, NULL) == GL_FALSE) { XtDestroyWidget(top); return FALSE; } xvi = glXChooseVisual(dpy, DefaultScreen(dpy), attributes); if (xvi == NULL) { XtDestroyWidget(top); return 0; } cx = glXCreateContext(dpy, xvi, 0, GL_TRUE); if (cx == NULL) { XtDestroyWidget(top); return 0; } cnt = 0; XtSetArg(args[cnt], XtNvisual, xvi->visual); cnt++; /* * Now we create an appropriate colormap. We could * use a default colormap based on the class of the * visual; we could examine some property on the * rootwindow to find the right colormap; we could * do all sorts of things... */ colormap = XCreateColormap (dpy, RootWindowOfScreen(XtScreen (top)), xvi->visual, AllocNone); XtSetArg(args[cnt], XtNcolormap, colormap); cnt++; /* * Now find some information about the visual. */ vinfo.visualid = XVisualIDFromVisual(xvi->visual); vinfo_list = XGetVisualInfo(dpy, VisualIDMask, &vinfo, &count); if (vinfo_list && count > 0) { XtSetArg(args[cnt], XtNdepth, vinfo_list[0].depth); cnt++; XFree((XPointer) vinfo_list); } XtDestroyWidget(top); /* * Free up the copied version of the command line arguments */ for(i=0; i < xargc; i++) if (xargv[i]) free(xargv[i]); free(xargv); retval = _OpenDisplay(argc, argv, dpy, args, cnt); if (retval > 0) { lsx_curwin->xvi = xvi; lsx_curwin->gl_context = cx; lsx_curwin->cmap = colormap; } return retval; } #endif /* OPENGL_SUPPORT */ void ShowDisplay(void) { XEvent xev; if (lsx_curwin->toplevel == NULL || lsx_curwin->window_shown == TRUE) return; XtRealizeWidget(lsx_curwin->toplevel); if (XtIsTransientShell(lsx_curwin->toplevel)) /* do popups differently */ { PositionPopup(lsx_curwin->toplevel); XtPopup(lsx_curwin->toplevel, XtGrabExclusive); lsx_curwin->window = (Window )XtWindow(lsx_curwin->toplevel); lsx_curwin->window_shown = TRUE; return; } /* * wait until the window is _really_ on screen */ while(!XtIsRealized(lsx_curwin->toplevel)) ; /* * Now make sure it is really on the screen. */ XPeekIfEvent(XtDisplay(lsx_curwin->toplevel), &xev, is_expose_event, NULL); SetDrawArea(lsx_curwin->last_draw_widget); lsx_curwin->window = (Window )XtWindow(lsx_curwin->toplevel); lsx_curwin->window_shown = TRUE; } /* end of ShowDisplay() */ static Bool is_expose_event(Display *d, XEvent *xev, char *blorg) { if (xev->type == Expose) return TRUE; else return FALSE; } void MainLoop(void) { if (lsx_curwin->toplevel == NULL) return; /* in case the user forgot to map the display, do it for them */ if (lsx_curwin->window_shown == FALSE) { ShowDisplay(); GetStandardColors(); } if (XtIsTransientShell(lsx_curwin->toplevel)) /* handle popups differently */ { WindowState *curwin = lsx_curwin; while (curwin->window_shown == TRUE) /* while window is still open */ { XEvent event; XtAppNextEvent(lsx_app_con, &event); XtDispatchEvent(&event); } /* * Ok, at this point the popup was just closed, so now CloseWindow() * stored some info for us in the global variable new_curwin (which * we use to change lsx_curwin (after free'ing what lsx_curwin used * to point to).. */ free(lsx_curwin); lsx_curwin = new_curwin; new_curwin = NULL; return; } else XtAppMainLoop(lsx_app_con); } void SyncDisplay(void) { if (lsx_curwin->display) XSync(lsx_curwin->display, FALSE); } void AddTimeOut(unsigned long interval, void (*func)(), void *data) { if (lsx_curwin->toplevel && func) XtAppAddTimeOut(lsx_app_con, interval, (XtTimerCallbackProc)func, data); } void AddReadCallback(int fd, IOCallback func, void *data) { XtInputMask mask = XtInputReadMask; XtAppAddInput(lsx_app_con, fd, (XtPointer)mask, (XtInputCallbackProc)func, data); } void AddWriteCallback(int fd, IOCallback func, void *data) { XtInputMask mask = XtInputWriteMask; XtAppAddInput(lsx_app_con, fd, (XtPointer)mask, (XtInputCallbackProc)func, data); } Widget MakeWindow(char *window_name, char *display_name, int exclusive) { WindowState *win=NULL; Display *d=NULL; Arg wargs[20]; int n=0; Visual *vis; Colormap cmap; char *argv[5]; int argc; if (lsx_curwin->display == NULL) /* no other windows open yet... */ return NULL; win = (WindowState *)calloc(sizeof(WindowState), 1); if (win == NULL) return NULL; /* * Setup a phony argv/argc to appease XtOpenDisplay(). */ if (window_name) argv[0] = window_name; else argv[0] = app_name; argv[1] = NULL; argc = 1; if (display_name != NULL) d = XtOpenDisplay(lsx_app_con, display_name, app_name, app_name, NULL, 0, &argc, argv); else d = base_display; if (d == NULL) { free(win); return NULL; } win->display = d; cmap = DefaultColormap(d, DefaultScreen(d)); vis = DefaultVisual(d, DefaultScreen(d)); n=0; XtSetArg(wargs[n], XtNtitle, app_name); n++; XtSetArg(wargs[n], XtNiconName, app_name); n++; XtSetArg(wargs[n], XtNcolormap, cmap); n++; XtSetArg(wargs[n], XtNvisual, vis); n++; if (exclusive == FALSE) { win->toplevel = XtAppCreateShell(argv[0], app_name, topLevelShellWidgetClass, d, wargs, n); } else { win->toplevel = XtCreatePopupShell(argv[0], transientShellWidgetClass, lsx_curwin->toplevel, NULL, 0); } if (win->toplevel == NULL) { if (d != base_display) XtCloseDisplay(d); free(win); return NULL; } win->form_widget = XtCreateManagedWidget("form", formWidgetClass, win->toplevel, NULL, 0); if (win->form_widget == NULL) { XtDestroyWidget(win->toplevel); if (d != base_display) XtCloseDisplay(d); free(win); return NULL; } win->toplevel_form = win->form_widget; win->screen = DefaultScreen(win->display); /* * Now link in the new window into the window list and make it * the current window. */ win->next = lsx_windows; lsx_windows = win; lsx_curwin = win; return win->toplevel; /* return a handle to the user */ } Widget MakeForm(Widget parent, int where1, Widget from1, int where2, Widget from2) { Widget form; if (lsx_curwin->toplevel == NULL) return NULL; if (parent == TOP_LEVEL_FORM) parent = lsx_curwin->toplevel_form; else if (strcmp(XtName(parent), "form") != 0) /* parent not a form widget */ return NULL; form = XtCreateManagedWidget("form", formWidgetClass, parent, NULL, 0); if (form == NULL) return NULL; SetWidgetPos(form, where1, from1, where2, from2); lsx_curwin->form_widget = form; return form; } void SetForm(Widget form) { if (lsx_curwin->toplevel == NULL) return; if (form == TOP_LEVEL_FORM) lsx_curwin->form_widget = lsx_curwin->toplevel_form; else lsx_curwin->form_widget = form; } void SetCurrentWindow(Widget w) { WindowState *win; if (w == ORIGINAL_WINDOW) { if (orig_window) lsx_curwin = orig_window; else if (lsx_windows) /* hmm, don't have orig_window */ lsx_curwin = lsx_windows; else lsx_curwin = &empty_window; /* hmm, don't have anything left */ SetDrawArea(lsx_curwin->last_draw_widget); return; } for(win=lsx_windows; win; win=win->next) if (win->toplevel == w && win->display == XtDisplay(w)) break; if (win == NULL) return; lsx_curwin = win; SetDrawArea(lsx_curwin->last_draw_widget); } void CloseWindow(void) { WindowState *tmp; int is_transient; if (lsx_curwin->toplevel == NULL) return; is_transient = XtIsTransientShell(lsx_curwin->toplevel); XtDestroyWidget(lsx_curwin->toplevel); if (lsx_curwin->display != base_display) { FreeFont(lsx_curwin->font); XtCloseDisplay(lsx_curwin->display); } /* * if the window to delete is not at the head of the list, find * it in the list of available windows. * else, just assign tmp to the head of the list. */ if (lsx_curwin != lsx_windows) for(tmp=lsx_windows; tmp && tmp->next != lsx_curwin; tmp=tmp->next) ; else tmp = lsx_windows; if (tmp == NULL) /* bogus window deletion... */ { return; } else if (lsx_curwin == lsx_windows) /* delete head of list */ { lsx_windows = lsx_curwin->next; tmp = lsx_windows; } else { tmp->next = lsx_curwin->next; } if (lsx_curwin == orig_window) orig_window = NULL; if (is_transient) { lsx_curwin->window_shown = FALSE; /* * Store tmp in a global so MainLoop() can change lsx_curwin * to what it should be after it frees everything. */ new_curwin = tmp; } else /* it's a normal window, so get rid of it completely */ { free(lsx_curwin); lsx_curwin = tmp; } } void Beep(void) { XBell(lsx_curwin->display, 100); }