xref: /petsc/src/sys/classes/draw/impls/x/xinit.c (revision c3e4dd79e17d3f0a51a524340fae4661630fd09e)
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",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 {
42   PetscFunctionBegin;
43   if (!XiWin) PetscFunctionReturn(0);
44   PetscCall(PetscFree(XiWin->font));
45   if (XiWin->disp) {
46 #if defined(PETSC_HAVE_SETJMP_H)
47     jmp_buf              jmpbuf;
48     PetscXIOErrorHandler 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(0);
64 }
65 
66 /*
67    PetscDrawXiCreateGC - setup the GC structure
68 */
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(0);
83 }
84 
85 /*
86    PetscDrawXiInit - basic setup the draw (display, graphics context, font)
87 */
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(0);
95 }
96 
97 /*
98     This routine waits until the window is actually created or destroyed
99     Returns 0 if window is mapped; 1 if window is destroyed.
100  */
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         PetscFunctionReturn(1);
118       case Expose:
119         PetscFunctionReturn(0);
120         /* else ignore event */
121       }
122     }
123   }
124   PetscFunctionReturn(0);
125 }
126 
127 /*
128     Actually display a window at [x,y] with sizes (w,h)
129 */
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 |
176           CWWinGravity | CWBackingStore | CWBackingPixel  | CWOverrideRedirect |
177           CWSaveUnder  | CWEventMask    | CWDontPropagate |
178           CWCursor     | CWColormap;
179 
180   XiWin->win = XCreateWindow(XiWin->disp,RootWindow(XiWin->disp,XiWin->screen),x,y,w,h,border_width,XiWin->depth,InputOutput,XiWin->vis,wmask,&window_attributes);
181   PetscCheck(XiWin->win,PETSC_COMM_SELF,PETSC_ERR_LIB,"Unable to open X window");
182 
183   /* set window manager hints */
184   {
185     XWMHints      wm_hints;
186     XClassHint    class_hints;
187     XTextProperty windowname,iconname;
188 
189     if (label) XStringListToTextProperty(&label,1,&windowname);
190     else       XStringListToTextProperty(&label,0,&windowname);
191     if (label) XStringListToTextProperty(&label,1,&iconname);
192     else       XStringListToTextProperty(&label,0,&iconname);
193 
194     wm_hints.initial_state = NormalState;
195     wm_hints.input         = True;
196     wm_hints.flags         = StateHint|InputHint;
197 
198     /* These properties can be used by window managers to decide how to display a window */
199     class_hints.res_name  = (char*)"petsc";
200     class_hints.res_class = (char*)"PETSc";
201 
202     size_hints.x          = x;
203     size_hints.y          = y;
204     size_hints.min_width  = 4*border_width;
205     size_hints.min_height = 4*border_width;
206     size_hints.width      = w;
207     size_hints.height     = h;
208     size_hints.flags      = USPosition | USSize | PMinSize;
209 
210     XSetWMProperties(XiWin->disp,XiWin->win,&windowname,&iconname,NULL,0,&size_hints,&wm_hints,&class_hints);
211     XFree((void*)windowname.value);
212     XFree((void*)iconname.value);
213   }
214 
215   /* make the window visible */
216   XSelectInput(XiWin->disp,XiWin->win,ExposureMask|StructureNotifyMask);
217   XMapWindow(XiWin->disp,XiWin->win);
218   /* some window systems are cruel and interfere with the placement of
219      windows.  We wait here for the window to be created or to die */
220   PetscCall(PetscDrawXiWaitMap(XiWin));
221   XSelectInput(XiWin->disp,XiWin->win,NoEventMask);
222   PetscFunctionReturn(0);
223 }
224 
225 PetscErrorCode PetscDrawXiQuickWindow(PetscDraw_X *XiWin,char *name,int x,int y,int nx,int ny)
226 {
227   PetscFunctionBegin;
228   PetscCall(PetscDrawSetColormap_X(XiWin,(Colormap)0));
229   PetscCall(PetscDrawXiDisplayWindow(XiWin,name,x,y,nx,ny));
230   XSetWindowBackground(XiWin->disp,XiWin->win,XiWin->background);
231   XClearWindow(XiWin->disp,XiWin->win);
232   PetscFunctionReturn(0);
233 }
234 
235 /*
236    A version from an already defined window
237 */
238 PetscErrorCode PetscDrawXiQuickWindowFromWindow(PetscDraw_X *XiWin,Window win)
239 {
240   XWindowAttributes attributes;
241 
242   PetscFunctionBegin;
243   XiWin->win = win;
244   XGetWindowAttributes(XiWin->disp,XiWin->win,&attributes);
245   PetscCall(PetscDrawSetColormap_X(XiWin,attributes.colormap));
246   PetscFunctionReturn(0);
247 }
248 
249 PetscErrorCode PetscDrawXiQuickPixmap(PetscDraw_X* XiWin)
250 {
251   PetscFunctionBegin;
252   if (XiWin->drw) XFreePixmap(XiWin->disp,XiWin->drw);
253   XiWin->drw = XCreatePixmap(XiWin->disp,RootWindow(XiWin->disp,XiWin->screen),XiWin->w,XiWin->h,XiWin->depth);
254   PetscDrawXiSetPixVal(XiWin,XiWin->background);
255   XFillRectangle(XiWin->disp,XiWin->drw,XiWin->gc.set,0,0,XiWin->w,XiWin->h);
256   XSync(XiWin->disp,False);
257   PetscFunctionReturn(0);
258 }
259 
260 PetscErrorCode PetscDrawXiResizeWindow(PetscDraw_X* XiWin,int w,int h)
261 {
262   XEvent event;
263   PetscFunctionBegin;
264   XSelectInput(XiWin->disp,XiWin->win,StructureNotifyMask);
265   XResizeWindow(XiWin->disp,XiWin->win,(unsigned int)w,(unsigned int)h);
266   XWindowEvent(XiWin->disp,XiWin->win,StructureNotifyMask,&event);
267   XSelectInput(XiWin->disp,XiWin->win,NoEventMask);
268   PetscFunctionReturn(0);
269 }
270 
271 PetscErrorCode PetscDrawXiGetGeometry(PetscDraw_X *XiWin,int *x,int *y,int *w,int *h)
272 {
273   XWindowAttributes attributes;
274   Window            root,parent,child;
275   int               xx=0,yy=0;
276   unsigned int      ww=0,hh=0,dummy;
277   PetscFunctionBegin;
278   if (XiWin->win) {
279     XGetGeometry(XiWin->disp,XiWin->win,&parent,&xx,&yy,&ww,&hh,&dummy,&dummy);
280     root = RootWindow(XiWin->disp,XiWin->screen);
281     if (!XTranslateCoordinates(XiWin->disp,XiWin->win,root,0,0,&xx,&yy,&child)) {
282       XGetWindowAttributes(XiWin->disp,XiWin->win,&attributes);
283       root = attributes.screen->root;
284       (void)XTranslateCoordinates(XiWin->disp,XiWin->win,root,0,0,&xx,&yy,&child);
285     }
286   } else if (XiWin->drw) {
287     XGetGeometry(XiWin->disp,XiWin->drw,&root,&xx,&yy,&ww,&hh,&dummy,&dummy);
288   }
289   if (x) *x = xx;
290   if (y) *y = yy;
291   if (w) *w = (int)ww;
292   if (h) *h = (int)hh;
293   PetscFunctionReturn(0);
294 }
295