1 /*
2 * Various operations done on windows.
3 */
4
5 #include "ctwm.h"
6
7 #include <stdio.h>
8
9 #include "animate.h"
10 #include "colormaps.h"
11 #include "drawing.h"
12 #include "events.h"
13 #include "iconmgr.h"
14 #include "image.h"
15 #include "otp.h"
16 #include "screen.h"
17 #include "win_decorations.h"
18 #include "win_iconify.h"
19 #include "win_ops.h"
20 #include "win_utils.h"
21
22
23 /*
24 * Update the visuals of a window (e.g., its own decorations and its
25 * representation in the icon manager) for having/losing focus.
26 *
27 * Formerly in util.c
28 */
29 void
SetFocusVisualAttributes(TwmWindow * tmp_win,bool focus)30 SetFocusVisualAttributes(TwmWindow *tmp_win, bool focus)
31 {
32 if(! tmp_win) {
33 return;
34 }
35
36 if(focus == tmp_win->hasfocusvisible) {
37 return;
38 }
39 if(tmp_win->highlight) {
40 if(Scr->use3Dborders) {
41 PaintBorders(tmp_win, focus);
42 }
43 else {
44 if(focus) {
45 XSetWindowBorder(dpy, tmp_win->frame, tmp_win->borderC.back);
46 if(tmp_win->title_w) {
47 XSetWindowBorder(dpy, tmp_win->title_w, tmp_win->borderC.back);
48 }
49 }
50 else {
51 /*
52 * XXX It seems possible this could be replaced by a
53 * single global 'gray' pixmap; I don't think it actually
54 * varies per window, and I don't see any obvious reason
55 * it can't be reused, so we may be able to save an
56 * allocation for each window by doing so...
57 */
58 XSetWindowBorderPixmap(dpy, tmp_win->frame, tmp_win->gray);
59 if(tmp_win->title_w) {
60 XSetWindowBorderPixmap(dpy, tmp_win->title_w, tmp_win->gray);
61 }
62 }
63 }
64 }
65
66 if(focus) {
67 bool hil = false;
68
69 if(tmp_win->lolite_wl) {
70 XUnmapWindow(dpy, tmp_win->lolite_wl);
71 }
72 if(tmp_win->lolite_wr) {
73 XUnmapWindow(dpy, tmp_win->lolite_wr);
74 }
75 if(tmp_win->hilite_wl) {
76 XMapWindow(dpy, tmp_win->hilite_wl);
77 hil = true;
78 }
79 if(tmp_win->hilite_wr) {
80 XMapWindow(dpy, tmp_win->hilite_wr);
81 hil = true;
82 }
83 if(hil && tmp_win->HiliteImage && tmp_win->HiliteImage->next) {
84 MaybeAnimate = true;
85 }
86 if(tmp_win->iconmanagerlist) {
87 ActiveIconManager(tmp_win->iconmanagerlist);
88 }
89 }
90 else {
91 if(tmp_win->hilite_wl) {
92 XUnmapWindow(dpy, tmp_win->hilite_wl);
93 }
94 if(tmp_win->hilite_wr) {
95 XUnmapWindow(dpy, tmp_win->hilite_wr);
96 }
97 if(tmp_win->lolite_wl) {
98 XMapWindow(dpy, tmp_win->lolite_wl);
99 }
100 if(tmp_win->lolite_wr) {
101 XMapWindow(dpy, tmp_win->lolite_wr);
102 }
103 if(tmp_win->iconmanagerlist) {
104 NotActiveIconManager(tmp_win->iconmanagerlist);
105 }
106 }
107 if(Scr->use3Dtitles && Scr->SunkFocusWindowTitle && tmp_win->title_height) {
108 ButtonState bs;
109
110 bs = focus ? on : off;
111 Draw3DBorder(tmp_win->title_w, Scr->TBInfo.titlex, 0,
112 tmp_win->title_width - Scr->TBInfo.titlex -
113 Scr->TBInfo.rightoff - Scr->TitlePadding,
114 Scr->TitleHeight, Scr->TitleShadowDepth,
115 tmp_win->title, bs, false, false);
116 }
117 tmp_win->hasfocusvisible = focus;
118 }
119
120
121 /*
122 * Shift the focus to a given window, and do whatever subsidiary ops that
123 * entails.
124 *
125 * Formerly in util.c
126 */
127 void
SetFocus(TwmWindow * tmp_win,Time tim)128 SetFocus(TwmWindow *tmp_win, Time tim)
129 {
130 Window w = (tmp_win ? tmp_win->w : PointerRoot);
131 bool f_iconmgr = false;
132
133 if(Scr->Focus && (Scr->Focus->isiconmgr)) {
134 f_iconmgr = true;
135 }
136 if(Scr->SloppyFocus && (w == PointerRoot) && (!f_iconmgr)) {
137 return;
138 }
139
140 XSetInputFocus(dpy, w, RevertToPointerRoot, tim);
141 #ifdef EWMH
142 EwmhSet_NET_ACTIVE_WINDOW(w);
143 #endif
144 if(Scr->Focus == tmp_win) {
145 return;
146 }
147
148 if(Scr->Focus) {
149 if(Scr->Focus->AutoSqueeze && !Scr->Focus->squeezed) {
150 AutoSqueeze(Scr->Focus);
151 }
152 SetFocusVisualAttributes(Scr->Focus, false);
153 #ifdef EWMH
154 // Priority may change when focus does
155 if(OtpIsFocusDependent(Scr->Focus)) {
156 OtpUnfocusWindow(Scr->Focus);
157 // That Scr->Focus = NULL's internally for us, but we don't
158 // care, since we're about to reset it if we need to.
159 }
160 #endif
161 }
162
163 if(tmp_win) {
164 if(tmp_win->AutoSqueeze && tmp_win->squeezed) {
165 AutoSqueeze(tmp_win);
166 }
167 SetFocusVisualAttributes(tmp_win, true);
168 #ifdef EWMH
169 // Priority may change when focus does
170 if(OtpIsFocusDependent(tmp_win)) {
171 OtpFocusWindow(tmp_win);
172 // Pre-sets Scr->Focus
173 }
174 #endif
175 }
176
177 // in the EWMH cases, this was already done.
178 Scr->Focus = tmp_win;
179
180 return;
181 }
182
183
184 /*
185 * Move the focus straight to the root, with associated cleanup.
186 *
187 * Formerly in menus.c
188 */
FocusOnRoot(void)189 void FocusOnRoot(void)
190 {
191 SetFocus(NULL, EventTime);
192 InstallColormaps(0, &Scr->RootColormaps);
193 if(! Scr->ClickToFocus) {
194 Scr->FocusRoot = true;
195 }
196 }
197
198
199 /*
200 * Handle doing squeezing bits for AutoSqueeze{} windows.
201 *
202 * Formerly in menus.c
203 */
204 void
AutoSqueeze(TwmWindow * tmp_win)205 AutoSqueeze(TwmWindow *tmp_win)
206 {
207 if(tmp_win->isiconmgr) {
208 return;
209 }
210 if(Scr->RaiseWhenAutoUnSqueeze && tmp_win->squeezed) {
211 OtpRaise(tmp_win, WinWin);
212 }
213 Squeeze(tmp_win);
214 }
215
216
217 /*
218 * Toggle a window's squeezed state.
219 *
220 * Formerly in menus.c
221 */
222 void
Squeeze(TwmWindow * tmp_win)223 Squeeze(TwmWindow *tmp_win)
224 {
225 long fx, fy, savex, savey;
226 int neww, newh;
227 bool south;
228 int grav = ((tmp_win->hints.flags & PWinGravity)
229 ? tmp_win->hints.win_gravity : NorthWestGravity);
230 long eventMask;
231 if(tmp_win->squeezed) {
232 tmp_win->squeezed = False;
233 #ifdef EWMH
234 EwmhSet_NET_WM_STATE(tmp_win, EWMH_STATE_SHADED);
235 #endif /* EWMH */
236 if(!tmp_win->isicon) {
237 XMapWindow(dpy, tmp_win->w);
238 }
239 SetupWindow(tmp_win, tmp_win->actual_frame_x, tmp_win->actual_frame_y,
240 tmp_win->actual_frame_width, tmp_win->actual_frame_height, -1);
241 ReMapTransients(tmp_win);
242 return;
243 }
244
245 newh = tmp_win->title_height + 2 * tmp_win->frame_bw3D;
246 if(newh < 3) {
247 XBell(dpy, 0);
248 return;
249 }
250 switch(grav) {
251 case SouthWestGravity :
252 case SouthGravity :
253 case SouthEastGravity :
254 south = true;
255 break;
256 default :
257 south = false;
258 break;
259 }
260 if(tmp_win->title_height && !tmp_win->AlwaysSqueezeToGravity) {
261 south = false;
262 }
263
264 tmp_win->squeezed = true;
265 tmp_win->actual_frame_width = tmp_win->frame_width;
266 tmp_win->actual_frame_height = tmp_win->frame_height;
267 savex = fx = tmp_win->frame_x;
268 savey = fy = tmp_win->frame_y;
269 neww = tmp_win->actual_frame_width;
270 if(south) {
271 fy += tmp_win->frame_height - newh;
272 }
273 if(tmp_win->squeeze_info) {
274 fx += tmp_win->title_x - tmp_win->frame_bw3D;
275 neww = tmp_win->title_width + 2 * (tmp_win->frame_bw + tmp_win->frame_bw3D);
276 }
277
278 eventMask = mask_out_event(tmp_win->w, StructureNotifyMask);
279 #ifdef EWMH
280 EwmhSet_NET_WM_STATE(tmp_win, EWMH_STATE_SHADED);
281 #endif /* EWMH */
282 XUnmapWindow(dpy, tmp_win->w);
283 restore_mask(tmp_win->w, eventMask);
284
285 if(fx + neww >= Scr->rootw - Scr->BorderRight) {
286 fx = Scr->rootw - Scr->BorderRight - neww;
287 }
288 if(fy + newh >= Scr->rooth - Scr->BorderBottom) {
289 fy = Scr->rooth - Scr->BorderBottom - newh;
290 }
291 SetupWindow(tmp_win, fx, fy, neww, newh, -1);
292 tmp_win->actual_frame_x = savex;
293 tmp_win->actual_frame_y = savey;
294
295 /* Now make the group members disappear */
296 UnmapTransients(tmp_win, false, eventMask);
297 }
298
299
300 /***********************************************************************
301 *
302 * Procedure:
303 * MoveOutline - move a window outline
304 *
305 * Inputs:
306 * root - the window we are outlining
307 * x - upper left x coordinate
308 * y - upper left y coordinate
309 * width - the width of the rectangle
310 * height - the height of the rectangle
311 * bw - the border width of the frame
312 * th - title height
313 *
314 ***********************************************************************
315 */
316 void
MoveOutline(Window root,int x,int y,int width,int height,int bw,int th)317 MoveOutline(Window root, int x, int y, int width, int height, int bw, int th)
318 {
319 static int lastx = 0;
320 static int lasty = 0;
321 static int lastWidth = 0;
322 static int lastHeight = 0;
323 static int lastBW = 0;
324 static int lastTH = 0;
325 int xl, xr, yt, yb, xinnerl, xinnerr, yinnert, yinnerb;
326 int xthird, ythird;
327 XSegment outline[18];
328 XSegment *r;
329
330 if(x == lastx && y == lasty && width == lastWidth && height == lastHeight
331 && lastBW == bw && th == lastTH) {
332 return;
333 }
334
335 r = outline;
336
337 #define DRAWIT() \
338 if (lastWidth || lastHeight) \
339 { \
340 xl = lastx; \
341 xr = lastx + lastWidth - 1; \
342 yt = lasty; \
343 yb = lasty + lastHeight - 1; \
344 xinnerl = xl + lastBW; \
345 xinnerr = xr - lastBW; \
346 yinnert = yt + lastTH + lastBW; \
347 yinnerb = yb - lastBW; \
348 xthird = (xinnerr - xinnerl) / 3; \
349 ythird = (yinnerb - yinnert) / 3; \
350 \
351 r->x1 = xl; \
352 r->y1 = yt; \
353 r->x2 = xr; \
354 r->y2 = yt; \
355 r++; \
356 \
357 r->x1 = xl; \
358 r->y1 = yb; \
359 r->x2 = xr; \
360 r->y2 = yb; \
361 r++; \
362 \
363 r->x1 = xl; \
364 r->y1 = yt; \
365 r->x2 = xl; \
366 r->y2 = yb; \
367 r++; \
368 \
369 r->x1 = xr; \
370 r->y1 = yt; \
371 r->x2 = xr; \
372 r->y2 = yb; \
373 r++; \
374 \
375 r->x1 = xinnerl + xthird; \
376 r->y1 = yinnert; \
377 r->x2 = r->x1; \
378 r->y2 = yinnerb; \
379 r++; \
380 \
381 r->x1 = xinnerl + (2 * xthird); \
382 r->y1 = yinnert; \
383 r->x2 = r->x1; \
384 r->y2 = yinnerb; \
385 r++; \
386 \
387 r->x1 = xinnerl; \
388 r->y1 = yinnert + ythird; \
389 r->x2 = xinnerr; \
390 r->y2 = r->y1; \
391 r++; \
392 \
393 r->x1 = xinnerl; \
394 r->y1 = yinnert + (2 * ythird); \
395 r->x2 = xinnerr; \
396 r->y2 = r->y1; \
397 r++; \
398 \
399 if (lastTH != 0) { \
400 r->x1 = xl; \
401 r->y1 = yt + lastTH; \
402 r->x2 = xr; \
403 r->y2 = r->y1; \
404 r++; \
405 } \
406 }
407
408 /* undraw the old one, if any */
409 DRAWIT();
410
411 lastx = x;
412 lasty = y;
413 lastWidth = width;
414 lastHeight = height;
415 lastBW = bw;
416 lastTH = th;
417
418 /* draw the new one, if any */
419 DRAWIT();
420
421 #undef DRAWIT
422
423
424 if(r != outline) {
425 XDrawSegments(dpy, root, Scr->DrawGC, outline, r - outline);
426 }
427 }
428