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 |
}
|