win_ops.c revision 0bbfda8a
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 */
29void
30SetFocusVisualAttributes(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 */
127void
128SetFocus(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 */
189void 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 */
204void
205AutoSqueeze(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 */
222void
223Squeeze(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 */
316void
317MoveOutline(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