1 /* 2 This file contains routines to open an X window display and window 3 This consists of a number of routines that set the various 4 fields in the Window structure, which is passed to 5 all of these routines. 6 7 Note that if you use the default visual and colormap, then you 8 can use these routines with any X toolkit that will give you the 9 Window id of the window that it is managing. Use that instead of the 10 call to PetscDrawXiCreateWindow . Similarly for the Display. 11 */ 12 13 #include <../src/sys/classes/draw/impls/x/ximpl.h> 14 15 PETSC_INTERN PetscErrorCode PetscDrawSetColormap_X(PetscDraw_X *, Colormap); 16 17 /* 18 PetscDrawXiOpenDisplay - Open and setup a display 19 */ 20 static PetscErrorCode PetscDrawXiOpenDisplay(PetscDraw_X *XiWin, const char display[]) 21 { 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(PETSC_SUCCESS); 38 } 39 40 PetscErrorCode PetscDrawXiClose(PetscDraw_X *XiWin) 41 { 42 PetscFunctionBegin; 43 if (!XiWin) PetscFunctionReturn(PETSC_SUCCESS); 44 PetscCall(PetscFree(XiWin->font)); 45 if (XiWin->disp) { 46 #if defined(PETSC_HAVE_SETJMP_H) 47 jmp_buf jmpbuf; 48 PetscXIOErrorHandlerFn *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(PETSC_SUCCESS); 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(PETSC_SUCCESS); 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(PETSC_SUCCESS); 95 } 96 97 /* 98 This routine waits until the window is actually created. If the window was 99 never mapped it generates an error 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 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Window was not properly created"); 118 case Expose: 119 PetscFunctionReturn(PETSC_SUCCESS); 120 /* else ignore event */ 121 } 122 } 123 } 124 PetscFunctionReturn(PETSC_SUCCESS); 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 | CWWinGravity | CWBackingStore | CWBackingPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask | CWDontPropagate | CWCursor | CWColormap; 176 177 XiWin->win = XCreateWindow(XiWin->disp, RootWindow(XiWin->disp, XiWin->screen), x, y, w, h, border_width, XiWin->depth, InputOutput, XiWin->vis, wmask, &window_attributes); 178 PetscCheck(XiWin->win, PETSC_COMM_SELF, PETSC_ERR_LIB, "Unable to open X window"); 179 180 /* set window manager hints */ 181 { 182 XWMHints wm_hints; 183 XClassHint class_hints; 184 XTextProperty windowname, iconname; 185 186 if (label) XStringListToTextProperty(&label, 1, &windowname); 187 else XStringListToTextProperty(&label, 0, &windowname); 188 if (label) XStringListToTextProperty(&label, 1, &iconname); 189 else XStringListToTextProperty(&label, 0, &iconname); 190 191 wm_hints.initial_state = NormalState; 192 wm_hints.input = True; 193 wm_hints.flags = StateHint | InputHint; 194 195 /* These properties can be used by window managers to decide how to display a window */ 196 class_hints.res_name = (char *)"petsc"; 197 class_hints.res_class = (char *)"PETSc"; 198 199 size_hints.x = x; 200 size_hints.y = y; 201 size_hints.min_width = 4 * border_width; 202 size_hints.min_height = 4 * border_width; 203 size_hints.width = w; 204 size_hints.height = h; 205 size_hints.flags = USPosition | USSize | PMinSize; 206 207 XSetWMProperties(XiWin->disp, XiWin->win, &windowname, &iconname, NULL, 0, &size_hints, &wm_hints, &class_hints); 208 XFree((void *)windowname.value); 209 XFree((void *)iconname.value); 210 } 211 212 /* make the window visible */ 213 XSelectInput(XiWin->disp, XiWin->win, ExposureMask | StructureNotifyMask); 214 XMapWindow(XiWin->disp, XiWin->win); 215 /* some window systems are cruel and interfere with the placement of 216 windows. We wait here for the window to be created or to die */ 217 PetscCall(PetscDrawXiWaitMap(XiWin)); 218 XSelectInput(XiWin->disp, XiWin->win, NoEventMask); 219 PetscFunctionReturn(PETSC_SUCCESS); 220 } 221 222 PetscErrorCode PetscDrawXiQuickWindow(PetscDraw_X *XiWin, char *name, int x, int y, int nx, int ny) 223 { 224 PetscFunctionBegin; 225 PetscCall(PetscDrawSetColormap_X(XiWin, (Colormap)0)); 226 PetscCall(PetscDrawXiDisplayWindow(XiWin, name, x, y, nx, ny)); 227 XSetWindowBackground(XiWin->disp, XiWin->win, XiWin->background); 228 XClearWindow(XiWin->disp, XiWin->win); 229 PetscFunctionReturn(PETSC_SUCCESS); 230 } 231 232 /* 233 A version from an already defined window 234 */ 235 PetscErrorCode PetscDrawXiQuickWindowFromWindow(PetscDraw_X *XiWin, Window win) 236 { 237 XWindowAttributes attributes; 238 239 PetscFunctionBegin; 240 XiWin->win = win; 241 XGetWindowAttributes(XiWin->disp, XiWin->win, &attributes); 242 PetscCall(PetscDrawSetColormap_X(XiWin, attributes.colormap)); 243 PetscFunctionReturn(PETSC_SUCCESS); 244 } 245 246 PetscErrorCode PetscDrawXiQuickPixmap(PetscDraw_X *XiWin) 247 { 248 PetscFunctionBegin; 249 if (XiWin->drw) XFreePixmap(XiWin->disp, XiWin->drw); 250 XiWin->drw = XCreatePixmap(XiWin->disp, RootWindow(XiWin->disp, XiWin->screen), XiWin->w, XiWin->h, XiWin->depth); 251 PetscDrawXiSetPixVal(XiWin, XiWin->background); 252 XFillRectangle(XiWin->disp, XiWin->drw, XiWin->gc.set, 0, 0, XiWin->w, XiWin->h); 253 XSync(XiWin->disp, False); 254 PetscFunctionReturn(PETSC_SUCCESS); 255 } 256 257 PetscErrorCode PetscDrawXiResizeWindow(PetscDraw_X *XiWin, int w, int h) 258 { 259 XEvent event; 260 261 PetscFunctionBegin; 262 XSelectInput(XiWin->disp, XiWin->win, StructureNotifyMask); 263 XResizeWindow(XiWin->disp, XiWin->win, (unsigned int)w, (unsigned int)h); 264 XWindowEvent(XiWin->disp, XiWin->win, StructureNotifyMask, &event); 265 XSelectInput(XiWin->disp, XiWin->win, NoEventMask); 266 PetscFunctionReturn(PETSC_SUCCESS); 267 } 268 269 PetscErrorCode PetscDrawXiGetGeometry(PetscDraw_X *XiWin, int *x, int *y, int *w, int *h) 270 { 271 XWindowAttributes attributes; 272 Window root, parent, child; 273 int xx = 0, yy = 0; 274 unsigned int ww = 0, hh = 0, dummy; 275 276 PetscFunctionBegin; 277 if (XiWin->win) { 278 XGetGeometry(XiWin->disp, XiWin->win, &parent, &xx, &yy, &ww, &hh, &dummy, &dummy); 279 root = RootWindow(XiWin->disp, XiWin->screen); 280 if (!XTranslateCoordinates(XiWin->disp, XiWin->win, root, 0, 0, &xx, &yy, &child)) { 281 XGetWindowAttributes(XiWin->disp, XiWin->win, &attributes); 282 root = attributes.screen->root; 283 (void)XTranslateCoordinates(XiWin->disp, XiWin->win, root, 0, 0, &xx, &yy, &child); 284 } 285 } else if (XiWin->drw) { 286 XGetGeometry(XiWin->disp, XiWin->drw, &root, &xx, &yy, &ww, &hh, &dummy, &dummy); 287 } 288 if (x) *x = xx; 289 if (y) *y = yy; 290 if (w) *w = (int)ww; 291 if (h) *h = (int)hh; 292 PetscFunctionReturn(PETSC_SUCCESS); 293 } 294