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