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