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