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