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