/* * Functions involving the info/identify window. */ #include "ctwm.h" #include #include #include #include "ctopts.h" #include "drawing.h" #include "functions.h" #include "functions_internal.h" #include "icons.h" #include "otp.h" #include "r_area.h" #include "r_layout.h" #include "screen.h" #include "version.h" #include "vscreen.h" /* We hold it in a big static buffer */ #define INFO_LINES 30 #define INFO_SIZE 200 static char Info[INFO_LINES][INFO_SIZE]; /* The builder */ static void Identify(TwmWindow *t); /* * The functions that cause this to pop up. * * n.b.: these are referenced in the Developer Manual in doc/devman/; if * you make any changes here be sure to tweak that if necessary. */ DFHANDLER(identify) { Identify(tmp_win); } DFHANDLER(version) { Identify(NULL); } /* * Building and displaying. */ /* * Backend for f.identify and f.version: Fills in the Info array with the * appropriate bits for ctwm and the window specified (if any), and * sizes/pops up the InfoWindow. * * Notably, the bits of Info aren't written into the window during this * process; that happens later as a result of the expose event. */ static void Identify(TwmWindow *t) { int i, n, twidth, width, height; int x, y; unsigned int wwidth, wheight, bw, depth; Window junk; int px, py, dummy; unsigned udummy; unsigned char *prop; unsigned long nitems, bytesafter; Atom actual_type; int actual_format; XRectangle inc_rect; XRectangle logical_rect; char *ctopts; /* * Include some checking we don't blow out _LINES. We use snprintf() * exclusively to avoid blowing out _SIZE. * * In an ideal world, we'd probably fix this to be more dynamically * allocated, but this will do for now. */ n = 0; #define CHKN do { \ if(n > (INFO_LINES - 3)) { \ fprintf(stderr, "Overflowing Info[] on line %d\n", n); \ sprintf(Info[n++], "(overflow)"); \ goto info_dismiss; \ } \ } while(0) snprintf(Info[n++], INFO_SIZE, "Twm version: %s", TwmVersion); CHKN; if(VCSRevision) { snprintf(Info[n++], INFO_SIZE, "VCS Revision: %s", VCSRevision); CHKN; } ctopts = ctopts_string(", "); snprintf(Info[n++], INFO_SIZE, "Compile time options : %s", ctopts); free(ctopts); CHKN; Info[n++][0] = '\0'; CHKN; if(t) { // The border would be on the frame, not t->w, so assume our // internal tracking is right for it XGetGeometry(dpy, t->w, &JunkRoot, &JunkX, &JunkY, &wwidth, &wheight, &JunkBW, &depth); bw = t->frame_bw; XTranslateCoordinates(dpy, t->w, Scr->Root, 0, 0, &x, &y, &junk); snprintf(Info[n++], INFO_SIZE, "Name = \"%s\"", t->name); CHKN; snprintf(Info[n++], INFO_SIZE, "Class.res_name = \"%s\"", t->class.res_name); CHKN; snprintf(Info[n++], INFO_SIZE, "Class.res_class = \"%s\"", t->class.res_class); CHKN; Info[n++][0] = '\0'; CHKN; snprintf(Info[n++], INFO_SIZE, "Geometry/root (UL) = %dx%d+%d+%d (Inner: %dx%d+%d+%d)", wwidth + 2 * (bw + t->frame_bw3D), wheight + 2 * (bw + t->frame_bw3D) + t->title_height, x - (bw + t->frame_bw3D), y - (bw + t->frame_bw3D + t->title_height), wwidth, wheight, x, y); CHKN; snprintf(Info[n++], INFO_SIZE, "Geometry/root (LR) = %dx%d-%d-%d (Inner: %dx%d-%d-%d)", wwidth + 2 * (bw + t->frame_bw3D), wheight + 2 * (bw + t->frame_bw3D) + t->title_height, Scr->rootw - (x + wwidth + bw + t->frame_bw3D), Scr->rooth - (y + wheight + bw + t->frame_bw3D), wwidth, wheight, Scr->rootw - (x + wwidth), Scr->rooth - (y + wheight)); CHKN; snprintf(Info[n++], INFO_SIZE, "Border width = %d", bw); CHKN; snprintf(Info[n++], INFO_SIZE, "3D border width = %d", t->frame_bw3D); CHKN; snprintf(Info[n++], INFO_SIZE, "Depth = %d", depth); CHKN; if(t->vs && t->vs->wsw && t->vs->wsw->currentwspc) { snprintf(Info[n++], INFO_SIZE, "Virtual Workspace = %s", t->vs->wsw->currentwspc->name); CHKN; } snprintf(Info[n++], INFO_SIZE, "OnTopPriority = %d", OtpEffectiveDisplayPriority(t)); CHKN; if(t->icon != NULL) { int iwx, iwy; XGetGeometry(dpy, t->icon->w, &JunkRoot, &iwx, &iwy, &wwidth, &wheight, &bw, &depth); Info[n++][0] = '\0'; CHKN; snprintf(Info[n++], INFO_SIZE, "IconGeom/root = %dx%d+%d+%d", wwidth, wheight, iwx, iwy); CHKN; snprintf(Info[n++], INFO_SIZE, "IconGeom/intern = %dx%d+%d+%d", t->icon->w_width, t->icon->w_height, t->icon->w_x, t->icon->w_y); CHKN; snprintf(Info[n++], INFO_SIZE, "IconBorder width = %d", bw); CHKN; snprintf(Info[n++], INFO_SIZE, "IconDepth = %d", depth); CHKN; } if(XGetWindowProperty(dpy, t->w, XA_WM_CLIENT_MACHINE, 0L, 64, False, XA_STRING, &actual_type, &actual_format, &nitems, &bytesafter, &prop) == Success) { if(nitems && prop) { snprintf(Info[n++], INFO_SIZE, "Client machine = %s", (char *)prop); XFree(prop); CHKN; } } Info[n++][0] = '\0'; CHKN; } #undef CHKN info_dismiss: snprintf(Info[n++], INFO_SIZE, "Click to dismiss...."); /* * OK, it's all built now. */ /* figure out the width and height of the info window */ height = n * (Scr->DefaultFont.height + 2); width = 1; for(i = 0; i < n; i++) { XmbTextExtents(Scr->DefaultFont.font_set, Info[i], strlen(Info[i]), &inc_rect, &logical_rect); twidth = logical_rect.width; if(twidth > width) { width = twidth; } } /* Unmap if it's currently up, while we muck with it */ if(Scr->InfoWindow.mapped) { XUnmapWindow(dpy, Scr->InfoWindow.win); /* Don't really need to bother since we're about to reset, but... */ Scr->InfoWindow.mapped = false; } /* Stash the new number of lines */ Scr->InfoWindow.lines = n; width += 10; /* some padding */ height += 10; /* some padding */ if(XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild, &dummy, &dummy, &px, &py, &udummy)) { px -= width / 2; py -= height / 3; } else { px = py = 0; } { RArea area = RAreaNew(px, py, width, height); int min_x, min_y, max_bottom, max_right; RLayoutFindLeftRightEdges(Scr->Layout, &area, &min_x, &max_right); if(px < min_x) { px = min_x; } else if(px + width - 1 > max_right) { px = max_right - width + 1; } RLayoutFindTopBottomEdges(Scr->Layout, &area, &min_y, &max_bottom); if(py < min_y) { py = min_y; } else if(py + height - 1 > max_bottom) { py = max_bottom - height + 1; } } XMoveResizeWindow(dpy, Scr->InfoWindow.win, px, py, width, height); XMapRaised(dpy, Scr->InfoWindow.win); Scr->InfoWindow.mapped = true; Scr->InfoWindow.width = width; Scr->InfoWindow.height = height; } /* * And the routine to actually write the text into the InfoWindow. This * gets called from events.c as a result of Expose events on the window. */ void draw_info_window(void) { int i; const int height = Scr->DefaultFont.height + 2; Draw3DBorder(Scr->InfoWindow.win, 0, 0, Scr->InfoWindow.width, Scr->InfoWindow.height, 2, Scr->DefaultC, off, true, false); FB(Scr->DefaultC.fore, Scr->DefaultC.back); for(i = 0; i < Scr->InfoWindow.lines ; i++) { XmbDrawString(dpy, Scr->InfoWindow.win, Scr->DefaultFont.font_set, Scr->NormalGC, 5, (i * height) + Scr->DefaultFont.y + 5, Info[i], strlen(Info[i])); } }