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