xref: /petsc/src/sys/classes/draw/impls/x/xinit.c (revision d71ae5a4db6382e7f06317b8d368875286fe9008)
1 
2 /*
3    This file contains routines to open an X window display and window
4    This consists of a number of routines that set the various
5    fields in the Window structure, which is passed to
6    all of these routines.
7 
8    Note that if you use the default visual and colormap, then you
9    can use these routines with any X toolkit that will give you the
10    Window id of the window that it is managing.  Use that instead of the
11    call to PetscDrawXiCreateWindow .  Similarly for the Display.
12 */
13 
14 #include <../src/sys/classes/draw/impls/x/ximpl.h>
15 
16 PETSC_INTERN PetscErrorCode PetscDrawSetColormap_X(PetscDraw_X *, Colormap);
17 
18 /*
19   PetscDrawXiOpenDisplay - Open and setup a display
20 */
21 static PetscErrorCode PetscDrawXiOpenDisplay(PetscDraw_X *XiWin, const char display[])
22 {
23   PetscFunctionBegin;
24   XiWin->disp = XOpenDisplay(display);
25   if (!XiWin->disp) {
26     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Unable to open display on %s\n\
27     Make sure your COMPUTE NODES are authorized to connect \n\
28     to this X server and either your DISPLAY variable\n\
29     is set or you use the -display name option\n",
30             display);
31   }
32   XiWin->screen     = DefaultScreen(XiWin->disp);
33   XiWin->vis        = DefaultVisual(XiWin->disp, XiWin->screen);
34   XiWin->depth      = DefaultDepth(XiWin->disp, XiWin->screen);
35   XiWin->cmap       = DefaultColormap(XiWin->disp, XiWin->screen);
36   XiWin->background = WhitePixel(XiWin->disp, XiWin->screen);
37   XiWin->foreground = BlackPixel(XiWin->disp, XiWin->screen);
38   PetscFunctionReturn(0);
39 }
40 
41 PetscErrorCode PetscDrawXiClose(PetscDraw_X *XiWin)
42 {
43   PetscFunctionBegin;
44   if (!XiWin) PetscFunctionReturn(0);
45   PetscCall(PetscFree(XiWin->font));
46   if (XiWin->disp) {
47 #if defined(PETSC_HAVE_SETJMP_H)
48     jmp_buf              jmpbuf;
49     PetscXIOErrorHandler xioerrhdl;
50     PetscCall(PetscMemcpy(&jmpbuf, &PetscXIOErrorHandlerJumpBuf, sizeof(jmpbuf)));
51     xioerrhdl = PetscSetXIOErrorHandler(PetscXIOErrorHandlerJump);
52     if (!setjmp(PetscXIOErrorHandlerJumpBuf))
53 #endif
54     {
55       XFreeGC(XiWin->disp, XiWin->gc.set);
56       XCloseDisplay(XiWin->disp);
57     }
58     XiWin->disp = NULL;
59 #if defined(PETSC_HAVE_SETJMP_H)
60     (void)PetscSetXIOErrorHandler(xioerrhdl);
61     PetscCall(PetscMemcpy(&PetscXIOErrorHandlerJumpBuf, &jmpbuf, sizeof(jmpbuf)));
62 #endif
63   }
64   PetscFunctionReturn(0);
65 }
66 
67 /*
68    PetscDrawXiCreateGC - setup the GC structure
69 */
70 static PetscErrorCode PetscDrawXiCreateGC(PetscDraw_X *XiWin, PetscDrawXiPixVal fg)
71 {
72   XGCValues gcvalues; /* window graphics context values */
73 
74   PetscFunctionBegin;
75   /* Set the graphics contexts */
76   /* create a gc for the ROP_SET operation (writing the fg value to a pixel) */
77   /* (do this with function GXcopy; GXset will automatically write 1) */
78   gcvalues.function   = GXcopy;
79   gcvalues.foreground = fg;
80   XiWin->gc.cur_pix   = fg;
81   XiWin->gc.set       = XCreateGC(XiWin->disp, RootWindow(XiWin->disp, XiWin->screen), GCFunction | GCForeground, &gcvalues);
82   PetscCheck(XiWin->gc.set, PETSC_COMM_SELF, PETSC_ERR_LIB, "Unable to create X graphics context");
83   PetscFunctionReturn(0);
84 }
85 
86 /*
87    PetscDrawXiInit - basic setup the draw (display, graphics context, font)
88 */
89 PetscErrorCode PetscDrawXiInit(PetscDraw_X *XiWin, const char display[])
90 {
91   PetscFunctionBegin;
92   PetscCall(PetscDrawXiOpenDisplay(XiWin, display));
93   PetscCall(PetscDrawXiCreateGC(XiWin, XiWin->foreground));
94   PetscCall(PetscDrawXiFontFixed(XiWin, 6, 10, &XiWin->font));
95   PetscFunctionReturn(0);
96 }
97 
98 /*
99     This routine waits until the window is actually created. If the window was
100     never mapped it generates an error
101 */
102 static PetscErrorCode PetscDrawXiWaitMap(PetscDraw_X *XiWin)
103 {
104   XEvent event;
105 
106   PetscFunctionBegin;
107   while (1) {
108     XMaskEvent(XiWin->disp, ExposureMask | StructureNotifyMask, &event);
109     if (event.xany.window != XiWin->win) break;
110     else {
111       switch (event.type) {
112       case ConfigureNotify:
113         /* window has been moved or resized */
114         XiWin->w = event.xconfigure.width - 2 * event.xconfigure.border_width;
115         XiWin->h = event.xconfigure.height - 2 * event.xconfigure.border_width;
116         break;
117       case DestroyNotify:
118         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Window was not properly created");
119       case Expose:
120         PetscFunctionReturn(0);
121         /* else ignore event */
122       }
123     }
124   }
125   PetscFunctionReturn(0);
126 }
127 
128 /*
129     Actually display a window at [x,y] with sizes (w,h)
130 */
131 static PetscErrorCode PetscDrawXiDisplayWindow(PetscDraw_X *XiWin, char *label, int x, int y, int w, int h)
132 {
133   unsigned int         wavail, havail;
134   XSizeHints           size_hints;
135   XWindowAttributes    in_window_attributes;
136   XSetWindowAttributes window_attributes;
137   unsigned int         border_width  = 0;
138   unsigned long        backgnd_pixel = WhitePixel(XiWin->disp, XiWin->screen);
139   unsigned long        wmask;
140 
141   PetscFunctionBegin;
142   /* get the available widths */
143   wavail = DisplayWidth(XiWin->disp, XiWin->screen);
144   havail = DisplayHeight(XiWin->disp, XiWin->screen);
145   PetscCheck(w > 0 && h > 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "X Window display has invalid height or width");
146   if ((unsigned int)w > wavail) w = wavail;
147   if ((unsigned int)h > havail) h = havail;
148 
149   if (x < 0) x = (int)(wavail - (unsigned int)w + (unsigned int)x);
150   if (y < 0) y = (int)(havail - (unsigned int)h + (unsigned int)y);
151   x = ((unsigned int)x + w > wavail) ? (int)(wavail - (unsigned int)w) : x;
152   y = ((unsigned int)y + h > havail) ? (int)(havail - (unsigned int)h) : y;
153 
154   /* We need XCreateWindow since we may need an visual other than the default one */
155   XGetWindowAttributes(XiWin->disp, RootWindow(XiWin->disp, XiWin->screen), &in_window_attributes);
156   window_attributes.background_pixmap = None;
157   window_attributes.background_pixel  = backgnd_pixel;
158   /* No border for now */
159   window_attributes.border_pixmap = None;
160   /*
161   window_attributes.border_pixel      = border_pixel;
162   */
163   window_attributes.bit_gravity = in_window_attributes.bit_gravity;
164   window_attributes.win_gravity = in_window_attributes.win_gravity;
165   /* Backing store is too slow in color systems */
166   window_attributes.backing_store         = NotUseful;
167   window_attributes.backing_pixel         = backgnd_pixel;
168   window_attributes.save_under            = 1;
169   window_attributes.event_mask            = 0;
170   window_attributes.do_not_propagate_mask = 0;
171   window_attributes.override_redirect     = 0;
172   window_attributes.colormap              = XiWin->cmap;
173   /* None for cursor does NOT mean none, it means cursor of Parent */
174   window_attributes.cursor = None;
175 
176   wmask = CWBackPixmap | CWBackPixel | CWBorderPixmap | CWBitGravity | CWWinGravity | CWBackingStore | CWBackingPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask | CWDontPropagate | CWCursor | CWColormap;
177 
178   XiWin->win = XCreateWindow(XiWin->disp, RootWindow(XiWin->disp, XiWin->screen), x, y, w, h, border_width, XiWin->depth, InputOutput, XiWin->vis, wmask, &window_attributes);
179   PetscCheck(XiWin->win, PETSC_COMM_SELF, PETSC_ERR_LIB, "Unable to open X window");
180 
181   /* set window manager hints */
182   {
183     XWMHints      wm_hints;
184     XClassHint    class_hints;
185     XTextProperty windowname, iconname;
186 
187     if (label) XStringListToTextProperty(&label, 1, &windowname);
188     else XStringListToTextProperty(&label, 0, &windowname);
189     if (label) XStringListToTextProperty(&label, 1, &iconname);
190     else XStringListToTextProperty(&label, 0, &iconname);
191 
192     wm_hints.initial_state = NormalState;
193     wm_hints.input         = True;
194     wm_hints.flags         = StateHint | InputHint;
195 
196     /* These properties can be used by window managers to decide how to display a window */
197     class_hints.res_name  = (char *)"petsc";
198     class_hints.res_class = (char *)"PETSc";
199 
200     size_hints.x          = x;
201     size_hints.y          = y;
202     size_hints.min_width  = 4 * border_width;
203     size_hints.min_height = 4 * border_width;
204     size_hints.width      = w;
205     size_hints.height     = h;
206     size_hints.flags      = USPosition | USSize | PMinSize;
207 
208     XSetWMProperties(XiWin->disp, XiWin->win, &windowname, &iconname, NULL, 0, &size_hints, &wm_hints, &class_hints);
209     XFree((void *)windowname.value);
210     XFree((void *)iconname.value);
211   }
212 
213   /* make the window visible */
214   XSelectInput(XiWin->disp, XiWin->win, ExposureMask | StructureNotifyMask);
215   XMapWindow(XiWin->disp, XiWin->win);
216   /* some window systems are cruel and interfere with the placement of
217      windows.  We wait here for the window to be created or to die */
218   PetscCall(PetscDrawXiWaitMap(XiWin));
219   XSelectInput(XiWin->disp, XiWin->win, NoEventMask);
220   PetscFunctionReturn(0);
221 }
222 
223 PetscErrorCode PetscDrawXiQuickWindow(PetscDraw_X *XiWin, char *name, int x, int y, int nx, int ny)
224 {
225   PetscFunctionBegin;
226   PetscCall(PetscDrawSetColormap_X(XiWin, (Colormap)0));
227   PetscCall(PetscDrawXiDisplayWindow(XiWin, name, x, y, nx, ny));
228   XSetWindowBackground(XiWin->disp, XiWin->win, XiWin->background);
229   XClearWindow(XiWin->disp, XiWin->win);
230   PetscFunctionReturn(0);
231 }
232 
233 /*
234    A version from an already defined window
235 */
236 PetscErrorCode PetscDrawXiQuickWindowFromWindow(PetscDraw_X *XiWin, Window win)
237 {
238   XWindowAttributes attributes;
239 
240   PetscFunctionBegin;
241   XiWin->win = win;
242   XGetWindowAttributes(XiWin->disp, XiWin->win, &attributes);
243   PetscCall(PetscDrawSetColormap_X(XiWin, attributes.colormap));
244   PetscFunctionReturn(0);
245 }
246 
247 PetscErrorCode PetscDrawXiQuickPixmap(PetscDraw_X *XiWin)
248 {
249   PetscFunctionBegin;
250   if (XiWin->drw) XFreePixmap(XiWin->disp, XiWin->drw);
251   XiWin->drw = XCreatePixmap(XiWin->disp, RootWindow(XiWin->disp, XiWin->screen), XiWin->w, XiWin->h, XiWin->depth);
252   PetscDrawXiSetPixVal(XiWin, XiWin->background);
253   XFillRectangle(XiWin->disp, XiWin->drw, XiWin->gc.set, 0, 0, XiWin->w, XiWin->h);
254   XSync(XiWin->disp, False);
255   PetscFunctionReturn(0);
256 }
257 
258 PetscErrorCode PetscDrawXiResizeWindow(PetscDraw_X *XiWin, int w, int h)
259 {
260   XEvent event;
261   PetscFunctionBegin;
262   XSelectInput(XiWin->disp, XiWin->win, StructureNotifyMask);
263   XResizeWindow(XiWin->disp, XiWin->win, (unsigned int)w, (unsigned int)h);
264   XWindowEvent(XiWin->disp, XiWin->win, StructureNotifyMask, &event);
265   XSelectInput(XiWin->disp, XiWin->win, NoEventMask);
266   PetscFunctionReturn(0);
267 }
268 
269 PetscErrorCode PetscDrawXiGetGeometry(PetscDraw_X *XiWin, int *x, int *y, int *w, int *h)
270 {
271   XWindowAttributes attributes;
272   Window            root, parent, child;
273   int               xx = 0, yy = 0;
274   unsigned int      ww = 0, hh = 0, dummy;
275   PetscFunctionBegin;
276   if (XiWin->win) {
277     XGetGeometry(XiWin->disp, XiWin->win, &parent, &xx, &yy, &ww, &hh, &dummy, &dummy);
278     root = RootWindow(XiWin->disp, XiWin->screen);
279     if (!XTranslateCoordinates(XiWin->disp, XiWin->win, root, 0, 0, &xx, &yy, &child)) {
280       XGetWindowAttributes(XiWin->disp, XiWin->win, &attributes);
281       root = attributes.screen->root;
282       (void)XTranslateCoordinates(XiWin->disp, XiWin->win, root, 0, 0, &xx, &yy, &child);
283     }
284   } else if (XiWin->drw) {
285     XGetGeometry(XiWin->disp, XiWin->drw, &root, &xx, &yy, &ww, &hh, &dummy, &dummy);
286   }
287   if (x) *x = xx;
288   if (y) *y = yy;
289   if (w) *w = (int)ww;
290   if (h) *h = (int)hh;
291   PetscFunctionReturn(0);
292 }
293