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