occupation.c revision 0bbfda8a
10bbfda8aSnia/* 20bbfda8aSnia * Occupation handling bits 30bbfda8aSnia * 40bbfda8aSnia * This is in fact pretty tightly tied and extremely similar to the 50bbfda8aSnia * handling of the WorkSpaceManager in workmgr.c, and used to be there. 60bbfda8aSnia * It makes sense to consider them together (and indeed, many of the 70bbfda8aSnia * configs that affect how this works are really WorkSpaceManager* or 80bbfda8aSnia * WMgr* commands. But having them crammed together in one file is 90bbfda8aSnia * unwieldy. 100bbfda8aSnia */ 110bbfda8aSnia 120bbfda8aSnia#include "ctwm.h" 130bbfda8aSnia 140bbfda8aSnia#include <stdio.h> 150bbfda8aSnia#include <string.h> 160bbfda8aSnia#include <stdlib.h> 170bbfda8aSnia 180bbfda8aSnia#include <X11/Xatom.h> 190bbfda8aSnia 200bbfda8aSnia#include "add_window.h" 210bbfda8aSnia#include "ctwm_atoms.h" 220bbfda8aSnia#include "drawing.h" 230bbfda8aSnia#include "events.h" 240bbfda8aSnia#include "iconmgr.h" 250bbfda8aSnia#include "list.h" 260bbfda8aSnia#include "screen.h" 270bbfda8aSnia#include "occupation.h" 280bbfda8aSnia#include "otp.h" 290bbfda8aSnia#include "util.h" 300bbfda8aSnia#include "vscreen.h" 310bbfda8aSnia#include "win_iconify.h" 320bbfda8aSnia#include "win_regions.h" 330bbfda8aSnia#include "win_utils.h" 340bbfda8aSnia#include "workspace_manager.h" 350bbfda8aSnia#include "workspace_utils.h" 360bbfda8aSnia 370bbfda8aSnia 380bbfda8aSniastatic int GetMaskFromResource(TwmWindow *win, char *res); 390bbfda8aSniastatic char *mk_nullsep_string(const char *prop, int len); 400bbfda8aSnia 410bbfda8aSniastatic bool CanChangeOccupation(TwmWindow **twm_winp); 420bbfda8aSnia 430bbfda8aSniaint fullOccupation = 0; 440bbfda8aSnia 450bbfda8aSnia/* 460bbfda8aSnia * The window whose occupation is currently being manipulated. 470bbfda8aSnia * 480bbfda8aSnia * XXX Should probably be static, but currently needed in 490bbfda8aSnia * WMapRemoveWindow(). Revisit. 500bbfda8aSnia */ 510bbfda8aSniaTwmWindow *occupyWin = NULL; 520bbfda8aSnia 530bbfda8aSnia 540bbfda8aSnia/* XXX Share with captive.c? */ 550bbfda8aSniastatic XrmOptionDescRec table [] = { 560bbfda8aSnia {"-xrm", NULL, XrmoptionResArg, (XPointer) NULL}, 570bbfda8aSnia}; 580bbfda8aSnia 590bbfda8aSnia 600bbfda8aSnia 610bbfda8aSnia 620bbfda8aSnia/* 630bbfda8aSnia **************************************************************** 640bbfda8aSnia * 650bbfda8aSnia * First, funcs related to setting and changing a window's occupation. 660bbfda8aSnia * 670bbfda8aSnia **************************************************************** 680bbfda8aSnia */ 690bbfda8aSnia 700bbfda8aSnia 710bbfda8aSnia/* 720bbfda8aSnia * Setup the occupation of a TwmWindow. Called as part of the 730bbfda8aSnia * AddWindow() process. 740bbfda8aSnia * 750bbfda8aSnia * XXX The logic flow in this is kinda weird, and it's not at all clear 760bbfda8aSnia * to what extent it's really doing the right on on what should override 770bbfda8aSnia * what, or which things should expand/contract on others... 780bbfda8aSnia */ 790bbfda8aSniavoid 800bbfda8aSniaSetupOccupation(TwmWindow *twm_win, int occupation_hint) 810bbfda8aSnia{ 820bbfda8aSnia char **cliargv = NULL; 830bbfda8aSnia int cliargc; 840bbfda8aSnia WorkSpace *ws; 850bbfda8aSnia 860bbfda8aSnia /* If there aren't any config'd workspaces, there's only 0 */ 870bbfda8aSnia if(! Scr->workSpaceManagerActive) { 880bbfda8aSnia twm_win->occupation = 1 << 0; /* occupy workspace #0 */ 890bbfda8aSnia /* more?... */ 900bbfda8aSnia 910bbfda8aSnia return; 920bbfda8aSnia } 930bbfda8aSnia 940bbfda8aSnia /* Workspace manager window doesn't get futzed with */ 950bbfda8aSnia if(twm_win->iswspmgr) { 960bbfda8aSnia return; 970bbfda8aSnia } 980bbfda8aSnia 990bbfda8aSnia /*twm_win->occupation = twm_win->iswinbox ? fullOccupation : 0;*/ 1000bbfda8aSnia twm_win->occupation = 0; 1010bbfda8aSnia 1020bbfda8aSnia /* Specified in any Occupy{} config params? */ 1030bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 1040bbfda8aSnia if(LookInList(ws->clientlist, twm_win->name, &twm_win->class)) { 1050bbfda8aSnia twm_win->occupation |= 1 << ws->number; 1060bbfda8aSnia } 1070bbfda8aSnia } 1080bbfda8aSnia 1090bbfda8aSnia /* OccupyAll{} */ 1100bbfda8aSnia if(LookInList(Scr->OccupyAll, twm_win->name, &twm_win->class)) { 1110bbfda8aSnia twm_win->occupation = fullOccupation; 1120bbfda8aSnia } 1130bbfda8aSnia 1140bbfda8aSnia /* See if it specified in -xrm stuff */ 1150bbfda8aSnia if(XGetCommand(dpy, twm_win->w, &cliargv, &cliargc)) { 1160bbfda8aSnia Bool status; 1170bbfda8aSnia char *str_type; 1180bbfda8aSnia XrmValue value; 1190bbfda8aSnia XrmDatabase db = NULL; 1200bbfda8aSnia 1210bbfda8aSnia XrmParseCommand(&db, table, 1, "ctwm", &cliargc, cliargv); 1220bbfda8aSnia XFreeStringList(cliargv); 1230bbfda8aSnia status = XrmGetResource(db, "ctwm.workspace", "Ctwm.Workspace", 1240bbfda8aSnia &str_type, &value); 1250bbfda8aSnia if((status == True) && (value.size != 0)) { 1260bbfda8aSnia /* Copy the value.addr because it's in XRM memory not ours */ 1270bbfda8aSnia char wrkSpcList[512]; 1280bbfda8aSnia safe_strncpy(wrkSpcList, value.addr, MIN(value.size, 512)); 1290bbfda8aSnia 1300bbfda8aSnia twm_win->occupation = GetMaskFromResource(twm_win, wrkSpcList); 1310bbfda8aSnia } 1320bbfda8aSnia XrmDestroyDatabase(db); 1330bbfda8aSnia } 1340bbfda8aSnia 1350bbfda8aSnia /* Does it have a property telling us */ 1360bbfda8aSnia if(RestartPreviousState) { 1370bbfda8aSnia Atom actual_type; 1380bbfda8aSnia int actual_format; 1390bbfda8aSnia unsigned long nitems, bytesafter; 1400bbfda8aSnia unsigned char *prop; 1410bbfda8aSnia 1420bbfda8aSnia if(XGetWindowProperty(dpy, twm_win->w, XA_WM_OCCUPATION, 0L, 2500, False, 1430bbfda8aSnia XA_STRING, &actual_type, &actual_format, &nitems, 1440bbfda8aSnia &bytesafter, &prop) == Success) { 1450bbfda8aSnia if(nitems != 0) { 1460bbfda8aSnia twm_win->occupation = GetMaskFromProperty(prop, nitems); 1470bbfda8aSnia XFree(prop); 1480bbfda8aSnia } 1490bbfda8aSnia } 1500bbfda8aSnia } 1510bbfda8aSnia 1520bbfda8aSnia#ifdef EWMH 1530bbfda8aSnia /* Maybe EWMH has something to tell us? */ 1540bbfda8aSnia if(twm_win->occupation == 0) { 1550bbfda8aSnia twm_win->occupation = EwmhGetOccupation(twm_win); 1560bbfda8aSnia } 1570bbfda8aSnia#endif /* EWMH */ 1580bbfda8aSnia 1590bbfda8aSnia /* Icon Managers shouldn't get altered */ 1600bbfda8aSnia /* XXX Should this be up near the top? */ 1610bbfda8aSnia if(twm_win->isiconmgr) { 1620bbfda8aSnia return; /* someone tried to modify occupation of icon managers */ 1630bbfda8aSnia } 1640bbfda8aSnia 1650bbfda8aSnia 1660bbfda8aSnia /* 1670bbfda8aSnia * Transient-ish things go with their parents unless 1680bbfda8aSnia * TransientHasOccupation set in the config. 1690bbfda8aSnia */ 1700bbfda8aSnia if(! Scr->TransientHasOccupation) { 1710bbfda8aSnia TwmWindow *t; 1720bbfda8aSnia 1730bbfda8aSnia if(twm_win->istransient) { 1740bbfda8aSnia t = GetTwmWindow(twm_win->transientfor); 1750bbfda8aSnia if(t != NULL) { 1760bbfda8aSnia twm_win->occupation = t->occupation; 1770bbfda8aSnia } 1780bbfda8aSnia } 1790bbfda8aSnia else if(twm_win->group != 0) { 1800bbfda8aSnia t = GetTwmWindow(twm_win->group); 1810bbfda8aSnia if(t != NULL) { 1820bbfda8aSnia twm_win->occupation = t->occupation; 1830bbfda8aSnia } 1840bbfda8aSnia } 1850bbfda8aSnia } 1860bbfda8aSnia 1870bbfda8aSnia 1880bbfda8aSnia /* If we were told something specific, go with that */ 1890bbfda8aSnia if(occupation_hint != 0) { 1900bbfda8aSnia twm_win->occupation = occupation_hint; 1910bbfda8aSnia } 1920bbfda8aSnia 1930bbfda8aSnia /* If it's apparently-nonsensical, put it in its vs's workspace */ 1940bbfda8aSnia if((twm_win->occupation & fullOccupation) == 0) { 1950bbfda8aSnia twm_win->occupation = 1 << twm_win->vs->wsw->currentwspc->number; 1960bbfda8aSnia } 1970bbfda8aSnia 1980bbfda8aSnia /* 1990bbfda8aSnia * If the occupation would not show it in the current vscreen, 2000bbfda8aSnia * make it vanish. 2010bbfda8aSnia * 2020bbfda8aSnia * If it could be shown in one of the other vscreens, change the vscreen. 2030bbfda8aSnia */ 2040bbfda8aSnia if(!OCCUPY(twm_win, twm_win->vs->wsw->currentwspc)) { 2050bbfda8aSnia VirtualScreen *vs; 2060bbfda8aSnia 2070bbfda8aSnia twm_win->vs = NULL; 2080bbfda8aSnia 2090bbfda8aSnia if(Scr->numVscreens > 1) { 2100bbfda8aSnia for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 2110bbfda8aSnia if(OCCUPY(twm_win, vs->wsw->currentwspc)) { 2120bbfda8aSnia twm_win->vs = vs; 2130bbfda8aSnia twm_win->parent_vs = vs; 2140bbfda8aSnia break; 2150bbfda8aSnia } 2160bbfda8aSnia } 2170bbfda8aSnia } 2180bbfda8aSnia } 2190bbfda8aSnia 2200bbfda8aSnia 2210bbfda8aSnia /* Set the property for the occupation */ 2220bbfda8aSnia { 2230bbfda8aSnia long eventMask; 2240bbfda8aSnia char *wsstr; 2250bbfda8aSnia int len; 2260bbfda8aSnia 2270bbfda8aSnia /* Ignore the PropertyChange we're about to do */ 2280bbfda8aSnia if((eventMask = mask_out_event(twm_win->w, PropertyChangeMask)) < 0) { 2290bbfda8aSnia /* Window is horked, not much we can do */ 2300bbfda8aSnia return; 2310bbfda8aSnia } 2320bbfda8aSnia 2330bbfda8aSnia /* Set the property for the occupation */ 2340bbfda8aSnia len = GetPropertyFromMask(twm_win->occupation, &wsstr); 2350bbfda8aSnia XChangeProperty(dpy, twm_win->w, XA_WM_OCCUPATION, XA_STRING, 8, 2360bbfda8aSnia PropModeReplace, (unsigned char *) wsstr, len); 2370bbfda8aSnia free(wsstr); 2380bbfda8aSnia 2390bbfda8aSnia#ifdef EWMH 2400bbfda8aSnia EwmhSet_NET_WM_DESKTOP(twm_win); 2410bbfda8aSnia#endif 2420bbfda8aSnia 2430bbfda8aSnia /* Restore event mask */ 2440bbfda8aSnia restore_mask(twm_win->w, eventMask); 2450bbfda8aSnia } 2460bbfda8aSnia 2470bbfda8aSnia /* Set WM_STATE prop */ 2480bbfda8aSnia { 2490bbfda8aSnia int state = NormalState; 2500bbfda8aSnia Window icon; 2510bbfda8aSnia 2520bbfda8aSnia if(!(RestartPreviousState 2530bbfda8aSnia && GetWMState(twm_win->w, &state, &icon) 2540bbfda8aSnia && (state == NormalState || state == IconicState 2550bbfda8aSnia || state == InactiveState))) { 2560bbfda8aSnia if(twm_win->wmhints->flags & StateHint) { 2570bbfda8aSnia state = twm_win->wmhints->initial_state; 2580bbfda8aSnia } 2590bbfda8aSnia } 2600bbfda8aSnia if(visible(twm_win)) { 2610bbfda8aSnia if(state == InactiveState) { 2620bbfda8aSnia SetMapStateProp(twm_win, NormalState); 2630bbfda8aSnia } 2640bbfda8aSnia } 2650bbfda8aSnia else { 2660bbfda8aSnia if(state == NormalState) { 2670bbfda8aSnia SetMapStateProp(twm_win, InactiveState); 2680bbfda8aSnia } 2690bbfda8aSnia } 2700bbfda8aSnia } 2710bbfda8aSnia} 2720bbfda8aSnia 2730bbfda8aSnia 2740bbfda8aSnia/* 2750bbfda8aSnia * Make sure a window is marked in a given workspace. f.addtoworkspace. 2760bbfda8aSnia * Also gets called as part of the process of mapping a window; if we're 2770bbfda8aSnia * mapping it here, it should know that it's here. And Xinerama magic 2780bbfda8aSnia * moves. 2790bbfda8aSnia */ 2800bbfda8aSniavoid 2810bbfda8aSniaAddToWorkSpace(char *wname, TwmWindow *twm_win) 2820bbfda8aSnia{ 2830bbfda8aSnia WorkSpace *ws; 2840bbfda8aSnia int newoccupation; 2850bbfda8aSnia 2860bbfda8aSnia if(!CanChangeOccupation(&twm_win)) { 2870bbfda8aSnia return; 2880bbfda8aSnia } 2890bbfda8aSnia ws = GetWorkspace(wname); 2900bbfda8aSnia if(!ws) { 2910bbfda8aSnia return; 2920bbfda8aSnia } 2930bbfda8aSnia 2940bbfda8aSnia if(twm_win->occupation & (1 << ws->number)) { 2950bbfda8aSnia return; 2960bbfda8aSnia } 2970bbfda8aSnia newoccupation = twm_win->occupation | (1 << ws->number); 2980bbfda8aSnia ChangeOccupation(twm_win, newoccupation); 2990bbfda8aSnia} 3000bbfda8aSnia 3010bbfda8aSnia 3020bbfda8aSnia/* 3030bbfda8aSnia * Converse of the above. f.removefromworkspace, also called from 3040bbfda8aSnia * Xinerama-related magic. 3050bbfda8aSnia */ 3060bbfda8aSniavoid 3070bbfda8aSniaRemoveFromWorkSpace(char *wname, TwmWindow *twm_win) 3080bbfda8aSnia{ 3090bbfda8aSnia WorkSpace *ws; 3100bbfda8aSnia int newoccupation; 3110bbfda8aSnia 3120bbfda8aSnia if(!CanChangeOccupation(&twm_win)) { 3130bbfda8aSnia return; 3140bbfda8aSnia } 3150bbfda8aSnia ws = GetWorkspace(wname); 3160bbfda8aSnia if(!ws) { 3170bbfda8aSnia return; 3180bbfda8aSnia } 3190bbfda8aSnia 3200bbfda8aSnia newoccupation = twm_win->occupation & ~(1 << ws->number); 3210bbfda8aSnia if(!newoccupation) { 3220bbfda8aSnia return; 3230bbfda8aSnia } 3240bbfda8aSnia ChangeOccupation(twm_win, newoccupation); 3250bbfda8aSnia} 3260bbfda8aSnia 3270bbfda8aSnia 3280bbfda8aSnia/* f.toggleoccupation - flip setting for [current] workspace */ 3290bbfda8aSniavoid 3300bbfda8aSniaToggleOccupation(char *wname, TwmWindow *twm_win) 3310bbfda8aSnia{ 3320bbfda8aSnia WorkSpace *ws; 3330bbfda8aSnia int newoccupation; 3340bbfda8aSnia 3350bbfda8aSnia if(!CanChangeOccupation(&twm_win)) { 3360bbfda8aSnia return; 3370bbfda8aSnia } 3380bbfda8aSnia ws = GetWorkspace(wname); 3390bbfda8aSnia if(!ws) { 3400bbfda8aSnia return; 3410bbfda8aSnia } 3420bbfda8aSnia 3430bbfda8aSnia newoccupation = twm_win->occupation ^ (1 << ws->number); 3440bbfda8aSnia if(!newoccupation) { 3450bbfda8aSnia /* Don't allow de-occupying _every_ ws */ 3460bbfda8aSnia return; 3470bbfda8aSnia } 3480bbfda8aSnia ChangeOccupation(twm_win, newoccupation); 3490bbfda8aSnia} 3500bbfda8aSnia 3510bbfda8aSnia 3520bbfda8aSnia/* f.movetonextworkspace */ 3530bbfda8aSniavoid 3540bbfda8aSniaMoveToNextWorkSpace(VirtualScreen *vs, TwmWindow *twm_win) 3550bbfda8aSnia{ 3560bbfda8aSnia WorkSpace *wlist1, *wlist2; 3570bbfda8aSnia int newoccupation; 3580bbfda8aSnia 3590bbfda8aSnia if(!CanChangeOccupation(&twm_win)) { 3600bbfda8aSnia return; 3610bbfda8aSnia } 3620bbfda8aSnia 3630bbfda8aSnia wlist1 = vs->wsw->currentwspc; 3640bbfda8aSnia wlist2 = wlist1->next; 3650bbfda8aSnia wlist2 = wlist2 ? wlist2 : Scr->workSpaceMgr.workSpaceList; 3660bbfda8aSnia 3670bbfda8aSnia /* Out of (here), into (here+1) */ 3680bbfda8aSnia newoccupation = (twm_win->occupation ^ (1 << wlist1->number)) 3690bbfda8aSnia | (1 << wlist2->number); 3700bbfda8aSnia ChangeOccupation(twm_win, newoccupation); 3710bbfda8aSnia} 3720bbfda8aSnia 3730bbfda8aSnia 3740bbfda8aSnia/* f.movetonextworkspaceandfollow */ 3750bbfda8aSniavoid 3760bbfda8aSniaMoveToNextWorkSpaceAndFollow(VirtualScreen *vs, TwmWindow *twm_win) 3770bbfda8aSnia{ 3780bbfda8aSnia if(!CanChangeOccupation(&twm_win)) { 3790bbfda8aSnia return; 3800bbfda8aSnia } 3810bbfda8aSnia 3820bbfda8aSnia MoveToNextWorkSpace(vs, twm_win); 3830bbfda8aSnia GotoNextWorkSpace(vs); 3840bbfda8aSnia#if 0 3850bbfda8aSnia OtpRaise(twm_win, WinWin); /* XXX really do this? */ 3860bbfda8aSnia#endif 3870bbfda8aSnia} 3880bbfda8aSnia 3890bbfda8aSnia 3900bbfda8aSnia/* f.movetoprevworkspaceand */ 3910bbfda8aSniavoid 3920bbfda8aSniaMoveToPrevWorkSpace(VirtualScreen *vs, TwmWindow *twm_win) 3930bbfda8aSnia{ 3940bbfda8aSnia WorkSpace *wlist1, *wlist2; 3950bbfda8aSnia int newoccupation; 3960bbfda8aSnia 3970bbfda8aSnia if(!CanChangeOccupation(&twm_win)) { 3980bbfda8aSnia return; 3990bbfda8aSnia } 4000bbfda8aSnia 4010bbfda8aSnia wlist1 = Scr->workSpaceMgr.workSpaceList; 4020bbfda8aSnia wlist2 = vs->wsw->currentwspc; 4030bbfda8aSnia if(wlist1 == NULL) { 4040bbfda8aSnia return; 4050bbfda8aSnia } 4060bbfda8aSnia 4070bbfda8aSnia while(wlist1->next != wlist2 && wlist1->next != NULL) { 4080bbfda8aSnia wlist1 = wlist1->next; 4090bbfda8aSnia } 4100bbfda8aSnia 4110bbfda8aSnia /* Out of (here), into (here-1) */ 4120bbfda8aSnia newoccupation = (twm_win->occupation ^ (1 << wlist2->number)) 4130bbfda8aSnia | (1 << wlist1->number); 4140bbfda8aSnia ChangeOccupation(twm_win, newoccupation); 4150bbfda8aSnia} 4160bbfda8aSnia 4170bbfda8aSnia 4180bbfda8aSnia/* f.movetoprevworkspaceandfollow */ 4190bbfda8aSniavoid 4200bbfda8aSniaMoveToPrevWorkSpaceAndFollow(VirtualScreen *vs, TwmWindow *twm_win) 4210bbfda8aSnia{ 4220bbfda8aSnia if(!CanChangeOccupation(&twm_win)) { 4230bbfda8aSnia return; 4240bbfda8aSnia } 4250bbfda8aSnia 4260bbfda8aSnia MoveToPrevWorkSpace(vs, twm_win); 4270bbfda8aSnia GotoPrevWorkSpace(vs); 4280bbfda8aSnia#if 0 4290bbfda8aSnia OtpRaise(twm_win, WinWin); /* XXX really do this? */ 4300bbfda8aSnia#endif 4310bbfda8aSnia} 4320bbfda8aSnia 4330bbfda8aSnia 4340bbfda8aSnia/* 4350bbfda8aSnia * Set the occupation based on the window name. This is called if 4360bbfda8aSnia * AutoOccupy is set, when we get a notification about a window name 4370bbfda8aSnia * change. 4380bbfda8aSnia */ 4390bbfda8aSniavoid 4400bbfda8aSniaWmgrRedoOccupation(TwmWindow *win) 4410bbfda8aSnia{ 4420bbfda8aSnia WorkSpace *ws; 4430bbfda8aSnia int newoccupation; 4440bbfda8aSnia 4450bbfda8aSnia if(LookInList(Scr->OccupyAll, win->name, &win->class)) { 4460bbfda8aSnia newoccupation = fullOccupation; 4470bbfda8aSnia } 4480bbfda8aSnia else { 4490bbfda8aSnia newoccupation = 0; 4500bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 4510bbfda8aSnia if(LookInList(ws->clientlist, win->name, &win->class)) { 4520bbfda8aSnia newoccupation |= 1 << ws->number; 4530bbfda8aSnia } 4540bbfda8aSnia } 4550bbfda8aSnia } 4560bbfda8aSnia if(newoccupation != 0) { 4570bbfda8aSnia ChangeOccupation(win, newoccupation); 4580bbfda8aSnia } 4590bbfda8aSnia} 4600bbfda8aSnia 4610bbfda8aSnia 4620bbfda8aSnia/* f.vanish */ 4630bbfda8aSniavoid 4640bbfda8aSniaWMgrRemoveFromCurrentWorkSpace(VirtualScreen *vs, TwmWindow *win) 4650bbfda8aSnia{ 4660bbfda8aSnia WorkSpace *ws; 4670bbfda8aSnia int newoccupation; 4680bbfda8aSnia 4690bbfda8aSnia ws = vs->wsw->currentwspc; 4700bbfda8aSnia if(!ws) { 4710bbfda8aSnia /* Impossible? */ 4720bbfda8aSnia return; 4730bbfda8aSnia } 4740bbfda8aSnia if(! OCCUPY(win, ws)) { 4750bbfda8aSnia return; 4760bbfda8aSnia } 4770bbfda8aSnia 4780bbfda8aSnia newoccupation = win->occupation & ~(1 << ws->number); 4790bbfda8aSnia if(newoccupation == 0) { 4800bbfda8aSnia return; 4810bbfda8aSnia } 4820bbfda8aSnia 4830bbfda8aSnia ChangeOccupation(win, newoccupation); 4840bbfda8aSnia} 4850bbfda8aSnia 4860bbfda8aSnia 4870bbfda8aSnia/* f.warphere */ 4880bbfda8aSniavoid 4890bbfda8aSniaWMgrAddToCurrentWorkSpaceAndWarp(VirtualScreen *vs, char *winname) 4900bbfda8aSnia{ 4910bbfda8aSnia TwmWindow *tw; 4920bbfda8aSnia int newoccupation; 4930bbfda8aSnia 4940bbfda8aSnia /* Find named window on this screen */ 4950bbfda8aSnia for(tw = Scr->FirstWindow; tw != NULL; tw = tw->next) { 4960bbfda8aSnia if(match(winname, tw->name)) { 4970bbfda8aSnia break; 4980bbfda8aSnia } 4990bbfda8aSnia } 5000bbfda8aSnia 5010bbfda8aSnia /* Didn't find it by name? Try by class */ 5020bbfda8aSnia if(!tw) { 5030bbfda8aSnia for(tw = Scr->FirstWindow; tw != NULL; tw = tw->next) { 5040bbfda8aSnia if(match(winname, tw->class.res_name)) { 5050bbfda8aSnia break; 5060bbfda8aSnia } 5070bbfda8aSnia } 5080bbfda8aSnia } 5090bbfda8aSnia if(!tw) { 5100bbfda8aSnia for(tw = Scr->FirstWindow; tw != NULL; tw = tw->next) { 5110bbfda8aSnia if(match(winname, tw->class.res_class)) { 5120bbfda8aSnia break; 5130bbfda8aSnia } 5140bbfda8aSnia } 5150bbfda8aSnia } 5160bbfda8aSnia 5170bbfda8aSnia /* Still didn't find? Beep at the user and bail. */ 5180bbfda8aSnia if(!tw) { 5190bbfda8aSnia XBell(dpy, 0); 5200bbfda8aSnia return; 5210bbfda8aSnia } 5220bbfda8aSnia 5230bbfda8aSnia /* If WarpUnmapped isn't set and this isn't mapped, beep and bail */ 5240bbfda8aSnia if((! Scr->WarpUnmapped) && (! tw->mapped)) { 5250bbfda8aSnia XBell(dpy, 0); 5260bbfda8aSnia return; 5270bbfda8aSnia } 5280bbfda8aSnia 5290bbfda8aSnia /* Move it here if it's not */ 5300bbfda8aSnia if(! OCCUPY(tw, vs->wsw->currentwspc)) { 5310bbfda8aSnia newoccupation = tw->occupation | (1 << vs->wsw->currentwspc->number); 5320bbfda8aSnia ChangeOccupation(tw, newoccupation); 5330bbfda8aSnia } 5340bbfda8aSnia 5350bbfda8aSnia /* If we get here, WarpUnmapped is set, so map it if we need to */ 5360bbfda8aSnia if(! tw->mapped) { 5370bbfda8aSnia DeIconify(tw); 5380bbfda8aSnia } 5390bbfda8aSnia 5400bbfda8aSnia /* And go */ 5410bbfda8aSnia WarpToWindow(tw, Scr->RaiseOnWarp); 5420bbfda8aSnia} 5430bbfda8aSnia 5440bbfda8aSnia 5450bbfda8aSnia/* f.occupyall backend */ 5460bbfda8aSniavoid 5470bbfda8aSniaOccupyAll(TwmWindow *twm_win) 5480bbfda8aSnia{ 5490bbfda8aSnia IconMgr *save; 5500bbfda8aSnia 5510bbfda8aSnia if(!CanChangeOccupation(&twm_win)) { 5520bbfda8aSnia return; 5530bbfda8aSnia } 5540bbfda8aSnia 5550bbfda8aSnia /* 5560bbfda8aSnia * Temporarily alter Scr->iconmgr because stuff down in 5570bbfda8aSnia * ChangeOccupation winds up adding/removing bits, and that doesn't 5580bbfda8aSnia * work right when we're setting all? XXX Investigate further. 5590bbfda8aSnia */ 5600bbfda8aSnia save = Scr->iconmgr; 5610bbfda8aSnia Scr->iconmgr = Scr->workSpaceMgr.workSpaceList->iconmgr; 5620bbfda8aSnia ChangeOccupation(twm_win, fullOccupation); 5630bbfda8aSnia Scr->iconmgr = save; 5640bbfda8aSnia} 5650bbfda8aSnia 5660bbfda8aSnia 5670bbfda8aSnia 5680bbfda8aSnia/* 5690bbfda8aSnia **************************************************************** 5700bbfda8aSnia * 5710bbfda8aSnia * Pieces related to the Occupy window 5720bbfda8aSnia * 5730bbfda8aSnia **************************************************************** 5740bbfda8aSnia */ 5750bbfda8aSnia 5760bbfda8aSniastatic ColorPair occupyButtoncp; 5770bbfda8aSnia 5780bbfda8aSniastatic char *ok_string = "OK", 5790bbfda8aSnia *cancel_string = "Cancel", 5800bbfda8aSnia *everywhere_string = "All"; 5810bbfda8aSnia 5820bbfda8aSnia/* 5830bbfda8aSnia * Create the Occupy window. Part of startup process. 5840bbfda8aSnia * 5850bbfda8aSnia * Do not do the layout of the parts, only calculate the initial total 5860bbfda8aSnia * size. For the layout, call ResizeOccupyWindow() at the end. 5870bbfda8aSnia * 5880bbfda8aSnia * There is only one Occupy window (per Screen), it is reparented to each 5890bbfda8aSnia * virtual screen as needed. 5900bbfda8aSnia */ 5910bbfda8aSniavoid 5920bbfda8aSniaCreateOccupyWindow(void) 5930bbfda8aSnia{ 5940bbfda8aSnia int width; // Caculated and altered, unlike most others 5950bbfda8aSnia int Dummy = 1; 5960bbfda8aSnia TwmWindow *tmp_win; 5970bbfda8aSnia /* Shorthands for the Occupy window */ 5980bbfda8aSnia OccupyWindow *occwin = Scr->workSpaceMgr.occupyWindow; 5990bbfda8aSnia Window w; // occwin->w 6000bbfda8aSnia /* Misc other shorthands */ 6010bbfda8aSnia const int lines = Scr->workSpaceMgr.lines; 6020bbfda8aSnia const int columns = Scr->workSpaceMgr.columns; 6030bbfda8aSnia const int bwidth = Scr->vScreenList->wsw->bwidth; 6040bbfda8aSnia const int bheight = Scr->vScreenList->wsw->bheight; 6050bbfda8aSnia const int vspace = occwin->vspace; 6060bbfda8aSnia const int hspace = occwin->hspace; 6070bbfda8aSnia const int height = ((bheight + vspace) * lines) + bheight + (2 * vspace); 6080bbfda8aSnia 6090bbfda8aSnia /* Struct embedded in [struct embedded in] Scr, so memory's waiting */ 6100bbfda8aSnia 6110bbfda8aSnia /* There isn't anything we should do without workspaces... */ 6120bbfda8aSnia if(!Scr->workSpaceManagerActive) { 6130bbfda8aSnia return; 6140bbfda8aSnia } 6150bbfda8aSnia 6160bbfda8aSnia /* Initialize font and colorpair bits */ 6170bbfda8aSnia occwin->font = Scr->IconManagerFont; 6180bbfda8aSnia occwin->cp = Scr->IconManagerC; 6190bbfda8aSnia#ifdef COLOR_BLIND_USER 6200bbfda8aSnia occwin->cp.shadc = Scr->White; 6210bbfda8aSnia occwin->cp.shadd = Scr->Black; 6220bbfda8aSnia#else 6230bbfda8aSnia if(!Scr->BeNiceToColormap) { 6240bbfda8aSnia GetShadeColors(&occwin->cp); 6250bbfda8aSnia } 6260bbfda8aSnia#endif 6270bbfda8aSnia 6280bbfda8aSnia /* We already know that these should be too */ 6290bbfda8aSnia occwin->lines = lines; 6300bbfda8aSnia occwin->columns = columns; 6310bbfda8aSnia 6320bbfda8aSnia 6330bbfda8aSnia /* 6340bbfda8aSnia * Work out the necessary size of the OK/Cancel/All buttons at the 6350bbfda8aSnia * bottom. 6360bbfda8aSnia */ 6370bbfda8aSnia { 6380bbfda8aSnia XRectangle inc_rect; 6390bbfda8aSnia XRectangle logical_rect; 6400bbfda8aSnia MyFont font = occwin->font; 6410bbfda8aSnia int bbwidth; // Bottom button width 6420bbfda8aSnia /* Window min width based on bottom vs. workspace btns */ 6430bbfda8aSnia int bb_width, ws_width; 6440bbfda8aSnia 6450bbfda8aSnia /* Buttons gotta be as wide as the biggest of the three strings */ 6460bbfda8aSnia XmbTextExtents(font.font_set, ok_string, strlen(ok_string), 6470bbfda8aSnia &inc_rect, &logical_rect); 6480bbfda8aSnia bbwidth = logical_rect.width; 6490bbfda8aSnia 6500bbfda8aSnia XmbTextExtents(font.font_set, cancel_string, strlen(cancel_string), 6510bbfda8aSnia &inc_rect, &logical_rect); 6520bbfda8aSnia bbwidth = MAX(bbwidth, logical_rect.width); 6530bbfda8aSnia 6540bbfda8aSnia XmbTextExtents(font.font_set, everywhere_string, 6550bbfda8aSnia strlen(everywhere_string), 6560bbfda8aSnia &inc_rect, &logical_rect); 6570bbfda8aSnia bbwidth = MAX(bbwidth, logical_rect.width); 6580bbfda8aSnia 6590bbfda8aSnia /* Plus the padding width */ 6600bbfda8aSnia bbwidth += hspace; 6610bbfda8aSnia 6620bbfda8aSnia /* 6630bbfda8aSnia * So, the final width of those bottom buttons is that, plus the 6640bbfda8aSnia * 3d button look extra on both sides, plus a little extra. I 6650bbfda8aSnia * guess that extra + 2 is similar to TitlePadding or 6660bbfda8aSnia * ButtonIndent on titlebars, but we don't have a config param 6670bbfda8aSnia * for it on the workspace manager (which is the config used for 6680bbfda8aSnia * the occupy window), so leave it as a magic constant for now. 6690bbfda8aSnia */ 6700bbfda8aSnia occwin->owidth = bbwidth + 2 * Scr->WMgrButtonShadowDepth + 2; 6710bbfda8aSnia 6720bbfda8aSnia /* 6730bbfda8aSnia * The whole thing has to be at least triple the min width of 6740bbfda8aSnia * those bottom buttons, since there are three of them. The 6750bbfda8aSnia * layout is "hspace button hspace button [...] hspace", to pad 6760bbfda8aSnia * between and on both sides. 6770bbfda8aSnia */ 6780bbfda8aSnia bb_width = 3 * (bbwidth + hspace) + hspace; 6790bbfda8aSnia 6800bbfda8aSnia /* 6810bbfda8aSnia * It also has to be the width of our per-WS buttons. Per-ws 6820bbfda8aSnia * buttons are sized the same as in the button-state WSM, and 6830bbfda8aSnia * then we add the padding to them as above. 6840bbfda8aSnia */ 6850bbfda8aSnia ws_width = columns * (bwidth + hspace) + hspace; 6860bbfda8aSnia 6870bbfda8aSnia /* So the window has to be as wide as the wider of those */ 6880bbfda8aSnia width = MAX(bb_width, ws_width); 6890bbfda8aSnia } 6900bbfda8aSnia 6910bbfda8aSnia 6920bbfda8aSnia /* Now we know the size, so make the window */ 6930bbfda8aSnia w = occwin->w = XCreateSimpleWindow(dpy, Scr->Root, 0, 0, width, height, 6940bbfda8aSnia 1, Scr->Black, occwin->cp.back); 6950bbfda8aSnia 6960bbfda8aSnia /* Take those base sizes as a minimum */ 6970bbfda8aSnia occwin->minwidth = width; 6980bbfda8aSnia occwin->minheight = height; 6990bbfda8aSnia 7000bbfda8aSnia 7010bbfda8aSnia /* 7020bbfda8aSnia * Make subwindows as buttons for the workspaces. They're laid out 7030bbfda8aSnia * in a grid mirroring the workspace manager's. 7040bbfda8aSnia */ 7050bbfda8aSnia { 7060bbfda8aSnia int i = 0, j = 0; 7070bbfda8aSnia WorkSpace *ws; 7080bbfda8aSnia 7090bbfda8aSnia occwin->obuttonw = calloc(Scr->workSpaceMgr.count, sizeof(Window)); 7100bbfda8aSnia 7110bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 7120bbfda8aSnia int idx = (j * columns) + i; 7130bbfda8aSnia 7140bbfda8aSnia /* 7150bbfda8aSnia * Make and map. Note that we're not setting the size or 7160bbfda8aSnia * location at all here; ResizeOccupyWindow() does all that. 7170bbfda8aSnia * We just make 'em. 7180bbfda8aSnia */ 7190bbfda8aSnia occwin->obuttonw[idx] = XCreateSimpleWindow(dpy, w, 7200bbfda8aSnia Dummy /* x */, 7210bbfda8aSnia Dummy /* y */, 7220bbfda8aSnia Dummy /* width */, 7230bbfda8aSnia Dummy /* height */, 7240bbfda8aSnia 0, Scr->Black, ws->cp.back); 7250bbfda8aSnia XMapWindow(dpy, occwin->obuttonw[idx]); 7260bbfda8aSnia 7270bbfda8aSnia /* Inc around to the next location */ 7280bbfda8aSnia i++; 7290bbfda8aSnia if(i == columns) { 7300bbfda8aSnia i = 0; 7310bbfda8aSnia j++; 7320bbfda8aSnia } 7330bbfda8aSnia } 7340bbfda8aSnia } 7350bbfda8aSnia 7360bbfda8aSnia 7370bbfda8aSnia /* 7380bbfda8aSnia * Now start putting together the OK/Cancel/All buttons 7390bbfda8aSnia */ 7400bbfda8aSnia 7410bbfda8aSnia /* Background for them is hardcoded */ 7420bbfda8aSnia GetColor(Scr->Monochrome, &(occupyButtoncp.back), "gray50"); 7430bbfda8aSnia 7440bbfda8aSnia /* Foreground (not used here) is too */ 7450bbfda8aSnia occupyButtoncp.fore = Scr->White; 7460bbfda8aSnia 7470bbfda8aSnia /* Override (probably historical */ 7480bbfda8aSnia if(!Scr->BeNiceToColormap) { 7490bbfda8aSnia GetShadeColors(&occupyButtoncp); 7500bbfda8aSnia } 7510bbfda8aSnia 7520bbfda8aSnia /* Make 'em */ 7530bbfda8aSnia { 7540bbfda8aSnia Window tw; 7550bbfda8aSnia 7560bbfda8aSnia tw = XCreateSimpleWindow(dpy, w, Dummy, Dummy, Dummy, Dummy, 0, 7570bbfda8aSnia Scr->Black, occupyButtoncp.back); 7580bbfda8aSnia XMapWindow(dpy, tw); 7590bbfda8aSnia occwin->OK = tw; 7600bbfda8aSnia 7610bbfda8aSnia tw = XCreateSimpleWindow(dpy, w, Dummy, Dummy, Dummy, Dummy, 0, 7620bbfda8aSnia Scr->Black, occupyButtoncp.back); 7630bbfda8aSnia XMapWindow(dpy, tw); 7640bbfda8aSnia occwin->cancel = tw; 7650bbfda8aSnia 7660bbfda8aSnia tw = XCreateSimpleWindow(dpy, w, Dummy, Dummy, Dummy, Dummy, 0, 7670bbfda8aSnia Scr->Black, occupyButtoncp.back); 7680bbfda8aSnia XMapWindow(dpy, tw); 7690bbfda8aSnia occwin->allworkspc = tw; 7700bbfda8aSnia } 7710bbfda8aSnia 7720bbfda8aSnia 7730bbfda8aSnia /* Setup various window properties */ 7740bbfda8aSnia { 7750bbfda8aSnia XSizeHints sizehints; 7760bbfda8aSnia XWMHints wmhints; 7770bbfda8aSnia 7780bbfda8aSnia sizehints.flags = PBaseSize | PMinSize | PMaxSize; 7790bbfda8aSnia sizehints.min_width = width; 7800bbfda8aSnia sizehints.min_height = height; 7810bbfda8aSnia sizehints.base_width = width; 7820bbfda8aSnia sizehints.base_height = height; 7830bbfda8aSnia sizehints.max_width = width; 7840bbfda8aSnia sizehints.max_height = height; 7850bbfda8aSnia 7860bbfda8aSnia wmhints.flags = InputHint | StateHint; 7870bbfda8aSnia wmhints.input = True; 7880bbfda8aSnia wmhints.initial_state = NormalState; 7890bbfda8aSnia 7900bbfda8aSnia XmbSetWMProperties(dpy, w, occwin->name, occwin->icon_name, 7910bbfda8aSnia NULL, 0, &sizehints, &wmhints, NULL); 7920bbfda8aSnia } 7930bbfda8aSnia 7940bbfda8aSnia 7950bbfda8aSnia /* 7960bbfda8aSnia * Create the TwmWindow wrapping around it, with decorations etc. We 7970bbfda8aSnia * do this so early in startup that we're not listening for window 7980bbfda8aSnia * creation events yet. 7990bbfda8aSnia */ 8000bbfda8aSnia tmp_win = AddWindow(w, AWT_OCCUPY, Scr->iconmgr, Scr->currentvs); 8010bbfda8aSnia if(! tmp_win) { 8020bbfda8aSnia fprintf(stderr, "cannot create occupy window, exiting...\n"); 8030bbfda8aSnia exit(1); 8040bbfda8aSnia } 8050bbfda8aSnia tmp_win->vs = NULL; 8060bbfda8aSnia tmp_win->occupation = 0; 8070bbfda8aSnia 8080bbfda8aSnia /* tmp_win is more convenient the rest of the func, but put in place */ 8090bbfda8aSnia occwin->twm_win = tmp_win; 8100bbfda8aSnia 8110bbfda8aSnia 8120bbfda8aSnia /* 8130bbfda8aSnia * Setup the window to have a button-pushing cursor and listen for 8140bbfda8aSnia * clicks. 8150bbfda8aSnia */ 8160bbfda8aSnia { 8170bbfda8aSnia unsigned long attrmask; 8180bbfda8aSnia XSetWindowAttributes attr; 8190bbfda8aSnia XWindowAttributes wattr; 8200bbfda8aSnia 8210bbfda8aSnia attr.cursor = Scr->ButtonCursor; 8220bbfda8aSnia attrmask = CWCursor; 8230bbfda8aSnia XChangeWindowAttributes(dpy, w, attrmask, &attr); 8240bbfda8aSnia 8250bbfda8aSnia XGetWindowAttributes(dpy, w, &wattr); 8260bbfda8aSnia attrmask = wattr.your_event_mask | KeyPressMask | KeyReleaseMask 8270bbfda8aSnia | ExposureMask; 8280bbfda8aSnia XSelectInput(dpy, w, attrmask); 8290bbfda8aSnia } 8300bbfda8aSnia 8310bbfda8aSnia 8320bbfda8aSnia /* 8330bbfda8aSnia * Now for each of the buttons (workspaces + OK/Cancel/All), we mark 8340bbfda8aSnia * them as listening to click and exposure events. We also stash 8350bbfda8aSnia * away the screen and wrapping TwmWindow in contexts so other code 8360bbfda8aSnia * can dredge them up. 8370bbfda8aSnia */ 8380bbfda8aSnia#define EVT (ButtonPressMask | ButtonReleaseMask | ExposureMask) 8390bbfda8aSnia#define BTN_IPT_CTX(win) \ 8400bbfda8aSnia XSelectInput(dpy, (win), EVT); \ 8410bbfda8aSnia XSaveContext(dpy, (win), TwmContext, (XPointer) tmp_win); \ 8420bbfda8aSnia XSaveContext(dpy, (win), ScreenContext, (XPointer) Scr); 8430bbfda8aSnia 8440bbfda8aSnia for(WorkSpace *ws = Scr->workSpaceMgr.workSpaceList 8450bbfda8aSnia ; ws != NULL ; ws = ws->next) { 8460bbfda8aSnia BTN_IPT_CTX(occwin->obuttonw[ws->number]); 8470bbfda8aSnia } 8480bbfda8aSnia 8490bbfda8aSnia BTN_IPT_CTX(occwin->OK); 8500bbfda8aSnia BTN_IPT_CTX(occwin->cancel); 8510bbfda8aSnia BTN_IPT_CTX(occwin->allworkspc); 8520bbfda8aSnia 8530bbfda8aSnia#undef BTN_IPT_CTX 8540bbfda8aSnia#undef EVT 8550bbfda8aSnia 8560bbfda8aSnia 8570bbfda8aSnia /* Mark that we're not mapped */ 8580bbfda8aSnia SetMapStateProp(tmp_win, WithdrawnState); 8590bbfda8aSnia 8600bbfda8aSnia /* Now call that func that sizes all the buttons */ 8610bbfda8aSnia ResizeOccupyWindow(tmp_win); 8620bbfda8aSnia} 8630bbfda8aSnia 8640bbfda8aSnia 8650bbfda8aSnia/* 8660bbfda8aSnia * Slightly misleading name: layout the internals of the Occupy window 8670bbfda8aSnia * based on its current size. That does happen when it's resized, but 8680bbfda8aSnia * also when it's initially created. I guess you could call "creation" a 8690bbfda8aSnia * resize of a sort... 8700bbfda8aSnia */ 8710bbfda8aSniavoid 8720bbfda8aSniaResizeOccupyWindow(TwmWindow *win) 8730bbfda8aSnia{ 8740bbfda8aSnia int bwidth, bheight, owidth, oheight; 8750bbfda8aSnia int hspace, vspace; 8760bbfda8aSnia int lines, columns; 8770bbfda8aSnia int neww, newh; 8780bbfda8aSnia WorkSpace *ws; 8790bbfda8aSnia int i, j, x, y; 8800bbfda8aSnia OccupyWindow *occwin = Scr->workSpaceMgr.occupyWindow; 8810bbfda8aSnia 8820bbfda8aSnia /* Floor at the original size */ 8830bbfda8aSnia neww = MAX(win->attr.width, occwin->minwidth); 8840bbfda8aSnia newh = MAX(win->attr.height, occwin->minheight); 8850bbfda8aSnia if(occwin->width == neww && occwin->height == newh) { 8860bbfda8aSnia return; 8870bbfda8aSnia } 8880bbfda8aSnia 8890bbfda8aSnia /* Space between WS buttons. From WMgr{Horiz,Vert}ButtonIndent. */ 8900bbfda8aSnia hspace = occwin->hspace; 8910bbfda8aSnia vspace = occwin->vspace; 8920bbfda8aSnia 8930bbfda8aSnia /* Lines/cols in the layout. Same as WorkspaceManager's */ 8940bbfda8aSnia lines = Scr->workSpaceMgr.lines; 8950bbfda8aSnia columns = Scr->workSpaceMgr.columns; 8960bbfda8aSnia 8970bbfda8aSnia /* Width/height of each button, based on the above and window size */ 8980bbfda8aSnia bwidth = (neww - columns * hspace) / columns; 8990bbfda8aSnia bheight = (newh - (lines + 2) * vspace) / (lines + 1); 9000bbfda8aSnia 9010bbfda8aSnia /* Width/height of the OK/Cancel/All buttons */ 9020bbfda8aSnia owidth = occwin->owidth; 9030bbfda8aSnia oheight = bheight; 9040bbfda8aSnia 9050bbfda8aSnia 9060bbfda8aSnia /* 9070bbfda8aSnia * Lay out the workspace buttons 9080bbfda8aSnia */ 9090bbfda8aSnia i = 0; 9100bbfda8aSnia j = 0; 9110bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 9120bbfda8aSnia XMoveResizeWindow(dpy, occwin->obuttonw [j * columns + i], 9130bbfda8aSnia i * (bwidth + hspace) + (hspace / 2), 9140bbfda8aSnia j * (bheight + vspace) + (vspace / 2), 9150bbfda8aSnia bwidth, bheight); 9160bbfda8aSnia i++; 9170bbfda8aSnia if(i == columns) { 9180bbfda8aSnia i = 0; 9190bbfda8aSnia j++; 9200bbfda8aSnia } 9210bbfda8aSnia } 9220bbfda8aSnia 9230bbfda8aSnia 9240bbfda8aSnia /* 9250bbfda8aSnia * Now the action buttons 9260bbfda8aSnia */ 9270bbfda8aSnia hspace = (neww - 3 * owidth) / 4; // Padding between 9280bbfda8aSnia x = hspace; 9290bbfda8aSnia y = ((bheight + vspace) * lines) + ((3 * vspace) / 2); 9300bbfda8aSnia XMoveResizeWindow(dpy, occwin->OK, x, y, owidth, oheight); 9310bbfda8aSnia x += owidth + hspace; 9320bbfda8aSnia XMoveResizeWindow(dpy, occwin->cancel, x, y, owidth, oheight); 9330bbfda8aSnia x += owidth + hspace; 9340bbfda8aSnia XMoveResizeWindow(dpy, occwin->allworkspc, x, y, owidth, oheight); 9350bbfda8aSnia 9360bbfda8aSnia 9370bbfda8aSnia /* Save all those dimensions we figured */ 9380bbfda8aSnia occwin->width = neww; 9390bbfda8aSnia occwin->height = newh; 9400bbfda8aSnia occwin->bwidth = bwidth; 9410bbfda8aSnia occwin->bheight = bheight; 9420bbfda8aSnia occwin->owidth = owidth; 9430bbfda8aSnia 9440bbfda8aSnia /* Don't need to repaint it; it'll get expose events */ 9450bbfda8aSnia} 9460bbfda8aSnia 9470bbfda8aSnia 9480bbfda8aSnia/* 9490bbfda8aSnia * Draw the window when we need to (e.g., on expose) 9500bbfda8aSnia */ 9510bbfda8aSniavoid 9520bbfda8aSniaPaintOccupyWindow(void) 9530bbfda8aSnia{ 9540bbfda8aSnia WorkSpace *ws; 9550bbfda8aSnia OccupyWindow *occwin; 9560bbfda8aSnia int width, height; 9570bbfda8aSnia 9580bbfda8aSnia occwin = Scr->workSpaceMgr.occupyWindow; 9590bbfda8aSnia width = occwin->width; 9600bbfda8aSnia height = occwin->height; 9610bbfda8aSnia 9620bbfda8aSnia Draw3DBorder(occwin->w, 0, 0, width, height, 2, occwin->cp, off, true, false); 9630bbfda8aSnia 9640bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 9650bbfda8aSnia Window bw = occwin->obuttonw [ws->number]; 9660bbfda8aSnia ButtonState bs = (occwin->tmpOccupation & (1 << ws->number)) ? on : off; 9670bbfda8aSnia 9680bbfda8aSnia PaintWsButton(OCCUPYWINDOW, NULL, bw, ws->label, ws->cp, bs); 9690bbfda8aSnia } 9700bbfda8aSnia PaintWsButton(OCCUPYBUTTON, NULL, occwin->OK, ok_string, 9710bbfda8aSnia occupyButtoncp, off); 9720bbfda8aSnia PaintWsButton(OCCUPYBUTTON, NULL, occwin->cancel, cancel_string, 9730bbfda8aSnia occupyButtoncp, off); 9740bbfda8aSnia PaintWsButton(OCCUPYBUTTON, NULL, occwin->allworkspc, everywhere_string, 9750bbfda8aSnia occupyButtoncp, off); 9760bbfda8aSnia} 9770bbfda8aSnia 9780bbfda8aSnia 9790bbfda8aSnia/* 9800bbfda8aSnia * Somebody clicked in the Occupy window 9810bbfda8aSnia */ 9820bbfda8aSniavoid 9830bbfda8aSniaOccupyHandleButtonEvent(XEvent *event) 9840bbfda8aSnia{ 9850bbfda8aSnia WorkSpace *ws; 9860bbfda8aSnia OccupyWindow *occupyW; 9870bbfda8aSnia Window buttonW; 9880bbfda8aSnia 9890bbfda8aSnia /* 9900bbfda8aSnia * Doesn't make sense that this can even happen if there are no 9910bbfda8aSnia * workspaces... 9920bbfda8aSnia */ 9930bbfda8aSnia if(! Scr->workSpaceManagerActive) { 9940bbfda8aSnia return; 9950bbfda8aSnia } 9960bbfda8aSnia 9970bbfda8aSnia /* ... or if there's no Occupy window up for anything */ 9980bbfda8aSnia if(occupyWin == NULL) { 9990bbfda8aSnia return; 10000bbfda8aSnia } 10010bbfda8aSnia 10020bbfda8aSnia /* Which sub-window (button) was clicked */ 10030bbfda8aSnia buttonW = event->xbutton.window; 10040bbfda8aSnia if(buttonW == 0) { 10050bbfda8aSnia return; /* icon */ 10060bbfda8aSnia } 10070bbfda8aSnia 10080bbfda8aSnia /* Grab onto the pointer for the duration of our action */ 10090bbfda8aSnia XGrabPointer(dpy, Scr->Root, True, 10100bbfda8aSnia ButtonPressMask | ButtonReleaseMask, 10110bbfda8aSnia GrabModeAsync, GrabModeAsync, 10120bbfda8aSnia Scr->Root, None, CurrentTime); 10130bbfda8aSnia 10140bbfda8aSnia /* Find the workspace button that was clicked */ 10150bbfda8aSnia occupyW = Scr->workSpaceMgr.occupyWindow; 10160bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 10170bbfda8aSnia if(occupyW->obuttonw [ws->number] == buttonW) { 10180bbfda8aSnia break; 10190bbfda8aSnia } 10200bbfda8aSnia } 10210bbfda8aSnia 10220bbfda8aSnia if(ws != NULL) { 10230bbfda8aSnia /* If one was, toggle it */ 10240bbfda8aSnia int mask = 1 << ws->number; 10250bbfda8aSnia ButtonState bs = (occupyW->tmpOccupation & mask) ? off : on; 10260bbfda8aSnia 10270bbfda8aSnia PaintWsButton(OCCUPYWINDOW, NULL, occupyW->obuttonw [ws->number], 10280bbfda8aSnia ws->label, ws->cp, bs); 10290bbfda8aSnia occupyW->tmpOccupation ^= mask; 10300bbfda8aSnia } 10310bbfda8aSnia else if(buttonW == occupyW->OK) { 10320bbfda8aSnia /* Else if we clicked OK, set things and close the window */ 10330bbfda8aSnia if(occupyW->tmpOccupation == 0) { 10340bbfda8aSnia return; 10350bbfda8aSnia } 10360bbfda8aSnia ChangeOccupation(occupyWin, occupyW->tmpOccupation); 10370bbfda8aSnia XUnmapWindow(dpy, occupyW->twm_win->frame); 10380bbfda8aSnia occupyW->twm_win->mapped = false; 10390bbfda8aSnia occupyW->twm_win->occupation = 0; 10400bbfda8aSnia occupyWin = NULL; 10410bbfda8aSnia XSync(dpy, 0); 10420bbfda8aSnia } 10430bbfda8aSnia else if(buttonW == occupyW->cancel) { 10440bbfda8aSnia /* Or cancel, do nothing and close the window */ 10450bbfda8aSnia XUnmapWindow(dpy, occupyW->twm_win->frame); 10460bbfda8aSnia occupyW->twm_win->mapped = false; 10470bbfda8aSnia occupyW->twm_win->occupation = 0; 10480bbfda8aSnia occupyWin = NULL; 10490bbfda8aSnia XSync(dpy, 0); 10500bbfda8aSnia } 10510bbfda8aSnia else if(buttonW == occupyW->allworkspc) { 10520bbfda8aSnia /* Or All, set 'em all */ 10530bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 10540bbfda8aSnia PaintWsButton(OCCUPYWINDOW, NULL, occupyW->obuttonw [ws->number], 10550bbfda8aSnia ws->label, ws->cp, on); 10560bbfda8aSnia } 10570bbfda8aSnia occupyW->tmpOccupation = fullOccupation; 10580bbfda8aSnia } 10590bbfda8aSnia 10600bbfda8aSnia /* Release the pointer, if ??? */ 10610bbfda8aSnia if(ButtonPressed == -1) { 10620bbfda8aSnia XUngrabPointer(dpy, CurrentTime); 10630bbfda8aSnia } 10640bbfda8aSnia} 10650bbfda8aSnia 10660bbfda8aSnia 10670bbfda8aSnia/* 10680bbfda8aSnia * f.occupy backend - pop up Occupy control for some window 10690bbfda8aSnia */ 10700bbfda8aSniavoid 10710bbfda8aSniaOccupy(TwmWindow *twm_win) 10720bbfda8aSnia{ 10730bbfda8aSnia int x, y; 10740bbfda8aSnia unsigned int width, height; 10750bbfda8aSnia int xoffset, yoffset; 10760bbfda8aSnia Window w; 10770bbfda8aSnia struct OccupyWindow *occupyWindow; 10780bbfda8aSnia TwmWindow *occupy_twm; 10790bbfda8aSnia 10800bbfda8aSnia /* Don't pop up on stuff we can't change */ 10810bbfda8aSnia if(!CanChangeOccupation(&twm_win)) { 10820bbfda8aSnia return; 10830bbfda8aSnia } 10840bbfda8aSnia 10850bbfda8aSnia /* Grab our one screen-wide f.occupy window */ 10860bbfda8aSnia occupyWindow = Scr->workSpaceMgr.occupyWindow; 10870bbfda8aSnia occupyWindow->tmpOccupation = twm_win->occupation; 10880bbfda8aSnia w = occupyWindow->w; 10890bbfda8aSnia 10900bbfda8aSnia /* Figure where to put it so it's centered on the cursor */ 10910bbfda8aSnia XGetGeometry(dpy, w, &JunkRoot, &JunkX, &JunkY, &width, &height, 10920bbfda8aSnia &JunkBW, &JunkDepth); 10930bbfda8aSnia XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkRoot, &JunkX, &JunkY, 10940bbfda8aSnia &x, &y, &JunkMask); 10950bbfda8aSnia x -= (width / 2); 10960bbfda8aSnia y -= (height / 2); 10970bbfda8aSnia if(x < 0) { 10980bbfda8aSnia x = 0; 10990bbfda8aSnia } 11000bbfda8aSnia if(y < 0) { 11010bbfda8aSnia y = 0; 11020bbfda8aSnia } 11030bbfda8aSnia xoffset = width + 2 * Scr->BorderWidth; 11040bbfda8aSnia yoffset = height + 2 * Scr->BorderWidth + Scr->TitleHeight; 11050bbfda8aSnia 11060bbfda8aSnia /* ... (but not off the screen!) */ 11070bbfda8aSnia if((x + xoffset) > Scr->rootw) { 11080bbfda8aSnia x = Scr->rootw - xoffset; 11090bbfda8aSnia } 11100bbfda8aSnia if((y + yoffset) > Scr->rooth) { 11110bbfda8aSnia y = Scr->rooth - yoffset; 11120bbfda8aSnia } 11130bbfda8aSnia 11140bbfda8aSnia occupy_twm = occupyWindow->twm_win; 11150bbfda8aSnia occupy_twm->occupation = twm_win->occupation; 11160bbfda8aSnia 11170bbfda8aSnia /* Move the occupy window to where it should be */ 11180bbfda8aSnia if(occupy_twm->parent_vs != twm_win->parent_vs) { 11190bbfda8aSnia occupy_twm->vs = twm_win->parent_vs; 11200bbfda8aSnia occupy_twm->frame_x = x; 11210bbfda8aSnia occupy_twm->frame_y = y; 11220bbfda8aSnia /* 11230bbfda8aSnia * XXX Should this be using DisplayWin() like everything else, 11240bbfda8aSnia * rather than manually grubbing beneath it? 11250bbfda8aSnia */ 11260bbfda8aSnia ReparentFrameAndIcon(occupy_twm); 11270bbfda8aSnia } 11280bbfda8aSnia else { 11290bbfda8aSnia XMoveWindow(dpy, occupyWindow->twm_win->frame, x, y); 11300bbfda8aSnia } 11310bbfda8aSnia 11320bbfda8aSnia /* And show it */ 11330bbfda8aSnia SetMapStateProp(occupy_twm, NormalState); 11340bbfda8aSnia XMapWindow(dpy, occupyWindow->w); 11350bbfda8aSnia XMapWindow(dpy, occupy_twm->frame); 11360bbfda8aSnia 11370bbfda8aSnia /* XXX Must be a better way to express "all the way on top" */ 11380bbfda8aSnia OtpSetPriority(occupy_twm, WinWin, 0, Above); 11390bbfda8aSnia 11400bbfda8aSnia /* Mark it shown, and stash what window we're showing it for */ 11410bbfda8aSnia occupyWindow->twm_win->mapped = true; 11420bbfda8aSnia occupyWin = twm_win; 11430bbfda8aSnia} 11440bbfda8aSnia 11450bbfda8aSnia 11460bbfda8aSnia 11470bbfda8aSnia 11480bbfda8aSnia/* 11490bbfda8aSnia **************************************************************** 11500bbfda8aSnia * 11510bbfda8aSnia * Backend and misc 11520bbfda8aSnia * 11530bbfda8aSnia **************************************************************** 11540bbfda8aSnia */ 11550bbfda8aSnia 11560bbfda8aSnia 11570bbfda8aSnia/* 11580bbfda8aSnia * The actual meat of occupation-changing; [re-]set the occupation for 11590bbfda8aSnia * the window. This is the func that actually sets and saves the new 11600bbfda8aSnia * occupation, moves the window where it should be, etc. Should maybe be 11610bbfda8aSnia * called something more like "SetOccupation()". 11620bbfda8aSnia */ 11630bbfda8aSniavoid 11640bbfda8aSniaChangeOccupation(TwmWindow *tmp_win, int newoccupation) 11650bbfda8aSnia{ 11660bbfda8aSnia TwmWindow *t; 11670bbfda8aSnia WorkSpace *ws; 11680bbfda8aSnia int oldoccupation; 11690bbfda8aSnia int changedoccupation; 11700bbfda8aSnia 11710bbfda8aSnia if((newoccupation == 0) 11720bbfda8aSnia || (newoccupation == tmp_win->occupation)) { 11730bbfda8aSnia /* 11740bbfda8aSnia * occupation=0 we interpret as "leave it alone". == current, 11750bbfda8aSnia * ditto. Go ahead and re-set the WM_OCCUPATION property though, 11760bbfda8aSnia * in case it's been broken by another client. 11770bbfda8aSnia */ 11780bbfda8aSnia char *namelist; 11790bbfda8aSnia int len; 11800bbfda8aSnia long eventMask; 11810bbfda8aSnia 11820bbfda8aSnia /* Mask out the PropertyChange events while we change the prop */ 11830bbfda8aSnia eventMask = mask_out_event(tmp_win->w, PropertyChangeMask); 11840bbfda8aSnia 11850bbfda8aSnia len = GetPropertyFromMask(tmp_win->occupation, &namelist); 11860bbfda8aSnia XChangeProperty(dpy, tmp_win->w, XA_WM_OCCUPATION, XA_STRING, 8, 11870bbfda8aSnia PropModeReplace, (unsigned char *) namelist, len); 11880bbfda8aSnia free(namelist); 11890bbfda8aSnia#ifdef EWMH 11900bbfda8aSnia EwmhSet_NET_WM_DESKTOP(tmp_win); 11910bbfda8aSnia#endif 11920bbfda8aSnia 11930bbfda8aSnia /* Reset event mask */ 11940bbfda8aSnia restore_mask(tmp_win->w, eventMask); 11950bbfda8aSnia return; 11960bbfda8aSnia } 11970bbfda8aSnia 11980bbfda8aSnia /* 11990bbfda8aSnia * OK, there's something to change. Stash the current state. 12000bbfda8aSnia */ 12010bbfda8aSnia oldoccupation = tmp_win->occupation; 12020bbfda8aSnia 12030bbfda8aSnia /* 12040bbfda8aSnia * Add it to IconManager in the new WS[en], remove from old. We have 12050bbfda8aSnia * to do the rather odd dance because AddIconManager() loops through 12060bbfda8aSnia * workspaces, and will add it to any workspaces it occupies (even if 12070bbfda8aSnia * it's already there). RemoveIconManager() goes over the window's 12080bbfda8aSnia * list of what icon managers it's on and removes it from any that 12090bbfda8aSnia * don't match the current occupation, so it can just be told "here's 12100bbfda8aSnia * where I should be". 12110bbfda8aSnia */ 12120bbfda8aSnia tmp_win->occupation = newoccupation & ~oldoccupation; 12130bbfda8aSnia AddIconManager(tmp_win); 12140bbfda8aSnia tmp_win->occupation = newoccupation; 12150bbfda8aSnia RemoveIconManager(tmp_win); 12160bbfda8aSnia 12170bbfda8aSnia /* If it shouldn't be "here", vanish it */ 12180bbfda8aSnia if(tmp_win->vs && !OCCUPY(tmp_win, tmp_win->vs->wsw->currentwspc)) { 12190bbfda8aSnia Vanish(tmp_win->vs, tmp_win); 12200bbfda8aSnia } 12210bbfda8aSnia 12220bbfda8aSnia /* 12230bbfda8aSnia * Try to find an(other) virtual screen which shows a workspace 12240bbfda8aSnia * where the window has occupation, so that the window can be shown 12250bbfda8aSnia * there now. 12260bbfda8aSnia */ 12270bbfda8aSnia if(!tmp_win->vs) { 12280bbfda8aSnia VirtualScreen *vs; 12290bbfda8aSnia for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 12300bbfda8aSnia if(OCCUPY(tmp_win, vs->wsw->currentwspc)) { 12310bbfda8aSnia DisplayWin(vs, tmp_win); 12320bbfda8aSnia break; 12330bbfda8aSnia } 12340bbfda8aSnia } 12350bbfda8aSnia } 12360bbfda8aSnia 12370bbfda8aSnia /* 12380bbfda8aSnia * Loop over workspaces. Find the first one that it used to be in. 12390bbfda8aSnia * If it's not there anymore, take it out of the WindowRegion there 12400bbfda8aSnia * (RWFR() silently returns if we're not using WindowRegion's), and 12410bbfda8aSnia * add it the WindowRegion in the first WS it now occupies. 12420bbfda8aSnia * 12430bbfda8aSnia * XXX I'm not sure this is entirely sensible; it seems like just 12440bbfda8aSnia * unconditionally Remove/Place'ing would have the same effect? 12450bbfda8aSnia */ 12460bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 12470bbfda8aSnia int mask = 1 << ws->number; 12480bbfda8aSnia if(oldoccupation & mask) { 12490bbfda8aSnia if(!(newoccupation & mask)) { 12500bbfda8aSnia int final_x, final_y; 12510bbfda8aSnia RemoveWindowFromRegion(tmp_win); 12520bbfda8aSnia if(PlaceWindowInRegion(tmp_win, &final_x, &final_y)) { 12530bbfda8aSnia XMoveWindow(dpy, tmp_win->frame, final_x, final_y); 12540bbfda8aSnia } 12550bbfda8aSnia } 12560bbfda8aSnia break; 12570bbfda8aSnia } 12580bbfda8aSnia } 12590bbfda8aSnia 12600bbfda8aSnia /* Now set the WM_OCCUPATION property */ 12610bbfda8aSnia { 12620bbfda8aSnia char *namelist; 12630bbfda8aSnia int len; 12640bbfda8aSnia long eventMask; 12650bbfda8aSnia 12660bbfda8aSnia eventMask = mask_out_event(tmp_win->w, PropertyChangeMask); 12670bbfda8aSnia 12680bbfda8aSnia len = GetPropertyFromMask(newoccupation, &namelist); 12690bbfda8aSnia XChangeProperty(dpy, tmp_win->w, XA_WM_OCCUPATION, XA_STRING, 8, 12700bbfda8aSnia PropModeReplace, (unsigned char *) namelist, len); 12710bbfda8aSnia free(namelist); 12720bbfda8aSnia#ifdef EWMH 12730bbfda8aSnia EwmhSet_NET_WM_DESKTOP(tmp_win); 12740bbfda8aSnia#endif 12750bbfda8aSnia 12760bbfda8aSnia restore_mask(tmp_win->w, eventMask); 12770bbfda8aSnia } 12780bbfda8aSnia 12790bbfda8aSnia 12800bbfda8aSnia /* 12810bbfda8aSnia * Handle showing it up in the workspace map in the appropriate 12820bbfda8aSnia * places. 12830bbfda8aSnia * 12840bbfda8aSnia * Note that this whole block messes with the {new,old}occupation 12850bbfda8aSnia * vars. That's "safe" because they're no longer used for their 12860bbfda8aSnia * original purposes, only for the WSmap changes, but it's still 12870bbfda8aSnia * kinda fugly. Change to local vars at the drop of a hat with later 12880bbfda8aSnia * changes... 12890bbfda8aSnia */ 12900bbfda8aSnia if(!WMapWindowMayBeAdded(tmp_win)) { 12910bbfda8aSnia /* Not showing in the map, so pretend it's nowhere */ 12920bbfda8aSnia newoccupation = 0; 12930bbfda8aSnia } 12940bbfda8aSnia if(Scr->workSpaceMgr.noshowoccupyall) { 12950bbfda8aSnia /* 12960bbfda8aSnia * Don't show OccupyAll. Note that this means both OccupyAll 12970bbfda8aSnia * window, AND windows manually set to occupy everything. We 12980bbfda8aSnia * don't have to adjust newoccupation, because the above 12990bbfda8aSnia * conditional would have caught it, so we only need to edit old. 13000bbfda8aSnia */ 13010bbfda8aSnia if(oldoccupation == fullOccupation) { 13020bbfda8aSnia oldoccupation = 0; 13030bbfda8aSnia } 13040bbfda8aSnia } 13050bbfda8aSnia 13060bbfda8aSnia /* Flip the ones that need flipping */ 13070bbfda8aSnia changedoccupation = oldoccupation ^ newoccupation; 13080bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 13090bbfda8aSnia int mask = 1 << ws->number; 13100bbfda8aSnia if(changedoccupation & mask) { 13110bbfda8aSnia if(newoccupation & mask) { 13120bbfda8aSnia /* Add to WS */ 13130bbfda8aSnia WMapAddWindowToWorkspace(tmp_win, ws); 13140bbfda8aSnia } 13150bbfda8aSnia else { 13160bbfda8aSnia /* 13170bbfda8aSnia * Remove from WS. We have to take it out of saved focus 13180bbfda8aSnia * if it were there. Maybe there are other places we 13190bbfda8aSnia * might need to remove it from (warpring?)? 13200bbfda8aSnia */ 13210bbfda8aSnia WMapRemoveWindowFromWorkspace(tmp_win, ws); 13220bbfda8aSnia if(Scr->SaveWorkspaceFocus && ws->save_focus == tmp_win) { 13230bbfda8aSnia ws->save_focus = NULL; 13240bbfda8aSnia } 13250bbfda8aSnia } 13260bbfda8aSnia } 13270bbfda8aSnia } 13280bbfda8aSnia 13290bbfda8aSnia 13300bbfda8aSnia /* 13310bbfda8aSnia * If transients don't have their own occupation, find any transients 13320bbfda8aSnia * of this window and move them with it. 13330bbfda8aSnia */ 13340bbfda8aSnia if(! Scr->TransientHasOccupation) { 13350bbfda8aSnia for(t = Scr->FirstWindow; t != NULL; t = t->next) { 13360bbfda8aSnia if(t != tmp_win && 13370bbfda8aSnia ((t->istransient && t->transientfor == tmp_win->w) || 13380bbfda8aSnia t->group == tmp_win->w)) { 13390bbfda8aSnia ChangeOccupation(t, tmp_win->occupation); 13400bbfda8aSnia } 13410bbfda8aSnia } 13420bbfda8aSnia } 13430bbfda8aSnia 13440bbfda8aSnia /* All done */ 13450bbfda8aSnia return; 13460bbfda8aSnia} 13470bbfda8aSnia 13480bbfda8aSnia 13490bbfda8aSnia/* 13500bbfda8aSnia * There are various reasons you might not be able to change the 13510bbfda8aSnia * occupation of a window (either due to attributes of it, or the state 13520bbfda8aSnia * of your session/WM), so provide a function to check them all when we 13530bbfda8aSnia * try a change. 13540bbfda8aSnia * 13550bbfda8aSnia * Note that this is _not_ called from ChangeOccupation(); only from 13560bbfda8aSnia * other things that wrap it. Since CO() gets called from states where 13570bbfda8aSnia * this would [falsely] fail, it would be a bad idea to put it there. 13580bbfda8aSnia */ 13590bbfda8aSniastatic bool 13600bbfda8aSniaCanChangeOccupation(TwmWindow **twm_winp) 13610bbfda8aSnia{ 13620bbfda8aSnia TwmWindow *twm_win; 13630bbfda8aSnia 13640bbfda8aSnia /* No workspaces config'd? Changing is nonsensical. */ 13650bbfda8aSnia if(!Scr->workSpaceManagerActive) { 13660bbfda8aSnia return false; 13670bbfda8aSnia } 13680bbfda8aSnia 13690bbfda8aSnia /* 13700bbfda8aSnia * f.occupy window up? Can't change in the middle of changing. 13710bbfda8aSnia * Though if it's not mapped, still pull it up, else iconifying the 13720bbfda8aSnia * occupy window breaks it forever. 13730bbfda8aSnia */ 13740bbfda8aSnia if(occupyWin != NULL && Scr->workSpaceMgr.occupyWindow->twm_win->mapped) { 13750bbfda8aSnia return false; 13760bbfda8aSnia } 13770bbfda8aSnia 13780bbfda8aSnia /* XXX Can we jut do this in the init? Check all callers. */ 13790bbfda8aSnia twm_win = *twm_winp; 13800bbfda8aSnia 13810bbfda8aSnia /* Don't change occupation of icon managers */ 13820bbfda8aSnia if(twm_win->isiconmgr) { 13830bbfda8aSnia return false; 13840bbfda8aSnia } 13850bbfda8aSnia 13860bbfda8aSnia /* XXX Should check iswspmgr here too? */ 13870bbfda8aSnia 13880bbfda8aSnia /* 13890bbfda8aSnia * If transients don't have their own occupation, check 13900bbfda8aSnia * transient/group bits. 13910bbfda8aSnia */ 13920bbfda8aSnia if(!Scr->TransientHasOccupation) { 13930bbfda8aSnia if(twm_win->istransient) { 13940bbfda8aSnia return false; 13950bbfda8aSnia } 13960bbfda8aSnia if(twm_win->group != (Window) 0 && twm_win->group != twm_win->w) { 13970bbfda8aSnia /* 13980bbfda8aSnia * When trying to modify a group member window, 13990bbfda8aSnia * operate on the group leader instead 14000bbfda8aSnia * (and thereby on all group member windows as well). 14010bbfda8aSnia * If we can't find the group leader, pretend it isn't set. 14020bbfda8aSnia */ 14030bbfda8aSnia twm_win = GetTwmWindow(twm_win->group); 14040bbfda8aSnia if(!twm_win) { 14050bbfda8aSnia return true; 14060bbfda8aSnia } 14070bbfda8aSnia *twm_winp = twm_win; 14080bbfda8aSnia } 14090bbfda8aSnia } 14100bbfda8aSnia 14110bbfda8aSnia /* Sure, go ahead, change it */ 14120bbfda8aSnia return true; 14130bbfda8aSnia} 14140bbfda8aSnia 14150bbfda8aSnia 14160bbfda8aSnia/* 14170bbfda8aSnia * Add a client name to a list determining which workspaces it will 14180bbfda8aSnia * occupy. Used in handling the Occupy { } block in config file. 14190bbfda8aSnia */ 14200bbfda8aSniabool 14210bbfda8aSniaAddToClientsList(char *workspace, char *client) 14220bbfda8aSnia{ 14230bbfda8aSnia WorkSpace *ws; 14240bbfda8aSnia 14250bbfda8aSnia /* "all" is a magic workspace value which makes it occupy anywhere */ 14260bbfda8aSnia if(strcmp(workspace, "all") == 0) { 14270bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 14280bbfda8aSnia AddToList(&ws->clientlist, client, ""); 14290bbfda8aSnia } 14300bbfda8aSnia return true; 14310bbfda8aSnia } 14320bbfda8aSnia 14330bbfda8aSnia /* If prefixed with "ws:", strip the prefix and lookup by WS name */ 14340bbfda8aSnia if(strncmp(workspace, "ws:", 3) == 0) { 14350bbfda8aSnia if((ws = GetWorkspace(workspace + 3)) != NULL) { 14360bbfda8aSnia AddToList(&ws->clientlist, client, ""); 14370bbfda8aSnia return true; 14380bbfda8aSnia } 14390bbfda8aSnia } 14400bbfda8aSnia 14410bbfda8aSnia /* Else find that named workspace and all this to it */ 14420bbfda8aSnia if((ws = GetWorkspace(workspace)) != NULL) { 14430bbfda8aSnia AddToList(&ws->clientlist, client, ""); 14440bbfda8aSnia return true; 14450bbfda8aSnia } 14460bbfda8aSnia 14470bbfda8aSnia /* Couldn't figure where to put it */ 14480bbfda8aSnia return false; 14490bbfda8aSnia} 14500bbfda8aSnia 14510bbfda8aSnia 14520bbfda8aSnia/* 14530bbfda8aSnia * Turn a ctwm.workspace resource string into an occupation mask. n.b.; 14540bbfda8aSnia * this changes the 'res' arg in-place. 14550bbfda8aSnia */ 14560bbfda8aSniastatic int 14570bbfda8aSniaGetMaskFromResource(TwmWindow *win, char *res) 14580bbfda8aSnia{ 14590bbfda8aSnia WorkSpace *ws; 14600bbfda8aSnia int mask; 14610bbfda8aSnia enum { O_SET, O_ADD, O_REM } mode; 14620bbfda8aSnia char *wrkSpcName, *tokst; 14630bbfda8aSnia 14640bbfda8aSnia /* 14650bbfda8aSnia * This can set the occupation to a specific set of workspaces ("ws1 14660bbfda8aSnia * ws3"), add to the set it woudl have otherwise ("+ws1 ws3"), or 14670bbfda8aSnia * remove from the set it would otherwise ("-ws1 ws3"). The +/- 14680bbfda8aSnia * apply to the whole expression, not to the individual entries in 14690bbfda8aSnia * it. So first, figure out what we're doing. 14700bbfda8aSnia */ 14710bbfda8aSnia mode = O_SET; 14720bbfda8aSnia if(*res == '+') { 14730bbfda8aSnia mode = O_ADD; 14740bbfda8aSnia res++; 14750bbfda8aSnia } 14760bbfda8aSnia else if(*res == '-') { 14770bbfda8aSnia mode = O_REM; 14780bbfda8aSnia res++; 14790bbfda8aSnia } 14800bbfda8aSnia 14810bbfda8aSnia /* 14820bbfda8aSnia * Walk through the string adding the workspaces specified into the 14830bbfda8aSnia * mask of what we're doing. 14840bbfda8aSnia */ 14850bbfda8aSnia mask = 0; 14860bbfda8aSnia for(wrkSpcName = strtok_r(res, " ", &tokst) ; wrkSpcName 14870bbfda8aSnia ; wrkSpcName = strtok_r(NULL, " ", &tokst)) { 14880bbfda8aSnia if(strcmp(wrkSpcName, "all") == 0) { 14890bbfda8aSnia mask = fullOccupation; 14900bbfda8aSnia break; 14910bbfda8aSnia } 14920bbfda8aSnia if(strcmp(wrkSpcName, "current") == 0) { 14930bbfda8aSnia VirtualScreen *vs = Scr->currentvs; 14940bbfda8aSnia if(vs) { 14950bbfda8aSnia mask |= (1 << vs->wsw->currentwspc->number); 14960bbfda8aSnia } 14970bbfda8aSnia continue; 14980bbfda8aSnia } 14990bbfda8aSnia 15000bbfda8aSnia ws = GetWorkspace(wrkSpcName); 15010bbfda8aSnia if(ws != NULL) { 15020bbfda8aSnia mask |= (1 << ws->number); 15030bbfda8aSnia } 15040bbfda8aSnia else { 15050bbfda8aSnia fprintf(stderr, "unknown workspace : %s\n", wrkSpcName); 15060bbfda8aSnia } 15070bbfda8aSnia } 15080bbfda8aSnia 15090bbfda8aSnia /* 15100bbfda8aSnia * And return that mask, with necessary alterations depending on +/- 15110bbfda8aSnia * specified. 15120bbfda8aSnia */ 15130bbfda8aSnia switch(mode) { 15140bbfda8aSnia case O_SET: 15150bbfda8aSnia return (mask); 15160bbfda8aSnia case O_ADD: 15170bbfda8aSnia return (mask | win->occupation); 15180bbfda8aSnia case O_REM: 15190bbfda8aSnia return (win->occupation & ~mask); 15200bbfda8aSnia } 15210bbfda8aSnia 15220bbfda8aSnia /* Can't get here */ 15230bbfda8aSnia fprintf(stderr, "%s(): Unreachable.\n", __func__); 15240bbfda8aSnia return 0; 15250bbfda8aSnia} 15260bbfda8aSnia 15270bbfda8aSnia 15280bbfda8aSnia/* 15290bbfda8aSnia * Turns a \0-separated buffer of workspace names into an occupation 15300bbfda8aSnia * bitmask. 15310bbfda8aSnia */ 15320bbfda8aSniaunsigned int 15330bbfda8aSniaGetMaskFromProperty(unsigned char *_prop, unsigned long len) 15340bbfda8aSnia{ 15350bbfda8aSnia char wrkSpcName[256]; 15360bbfda8aSnia WorkSpace *ws; 15370bbfda8aSnia unsigned int mask; 15380bbfda8aSnia int l; 15390bbfda8aSnia char *prop; 15400bbfda8aSnia 15410bbfda8aSnia mask = 0; 15420bbfda8aSnia l = 0; 15430bbfda8aSnia prop = (char *) _prop; 15440bbfda8aSnia while(l < len) { 15450bbfda8aSnia /* If you have WS names longer than 256 chars, that's just Too Bad */ 15460bbfda8aSnia safe_strncpy(wrkSpcName, prop, 256); 15470bbfda8aSnia l += strlen(prop) + 1; 15480bbfda8aSnia prop += strlen(prop) + 1; 15490bbfda8aSnia if(strcmp(wrkSpcName, "all") == 0) { 15500bbfda8aSnia mask = fullOccupation; 15510bbfda8aSnia break; 15520bbfda8aSnia } 15530bbfda8aSnia 15540bbfda8aSnia ws = GetWorkspace(wrkSpcName); 15550bbfda8aSnia if(ws != NULL) { 15560bbfda8aSnia mask |= (1 << ws->number); 15570bbfda8aSnia } 15580bbfda8aSnia else { 15590bbfda8aSnia fprintf(stderr, "unknown workspace : %s\n", wrkSpcName); 15600bbfda8aSnia } 15610bbfda8aSnia } 15620bbfda8aSnia 15630bbfda8aSnia#if 0 15640bbfda8aSnia { 15650bbfda8aSnia char *dbs = mk_nullsep_string((char *)_prop, len); 15660bbfda8aSnia fprintf(stderr, "%s('%s') -> 0x%x\n", __func__, dbs, mask); 15670bbfda8aSnia free(dbs); 15680bbfda8aSnia } 15690bbfda8aSnia#endif 15700bbfda8aSnia 15710bbfda8aSnia return (mask); 15720bbfda8aSnia} 15730bbfda8aSnia 15740bbfda8aSnia 15750bbfda8aSnia/* 15760bbfda8aSnia * Turns an occupation mask into a \0-separated buffer (not really a 15770bbfda8aSnia * string) of the workspace names. 15780bbfda8aSnia */ 15790bbfda8aSniaint 15800bbfda8aSniaGetPropertyFromMask(unsigned int mask, char **prop) 15810bbfda8aSnia{ 15820bbfda8aSnia WorkSpace *ws; 15830bbfda8aSnia int len; 15840bbfda8aSnia char *wss[MAXWORKSPACE]; 15850bbfda8aSnia int i; 15860bbfda8aSnia 15870bbfda8aSnia /* If it's everything, just say 'all' */ 15880bbfda8aSnia if(mask == fullOccupation) { 15890bbfda8aSnia *prop = strdup("all"); 15900bbfda8aSnia return 3; 15910bbfda8aSnia } 15920bbfda8aSnia 15930bbfda8aSnia /* Stash up pointers to all the labels for WSen it's in */ 15940bbfda8aSnia memset(wss, 0, sizeof(wss)); 15950bbfda8aSnia i = 0; 15960bbfda8aSnia len = 0; 15970bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 15980bbfda8aSnia if(mask & (1 << ws->number)) { 15990bbfda8aSnia wss[i++] = ws->label; 16000bbfda8aSnia len += strlen(ws->label) + 1; 16010bbfda8aSnia } 16020bbfda8aSnia } 16030bbfda8aSnia 16040bbfda8aSnia /* Assemble them into \0-separated string */ 16050bbfda8aSnia *prop = malloc(len); 16060bbfda8aSnia len = 0; 16070bbfda8aSnia for(i = 0 ; wss[i] != NULL ; i++) { 16080bbfda8aSnia strcpy((*prop + len), wss[i]); 16090bbfda8aSnia len += strlen(wss[i]) + 1; // Skip past \0 16100bbfda8aSnia } 16110bbfda8aSnia 16120bbfda8aSnia#if 0 16130bbfda8aSnia { 16140bbfda8aSnia char *dbs = mk_nullsep_string(*prop, len); 16150bbfda8aSnia fprintf(stderr, "%s(0x%x) -> %d:'%s'\n", __func__, mask, len, dbs); 16160bbfda8aSnia free(dbs); 16170bbfda8aSnia } 16180bbfda8aSnia#endif 16190bbfda8aSnia 16200bbfda8aSnia return len; 16210bbfda8aSnia} 16220bbfda8aSnia 16230bbfda8aSnia 16240bbfda8aSnia/* 16250bbfda8aSnia * Generate a printable variant of the null-separated strings we use for 16260bbfda8aSnia * stashing in XA_WM_OCCUPATION. Used for debugging 16270bbfda8aSnia * Get{Property,Mask}From{Mask,Property}(). 16280bbfda8aSnia */ 16290bbfda8aSnia#ifdef __GNUC__ 16300bbfda8aSnia# pragma GCC diagnostic push 16310bbfda8aSnia# pragma GCC diagnostic ignored "-Wunused-function" 16320bbfda8aSnia#endif 16330bbfda8aSniastatic char * 16340bbfda8aSniamk_nullsep_string(const char *prop, int len) 16350bbfda8aSnia{ 16360bbfda8aSnia char *dbs; 16370bbfda8aSnia int i, j; 16380bbfda8aSnia 16390bbfda8aSnia /* 16400bbfda8aSnia * '\0' => "\\0" means we need longer than input; *2 is overkill, 16410bbfda8aSnia * but always sufficient, and it's cheap. 16420bbfda8aSnia */ 16430bbfda8aSnia dbs = malloc(len * 2); 16440bbfda8aSnia i = j = 0; 16450bbfda8aSnia while(i < len) { 16460bbfda8aSnia size_t slen = strlen(prop + i); 16470bbfda8aSnia 16480bbfda8aSnia strcpy(dbs + j, (prop + i)); 16490bbfda8aSnia i += slen + 1; 16500bbfda8aSnia strcpy(dbs + j + slen, "\\0"); 16510bbfda8aSnia j += slen + 2; 16520bbfda8aSnia } 16530bbfda8aSnia 16540bbfda8aSnia return dbs; 16550bbfda8aSnia} 16560bbfda8aSnia#ifdef __GNUC__ 16570bbfda8aSnia# pragma GCC diagnostic pop 16580bbfda8aSnia#endif 1659