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