8e7fef039abadf4b953364074f79700993671f88
[alexxy/gromacs.git] / src / ngmx / x11.c
1 /*
2  * 
3  *                This source code is part of
4  * 
5  *                 G   R   O   M   A   C   S
6  * 
7  *          GROningen MAchine for Chemical Simulations
8  * 
9  *                        VERSION 3.2.0
10  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12  * Copyright (c) 2001-2004, The GROMACS development team,
13  * check out http://www.gromacs.org for more information.
14
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  * 
20  * If you want to redistribute modifications, please consider that
21  * scientific software is very special. Version control is crucial -
22  * bugs must be traceable. We will be happy to consider code for
23  * inclusion in the official distribution, but derived work must not
24  * be called official GROMACS. Details are found in the README & COPYING
25  * files - if they are missing, get the official version at www.gromacs.org.
26  * 
27  * To help us fund GROMACS development, we humbly ask that you cite
28  * the papers on the package - you can find them in the top README file.
29  * 
30  * For more info, check our website at http://www.gromacs.org
31  * 
32  * And Hey:
33  * Gyas ROwers Mature At Cryogenic Speed
34  */
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include "typedefs.h"
40 #include <Xstuff.h>
41 #include <x11.h>
42 #include "sysstuff.h"
43 #include "string.h"
44 #include "smalloc.h"
45 #include "string2.h"
46
47 /* These colours will be mapped to black on a monochrome screen */
48 unsigned long BLACK,BLUE,GREEN,CYAN,RED,BROWN,GREY,DARKGREY;
49
50 /* These colours will be mapped to white on a monochrome screen */
51 unsigned long LIGHTBLUE,LIGHTGREEN,LIGHTGREY,LIGHTCYAN,LIGHTRED,VIOLET,YELLOW,WHITE;
52
53 static XFontStruct *XLQF(FILE *err, Display *disp, const char *name)
54 {
55   XFontStruct *font=XLoadQueryFont(disp,name);
56 #ifdef DEBUG
57   if (font != NULL) 
58     fprintf(err, "Loaded font %s\n",name);
59 #endif
60   return font;
61 }
62   
63 static XFontStruct *GetFont(FILE *err, Display *disp, char *name)
64 {
65   static const char *fontnames[] = { 
66     "sansb12","8x13bold","8x13",
67     "9x15","6x13","fixed" 
68     };
69 #define MAXNAMES (sizeof(fontnames)/sizeof(fontnames[0]))
70   int i;
71   XFontStruct *font;
72   int count;
73   char **fontlist;
74   bool bFont = FALSE;
75
76   if (name)
77     bFont=(bool) ((font=XLQF(err,disp,name))!=NULL);
78   else
79     font=NULL;
80     
81   for (i=0; (!bFont && (i<MAXNAMES)); i++) 
82     bFont=(bool) ((font=XLQF(err,disp,fontnames[i]))!=NULL);
83
84   if (!bFont) {
85     fontlist=XListFonts(disp,"?",1,&count);
86     if (count!=0) 
87       bFont=(bool) ((font=XLQF(err,disp,fontlist[0]))!=NULL);
88   }
89   if (!bFont) 
90     fprintf (err, "Cannot load any suitable font\n");
91   return font;
92 }
93
94 static GC GetGC(Display *disp, XFontStruct *font)
95 {
96   XGCValues     values;
97
98   values.font = font->fid;
99   values.foreground = WhitePixel(disp,DefaultScreen(disp));
100
101   return XCreateGC(disp,DefaultRootWindow(disp),GCForeground|GCFont,&values);
102 }
103
104 void GetNamedColor(t_x11 *x11,const char *name,unsigned long *col)
105 {
106   /* If name is found than col set to that colour else col is unchanged */
107   XColor exact,clr;
108
109   if (XAllocNamedColor(x11->disp,x11->cmap,name,&clr,&exact))
110     *col=clr.pixel;
111   else
112     fprintf(x11->console,"No colour %s\n",name);
113 }
114
115 static t_wlist *GetWList(t_x11 *x11, Window w)
116 {
117   t_wlist *curs;
118
119   curs=x11->wlist;
120   while (curs && (curs->w != w))
121     curs=curs->next;
122
123   return curs;
124 }
125
126 typedef struct {
127   Window w;
128   bool   b;
129 } t_peek;
130
131 static Bool TestEvent(Display *disp,XEvent *event,char *arg)
132 {
133   t_peek *tp;
134
135   fprintf(stderr,"TestEvent\n");
136   tp=(t_peek *)arg;
137   if ((event->xany.window==tp->w) && (event->type==ConfigureNotify)) {
138     tp->b=TRUE;
139     return True;
140   }
141   return False;
142 }
143
144 static void MainLoop(t_x11 *x11)
145 {
146   bool    bReturn;
147   XEvent  event;
148   t_wlist *curs;
149   Window  w;
150
151   for (bReturn=FALSE; (!bReturn); ) {
152     if (x11->wlist) {
153       XNextEvent(x11->disp,&event);
154       w=event.xany.window;
155       curs=GetWList(x11,w);
156       if (!curs)
157         bReturn=TRUE;
158       if (!bReturn) {
159         switch (event.type) {
160         case Expose:
161           /* Filter out expose events with non-zero count field */
162           if (event.xexpose.count != 0)
163             curs=NULL;
164           break;
165         case ConfigureNotify:
166           /* Check if more are coming... 
167           if (XCheckTypedWindowEvent(x11->disp,w,ConfigureNotify,&config))
168             curs=NULL; */
169           break;
170         default:
171           break;
172         }
173         if (curs)
174           bReturn=(*curs->cb)(x11,&event,w,curs->data);
175       }
176     }
177   }
178 }
179
180 static void RegisterCallback(t_x11 *x11,Window w,Window Parent,
181                              CallBack cb, void *data)
182 {
183   t_wlist *curs,*item;
184
185   snew(item,1);
186   item->w=w;
187   item->Parent=Parent;
188   item->cb=cb;
189   item->mask=0;
190   item->data=data;
191   item->next=NULL;
192
193   if (x11->wlist) {
194     curs=x11->wlist;
195     while(curs->next)
196       curs=curs->next;
197     curs->next=item;
198   }
199   else
200     x11->wlist=item;
201 }
202
203 static void UnRegisterCallback(t_x11 *x11, Window w)
204 {
205   t_wlist *curs;
206
207   curs=x11->wlist;
208   if (curs) {
209     if (curs->w==w) {
210       x11->wlist=curs->next;
211       sfree(curs);
212     }
213     else {
214       while (curs->next && (curs->next->w != w))
215         curs=curs->next;
216       if (curs->next) {
217         t_wlist *tmp=curs->next;
218
219         curs->next=curs->next->next;
220         sfree(tmp);
221       }
222     }
223   }
224 }
225
226 static void SetInputMask(t_x11 *x11, Window w, unsigned long mask)
227 {
228   t_wlist *curs;
229
230   curs=GetWList(x11,w);
231   if (curs) {
232     curs->mask=mask;
233     XSelectInput(x11->disp,w,(long)mask);
234   }
235   else 
236     fprintf(x11->console,"No such window (%d)\n",(int)w);
237 }
238
239 static unsigned long GetInputMask(t_x11 *x11, Window w)
240 {
241   t_wlist *curs;
242
243   curs=GetWList(x11,w);
244   if (curs)
245     return curs->mask;
246   else
247     return 0;
248 }
249
250 static void CleanUp(t_x11 *x11) 
251 {
252   t_wlist *curs;
253   
254   curs=x11->wlist;
255   while (curs) {
256     x11->wlist=curs->next;
257     XDestroyWindow(x11->disp,curs->w);
258     sfree(curs);
259     curs=x11->wlist;
260   }
261   XCloseDisplay(x11->disp);
262 }
263
264 static void Xrm(int *argc, char *argv[])
265 {
266   /*
267   static XrmOptionDescRec opTable[] = {
268     {"-background",   "*background",    
269        XrmoptionSepArg, (caddr_t) NULL},
270     {"-bd",           "*borderColor",   
271        XrmoptionSepArg, (caddr_t) NULL},
272     {"-bg",           "*background",    
273        XrmoptionSepArg, (caddr_t) NULL},
274     {"-borderwidth",  "*TopLevelShell.borderwidth",    
275        XrmoptionSepArg, (caddr_t) NULL},
276     {"-bordercolor",   "*borderColor",    
277        XrmoptionSepArg, (caddr_t) NULL},
278     {"-bw",            "*TopLevelShell.borderColor",    
279        XrmoptionSepArg, (caddr_t) NULL},
280     {"-display",       ".display",    
281        XrmoptionSepArg, (caddr_t) NULL},
282     {"-fg",            "*foreground",
283        XrmoptionSepArg, (caddr_t) NULL},
284     {"-fn",            "*font",
285        XrmoptionSepArg, (caddr_t) NULL},
286     {"-font",          "*font",
287        XrmoptionSepArg, (caddr_t) NULL},
288     {"-foreground",    "*foreground",
289        XrmoptionSepArg, (caddr_t) NULL},
290     {"-geometry",      ".TopLevelShell.geometry",
291        XrmoptionSepArg, (caddr_t) NULL},
292     {"-iconic",        ".TopLevelShell.iconic",
293        XrmoptionNoArg,  (caddr_t) "on"},
294     {"-name",          ".name",
295        XrmoptionSepArg, (caddr_t) NULL},
296     {"-reverse",       "*reverseVideo",
297        XrmoptionNoArg,  (caddr_t) "on"},
298     {"-rv",            "*reverseVideo",
299        XrmoptionNoArg,  (caddr_t) "on"},
300     {"-synchronous",   ".synchronous",
301        XrmoptionNoArg,  (caddr_t) "on"},
302     {"-title",         ".TopLevelShell.title",
303        XrmoptionSepArg, (caddr_t) NULL},
304     {"-xrm",            NULL,
305        XrmoptionSepArg, (caddr_t) NULL},
306   };
307 #define TABLELENGTH (sizeof(opTable)/sizeof(opTable[0]))
308   XrmInitialize();*/
309 }
310
311 static void Flush(t_x11 *x11)
312 {
313   fflush(x11->console);
314 }
315
316 t_x11 *GetX11(int *argc, char *argv[])
317 {
318   static const char *v_name[] = {
319     "DirectColor","TrueColor", "PseudoColor",
320     "StaticColor","GrayScale", "StaticGray"
321     };
322   static int v_class[] = {
323     DirectColor,TrueColor, PseudoColor,
324     StaticColor,GrayScale, StaticGray
325     };
326 #define NCLASS (sizeof(v_class)/sizeof(v_class[0]))
327
328   XVisualInfo v_info;
329   t_x11       *x11;
330   int         ARGC;
331   char        **ARGV;
332   char        *display;
333   char        *fontname;
334   char        *title,*FG=NULL,*BG=NULL;
335   bool        bVerbose=FALSE;
336   int         i;
337
338   title=strdup(argv[0]);
339
340   /* First check environment */
341   fontname=getenv("GMXFONT");
342   display=getenv("DISPLAY");
343
344   snew(ARGV,*argc);
345   ARGC=1;
346   for(i=1; (i < *argc); i++) {
347     if (argv[i][0]=='-') {
348       if (strlen(argv[i]) > 1) {
349         if ((*argc)>i+1)
350           switch(argv[i][1]) {
351           case 'b':
352             BG=argv[++i];
353             break;
354           case 'd':
355             display=argv[++i];
356             break;
357           case 'f':
358             switch(argv[i][2]) {
359             case 'o':
360               fontname=argv[++i];
361               break;
362             case 'g':
363               FG=argv[++i];
364               break;
365             }
366             break;
367           case 't':
368             sfree(title);
369             title=strdup(argv[++i]);
370             break;
371           case 'v':
372             bVerbose=TRUE;
373             break;
374           default:
375             ARGV[ARGC++]=argv[i];
376             break;
377           }
378       }
379     }
380     else 
381       ARGV[ARGC++]=argv[i];
382   }
383   for (i=1; (i<ARGC); i++)
384     argv[i]=ARGV[i];
385   *argc=ARGC;
386   argv[ARGC]=NULL;
387
388   snew(x11,1);
389   x11->dispname=display;
390   if (bVerbose)
391     x11->console=stderr;
392   else
393     if ((x11->console=fopen("/dev/null","w"))== NULL)
394       x11->console=stderr;
395
396   if ((x11->disp=XOpenDisplay(display))==NULL) {
397     if (bVerbose)
398       fprintf(x11->console,"Display %s invalid\n",display);
399     return NULL;
400   }
401   
402   if ((x11->font=GetFont(x11->console,x11->disp,fontname))==NULL)
403     return NULL;
404   if ((x11->gc=GetGC(x11->disp,x11->font))==NULL)
405     return NULL;
406
407   x11->root=DefaultRootWindow(x11->disp);
408   x11->screen=DefaultScreen(x11->disp);
409   x11->depth=DefaultDepth(x11->disp,x11->screen);
410   x11->cmap=DefaultColormap(x11->disp,x11->screen);
411
412   /* These colours will be mapped to black on a monochrome screen */
413   x11->fg=BLACK=BLUE=GREEN=CYAN=RED=BROWN=GREY=DARKGREY=
414     BlackPixel(x11->disp,x11->screen);
415
416   /* These colours will be mapped to white on a monochrome screen */
417   x11->bg=
418     LIGHTBLUE=LIGHTGREY=LIGHTGREEN=LIGHTCYAN=LIGHTRED=VIOLET=YELLOW=WHITE=
419       WhitePixel(x11->disp,x11->screen);
420
421   if (x11->depth > 1) {
422     /* Not B & W, Look what kind of screen we've got... */
423     for (i=0; (i < NCLASS); i++)
424       if (!XMatchVisualInfo(x11->disp,x11->screen,x11->depth,
425                             v_class[i],&v_info))
426         break;
427     if ((i==4) || (i==5)) 
428       fprintf(x11->console,"Greyscale screen, using B & W only\n");
429     else {
430       /* We have real color! */
431       fprintf(x11->console,"%s screen with depth %d.\n",
432              (i==NCLASS)?"Unknown":v_name[i],x11->depth);
433       GetNamedColor(x11,"midnight blue",&BLUE);
434       GetNamedColor(x11,"DarkGreen",&GREEN);
435       GetNamedColor(x11,"SeaGreen",&CYAN);
436       GetNamedColor(x11,"red4",&RED);
437       GetNamedColor(x11,"Gray",&GREY);
438       GetNamedColor(x11,"Gray",&DARKGREY);
439       GetNamedColor(x11,"LightGray",&LIGHTGREY);
440       GetNamedColor(x11,"green",&LIGHTGREEN);
441       GetNamedColor(x11,"cyan",&LIGHTCYAN);
442       GetNamedColor(x11,"tomato1",&LIGHTRED);
443       GetNamedColor(x11,"violet",&VIOLET);
444       GetNamedColor(x11,"yellow",&YELLOW);
445       GetNamedColor(x11,"brown",&BROWN);
446       GetNamedColor(x11,"CornFlowerBlue",&LIGHTBLUE);
447     }
448   }
449   else
450     fprintf(x11->console,"Monochrome screen.\n");
451
452   /* We should use Xrm here... */
453   if (FG)
454     GetNamedColor(x11,FG,&(x11->fg));
455   else
456     x11->fg=BLACK;
457   if (BG)
458     GetNamedColor(x11,BG,&(x11->bg));
459   else
460     x11->bg=LIGHTGREY;
461   x11->title=strdup(title);
462   sfree(title);
463   x11->wlist=NULL;
464   x11->GetNamedColor=&GetNamedColor;
465   x11->MainLoop=&MainLoop;
466   x11->RegisterCallback=&RegisterCallback;
467   x11->UnRegisterCallback=&UnRegisterCallback;
468   x11->SetInputMask=&SetInputMask;
469   x11->GetInputMask=&GetInputMask;
470   x11->CleanUp=&CleanUp;
471   x11->Flush=&Flush;
472
473   x11->Flush(x11);
474
475   return x11;
476 }
477