Remove unnecessary config.h includes
[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 "gmxpre.h"
38
39 #include <stdlib.h>
40 #include <string.h>
41
42 #include "gromacs/legacyheaders/typedefs.h"
43 #include "gromacs/utility/cstringutil.h"
44 #include "gromacs/utility/smalloc.h"
45 #include "Xstuff.h"
46 #include "x11.h"
47
48 /* These colours will be mapped to black on a monochrome screen */
49 unsigned long BLACK, BLUE, GREEN, CYAN, RED, BROWN, GREY, DARKGREY;
50
51 /* These colours will be mapped to white on a monochrome screen */
52 unsigned long LIGHTBLUE, LIGHTGREEN, LIGHTGREY, LIGHTCYAN, LIGHTRED, VIOLET, YELLOW, WHITE;
53
54 static XFontStruct *XLQF(FILE gmx_unused *err, Display *disp, const char *name)
55 {
56     XFontStruct *font = XLoadQueryFont(disp, name);
57 #ifdef DEBUG
58     if (font != NULL)
59     {
60         fprintf(err, "Loaded font %s\n", name);
61     }
62 #endif
63     return font;
64 }
65
66 static XFontStruct *GetFont(FILE *err, Display *disp, char *name)
67 {
68     static const char *fontnames[] = {
69         "sansb12", "8x13bold", "8x13",
70         "9x15", "6x13", "fixed"
71     };
72 #define MAXNAMES (sizeof(fontnames)/sizeof(fontnames[0]))
73     unsigned int       i;
74     XFontStruct       *font;
75     int                count;
76     char             **fontlist;
77     bool               bFont = false;
78
79     if (name)
80     {
81         bFont = ((font = XLQF(err, disp, name)) != NULL);
82     }
83     else
84     {
85         font = NULL;
86     }
87
88     for (i = 0; (!bFont && (i < MAXNAMES)); i++)
89     {
90         bFont = ((font = XLQF(err, disp, fontnames[i])) != NULL);
91     }
92
93     if (!bFont)
94     {
95         fontlist = XListFonts(disp, "?", 1, &count);
96         if (count != 0)
97         {
98             bFont = ((font = XLQF(err, disp, fontlist[0])) != NULL);
99         }
100     }
101     if (!bFont)
102     {
103         fprintf (err, "Cannot load any suitable font\n");
104     }
105     return font;
106 }
107
108 static GC GetGC(Display *disp, XFontStruct *font)
109 {
110     XGCValues     values;
111
112     values.font       = font->fid;
113     values.foreground = WhitePixel(disp, DefaultScreen(disp));
114
115     return XCreateGC(disp, DefaultRootWindow(disp), GCForeground|GCFont, &values);
116 }
117
118 void GetNamedColor(t_x11 *x11, const char *name, unsigned long *col)
119 {
120     /* If name is found than col set to that colour else col is unchanged */
121     XColor exact, clr;
122
123     if (XAllocNamedColor(x11->disp, x11->cmap, name, &clr, &exact))
124     {
125         *col = clr.pixel;
126     }
127     else
128     {
129         fprintf(x11->console, "No colour %s\n", name);
130     }
131 }
132
133 static t_wlist *GetWList(t_x11 *x11, Window w)
134 {
135     t_wlist *curs;
136
137     curs = x11->wlist;
138     while (curs && (curs->w != w))
139     {
140         curs = curs->next;
141     }
142
143     return curs;
144 }
145
146 static void MainLoop(t_x11 *x11)
147 {
148     bool        bReturn;
149     XEvent      event;
150     t_wlist    *curs;
151     Window      w;
152
153     for (bReturn = false; (!bReturn); )
154     {
155         if (x11->wlist)
156         {
157             XNextEvent(x11->disp, &event);
158             w    = event.xany.window;
159             curs = GetWList(x11, w);
160             if (!curs)
161             {
162                 bReturn = true;
163             }
164             if (!bReturn)
165             {
166                 switch (event.type)
167                 {
168                     case Expose:
169                         /* Filter out expose events with non-zero count field */
170                         if (event.xexpose.count != 0)
171                         {
172                             curs = NULL;
173                         }
174                         break;
175                     case ConfigureNotify:
176                         /* Check if more are coming...
177                            if (XCheckTypedWindowEvent(x11->disp,w,ConfigureNotify,&config))
178                            curs=NULL; */
179                         break;
180                     default:
181                         break;
182                 }
183                 if (curs)
184                 {
185                     bReturn = (*curs->cb)(x11, &event, w, curs->data);
186                 }
187             }
188         }
189     }
190 }
191
192 static void RegisterCallback(t_x11 *x11, Window w, Window Parent,
193                              CallBack cb, void *data)
194 {
195     t_wlist *curs, *item;
196
197     snew(item, 1);
198     item->w      = w;
199     item->Parent = Parent;
200     item->cb     = cb;
201     item->mask   = 0;
202     item->data   = data;
203     item->next   = NULL;
204
205     if (x11->wlist)
206     {
207         curs = x11->wlist;
208         while (curs->next)
209         {
210             curs = curs->next;
211         }
212         curs->next = item;
213     }
214     else
215     {
216         x11->wlist = item;
217     }
218 }
219
220 static void UnRegisterCallback(t_x11 *x11, Window w)
221 {
222     t_wlist *curs;
223
224     curs = x11->wlist;
225     if (curs)
226     {
227         if (curs->w == w)
228         {
229             x11->wlist = curs->next;
230             sfree(curs);
231         }
232         else
233         {
234             while (curs->next && (curs->next->w != w))
235             {
236                 curs = curs->next;
237             }
238             if (curs->next)
239             {
240                 t_wlist *tmp = curs->next;
241
242                 curs->next = curs->next->next;
243                 sfree(tmp);
244             }
245         }
246     }
247 }
248
249 static void SetInputMask(t_x11 *x11, Window w, unsigned long mask)
250 {
251     t_wlist *curs;
252
253     curs = GetWList(x11, w);
254     if (curs)
255     {
256         curs->mask = mask;
257         XSelectInput(x11->disp, w, (long)mask);
258     }
259     else
260     {
261         fprintf(x11->console, "No such window (%d)\n", (int)w);
262     }
263 }
264
265 static unsigned long GetInputMask(t_x11 *x11, Window w)
266 {
267     t_wlist *curs;
268
269     curs = GetWList(x11, w);
270     if (curs)
271     {
272         return curs->mask;
273     }
274     else
275     {
276         return 0;
277     }
278 }
279
280 static void CleanUp(t_x11 *x11)
281 {
282     t_wlist *curs;
283
284     curs = x11->wlist;
285     while (curs)
286     {
287         x11->wlist = curs->next;
288         XDestroyWindow(x11->disp, curs->w);
289         sfree(curs);
290         curs = x11->wlist;
291     }
292     XCloseDisplay(x11->disp);
293 }
294
295 static void Flush(t_x11 *x11)
296 {
297     fflush(x11->console);
298 }
299
300 t_x11 *GetX11(int *argc, char *argv[])
301 {
302     static const char *v_name[] = {
303         "DirectColor", "TrueColor", "PseudoColor",
304         "StaticColor", "GrayScale", "StaticGray"
305     };
306     static int         v_class[] = {
307         DirectColor, TrueColor, PseudoColor,
308         StaticColor, GrayScale, StaticGray
309     };
310 #define NCLASS (sizeof(v_class)/sizeof(v_class[0]))
311
312     XVisualInfo     v_info;
313     t_x11          *x11;
314     int             ARGC;
315     char          **ARGV;
316     char           *display;
317     char           *fontname;
318     char           *title, *FG = NULL, *BG = NULL;
319     bool            bVerbose = false;
320     int             i;
321
322     title = gmx_strdup(argv[0]);
323
324     /* First check environment */
325     fontname = getenv("GMX_FONT");
326     display  = getenv("DISPLAY");
327
328     snew(ARGV, *argc);
329     ARGC = 1;
330     for (i = 1; (i < *argc); i++)
331     {
332         if (argv[i][0] == '-')
333         {
334             if (strlen(argv[i]) > 1)
335             {
336                 if ((*argc) > i+1)
337                 {
338                     switch (argv[i][1])
339                     {
340                         case 'b':
341                             BG = argv[++i];
342                             break;
343                         case 'd':
344                             display = argv[++i];
345                             break;
346                         case 'f':
347                             switch (argv[i][2])
348                             {
349                                 case 'o':
350                                     fontname = argv[++i];
351                                     break;
352                                 case 'g':
353                                     FG = argv[++i];
354                                     break;
355                             }
356                             break;
357                         case 't':
358                             sfree(title);
359                             title = gmx_strdup(argv[++i]);
360                             break;
361                         case 'v':
362                             bVerbose = true;
363                             break;
364                         default:
365                             ARGV[ARGC++] = argv[i];
366                             break;
367                     }
368                 }
369             }
370         }
371         else
372         {
373             ARGV[ARGC++] = argv[i];
374         }
375     }
376     for (i = 1; (i < ARGC); i++)
377     {
378         argv[i] = ARGV[i];
379     }
380     *argc      = ARGC;
381     argv[ARGC] = NULL;
382
383     snew(x11, 1);
384     x11->dispname = display;
385     if (bVerbose)
386     {
387         x11->console = stderr;
388     }
389     else
390     if ((x11->console = fopen("/dev/null", "w")) == NULL)
391     {
392         x11->console = stderr;
393     }
394
395     if ((x11->disp = XOpenDisplay(display)) == NULL)
396     {
397         if (bVerbose)
398         {
399             fprintf(x11->console, "Display %s invalid\n", display);
400         }
401         return NULL;
402     }
403
404     if ((x11->font = GetFont(x11->console, x11->disp, fontname)) == NULL)
405     {
406         return NULL;
407     }
408     if ((x11->gc = GetGC(x11->disp, x11->font)) == NULL)
409     {
410         return NULL;
411     }
412
413     x11->root   = DefaultRootWindow(x11->disp);
414     x11->screen = DefaultScreen(x11->disp);
415     x11->depth  = DefaultDepth(x11->disp, x11->screen);
416     x11->cmap   = DefaultColormap(x11->disp, x11->screen);
417
418     /* These colours will be mapped to black on a monochrome screen */
419     x11->fg = BLACK = BLUE = GREEN = CYAN = RED = BROWN = GREY = DARKGREY =
420                                         BlackPixel(x11->disp, x11->screen);
421
422     /* These colours will be mapped to white on a monochrome screen */
423     x11->bg       =
424         LIGHTBLUE = LIGHTGREY = LIGHTGREEN = LIGHTCYAN = LIGHTRED = VIOLET = YELLOW = WHITE =
425                                         WhitePixel(x11->disp, x11->screen);
426
427     if (x11->depth > 1)
428     {
429         /* Not B & W, Look what kind of screen we've got... */
430         for (i = 0; (i < (int)NCLASS); i++)
431         {
432             if (!XMatchVisualInfo(x11->disp, x11->screen, x11->depth,
433                                   v_class[i], &v_info))
434             {
435                 break;
436             }
437         }
438         if ((i == 4) || (i == 5))
439         {
440             fprintf(x11->console, "Greyscale screen, using B & W only\n");
441         }
442         else
443         {
444             /* We have real color! */
445             fprintf(x11->console, "%s screen with depth %d.\n",
446                     (i == NCLASS) ? "Unknown" : v_name[i], x11->depth);
447             GetNamedColor(x11, "midnight blue", &BLUE);
448             GetNamedColor(x11, "DarkGreen", &GREEN);
449             GetNamedColor(x11, "SeaGreen", &CYAN);
450             GetNamedColor(x11, "red4", &RED);
451             GetNamedColor(x11, "Gray", &GREY);
452             GetNamedColor(x11, "Gray", &DARKGREY);
453             GetNamedColor(x11, "LightGray", &LIGHTGREY);
454             GetNamedColor(x11, "green", &LIGHTGREEN);
455             GetNamedColor(x11, "cyan", &LIGHTCYAN);
456             GetNamedColor(x11, "tomato1", &LIGHTRED);
457             GetNamedColor(x11, "violet", &VIOLET);
458             GetNamedColor(x11, "yellow", &YELLOW);
459             GetNamedColor(x11, "brown", &BROWN);
460             GetNamedColor(x11, "CornFlowerBlue", &LIGHTBLUE);
461         }
462     }
463     else
464     {
465         fprintf(x11->console, "Monochrome screen.\n");
466     }
467
468     /* We should use Xrm here... */
469     if (FG)
470     {
471         GetNamedColor(x11, FG, &(x11->fg));
472     }
473     else
474     {
475         x11->fg = BLACK;
476     }
477     if (BG)
478     {
479         GetNamedColor(x11, BG, &(x11->bg));
480     }
481     else
482     {
483         x11->bg = LIGHTGREY;
484     }
485     x11->title = gmx_strdup(title);
486     sfree(title);
487     x11->wlist              = NULL;
488     x11->GetNamedColor      = &GetNamedColor;
489     x11->MainLoop           = &MainLoop;
490     x11->RegisterCallback   = &RegisterCallback;
491     x11->UnRegisterCallback = &UnRegisterCallback;
492     x11->SetInputMask       = &SetInputMask;
493     x11->GetInputMask       = &GetInputMask;
494     x11->CleanUp            = &CleanUp;
495     x11->Flush              = &Flush;
496
497     x11->Flush(x11);
498
499     return x11;
500 }