xref: /petsc/src/sys/classes/draw/impls/x/xops.c (revision 6a5217c03994f2d95bb2e6dbd8bed42381aeb015)
1 /*
2     Defines the operations for the X PetscDraw implementation.
3 */
4 
5 #include <../src/sys/classes/draw/impls/x/ximpl.h>         /*I  "petscsys.h" I*/
6 
7 /*
8      These macros transform from the users coordinates to the  X-window pixel coordinates.
9 */
10 #define XTRANS(draw,xwin,x)  ((int)(((xwin)->w-1)*((draw)->port_xl + (((x - (draw)->coor_xl)*((draw)->port_xr - (draw)->port_xl))/((draw)->coor_xr - (draw)->coor_xl)))))
11 #define YTRANS(draw,xwin,y)  (((xwin)->h-1) - (int)(((xwin)->h-1)*((draw)->port_yl + (((y - (draw)->coor_yl)*((draw)->port_yr - (draw)->port_yl))/((draw)->coor_yr - (draw)->coor_yl)))))
12 
13 #define ITRANS(draw,xwin,i)  ((draw)->coor_xl + (((PetscReal)(i))*((draw)->coor_xr - (draw)->coor_xl)/((xwin)->w-1) - (draw)->port_xl)/((draw)->port_xr - (draw)->port_xl))
14 #define JTRANS(draw,xwin,j)  ((draw)->coor_yl + (((PetscReal)(j))/((xwin)->h-1) + (draw)->port_yl - 1)*((draw)->coor_yr - (draw)->coor_yl)/((draw)->port_yl - (draw)->port_yr))
15 
16 static PetscErrorCode PetscDrawSetViewport_X(PetscDraw draw,PetscReal xl,PetscReal yl,PetscReal xr,PetscReal yr)
17 {
18   PetscDraw_X    *XiWin = (PetscDraw_X*)draw->data;
19   int            xa,ya,xb,yb,xmax = XiWin->w-1,ymax = XiWin->h-1;
20   XRectangle     box;
21   PetscErrorCode ierr;
22 
23   PetscFunctionBegin;
24   xa = (int)(xl*xmax); ya = ymax - (int)(yr*ymax);
25   xb = (int)(xr*xmax); yb = ymax - (int)(yl*ymax);
26   ierr = PetscDrawCollectiveBegin(draw);PetscCall(ierr);
27   box.x = (short)xa; box.width  = (unsigned short)(xb + 1 - xa);
28   box.y = (short)ya; box.height = (unsigned short)(yb + 1 - ya);
29   XSetClipRectangles(XiWin->disp,XiWin->gc.set,0,0,&box,1,Unsorted);
30   ierr = PetscDrawCollectiveEnd(draw);PetscCall(ierr);
31   PetscFunctionReturn(0);
32 }
33 
34 static PetscErrorCode PetscDrawCoordinateToPixel_X(PetscDraw draw,PetscReal x,PetscReal y,int *i,int *j)
35 {
36   PetscDraw_X *XiWin = (PetscDraw_X*)draw->data;
37 
38   PetscFunctionBegin;
39   *i = XTRANS(draw,XiWin,x);
40   *j = YTRANS(draw,XiWin,y);
41   PetscFunctionReturn(0);
42 }
43 
44 static PetscErrorCode PetscDrawPixelToCoordinate_X(PetscDraw draw,int i,int j,PetscReal *x,PetscReal *y)
45 {
46   PetscDraw_X *XiWin = (PetscDraw_X*)draw->data;
47 
48   PetscFunctionBegin;
49   *x = ITRANS(draw,XiWin,i);
50   *y = JTRANS(draw,XiWin,j);
51   PetscFunctionReturn(0);
52 }
53 
54 static PetscErrorCode PetscDrawPoint_X(PetscDraw draw,PetscReal x,PetscReal y,int c)
55 {
56   PetscDraw_X *XiWin = (PetscDraw_X*)draw->data;
57   int         xx,yy,i,j;
58 
59   PetscFunctionBegin;
60   xx = XTRANS(draw,XiWin,x);
61   yy = YTRANS(draw,XiWin,y);
62   PetscDrawXiSetColor(XiWin,c);
63   for (i=-1; i<2; i++) {
64     for (j=-1; j<2; j++) {
65       XDrawPoint(XiWin->disp,PetscDrawXiDrawable(XiWin),XiWin->gc.set,xx+i,yy+j);
66     }
67   }
68   PetscFunctionReturn(0);
69 }
70 
71 static PetscErrorCode PetscDrawPointPixel_X(PetscDraw draw,int x,int y,int c)
72 {
73   PetscDraw_X *XiWin = (PetscDraw_X*)draw->data;
74 
75   PetscFunctionBegin;
76   PetscDrawXiSetColor(XiWin,c);
77   XDrawPoint(XiWin->disp,PetscDrawXiDrawable(XiWin),XiWin->gc.set,x,y);
78   PetscFunctionReturn(0);
79 }
80 
81 static PetscErrorCode PetscDrawLine_X(PetscDraw draw,PetscReal xl,PetscReal yl,PetscReal xr,PetscReal yr,int cl)
82 {
83   PetscDraw_X *XiWin = (PetscDraw_X*)draw->data;
84   int         x_1,y_1,x_2,y_2;
85 
86   PetscFunctionBegin;
87   PetscDrawXiSetColor(XiWin,cl);
88   x_1 = XTRANS(draw,XiWin,xl); x_2  = XTRANS(draw,XiWin,xr);
89   y_1 = YTRANS(draw,XiWin,yl); y_2  = YTRANS(draw,XiWin,yr);
90   XDrawLine(XiWin->disp,PetscDrawXiDrawable(XiWin),XiWin->gc.set,x_1,y_1,x_2,y_2);
91   PetscFunctionReturn(0);
92 }
93 
94 static PetscErrorCode PetscDrawArrow_X(PetscDraw draw,PetscReal xl,PetscReal yl,PetscReal xr,PetscReal yr,int cl)
95 {
96   PetscDraw_X *XiWin = (PetscDraw_X*)draw->data;
97   int         x_1,y_1,x_2,y_2;
98 
99   PetscFunctionBegin;
100   PetscDrawXiSetColor(XiWin,cl);
101   x_1 = XTRANS(draw,XiWin,xl); x_2 = XTRANS(draw,XiWin,xr);
102   y_1 = YTRANS(draw,XiWin,yl); y_2 = YTRANS(draw,XiWin,yr);
103   XDrawLine(XiWin->disp,PetscDrawXiDrawable(XiWin),XiWin->gc.set,x_1,y_1,x_2,y_2);
104   if (x_1 == x_2 && y_1 == y_2) PetscFunctionReturn(0);
105   if (x_1 == x_2 && PetscAbs(y_1 - y_2) > 7) {
106     if (y_2 > y_1) {
107       XDrawLine(XiWin->disp,PetscDrawXiDrawable(XiWin),XiWin->gc.set,x_2,y_2,x_2-3,y_2-3);
108       XDrawLine(XiWin->disp,PetscDrawXiDrawable(XiWin),XiWin->gc.set,x_2,y_2,x_2+3,y_2-3);
109     } else {
110       XDrawLine(XiWin->disp,PetscDrawXiDrawable(XiWin),XiWin->gc.set,x_2,y_2,x_2-3,y_2+3);
111       XDrawLine(XiWin->disp,PetscDrawXiDrawable(XiWin),XiWin->gc.set,x_2,y_2,x_2+3,y_2+3);
112     }
113   }
114   if (y_1 == y_2 && PetscAbs(x_1 - x_2) > 7) {
115     if (x_2 > x_1) {
116       XDrawLine(XiWin->disp,PetscDrawXiDrawable(XiWin),XiWin->gc.set,x_2-3,y_2-3,x_2,y_2);
117       XDrawLine(XiWin->disp,PetscDrawXiDrawable(XiWin),XiWin->gc.set,x_2-3,y_2+3,x_2,y_2);
118     } else {
119       XDrawLine(XiWin->disp,PetscDrawXiDrawable(XiWin),XiWin->gc.set,x_2,y_2,x_2+3,y_2-3);
120       XDrawLine(XiWin->disp,PetscDrawXiDrawable(XiWin),XiWin->gc.set,x_2,y_2,x_2+3,y_2+3);
121     }
122   }
123   PetscFunctionReturn(0);
124 }
125 
126 static PetscErrorCode PetscDrawRectangle_X(PetscDraw draw,PetscReal xl,PetscReal yl,PetscReal xr,PetscReal yr,int c1,int c2,int c3,int c4)
127 {
128   PetscDraw_X *XiWin = (PetscDraw_X*)draw->data;
129   int         x,y,w,h,c = (c1 + c2 + c3 + c4)/4;
130 
131   PetscFunctionBegin;
132   PetscDrawXiSetColor(XiWin,c);
133   x = XTRANS(draw,XiWin,xl); w = XTRANS(draw,XiWin,xr) + 1 - x; if (w <= 0) w = 1;
134   y = YTRANS(draw,XiWin,yr); h = YTRANS(draw,XiWin,yl) + 1 - y; if (h <= 0) h = 1;
135   XFillRectangle(XiWin->disp,PetscDrawXiDrawable(XiWin),XiWin->gc.set,x,y,w,h);
136   PetscFunctionReturn(0);
137 }
138 
139 static PetscErrorCode PetscDrawEllipse_X(PetscDraw draw,PetscReal x,PetscReal y,PetscReal a,PetscReal b,int c)
140 {
141   PetscDraw_X *XiWin = (PetscDraw_X*)draw->data;
142   int         xA,yA,w,h;
143 
144   PetscFunctionBegin;
145   PetscDrawXiSetColor(XiWin, c);
146   xA = XTRANS(draw,XiWin, x - a/2); w = XTRANS(draw,XiWin, x + a/2) + 1 - xA; w = PetscAbs(w);
147   yA = YTRANS(draw,XiWin, y + b/2); h = YTRANS(draw,XiWin, y - b/2) + 1 - yA; h = PetscAbs(h);
148   XFillArc(XiWin->disp,PetscDrawXiDrawable(XiWin),XiWin->gc.set,xA,yA,w,h,0,360*64);
149   PetscFunctionReturn(0);
150 }
151 
152 PETSC_INTERN PetscErrorCode PetscDrawInterpolatedTriangle_X(PetscDraw_X*,int,int,int,int,int,int,int,int,int);
153 
154 static PetscErrorCode PetscDrawTriangle_X(PetscDraw draw,PetscReal X1,PetscReal Y_1,PetscReal X2,PetscReal Y2,PetscReal X3,PetscReal Y3,int c1,int c2,int c3)
155 {
156   PetscDraw_X *XiWin = (PetscDraw_X*)draw->data;
157 
158   PetscFunctionBegin;
159   if (c1 == c2 && c2 == c3) {
160     XPoint pt[3];
161     PetscDrawXiSetColor(XiWin,c1);
162     pt[0].x = XTRANS(draw,XiWin,X1);
163     pt[0].y = YTRANS(draw,XiWin,Y_1);
164     pt[1].x = XTRANS(draw,XiWin,X2);
165     pt[1].y = YTRANS(draw,XiWin,Y2);
166     pt[2].x = XTRANS(draw,XiWin,X3);
167     pt[2].y = YTRANS(draw,XiWin,Y3);
168     XFillPolygon(XiWin->disp,PetscDrawXiDrawable(XiWin),XiWin->gc.set,pt,3,Convex,CoordModeOrigin);
169   } else {
170     int x1,y_1,x2,y2,x3,y3;
171     x1   = XTRANS(draw,XiWin,X1);
172     y_1  = YTRANS(draw,XiWin,Y_1);
173     x2   = XTRANS(draw,XiWin,X2);
174     y2   = YTRANS(draw,XiWin,Y2);
175     x3   = XTRANS(draw,XiWin,X3);
176     y3   = YTRANS(draw,XiWin,Y3);
177     PetscCall(PetscDrawInterpolatedTriangle_X(XiWin,x1,y_1,c1,x2,y2,c2,x3,y3,c3));
178   }
179   PetscFunctionReturn(0);
180 }
181 
182 static PetscErrorCode PetscDrawStringSetSize_X(PetscDraw draw,PetscReal x,PetscReal y)
183 {
184   PetscDraw_X *XiWin = (PetscDraw_X*)draw->data;
185   int          w,h;
186 
187   PetscFunctionBegin;
188   w    = (int)((XiWin->w)*x*(draw->port_xr - draw->port_xl)/(draw->coor_xr - draw->coor_xl));
189   h    = (int)((XiWin->h)*y*(draw->port_yr - draw->port_yl)/(draw->coor_yr - draw->coor_yl));
190   PetscCall(PetscFree(XiWin->font));
191   PetscCall(PetscDrawXiFontFixed(XiWin,w,h,&XiWin->font));
192   PetscFunctionReturn(0);
193 }
194 
195 static PetscErrorCode PetscDrawStringGetSize_X(PetscDraw draw,PetscReal *x,PetscReal  *y)
196 {
197   PetscDraw_X *XiWin = (PetscDraw_X*)draw->data;
198   PetscReal   w,h;
199 
200   PetscFunctionBegin;
201   w = XiWin->font->font_w; h = XiWin->font->font_h;
202   if (x) *x = w*(draw->coor_xr - draw->coor_xl)/((XiWin->w)*(draw->port_xr - draw->port_xl));
203   if (y) *y = h*(draw->coor_yr - draw->coor_yl)/((XiWin->h)*(draw->port_yr - draw->port_yl));
204   PetscFunctionReturn(0);
205 }
206 
207 static PetscErrorCode PetscDrawString_X(PetscDraw draw,PetscReal x,PetscReal y,int c,const char chrs[])
208 {
209   PetscDraw_X *XiWin         = (PetscDraw_X*)draw->data;
210   int          xx,yy,descent = XiWin->font->font_descent;
211   size_t       len;
212   char        *substr;
213   PetscToken   token;
214 
215   PetscFunctionBegin;
216   xx = XTRANS(draw,XiWin,x);
217   yy = YTRANS(draw,XiWin,y);
218   PetscDrawXiSetColor(XiWin,c);
219 
220   PetscCall(PetscTokenCreate(chrs,'\n',&token));
221   PetscCall(PetscTokenFind(token,&substr));
222   while (substr) {
223     PetscCall(PetscStrlen(substr,&len));
224     XDrawString(XiWin->disp,PetscDrawXiDrawable(XiWin),XiWin->gc.set,xx,yy-descent,substr,len);
225     yy  += XiWin->font->font_h;
226     PetscCall(PetscTokenFind(token,&substr));
227   }
228   PetscCall(PetscTokenDestroy(&token));
229   PetscFunctionReturn(0);
230 }
231 
232 static PetscErrorCode PetscDrawStringVertical_X(PetscDraw draw,PetscReal x,PetscReal y,int c,const char text[])
233 {
234   PetscDraw_X    *XiWin = (PetscDraw_X*)draw->data;
235   int            xx,yy,offset = XiWin->font->font_h - XiWin->font->font_descent;
236   char           chr[2] = {0, 0};
237 
238   PetscFunctionBegin;
239   xx = XTRANS(draw,XiWin,x);
240   yy = YTRANS(draw,XiWin,y);
241   PetscDrawXiSetColor(XiWin,c);
242   while ((chr[0] = *text++)) {
243     XDrawString(XiWin->disp,PetscDrawXiDrawable(XiWin),XiWin->gc.set,xx,yy+offset,chr,1);
244     yy += XiWin->font->font_h;
245   }
246   PetscFunctionReturn(0);
247 }
248 
249 static PetscErrorCode PetscDrawFlush_X(PetscDraw draw)
250 {
251   PetscDraw_X    *XiWin = (PetscDraw_X*)draw->data;
252   PetscMPIInt    rank;
253   PetscErrorCode ierr;
254 
255   PetscFunctionBegin;
256   /* make sure the X server processed requests from all processes */
257   ierr = PetscDrawCollectiveBegin(draw);PetscCall(ierr);
258   XSync(XiWin->disp,False);
259   ierr = PetscDrawCollectiveEnd(draw);PetscCall(ierr);
260   PetscCallMPI(MPI_Barrier(PetscObjectComm((PetscObject)draw)));
261 
262   /* transfer pixmap contents to window (only the first process does this) */
263   if (XiWin->drw && XiWin->win) {
264     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)draw),&rank));
265     ierr = PetscDrawCollectiveBegin(draw);PetscCall(ierr);
266     if (rank == 0) XCopyArea(XiWin->disp,XiWin->drw,XiWin->win,XiWin->gc.set,0,0,XiWin->w,XiWin->h,0,0);
267     if (rank == 0) XSync(XiWin->disp,False);
268     ierr = PetscDrawCollectiveEnd(draw);PetscCall(ierr);
269     PetscCallMPI(MPI_Barrier(PetscObjectComm((PetscObject)draw)));
270   }
271   PetscFunctionReturn(0);
272 }
273 
274 static PetscErrorCode PetscDrawClear_X(PetscDraw draw)
275 {
276   PetscDraw_X    *XiWin = (PetscDraw_X*)draw->data;
277   int            xmax = XiWin->w-1,  ymax = XiWin->h-1;
278   PetscReal      xl = draw->port_xl, yl = draw->port_yl;
279   PetscReal      xr = draw->port_xr, yr = draw->port_yr;
280   PetscMPIInt    rank;
281   PetscErrorCode ierr;
282 
283   PetscFunctionBegin;
284   /* make sure the X server processed requests from all processes */
285   ierr = PetscDrawCollectiveBegin(draw);PetscCall(ierr);
286   XSync(XiWin->disp,False);
287   ierr = PetscDrawCollectiveEnd(draw);PetscCall(ierr);
288   PetscCallMPI(MPI_Barrier(PetscObjectComm((PetscObject)draw)));
289 
290   /* only the first process handles the clearing business */
291   ierr = PetscDrawCollectiveBegin(draw);PetscCall(ierr);
292   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)draw),&rank));
293   if (rank == 0) {
294     int xa = (int)(xl*xmax), ya = ymax - (int)(yr*ymax);
295     int xb = (int)(xr*xmax), yb = ymax - (int)(yl*ymax);
296     unsigned int w = (unsigned int)(xb + 1 - xa);
297     unsigned int h = (unsigned int)(yb + 1 - ya);
298     PetscDrawXiSetPixVal(XiWin,XiWin->background);
299     XFillRectangle(XiWin->disp,PetscDrawXiDrawable(XiWin),XiWin->gc.set,xa,ya,w,h);
300     XSync(XiWin->disp,False);
301   }
302   ierr = PetscDrawCollectiveEnd(draw);PetscCall(ierr);
303   PetscCallMPI(MPI_Barrier(PetscObjectComm((PetscObject)draw)));
304   PetscFunctionReturn(0);
305 }
306 
307 static PetscErrorCode PetscDrawSetDoubleBuffer_X(PetscDraw draw)
308 {
309   PetscDraw_X    *win = (PetscDraw_X*)draw->data;
310   PetscMPIInt    rank;
311   PetscErrorCode ierr;
312 
313   PetscFunctionBegin;
314   if (win->drw) PetscFunctionReturn(0);
315   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)draw),&rank));
316 
317   ierr = PetscDrawCollectiveBegin(draw);PetscCall(ierr);
318   if (rank == 0) PetscCall(PetscDrawXiQuickPixmap(win));
319   ierr = PetscDrawCollectiveEnd(draw);PetscCall(ierr);
320   PetscCallMPI(MPI_Bcast(&win->drw,1,MPI_UNSIGNED_LONG,0,PetscObjectComm((PetscObject)draw)));
321   PetscFunctionReturn(0);
322 }
323 
324 static PetscErrorCode PetscDrawGetPopup_X(PetscDraw draw,PetscDraw *popup)
325 {
326   PetscDraw_X *win = (PetscDraw_X*)draw->data;
327   PetscBool    flg = PETSC_TRUE;
328 
329   PetscFunctionBegin;
330   PetscCall(PetscOptionsGetBool(((PetscObject)draw)->options,((PetscObject)draw)->prefix,"-draw_popup",&flg,NULL));
331   if (!flg || !win->win) {*popup = NULL; PetscFunctionReturn(0);}
332 
333   PetscCall(PetscDrawCreate(PetscObjectComm((PetscObject)draw),draw->display,NULL,win->x,win->y+win->h+10,220,220,popup));
334   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*popup,"popup_"));
335   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*popup,((PetscObject)draw)->prefix));
336   PetscCall(PetscDrawSetType(*popup,PETSC_DRAW_X));
337   draw->popup = *popup;
338   PetscFunctionReturn(0);
339 }
340 
341 static PetscErrorCode PetscDrawSetTitle_X(PetscDraw draw,const char title[])
342 {
343   PetscDraw_X    *win = (PetscDraw_X*)draw->data;
344   PetscMPIInt    rank;
345   PetscErrorCode ierr;
346 
347   PetscFunctionBegin;
348   if (!win->win) PetscFunctionReturn(0);
349   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)draw),&rank));
350   ierr = PetscDrawCollectiveBegin(draw);PetscCall(ierr);
351   if (rank == 0) {
352     size_t        len;
353     XTextProperty prop;
354     PetscCall(PetscStrlen(title,&len));
355     XGetWMName(win->disp,win->win,&prop);
356     XFree((void*)prop.value);
357     prop.value  = (unsigned char*)title;
358     prop.nitems = (long)len;
359     XSetWMName(win->disp,win->win,&prop);
360   }
361   ierr = PetscDrawCollectiveEnd(draw);PetscCall(ierr);
362   PetscFunctionReturn(0);
363 }
364 
365 static PetscErrorCode PetscDrawCheckResizedWindow_X(PetscDraw draw)
366 {
367   PetscDraw_X    *win = (PetscDraw_X*)draw->data;
368   int            xywh[4];
369   PetscMPIInt    rank;
370   PetscErrorCode ierr;
371 
372   PetscFunctionBegin;
373   if (!win->win) PetscFunctionReturn(0);
374   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)draw),&rank));
375 
376   ierr = PetscDrawCollectiveBegin(draw);PetscCall(ierr);
377   if (rank == 0) PetscCall(PetscDrawXiGetGeometry(win,xywh,xywh+1,xywh+2,xywh+3));
378   ierr = PetscDrawCollectiveEnd(draw);PetscCall(ierr);
379   PetscCallMPI(MPI_Bcast(xywh,4,MPI_INT,0,PetscObjectComm((PetscObject)draw)));
380 
381   /* record new window position */
382   draw->x = win->x = xywh[0];
383   draw->y = win->y = xywh[1];
384   if (xywh[2] == win->w && xywh[3] == win->h) PetscFunctionReturn(0);
385   /* record new window sizes */
386   draw->w = win->w = xywh[2];
387   draw->h = win->h = xywh[3];
388 
389   /* recreate pixmap (only first processor does this) */
390   ierr = PetscDrawCollectiveBegin(draw);PetscCall(ierr);
391   if (rank == 0 && win->drw) PetscCall(PetscDrawXiQuickPixmap(win));
392   ierr = PetscDrawCollectiveEnd(draw);PetscCall(ierr);
393   PetscCallMPI(MPI_Bcast(&win->drw,1,MPI_UNSIGNED_LONG,0,PetscObjectComm((PetscObject)draw)));
394   /* reset the clipping */
395   PetscCall(PetscDrawSetViewport_X(draw,draw->port_xl,draw->port_yl,draw->port_xr,draw->port_yr));
396   PetscFunctionReturn(0);
397 }
398 
399 static PetscErrorCode PetscDrawResizeWindow_X(PetscDraw draw,int w,int h)
400 {
401   PetscDraw_X    *win = (PetscDraw_X*)draw->data;
402   PetscMPIInt    rank;
403   PetscErrorCode ierr;
404 
405   PetscFunctionBegin;
406   if (w == win->w && h == win->h) PetscFunctionReturn(0);
407   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)draw),&rank));
408 
409   if (win->win) {
410     ierr = PetscDrawCollectiveBegin(draw);PetscCall(ierr);
411     if (rank == 0) PetscCall(PetscDrawXiResizeWindow(win,w,h));
412     ierr = PetscDrawCollectiveEnd(draw);PetscCall(ierr);
413     PetscCall(PetscDrawCheckResizedWindow_X(draw));
414   } else if (win->drw) {
415     draw->w = win->w = w; draw->h = win->h = h;
416     /* recreate pixmap (only first processor does this) */
417     ierr = PetscDrawCollectiveBegin(draw);PetscCall(ierr);
418     if (rank == 0) PetscCall(PetscDrawXiQuickPixmap(win));
419     PetscCallMPI(MPI_Bcast(&win->drw,1,MPI_UNSIGNED_LONG,0,PetscObjectComm((PetscObject)draw)));
420     /* reset the clipping */
421     ierr = PetscDrawCollectiveEnd(draw);PetscCall(ierr);
422     PetscCall(PetscDrawSetViewport_X(draw,draw->port_xl,draw->port_yl,draw->port_xr,draw->port_yr));
423   }
424   PetscFunctionReturn(0);
425 }
426 
427 #include <X11/cursorfont.h>
428 
429 static PetscErrorCode PetscDrawGetMouseButton_X(PetscDraw draw,PetscDrawButton *button,PetscReal *x_user,PetscReal *y_user,PetscReal *x_phys,PetscReal *y_phys)
430 {
431   PetscDraw_X    *win = (PetscDraw_X*)draw->data;
432   Cursor         cursor;
433   XEvent         report;
434   Window         root,child;
435   int            root_x,root_y,px=0,py=0;
436   unsigned int   w,h,border,depth;
437   unsigned int   keys_button;
438   PetscMPIInt    rank;
439   PetscReal      xx,yy;
440   PetscErrorCode ierr;
441 
442   PetscFunctionBegin;
443   *button = PETSC_BUTTON_NONE;
444   if (!win->win) PetscFunctionReturn(0);
445   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)draw),&rank));
446 
447   ierr = PetscDrawCollectiveBegin(draw);PetscCall(ierr);
448   if (rank) goto finally;
449 
450   /* change cursor to indicate input */
451   cursor = XCreateFontCursor(win->disp,XC_hand2); PetscCheck(cursor,PETSC_COMM_SELF,PETSC_ERR_LIB,"Unable to create X cursor");
452   XDefineCursor(win->disp,win->win,cursor);
453   /* wait for mouse button events */
454   XSelectInput(win->disp,win->win,ButtonPressMask|ButtonReleaseMask);
455   while (XCheckTypedEvent(win->disp,ButtonPress,&report));
456   XMaskEvent(win->disp,ButtonReleaseMask,&report);
457   /* get mouse pointer coordinates */
458   XQueryPointer(win->disp,report.xmotion.window,&root,&child,&root_x,&root_y,&px,&py,&keys_button);
459   /* the user may resize the window before pressing the mouse button */
460   XGetGeometry(win->disp,win->win,&root,&root_x,&root_y,&w,&h,&border,&depth);
461   /* cleanup input event handler and cursor  */
462   XSelectInput(win->disp,win->win,NoEventMask);
463   XUndefineCursor(win->disp,win->win);
464   XFreeCursor(win->disp, cursor);
465   XSync(win->disp,False);
466 
467   switch (report.xbutton.button) {
468   case Button1: *button = PETSC_BUTTON_LEFT; break;
469   case Button2: *button = PETSC_BUTTON_CENTER; break;
470   case Button3: *button = PETSC_BUTTON_RIGHT; break;
471   case Button4: *button = PETSC_BUTTON_WHEEL_UP; break;
472   case Button5: *button = PETSC_BUTTON_WHEEL_DOWN; break;
473   }
474   if (report.xbutton.state & ShiftMask) {
475     switch (report.xbutton.button) {
476     case Button1: *button = PETSC_BUTTON_LEFT_SHIFT; break;
477     case Button2: *button = PETSC_BUTTON_CENTER_SHIFT; break;
478     case Button3: *button = PETSC_BUTTON_RIGHT_SHIFT; break;
479     }
480   }
481   xx = ((PetscReal)px)/w;
482   yy = 1 - ((PetscReal)py)/h;
483   if (x_user) *x_user = draw->coor_xl + (xx - draw->port_xl)*(draw->coor_xr - draw->coor_xl)/(draw->port_xr - draw->port_xl);
484   if (y_user) *y_user = draw->coor_yl + (yy - draw->port_yl)*(draw->coor_yr - draw->coor_yl)/(draw->port_yr - draw->port_yl);
485   if (x_phys) *x_phys = xx;
486   if (y_phys) *y_phys = yy;
487 
488 finally:
489   ierr = PetscDrawCollectiveEnd(draw);PetscCall(ierr);
490   PetscCall(PetscDrawCheckResizedWindow_X(draw));
491   PetscFunctionReturn(0);
492 }
493 
494 static PetscErrorCode PetscDrawPause_X(PetscDraw draw)
495 {
496   PetscDraw_X *win = (PetscDraw_X*)draw->data;
497 
498   PetscFunctionBegin;
499   if (!win->win) PetscFunctionReturn(0);
500   if (draw->pause > 0) PetscSleep(draw->pause);
501   else if (draw->pause == -1) {
502     PetscDrawButton button = PETSC_BUTTON_NONE;
503     PetscCall(PetscDrawGetMouseButton(draw,&button,NULL,NULL,NULL,NULL));
504     if (button == PETSC_BUTTON_CENTER) draw->pause = 0;
505   }
506   PetscFunctionReturn(0);
507 }
508 
509 static PetscErrorCode PetscDrawDestroy_X(PetscDraw draw)
510 {
511   PetscDraw_X *win = (PetscDraw_X*)draw->data;
512 
513   PetscFunctionBegin;
514   PetscCall(PetscDrawDestroy(&draw->popup));
515   PetscCall(PetscDrawXiClose(win));
516   PetscCall(PetscFree(draw->data));
517   PetscFunctionReturn(0);
518 }
519 
520 static       PetscErrorCode PetscDrawGetSingleton_X(PetscDraw,PetscDraw*);
521 static       PetscErrorCode PetscDrawRestoreSingleton_X(PetscDraw,PetscDraw*);
522 PETSC_INTERN PetscErrorCode PetscDrawGetImage_X(PetscDraw,unsigned char[][3],unsigned int*,unsigned int*,unsigned char*[]);
523 
524 static struct _PetscDrawOps DvOps = { PetscDrawSetDoubleBuffer_X,
525                                       PetscDrawFlush_X,
526                                       PetscDrawLine_X,
527                                       NULL,
528                                       NULL,
529                                       PetscDrawPoint_X,
530                                       NULL,
531                                       PetscDrawString_X,
532                                       PetscDrawStringVertical_X,
533                                       PetscDrawStringSetSize_X,
534                                       PetscDrawStringGetSize_X,
535                                       PetscDrawSetViewport_X,
536                                       PetscDrawClear_X,
537                                       PetscDrawRectangle_X,
538                                       PetscDrawTriangle_X,
539                                       PetscDrawEllipse_X,
540                                       PetscDrawGetMouseButton_X,
541                                       PetscDrawPause_X,
542                                       NULL,
543                                       NULL,
544                                       PetscDrawGetPopup_X,
545                                       PetscDrawSetTitle_X,
546                                       PetscDrawCheckResizedWindow_X,
547                                       PetscDrawResizeWindow_X,
548                                       PetscDrawDestroy_X,
549                                       NULL,
550                                       PetscDrawGetSingleton_X,
551                                       PetscDrawRestoreSingleton_X,
552                                       NULL,
553                                       PetscDrawGetImage_X,
554                                       NULL,
555                                       PetscDrawArrow_X,
556                                       PetscDrawCoordinateToPixel_X,
557                                       PetscDrawPixelToCoordinate_X,
558                                       PetscDrawPointPixel_X,
559                                       NULL};
560 
561 static PetscErrorCode PetscDrawGetSingleton_X(PetscDraw draw,PetscDraw *sdraw)
562 {
563   PetscDraw_X *Xwin = (PetscDraw_X*)draw->data,*sXwin;
564 
565   PetscFunctionBegin;
566   PetscCall(PetscDrawCreate(PETSC_COMM_SELF,draw->display,draw->title,draw->x,draw->y,draw->w,draw->h,sdraw));
567   PetscCall(PetscObjectChangeTypeName((PetscObject)*sdraw,PETSC_DRAW_X));
568   PetscCall(PetscMemcpy((*sdraw)->ops,&DvOps,sizeof(DvOps)));
569 
570   if (draw->popup) PetscCall(PetscDrawGetSingleton(draw->popup,&(*sdraw)->popup));
571   (*sdraw)->pause   = draw->pause;
572   (*sdraw)->coor_xl = draw->coor_xl;
573   (*sdraw)->coor_xr = draw->coor_xr;
574   (*sdraw)->coor_yl = draw->coor_yl;
575   (*sdraw)->coor_yr = draw->coor_yr;
576   (*sdraw)->port_xl = draw->port_xl;
577   (*sdraw)->port_xr = draw->port_xr;
578   (*sdraw)->port_yl = draw->port_yl;
579   (*sdraw)->port_yr = draw->port_yr;
580 
581   /* share drawables (windows and/or pixmap) from the parent draw */
582   PetscCall(PetscNewLog(*sdraw,&sXwin));
583   (*sdraw)->data = (void*)sXwin;
584   PetscCall(PetscDrawXiInit(sXwin,draw->display));
585   if (Xwin->win) {
586     PetscCall(PetscDrawXiQuickWindowFromWindow(sXwin,Xwin->win));
587     sXwin->drw = Xwin->drw; /* XXX If the window is ever resized, this is wrong! */
588   } else if (Xwin->drw) {
589     PetscCall(PetscDrawXiColormap(sXwin));
590     sXwin->drw = Xwin->drw;
591   }
592   PetscCall(PetscDrawXiGetGeometry(sXwin,&sXwin->x,&sXwin->y,&sXwin->w,&sXwin->h));
593   (*sdraw)->x = sXwin->x; (*sdraw)->y = sXwin->y;
594   (*sdraw)->w = sXwin->w; (*sdraw)->h = sXwin->h;
595   PetscFunctionReturn(0);
596 }
597 
598 static PetscErrorCode PetscDrawRestoreSingleton_X(PetscDraw draw,PetscDraw *sdraw)
599 {
600   PetscFunctionBegin;
601   if (draw->popup && (*sdraw)->popup) {
602     PetscBool isdrawx;
603     PetscDraw_X *pXwin = (PetscDraw_X*)draw->popup->data;
604     PetscDraw_X *sXwin = (PetscDraw_X*)(*sdraw)->popup->data;
605     PetscCall(PetscObjectTypeCompare((PetscObject)draw->popup,PETSC_DRAW_X,&isdrawx));
606     if (!isdrawx) goto finally;
607     PetscCall(PetscObjectTypeCompare((PetscObject)(*sdraw)->popup,PETSC_DRAW_X,&isdrawx));
608     if (!isdrawx) goto finally;
609     if (sXwin->win == pXwin->win) {
610       PetscCall(PetscDrawRestoreSingleton(draw->popup,&(*sdraw)->popup));
611     }
612   }
613 finally:
614   PetscCall(PetscDrawDestroy(sdraw));
615   PetscFunctionReturn(0);
616 }
617 
618 static PetscErrorCode PetscDrawXGetDisplaySize_Private(const char name[],int *width,int *height,PetscBool *has_display)
619 {
620   Display *display;
621 
622   PetscFunctionBegin;
623   display = XOpenDisplay(name);
624   if (!display) {
625     *width  = *height = 0;
626     (*PetscErrorPrintf)("Unable to open display on %s\n\
627     Make sure your COMPUTE NODES are authorized to connect\n\
628     to this X server and either your DISPLAY variable\n\
629     is set or you use the -display name option\n",name);
630     *has_display = PETSC_FALSE;
631     PetscFunctionReturn(0);
632   }
633   *has_display = PETSC_TRUE;
634   *width  = (int)DisplayWidth(display,DefaultScreen(display));
635   *height = (int)DisplayHeight(display,DefaultScreen(display));
636   XCloseDisplay(display);
637   PetscFunctionReturn(0);
638 }
639 
640 /*MC
641      PETSC_DRAW_X  - PETSc graphics device that uses either X windows or its virtual version Xvfb
642 
643    Options Database Keys:
644 +  -display <display> - sets the display to use
645 .  -x_virtual - forces use of a X virtual display Xvfb that will not display anything but -draw_save will still work.
646                 Xvfb is automatically started up in PetscSetDisplay() with this option
647 .  -draw_size w,h - percentage of screen (either 1, .5, .3, .25), or size in pixels
648 .  -geometry x,y,w,h - set location and size in pixels
649 .  -draw_virtual - do not open a window (draw on a pixmap), -draw_save will still work
650 -  -draw_double_buffer - avoid window flickering (draw on pixmap and flush to window)
651 
652    Level: beginner
653 
654 .seealso:  PetscDrawOpenX(), PetscDrawSetDisplay(), PetscDrawSetFromOptions()
655 
656 M*/
657 
658 PETSC_EXTERN PetscErrorCode PetscDrawCreate_X(PetscDraw draw)
659 {
660   PetscDraw_X    *Xwin;
661   PetscMPIInt    rank;
662   int            x = draw->x,y = draw->y,w = draw->w,h = draw->h;
663   static int     xavailable = 0,yavailable = 0,ybottom = 0,xmax = 0,ymax = 0;
664   PetscBool      set,dvirtual = PETSC_FALSE,doublebuffer = PETSC_TRUE,has_display;
665   PetscInt       xywh[4],osize = 4,nsizes=2;
666   PetscReal      sizes[2] = {.3,.3};
667   static size_t  DISPLAY_LENGTH = 265;
668 
669   PetscFunctionBegin;
670   /* get the display variable */
671   if (!draw->display) {
672     PetscCall(PetscMalloc1(DISPLAY_LENGTH,&draw->display));
673     PetscCall(PetscGetDisplay(draw->display,DISPLAY_LENGTH));
674   }
675 
676   /* initialize the display size */
677   if (!xmax) {
678     PetscCall(PetscDrawXGetDisplaySize_Private(draw->display,&xmax,&ymax,&has_display));
679     /* if some processors fail on this and others succed then this is a problem ! */
680     if (!has_display) {
681       (*PetscErrorPrintf)("PETSc unable to use X windows\nproceeding without graphics\n");
682       PetscCall(PetscDrawSetType(draw,PETSC_DRAW_NULL));
683       PetscFunctionReturn(0);
684     }
685   }
686 
687   /* allow user to set size of drawable */
688   PetscCall(PetscOptionsGetRealArray(((PetscObject)draw)->options,((PetscObject)draw)->prefix,"-draw_size",sizes,&nsizes,&set));
689   if (set && nsizes == 1 && sizes[0] > 1.0) sizes[1] = sizes[0];
690   if (set) {
691     if (sizes[0] > 1.0)       w = (int)sizes[0];
692     else if (sizes[0] == 1.0) w = PETSC_DRAW_FULL_SIZE;
693     else if (sizes[0] == .5)  w = PETSC_DRAW_HALF_SIZE;
694     else if (sizes[0] == .3)  w = PETSC_DRAW_THIRD_SIZE;
695     else if (sizes[0] == .25) w = PETSC_DRAW_QUARTER_SIZE;
696     if (sizes[1] > 1.0)       h = (int)sizes[1];
697     else if (sizes[1] == 1.0) h = PETSC_DRAW_FULL_SIZE;
698     else if (sizes[1] == .5)  h = PETSC_DRAW_HALF_SIZE;
699     else if (sizes[1] == .3)  h = PETSC_DRAW_THIRD_SIZE;
700     else if (sizes[1] == .25) h = PETSC_DRAW_QUARTER_SIZE;
701   }
702   if (w == PETSC_DECIDE || w == PETSC_DEFAULT) w = draw->w = 300;
703   if (h == PETSC_DECIDE || h == PETSC_DEFAULT) h = draw->h = 300;
704   switch (w) {
705   case PETSC_DRAW_FULL_SIZE:    w = draw->w = (xmax - 10);   break;
706   case PETSC_DRAW_HALF_SIZE:    w = draw->w = (xmax - 20)/2; break;
707   case PETSC_DRAW_THIRD_SIZE:   w = draw->w = (xmax - 30)/3; break;
708   case PETSC_DRAW_QUARTER_SIZE: w = draw->w = (xmax - 40)/4; break;
709   }
710   switch (h) {
711   case PETSC_DRAW_FULL_SIZE:    h = draw->h = (ymax - 10);   break;
712   case PETSC_DRAW_HALF_SIZE:    h = draw->h = (ymax - 20)/2; break;
713   case PETSC_DRAW_THIRD_SIZE:   h = draw->h = (ymax - 30)/3; break;
714   case PETSC_DRAW_QUARTER_SIZE: h = draw->h = (ymax - 40)/4; break;
715   }
716 
717   PetscCall(PetscOptionsGetBool(((PetscObject)draw)->options,((PetscObject)draw)->prefix,"-draw_virtual",&dvirtual,NULL));
718 
719   if (!dvirtual) {
720 
721     /* allow user to set location and size of window */
722     xywh[0] = x; xywh[1] = y; xywh[2] = w; xywh[3] = h;
723     PetscCall(PetscOptionsGetIntArray(((PetscObject)draw)->options,((PetscObject)draw)->prefix,"-geometry",xywh,&osize,NULL));
724     x = (int)xywh[0]; y = (int)xywh[1]; w = (int)xywh[2]; h = (int)xywh[3];
725     if (w == PETSC_DECIDE || w == PETSC_DEFAULT) w = 300;
726     if (h == PETSC_DECIDE || h == PETSC_DEFAULT) h = 300;
727     draw->x = x; draw->y = y; draw->w = w; draw->h = h;
728 
729     if (draw->x == PETSC_DECIDE || draw->y == PETSC_DECIDE) {
730       /*
731        PETSc tries to place windows starting in the upper left corner
732         and moving across to the right.
733 
734        +0,0-------------------------------------------+
735        |  Region used so far  +xavailable,yavailable  |
736        |                      |                       |
737        |                      |                       |
738        +--------------------- +ybottom                |
739        |                                              |
740        |                                              |
741        +----------------------------------------------+xmax,ymax
742 
743       */
744       /*  First: can we add it to the right? */
745       if (xavailable + w + 10 <= xmax) {
746         x       = xavailable;
747         y       = yavailable;
748         ybottom = PetscMax(ybottom,y + h + 30);
749       } else {
750         /* No, so add it below on the left */
751         xavailable = x = 0;
752         yavailable = y = ybottom;
753         ybottom    = ybottom + h + 30;
754       }
755     }
756     /* update available region */
757     xavailable = PetscMax(xavailable,x + w + 10);
758     if (xavailable >= xmax) {
759       xavailable = 0;
760       yavailable = yavailable + h + 30;
761       ybottom    = yavailable;
762     }
763     if (yavailable >= ymax) {
764       y          = 0;
765       yavailable = 0;
766       ybottom    = 0;
767     }
768 
769   } /* endif (!dvirtual) */
770 
771   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)draw),&rank));
772   PetscCheckFalse(rank == 0 && (w <= 0 || h <= 0),PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Negative window width or height");
773 
774   PetscCall(PetscNewLog(draw,&Xwin));
775   PetscCall(PetscMemcpy(draw->ops,&DvOps,sizeof(DvOps)));
776   draw->data = (void*)Xwin;
777 
778   PetscCall(PetscDrawXiInit(Xwin,draw->display));
779   if (!dvirtual) {
780     Xwin->x = x; Xwin->y = y;
781     Xwin->w = w; Xwin->h = h;
782     if (rank == 0) PetscCall(PetscDrawXiQuickWindow(Xwin,draw->title,x,y,w,h));
783     PetscCallMPI(MPI_Bcast(&Xwin->win,1,MPI_UNSIGNED_LONG,0,PetscObjectComm((PetscObject)draw)));
784     if (rank) PetscCall(PetscDrawXiQuickWindowFromWindow(Xwin,Xwin->win));
785   } else {
786     Xwin->x = 0; Xwin->y = 0;
787     Xwin->w = w; Xwin->h = h;
788     PetscCall(PetscDrawXiColormap(Xwin));
789     if (rank == 0) PetscCall(PetscDrawXiQuickPixmap(Xwin));
790     PetscCallMPI(MPI_Bcast(&Xwin->drw,1,MPI_UNSIGNED_LONG,0,PetscObjectComm((PetscObject)draw)));
791   }
792   PetscCall(PetscDrawXiGetGeometry(Xwin,&Xwin->x,&Xwin->y,&Xwin->w,&Xwin->h));
793   draw->x = Xwin->x; draw->y = Xwin->y;
794   draw->w = Xwin->w; draw->h = Xwin->h;
795 
796   PetscCall(PetscOptionsGetBool(((PetscObject)draw)->options,((PetscObject)draw)->prefix,"-draw_double_buffer",&doublebuffer,NULL));
797   if (doublebuffer) PetscCall(PetscDrawSetDoubleBuffer(draw));
798   PetscFunctionReturn(0);
799 }
800