~ctwm/ctwm/trunk

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