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