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