1/* 2 * Functions involving the info/identify window. 3 */ 4 5#include "ctwm.h" 6 7#include <stdio.h> 8#include <stdlib.h> 9 10#include <X11/Xatom.h> 11 12#include "ctopts.h" 13#include "drawing.h" 14#include "functions.h" 15#include "functions_internal.h" 16#include "icons.h" 17#include "otp.h" 18#include "r_area.h" 19#include "r_layout.h" 20#include "screen.h" 21#include "version.h" 22#include "vscreen.h" 23 24 25/* We hold it in a big static buffer */ 26#define INFO_LINES 30 27#define INFO_SIZE 200 28static char Info[INFO_LINES][INFO_SIZE]; 29 30/* The builder */ 31static void Identify(TwmWindow *t); 32 33 34/* 35 * The functions that cause this to pop up. 36 * 37 * n.b.: these are referenced in the Developer Manual in doc/devman/; if 38 * you make any changes here be sure to tweak that if necessary. 39 */ 40DFHANDLER(identify) 41{ 42 Identify(tmp_win); 43} 44 45DFHANDLER(version) 46{ 47 Identify(NULL); 48} 49 50 51/* 52 * Building and displaying. 53 */ 54 55/* 56 * Backend for f.identify and f.version: Fills in the Info array with the 57 * appropriate bits for ctwm and the window specified (if any), and 58 * sizes/pops up the InfoWindow. 59 * 60 * Notably, the bits of Info aren't written into the window during this 61 * process; that happens later as a result of the expose event. 62 */ 63static void 64Identify(TwmWindow *t) 65{ 66 int i, n, twidth, width, height; 67 int x, y; 68 unsigned int wwidth, wheight, bw, depth; 69 Window junk; 70 int px, py, dummy; 71 unsigned udummy; 72 unsigned char *prop; 73 unsigned long nitems, bytesafter; 74 Atom actual_type; 75 int actual_format; 76 XRectangle inc_rect; 77 XRectangle logical_rect; 78 char *ctopts; 79 80 /* 81 * Include some checking we don't blow out _LINES. We use snprintf() 82 * exclusively to avoid blowing out _SIZE. 83 * 84 * In an ideal world, we'd probably fix this to be more dynamically 85 * allocated, but this will do for now. 86 */ 87 n = 0; 88#define CHKN do { \ 89 if(n > (INFO_LINES - 3)) { \ 90 fprintf(stderr, "Overflowing Info[] on line %d\n", n); \ 91 sprintf(Info[n++], "(overflow)"); \ 92 goto info_dismiss; \ 93 } \ 94 } while(0) 95 96 snprintf(Info[n++], INFO_SIZE, "Twm version: %s", TwmVersion); 97 CHKN; 98 if(VCSRevision) { 99 snprintf(Info[n++], INFO_SIZE, "VCS Revision: %s", VCSRevision); 100 CHKN; 101 } 102 103 ctopts = ctopts_string(", "); 104 snprintf(Info[n++], INFO_SIZE, "Compile time options : %s", ctopts); 105 free(ctopts); 106 CHKN; 107 108 Info[n++][0] = '\0'; 109 CHKN; 110 111 if(t) { 112 // The border would be on the frame, not t->w, so assume our 113 // internal tracking is right for it 114 XGetGeometry(dpy, t->w, &JunkRoot, &JunkX, &JunkY, 115 &wwidth, &wheight, &JunkBW, &depth); 116 bw = t->frame_bw; 117 XTranslateCoordinates(dpy, t->w, Scr->Root, 0, 0, 118 &x, &y, &junk); 119 snprintf(Info[n++], INFO_SIZE, "Name = \"%s\"", 120 t->name); 121 CHKN; 122 snprintf(Info[n++], INFO_SIZE, "Class.res_name = \"%s\"", 123 t->class.res_name); 124 CHKN; 125 snprintf(Info[n++], INFO_SIZE, "Class.res_class = \"%s\"", 126 t->class.res_class); 127 CHKN; 128 Info[n++][0] = '\0'; 129 CHKN; 130 snprintf(Info[n++], INFO_SIZE, 131 "Geometry/root (UL) = %dx%d+%d+%d (Inner: %dx%d+%d+%d)", 132 wwidth + 2 * (bw + t->frame_bw3D), 133 wheight + 2 * (bw + t->frame_bw3D) + t->title_height, 134 x - (bw + t->frame_bw3D), 135 y - (bw + t->frame_bw3D + t->title_height), 136 wwidth, wheight, x, y); 137 CHKN; 138 snprintf(Info[n++], INFO_SIZE, 139 "Geometry/root (LR) = %dx%d-%d-%d (Inner: %dx%d-%d-%d)", 140 wwidth + 2 * (bw + t->frame_bw3D), 141 wheight + 2 * (bw + t->frame_bw3D) + t->title_height, 142 Scr->rootw - (x + wwidth + bw + t->frame_bw3D), 143 Scr->rooth - (y + wheight + bw + t->frame_bw3D), 144 wwidth, wheight, 145 Scr->rootw - (x + wwidth), Scr->rooth - (y + wheight)); 146 CHKN; 147 snprintf(Info[n++], INFO_SIZE, "Border width = %d", bw); 148 CHKN; 149 snprintf(Info[n++], INFO_SIZE, "3D border width = %d", t->frame_bw3D); 150 CHKN; 151 snprintf(Info[n++], INFO_SIZE, "Depth = %d", depth); 152 CHKN; 153 if(t->vs && 154 t->vs->wsw && 155 t->vs->wsw->currentwspc) { 156 snprintf(Info[n++], INFO_SIZE, "Virtual Workspace = %s", 157 t->vs->wsw->currentwspc->name); 158 CHKN; 159 } 160 snprintf(Info[n++], INFO_SIZE, "OnTopPriority = %d", 161 OtpEffectiveDisplayPriority(t)); 162 CHKN; 163 164 if(t->icon != NULL) { 165 int iwx, iwy; 166 167 XGetGeometry(dpy, t->icon->w, &JunkRoot, &iwx, &iwy, 168 &wwidth, &wheight, &bw, &depth); 169 Info[n++][0] = '\0'; 170 CHKN; 171 snprintf(Info[n++], INFO_SIZE, "IconGeom/root = %dx%d+%d+%d", 172 wwidth, wheight, iwx, iwy); 173 CHKN; 174 snprintf(Info[n++], INFO_SIZE, "IconGeom/intern = %dx%d+%d+%d", 175 t->icon->w_width, t->icon->w_height, 176 t->icon->w_x, t->icon->w_y); 177 CHKN; 178 snprintf(Info[n++], INFO_SIZE, "IconBorder width = %d", bw); 179 CHKN; 180 snprintf(Info[n++], INFO_SIZE, "IconDepth = %d", depth); 181 CHKN; 182 } 183 184 if(XGetWindowProperty(dpy, t->w, XA_WM_CLIENT_MACHINE, 0L, 64, False, 185 XA_STRING, &actual_type, &actual_format, &nitems, 186 &bytesafter, &prop) == Success) { 187 if(nitems && prop) { 188 snprintf(Info[n++], INFO_SIZE, "Client machine = %s", 189 (char *)prop); 190 XFree(prop); 191 CHKN; 192 } 193 } 194 Info[n++][0] = '\0'; 195 CHKN; 196 } 197 198#undef CHKN 199info_dismiss: 200 snprintf(Info[n++], INFO_SIZE, "Click to dismiss...."); 201 202 203 /* 204 * OK, it's all built now. 205 */ 206 207 /* figure out the width and height of the info window */ 208 height = n * (Scr->DefaultFont.height + 2); 209 width = 1; 210 for(i = 0; i < n; i++) { 211 XmbTextExtents(Scr->DefaultFont.font_set, Info[i], 212 strlen(Info[i]), &inc_rect, &logical_rect); 213 214 twidth = logical_rect.width; 215 if(twidth > width) { 216 width = twidth; 217 } 218 } 219 220 /* Unmap if it's currently up, while we muck with it */ 221 if(Scr->InfoWindow.mapped) { 222 XUnmapWindow(dpy, Scr->InfoWindow.win); 223 /* Don't really need to bother since we're about to reset, but... */ 224 Scr->InfoWindow.mapped = false; 225 } 226 227 /* Stash the new number of lines */ 228 Scr->InfoWindow.lines = n; 229 230 width += 10; /* some padding */ 231 height += 10; /* some padding */ 232 if(XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild, 233 &dummy, &dummy, &px, &py, &udummy)) { 234 px -= width / 2; 235 py -= height / 3; 236 } 237 else { 238 px = py = 0; 239 } 240 241 { 242 RArea area = RAreaNew(px, py, width, height); 243 int min_x, min_y, max_bottom, max_right; 244 245 RLayoutFindLeftRightEdges(Scr->Layout, &area, &min_x, &max_right); 246 if(px < min_x) { 247 px = min_x; 248 } 249 else if(px + width - 1 > max_right) { 250 px = max_right - width + 1; 251 } 252 253 RLayoutFindTopBottomEdges(Scr->Layout, &area, &min_y, &max_bottom); 254 if(py < min_y) { 255 py = min_y; 256 } 257 else if(py + height - 1 > max_bottom) { 258 py = max_bottom - height + 1; 259 } 260 } 261 XMoveResizeWindow(dpy, Scr->InfoWindow.win, px, py, width, height); 262 XMapRaised(dpy, Scr->InfoWindow.win); 263 Scr->InfoWindow.mapped = true; 264 Scr->InfoWindow.width = width; 265 Scr->InfoWindow.height = height; 266} 267 268 269/* 270 * And the routine to actually write the text into the InfoWindow. This 271 * gets called from events.c as a result of Expose events on the window. 272 */ 273void 274draw_info_window(void) 275{ 276 int i; 277 const int height = Scr->DefaultFont.height + 2; 278 279 Draw3DBorder(Scr->InfoWindow.win, 0, 0, 280 Scr->InfoWindow.width, Scr->InfoWindow.height, 281 2, Scr->DefaultC, off, true, false); 282 283 FB(Scr->DefaultC.fore, Scr->DefaultC.back); 284 285 for(i = 0; i < Scr->InfoWindow.lines ; i++) { 286 XmbDrawString(dpy, Scr->InfoWindow.win, Scr->DefaultFont.font_set, 287 Scr->NormalGC, 5, 288 (i * height) + Scr->DefaultFont.y + 5, 289 Info[i], strlen(Info[i])); 290 } 291} 292