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