b403a9e71b5ac96c7850108df398b05d3f3ee87d
[alexxy/gromacs.git] / src / programs / view / xdlg.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-2004, The GROMACS development team.
6  * Copyright (c) 2013,2014,2015,2017,2019, 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 "xdlg.h"
40
41 #include <cstdio>
42 #include <cstdlib>
43 #include <cstring>
44
45 #include "gromacs/utility/cstringutil.h"
46 #include "gromacs/utility/fatalerror.h"
47 #include "gromacs/utility/smalloc.h"
48
49 #include "Xstuff.h"
50 #include "xmb.h"
51 #include "xutil.h"
52 /*****************************
53  *
54  * Helpful routines
55  *
56  ****************************/
57 t_dlgitem* FindItem(t_dlg* dlg, t_id id)
58 {
59     int i;
60
61     for (i = 0; (i < dlg->nitem); i++)
62     {
63         if (dlg->dlgitem[i]->ID == id)
64         {
65             return dlg->dlgitem[i];
66         }
67     }
68     return nullptr;
69 }
70
71 t_dlgitem* FindWin(t_dlg* dlg, Window win)
72 {
73     int i;
74
75     for (i = 0; (i < dlg->nitem); i++)
76     {
77         if (dlg->dlgitem[i]->win.self == win)
78         {
79             return dlg->dlgitem[i];
80         }
81     }
82     return nullptr;
83 }
84
85 /*****************************
86  *
87  * Routines to manipulate items on a dialog box
88  *
89  ****************************/
90 bool QueryDlgItemSize(t_dlg* dlg, t_id id, int* w, int* h)
91 {
92     t_dlgitem* dlgitem;
93
94     if ((dlgitem = FindItem(dlg, id)) != nullptr)
95     {
96         *w = dlgitem->win.width;
97         *h = dlgitem->win.height;
98         return true;
99     }
100     return false;
101 }
102
103 bool QueryDlgItemPos(t_dlg* dlg, t_id id, int* x0, int* y0)
104 {
105     t_dlgitem* dlgitem;
106
107     if ((dlgitem = FindItem(dlg, id)) != nullptr)
108     {
109         *x0 = dlgitem->win.x;
110         *y0 = dlgitem->win.y;
111         return true;
112     }
113     return false;
114 }
115
116 int QueryDlgItemX(t_dlg* dlg, t_id id)
117 {
118     t_dlgitem* dlgitem;
119
120     if ((dlgitem = FindItem(dlg, id)) != nullptr)
121     {
122         return dlgitem->win.x;
123     }
124     return 0;
125 }
126
127 int QueryDlgItemY(t_dlg* dlg, t_id id)
128 {
129     t_dlgitem* dlgitem;
130
131     if ((dlgitem = FindItem(dlg, id)) != nullptr)
132     {
133         return dlgitem->win.y;
134     }
135     return 0;
136 }
137
138 int QueryDlgItemW(t_dlg* dlg, t_id id)
139 {
140     t_dlgitem* dlgitem;
141
142     if ((dlgitem = FindItem(dlg, id)) != nullptr)
143     {
144         return dlgitem->win.width;
145     }
146     return 0;
147 }
148
149 int QueryDlgItemH(t_dlg* dlg, t_id id)
150 {
151     t_dlgitem* dlgitem;
152
153     if ((dlgitem = FindItem(dlg, id)) != nullptr)
154     {
155         return dlgitem->win.height;
156     }
157     return 0;
158 }
159
160 bool SetDlgItemSize(t_dlg* dlg, t_id id, int w, int h)
161 {
162     t_dlgitem* dlgitem;
163 #ifdef DEBUG
164     int old_w, old_h;
165 #endif
166
167     if ((dlgitem = FindItem(dlg, id)) != nullptr)
168     {
169 #ifdef DEBUG
170         old_w = dlgitem->win.width;
171         old_h = dlgitem->win.height;
172 #endif
173         if (w)
174         {
175             dlgitem->win.width = w;
176         }
177         if (h)
178         {
179             dlgitem->win.height = h;
180         }
181 #ifdef DEBUG
182         std::fprintf(dlg->x11->console, "Size window from: %dx%d to %dx%d\n", old_w, old_h,
183                      dlgitem->win.width, dlgitem->win.height);
184         dlg->x11->Flush(dlg->x11);
185 #endif
186         if (dlgitem->win.self)
187         {
188             XResizeWindow(dlg->x11->disp, dlgitem->win.self, dlgitem->win.width, dlgitem->win.height);
189         }
190         if ((w) && (dlgitem->type == edlgGB))
191         {
192             int  i;
193             t_id gid = dlgitem->GroupID;
194             t_id id  = dlgitem->ID;
195             for (i = 0; (i < dlg->nitem); i++)
196             {
197                 t_dlgitem* child = dlg->dlgitem[i];
198                 if ((child->GroupID == gid) && (child->ID != id))
199                 {
200                     SetDlgItemSize(dlg, child->ID, w - 4 * OFFS_X, 0);
201                 }
202             }
203         }
204         return true;
205     }
206     return false;
207 }
208
209 bool SetDlgItemPos(t_dlg* dlg, t_id id, int x0, int y0)
210 {
211     t_dlgitem* dlgitem;
212     int        old_x, old_y;
213
214     if ((dlgitem = FindItem(dlg, id)) != nullptr)
215     {
216         old_x          = dlgitem->win.x;
217         old_y          = dlgitem->win.y;
218         dlgitem->win.x = x0;
219         dlgitem->win.y = y0;
220 #ifdef DEBUG
221         std::fprintf(dlg->x11->console, "Move window from: %d,%d to %d,%d\n", old_x, old_y, x0, y0);
222         dlg->x11->Flush(dlg->x11);
223 #endif
224         if (dlgitem->win.self)
225         {
226             XMoveWindow(dlg->x11->disp, dlgitem->win.self, x0, y0);
227         }
228         if (dlgitem->type == edlgGB)
229         {
230             int  i, x, y;
231             t_id gid = dlgitem->GroupID;
232             t_id id  = dlgitem->ID;
233             x        = dlgitem->win.x + 2 * OFFS_X - old_x;
234             y        = dlgitem->win.y + 2 * OFFS_Y - old_y;
235             for (i = 0; (i < dlg->nitem); i++)
236             {
237                 t_dlgitem* child = dlg->dlgitem[i];
238                 if ((child->GroupID == gid) && (child->ID != id))
239                 {
240                     SetDlgItemPos(dlg, child->ID, child->win.x + x, child->win.y + y);
241                 }
242             }
243         }
244         return true;
245     }
246     return false;
247 }
248
249 /*****************************
250  *
251  * Routines to extract information from the dlg proc
252  * after dlg is exec'ed
253  *
254  ****************************/
255 bool IsCBChecked(t_dlg* dlg, t_id id)
256 {
257     t_dlgitem* dlgitem;
258
259     if ((dlgitem = FindItem(dlg, id)) != nullptr)
260     {
261         if (dlgitem->type == edlgCB)
262         {
263             return dlgitem->u.checkbox.bChecked;
264         }
265     }
266
267     return false;
268 }
269
270 t_id RBSelected(t_dlg* dlg, int gid)
271 {
272     int i;
273
274     for (i = 0; (i < dlg->nitem); i++)
275     {
276         if ((dlg->dlgitem[i]->type == edlgRB) && (dlg->dlgitem[i]->u.radiobutton.bSelect)
277             && (dlg->dlgitem[i]->GroupID == gid))
278         {
279             return dlg->dlgitem[i]->ID;
280         }
281     }
282
283     return -1;
284 }
285
286 int EditTextLen(t_dlg* dlg, t_id id)
287 {
288     t_dlgitem* dlgitem;
289
290     if ((dlgitem = FindItem(dlg, id)) != nullptr)
291     {
292         if (dlgitem->type == edlgET)
293         {
294             return std::strlen(dlgitem->u.edittext.buf);
295         }
296     }
297
298     return 0;
299 }
300
301 char* EditText(t_dlg* dlg, t_id id)
302 {
303     t_dlgitem* dlgitem;
304
305     if ((dlgitem = FindItem(dlg, id)) != nullptr)
306     {
307         if (dlgitem->type == edlgET)
308         {
309             return dlgitem->u.edittext.buf;
310         }
311     }
312
313     return nullptr;
314 }
315
316 /*****************************
317  *
318  * Exececute the dialog box procedure
319  * Returns when a button is pushed.
320  * return value is the ID of the button
321  *
322  ****************************/
323 void ShowDlg(t_dlg* dlg)
324 {
325     int        i;
326     t_dlgitem* dlgitem;
327
328     XMapWindow(dlg->x11->disp, dlg->win.self);
329     XMapSubwindows(dlg->x11->disp, dlg->win.self);
330     for (i = 0; (i < dlg->nitem); i++)
331     {
332         LightBorder(dlg->x11->disp, dlg->dlgitem[i]->win.self, dlg->bg);
333     }
334     XSetForeground(dlg->x11->disp, dlg->x11->gc, dlg->x11->fg);
335     for (i = 0; (i < dlg->nitem); i++)
336     {
337         dlgitem = dlg->dlgitem[i];
338         if ((dlgitem->type == edlgBN) && (dlgitem->u.button.bDefault))
339         {
340             PushMouse(dlg->x11->disp, dlgitem->win.self, dlgitem->win.width / 2, dlgitem->win.height / 2);
341             dlg->bPop = true;
342             break;
343         }
344     }
345     dlg->bGrab = false;
346 }
347
348 void HideDlg(t_dlg* dlg)
349 {
350     if (dlg->bPop)
351     {
352         PopMouse(dlg->x11->disp);
353     }
354
355     XUnmapSubwindows(dlg->x11->disp, dlg->win.self);
356     XUnmapWindow(dlg->x11->disp, dlg->win.self);
357 }
358
359 void NoHelp(t_dlg* dlg)
360 {
361     const char* lines[2] = { "Error", "No help for this item" };
362     MessageBox(dlg->x11, dlg->wDad, "No Help", 2, lines, MB_OK | MB_ICONSTOP | MB_APPLMODAL,
363                nullptr, nullptr);
364 }
365
366 void HelpDlg(t_dlg* dlg)
367 {
368     const char* lines[] = { "Place the cursor over one of the items",
369                             "and press the F1 key to get more help.", "First press the OK button." };
370     MessageBox(dlg->x11, dlg->win.self, "Help Dialogbox", 3, lines,
371                MB_OK | MB_ICONINFORMATION | MB_APPLMODAL, nullptr, nullptr);
372 }
373
374 void HelpNow(t_dlg* dlg, t_dlgitem* dlgitem)
375 {
376     char   buf[80];
377     bool   bCont = true;
378     int    i, nlines = 0;
379     char** lines = nullptr;
380
381     if (!dlgitem->help)
382     {
383         NoHelp(dlg);
384         return;
385     }
386
387     std::printf("%s\n", dlgitem->help);
388     do
389     {
390         fgets2(buf, 79, stdin);
391 #ifdef DEBUG
392         std::fprintf(dlg->x11->console, "buffer: '%s'\n", buf);
393         dlg->x11->Flush(dlg->x11);
394 #endif
395         if (gmx_strcasecmp(buf, "nok") == 0)
396         {
397             /* An error occurred */
398             if (lines)
399             {
400                 for (i = 0; (i < nlines); i++)
401                 {
402                     sfree(lines[i]);
403                 }
404                 sfree(lines);
405             }
406             NoHelp(dlg);
407             return;
408         }
409         else
410         {
411             bCont = (gmx_strcasecmp(buf, "ok") != 0);
412             if (bCont)
413             {
414                 srenew(lines, ++nlines);
415                 lines[nlines - 1] = gmx_strdup(buf);
416             }
417         }
418     } while (bCont);
419     MessageBox(dlg->x11, dlg->wDad, "Help", nlines, lines,
420                MB_OK | MB_ICONINFORMATION | MB_APPLMODAL, nullptr, nullptr);
421     for (i = 0; (i < nlines); i++)
422     {
423         sfree(lines[i]);
424     }
425     sfree(lines);
426 }
427
428 static void EnterDlg(t_dlg* dlg)
429 {
430     if (dlg->flags & DLG_APPLMODAL)
431     {
432         dlg->bGrab = GrabOK(dlg->x11->console,
433                             XGrabPointer(dlg->x11->disp, dlg->win.self, True, 0, GrabModeAsync,
434                                          GrabModeAsync, dlg->win.self, None, CurrentTime));
435     }
436     dlg->x11->Flush(dlg->x11);
437 }
438
439 static void ExitDlg(t_dlg* dlg)
440 {
441     if (dlg->bGrab)
442     {
443         XUngrabPointer(dlg->x11->disp, CurrentTime);
444         dlg->bGrab = false;
445     }
446     HideDlg(dlg);
447     if (dlg->flags & DLG_FREEONBUTTON)
448     {
449         FreeDlg(dlg);
450     }
451 }
452
453 static bool DlgCB(t_x11* x11, XEvent* event, Window w, void* data)
454 {
455     t_dlg*     dlg = (t_dlg*)data;
456     int        i, nWndProc;
457     t_dlgitem* dlgitem;
458
459     if ((dlgitem = FindWin(dlg, w)) != nullptr)
460     {
461         nWndProc = (dlgitem->WndProc)(x11, dlgitem, event);
462 #ifdef DEBUG
463         std::fprintf(x11->console, "window: %s, nWndProc: %d\n", dlgitem->win.text, nWndProc);
464         x11->Flush(x11);
465 #endif
466         switch (nWndProc)
467         {
468             case ENTERPRESSED:
469                 if ((dlgitem->type == edlgBN) && (dlgitem->u.button.bDefault))
470                 {
471                     if (dlg->cb)
472                     {
473                         dlg->cb(x11, DLG_EXIT, dlgitem->ID, dlgitem->win.text, dlg->data);
474                     }
475                     else
476                     {
477                         ExitDlg(dlg);
478                     }
479                 }
480                 else
481                 {
482                     for (i = 0; (i < dlg->nitem); i++)
483                     {
484                         if ((dlg->dlgitem[i]->type == edlgBN) && (dlg->dlgitem[i]->u.button.bDefault))
485                         {
486                             PushMouse(x11->disp, dlg->dlgitem[i]->win.self,
487                                       dlg->dlgitem[i]->win.width / 2, dlg->dlgitem[i]->win.height / 2);
488                             break;
489                         }
490                     }
491                 }
492                 break;
493             case BNPRESSED:
494                 if (dlg->cb)
495                 {
496                     dlg->cb(x11, DLG_EXIT, dlgitem->ID, dlgitem->win.text, dlg->data);
497                 }
498                 else
499                 {
500                     ExitDlg(dlg);
501                 }
502                 break;
503             case RBPRESSED:
504             {
505                 int  gid = dlgitem->GroupID;
506                 t_id tid = RBSelected(dlg, gid);
507 #ifdef DEBUG
508                 std::fprintf(stderr, "RBPRESSED\n");
509 #endif
510                 if (tid != -1)
511                 {
512                     t_dlgitem* dit             = FindItem(dlg, tid);
513                     dit->u.radiobutton.bSelect = false;
514                     ExposeWin(x11->disp, dit->win.self);
515                 }
516                 else
517                 {
518                     gmx_fatal(FARGS, "No RB Selected initially!\n");
519                 }
520                 dlgitem->u.radiobutton.bSelect = true;
521                 ExposeWin(x11->disp, dlgitem->win.self);
522                 if (dlg->cb)
523                 {
524                     dlg->cb(x11, DLG_SET, dlgitem->ID, dlgitem->win.text, dlg->data);
525                 }
526                 break;
527             }
528             case CBPRESSED:
529                 ExposeWin(x11->disp, dlgitem->win.self);
530                 if (dlg->cb)
531                 {
532                     dlg->cb(x11, DLG_SET, dlgitem->ID, dlgitem->set, dlg->data);
533                 }
534                 break;
535             case ETCHANGED:
536                 ExposeWin(x11->disp, dlgitem->win.self);
537                 if (dlg->cb)
538                 {
539                     dlg->cb(x11, DLG_SET, dlgitem->ID, dlgitem->u.edittext.buf, dlg->data);
540                 }
541                 break;
542             case HELPPRESSED: HelpNow(dlg, dlgitem); break;
543             case ITEMOK: break;
544             default: gmx_fatal(FARGS, "Invalid return code (%d) from wndproc\n", nWndProc);
545         }
546     }
547     else if (w == dlg->win.self)
548     {
549         switch (event->type)
550         {
551             case Expose: EnterDlg(dlg); break;
552             case ButtonPress:
553             case KeyPress:
554                 if (HelpPressed(event))
555                 {
556                     HelpDlg(dlg);
557                 }
558                 else
559                 {
560                     XBell(x11->disp, 50);
561                 }
562                 break;
563             default: break;
564         }
565     }
566     return false;
567 }
568
569 /*****************************
570  *
571  * Routine to add an item to the dialog box
572  * The pointer to the item is copied to the dlg struct,
573  * the item itself may not be freed until the dlg is done with
574  *
575  ****************************/
576 static void DoCreateDlg(t_dlg* dlg)
577 {
578     XSizeHints           hints;
579     XSetWindowAttributes attr;
580     unsigned long        Val;
581
582     attr.border_pixel      = dlg->x11->fg;
583     attr.background_pixel  = dlg->bg;
584     attr.override_redirect = False;
585     attr.save_under        = True;
586     attr.cursor            = XCreateFontCursor(dlg->x11->disp, XC_hand2);
587     Val           = CWBackPixel | CWBorderPixel | CWOverrideRedirect | CWSaveUnder | CWCursor;
588     dlg->win.self = XCreateWindow(dlg->x11->disp, dlg->wDad, dlg->win.x, dlg->win.y, dlg->win.width,
589                                   dlg->win.height, dlg->win.bwidth, CopyFromParent, InputOutput,
590                                   CopyFromParent, Val, &attr);
591     dlg->x11->RegisterCallback(dlg->x11, dlg->win.self, dlg->wDad, DlgCB, dlg);
592     dlg->x11->SetInputMask(dlg->x11, dlg->win.self, ExposureMask | ButtonPressMask | KeyPressMask);
593
594     if (!CheckWindow(dlg->win.self))
595     {
596         std::exit(1);
597     }
598     hints.x     = dlg->win.x;
599     hints.y     = dlg->win.y;
600     hints.flags = PPosition;
601     XSetStandardProperties(dlg->x11->disp, dlg->win.self, dlg->title, dlg->title, None, nullptr, 0, &hints);
602 }
603
604 void AddDlgItem(t_dlg* dlg, t_dlgitem* item)
605 {
606 #define EnterLeaveMask (EnterWindowMask | LeaveWindowMask)
607 #define UserMask (ButtonPressMask | KeyPressMask)
608     static unsigned long InputMask[edlgNR] = {
609         ExposureMask | UserMask | EnterLeaveMask, /* edlgBN */
610         ExposureMask | UserMask | EnterLeaveMask, /* edlgRB */
611         ExposureMask,                             /* edlgGB */
612         ExposureMask | UserMask | EnterLeaveMask, /* edlgCB */
613         0,                                        /* edlgPM */
614         ExposureMask,                             /* edlgST */
615         ExposureMask | UserMask | EnterLeaveMask  /* edlgET */
616     };
617
618     if (!dlg->win.self)
619     {
620         DoCreateDlg(dlg);
621     }
622     srenew(dlg->dlgitem, dlg->nitem + 1);
623     if (!item)
624     {
625         gmx_fatal(FARGS, "dlgitem not allocated");
626     }
627     item->win.self = XCreateSimpleWindow(dlg->x11->disp, dlg->win.self, item->win.x, item->win.y,
628                                          item->win.width, item->win.height, item->win.bwidth,
629                                          dlg->x11->fg, dlg->x11->bg);
630     CheckWindow(item->win.self);
631
632     dlg->x11->RegisterCallback(dlg->x11, item->win.self, dlg->win.self, DlgCB, dlg);
633     dlg->x11->SetInputMask(dlg->x11, item->win.self, InputMask[item->type]);
634
635     switch (item->type)
636     {
637         case edlgPM:
638             XSetWindowBackgroundPixmap(dlg->x11->disp, item->win.self, item->u.pixmap.pm);
639             break;
640         default: break;
641     }
642     dlg->dlgitem[dlg->nitem] = item;
643
644     dlg->nitem++;
645 }
646
647 void AddDlgItems(t_dlg* dlg, int nitem, t_dlgitem* item[])
648 {
649     int i;
650
651     for (i = 0; (i < nitem); i++)
652     {
653 #ifdef DEBUG
654         std::fprintf(dlg->x11->console, "Adding item: %d from group %d\n", item[i]->ID, item[i]->GroupID);
655         dlg->x11->Flush(dlg->x11);
656 #endif
657         AddDlgItem(dlg, item[i]);
658     }
659 }
660
661 void FreeDlgItem(t_dlg* dlg, t_id id)
662 {
663     t_dlgitem* dlgitem;
664     int        i;
665
666     if ((dlgitem = FindItem(dlg, id)) != nullptr)
667     {
668         dlg->x11->UnRegisterCallback(dlg->x11, dlgitem->win.self);
669         if (dlgitem->win.self)
670         {
671             XDestroyWindow(dlg->x11->disp, dlgitem->win.self);
672         }
673         FreeWin(dlg->x11->disp, &(dlgitem->win));
674         switch (dlgitem->type)
675         {
676             case edlgBN:
677             case edlgRB: break;
678             case edlgGB: sfree(dlgitem->u.groupbox.item); break;
679             case edlgCB: break;
680             case edlgPM: XFreePixmap(dlg->x11->disp, dlgitem->u.pixmap.pm); break;
681             case edlgST:
682                 for (i = 0; (i < dlgitem->u.statictext.nlines); i++)
683                 {
684                     sfree(dlgitem->u.statictext.lines[i]);
685                 }
686                 sfree(dlgitem->u.statictext.lines);
687                 break;
688             case edlgET: sfree(dlgitem->u.edittext.buf); break;
689             default: break;
690         }
691     }
692 }
693
694 void FreeDlg(t_dlg* dlg)
695 {
696     int i;
697
698     if (dlg->dlgitem)
699     {
700         HideDlg(dlg);
701         dlg->x11->UnRegisterCallback(dlg->x11, dlg->win.self);
702         for (i = 0; (i < dlg->nitem); i++)
703         {
704             FreeDlgItem(dlg, dlg->dlgitem[i]->ID);
705             if (dlg->dlgitem[i])
706             {
707                 sfree(dlg->dlgitem[i]);
708             }
709         }
710         sfree(dlg->dlgitem);
711         if (dlg->win.self)
712         {
713             XDestroyWindow(dlg->x11->disp, dlg->win.self);
714         }
715         dlg->dlgitem = nullptr;
716     }
717 }
718
719 /*****************************
720  *
721  * Routine to create the DLG structure, returns NULL on failure
722  *
723  ****************************/
724 t_dlg* CreateDlg(t_x11* x11, Window Parent, const char* title, int x0, int y0, int w, int h, int bw, DlgCallback* cb, void* data)
725 {
726     t_dlg* dlg;
727     int    x = 0, y = 0;
728
729     snew(dlg, 1);
730     dlg->x11  = x11;
731     dlg->cb   = cb;
732     dlg->data = data;
733     if (title)
734     {
735         dlg->title = gmx_strdup(title);
736     }
737     else
738     {
739         dlg->title = nullptr;
740     }
741     if (w == 0)
742     {
743         w = 1;
744     }
745     if (h == 0)
746     {
747         h = 1;
748     }
749     if (!Parent)
750     {
751         Parent    = x11->root;
752         dlg->xmax = DisplayWidth(x11->disp, x11->screen);
753         dlg->ymax = DisplayHeight(x11->disp, x11->screen);
754     }
755     else
756     {
757         Window       root;
758         unsigned int dum;
759
760         XGetGeometry(x11->disp, Parent, &root, &x, &y, &(dlg->xmax), &(dlg->ymax), &dum, &dum);
761 #ifdef DEBUG
762         std::fprintf(x11->console, "Daddy is %d x %d at %d, %d\n", dlg->xmax, dlg->ymax, x, y);
763         dlg->x11->Flush(dlg->x11);
764 #endif
765     }
766     if (x0)
767     {
768         x = x0;
769     }
770     if (y0)
771     {
772         y = y0;
773     }
774     InitWin(&(dlg->win), x, y, w, h, bw, nullptr);
775     SetDlgSize(dlg, w, h, x0 || y0);
776
777     dlg->wDad    = Parent;
778     dlg->fg      = x11->fg;
779     dlg->bg      = x11->bg;
780     dlg->nitem   = 0;
781     dlg->dlgitem = nullptr;
782
783     DoCreateDlg(dlg);
784     return dlg;
785 }
786
787 void SetDlgSize(t_dlg* dlg, int w, int h, bool bAutoPosition)
788 {
789     if (bAutoPosition)
790     {
791         int x, y;
792
793         x          = (dlg->xmax - w) / 2;
794         y          = (dlg->ymax - h) / 2;
795         dlg->win.x = x;
796         dlg->win.y = y;
797     }
798     dlg->win.width  = w;
799     dlg->win.height = h;
800
801 #ifdef DEBUG
802     std::fprintf(dlg->x11->console, "SetDlgSize: Dialog is %dx%d, at %d,%d\n", dlg->win.width,
803                  dlg->win.height, dlg->win.x, dlg->win.y);
804     dlg->x11->Flush(dlg->x11);
805 #endif
806     if (dlg->win.self)
807     {
808         XMoveWindow(dlg->x11->disp, dlg->win.self, dlg->win.x, dlg->win.y);
809         XResizeWindow(dlg->x11->disp, dlg->win.self, w, h);
810     }
811 }