10bbfda8aSnia/*
20bbfda8aSnia * Window-handling utility funcs
30bbfda8aSnia */
40bbfda8aSnia
50bbfda8aSnia#include "ctwm.h"
60bbfda8aSnia
70bbfda8aSnia#include <stdio.h>
80bbfda8aSnia#include <stdlib.h>
90bbfda8aSnia
100bbfda8aSnia#include <X11/Xatom.h>
110bbfda8aSnia
120bbfda8aSnia#include "add_window.h" // NoName
130bbfda8aSnia#include "ctwm_atoms.h"
140bbfda8aSnia#include "drawing.h"
150bbfda8aSnia#include "events.h"
160bbfda8aSnia#include "event_internal.h" // Temp?
170bbfda8aSnia#ifdef EWMH
180bbfda8aSnia# include "ewmh_atoms.h"
190bbfda8aSnia#endif
200bbfda8aSnia#include "icons.h"
210bbfda8aSnia#include "list.h"
220bbfda8aSnia#include "occupation.h"
230bbfda8aSnia#include "otp.h"
24b18c2d1eSnia#include "r_area.h"
25b18c2d1eSnia#include "r_area_list.h"
26b18c2d1eSnia#include "r_layout.h"
270bbfda8aSnia#include "screen.h"
280bbfda8aSnia#include "util.h"
290bbfda8aSnia#include "win_decorations.h"
300bbfda8aSnia#include "win_ops.h"
310bbfda8aSnia#include "win_utils.h"
320bbfda8aSnia#include "workspace_utils.h"
330bbfda8aSnia
340bbfda8aSnia
350bbfda8aSnia/*
360bbfda8aSnia * Fill in size hints for a window from WM_NORMAL_HINTS prop.
370bbfda8aSnia *
380bbfda8aSnia * Formerly in add_window.c
390bbfda8aSnia */
400bbfda8aSniavoid
410bbfda8aSniaGetWindowSizeHints(TwmWindow *tmp)
420bbfda8aSnia{
430bbfda8aSnia	long supplied = 0;
440bbfda8aSnia	XSizeHints *hints = &tmp->hints;
450bbfda8aSnia
460bbfda8aSnia	if(!XGetWMNormalHints(dpy, tmp->w, hints, &supplied)) {
470bbfda8aSnia		hints->flags = 0;
480bbfda8aSnia	}
490bbfda8aSnia
500bbfda8aSnia	if(hints->flags & PResizeInc) {
510bbfda8aSnia		if(hints->width_inc == 0) {
520bbfda8aSnia			hints->width_inc = 1;
530bbfda8aSnia		}
540bbfda8aSnia		if(hints->height_inc == 0) {
550bbfda8aSnia			hints->height_inc = 1;
560bbfda8aSnia		}
570bbfda8aSnia	}
580bbfda8aSnia
590bbfda8aSnia	if(!(supplied & PWinGravity) && (hints->flags & USPosition)) {
600bbfda8aSnia		static int gravs[] = { SouthEastGravity, SouthWestGravity,
610bbfda8aSnia		                       NorthEastGravity, NorthWestGravity
620bbfda8aSnia		                     };
630bbfda8aSnia		int right =  tmp->attr.x + tmp->attr.width + 2 * tmp->old_bw;
640bbfda8aSnia		int bottom = tmp->attr.y + tmp->attr.height + 2 * tmp->old_bw;
650bbfda8aSnia		hints->win_gravity =
660bbfda8aSnia		        gravs[((Scr->rooth - bottom <
670bbfda8aSnia		                tmp->title_height + 2 * tmp->frame_bw3D) ? 0 : 2) |
680bbfda8aSnia		              ((Scr->rootw - right   <
690bbfda8aSnia		                tmp->title_height + 2 * tmp->frame_bw3D) ? 0 : 1)];
700bbfda8aSnia		hints->flags |= PWinGravity;
710bbfda8aSnia	}
720bbfda8aSnia
730bbfda8aSnia	/* Check for min size < max size */
740bbfda8aSnia	if((hints->flags & (PMinSize | PMaxSize)) == (PMinSize | PMaxSize)) {
750bbfda8aSnia		if(hints->max_width < hints->min_width) {
760bbfda8aSnia			if(hints->max_width > 0) {
770bbfda8aSnia				hints->min_width = hints->max_width;
780bbfda8aSnia			}
790bbfda8aSnia			else if(hints->min_width > 0) {
800bbfda8aSnia				hints->max_width = hints->min_width;
810bbfda8aSnia			}
820bbfda8aSnia			else {
830bbfda8aSnia				hints->max_width = hints->min_width = 1;
840bbfda8aSnia			}
850bbfda8aSnia		}
860bbfda8aSnia
870bbfda8aSnia		if(hints->max_height < hints->min_height) {
880bbfda8aSnia			if(hints->max_height > 0) {
890bbfda8aSnia				hints->min_height = hints->max_height;
900bbfda8aSnia			}
910bbfda8aSnia			else if(hints->min_height > 0) {
920bbfda8aSnia				hints->max_height = hints->min_height;
930bbfda8aSnia			}
940bbfda8aSnia			else {
950bbfda8aSnia				hints->max_height = hints->min_height = 1;
960bbfda8aSnia			}
970bbfda8aSnia		}
980bbfda8aSnia	}
990bbfda8aSnia}
1000bbfda8aSnia
1010bbfda8aSnia
1020bbfda8aSnia/*
1030bbfda8aSnia * Fill in info from WM_PROTOCOLS property
1040bbfda8aSnia *
1050bbfda8aSnia * Formerly in add_window.c
1060bbfda8aSnia */
1070bbfda8aSniavoid
1080bbfda8aSniaFetchWmProtocols(TwmWindow *tmp)
1090bbfda8aSnia{
1100bbfda8aSnia	unsigned long flags = 0L;
1110bbfda8aSnia	Atom *protocols = NULL;
1120bbfda8aSnia	int n;
1130bbfda8aSnia
1140bbfda8aSnia	if(XGetWMProtocols(dpy, tmp->w, &protocols, &n)) {
1150bbfda8aSnia		int i;
1160bbfda8aSnia		Atom *ap;
1170bbfda8aSnia
1180bbfda8aSnia		for(i = 0, ap = protocols; i < n; i++, ap++) {
1190bbfda8aSnia			if(*ap == XA_WM_TAKE_FOCUS) {
1200bbfda8aSnia				flags |= DoesWmTakeFocus;
1210bbfda8aSnia			}
1220bbfda8aSnia			if(*ap == XA_WM_SAVE_YOURSELF) {
1230bbfda8aSnia				flags |= DoesWmSaveYourself;
1240bbfda8aSnia			}
1250bbfda8aSnia			if(*ap == XA_WM_DELETE_WINDOW) {
1260bbfda8aSnia				flags |= DoesWmDeleteWindow;
1270bbfda8aSnia			}
1280bbfda8aSnia		}
1290bbfda8aSnia		if(protocols) {
1300bbfda8aSnia			XFree(protocols);
1310bbfda8aSnia		}
1320bbfda8aSnia	}
1330bbfda8aSnia	tmp->protocols = flags;
1340bbfda8aSnia}
1350bbfda8aSnia
1360bbfda8aSnia
1370bbfda8aSnia/*
1380bbfda8aSnia * Figure signs for calculating location offsets for a window dependent
1390bbfda8aSnia * on its gravity.
1400bbfda8aSnia *
1410bbfda8aSnia * Depending on how its gravity is set, offsets to window coordinates for
1420bbfda8aSnia * e.g. border widths may need to move either down (right) or up (left).
1430bbfda8aSnia * Or possibly not at all.  So we write multipliers into passed vars for
1440bbfda8aSnia * callers.
1450bbfda8aSnia *
1460bbfda8aSnia * Formerly in add_window.c
1470bbfda8aSnia */
1480bbfda8aSniavoid
1490bbfda8aSniaGetGravityOffsets(TwmWindow *tmp, int *xp, int *yp)
1500bbfda8aSnia{
1510bbfda8aSnia	static struct _gravity_offset {
1520bbfda8aSnia		int x, y;
1530bbfda8aSnia	} gravity_offsets[] = {
1540bbfda8aSnia		[ForgetGravity]    = {  0,  0 },
1550bbfda8aSnia		[NorthWestGravity] = { -1, -1 },
1560bbfda8aSnia		[NorthGravity]     = {  0, -1 },
1570bbfda8aSnia		[NorthEastGravity] = {  1, -1 },
1580bbfda8aSnia		[WestGravity]      = { -1,  0 },
1590bbfda8aSnia		[CenterGravity]    = {  0,  0 },
1600bbfda8aSnia		[EastGravity]      = {  1,  0 },
1610bbfda8aSnia		[SouthWestGravity] = { -1,  1 },
1620bbfda8aSnia		[SouthGravity]     = {  0,  1 },
1630bbfda8aSnia		[SouthEastGravity] = {  1,  1 },
1640bbfda8aSnia		[StaticGravity]    = {  0,  0 },
1650bbfda8aSnia	};
1660bbfda8aSnia	int g = ((tmp->hints.flags & PWinGravity)
1670bbfda8aSnia	         ? tmp->hints.win_gravity : NorthWestGravity);
1680bbfda8aSnia
1690bbfda8aSnia	if(g < ForgetGravity || g > StaticGravity) {
1700bbfda8aSnia		*xp = *yp = 0;
1710bbfda8aSnia	}
1720bbfda8aSnia	else {
1730bbfda8aSnia		*xp = gravity_offsets[g].x;
1740bbfda8aSnia		*yp = gravity_offsets[g].y;
1750bbfda8aSnia	}
1760bbfda8aSnia}
1770bbfda8aSnia
1780bbfda8aSnia
1790bbfda8aSnia/*
1800bbfda8aSnia * Finds the TwmWindow structure associated with a Window (if any), or
1810bbfda8aSnia * NULL.
1820bbfda8aSnia *
1830bbfda8aSnia * This is a relatively cheap function since it does not involve
1840bbfda8aSnia * communication with the server. Probably faster than walking the list
1850bbfda8aSnia * of TwmWindows, since the lookup is by a hash table.
1860bbfda8aSnia *
1870bbfda8aSnia * Formerly in add_window.c
1880bbfda8aSnia */
1890bbfda8aSniaTwmWindow *
1900bbfda8aSniaGetTwmWindow(Window w)
1910bbfda8aSnia{
1920bbfda8aSnia	TwmWindow *twmwin;
1930bbfda8aSnia	int stat;
1940bbfda8aSnia
1950bbfda8aSnia	stat = XFindContext(dpy, w, TwmContext, (XPointer *)&twmwin);
1960bbfda8aSnia	if(stat == XCNOENT) {
1970bbfda8aSnia		twmwin = NULL;
1980bbfda8aSnia	}
1990bbfda8aSnia
2000bbfda8aSnia	return twmwin;
2010bbfda8aSnia}
2020bbfda8aSnia
2030bbfda8aSnia
2040bbfda8aSnia/***********************************************************************
2050bbfda8aSnia *
2060bbfda8aSnia *  Procedure:
2070bbfda8aSnia *      GetWMPropertyString - Get Window Manager text property and
2080bbfda8aSnia *                              convert it to a string.
2090bbfda8aSnia *
2100bbfda8aSnia *  Returned Value:
2110bbfda8aSnia *      (char *) - pointer to the malloc'd string or NULL
2120bbfda8aSnia *
2130bbfda8aSnia *  Inputs:
2140bbfda8aSnia *      w       - the id of the window whose property is to be retrieved
2150bbfda8aSnia *      prop    - property atom (typically WM_NAME or WM_ICON_NAME)
2160bbfda8aSnia *
2170bbfda8aSnia ***********************************************************************
2180bbfda8aSnia *
2190bbfda8aSnia * Formerly in util.c
2200bbfda8aSnia */
2210bbfda8aSniachar *
2220bbfda8aSniaGetWMPropertyString(Window w, Atom prop)
2230bbfda8aSnia{
2240bbfda8aSnia	XTextProperty       text_prop;
2250bbfda8aSnia	char                *stringptr;
2260bbfda8aSnia
2270bbfda8aSnia	XGetTextProperty(dpy, w, &text_prop, prop);
2280bbfda8aSnia	if(text_prop.value == NULL) {
2290bbfda8aSnia		return NULL;
2300bbfda8aSnia	}
2310bbfda8aSnia
2320bbfda8aSnia	if(text_prop.encoding == XA_STRING
2330bbfda8aSnia	                || text_prop.encoding == XA_UTF8_STRING
2340bbfda8aSnia	                || text_prop.encoding == XA_COMPOUND_TEXT) {
2350bbfda8aSnia		/* property is encoded as compound text - convert to locale string */
2360bbfda8aSnia		char **text_list;
2370bbfda8aSnia		int  text_list_count;
2380bbfda8aSnia		int status;
2390bbfda8aSnia
2400bbfda8aSnia		/* Check historical strictness */
2410bbfda8aSnia		if(Scr->StrictWinNameEncoding) {
2420bbfda8aSnia			bool fail = false;
2430bbfda8aSnia
2440bbfda8aSnia			if((prop == XA_WM_NAME || prop == XA_WM_ICON_NAME)
2450bbfda8aSnia			                && text_prop.encoding != XA_STRING
2460bbfda8aSnia			                && text_prop.encoding != XA_COMPOUND_TEXT) {
2470bbfda8aSnia				fail = true;
2480bbfda8aSnia			}
2490bbfda8aSnia
2500bbfda8aSnia#ifdef EWMH
2510bbfda8aSnia			if((prop == XA__NET_WM_NAME || prop == XA__NET_WM_ICON_NAME)
2520bbfda8aSnia			                && text_prop.encoding != XA_UTF8_STRING) {
2530bbfda8aSnia				fail = true;
2540bbfda8aSnia			}
2550bbfda8aSnia#endif // EWMH
2560bbfda8aSnia
2570bbfda8aSnia			if(fail) {
2580bbfda8aSnia				fprintf(stderr, "%s: Invalid encoding for property %s "
2590bbfda8aSnia				        "of window 0x%lx\n", ProgramName,
2600bbfda8aSnia				        XGetAtomName(dpy, prop), w);
2610bbfda8aSnia				XFree(text_prop.value);
2620bbfda8aSnia				return NULL;
2630bbfda8aSnia			}
2640bbfda8aSnia		}
2650bbfda8aSnia
2660bbfda8aSnia
2670bbfda8aSnia		status = XmbTextPropertyToTextList(dpy, &text_prop, &text_list,
2680bbfda8aSnia		                                   &text_list_count);
2690bbfda8aSnia		if(text_list_count == 0
2700bbfda8aSnia		                || text_list == NULL
2710bbfda8aSnia		                || text_list[0] == NULL) {
2720bbfda8aSnia			// Got nothing
2730bbfda8aSnia			XFree(text_prop.value);
2740bbfda8aSnia			return NULL;
2750bbfda8aSnia		}
2760bbfda8aSnia		else if(status < 0 || text_list_count < 0) {
2770bbfda8aSnia			// Got an error statuf
2780bbfda8aSnia			switch(status) {
2790bbfda8aSnia				case XConverterNotFound:
2800bbfda8aSnia					fprintf(stderr,
2810bbfda8aSnia					        "%s: Converter not found; unable to convert property %s of window ID %lx.\n",
2820bbfda8aSnia					        ProgramName, XGetAtomName(dpy, prop), w);
2830bbfda8aSnia					break;
2840bbfda8aSnia				case XNoMemory:
2850bbfda8aSnia					fprintf(stderr,
2860bbfda8aSnia					        "%s: Insufficient memory; unable to convert property %s of window ID %lx.\n",
2870bbfda8aSnia					        ProgramName, XGetAtomName(dpy, prop), w);
2880bbfda8aSnia					break;
2890bbfda8aSnia				case XLocaleNotSupported:
2900bbfda8aSnia					fprintf(stderr,
2910bbfda8aSnia					        "%s: Locale not supported; unable to convert property %s of window ID %lx.\n",
2920bbfda8aSnia					        ProgramName, XGetAtomName(dpy, prop), w);
2930bbfda8aSnia					break;
2940bbfda8aSnia			}
2950bbfda8aSnia			stringptr = NULL;
2960bbfda8aSnia			/*
2970bbfda8aSnia			   don't call XFreeStringList - text_list appears to have
2980bbfda8aSnia			   invalid address if status is bad
2990bbfda8aSnia			   XFreeStringList(text_list);
3000bbfda8aSnia			*/
3010bbfda8aSnia		}
3020bbfda8aSnia		else {
3030bbfda8aSnia			// Actually got the data!
3040bbfda8aSnia			stringptr = strdup(text_list[0]);
3050bbfda8aSnia			XFreeStringList(text_list);
3060bbfda8aSnia		}
3070bbfda8aSnia	}
3080bbfda8aSnia	else {
3090bbfda8aSnia		/* property is encoded in a format we don't understand */
3100bbfda8aSnia		fprintf(stderr,
3110bbfda8aSnia		        "%s: Encoding not STRING or COMPOUND_TEXT; unable to decode property %s of window ID %lx.\n",
3120bbfda8aSnia		        ProgramName, XGetAtomName(dpy, prop), w);
3130bbfda8aSnia		stringptr = NULL;
3140bbfda8aSnia	}
3150bbfda8aSnia	XFree(text_prop.value);
3160bbfda8aSnia
3170bbfda8aSnia	return stringptr;
3180bbfda8aSnia}
3190bbfda8aSnia
3200bbfda8aSnia
3210bbfda8aSnia/*
3220bbfda8aSnia * Cleanup something stored that we got from the above originally.
3230bbfda8aSnia *
3240bbfda8aSnia * Formerly in util.c
3250bbfda8aSnia */
3260bbfda8aSniavoid
3270bbfda8aSniaFreeWMPropertyString(char *prop)
3280bbfda8aSnia{
3290bbfda8aSnia	if(prop && prop != NoName) {
3300bbfda8aSnia		free(prop);
3310bbfda8aSnia	}
3320bbfda8aSnia}
3330bbfda8aSnia
3340bbfda8aSnia
3350bbfda8aSnia/*
3360bbfda8aSnia * Window mapped on some virtual screen?
3370bbfda8aSnia *
3380bbfda8aSnia * Formerly in util.c
3390bbfda8aSnia */
3400bbfda8aSniabool
3410bbfda8aSniavisible(const TwmWindow *tmp_win)
3420bbfda8aSnia{
3430bbfda8aSnia	return (tmp_win->vs != NULL);
3440bbfda8aSnia}
3450bbfda8aSnia
3460bbfda8aSnia
3470bbfda8aSnia/*
3480bbfda8aSnia * Various code paths do a dance of "mask off notifications of event type
3490bbfda8aSnia * ; do something that triggers that event (but we're doing it, so we
3500bbfda8aSnia * don't need the notification) ; restore previous mask".  So have some
3510bbfda8aSnia * util funcs to make it more visually obvious.
3520bbfda8aSnia *
3530bbfda8aSnia * e.g.:
3540bbfda8aSnia *     long prev_mask = mask_out_event(w, PropertyChangeMask);
3550bbfda8aSnia *     do_something_that_changes_properties();
3560bbfda8aSnia *     restore_mask(prev_mask);
3570bbfda8aSnia *
3580bbfda8aSnia * We're cheating a little with the -1 return on mask_out_event(), as
3590bbfda8aSnia * that's theoretically valid for the data type.  It's not as far as I
3600bbfda8aSnia * can tell for X or us though; having all the bits set (well, I guess
3610bbfda8aSnia * I'm assuming 2s-complement too) is pretty absurd, and there are only
3620bbfda8aSnia * 25 defined bits in Xlib, so even on 32-bit systems, it shouldn't fill
3630bbfda8aSnia * up long.
3640bbfda8aSnia */
3650bbfda8aSnialong
3660bbfda8aSniamask_out_event(Window w, long ignore_event)
3670bbfda8aSnia{
3680bbfda8aSnia	XWindowAttributes wattr;
3690bbfda8aSnia
3700bbfda8aSnia	/* Get current mask */
3710bbfda8aSnia	if(XGetWindowAttributes(dpy, w, &wattr) == 0) {
3720bbfda8aSnia		return -1;
3730bbfda8aSnia	}
3740bbfda8aSnia
3750bbfda8aSnia	/*
3760bbfda8aSnia	 * If we're ignoring nothing, nothing to do.  This is probably not
3770bbfda8aSnia	 * strictly speaking a useful thing to ask for in general, but it's
3780bbfda8aSnia	 * the right thing for us to do if we're asked to do nothing.
3790bbfda8aSnia	 */
3800bbfda8aSnia	if(ignore_event == 0) {
3810bbfda8aSnia		return wattr.your_event_mask;
3820bbfda8aSnia	}
3830bbfda8aSnia
3840bbfda8aSnia	/* Delegate */
3850bbfda8aSnia	return mask_out_event_mask(w, ignore_event, wattr.your_event_mask);
3860bbfda8aSnia}
3870bbfda8aSnia
3880bbfda8aSnialong
3890bbfda8aSniamask_out_event_mask(Window w, long ignore_event, long curmask)
3900bbfda8aSnia{
3910bbfda8aSnia	/* Set to the current, minus what we're wanting to ignore */
3920bbfda8aSnia	XSelectInput(dpy, w, (curmask & ~ignore_event));
3930bbfda8aSnia
3940bbfda8aSnia	/* Return what it was */
3950bbfda8aSnia	return curmask;
3960bbfda8aSnia}
3970bbfda8aSnia
3980bbfda8aSniaint
3990bbfda8aSniarestore_mask(Window w, long restore)
4000bbfda8aSnia{
4010bbfda8aSnia	return XSelectInput(dpy, w, restore);
4020bbfda8aSnia}
4030bbfda8aSnia
4040bbfda8aSnia
4050bbfda8aSnia/*
4060bbfda8aSnia * Setting and getting WM_STATE property.
4070bbfda8aSnia *
4080bbfda8aSnia * x-ref ICCCM section 4.1.3.1
4090bbfda8aSnia * https://tronche.com/gui/x/icccm/sec-4.html#s-4.1.3.1
4100bbfda8aSnia *
4110bbfda8aSnia * XXX These should probably be named more alike, as they're
4120bbfda8aSnia * complementary ops.
4130bbfda8aSnia */
4140bbfda8aSniavoid
4150bbfda8aSniaSetMapStateProp(TwmWindow *tmp_win, int state)
4160bbfda8aSnia{
4170bbfda8aSnia	unsigned long data[2];              /* "suggested" by ICCCM version 1 */
4180bbfda8aSnia
4190bbfda8aSnia	data[0] = (unsigned long) state;
4200bbfda8aSnia	data[1] = (unsigned long)(tmp_win->iconify_by_unmapping ? None :
4210bbfda8aSnia	                          (tmp_win->icon ? tmp_win->icon->w : None));
4220bbfda8aSnia
4230bbfda8aSnia	XChangeProperty(dpy, tmp_win->w, XA_WM_STATE, XA_WM_STATE, 32,
4240bbfda8aSnia	                PropModeReplace, (unsigned char *) data, 2);
4250bbfda8aSnia}
4260bbfda8aSnia
4270bbfda8aSnia
4280bbfda8aSniabool
4290bbfda8aSniaGetWMState(Window w, int *statep, Window *iwp)
4300bbfda8aSnia{
4310bbfda8aSnia	Atom actual_type;
4320bbfda8aSnia	int actual_format;
4330bbfda8aSnia	unsigned long nitems, bytesafter;
4340bbfda8aSnia	unsigned long *datap = NULL;
4350bbfda8aSnia	bool retval = false;
4360bbfda8aSnia
4370bbfda8aSnia	if(XGetWindowProperty(dpy, w, XA_WM_STATE, 0L, 2L, False, XA_WM_STATE,
4380bbfda8aSnia	                      &actual_type, &actual_format, &nitems, &bytesafter,
4390bbfda8aSnia	                      (unsigned char **) &datap) != Success || !datap) {
4400bbfda8aSnia		return false;
4410bbfda8aSnia	}
4420bbfda8aSnia
4430bbfda8aSnia	if(nitems <= 2) {                   /* "suggested" by ICCCM version 1 */
4440bbfda8aSnia		*statep = (int) datap[0];
4450bbfda8aSnia		*iwp = (Window) datap[1];
4460bbfda8aSnia		retval = true;
4470bbfda8aSnia	}
4480bbfda8aSnia
4490bbfda8aSnia	XFree(datap);
4500bbfda8aSnia	return retval;
4510bbfda8aSnia}
4520bbfda8aSnia
4530bbfda8aSnia
4540bbfda8aSnia/*
4550bbfda8aSnia * Display a window's position in the dimensions window.  This is used
4560bbfda8aSnia * during various window positioning (during new window popups, moves,
4570bbfda8aSnia * etc).
4580bbfda8aSnia *
4590bbfda8aSnia * This reuses the same window for the position as is used during
4600bbfda8aSnia * resizing for the dimesions of the window in DisplaySize().  The
4610bbfda8aSnia * innards of the funcs can probably be collapsed together a little, and
4620bbfda8aSnia * the higher-level knowledge of Scr->SizeWindow (e.g., for unmapping
4630bbfda8aSnia * after ths op is done) should probably be encapsulated a bit better.
4640bbfda8aSnia */
4650bbfda8aSniavoid
4660bbfda8aSniaDisplayPosition(const TwmWindow *_unused_tmp_win, int x, int y)
4670bbfda8aSnia{
4680bbfda8aSnia	char str [100];
4690bbfda8aSnia	char signx = '+';
4700bbfda8aSnia	char signy = '+';
4710bbfda8aSnia
4720bbfda8aSnia	if(x < 0) {
4730bbfda8aSnia		x = -x;
4740bbfda8aSnia		signx = '-';
4750bbfda8aSnia	}
4760bbfda8aSnia	if(y < 0) {
4770bbfda8aSnia		y = -y;
4780bbfda8aSnia		signy = '-';
4790bbfda8aSnia	}
4800bbfda8aSnia	sprintf(str, " %c%-4d %c%-4d ", signx, x, signy, y);
4810bbfda8aSnia	XRaiseWindow(dpy, Scr->SizeWindow);
4820bbfda8aSnia
4830bbfda8aSnia	Draw3DBorder(Scr->SizeWindow, 0, 0,
4840bbfda8aSnia	             Scr->SizeStringOffset + Scr->SizeStringWidth + SIZE_HINDENT,
4850bbfda8aSnia	             Scr->SizeFont.height + SIZE_VINDENT * 2,
4860bbfda8aSnia	             2, Scr->DefaultC, off, false, false);
4870bbfda8aSnia
4880bbfda8aSnia	FB(Scr->DefaultC.fore, Scr->DefaultC.back);
4890bbfda8aSnia	XmbDrawImageString(dpy, Scr->SizeWindow, Scr->SizeFont.font_set,
4900bbfda8aSnia	                   Scr->NormalGC, Scr->SizeStringOffset,
4910bbfda8aSnia	                   Scr->SizeFont.ascent + SIZE_VINDENT, str, 13);
4920bbfda8aSnia}
4930bbfda8aSnia
494b18c2d1eSniavoid
495b18c2d1eSniaMoveResizeSizeWindow(int x, int y, unsigned int width, unsigned int height)
496b18c2d1eSnia{
497b18c2d1eSnia	XResizeWindow(dpy, Scr->SizeWindow, width, height);
498b18c2d1eSnia
499b18c2d1eSnia	if(Scr->CenterFeedbackWindow) {
500b18c2d1eSnia		RArea monitor = RLayoutGetAreaAtXY(Scr->BorderedLayout, x, y);
501b18c2d1eSnia
502b18c2d1eSnia		XMoveWindow(dpy, Scr->SizeWindow,
503b18c2d1eSnia		            monitor.x + monitor.width / 2 - width / 2,
504b18c2d1eSnia		            monitor.y + monitor.height / 2 - height / 2);
505b18c2d1eSnia	}
506b18c2d1eSnia}
507b18c2d1eSnia
5080bbfda8aSnia
5090bbfda8aSnia/*
5100bbfda8aSnia * Various funcs for adjusting coordinates for windows based on
5110bbfda8aSnia * resistances etc.
5120bbfda8aSnia *
5130bbfda8aSnia * XXX In desperate need of better commenting.
5140bbfda8aSnia */
515b18c2d1eSniastatic void
516b18c2d1eSnia_tryToPack(RArea *final, const RArea *cur_win)
517b18c2d1eSnia{
518b18c2d1eSnia	if(final->x >= cur_win->x + cur_win->width) {
519b18c2d1eSnia		return;
520b18c2d1eSnia	}
521b18c2d1eSnia	if(final->y >= cur_win->y + cur_win->height) {
522b18c2d1eSnia		return;
523b18c2d1eSnia	}
524b18c2d1eSnia	if(final->x + final->width <= cur_win->x) {
525b18c2d1eSnia		return;
526b18c2d1eSnia	}
527b18c2d1eSnia	if(final->y + final->height <= cur_win->y) {
528b18c2d1eSnia		return;
529b18c2d1eSnia	}
530b18c2d1eSnia
531b18c2d1eSnia	if(final->x + Scr->MovePackResistance > cur_win->x +
532b18c2d1eSnia	                cur_win->width) {  /* left */
533b18c2d1eSnia		final->x = MAX(final->x, cur_win->x + cur_win->width);
534b18c2d1eSnia		return;
535b18c2d1eSnia	}
536b18c2d1eSnia	if(final->x + final->width < cur_win->x +
537b18c2d1eSnia	                Scr->MovePackResistance) {  /* right */
538b18c2d1eSnia		final->x = MIN(final->x, cur_win->x - final->width);
539b18c2d1eSnia		return;
540b18c2d1eSnia	}
541b18c2d1eSnia	if(final->y + Scr->MovePackResistance > cur_win->y +
542b18c2d1eSnia	                cur_win->height) {  /* top */
543b18c2d1eSnia		final->y = MAX(final->y, cur_win->y + cur_win->height);
544b18c2d1eSnia		return;
545b18c2d1eSnia	}
546b18c2d1eSnia	if(final->y + final->height < cur_win->y +
547b18c2d1eSnia	                Scr->MovePackResistance) {  /* bottom */
548b18c2d1eSnia		final->y = MIN(final->y, cur_win->y - final->height);
549b18c2d1eSnia	}
550b18c2d1eSnia}
551b18c2d1eSnia
552b18c2d1eSniastatic bool
553b18c2d1eSnia_tryToPackVsEachMonitor(const RArea *monitor_area, void *vfinal)
554b18c2d1eSnia{
555b18c2d1eSnia	_tryToPack((RArea *)vfinal, monitor_area);
556b18c2d1eSnia	return false;
557b18c2d1eSnia}
558b18c2d1eSnia
5590bbfda8aSniavoid
5600bbfda8aSniaTryToPack(TwmWindow *tmp_win, int *x, int *y)
5610bbfda8aSnia{
5620bbfda8aSnia	TwmWindow   *t;
563b18c2d1eSnia	RArea cur_win;
564b18c2d1eSnia	RArea final = RAreaNew(*x, *y,
565b18c2d1eSnia	                       tmp_win->frame_width  + 2 * tmp_win->frame_bw,
566b18c2d1eSnia	                       tmp_win->frame_height + 2 * tmp_win->frame_bw);
567b18c2d1eSnia
568b18c2d1eSnia	/* Global layout is not a single rectangle, check against the
569b18c2d1eSnia	 * monitor borders */
570b18c2d1eSnia	if(Scr->BorderedLayout->horiz->len > 1) {
571b18c2d1eSnia		RAreaListForeach(
572b18c2d1eSnia		        Scr->BorderedLayout->monitors, _tryToPackVsEachMonitor, &final);
573b18c2d1eSnia	}
5740bbfda8aSnia
5750bbfda8aSnia	for(t = Scr->FirstWindow; t != NULL; t = t->next) {
5760bbfda8aSnia		if(t == tmp_win) {
5770bbfda8aSnia			continue;
5780bbfda8aSnia		}
579b18c2d1eSnia#ifdef WINBOX
5800bbfda8aSnia		if(t->winbox != tmp_win->winbox) {
5810bbfda8aSnia			continue;
5820bbfda8aSnia		}
583b18c2d1eSnia#endif
5840bbfda8aSnia		if(t->vs != tmp_win->vs) {
5850bbfda8aSnia			continue;
5860bbfda8aSnia		}
5870bbfda8aSnia		if(!t->mapped) {
5880bbfda8aSnia			continue;
5890bbfda8aSnia		}
5900bbfda8aSnia
591b18c2d1eSnia		cur_win = RAreaNew(t->frame_x, t->frame_y,
592b18c2d1eSnia		                   t->frame_width  + 2 * t->frame_bw,
593b18c2d1eSnia		                   t->frame_height + 2 * t->frame_bw);
5940bbfda8aSnia
595b18c2d1eSnia		_tryToPack(&final, &cur_win);
5960bbfda8aSnia	}
597b18c2d1eSnia
598b18c2d1eSnia	*x = final.x;
599b18c2d1eSnia	*y = final.y;
6000bbfda8aSnia}
6010bbfda8aSnia
6020bbfda8aSnia
6030bbfda8aSnia/*
6040bbfda8aSnia * Directionals for TryToPush_be().  These differ from the specs for
6050bbfda8aSnia * jump/pack/fill in functions. because there's an indeterminate option.
6060bbfda8aSnia */
6070bbfda8aSniatypedef enum {
6080bbfda8aSnia	PD_ANY,
6090bbfda8aSnia	PD_BOTTOM,
6100bbfda8aSnia	PD_LEFT,
6110bbfda8aSnia	PD_RIGHT,
6120bbfda8aSnia	PD_TOP,
6130bbfda8aSnia} PushDirection;
6140bbfda8aSniastatic void TryToPush_be(TwmWindow *tmp_win, int x, int y, PushDirection dir);
6150bbfda8aSnia
6160bbfda8aSniavoid
6170bbfda8aSniaTryToPush(TwmWindow *tmp_win, int x, int y)
6180bbfda8aSnia{
6190bbfda8aSnia	TryToPush_be(tmp_win, x, y, PD_ANY);
6200bbfda8aSnia}
6210bbfda8aSnia
6220bbfda8aSniastatic void
6230bbfda8aSniaTryToPush_be(TwmWindow *tmp_win, int x, int y, PushDirection dir)
6240bbfda8aSnia{
6250bbfda8aSnia	TwmWindow   *t;
6260bbfda8aSnia	int         newx, newy, ndir;
6270bbfda8aSnia	bool        move;
6280bbfda8aSnia	int         w, h;
6290bbfda8aSnia	int         winw = tmp_win->frame_width  + 2 * tmp_win->frame_bw;
6300bbfda8aSnia	int         winh = tmp_win->frame_height + 2 * tmp_win->frame_bw;
6310bbfda8aSnia
6320bbfda8aSnia	for(t = Scr->FirstWindow; t != NULL; t = t->next) {
6330bbfda8aSnia		if(t == tmp_win) {
6340bbfda8aSnia			continue;
6350bbfda8aSnia		}
636b18c2d1eSnia#ifdef WINBOX
6370bbfda8aSnia		if(t->winbox != tmp_win->winbox) {
6380bbfda8aSnia			continue;
6390bbfda8aSnia		}
640b18c2d1eSnia#endif
6410bbfda8aSnia		if(t->vs != tmp_win->vs) {
6420bbfda8aSnia			continue;
6430bbfda8aSnia		}
6440bbfda8aSnia		if(!t->mapped) {
6450bbfda8aSnia			continue;
6460bbfda8aSnia		}
6470bbfda8aSnia
6480bbfda8aSnia		w = t->frame_width  + 2 * t->frame_bw;
6490bbfda8aSnia		h = t->frame_height + 2 * t->frame_bw;
6500bbfda8aSnia		if(x >= t->frame_x + w) {
6510bbfda8aSnia			continue;
6520bbfda8aSnia		}
6530bbfda8aSnia		if(y >= t->frame_y + h) {
6540bbfda8aSnia			continue;
6550bbfda8aSnia		}
6560bbfda8aSnia		if(x + winw <= t->frame_x) {
6570bbfda8aSnia			continue;
6580bbfda8aSnia		}
6590bbfda8aSnia		if(y + winh <= t->frame_y) {
6600bbfda8aSnia			continue;
6610bbfda8aSnia		}
6620bbfda8aSnia
6630bbfda8aSnia		move = false;
6640bbfda8aSnia		if((dir == PD_ANY || dir == PD_LEFT) &&
6650bbfda8aSnia		                (x + Scr->MovePackResistance > t->frame_x + w)) {
6660bbfda8aSnia			newx = x - w;
6670bbfda8aSnia			newy = t->frame_y;
6680bbfda8aSnia			ndir = PD_LEFT;
6690bbfda8aSnia			move = true;
6700bbfda8aSnia		}
6710bbfda8aSnia		else if((dir == PD_ANY || dir == PD_RIGHT) &&
6720bbfda8aSnia		                (x + winw < t->frame_x + Scr->MovePackResistance)) {
6730bbfda8aSnia			newx = x + winw;
6740bbfda8aSnia			newy = t->frame_y;
6750bbfda8aSnia			ndir = PD_RIGHT;
6760bbfda8aSnia			move = true;
6770bbfda8aSnia		}
6780bbfda8aSnia		else if((dir == PD_ANY || dir == PD_TOP) &&
6790bbfda8aSnia		                (y + Scr->MovePackResistance > t->frame_y + h)) {
6800bbfda8aSnia			newx = t->frame_x;
6810bbfda8aSnia			newy = y - h;
6820bbfda8aSnia			ndir = PD_TOP;
6830bbfda8aSnia			move = true;
6840bbfda8aSnia		}
6850bbfda8aSnia		else if((dir == PD_ANY || dir == PD_BOTTOM) &&
6860bbfda8aSnia		                (y + winh < t->frame_y + Scr->MovePackResistance)) {
6870bbfda8aSnia			newx = t->frame_x;
6880bbfda8aSnia			newy = y + winh;
6890bbfda8aSnia			ndir = PD_BOTTOM;
6900bbfda8aSnia			move = true;
6910bbfda8aSnia		}
6920bbfda8aSnia		if(move) {
6930bbfda8aSnia			TryToPush_be(t, newx, newy, ndir);
6940bbfda8aSnia			TryToPack(t, &newx, &newy);
6950bbfda8aSnia			ConstrainByBorders(tmp_win,
6960bbfda8aSnia			                   &newx, t->frame_width  + 2 * t->frame_bw,
6970bbfda8aSnia			                   &newy, t->frame_height + 2 * t->frame_bw);
6980bbfda8aSnia			SetupWindow(t, newx, newy, t->frame_width, t->frame_height, -1);
6990bbfda8aSnia		}
7000bbfda8aSnia	}
7010bbfda8aSnia}
7020bbfda8aSnia
7030bbfda8aSnia
7040bbfda8aSniavoid
7050bbfda8aSniaTryToGrid(TwmWindow *tmp_win, int *x, int *y)
7060bbfda8aSnia{
7070bbfda8aSnia	int w    = tmp_win->frame_width  + 2 * tmp_win->frame_bw;
7080bbfda8aSnia	int h    = tmp_win->frame_height + 2 * tmp_win->frame_bw;
7090bbfda8aSnia	int grav = ((tmp_win->hints.flags & PWinGravity)
7100bbfda8aSnia	            ? tmp_win->hints.win_gravity : NorthWestGravity);
7110bbfda8aSnia
7120bbfda8aSnia	switch(grav) {
7130bbfda8aSnia		case ForgetGravity :
7140bbfda8aSnia		case StaticGravity :
7150bbfda8aSnia		case NorthWestGravity :
7160bbfda8aSnia		case NorthGravity :
7170bbfda8aSnia		case WestGravity :
7180bbfda8aSnia		case CenterGravity :
7190bbfda8aSnia			*x = ((*x - Scr->BorderLeft) / Scr->XMoveGrid) * Scr->XMoveGrid
7200bbfda8aSnia			     + Scr->BorderLeft;
7210bbfda8aSnia			*y = ((*y - Scr->BorderTop) / Scr->YMoveGrid) * Scr->YMoveGrid
7220bbfda8aSnia			     + Scr->BorderTop;
7230bbfda8aSnia			break;
7240bbfda8aSnia		case NorthEastGravity :
7250bbfda8aSnia		case EastGravity :
7260bbfda8aSnia			*x = (((*x + w - Scr->BorderLeft) / Scr->XMoveGrid) *
7270bbfda8aSnia			      Scr->XMoveGrid) - w + Scr->BorderLeft;
7280bbfda8aSnia			*y = ((*y - Scr->BorderTop) / Scr->YMoveGrid) *
7290bbfda8aSnia			     Scr->YMoveGrid + Scr->BorderTop;
7300bbfda8aSnia			break;
7310bbfda8aSnia		case SouthWestGravity :
7320bbfda8aSnia		case SouthGravity :
7330bbfda8aSnia			*x = ((*x - Scr->BorderLeft) / Scr->XMoveGrid) * Scr->XMoveGrid
7340bbfda8aSnia			     + Scr->BorderLeft;
7350bbfda8aSnia			*y = (((*y + h - Scr->BorderTop) / Scr->YMoveGrid) * Scr->YMoveGrid)
7360bbfda8aSnia			     - h + Scr->BorderTop;
7370bbfda8aSnia			break;
7380bbfda8aSnia		case SouthEastGravity :
7390bbfda8aSnia			*x = (((*x + w - Scr->BorderLeft) / Scr->XMoveGrid) *
7400bbfda8aSnia			      Scr->XMoveGrid) - w + Scr->BorderLeft;
7410bbfda8aSnia			*y = (((*y + h - Scr->BorderTop) / Scr->YMoveGrid) *
7420bbfda8aSnia			      Scr->YMoveGrid) - h + Scr->BorderTop;
7430bbfda8aSnia			break;
7440bbfda8aSnia	}
7450bbfda8aSnia}
7460bbfda8aSnia
7470bbfda8aSnia
7480bbfda8aSnia
749b18c2d1eSnia#ifdef WINBOX
7500bbfda8aSnia/*
7510bbfda8aSnia * Functions related to keeping windows from being placed off-screen (or
7520bbfda8aSnia * off-screen too far).  Involved in handling of params like DontMoveOff
7530bbfda8aSnia * and MoveOffResistance, etc.
7540bbfda8aSnia */
7550bbfda8aSniastatic void ConstrainLeftTop(int *value, int border);
7560bbfda8aSniastatic void ConstrainRightBottom(int *value, int size1, int border, int size2);
757b18c2d1eSnia#endif
758b18c2d1eSnia
759b18c2d1eSniabool
760b18c2d1eSniaConstrainByLayout(RLayout *layout, int move_off_res, int *left, int width,
761b18c2d1eSnia                  int *top, int height)
762b18c2d1eSnia{
763b18c2d1eSnia	RArea area = RAreaNew(*left, *top, width, height);
764b18c2d1eSnia	int limit;
765b18c2d1eSnia	bool clipped = false;
766b18c2d1eSnia
767b18c2d1eSnia	limit = RLayoutFindBottomEdge(layout, &area) - height + 1;
768b18c2d1eSnia	if(area.y > limit) {
769b18c2d1eSnia		if(move_off_res >= 0 && area.y >= limit + move_off_res) {
770b18c2d1eSnia			area.y -= move_off_res;
771b18c2d1eSnia		}
772b18c2d1eSnia		else {
773b18c2d1eSnia			area.y = limit;
774b18c2d1eSnia			clipped = true;
775b18c2d1eSnia		}
776b18c2d1eSnia	}
777b18c2d1eSnia
778b18c2d1eSnia	limit = RLayoutFindRightEdge(layout, &area) - width + 1;
779b18c2d1eSnia	if(area.x > limit) {
780b18c2d1eSnia		if(move_off_res >= 0 && area.x >= limit + move_off_res) {
781b18c2d1eSnia			area.x -= move_off_res;
782b18c2d1eSnia		}
783b18c2d1eSnia		else {
784b18c2d1eSnia			area.x = limit;
785b18c2d1eSnia			clipped = true;
786b18c2d1eSnia		}
787b18c2d1eSnia	}
788b18c2d1eSnia
789b18c2d1eSnia	limit = RLayoutFindLeftEdge(layout, &area);
790b18c2d1eSnia	if(area.x < limit) {
791b18c2d1eSnia		if(move_off_res >= 0 && area.x <= limit - move_off_res) {
792b18c2d1eSnia			area.x += move_off_res;
793b18c2d1eSnia		}
794b18c2d1eSnia		else {
795b18c2d1eSnia			area.x = limit;
796b18c2d1eSnia			clipped = true;
797b18c2d1eSnia		}
798b18c2d1eSnia	}
799b18c2d1eSnia
800b18c2d1eSnia	limit = RLayoutFindTopEdge(layout, &area);
801b18c2d1eSnia	if(area.y < limit) {
802b18c2d1eSnia		if(move_off_res >= 0 && area.y <= limit - move_off_res) {
803b18c2d1eSnia			area.y += move_off_res;
804b18c2d1eSnia		}
805b18c2d1eSnia		else {
806b18c2d1eSnia			area.y = limit;
807b18c2d1eSnia			clipped = true;
808b18c2d1eSnia		}
809b18c2d1eSnia	}
810b18c2d1eSnia
811b18c2d1eSnia	*left = area.x;
812b18c2d1eSnia	*top = area.y;
813b18c2d1eSnia
814b18c2d1eSnia	return clipped;
815b18c2d1eSnia}
8160bbfda8aSnia
8170bbfda8aSniavoid
8180bbfda8aSniaConstrainByBorders1(int *left, int width, int *top, int height)
8190bbfda8aSnia{
820b18c2d1eSnia	ConstrainByLayout(Scr->BorderedLayout, Scr->MoveOffResistance,
821b18c2d1eSnia	                  left, width, top, height);
8220bbfda8aSnia}
8230bbfda8aSnia
8240bbfda8aSniavoid
8250bbfda8aSniaConstrainByBorders(TwmWindow *twmwin, int *left, int width,
8260bbfda8aSnia                   int *top, int height)
8270bbfda8aSnia{
828b18c2d1eSnia	if(false) {
829b18c2d1eSnia		// Dummy
830b18c2d1eSnia	}
831b18c2d1eSnia#ifdef WINBOX
832b18c2d1eSnia	else if(twmwin->winbox) {
8330bbfda8aSnia		XWindowAttributes attr;
8340bbfda8aSnia		XGetWindowAttributes(dpy, twmwin->winbox->window, &attr);
8350bbfda8aSnia		ConstrainRightBottom(left, width, 0, attr.width);
8360bbfda8aSnia		ConstrainLeftTop(left, 0);
8370bbfda8aSnia		ConstrainRightBottom(top, height, 0, attr.height);
8380bbfda8aSnia		ConstrainLeftTop(top, 0);
8390bbfda8aSnia	}
840b18c2d1eSnia#endif
8410bbfda8aSnia	else {
8420bbfda8aSnia		ConstrainByBorders1(left, width, top, height);
8430bbfda8aSnia	}
8440bbfda8aSnia}
8450bbfda8aSnia
846b18c2d1eSnia#ifdef WINBOX
8470bbfda8aSniastatic void
8480bbfda8aSniaConstrainLeftTop(int *value, int border)
8490bbfda8aSnia{
8500bbfda8aSnia	if(*value < border) {
8510bbfda8aSnia		if(Scr->MoveOffResistance < 0 ||
8520bbfda8aSnia		                *value > border - Scr->MoveOffResistance) {
8530bbfda8aSnia			*value = border;
8540bbfda8aSnia		}
8550bbfda8aSnia		else if(Scr->MoveOffResistance > 0 &&
8560bbfda8aSnia		                *value <= border - Scr->MoveOffResistance) {
8570bbfda8aSnia			*value = *value + Scr->MoveOffResistance;
8580bbfda8aSnia		}
8590bbfda8aSnia	}
8600bbfda8aSnia}
8610bbfda8aSnia
8620bbfda8aSniastatic void
8630bbfda8aSniaConstrainRightBottom(int *value, int size1, int border, int size2)
8640bbfda8aSnia{
8650bbfda8aSnia	if(*value + size1 > size2 - border) {
8660bbfda8aSnia		if(Scr->MoveOffResistance < 0 ||
8670bbfda8aSnia		                *value + size1 < size2 - border + Scr->MoveOffResistance) {
8680bbfda8aSnia			*value = size2 - size1 - border;
8690bbfda8aSnia		}
8700bbfda8aSnia		else if(Scr->MoveOffResistance > 0 &&
8710bbfda8aSnia		                *value + size1 >= size2 - border + Scr->MoveOffResistance) {
8720bbfda8aSnia			*value = *value - Scr->MoveOffResistance;
8730bbfda8aSnia		}
8740bbfda8aSnia	}
8750bbfda8aSnia}
876b18c2d1eSnia#endif
8770bbfda8aSnia
8780bbfda8aSnia
8790bbfda8aSnia/*
8800bbfda8aSnia * Zoom over to a particular window.
8810bbfda8aSnia */
8820bbfda8aSniavoid
8830bbfda8aSniaWarpToWindow(TwmWindow *t, bool must_raise)
8840bbfda8aSnia{
8850bbfda8aSnia	int x, y;
8860bbfda8aSnia
8870bbfda8aSnia	if(t->ring.cursor_valid) {
8880bbfda8aSnia		x = t->ring.curs_x;
8890bbfda8aSnia		y = t->ring.curs_y;
8900bbfda8aSnia#ifdef DEBUG
8910bbfda8aSnia		fprintf(stderr, "WarpToWindow: cursor_valid; x == %d, y == %d\n", x, y);
8920bbfda8aSnia#endif
8930bbfda8aSnia
8940bbfda8aSnia		/*
8950bbfda8aSnia		 * XXX is this correct with 3D borders? Easier check possible?
8960bbfda8aSnia		 * frame_bw is for the left border.
8970bbfda8aSnia		 */
8980bbfda8aSnia		if(x < t->frame_bw) {
8990bbfda8aSnia			x = t->frame_bw;
9000bbfda8aSnia		}
9010bbfda8aSnia		if(x >= t->frame_width + t->frame_bw) {
9020bbfda8aSnia			x  = t->frame_width + t->frame_bw - 1;
9030bbfda8aSnia		}
9040bbfda8aSnia		if(y < t->title_height + t->frame_bw) {
9050bbfda8aSnia			y = t->title_height + t->frame_bw;
9060bbfda8aSnia		}
9070bbfda8aSnia		if(y >= t->frame_height + t->frame_bw) {
9080bbfda8aSnia			y  = t->frame_height + t->frame_bw - 1;
9090bbfda8aSnia		}
9100bbfda8aSnia#ifdef DEBUG
9110bbfda8aSnia		fprintf(stderr, "WarpToWindow: adjusted    ; x := %d, y := %d\n", x, y);
9120bbfda8aSnia#endif
9130bbfda8aSnia	}
9140bbfda8aSnia	else {
9150bbfda8aSnia		x = t->frame_width / 2;
9160bbfda8aSnia		y = t->frame_height / 2;
9170bbfda8aSnia#ifdef DEBUG
9180bbfda8aSnia		fprintf(stderr, "WarpToWindow: middle; x := %d, y := %d\n", x, y);
9190bbfda8aSnia#endif
9200bbfda8aSnia	}
9210bbfda8aSnia#if 0
9220bbfda8aSnia	int dest_x, dest_y;
9230bbfda8aSnia	Window child;
9240bbfda8aSnia
9250bbfda8aSnia	/*
9260bbfda8aSnia	 * Check if the proposed position actually is visible. If not, raise the window.
9270bbfda8aSnia	 * "If the coordinates are contained in a mapped
9280bbfda8aSnia	 * child of dest_w, that child is returned to child_return."
9290bbfda8aSnia	 * We'll need to check for the right child window; the frame probably.
9300bbfda8aSnia	 * (What about XXX window boxes?)
9310bbfda8aSnia	 *
9320bbfda8aSnia	 * Alternatively, use XQueryPointer() which returns the root window
9330bbfda8aSnia	 * the pointer is in, but XXX that won't work for VirtualScreens.
9340bbfda8aSnia	 */
9350bbfda8aSnia	if(XTranslateCoordinates(dpy, t->frame, Scr->Root, x, y, &dest_x, &dest_y,
9360bbfda8aSnia	                         &child)) {
9370bbfda8aSnia		if(child != t->frame) {
9380bbfda8aSnia			must_raise = true;
9390bbfda8aSnia		}
9400bbfda8aSnia	}
9410bbfda8aSnia#endif
9420bbfda8aSnia	if(t->auto_raise || must_raise) {
9430bbfda8aSnia		AutoRaiseWindow(t);
9440bbfda8aSnia	}
9450bbfda8aSnia	if(! visible(t)) {
9460bbfda8aSnia		WorkSpace *wlist;
9470bbfda8aSnia
9480bbfda8aSnia		for(wlist = Scr->workSpaceMgr.workSpaceList; wlist != NULL;
9490bbfda8aSnia		                wlist = wlist->next) {
9500bbfda8aSnia			if(OCCUPY(t, wlist)) {
9510bbfda8aSnia				break;
9520bbfda8aSnia			}
9530bbfda8aSnia		}
9540bbfda8aSnia		if(wlist != NULL) {
9550bbfda8aSnia			GotoWorkSpace(Scr->currentvs, wlist);
9560bbfda8aSnia		}
9570bbfda8aSnia	}
9580bbfda8aSnia
9590bbfda8aSnia	XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0, x + t->frame_x, y + t->frame_y);
9600bbfda8aSnia	SetFocus(t, EventTime);
9610bbfda8aSnia
9620bbfda8aSnia#ifdef DEBUG
9630bbfda8aSnia	{
9640bbfda8aSnia		Window root_return;
9650bbfda8aSnia		Window child_return;
9660bbfda8aSnia		int root_x_return;
9670bbfda8aSnia		int root_y_return;
9680bbfda8aSnia		int win_x_return;
9690bbfda8aSnia		int win_y_return;
9700bbfda8aSnia		unsigned int mask_return;
9710bbfda8aSnia
9720bbfda8aSnia		if(XQueryPointer(dpy, t->frame, &root_return, &child_return, &root_x_return,
9730bbfda8aSnia		                 &root_y_return, &win_x_return, &win_y_return, &mask_return)) {
9740bbfda8aSnia			fprintf(stderr,
9750bbfda8aSnia			        "XQueryPointer: root_return=%x, child_return=%x, root_x_return=%d, root_y_return=%d, win_x_return=%d, win_y_return=%d\n",
9760bbfda8aSnia			        root_return, child_return, root_x_return, root_y_return, win_x_return,
9770bbfda8aSnia			        win_y_return);
9780bbfda8aSnia		}
9790bbfda8aSnia	}
9800bbfda8aSnia#endif
9810bbfda8aSnia}
9820bbfda8aSnia
9830bbfda8aSnia
9840bbfda8aSnia/*
9850bbfda8aSnia * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all
9860bbfda8aSnia * client messages will have the following form:
9870bbfda8aSnia *
9880bbfda8aSnia *     event type       ClientMessage
9890bbfda8aSnia *     message type     XA_WM_PROTOCOLS
9900bbfda8aSnia *     window           tmp->w
9910bbfda8aSnia *     format           32
9920bbfda8aSnia *     data[0]          message atom
9930bbfda8aSnia *     data[1]          time stamp
9940bbfda8aSnia */
9950bbfda8aSniavoid
9960bbfda8aSniasend_clientmessage(Window w, Atom a, Time timestamp)
9970bbfda8aSnia{
9980bbfda8aSnia	XClientMessageEvent ev;
9990bbfda8aSnia
10000bbfda8aSnia	ev.type = ClientMessage;
10010bbfda8aSnia	ev.window = w;
10020bbfda8aSnia	ev.message_type = XA_WM_PROTOCOLS;
10030bbfda8aSnia	ev.format = 32;
10040bbfda8aSnia	ev.data.l[0] = a;
10050bbfda8aSnia	ev.data.l[1] = timestamp;
10060bbfda8aSnia	XSendEvent(dpy, w, False, 0L, (XEvent *) &ev);
10070bbfda8aSnia}
10080bbfda8aSnia
10090bbfda8aSnia
10100bbfda8aSnia/*
10110bbfda8aSnia * Create synthetic WM_HINTS info for windows.  When a window specifies
10120bbfda8aSnia * stuff, we should probably pay attention to it (though we don't
10130bbfda8aSnia * always; x-ref comments in AddWindow() especially about focus).
10140bbfda8aSnia * However, when it doesn't tell us anything at all, we should assume
10150bbfda8aSnia * something useful.  "Window managers are free to assume convenient
10160bbfda8aSnia * values for all fields of the WM_HINTS property if a window is mapped
10170bbfda8aSnia * without one."  (ICCCM Ch. 4,
10180bbfda8aSnia * <https://www.x.org/releases/X11R7.7/doc/xorg-docs/icccm/icccm.html#Client_Properties>).
10190bbfda8aSnia *
10200bbfda8aSnia * Specifically, we assume it wants us to give it focus.  It's fairly
10210bbfda8aSnia * bogus for a window not to tell us anything, but e.g current versions
10220bbfda8aSnia * of Chrome do (don't do) just that.  So we better make up something
10230bbfda8aSnia * useful.
10240bbfda8aSnia *
10250bbfda8aSnia * Should probably be some configurability for this, so make the func
10260bbfda8aSnia * take the window, even though we don't currently do anything useful
10270bbfda8aSnia * with it...
10280bbfda8aSnia */
10290bbfda8aSniaXWMHints *
10300bbfda8aSniagen_synthetic_wmhints(TwmWindow *win)
10310bbfda8aSnia{
10320bbfda8aSnia	XWMHints *hints;
10330bbfda8aSnia
10340bbfda8aSnia	hints = XAllocWMHints();
10350bbfda8aSnia	if(!hints) {
10360bbfda8aSnia		return NULL;
10370bbfda8aSnia	}
10380bbfda8aSnia
10390bbfda8aSnia	/*
10400bbfda8aSnia	 * Reasonable defaults.  Takes input, in normal state.
10410bbfda8aSnia	 *
10420bbfda8aSnia	 * XXX Make configurable?
10430bbfda8aSnia	 */
10440bbfda8aSnia	hints->flags = InputHint | StateHint;
10450bbfda8aSnia	hints->input = True;
10460bbfda8aSnia	hints->initial_state = NormalState;
10470bbfda8aSnia
10480bbfda8aSnia	return hints;
10490bbfda8aSnia}
10500bbfda8aSnia
10510bbfda8aSnia
10520bbfda8aSnia/**
10530bbfda8aSnia * Perform whatever adaptations of WM_HINTS info we do.
10540bbfda8aSnia *
10550bbfda8aSnia * Most of these relate to focus, but we also fiddle with group
10560bbfda8aSnia * membership.
10570bbfda8aSnia */
10580bbfda8aSniaXWMHints *
10590bbfda8aSniamunge_wmhints(TwmWindow *win, XWMHints *hints)
10600bbfda8aSnia{
10610bbfda8aSnia	/*
10620bbfda8aSnia	 * If we have WM_HINTS, but they don't tell us anything about focus,
10630bbfda8aSnia	 * force it to true for our purposes.
10640bbfda8aSnia	 *
10650bbfda8aSnia	 * CL: Having with not willing focus cause problems with AutoSqueeze
10660bbfda8aSnia	 * and a few others things. So I suppress it. And the whole focus
10670bbfda8aSnia	 * thing is buggy anyway.
10680bbfda8aSnia	 */
10690bbfda8aSnia	if(!(hints->flags & InputHint)) {
10700bbfda8aSnia		hints->input = True;
10710bbfda8aSnia	}
10720bbfda8aSnia
10730bbfda8aSnia	/*
10740bbfda8aSnia	 * Now we're expecting to give the window focus if it asked for it
10750bbfda8aSnia	 * via WM_HINTS, if it didn't say anything one way or the other in
10760bbfda8aSnia	 * WM_HINTS, or if it didn't give us any WM_HINTS at all.  But if it
10770bbfda8aSnia	 * explicitly asked not to, we don't give it unless overridden by
10780bbfda8aSnia	 * config.
10790bbfda8aSnia	 */
10800bbfda8aSnia	if(Scr->ForceFocus || IsInList(Scr->ForceFocusL, win)) {
10810bbfda8aSnia		hints->input = True;
10820bbfda8aSnia	}
10830bbfda8aSnia
10840bbfda8aSnia
10850bbfda8aSnia	/* Setup group bits */
10860bbfda8aSnia	if(hints->flags & WindowGroupHint) {
10870bbfda8aSnia		win->group = hints->window_group;
10880bbfda8aSnia		if(win->group) {
10890bbfda8aSnia			/*
10900bbfda8aSnia			 * GTK windows often have a spurious "group leader" window which is
10910bbfda8aSnia			 * never reported to us and therefore does not really exist.  This
10920bbfda8aSnia			 * is annoying because we treat group members a lot like transient
10930bbfda8aSnia			 * windows.  Look for that here. It is in fact a duplicate of the
10940bbfda8aSnia			 * WM_CLIENT_LEADER property.
10950bbfda8aSnia			 */
10960bbfda8aSnia			if(win->group != win->w && !GetTwmWindow(win->group)) {
10970bbfda8aSnia				win->group = 0;
10980bbfda8aSnia			}
10990bbfda8aSnia		}
11000bbfda8aSnia	}
11010bbfda8aSnia	else {
11020bbfda8aSnia		win->group = 0;
11030bbfda8aSnia	}
11040bbfda8aSnia
11050bbfda8aSnia	return hints;
11060bbfda8aSnia}
11070bbfda8aSnia
11080bbfda8aSnia
11090bbfda8aSnia/**
11100bbfda8aSnia * [Re]set a window's name.  This goes over the available naming sources
11110bbfda8aSnia * for the window and points the TwmWindow::name at the appropriate one.
11120bbfda8aSnia * It may also set a property to signal other EWMH-aware clients when
11130bbfda8aSnia * we're naming it a way they can't see themselves.
11140bbfda8aSnia *
11150bbfda8aSnia * \note This should rarely be called directly; apply_window_name()
11160bbfda8aSnia * should be used instead.  It's split out because we need to do this
11170bbfda8aSnia * step individually in AddWindow().
11180bbfda8aSnia *
11190bbfda8aSnia * \note Note also that we never need to worry about freeing the
11200bbfda8aSnia * TwmWindow::name; it always points to one of the TwmWindow::names
11210bbfda8aSnia * values (which are free'd by the event handler when they change) or to
11220bbfda8aSnia * NoName (which is static).  So we can just casually flip it around at
11230bbfda8aSnia * will.
11240bbfda8aSnia */
11250bbfda8aSniabool
11260bbfda8aSniaset_window_name(TwmWindow *win)
11270bbfda8aSnia{
11280bbfda8aSnia	char *newname = NULL;
11290bbfda8aSnia#define TRY(fld) { \
11300bbfda8aSnia                if(newname == NULL && win->names.fld != NULL) { \
11310bbfda8aSnia                        newname = win->names.fld; \
11320bbfda8aSnia                } \
11330bbfda8aSnia        }
11340bbfda8aSnia	TRY(ctwm_wm_name)
11350bbfda8aSnia#ifdef EWMH
11360bbfda8aSnia	TRY(net_wm_name)
11370bbfda8aSnia#endif
11380bbfda8aSnia	TRY(wm_name)
11390bbfda8aSnia#undef TRY
11400bbfda8aSnia
11410bbfda8aSnia	if(newname == NULL) {
11420bbfda8aSnia		newname = NoName;
11430bbfda8aSnia	}
11440bbfda8aSnia	if(win->name == newname) {
11450bbfda8aSnia		return false; // Nothing to do
11460bbfda8aSnia	}
11470bbfda8aSnia
11480bbfda8aSnia	// Now we know what to call it
11490bbfda8aSnia	win->name = newname;
11500bbfda8aSnia
11510bbfda8aSnia#ifdef EWMH
11520bbfda8aSnia	// EWMH says we set an additional property on any windows where what
11530bbfda8aSnia	// we consider the name isn't what's in _NET_WM_NAME, so pagers etc
11540bbfda8aSnia	// can call it the same as we do.
11550bbfda8aSnia	//
11560bbfda8aSnia	// The parts of the text describing it conflict a little; at one
11570bbfda8aSnia	// place, it implies this should be set unless we're using
11580bbfda8aSnia	// _NET_WM_NAME, in another it seems to suggest WM_NAME should be
11590bbfda8aSnia	// considered applicable too.  I choose to implement it excluding
11600bbfda8aSnia	// both, so this only gets set if we're overriding either standard
11610bbfda8aSnia	// naming (probably rare).
11620bbfda8aSnia	if(win->name != win->names.net_wm_name && win->name != win->names.wm_name) {
11630bbfda8aSnia		// XXX We're not doing any checking of the encoding here...  I
11640bbfda8aSnia		// don't see that Xlib helps us any, so we probably have to fall
11650bbfda8aSnia		// back to iconv?  That came into the base in POSIX 2008, but was
11660bbfda8aSnia		// in XSI back into the 90's I believe?
11670bbfda8aSnia		XChangeProperty(dpy, win->w, XA__NET_WM_VISIBLE_NAME, XA_UTF8_STRING,
11680bbfda8aSnia		                8, PropModeReplace, (unsigned char *)win->name,
11690bbfda8aSnia		                strlen(win->name));
11700bbfda8aSnia	}
11710bbfda8aSnia	else {
11720bbfda8aSnia		XDeleteProperty(dpy, win->w, XA__NET_WM_VISIBLE_NAME);
11730bbfda8aSnia	}
11740bbfda8aSnia#endif // EWMH
11750bbfda8aSnia
11760bbfda8aSnia	// We set a name
11770bbfda8aSnia	return true;
11780bbfda8aSnia}
11790bbfda8aSnia
11800bbfda8aSnia
11810bbfda8aSnia/**
11820bbfda8aSnia * [Re]set and apply changes to a window's name.  This is called after
11830bbfda8aSnia * we've received a new WM_NAME (or other name-setting) property, to
11840bbfda8aSnia * update our titlebars, icon managers, etc.
11850bbfda8aSnia */
11860bbfda8aSniavoid
11870bbfda8aSniaapply_window_name(TwmWindow *win)
11880bbfda8aSnia{
11890bbfda8aSnia	/* [Re]set ->name */
11900bbfda8aSnia	if(set_window_name(win) == false) {
11910bbfda8aSnia		// No change
11920bbfda8aSnia		return;
11930bbfda8aSnia	}
11940bbfda8aSnia	win->nameChanged = true;
11950bbfda8aSnia
11960bbfda8aSnia
11970bbfda8aSnia	/* Update the active name */
11980bbfda8aSnia	{
11990bbfda8aSnia		XRectangle inc_rect;
12000bbfda8aSnia		XRectangle logical_rect;
12010bbfda8aSnia
12020bbfda8aSnia		XmbTextExtents(Scr->TitleBarFont.font_set,
12030bbfda8aSnia		               win->name, strlen(win->name),
12040bbfda8aSnia		               &inc_rect, &logical_rect);
12050bbfda8aSnia		win->name_width = logical_rect.width;
12060bbfda8aSnia	}
12070bbfda8aSnia
12080bbfda8aSnia	/* recompute the priority if necessary */
12090bbfda8aSnia	if(Scr->AutoPriority) {
12100bbfda8aSnia		OtpRecomputePrefs(win);
12110bbfda8aSnia	}
12120bbfda8aSnia
12130bbfda8aSnia	SetupWindow(win, win->frame_x, win->frame_y,
12140bbfda8aSnia	            win->frame_width, win->frame_height, -1);
12150bbfda8aSnia
12160bbfda8aSnia	if(win->title_w) {
12170bbfda8aSnia		XClearArea(dpy, win->title_w, 0, 0, 0, 0, True);
12180bbfda8aSnia	}
12190bbfda8aSnia	if(Scr->AutoOccupy) {
12200bbfda8aSnia		WmgrRedoOccupation(win);
12210bbfda8aSnia	}
12220bbfda8aSnia
12230bbfda8aSnia#if 0
12240bbfda8aSnia	/* Experimental, not yet working. */
12250bbfda8aSnia	{
12260bbfda8aSnia		ColorPair cp;
12270bbfda8aSnia		int f, b;
12280bbfda8aSnia
12290bbfda8aSnia		f = GetColorFromList(Scr->TitleForegroundL, win->name,
12300bbfda8aSnia		                     &win->class, &cp.fore);
12310bbfda8aSnia		b = GetColorFromList(Scr->TitleBackgroundL, win->name,
12320bbfda8aSnia		                     &win->class, &cp.back);
12330bbfda8aSnia		if(f || b) {
12340bbfda8aSnia			if(Scr->use3Dtitles  && !Scr->BeNiceToColormap) {
12350bbfda8aSnia				GetShadeColors(&cp);
12360bbfda8aSnia			}
12370bbfda8aSnia			win->title = cp;
12380bbfda8aSnia		}
12390bbfda8aSnia		f = GetColorFromList(Scr->BorderColorL, win->name,
12400bbfda8aSnia		                     &win->class, &cp.fore);
12410bbfda8aSnia		b = GetColorFromList(Scr->BorderColorL, win->name,
12420bbfda8aSnia		                     &win->class, &cp.back);
12430bbfda8aSnia		if(f || b) {
12440bbfda8aSnia			if(Scr->use3Dborders && !Scr->BeNiceToColormap) {
12450bbfda8aSnia				GetShadeColors(&cp);
12460bbfda8aSnia			}
12470bbfda8aSnia			win->borderC = cp;
12480bbfda8aSnia		}
12490bbfda8aSnia
12500bbfda8aSnia		f = GetColorFromList(Scr->BorderTileForegroundL, win->name,
12510bbfda8aSnia		                     &win->class, &cp.fore);
12520bbfda8aSnia		b = GetColorFromList(Scr->BorderTileBackgroundL, win->name,
12530bbfda8aSnia		                     &win->class, &cp.back);
12540bbfda8aSnia		if(f || b) {
12550bbfda8aSnia			if(Scr->use3Dborders && !Scr->BeNiceToColormap) {
12560bbfda8aSnia				GetShadeColors(&cp);
12570bbfda8aSnia			}
12580bbfda8aSnia			win->border_tile = cp;
12590bbfda8aSnia		}
12600bbfda8aSnia	}
12610bbfda8aSnia#endif
12620bbfda8aSnia
12630bbfda8aSnia	/*
12640bbfda8aSnia	 * If we haven't set a separate icon name, we use the window name, so
12650bbfda8aSnia	 * we need to update it.
12660bbfda8aSnia	 */
12670bbfda8aSnia	if(win->names.icon_set == false) {
12680bbfda8aSnia		apply_window_icon_name(win);
12690bbfda8aSnia	}
12700bbfda8aSnia	AutoPopupMaybe(win);
12710bbfda8aSnia
12720bbfda8aSnia	return;
12730bbfda8aSnia}
12740bbfda8aSnia
12750bbfda8aSnia
12760bbfda8aSnia/**
12770bbfda8aSnia * [Re]set a window's icon name.  As with the window name version in
12780bbfda8aSnia * set_window_name(), this is mostly separate so the AddWindow() process
12790bbfda8aSnia * can call it.
12800bbfda8aSnia *
12810bbfda8aSnia * \note As with TwmWindow::name, we never want to try free()'ing or the
12820bbfda8aSnia * like TwmWindow::icon_name.
12830bbfda8aSnia *
12840bbfda8aSnia * \sa set_window_name() for details; this is just the icon name
12850bbfda8aSnia * equivalent of it.
12860bbfda8aSnia */
12870bbfda8aSniabool
12880bbfda8aSniaset_window_icon_name(TwmWindow *win)
12890bbfda8aSnia{
12900bbfda8aSnia	char *newname = NULL;
12910bbfda8aSnia#define TRY(fld) { \
12920bbfda8aSnia                if(newname == NULL && win->names.fld != NULL) { \
12930bbfda8aSnia                        newname = win->names.fld; \
12940bbfda8aSnia                        win->names.icon_set = true; \
12950bbfda8aSnia                } \
12960bbfda8aSnia        }
12970bbfda8aSnia	TRY(ctwm_wm_icon_name)
12980bbfda8aSnia#ifdef EWMH
12990bbfda8aSnia	TRY(net_wm_icon_name)
13000bbfda8aSnia#endif
13010bbfda8aSnia	TRY(wm_icon_name)
13020bbfda8aSnia#undef TRY
13030bbfda8aSnia
13040bbfda8aSnia	// Our fallback for icon names is the window name.  Flag when we're
13050bbfda8aSnia	// doing that, so the window name handler can know when it needs to
13060bbfda8aSnia	// call us.
13070bbfda8aSnia	if(newname == NULL) {
13080bbfda8aSnia		newname = win->name;
13090bbfda8aSnia		win->names.icon_set = false;
13100bbfda8aSnia	}
13110bbfda8aSnia	if(win->icon_name == newname) {
13120bbfda8aSnia		return false; // Nothing to do
13130bbfda8aSnia	}
13140bbfda8aSnia
13150bbfda8aSnia	// A name is chosen
13160bbfda8aSnia	win->icon_name = newname;
13170bbfda8aSnia
13180bbfda8aSnia#ifdef EWMH
13190bbfda8aSnia	// EWMH asks for _NET_WM_VISIBLE_ICON_NAME in various cases where
13200bbfda8aSnia	// we're not using 'standard' properties' values.  x-ref comments above in
13210bbfda8aSnia	// set_window_name() about the parallel property for the window name
13220bbfda8aSnia	// for various caveats.
13230bbfda8aSnia	if(win->icon_name != win->names.net_wm_icon_name
13240bbfda8aSnia	                && win->icon_name != win->names.wm_icon_name) {
13250bbfda8aSnia		// XXX Still encoding questionable; x-ref above.
13260bbfda8aSnia		XChangeProperty(dpy, win->w, XA__NET_WM_VISIBLE_ICON_NAME,
13270bbfda8aSnia		                XA_UTF8_STRING,
13280bbfda8aSnia		                8, PropModeReplace, (unsigned char *)win->icon_name,
13290bbfda8aSnia		                strlen(win->icon_name));
13300bbfda8aSnia	}
13310bbfda8aSnia	else {
13320bbfda8aSnia		XDeleteProperty(dpy, win->w, XA__NET_WM_VISIBLE_ICON_NAME);
13330bbfda8aSnia	}
13340bbfda8aSnia#endif // EWMH
13350bbfda8aSnia
13360bbfda8aSnia	// Did it
13370bbfda8aSnia	return true;
13380bbfda8aSnia}
13390bbfda8aSnia
13400bbfda8aSnia
13410bbfda8aSnia/**
13420bbfda8aSnia * [Re]set and apply changes to a window's icon name.  This is called
13430bbfda8aSnia * after we've received a new WM_ICON_NAME (or other name-setting)
13440bbfda8aSnia * property, to update our titlebars, icon managers, etc.
13450bbfda8aSnia *
13460bbfda8aSnia * \sa apply_window_name() which does the same for the window title.
13470bbfda8aSnia */
13480bbfda8aSniavoid
13490bbfda8aSniaapply_window_icon_name(TwmWindow *win)
13500bbfda8aSnia{
13510bbfda8aSnia	/* [Re]set ->icon_name */
13520bbfda8aSnia	if(set_window_icon_name(win) == false) {
13530bbfda8aSnia		// No change
13540bbfda8aSnia		return;
13550bbfda8aSnia	}
13560bbfda8aSnia
13570bbfda8aSnia
13580bbfda8aSnia	/* Lot less to do for icons... */
13590bbfda8aSnia	RedoIcon(Tmp_win);
13600bbfda8aSnia	AutoPopupMaybe(Tmp_win);
13610bbfda8aSnia
13620bbfda8aSnia	return;
13630bbfda8aSnia}
1364