10bbfda8aSnia/* 20bbfda8aSnia * Copyright 1992 Claude Lecommandeur. 30bbfda8aSnia */ 40bbfda8aSnia 50bbfda8aSnia#include "ctwm.h" 60bbfda8aSnia 70bbfda8aSnia#include <stdio.h> 80bbfda8aSnia#include <string.h> 90bbfda8aSnia#include <stdlib.h> 100bbfda8aSnia 110bbfda8aSnia#include <X11/Xatom.h> 120bbfda8aSnia 130bbfda8aSnia#include "ctwm_atoms.h" 140bbfda8aSnia#include "util.h" 150bbfda8aSnia#include "animate.h" 160bbfda8aSnia#include "screen.h" 170bbfda8aSnia#include "add_window.h" 180bbfda8aSnia#include "events.h" 190bbfda8aSnia#include "otp.h" 200bbfda8aSnia#include "cursor.h" 210bbfda8aSnia#include "image.h" 220bbfda8aSnia#include "drawing.h" 230bbfda8aSnia#include "list.h" 240bbfda8aSnia#include "occupation.h" 250bbfda8aSnia#include "vscreen.h" 260bbfda8aSnia#include "win_decorations.h" 270bbfda8aSnia#include "win_iconify.h" 280bbfda8aSnia#include "win_ops.h" 290bbfda8aSnia#include "win_utils.h" 300bbfda8aSnia#include "workspace_manager.h" 310bbfda8aSnia#include "workspace_utils.h" 32b18c2d1eSnia#include "xparsegeometry.h" 33b18c2d1eSnia 340bbfda8aSnia 350bbfda8aSnia#include "gram.tab.h" 360bbfda8aSnia 370bbfda8aSnia 380bbfda8aSnia// Temp; x-ref desc in workspace_utils 390bbfda8aSniaextern bool useBackgroundInfo; 400bbfda8aSnia 410bbfda8aSnia 420bbfda8aSniastatic void CreateWorkSpaceManagerWindow(VirtualScreen *vs); 430bbfda8aSniastatic void ResizeWorkSpaceManager(VirtualScreen *vs, TwmWindow *win); 440bbfda8aSniastatic void PaintWorkSpaceManagerBorder(VirtualScreen *vs); 450bbfda8aSnia 460bbfda8aSniastatic void wmap_mapwin_backend(TwmWindow *win, bool handleraise); 470bbfda8aSnia 480bbfda8aSniastatic void WMapRedrawWindow(Window window, int width, int height, 490bbfda8aSnia ColorPair cp, const char *label); 500bbfda8aSnia 510bbfda8aSniastatic void InvertColorPair(ColorPair *cp); 520bbfda8aSnia 530bbfda8aSnia 540bbfda8aSniastatic XContext MapWListContext = None; 550bbfda8aSniastatic Cursor handCursor = None; 560bbfda8aSnia 570bbfda8aSnia 580bbfda8aSnia 590bbfda8aSnia/* 600bbfda8aSnia **************************************************************** 610bbfda8aSnia * 620bbfda8aSnia * First, functions related to general creation and drawing of the WSM 630bbfda8aSnia * window and its backing structs 640bbfda8aSnia * 650bbfda8aSnia **************************************************************** 660bbfda8aSnia */ 670bbfda8aSnia 680bbfda8aSnia/* 690bbfda8aSnia * Allocate an X Context for WSM stuff. 700bbfda8aSnia */ 710bbfda8aSniavoid 720bbfda8aSniaInitWorkSpaceManagerContext(void) 730bbfda8aSnia{ 740bbfda8aSnia if(MapWListContext == None) { 750bbfda8aSnia MapWListContext = XUniqueContext(); 760bbfda8aSnia } 770bbfda8aSnia} 780bbfda8aSnia 790bbfda8aSnia 80b18c2d1eSnia/** 810bbfda8aSnia * Prep up structures for WSM windows in each VS. Called (for each 82b18c2d1eSnia * Screen) in startup after InitVirtualScreens() has setup the VS stuff 83b18c2d1eSnia * (and after config file processing). This also retrieves info for each 84b18c2d1eSnia * vs about which workspace is active, if available (from restarting 85b18c2d1eSnia * ourself, etc). 86b18c2d1eSnia * 87b18c2d1eSnia * XXX Passed param isn't quite complete, as we call some funcs that use 88b18c2d1eSnia * global Scr... 890bbfda8aSnia */ 900bbfda8aSniavoid 91b18c2d1eSniaConfigureWorkSpaceManager(ScreenInfo *scr) 920bbfda8aSnia{ 93b18c2d1eSnia WorkSpace *ws = Scr->workSpaceMgr.workSpaceList; 94b18c2d1eSnia char *vsmapbuf, *vsmap; 95b18c2d1eSnia 96b18c2d1eSnia // Get the workspace name that's up on this vscreen. This is 97b18c2d1eSnia // where the startup process actually sets what workspace we're 98b18c2d1eSnia // [re]starting in. 99b18c2d1eSnia vsmapbuf = CtwmGetVScreenMap(dpy, Scr->Root); 100b18c2d1eSnia if(vsmapbuf != NULL) { 101b18c2d1eSnia // Property is a comma-separate list of the workspaces for 102b18c2d1eSnia // each vscreen, in magic order. So we start by chopping off 103b18c2d1eSnia // the first and then re-chop in the loop below. 104b18c2d1eSnia vsmap = strtok(vsmapbuf, ","); 105b18c2d1eSnia } 106b18c2d1eSnia else { 107b18c2d1eSnia vsmap = NULL; 108b18c2d1eSnia } 109b18c2d1eSnia 110b18c2d1eSnia 111b18c2d1eSnia // Setup each vs 112b18c2d1eSnia for(VirtualScreen *vs = scr->vScreenList; vs != NULL; vs = vs->next) { 113b18c2d1eSnia WorkSpace *fws; 1140bbfda8aSnia 1150bbfda8aSnia /* 1160bbfda8aSnia * Make sure this is all properly initialized to nothing. Otherwise 1170bbfda8aSnia * bad and undefined behavior can show up in certain cases (e.g., 1180bbfda8aSnia * with no Workspaces {} defined in .ctwmrc, the only defined 1190bbfda8aSnia * workspace will be random memory bytes, which can causes crashes on 1200bbfda8aSnia * e.g. f.menu "TwmWindows".) 1210bbfda8aSnia */ 1220bbfda8aSnia WorkSpaceWindow *wsw = calloc(1, sizeof(WorkSpaceWindow)); 123b18c2d1eSnia wsw->state = scr->workSpaceMgr.initialstate; 124b18c2d1eSnia 125b18c2d1eSnia // If we have a current ws for this vs, assign it in, and 126b18c2d1eSnia // loop onward to the ws for the next vs. For any we don't 127b18c2d1eSnia // have a default for, the default ws is the first one we haven't 128b18c2d1eSnia // used yet. 129b18c2d1eSnia if((fws = GetWorkspace(vsmap)) != NULL) { 130b18c2d1eSnia wsw->currentwspc = fws; 131b18c2d1eSnia vsmap = strtok(NULL, ","); 132b18c2d1eSnia } 133b18c2d1eSnia else { 134b18c2d1eSnia wsw->currentwspc = ws; 135b18c2d1eSnia if(ws) { 136b18c2d1eSnia ws = ws->next; 137b18c2d1eSnia } 138b18c2d1eSnia } 139b18c2d1eSnia 1400bbfda8aSnia vs->wsw = wsw; 1410bbfda8aSnia } 142b18c2d1eSnia 143b18c2d1eSnia free(vsmapbuf); 1440bbfda8aSnia} 1450bbfda8aSnia 1460bbfda8aSnia 147b18c2d1eSnia 148b18c2d1eSnia 1490bbfda8aSnia/* 1500bbfda8aSnia * Create workspace manager windows for each vscreen. Called (for each 1510bbfda8aSnia * screen) late in startup, after the preceeding funcs have run their 1520bbfda8aSnia * course. 1530bbfda8aSnia */ 1540bbfda8aSniavoid 1550bbfda8aSniaCreateWorkSpaceManager(void) 1560bbfda8aSnia{ 1570bbfda8aSnia if(! Scr->workSpaceManagerActive) { 1580bbfda8aSnia return; 1590bbfda8aSnia } 1600bbfda8aSnia 1610bbfda8aSnia /* Setup basic fonts/colors/cursors */ 1620bbfda8aSnia Scr->workSpaceMgr.windowFont.basename = 1630bbfda8aSnia "-adobe-courier-medium-r-normal--10-100-75-75-m-60-iso8859-1"; 1640bbfda8aSnia Scr->workSpaceMgr.buttonFont = Scr->IconManagerFont; 1650bbfda8aSnia Scr->workSpaceMgr.cp = Scr->IconManagerC; 1660bbfda8aSnia if(!Scr->BeNiceToColormap) { 1670bbfda8aSnia GetShadeColors(&Scr->workSpaceMgr.cp); 1680bbfda8aSnia } 1690bbfda8aSnia if(handCursor == None) { 1700bbfda8aSnia NewFontCursor(&handCursor, "top_left_arrow"); 1710bbfda8aSnia } 1720bbfda8aSnia 1730bbfda8aSnia 1740bbfda8aSnia /* 1750bbfda8aSnia * Create a WSM window for each vscreen. We don't need one for each 1760bbfda8aSnia * workspace (we just reuse the same one), but we do need one for 1770bbfda8aSnia * each vscreen (since they have to be displayed simultaneously). 1780bbfda8aSnia */ 179b18c2d1eSnia for(VirtualScreen *vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 180b18c2d1eSnia CreateWorkSpaceManagerWindow(vs); 1810bbfda8aSnia } 1820bbfda8aSnia 1830bbfda8aSnia 1840bbfda8aSnia /* 1850bbfda8aSnia * Init background in the WSM workspace subwindow and potentially the 1860bbfda8aSnia * root window to the settings for the active workspace 1870bbfda8aSnia * 1880bbfda8aSnia * XXX CTAG_BGDRAW This process is also done in similar fashion 1890bbfda8aSnia * during CreateWorkSpaceManagerWindow(), and the two parts are done 1900bbfda8aSnia * split well apart during GotoWorkSpace(). The details of the 1910bbfda8aSnia * process should be factored out into helper functions instead of 1920bbfda8aSnia * being reimplemented in each place. That will require a little 1930bbfda8aSnia * shuffling of code, and careful thinking on the apparent 1940bbfda8aSnia * differences (which seem like they may be cosmetic). Todo. 1950bbfda8aSnia */ 1960bbfda8aSnia for(VirtualScreen *vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 1970bbfda8aSnia WorkSpaceWindow *wsw = vs->wsw; // Our WSW 1980bbfda8aSnia WorkSpace *ws2 = wsw->currentwspc; // Active WS 1990bbfda8aSnia MapSubwindow *msw = wsw->mswl[ws2->number]; // Active WS's subwin 2000bbfda8aSnia 2010bbfda8aSnia /* Setup the background/border on the active workspace */ 2020bbfda8aSnia if(Scr->workSpaceMgr.curImage == NULL) { 2030bbfda8aSnia if(Scr->workSpaceMgr.curPaint) { 2040bbfda8aSnia XSetWindowBackground(dpy, msw->w, Scr->workSpaceMgr.curColors.back); 2050bbfda8aSnia } 2060bbfda8aSnia } 2070bbfda8aSnia else { 2080bbfda8aSnia XSetWindowBackgroundPixmap(dpy, msw->w, Scr->workSpaceMgr.curImage->pixmap); 2090bbfda8aSnia } 2100bbfda8aSnia XSetWindowBorder(dpy, msw->w, Scr->workSpaceMgr.curBorderColor); 2110bbfda8aSnia XClearWindow(dpy, msw->w); 2120bbfda8aSnia 2130bbfda8aSnia /* Set the root window to the color/image of that WS if we should */ 2140bbfda8aSnia if(useBackgroundInfo && ! Scr->DontPaintRootWindow) { 2150bbfda8aSnia if(ws2->image == NULL) { 2160bbfda8aSnia XSetWindowBackground(dpy, vs->window, ws2->backcp.back); 2170bbfda8aSnia } 2180bbfda8aSnia else { 2190bbfda8aSnia XSetWindowBackgroundPixmap(dpy, vs->window, ws2->image->pixmap); 2200bbfda8aSnia } 2210bbfda8aSnia XClearWindow(dpy, vs->window); 2220bbfda8aSnia } 2230bbfda8aSnia } 2240bbfda8aSnia 2250bbfda8aSnia 2260bbfda8aSnia /* 2270bbfda8aSnia * Set the property we use to store the full list of workspaces. 2280bbfda8aSnia * 2290bbfda8aSnia * XXX This isn't really part of creating the WSM windows, so doesn't 2300bbfda8aSnia * strictly belong here. It does need to happen after the config 2310bbfda8aSnia * file parsing setup the workspaces, so couldn't go into 2320bbfda8aSnia * InitWorkSpaceManager(). It could probably move into 2330bbfda8aSnia * ConfigureWorkSpaceManager() though, or could move into a separate 2340bbfda8aSnia * hypotehtical ConfigureWorkSpaces() sort of thing... 2350bbfda8aSnia */ 2360bbfda8aSnia { 2370bbfda8aSnia char *wrkSpcList; 2380bbfda8aSnia int len; 2390bbfda8aSnia 2400bbfda8aSnia len = GetPropertyFromMask(0xFFFFFFFFu, &wrkSpcList); 2410bbfda8aSnia XChangeProperty(dpy, Scr->Root, XA_WM_WORKSPACESLIST, XA_STRING, 8, 2420bbfda8aSnia PropModeReplace, (unsigned char *) wrkSpcList, len); 2430bbfda8aSnia free(wrkSpcList); 2440bbfda8aSnia } 2450bbfda8aSnia} 2460bbfda8aSnia 2470bbfda8aSnia 2480bbfda8aSnia/* 2490bbfda8aSnia * Put together the actual window for the workspace manager. Called as 2500bbfda8aSnia * part of CreateWorkSpaceManager() during startup, once per vscreen 2510bbfda8aSnia * (since there's a separate window for each). 2520bbfda8aSnia */ 2530bbfda8aSniastatic void 2540bbfda8aSniaCreateWorkSpaceManagerWindow(VirtualScreen *vs) 2550bbfda8aSnia{ 2560bbfda8aSnia unsigned int width, height; 2570bbfda8aSnia TwmWindow *tmp_win; 2580bbfda8aSnia int x, y, gravity; 2590bbfda8aSnia /* Shortcuts */ 2600bbfda8aSnia const int vspace = Scr->workSpaceMgr.vspace; 2610bbfda8aSnia const int hspace = Scr->workSpaceMgr.hspace; 2620bbfda8aSnia const long count = Scr->workSpaceMgr.count; 2630bbfda8aSnia 2640bbfda8aSnia /* No workspaces? Nothing to do. */ 2650bbfda8aSnia if(count == 0) { 2660bbfda8aSnia return; 2670bbfda8aSnia } 2680bbfda8aSnia 2690bbfda8aSnia /* 2700bbfda8aSnia * Work out grid. wSM.columns will be filled if specified in 2710bbfda8aSnia * WorkSpaceManageGeometry, or uninitialized (0) if not. 2720bbfda8aSnia */ 2730bbfda8aSnia { 2740bbfda8aSnia int lines, columns; 2750bbfda8aSnia columns = Scr->workSpaceMgr.columns; 2760bbfda8aSnia if(columns == 0) { 2770bbfda8aSnia lines = 2; 2780bbfda8aSnia columns = ((count - 1) / lines) + 1; 2790bbfda8aSnia } 2800bbfda8aSnia else { 2810bbfda8aSnia lines = ((count - 1) / columns) + 1; 2820bbfda8aSnia } 2830bbfda8aSnia Scr->workSpaceMgr.lines = lines; 2840bbfda8aSnia Scr->workSpaceMgr.columns = columns; 2850bbfda8aSnia } 2860bbfda8aSnia 2870bbfda8aSnia 2880bbfda8aSnia /* Work out dimensions of stuff */ 2890bbfda8aSnia { 2900bbfda8aSnia unsigned int bwidth, bheight; 2910bbfda8aSnia unsigned short strWid; 2920bbfda8aSnia WorkSpace *ws; 2930bbfda8aSnia const char *geometry = Scr->workSpaceMgr.geometry; 2940bbfda8aSnia const int lines = Scr->workSpaceMgr.lines; 2950bbfda8aSnia const int columns = Scr->workSpaceMgr.columns; 2960bbfda8aSnia 2970bbfda8aSnia /* Figure longest label */ 2980bbfda8aSnia strWid = 0; 2990bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 3000bbfda8aSnia XRectangle inc_rect; 3010bbfda8aSnia XRectangle logical_rect; 3020bbfda8aSnia unsigned short wid; 3030bbfda8aSnia const MyFont font = Scr->workSpaceMgr.buttonFont; 3040bbfda8aSnia 3050bbfda8aSnia XmbTextExtents(font.font_set, ws->label, strlen(ws->label), 3060bbfda8aSnia &inc_rect, &logical_rect); 3070bbfda8aSnia wid = logical_rect.width; 3080bbfda8aSnia if(wid > strWid) { 3090bbfda8aSnia strWid = wid; 3100bbfda8aSnia } 3110bbfda8aSnia } 3120bbfda8aSnia 3130bbfda8aSnia /* 3140bbfda8aSnia * If WorkSpaceManagerGeometry is given, work from that. Else, 3150bbfda8aSnia * create a workable minimum ourselves. 3160bbfda8aSnia * */ 3170bbfda8aSnia if(geometry != NULL) { 3180bbfda8aSnia int mask; 3190bbfda8aSnia 3200bbfda8aSnia /* Base button/subwindow sizes */ 3210bbfda8aSnia bwidth = strWid + 10; 3220bbfda8aSnia bheight = 22; 3230bbfda8aSnia 3240bbfda8aSnia /* Adjust to WSMGeometry if specified */ 325b18c2d1eSnia mask = RLayoutXParseGeometry(Scr->Layout, geometry, &x, &y, &width, &height); 3260bbfda8aSnia if(mask & WidthValue) { 3270bbfda8aSnia bwidth = (width - (columns * hspace)) / columns; 3280bbfda8aSnia } 3290bbfda8aSnia if(mask & HeightValue) { 3300bbfda8aSnia bheight = (height - (lines * vspace)) / lines; 3310bbfda8aSnia } 3320bbfda8aSnia 3330bbfda8aSnia /* Size of the whole thing is based off those */ 3340bbfda8aSnia width = columns * (bwidth + hspace); 3350bbfda8aSnia height = lines * (bheight + vspace); 3360bbfda8aSnia 3370bbfda8aSnia /* 3380bbfda8aSnia * If no Y given, put it at the bottom of the screen. If one 3390bbfda8aSnia * is, just accept it. If it's a negative, we have to figure 3400bbfda8aSnia * out where that actually is on this vscreen. 3410bbfda8aSnia */ 3420bbfda8aSnia if(!(mask & YValue)) { 3430bbfda8aSnia y = 0; 3440bbfda8aSnia mask |= YNegative; 3450bbfda8aSnia } 3460bbfda8aSnia if(mask & YNegative) { 3470bbfda8aSnia y += vs->h - height; 3480bbfda8aSnia } 3490bbfda8aSnia 3500bbfda8aSnia /* 3510bbfda8aSnia * If X is given, tweak as necessary for the vscreen 3520bbfda8aSnia * location. Otherwise, put it in in something like the 3530bbfda8aSnia * middle. 3540bbfda8aSnia */ 3550bbfda8aSnia if(mask & XValue) { 3560bbfda8aSnia if(mask & XNegative) { 3570bbfda8aSnia x += vs->w - width; 3580bbfda8aSnia gravity = (mask & YNegative) ? SouthEastGravity : NorthEastGravity; 3590bbfda8aSnia } 3600bbfda8aSnia else { 3610bbfda8aSnia gravity = (mask & YNegative) ? SouthWestGravity : NorthWestGravity; 3620bbfda8aSnia } 3630bbfda8aSnia } 3640bbfda8aSnia else { 3650bbfda8aSnia x = (vs->w - width) / 2; 3660bbfda8aSnia gravity = (mask & YValue) ? ((mask & YNegative) ? 3670bbfda8aSnia SouthGravity : NorthGravity) : SouthGravity; 3680bbfda8aSnia } 3690bbfda8aSnia } 3700bbfda8aSnia else { 3710bbfda8aSnia /* No geom specified, come up with one */ 3720bbfda8aSnia bwidth = strWid + 2 * Scr->WMgrButtonShadowDepth + 6; 3730bbfda8aSnia bheight = 22; 3740bbfda8aSnia width = columns * (bwidth + hspace); 3750bbfda8aSnia height = lines * (bheight + vspace); 3760bbfda8aSnia x = (vs->w - width) / 2; 3770bbfda8aSnia y = vs->h - height; 3780bbfda8aSnia gravity = NorthWestGravity; 3790bbfda8aSnia } 3800bbfda8aSnia } 3810bbfda8aSnia 3820bbfda8aSnia /* Set w/h to dummy values; ResizeWorkSpaceManager() writes real ones */ 3830bbfda8aSnia vs->wsw->width = 1; 3840bbfda8aSnia vs->wsw->height = 1; 3850bbfda8aSnia 3860bbfda8aSnia /* Allocate structs for map/button subwindows */ 3870bbfda8aSnia vs->wsw->bswl = calloc(count, sizeof(ButtonSubwindow *)); 3880bbfda8aSnia vs->wsw->mswl = calloc(count, sizeof(MapSubwindow *)); 3890bbfda8aSnia 3900bbfda8aSnia /* Create main window */ 3910bbfda8aSnia vs->wsw->w = XCreateSimpleWindow(dpy, Scr->Root, x, y, width, height, 0, 3920bbfda8aSnia Scr->Black, Scr->workSpaceMgr.cp.back); 3930bbfda8aSnia 3940bbfda8aSnia 3950bbfda8aSnia /* 3960bbfda8aSnia * Create the map and button subwindows for each workspace 3970bbfda8aSnia */ 3980bbfda8aSnia { 3990bbfda8aSnia WorkSpace *ws; 4000bbfda8aSnia 4010bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 4020bbfda8aSnia MapSubwindow *msw; 4030bbfda8aSnia ButtonSubwindow *bsw; 4040bbfda8aSnia const int Dummy = 1; 4050bbfda8aSnia const unsigned long border = Scr->workSpaceMgr.defBorderColor; 4060bbfda8aSnia 4070bbfda8aSnia /* Alloc structs */ 4080bbfda8aSnia vs->wsw->bswl[ws->number] = bsw 4090bbfda8aSnia = calloc(1, sizeof(ButtonSubwindow)); 4100bbfda8aSnia vs->wsw->mswl[ws->number] = msw = calloc(1, sizeof(MapSubwindow)); 4110bbfda8aSnia 4120bbfda8aSnia /* 4130bbfda8aSnia * Create windows for button/map. ResizeWorkSpaceManager() 4140bbfda8aSnia * sets the real sizes and positions, so we dummy 'em. 4150bbfda8aSnia */ 4160bbfda8aSnia bsw->w = XCreateSimpleWindow(dpy, vs->wsw->w, 4170bbfda8aSnia Dummy, Dummy, Dummy, Dummy, 4180bbfda8aSnia 0, Scr->Black, ws->cp.back); 4190bbfda8aSnia 4200bbfda8aSnia msw->w = XCreateSimpleWindow(dpy, vs->wsw->w, 4210bbfda8aSnia Dummy, Dummy, Dummy, Dummy, 4220bbfda8aSnia 1, border, ws->cp.back); 4230bbfda8aSnia 4240bbfda8aSnia /* Map whichever is up by default */ 4250bbfda8aSnia if(vs->wsw->state == WMS_buttons) { 4260bbfda8aSnia XMapWindow(dpy, bsw->w); 4270bbfda8aSnia } 4280bbfda8aSnia else { 4290bbfda8aSnia XMapWindow(dpy, msw->w); 4300bbfda8aSnia } 4310bbfda8aSnia 4320bbfda8aSnia /* Setup background on map-state window */ 4330bbfda8aSnia /* XXX X-ref CTAG_BGDRAW in CreateWorkSpaceManager() */ 4340bbfda8aSnia if(useBackgroundInfo) { 4350bbfda8aSnia if(ws->image == NULL || Scr->NoImagesInWorkSpaceManager) { 4360bbfda8aSnia XSetWindowBackground(dpy, msw->w, ws->backcp.back); 4370bbfda8aSnia } 4380bbfda8aSnia else { 4390bbfda8aSnia XSetWindowBackgroundPixmap(dpy, msw->w, ws->image->pixmap); 4400bbfda8aSnia } 4410bbfda8aSnia } 4420bbfda8aSnia else { 4430bbfda8aSnia if(Scr->workSpaceMgr.defImage == NULL || Scr->NoImagesInWorkSpaceManager) { 4440bbfda8aSnia XSetWindowBackground(dpy, msw->w, Scr->workSpaceMgr.defColors.back); 4450bbfda8aSnia } 4460bbfda8aSnia else { 4470bbfda8aSnia XSetWindowBackgroundPixmap(dpy, msw->w, Scr->workSpaceMgr.defImage->pixmap); 4480bbfda8aSnia } 4490bbfda8aSnia } 4500bbfda8aSnia 4510bbfda8aSnia /* 4520bbfda8aSnia * Clear out button subwin; PaintWorkSpaceManager() fills it 4530bbfda8aSnia * in. Is this really necessary? 4540bbfda8aSnia */ 4550bbfda8aSnia XClearWindow(dpy, bsw->w); 4560bbfda8aSnia } 4570bbfda8aSnia } 4580bbfda8aSnia 4590bbfda8aSnia 4600bbfda8aSnia /* Set WM properties */ 4610bbfda8aSnia { 4620bbfda8aSnia XSizeHints sizehints; 4630bbfda8aSnia XWMHints wmhints; 4640bbfda8aSnia const int lines = Scr->workSpaceMgr.lines; 4650bbfda8aSnia const int columns = Scr->workSpaceMgr.columns; 4660bbfda8aSnia const char *name = Scr->workSpaceMgr.name; 4670bbfda8aSnia const char *icon_name = Scr->workSpaceMgr.icon_name; 4680bbfda8aSnia 4690bbfda8aSnia sizehints.flags = USPosition | PBaseSize | PMinSize | PResizeInc 4700bbfda8aSnia | PWinGravity; 4710bbfda8aSnia sizehints.x = x; 4720bbfda8aSnia sizehints.y = y; 4730bbfda8aSnia sizehints.base_width = columns * hspace; 4740bbfda8aSnia sizehints.base_height = lines * vspace; 4750bbfda8aSnia sizehints.width_inc = columns; 4760bbfda8aSnia sizehints.height_inc = lines; 4770bbfda8aSnia sizehints.min_width = columns * (hspace + 2); 4780bbfda8aSnia sizehints.min_height = lines * (vspace + 2); 4790bbfda8aSnia sizehints.win_gravity = gravity; 4800bbfda8aSnia 4810bbfda8aSnia wmhints.flags = InputHint | StateHint; 4820bbfda8aSnia wmhints.input = True; 4830bbfda8aSnia wmhints.initial_state = NormalState; 4840bbfda8aSnia 4850bbfda8aSnia XmbSetWMProperties(dpy, vs->wsw->w, name, icon_name, NULL, 0, 4860bbfda8aSnia &sizehints, &wmhints, NULL); 4870bbfda8aSnia } 4880bbfda8aSnia 4890bbfda8aSnia 4900bbfda8aSnia /* Create our TwmWindow wrapping around it */ 4910bbfda8aSnia tmp_win = AddWindow(vs->wsw->w, AWT_WORKSPACE_MANAGER, 4920bbfda8aSnia Scr->iconmgr, vs); 4930bbfda8aSnia if(! tmp_win) { 4940bbfda8aSnia fprintf(stderr, "cannot create workspace manager window, exiting...\n"); 4950bbfda8aSnia exit(1); 4960bbfda8aSnia } 4970bbfda8aSnia tmp_win->occupation = fullOccupation; 4980bbfda8aSnia tmp_win->attr.width = width; 4990bbfda8aSnia tmp_win->attr.height = height; 5000bbfda8aSnia vs->wsw->twm_win = tmp_win; 5010bbfda8aSnia 5020bbfda8aSnia 5030bbfda8aSnia /* Do the figuring to size and internal-layout it */ 5040bbfda8aSnia ResizeWorkSpaceManager(vs, tmp_win); 5050bbfda8aSnia 5060bbfda8aSnia 5070bbfda8aSnia /* Setup cursor/gravity and listen for events */ 5080bbfda8aSnia { 5090bbfda8aSnia XWindowAttributes wattr; 5100bbfda8aSnia XSetWindowAttributes attr; 5110bbfda8aSnia unsigned long attrmask; 5120bbfda8aSnia 5130bbfda8aSnia attr.cursor = Scr->ButtonCursor; 5140bbfda8aSnia attr.win_gravity = gravity; 5150bbfda8aSnia attrmask = CWCursor | CWWinGravity; 5160bbfda8aSnia XChangeWindowAttributes(dpy, vs->wsw->w, attrmask, &attr); 5170bbfda8aSnia 5180bbfda8aSnia XGetWindowAttributes(dpy, vs->wsw->w, &wattr); 5190bbfda8aSnia attrmask = wattr.your_event_mask | KeyPressMask | KeyReleaseMask 5200bbfda8aSnia | ExposureMask; 5210bbfda8aSnia XSelectInput(dpy, vs->wsw->w, attrmask); 5220bbfda8aSnia } 5230bbfda8aSnia 5240bbfda8aSnia 5250bbfda8aSnia /* 5260bbfda8aSnia * Mark the buttons as listening to click and exposure events, and 5270bbfda8aSnia * stash away some pointers in contexts. We stash the overall WSM 5280bbfda8aSnia * window in TwmContext, which means that when an event looks up the 5290bbfda8aSnia * window, it finds the WSM rather than the subwindow, and then falls 5300bbfda8aSnia * into the WMgrHandle*Event()'s, which then dig down into the event 5310bbfda8aSnia * to find where it happened in there. 5320bbfda8aSnia * 5330bbfda8aSnia * The map window doesn't listen to expose events; it's just empty 5340bbfda8aSnia * and background colored. The individual subwindows in the map 5350bbfda8aSnia * listen for exposes for drawing themselves. 5360bbfda8aSnia * 5370bbfda8aSnia * Dragging windows around to move or re-occupy in the map window 5380bbfda8aSnia * does rely on motion events, but we don't listen for them here. 5390bbfda8aSnia * That happens in WMgrHandleButtonEvent() after getting the initial 5400bbfda8aSnia * click. It changes the listen and runs through the action 5410bbfda8aSnia * internally; those motions never run through our main event loop. 5420bbfda8aSnia */ 5430bbfda8aSnia for(WorkSpace *ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; 5440bbfda8aSnia ws = ws->next) { 5450bbfda8aSnia Window buttonw = vs->wsw->bswl[ws->number]->w; 5460bbfda8aSnia Window mapsubw = vs->wsw->mswl[ws->number]->w; 5470bbfda8aSnia 5480bbfda8aSnia XSelectInput(dpy, buttonw, ButtonPressMask | ButtonReleaseMask 5490bbfda8aSnia | ExposureMask); 5500bbfda8aSnia XSaveContext(dpy, buttonw, TwmContext, (XPointer) tmp_win); 5510bbfda8aSnia XSaveContext(dpy, buttonw, ScreenContext, (XPointer) Scr); 5520bbfda8aSnia 5530bbfda8aSnia XSelectInput(dpy, mapsubw, ButtonPressMask | ButtonReleaseMask); 5540bbfda8aSnia XSaveContext(dpy, mapsubw, TwmContext, (XPointer) tmp_win); 5550bbfda8aSnia XSaveContext(dpy, mapsubw, ScreenContext, (XPointer) Scr); 5560bbfda8aSnia } 5570bbfda8aSnia 5580bbfda8aSnia 5590bbfda8aSnia /* Set WM_STATE prop */ 5600bbfda8aSnia SetMapStateProp(tmp_win, WithdrawnState); 5610bbfda8aSnia 5620bbfda8aSnia 5630bbfda8aSnia /* Setup root window if necessary */ 5640bbfda8aSnia /* XXX X-ref CTAG_BGDRAW in CreateWorkSpaceManager() */ 5650bbfda8aSnia if(useBackgroundInfo && ! Scr->DontPaintRootWindow) { 5660bbfda8aSnia WorkSpace *ws = Scr->workSpaceMgr.workSpaceList; 5670bbfda8aSnia if(ws->image == NULL) { 5680bbfda8aSnia XSetWindowBackground(dpy, Scr->Root, ws->backcp.back); 5690bbfda8aSnia } 5700bbfda8aSnia else { 5710bbfda8aSnia XSetWindowBackgroundPixmap(dpy, Scr->Root, ws->image->pixmap); 5720bbfda8aSnia } 5730bbfda8aSnia XClearWindow(dpy, Scr->Root); 5740bbfda8aSnia } 5750bbfda8aSnia 5760bbfda8aSnia 5770bbfda8aSnia /* 5780bbfda8aSnia * Don't have to PaintWorkSpaceManager(vs) here, because 5790bbfda8aSnia * ResizeWorkSpaceManager() already called it for us. 5800bbfda8aSnia */ 5810bbfda8aSnia} 5820bbfda8aSnia 5830bbfda8aSnia 5840bbfda8aSnia/* 5850bbfda8aSnia * Size and layout a WSM. Mostly an internal bit in the process of 5860bbfda8aSnia * setting it up. 5870bbfda8aSnia */ 5880bbfda8aSniastatic void 5890bbfda8aSniaResizeWorkSpaceManager(VirtualScreen *vs, TwmWindow *win) 5900bbfda8aSnia{ 5910bbfda8aSnia WorkSpace *ws; 5920bbfda8aSnia int i, j; 5930bbfda8aSnia /* Lots of shortcuts to ease reading */ 5940bbfda8aSnia const int neww = win->attr.width; 5950bbfda8aSnia const int newh = win->attr.height; 5960bbfda8aSnia const int hspace = Scr->workSpaceMgr.hspace; 5970bbfda8aSnia const int vspace = Scr->workSpaceMgr.vspace; 5980bbfda8aSnia const int lines = Scr->workSpaceMgr.lines; 5990bbfda8aSnia const int columns = Scr->workSpaceMgr.columns; 6000bbfda8aSnia const int bwidth = (neww - (columns * hspace)) / columns; 6010bbfda8aSnia const int bheight = (newh - (lines * vspace)) / lines; 6020bbfda8aSnia const int wwidth = neww / columns; 6030bbfda8aSnia const int wheight = newh / lines; 6040bbfda8aSnia const float wf = (float)(wwidth - 2) / (float) vs->w; 6050bbfda8aSnia const float hf = (float)(wheight - 2) / (float) vs->h; 6060bbfda8aSnia 6070bbfda8aSnia /* If nothing's changed since our last run, there's nothing to change */ 6080bbfda8aSnia if(neww == vs->wsw->width && newh == vs->wsw->height) { 6090bbfda8aSnia return; 6100bbfda8aSnia } 6110bbfda8aSnia 6120bbfda8aSnia /* Set the new overall vals */ 6130bbfda8aSnia vs->wsw->bwidth = bwidth; 6140bbfda8aSnia vs->wsw->bheight = bheight; 6150bbfda8aSnia vs->wsw->width = neww; 6160bbfda8aSnia vs->wsw->height = newh; 6170bbfda8aSnia vs->wsw->wwidth = wwidth; 6180bbfda8aSnia vs->wsw->wheight = wheight; 6190bbfda8aSnia 6200bbfda8aSnia /* Iterate over the WS's */ 6210bbfda8aSnia i = 0; 6220bbfda8aSnia j = 0; 6230bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 6240bbfda8aSnia MapSubwindow *msw = vs->wsw->mswl[ws->number]; 6250bbfda8aSnia ButtonSubwindow *bsw = vs->wsw->bswl[ws->number]; 6260bbfda8aSnia 6270bbfda8aSnia /* Move button window to its place in the grid and size appropriately */ 6280bbfda8aSnia XMoveResizeWindow(dpy, bsw->w, 6290bbfda8aSnia i * (bwidth + hspace) + (hspace / 2), 6300bbfda8aSnia j * (bheight + vspace) + (vspace / 2), 6310bbfda8aSnia bwidth, bheight); 6320bbfda8aSnia 6330bbfda8aSnia /* Move the map window as well */ 6340bbfda8aSnia msw->x = i * wwidth; 6350bbfda8aSnia msw->y = j * wheight; 6360bbfda8aSnia XMoveResizeWindow(dpy, msw->w, msw->x, msw->y, wwidth - 2, wheight - 2); 6370bbfda8aSnia 6380bbfda8aSnia /* 6390bbfda8aSnia * Redo interior sizing and placement of all the windows in the 6400bbfda8aSnia * WS in the map window 6410bbfda8aSnia */ 6420bbfda8aSnia for(WinList *wl = msw->wl; wl != NULL; wl = wl->next) { 6430bbfda8aSnia TwmWindow *tmp_win = wl->twm_win; 6440bbfda8aSnia wl->x = (int)(tmp_win->frame_x * wf); 6450bbfda8aSnia wl->y = (int)(tmp_win->frame_y * hf); 6460bbfda8aSnia wl->width = (unsigned int)((tmp_win->frame_width * wf) + 0.5); 6470bbfda8aSnia wl->height = (unsigned int)((tmp_win->frame_height * hf) + 0.5); 6480bbfda8aSnia XMoveResizeWindow(dpy, wl->w, wl->x, wl->y, wl->width, wl->height); 6490bbfda8aSnia } 6500bbfda8aSnia 6510bbfda8aSnia /* And around to the next WS */ 6520bbfda8aSnia i++; 6530bbfda8aSnia if(i == columns) { 6540bbfda8aSnia i = 0; 6550bbfda8aSnia j++; 6560bbfda8aSnia }; 6570bbfda8aSnia } 6580bbfda8aSnia 6590bbfda8aSnia 6600bbfda8aSnia /* Draw it */ 6610bbfda8aSnia PaintWorkSpaceManager(vs); 6620bbfda8aSnia} 6630bbfda8aSnia 6640bbfda8aSnia 6650bbfda8aSnia/* 6660bbfda8aSnia * Draw up the button-state pieces of a WSM window. 6670bbfda8aSnia * 6680bbfda8aSnia * Note: this is currently stubbed out and does nothing. Historically 6690bbfda8aSnia * it's been called during startup when the WSM window is put together, 6700bbfda8aSnia * and when the screen is unmasked. However, the only apparent result is 6710bbfda8aSnia * that the border and buttons get drawn a little earlier; they already 6720bbfda8aSnia * get expose events that get picked up when we start the event loop. 6730bbfda8aSnia * 6740bbfda8aSnia * If we don't find any reason to reinstate it, we should remove this in 6750bbfda8aSnia * the future. 6760bbfda8aSnia */ 6770bbfda8aSniavoid 6780bbfda8aSniaPaintWorkSpaceManager(VirtualScreen *vs) 6790bbfda8aSnia{ 6800bbfda8aSnia WorkSpace *ws; 6810bbfda8aSnia 6820bbfda8aSnia /* x-ref header comment */ 6830bbfda8aSnia return; 6840bbfda8aSnia 6850bbfda8aSnia PaintWorkSpaceManagerBorder(vs); 6860bbfda8aSnia 6870bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 6880bbfda8aSnia Window buttonw = vs->wsw->bswl[ws->number]->w; 6890bbfda8aSnia ButtonState bs = (ws == vs->wsw->currentwspc) ? on : off; 6900bbfda8aSnia 6910bbfda8aSnia PaintWsButton(WSPCWINDOW, vs, buttonw, ws->label, ws->cp, bs); 6920bbfda8aSnia } 6930bbfda8aSnia} 6940bbfda8aSnia 6950bbfda8aSnia 6960bbfda8aSnia/* 6970bbfda8aSnia * Border around the WSM 6980bbfda8aSnia */ 6990bbfda8aSniastatic void 7000bbfda8aSniaPaintWorkSpaceManagerBorder(VirtualScreen *vs) 7010bbfda8aSnia{ 7020bbfda8aSnia int width, height; 7030bbfda8aSnia 7040bbfda8aSnia width = vs->wsw->width; 7050bbfda8aSnia height = vs->wsw->height; 7060bbfda8aSnia Draw3DBorder(vs->wsw->w, 0, 0, width, height, 2, Scr->workSpaceMgr.cp, off, 7070bbfda8aSnia true, false); 7080bbfda8aSnia} 7090bbfda8aSnia 7100bbfda8aSnia 7110bbfda8aSnia/* 7120bbfda8aSnia * Draw a workspace manager window on expose. X-ref comment on 7130bbfda8aSnia * PaintWorkSpaceManager(). 7140bbfda8aSnia */ 7150bbfda8aSniavoid 7160bbfda8aSniaWMgrHandleExposeEvent(VirtualScreen *vs, XEvent *event) 7170bbfda8aSnia{ 7180bbfda8aSnia if(vs->wsw->state == WMS_buttons) { 7190bbfda8aSnia Window buttonw; 7200bbfda8aSnia WorkSpace *ws; 7210bbfda8aSnia 7220bbfda8aSnia /* Find the button we're exposing */ 7230bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 7240bbfda8aSnia buttonw = vs->wsw->bswl[ws->number]->w; 7250bbfda8aSnia if(event->xexpose.window == buttonw) { 7260bbfda8aSnia break; 7270bbfda8aSnia } 7280bbfda8aSnia } 7290bbfda8aSnia 7300bbfda8aSnia /* If none, just paint the border. Else paint the button. */ 7310bbfda8aSnia if(ws == NULL) { 7320bbfda8aSnia PaintWorkSpaceManagerBorder(vs); 7330bbfda8aSnia } 7340bbfda8aSnia else { 7350bbfda8aSnia ButtonState bs = (ws == vs->wsw->currentwspc) ? on : off; 7360bbfda8aSnia PaintWsButton(WSPCWINDOW, vs, buttonw, ws->label, ws->cp, bs); 7370bbfda8aSnia } 7380bbfda8aSnia } 7390bbfda8aSnia else { 7400bbfda8aSnia WinList *wl; 7410bbfda8aSnia 7420bbfda8aSnia /* 7430bbfda8aSnia * This is presumably exposing some individual window in the WS 7440bbfda8aSnia * subwindow; find it from the stashed context on the window, and 7450bbfda8aSnia * redraw it. 7460bbfda8aSnia */ 7470bbfda8aSnia if(XFindContext(dpy, event->xexpose.window, MapWListContext, 7480bbfda8aSnia (XPointer *) &wl) == XCNOENT) { 7490bbfda8aSnia return; 7500bbfda8aSnia } 7510bbfda8aSnia if(wl && wl->twm_win && wl->twm_win->mapped) { 7520bbfda8aSnia WMapRedrawName(vs, wl); 7530bbfda8aSnia } 7540bbfda8aSnia } 7550bbfda8aSnia} 7560bbfda8aSnia 7570bbfda8aSnia 7580bbfda8aSnia 7590bbfda8aSnia/* 7600bbfda8aSnia * Moving the WSM between button and map state 7610bbfda8aSnia */ 7620bbfda8aSniavoid 7630bbfda8aSniaWMgrToggleState(VirtualScreen *vs) 7640bbfda8aSnia{ 7650bbfda8aSnia if(vs->wsw->state == WMS_buttons) { 7660bbfda8aSnia WMgrSetMapState(vs); 7670bbfda8aSnia } 7680bbfda8aSnia else { 7690bbfda8aSnia WMgrSetButtonsState(vs); 7700bbfda8aSnia } 7710bbfda8aSnia} 7720bbfda8aSnia 7730bbfda8aSniavoid 7740bbfda8aSniaWMgrSetMapState(VirtualScreen *vs) 7750bbfda8aSnia{ 7760bbfda8aSnia WorkSpace *ws; 7770bbfda8aSnia 7780bbfda8aSnia if(vs->wsw->state == WMS_map) { 7790bbfda8aSnia return; 7800bbfda8aSnia } 7810bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 7820bbfda8aSnia XUnmapWindow(dpy, vs->wsw->bswl [ws->number]->w); 7830bbfda8aSnia XMapWindow(dpy, vs->wsw->mswl [ws->number]->w); 7840bbfda8aSnia } 7850bbfda8aSnia vs->wsw->state = WMS_map; 7860bbfda8aSnia MaybeAnimate = true; 7870bbfda8aSnia} 7880bbfda8aSnia 7890bbfda8aSniavoid 7900bbfda8aSniaWMgrSetButtonsState(VirtualScreen *vs) 7910bbfda8aSnia{ 7920bbfda8aSnia WorkSpace *ws; 7930bbfda8aSnia 7940bbfda8aSnia if(vs->wsw->state == WMS_buttons) { 7950bbfda8aSnia return; 7960bbfda8aSnia } 7970bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 7980bbfda8aSnia XUnmapWindow(dpy, vs->wsw->mswl [ws->number]->w); 7990bbfda8aSnia XMapWindow(dpy, vs->wsw->bswl [ws->number]->w); 8000bbfda8aSnia } 8010bbfda8aSnia vs->wsw->state = WMS_buttons; 8020bbfda8aSnia} 8030bbfda8aSnia 8040bbfda8aSnia 8050bbfda8aSnia 8060bbfda8aSnia 8070bbfda8aSnia/* 8080bbfda8aSnia **************************************************************** 8090bbfda8aSnia * 8100bbfda8aSnia * Handlers for mouse/key actions in the WSM 8110bbfda8aSnia * 8120bbfda8aSnia **************************************************************** 8130bbfda8aSnia */ 8140bbfda8aSnia 8150bbfda8aSnia/* 8160bbfda8aSnia * Key press/release events in the WSM. A major use (and only for 8170bbfda8aSnia * release) is the Ctrl-key switching between map and button state. The 8180bbfda8aSnia * other use is on-the-fly renaming of workspaces by typing in the 8190bbfda8aSnia * button-state WSM. 8200bbfda8aSnia */ 8210bbfda8aSniavoid 8220bbfda8aSniaWMgrHandleKeyReleaseEvent(VirtualScreen *vs, XEvent *event) 8230bbfda8aSnia{ 8240bbfda8aSnia KeySym keysym; 8250bbfda8aSnia 8260bbfda8aSnia keysym = XLookupKeysym((XKeyEvent *) event, 0); 8270bbfda8aSnia if(! keysym) { 8280bbfda8aSnia return; 8290bbfda8aSnia } 8300bbfda8aSnia if(keysym == XK_Control_L || keysym == XK_Control_R) { 8310bbfda8aSnia /* DontToggleWorkSpaceManagerState added 20040607 by dl*/ 8320bbfda8aSnia if(!Scr->DontToggleWorkspaceManagerState) { 8330bbfda8aSnia WMgrToggleState(vs); 8340bbfda8aSnia } 8350bbfda8aSnia return; 8360bbfda8aSnia } 8370bbfda8aSnia} 8380bbfda8aSnia 8390bbfda8aSniavoid 8400bbfda8aSniaWMgrHandleKeyPressEvent(VirtualScreen *vs, XEvent *event) 8410bbfda8aSnia{ 8420bbfda8aSnia WorkSpace *ws; 8430bbfda8aSnia 8440bbfda8aSnia /* Check if we're using Control to toggle the state */ 8450bbfda8aSnia { 8460bbfda8aSnia KeySym keysym = XLookupKeysym((XKeyEvent *) event, 0); 8470bbfda8aSnia if(! keysym) { 8480bbfda8aSnia return; 8490bbfda8aSnia } 8500bbfda8aSnia if(keysym == XK_Control_L || keysym == XK_Control_R) { 8510bbfda8aSnia /* DontToggleWorkSpaceManagerState added 20040607 by dl*/ 8520bbfda8aSnia if(!Scr->DontToggleWorkspaceManagerState) { 8530bbfda8aSnia WMgrToggleState(vs); 8540bbfda8aSnia } 8550bbfda8aSnia return; 8560bbfda8aSnia } 8570bbfda8aSnia } 8580bbfda8aSnia 8590bbfda8aSnia /* Otherwise, key presses do nothing in map state */ 8600bbfda8aSnia if(vs->wsw->state == WMS_map) { 8610bbfda8aSnia return; 8620bbfda8aSnia } 8630bbfda8aSnia 8640bbfda8aSnia /* 8650bbfda8aSnia * If we're typing in a button-state WSM, and the mouse is on one of 8660bbfda8aSnia * the buttons, that means we're changing the name, so do that dance. 8670bbfda8aSnia */ 8680bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 8690bbfda8aSnia if(vs->wsw->bswl[ws->number]->w == event->xkey.subwindow) { 8700bbfda8aSnia break; 8710bbfda8aSnia } 8720bbfda8aSnia } 8730bbfda8aSnia if(ws == NULL) { 8740bbfda8aSnia /* Not on a button, nothing to do */ 8750bbfda8aSnia return; 8760bbfda8aSnia } 8770bbfda8aSnia 8780bbfda8aSnia 8790bbfda8aSnia /* 8800bbfda8aSnia * Edit the label. 8810bbfda8aSnia */ 8820bbfda8aSnia { 8830bbfda8aSnia int nkeys; 8840bbfda8aSnia char keys[16]; 8850bbfda8aSnia size_t nlen; 8860bbfda8aSnia char *newname; 8870bbfda8aSnia 8880bbfda8aSnia /* Look up what keystrokes are queued. Arbitrary buf size */ 8890bbfda8aSnia nkeys = XLookupString(&(event->xkey), keys, 16, NULL, NULL); 8900bbfda8aSnia 8910bbfda8aSnia /* Label length can't grow to more than cur+nkeys */ 8920bbfda8aSnia nlen = strlen(ws->label); 8930bbfda8aSnia newname = malloc(nlen + nkeys + 1); 8940bbfda8aSnia strcpy(newname, ws->label); 8950bbfda8aSnia 8960bbfda8aSnia /* Iterate over the passed keystrokes */ 8970bbfda8aSnia for(int i = 0 ; i < nkeys ; i++) { 8980bbfda8aSnia unsigned char k = keys[i]; 8990bbfda8aSnia 9000bbfda8aSnia if(isprint(k)) { 9010bbfda8aSnia /* Printable chars append to the string */ 9020bbfda8aSnia newname[nlen++] = k; 9030bbfda8aSnia } 9040bbfda8aSnia else if((k == 127) || (k == 8)) { 9050bbfda8aSnia /* 9060bbfda8aSnia * DEL or BS back up a char. 9070bbfda8aSnia * 9080bbfda8aSnia * XXX Would it be more generally correct to do this via 9090bbfda8aSnia * keysyms, in the face of changed keyboard mappings or 9100bbfda8aSnia * significantly differing locales? 9110bbfda8aSnia */ 9120bbfda8aSnia if(nlen != 0) { 9130bbfda8aSnia nlen--; 9140bbfda8aSnia } 9150bbfda8aSnia } 9160bbfda8aSnia else { 9170bbfda8aSnia /* Any other char stops the process dead */ 9180bbfda8aSnia break; 9190bbfda8aSnia } 9200bbfda8aSnia } 9210bbfda8aSnia /* Now ends where it ends */ 9220bbfda8aSnia newname[nlen] = '\0'; 9230bbfda8aSnia 9240bbfda8aSnia /* Swap it in */ 9250bbfda8aSnia free(ws->label); 9260bbfda8aSnia ws->label = newname; 9270bbfda8aSnia } 9280bbfda8aSnia 9290bbfda8aSnia 9300bbfda8aSnia /* Redraw the button with the new label */ 9310bbfda8aSnia { 9320bbfda8aSnia ButtonState bs = (ws == vs->wsw->currentwspc) ? on : off; 9330bbfda8aSnia 9340bbfda8aSnia PaintWsButton(WSPCWINDOW, vs, vs->wsw->bswl[ws->number]->w, ws->label, 9350bbfda8aSnia ws->cp, bs); 9360bbfda8aSnia } 9370bbfda8aSnia} 9380bbfda8aSnia 9390bbfda8aSnia 9400bbfda8aSnia/* 9410bbfda8aSnia * Mouse clicking in WSM. Gets called on button press (not release). In 9420bbfda8aSnia * the simple case, that's just switching workspaces. In the more 9430bbfda8aSnia * complex, it's changing window occupation in various different ways, or 9440bbfda8aSnia * even moving windows. When that's happening, it internally hijacks 9450bbfda8aSnia * button/motion/exposure events and implements them for the moving, with 9460bbfda8aSnia * magic escapes if it gets them for something else. Ew. 9470bbfda8aSnia */ 9480bbfda8aSniavoid 9490bbfda8aSniaWMgrHandleButtonEvent(VirtualScreen *vs, XEvent *event) 9500bbfda8aSnia{ 9510bbfda8aSnia WorkSpace *oldws, *newws; 9520bbfda8aSnia WinList *wl; 9530bbfda8aSnia TwmWindow *win; 9540bbfda8aSnia unsigned int W0, H0; 9550bbfda8aSnia XEvent lastev; 9560bbfda8aSnia Window w = 0; 9570bbfda8aSnia Position newX = 0, newY = 0, winX = 0, winY = 0; 9580bbfda8aSnia bool alreadyvivible, realmovemode; 9590bbfda8aSnia const WorkSpaceWindow *mw = vs->wsw; 9600bbfda8aSnia 9610bbfda8aSnia /* Shortcuts into the event */ 9620bbfda8aSnia const Window parent = event->xbutton.window; // Map/button for WS 9630bbfda8aSnia const Window sw = event->xbutton.subwindow; // Map mini-win 9640bbfda8aSnia const Time etime = event->xbutton.time; 9650bbfda8aSnia const unsigned int button = event->xbutton.button; 9660bbfda8aSnia const unsigned int modifier = event->xbutton.state; 9670bbfda8aSnia 9680bbfda8aSnia 9690bbfda8aSnia /* If we're in button state, we're just clicking to change */ 9700bbfda8aSnia if(vs->wsw->state == WMS_buttons) { 9710bbfda8aSnia WorkSpace *ws; 9720bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 9730bbfda8aSnia if(vs->wsw->bswl[ws->number]->w == parent) { 9740bbfda8aSnia GotoWorkSpace(vs, ws); 9750bbfda8aSnia break; 9760bbfda8aSnia } 9770bbfda8aSnia } 9780bbfda8aSnia return; 9790bbfda8aSnia } 9800bbfda8aSnia 9810bbfda8aSnia /* 9820bbfda8aSnia * If we get this far, we're in map state, where things are more 9830bbfda8aSnia * complicated. A simple click/release means change here too, but 9840bbfda8aSnia * there's also the possibility of dragging a subwindow around to 9850bbfda8aSnia * change its window's occupation. 9860bbfda8aSnia */ 9870bbfda8aSnia 9880bbfda8aSnia /* Find what workspace we're clicking in */ 9890bbfda8aSnia for(oldws = Scr->workSpaceMgr.workSpaceList ; oldws != NULL ; 9900bbfda8aSnia oldws = oldws->next) { 9910bbfda8aSnia if(vs->wsw->mswl[oldws->number]->w == parent) { 9920bbfda8aSnia break; 9930bbfda8aSnia } 9940bbfda8aSnia } 9950bbfda8aSnia if(oldws == NULL) { 9960bbfda8aSnia /* None? We're done here. */ 9970bbfda8aSnia return; 9980bbfda8aSnia } 9990bbfda8aSnia 10000bbfda8aSnia /* 10010bbfda8aSnia * If clicked in the workspace but outside a window, we can only be 10020bbfda8aSnia * switching workspaces. So just do that, and we're done. 10030bbfda8aSnia */ 10040bbfda8aSnia if(sw == (Window) 0) { 10050bbfda8aSnia GotoWorkSpace(vs, oldws); 10060bbfda8aSnia return; 10070bbfda8aSnia } 10080bbfda8aSnia 10090bbfda8aSnia /* Use the context to find the winlist entry for this window */ 10100bbfda8aSnia if(XFindContext(dpy, sw, MapWListContext, (XPointer *) &wl) == XCNOENT) { 10110bbfda8aSnia return; 10120bbfda8aSnia } 10130bbfda8aSnia win = wl->twm_win; 10140bbfda8aSnia 10150bbfda8aSnia /* 10160bbfda8aSnia * Sometimes we skip transients, so do so. XXX Should this 10170bbfda8aSnia * GotoWorkSpace()? 10180bbfda8aSnia */ 10190bbfda8aSnia if((! Scr->TransientHasOccupation) && win->istransient) { 10200bbfda8aSnia return; 10210bbfda8aSnia } 10220bbfda8aSnia 10230bbfda8aSnia /* 10240bbfda8aSnia * Are we trying to actually move the window, by moving its avatar in 10250bbfda8aSnia * the WSM? If ReallyMoveInWorkspaceManager is set, we're moving on 10260bbfda8aSnia * click, but not in shift-click. If it's not, it's the reverse. 10270bbfda8aSnia * 10280bbfda8aSnia * XXX This interacts really oddly and badly when you're also moving 10290bbfda8aSnia * the window from WS to WS. 10300bbfda8aSnia */ 10310bbfda8aSnia realmovemode = false; 10320bbfda8aSnia if(Scr->ReallyMoveInWorkspaceManager) { 10330bbfda8aSnia if(!(modifier & ShiftMask)) { 10340bbfda8aSnia realmovemode = true; 10350bbfda8aSnia } 10360bbfda8aSnia } 10370bbfda8aSnia else if(modifier & ShiftMask) { 10380bbfda8aSnia realmovemode = true; 10390bbfda8aSnia } 10400bbfda8aSnia 10410bbfda8aSnia /* 10420bbfda8aSnia * Frob screen-wide OpaqueMove as necessary for this window's 10430bbfda8aSnia * details. 10440bbfda8aSnia * XXX Really? 10450bbfda8aSnia */ 10460bbfda8aSnia if(win->OpaqueMove) { 10470bbfda8aSnia if(Scr->OpaqueMoveThreshold >= 200) { 10480bbfda8aSnia Scr->OpaqueMove = true; 10490bbfda8aSnia } 10500bbfda8aSnia else { 10510bbfda8aSnia const unsigned long winsz = win->frame_width * win->frame_height; 10520bbfda8aSnia const unsigned long scrsz = vs->w * vs->h; 10530bbfda8aSnia const float sf = Scr->OpaqueMoveThreshold / 100.0; 10540bbfda8aSnia if(winsz > (scrsz * sf)) { 10550bbfda8aSnia Scr->OpaqueMove = false; 10560bbfda8aSnia } 10570bbfda8aSnia else { 10580bbfda8aSnia Scr->OpaqueMove = true; 10590bbfda8aSnia } 10600bbfda8aSnia } 10610bbfda8aSnia } 10620bbfda8aSnia else { 10630bbfda8aSnia Scr->OpaqueMove = false; 10640bbfda8aSnia } 10650bbfda8aSnia 10660bbfda8aSnia /* 10670bbfda8aSnia * Buttons inside the workspace manager, when clicking on the 10680bbfda8aSnia * representation of a window: 10690bbfda8aSnia * 1: drag window to a different workspace 10700bbfda8aSnia * 2: drag a copy of the window to a different workspace 10710bbfda8aSnia * (show it in both workspaces) 10720bbfda8aSnia * 3: remove the window from this workspace (if it isn't the last). 10730bbfda8aSnia * 10740bbfda8aSnia * XXX If you move between workspaces while also doing realmovemode, 10750bbfda8aSnia * really messed up things happen. 10760bbfda8aSnia */ 10770bbfda8aSnia switch(button) { 10780bbfda8aSnia case 1 : { 10790bbfda8aSnia /* 10800bbfda8aSnia * Moving from one to another; get rid of the old location, 10810bbfda8aSnia * then fall through to the "duplicating" case below. 10820bbfda8aSnia */ 10830bbfda8aSnia XUnmapWindow(dpy, sw); 10840bbfda8aSnia /* FALLTHRU */ 10850bbfda8aSnia } 10860bbfda8aSnia 10870bbfda8aSnia case 2 : { 10880bbfda8aSnia /* 10890bbfda8aSnia * Duplicating window to another WS. We create a copy of the 10900bbfda8aSnia * window, and start moving that. The 'moving' case above 10910bbfda8aSnia * falls through to us after unmapping that old window, 10920bbfda8aSnia * leaving just our copy, which is good enough. This is 10930bbfda8aSnia * really just setting up the visual stuff for the move; the 10940bbfda8aSnia * actual occupation changes etc. come at the end of the 10950bbfda8aSnia * motion, much lower down. 10960bbfda8aSnia */ 10970bbfda8aSnia int X0, Y0, X1, Y1; 10980bbfda8aSnia unsigned int bw; 10990bbfda8aSnia XSetWindowAttributes attrs; 11000bbfda8aSnia Window junkW; 11010bbfda8aSnia 11020bbfda8aSnia /* [XYWH]0 = size/location of the avatar in the map */ 11030bbfda8aSnia XGetGeometry(dpy, sw, &junkW, &X0, &Y0, &W0, &H0, &bw, &JunkDepth); 11040bbfda8aSnia 11050bbfda8aSnia /* 11060bbfda8aSnia * [XY]0 are the coordinates of the avatar subwindow inside 11070bbfda8aSnia * the individual workspace window in the map. Turn those 11080bbfda8aSnia * into [XY]1 as the coordinates of it relative to the whole 11090bbfda8aSnia * WSM window. 11100bbfda8aSnia */ 11110bbfda8aSnia XTranslateCoordinates(dpy, vs->wsw->mswl[oldws->number]->w, 11120bbfda8aSnia mw->w, X0, Y0, &X1, &Y1, &junkW); 11130bbfda8aSnia 11140bbfda8aSnia /* 11150bbfda8aSnia * Create the copy window to drag around, as a child of the 11160bbfda8aSnia * whole WSM (so we can move it between workspaces), and map 11170bbfda8aSnia * it. 11180bbfda8aSnia */ 11190bbfda8aSnia attrs.event_mask = ExposureMask; 11200bbfda8aSnia attrs.background_pixel = wl->cp.back; 11210bbfda8aSnia attrs.border_pixel = wl->cp.back; 11220bbfda8aSnia w = XCreateWindow(dpy, mw->w, X1, Y1, W0, H0, bw, 11230bbfda8aSnia CopyFromParent, CopyFromParent, CopyFromParent, 11240bbfda8aSnia CWEventMask | CWBackPixel | CWBorderPixel, 11250bbfda8aSnia &attrs); 11260bbfda8aSnia XMapRaised(dpy, w); 11270bbfda8aSnia 11280bbfda8aSnia /* Do our dance on it to draw the name/color/etc */ 11290bbfda8aSnia WMapRedrawWindow(w, W0, H0, wl->cp, wl->twm_win->icon_name); 11300bbfda8aSnia 11310bbfda8aSnia /* 11320bbfda8aSnia * If we're moving the real window and 11330bbfda8aSnia * AlwaysShowWindowWhenMovingFromWorkspaceManager is set in 11340bbfda8aSnia * config, we need to be sure the real window is visible 11350bbfda8aSnia * while we move it. 11360bbfda8aSnia */ 11370bbfda8aSnia if(realmovemode && Scr->ShowWinWhenMovingInWmgr) { 11380bbfda8aSnia if(Scr->OpaqueMove) { 11390bbfda8aSnia DisplayWin(vs, win); 11400bbfda8aSnia } 11410bbfda8aSnia else { 11420bbfda8aSnia MoveOutline(Scr->Root, 11430bbfda8aSnia win->frame_x - win->frame_bw, 11440bbfda8aSnia win->frame_y - win->frame_bw, 11450bbfda8aSnia win->frame_width + 2 * win->frame_bw, 11460bbfda8aSnia win->frame_height + 2 * win->frame_bw, 11470bbfda8aSnia win->frame_bw, 11480bbfda8aSnia win->title_height + win->frame_bw3D); 11490bbfda8aSnia } 11500bbfda8aSnia } 11510bbfda8aSnia 11520bbfda8aSnia /* Move onward */ 11530bbfda8aSnia break; 11540bbfda8aSnia } 11550bbfda8aSnia 11560bbfda8aSnia /* 11570bbfda8aSnia * For the button 3 or anything else case, there's no dragging or 11580bbfda8aSnia * anything, so they do their thing and just immediately return. 11590bbfda8aSnia */ 11600bbfda8aSnia case 3 : { 11610bbfda8aSnia int newocc = win->occupation & ~(1 << oldws->number); 11620bbfda8aSnia if(newocc != 0) { 11630bbfda8aSnia ChangeOccupation(win, newocc); 11640bbfda8aSnia } 11650bbfda8aSnia return; 11660bbfda8aSnia } 11670bbfda8aSnia 11680bbfda8aSnia default : 11690bbfda8aSnia return; 11700bbfda8aSnia } 11710bbfda8aSnia 11720bbfda8aSnia /* 11730bbfda8aSnia * Keep dragging the representation of the window 11740bbfda8aSnia * 11750bbfda8aSnia * XXX Look back at this and see if we can move it to an inner 11760bbfda8aSnia * function for readability... 11770bbfda8aSnia */ 11780bbfda8aSnia { 11790bbfda8aSnia const float wf = (float)(mw->wwidth - 1) / (float) vs->w; 11800bbfda8aSnia const float hf = (float)(mw->wheight - 1) / (float) vs->h; 11810bbfda8aSnia int XW, YW; 11820bbfda8aSnia bool cont; 11830bbfda8aSnia Window junkW; 11840bbfda8aSnia 11850bbfda8aSnia /* Figure where in the subwindow the click was, and stash in XW/YW */ 11860bbfda8aSnia XTranslateCoordinates(dpy, Scr->Root, sw, event->xbutton.x_root, 11870bbfda8aSnia event->xbutton.y_root, 11880bbfda8aSnia &XW, &YW, &junkW); 11890bbfda8aSnia 11900bbfda8aSnia /* 11910bbfda8aSnia * Grab the pointer, lock it into the WSM, and get the events 11920bbfda8aSnia * related to buttons and movement. We don't need 11930bbfda8aSnia * PointerMotionMask, since that would only happen after buttons 11940bbfda8aSnia * are released, and we'll be done by then. 11950bbfda8aSnia */ 11960bbfda8aSnia XGrabPointer(dpy, mw->w, False, 11970bbfda8aSnia ButtonPressMask | ButtonMotionMask | ButtonReleaseMask, 11980bbfda8aSnia GrabModeAsync, GrabModeAsync, mw->w, Scr->MoveCursor, 11990bbfda8aSnia CurrentTime); 12000bbfda8aSnia 12010bbfda8aSnia /* Start handling events until we're done */ 12020bbfda8aSnia alreadyvivible = false; 12030bbfda8aSnia cont = true; 12040bbfda8aSnia while(cont) { 12050bbfda8aSnia XEvent ev; 12060bbfda8aSnia 12070bbfda8aSnia /* Grab the next event and handle */ 12080bbfda8aSnia XMaskEvent(dpy, ButtonPressMask | ButtonMotionMask | 12090bbfda8aSnia ButtonReleaseMask | ExposureMask, &ev); 12100bbfda8aSnia switch(ev.xany.type) { 12110bbfda8aSnia case Expose : { 12120bbfda8aSnia /* Something got exposed */ 12130bbfda8aSnia if(ev.xexpose.window == w) { 12140bbfda8aSnia /* 12150bbfda8aSnia * The win we're working with? We know how to do 12160bbfda8aSnia * that. 12170bbfda8aSnia */ 12180bbfda8aSnia WMapRedrawWindow(w, W0, H0, wl->cp, 12190bbfda8aSnia wl->twm_win->icon_name); 12200bbfda8aSnia break; 12210bbfda8aSnia } 12220bbfda8aSnia 12230bbfda8aSnia /* Else, delegate to our global dispatcher */ 12240bbfda8aSnia Event = ev; 12250bbfda8aSnia DispatchEvent(); 12260bbfda8aSnia break; 12270bbfda8aSnia } 12280bbfda8aSnia 12290bbfda8aSnia case ButtonPress : 12300bbfda8aSnia case ButtonRelease : { 12310bbfda8aSnia /* 12320bbfda8aSnia * Events for buttons other than the one whose press 12330bbfda8aSnia * started this activity are totally ignored. 12340bbfda8aSnia */ 12350bbfda8aSnia if(ev.xbutton.button != button) { 12360bbfda8aSnia break; 12370bbfda8aSnia } 12380bbfda8aSnia 12390bbfda8aSnia /* 12400bbfda8aSnia * Otherwise, this is a press/release of the button 12410bbfda8aSnia * that started things. Though I'm not sure how it 12420bbfda8aSnia * could be a press, since it was already pressed. 12430bbfda8aSnia * Regardless, this is our exit condition. Fall 12440bbfda8aSnia * through into the Motion case to handle any 12450bbfda8aSnia * remaining movement. 12460bbfda8aSnia */ 12470bbfda8aSnia lastev = ev; 12480bbfda8aSnia cont = false; 12490bbfda8aSnia newX = ev.xbutton.x; 12500bbfda8aSnia newY = ev.xbutton.y; 12510bbfda8aSnia } 12520bbfda8aSnia 12530bbfda8aSnia /* Everything remaining is motion handling */ 12540bbfda8aSnia case MotionNotify : { 12550bbfda8aSnia /* If we fell through from above, no new movement */ 12560bbfda8aSnia if(cont) { 12570bbfda8aSnia newX = ev.xmotion.x; 12580bbfda8aSnia newY = ev.xmotion.y; 12590bbfda8aSnia } 12600bbfda8aSnia 12610bbfda8aSnia /* Lots to do if we're moving the window for real */ 12620bbfda8aSnia if(realmovemode) { 12630bbfda8aSnia int XSW, YSW; 12640bbfda8aSnia WorkSpace *cws; 12650bbfda8aSnia MapSubwindow *msw; 12660bbfda8aSnia 12670bbfda8aSnia /* Did the move start in the currently visible WS? */ 12680bbfda8aSnia bool startincurrent = (oldws == vs->wsw->currentwspc); 12690bbfda8aSnia 12700bbfda8aSnia /* Find the workspace we wound up in */ 12710bbfda8aSnia for(cws = Scr->workSpaceMgr.workSpaceList ; 12720bbfda8aSnia cws != NULL ; 12730bbfda8aSnia cws = cws->next) { 12740bbfda8aSnia msw = vs->wsw->mswl [cws->number]; 12750bbfda8aSnia if((newX >= msw->x) 12760bbfda8aSnia && (newX < msw->x + mw->wwidth) 12770bbfda8aSnia && (newY >= msw->y) 12780bbfda8aSnia && (newY < msw->y + mw->wheight)) { 12790bbfda8aSnia break; 12800bbfda8aSnia } 12810bbfda8aSnia } 12820bbfda8aSnia if(!cws) { 12830bbfda8aSnia /* None? Ignore. */ 12840bbfda8aSnia break; 12850bbfda8aSnia } 12860bbfda8aSnia 12870bbfda8aSnia /* 12880bbfda8aSnia * Mouse is wherever it started inside the 12890bbfda8aSnia * subwindow, so figure the X/Y of the top left 12900bbfda8aSnia * of the subwindow from there. (coords relative 12910bbfda8aSnia * to the whole WSM because of grab) 12920bbfda8aSnia */ 12930bbfda8aSnia winX = newX - XW; 12940bbfda8aSnia winY = newY - YW; 12950bbfda8aSnia 12960bbfda8aSnia /* XXX redundant w/previous? */ 12970bbfda8aSnia msw = vs->wsw->mswl[cws->number]; 12980bbfda8aSnia 12990bbfda8aSnia /* 13000bbfda8aSnia * Figure where those coords are relative to the 13010bbfda8aSnia * per-workspace window. 13020bbfda8aSnia */ 13030bbfda8aSnia XTranslateCoordinates(dpy, mw->w, msw->w, 13040bbfda8aSnia winX, winY, &XSW, &YSW, &junkW); 13050bbfda8aSnia 13060bbfda8aSnia /* 13070bbfda8aSnia * Now rework the win[XY] to be the coordinates 13080bbfda8aSnia * the window would be in the whole screen, based 13090bbfda8aSnia * on the [XY]SW inside the map, using our scale 13100bbfda8aSnia * factors. 13110bbfda8aSnia */ 13120bbfda8aSnia winX = (int)(XSW / wf); 13130bbfda8aSnia winY = (int)(YSW / hf); 13140bbfda8aSnia 13150bbfda8aSnia /* 13160bbfda8aSnia * Clip to the screen if DontMoveOff is set. 13170bbfda8aSnia * 13180bbfda8aSnia * XXX Can we use the Constrain*() functions for 13190bbfda8aSnia * this, instead of implementing icky magic 13200bbfda8aSnia * internally? 13210bbfda8aSnia */ 13220bbfda8aSnia if(Scr->DontMoveOff) { 13230bbfda8aSnia const int width = win->frame_width; 13240bbfda8aSnia const int height = win->frame_height; 13250bbfda8aSnia 13260bbfda8aSnia if((winX < Scr->BorderLeft) && ((Scr->MoveOffResistance < 0) || 13270bbfda8aSnia (winX > Scr->BorderLeft - Scr->MoveOffResistance))) { 13280bbfda8aSnia winX = Scr->BorderLeft; 13290bbfda8aSnia newX = msw->x + XW + Scr->BorderLeft * mw->wwidth / vs->w; 13300bbfda8aSnia } 13310bbfda8aSnia if(((winX + width) > vs->w - Scr->BorderRight) && 13320bbfda8aSnia ((Scr->MoveOffResistance < 0) || 13330bbfda8aSnia ((winX + width) < vs->w - Scr->BorderRight + Scr->MoveOffResistance))) { 13340bbfda8aSnia winX = vs->w - Scr->BorderRight - width; 13350bbfda8aSnia newX = msw->x + mw->wwidth * 13360bbfda8aSnia (1 - Scr->BorderRight / (double) vs->w) - wl->width + XW - 2; 13370bbfda8aSnia } 13380bbfda8aSnia if((winY < Scr->BorderTop) && ((Scr->MoveOffResistance < 0) || 13390bbfda8aSnia (winY > Scr->BorderTop - Scr->MoveOffResistance))) { 13400bbfda8aSnia winY = Scr->BorderTop; 13410bbfda8aSnia newY = msw->y + YW + Scr->BorderTop * mw->height / vs->h; 13420bbfda8aSnia } 13430bbfda8aSnia if(((winY + height) > vs->h - Scr->BorderBottom) && 13440bbfda8aSnia ((Scr->MoveOffResistance < 0) || 13450bbfda8aSnia ((winY + height) < vs->h - Scr->BorderBottom + Scr->MoveOffResistance))) { 13460bbfda8aSnia winY = vs->h - Scr->BorderBottom - height; 13470bbfda8aSnia newY = msw->y + mw->wheight 13480bbfda8aSnia * (1 - Scr->BorderBottom / (double) vs->h) 13490bbfda8aSnia * - wl->height + YW - 2; 13500bbfda8aSnia } 13510bbfda8aSnia } 13520bbfda8aSnia 13530bbfda8aSnia 13540bbfda8aSnia /* Setup the avatar for the new position of win */ 13550bbfda8aSnia WMapSetupWindow(win, winX, winY, -1, -1); 13560bbfda8aSnia 13570bbfda8aSnia /* 13580bbfda8aSnia * If SWWMIW, we already made sure above the 13590bbfda8aSnia * window is always visible on the screen. So we 13600bbfda8aSnia * don't need to do any of the following steps to 13610bbfda8aSnia * maybe show it or maybe un-show it, since we 13620bbfda8aSnia * know it's already always shown. 13630bbfda8aSnia */ 13640bbfda8aSnia if(Scr->ShowWinWhenMovingInWmgr) { 13650bbfda8aSnia goto movewin; 13660bbfda8aSnia } 13670bbfda8aSnia 13680bbfda8aSnia /* 13690bbfda8aSnia * If we wound up in the same workspace as is 13700bbfda8aSnia * being displayed on the screen, we need to make 13710bbfda8aSnia * sure that window is showing up on the screen 13720bbfda8aSnia * as a "about to be occupied here if you release 13730bbfda8aSnia * the button" indication. 13740bbfda8aSnia */ 13750bbfda8aSnia if(cws == vs->wsw->currentwspc) { 13760bbfda8aSnia if(alreadyvivible) { 13770bbfda8aSnia /* Unless it's already there */ 13780bbfda8aSnia goto movewin; 13790bbfda8aSnia } 13800bbfda8aSnia if(Scr->OpaqueMove) { 13810bbfda8aSnia XMoveWindow(dpy, win->frame, winX, winY); 13820bbfda8aSnia DisplayWin(vs, win); 13830bbfda8aSnia } 13840bbfda8aSnia else { 13850bbfda8aSnia MoveOutline(Scr->Root, 13860bbfda8aSnia winX - win->frame_bw, 13870bbfda8aSnia winY - win->frame_bw, 13880bbfda8aSnia win->frame_width + 2 * win->frame_bw, 13890bbfda8aSnia win->frame_height + 2 * win->frame_bw, 13900bbfda8aSnia win->frame_bw, 13910bbfda8aSnia win->title_height + win->frame_bw3D); 13920bbfda8aSnia } 13930bbfda8aSnia alreadyvivible = true; 13940bbfda8aSnia 13950bbfda8aSnia /* 13960bbfda8aSnia * We already moved it, skip past the other 13970bbfda8aSnia * code trying to move it in other cases. 13980bbfda8aSnia */ 13990bbfda8aSnia goto move; 14000bbfda8aSnia } 14010bbfda8aSnia 14020bbfda8aSnia /* 14030bbfda8aSnia * If it's for whatever reason not being shown on 14040bbfda8aSnia * the screen, then we don't need to move it; hop 14050bbfda8aSnia * straight to moving the avatar. 14060bbfda8aSnia */ 14070bbfda8aSnia if(!alreadyvivible) { 14080bbfda8aSnia goto move; 14090bbfda8aSnia } 14100bbfda8aSnia 14110bbfda8aSnia /* 14120bbfda8aSnia * So it _is_ being shown. If it's not supposed 14130bbfda8aSnia * to be here, hide it away (don't need to worry 14140bbfda8aSnia * about AlwaysShow, it would have skipped past 14150bbfda8aSnia * us from ab0ve). Also, if we started moving 14160bbfda8aSnia * the window out of the visible workspace with 14170bbfda8aSnia * button 1, it's gonna not be here if you 14180bbfda8aSnia * release, so hide it away. 14190bbfda8aSnia */ 14200bbfda8aSnia if(!OCCUPY(win, vs->wsw->currentwspc) || 14210bbfda8aSnia (startincurrent && (button == 1))) { 14220bbfda8aSnia if(Scr->OpaqueMove) { 14230bbfda8aSnia Vanish(vs, win); 14240bbfda8aSnia XMoveWindow(dpy, win->frame, winX, winY); 14250bbfda8aSnia } 14260bbfda8aSnia else { 14270bbfda8aSnia MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0); 14280bbfda8aSnia } 14290bbfda8aSnia alreadyvivible = false; 14300bbfda8aSnia goto move; 14310bbfda8aSnia } 14320bbfda8aSnia 14330bbfda8aSniamovewin: 14340bbfda8aSnia /* 14350bbfda8aSnia * However we get here, the real window is 14360bbfda8aSnia * visible and needs to be moved. So move it. 14370bbfda8aSnia */ 14380bbfda8aSnia if(Scr->OpaqueMove) { 14390bbfda8aSnia XMoveWindow(dpy, win->frame, winX, winY); 14400bbfda8aSnia } 14410bbfda8aSnia else { 14420bbfda8aSnia MoveOutline(Scr->Root, 14430bbfda8aSnia winX - win->frame_bw, 14440bbfda8aSnia winY - win->frame_bw, 14450bbfda8aSnia win->frame_width + 2 * win->frame_bw, 14460bbfda8aSnia win->frame_height + 2 * win->frame_bw, 14470bbfda8aSnia win->frame_bw, 14480bbfda8aSnia win->title_height + win->frame_bw3D); 14490bbfda8aSnia } 14500bbfda8aSnia } 14510bbfda8aSnia 14520bbfda8aSniamove: 14530bbfda8aSnia /* 14540bbfda8aSnia * Just move the subwindow in the map to the new 14550bbfda8aSnia * location. 14560bbfda8aSnia */ 14570bbfda8aSnia XMoveWindow(dpy, w, newX - XW, newY - YW); 14580bbfda8aSnia 14590bbfda8aSnia /* And we're done. Next event! */ 14600bbfda8aSnia break; 14610bbfda8aSnia } 14620bbfda8aSnia } 14630bbfda8aSnia } 14640bbfda8aSnia } 14650bbfda8aSnia 14660bbfda8aSnia /* 14670bbfda8aSnia * Finished with dragging (button released). 14680bbfda8aSnia */ 14690bbfda8aSnia if(realmovemode) { 14700bbfda8aSnia /* Moving the real window? Move the real window. */ 14710bbfda8aSnia if(Scr->ShowWinWhenMovingInWmgr || alreadyvivible) { 14720bbfda8aSnia if(Scr->OpaqueMove && !OCCUPY(win, vs->wsw->currentwspc)) { 14730bbfda8aSnia Vanish(vs, win); 14740bbfda8aSnia } 14750bbfda8aSnia if(!Scr->OpaqueMove) { 14760bbfda8aSnia MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0); 14770bbfda8aSnia WMapRedrawName(vs, wl); 14780bbfda8aSnia } 14790bbfda8aSnia } 14800bbfda8aSnia SetupWindow(win, winX, winY, win->frame_width, win->frame_height, -1); 14810bbfda8aSnia } 14820bbfda8aSnia 14830bbfda8aSnia /* 14840bbfda8aSnia * Last event that caused us to escape is other code's 14850bbfda8aSnia * responsibility, put it back in the queue. 14860bbfda8aSnia */ 14870bbfda8aSnia lastev.xbutton.subwindow = (Window) 0; 14880bbfda8aSnia lastev.xbutton.window = parent; 14890bbfda8aSnia XPutBackEvent(dpy, &lastev); 14900bbfda8aSnia 14910bbfda8aSnia /* End our grab */ 14920bbfda8aSnia XUngrabPointer(dpy, CurrentTime); 14930bbfda8aSnia 14940bbfda8aSnia /* 14950bbfda8aSnia * If you wanted to change workspaces, and clicked _outside_ a 14960bbfda8aSnia * window, it would have just switched way up near the top of the 14970bbfda8aSnia * function. But if you clicked _in_ a window [in the WSM map], it 14980bbfda8aSnia * would have to go through the whole fun to find out whether you 14990bbfda8aSnia * wanted to move/reoccupy the window, or were just wanting to change 15000bbfda8aSnia * WSen. 15010bbfda8aSnia * 15020bbfda8aSnia * So if it's been <250ms (completely arbitrary and non-configgable, 15030bbfda8aSnia * probably should be rethought) since you started, assume you just 15040bbfda8aSnia * wanted to switch workspaces. Don't do any occupation change, And 15050bbfda8aSnia * just switch. Also do some magic related to the map/button 15060bbfda8aSnia * toggling. 15070bbfda8aSnia * 15080bbfda8aSnia * XXX This still leaves any window _moves_ done. It seems like it 15090bbfda8aSnia * should probably revert those too? 15100bbfda8aSnia */ 15110bbfda8aSnia if((lastev.xbutton.time - etime) < 250) { 15120bbfda8aSnia KeyCode control_L_code, control_R_code; 15130bbfda8aSnia char keys [32]; 15140bbfda8aSnia 15150bbfda8aSnia /* Re-show old miniwindow, destroy the temp, and warp to WS */ 15160bbfda8aSnia XMapWindow(dpy, sw); 15170bbfda8aSnia XDestroyWindow(dpy, w); 15180bbfda8aSnia GotoWorkSpace(vs, oldws); 15190bbfda8aSnia if(!Scr->DontWarpCursorInWMap) { 15200bbfda8aSnia WarpToWindow(win, Scr->RaiseOnWarp); 15210bbfda8aSnia } 15220bbfda8aSnia 15230bbfda8aSnia /* 15240bbfda8aSnia * The control keys toggle between map and button state. If we 15250bbfda8aSnia * did a short move, and ctrl is being held at the end, flip the 15260bbfda8aSnia * state. This has several possible causes and effects. 15270bbfda8aSnia * 15280bbfda8aSnia * One is that _during_ a move, we don't do look through KeyPress 15290bbfda8aSnia * events, so we wouldn't see it happen yet. But after we're 15300bbfda8aSnia * done and return back into the event loop, that press will come 15310bbfda8aSnia * in and cause the state to change. It may be weird to the user 15320bbfda8aSnia * to see that happen, not when they hit ctrl, but _later_, after 15330bbfda8aSnia * they release the mouse button. The "best" solution may be to 15340bbfda8aSnia * find that press in the event queue and empty it out, but a 15350bbfda8aSnia * cheap solution is just to pre-flip it and then let the event 15360bbfda8aSnia * code flip it back. Flickery maybe, but easy. Now, _should_ we be 15370bbfda8aSnia * doing that? I'm a little doubtful... 15380bbfda8aSnia * 15390bbfda8aSnia * A second is that if the WSM is "naturally" in button mode, and 15400bbfda8aSnia * you temporarily ctrl-flip it into map mode and then click in a 15410bbfda8aSnia * window. This code will cause it to automatically flip back 15420bbfda8aSnia * after you release the mouse if you haven't released ctrl yet. 15430bbfda8aSnia * This is apparently needed because, unless you have 15440bbfda8aSnia * DontWarpCursorInWMap set, the previous few lines of code would 15450bbfda8aSnia * have shifted the cursor to the window you clicked, which means 15460bbfda8aSnia * you don't get a chance to release it in the WSM and flip the 15470bbfda8aSnia * state back. It seems a reasonable assumption that the user 15480bbfda8aSnia * wanted a temporary change of state just for the purposes of 15490bbfda8aSnia * the change. 15500bbfda8aSnia * 15510bbfda8aSnia * (if you had released the ctrl before the mouse, the release 15520bbfda8aSnia * event would already be queued up up on the WSM, so would flip 15530bbfda8aSnia * it back after we return) 15540bbfda8aSnia * 15550bbfda8aSnia * XXX Should we be checking DontToggleWorkSpaceManagerState 15560bbfda8aSnia * here? 15570bbfda8aSnia */ 15580bbfda8aSnia control_L_code = XKeysymToKeycode(dpy, XStringToKeysym("Control_L")); 15590bbfda8aSnia control_R_code = XKeysymToKeycode(dpy, XStringToKeysym("Control_R")); 15600bbfda8aSnia XQueryKeymap(dpy, keys); 15610bbfda8aSnia if((keys [control_L_code / 8] & ((char) 0x80 >> (control_L_code % 8))) || 15620bbfda8aSnia keys [control_R_code / 8] & ((char) 0x80 >> (control_R_code % 8))) { 15630bbfda8aSnia WMgrToggleState(vs); 15640bbfda8aSnia } 15650bbfda8aSnia return; 15660bbfda8aSnia } 15670bbfda8aSnia 15680bbfda8aSnia 15690bbfda8aSnia /* Find the workspace we finally found up in */ 15700bbfda8aSnia for(newws = Scr->workSpaceMgr.workSpaceList ; newws != NULL ; 15710bbfda8aSnia newws = newws->next) { 15720bbfda8aSnia MapSubwindow *msw = vs->wsw->mswl[newws->number]; 15730bbfda8aSnia if((newX >= msw->x) && (newX < msw->x + mw->wwidth) && 15740bbfda8aSnia (newY >= msw->y) && (newY < msw->y + mw->wheight)) { 15750bbfda8aSnia break; 15760bbfda8aSnia } 15770bbfda8aSnia } 15780bbfda8aSnia 15790bbfda8aSnia /* And finish off whatever we're supposed to be doing */ 15800bbfda8aSnia switch(button) { 15810bbfda8aSnia case 1 : { /* moving to another workspace */ 15820bbfda8aSnia int occupation; 15830bbfda8aSnia 15840bbfda8aSnia /* If nothing to change, re-map avatar and we're done */ 15850bbfda8aSnia if((newws == NULL) || (newws == oldws) || 15860bbfda8aSnia OCCUPY(wl->twm_win, newws)) { 15870bbfda8aSnia XMapWindow(dpy, sw); 15880bbfda8aSnia break; 15890bbfda8aSnia } 15900bbfda8aSnia 15910bbfda8aSnia /* Out of the old, into the new */ 15920bbfda8aSnia occupation = win->occupation; 15930bbfda8aSnia occupation |= (1 << newws->number); 15940bbfda8aSnia occupation &= ~(1 << oldws->number); 15950bbfda8aSnia ChangeOccupation(win, occupation); 15960bbfda8aSnia 15970bbfda8aSnia /* 15980bbfda8aSnia * Raise it to the top if it's in our current ws, and 15990bbfda8aSnia * properly slot it into the WSM map stack if not. 16000bbfda8aSnia */ 16010bbfda8aSnia if(newws == vs->wsw->currentwspc) { 16020bbfda8aSnia OtpRaise(win, WinWin); 16030bbfda8aSnia WMapRaise(win); 16040bbfda8aSnia } 16050bbfda8aSnia else { 16060bbfda8aSnia WMapRestack(newws); 16070bbfda8aSnia } 16080bbfda8aSnia 16090bbfda8aSnia break; 16100bbfda8aSnia } 16110bbfda8aSnia 16120bbfda8aSnia case 2 : { /* putting in extra workspace */ 16130bbfda8aSnia int occupation; 16140bbfda8aSnia 16150bbfda8aSnia /* Nothing to do if it's going nowhere or places it already is */ 16160bbfda8aSnia if((newws == NULL) || (newws == oldws) || 16170bbfda8aSnia OCCUPY(wl->twm_win, newws)) { 16180bbfda8aSnia break; 16190bbfda8aSnia } 16200bbfda8aSnia 16210bbfda8aSnia /* Move */ 16220bbfda8aSnia occupation = win->occupation | (1 << newws->number); 16230bbfda8aSnia ChangeOccupation(win, occupation); 16240bbfda8aSnia 16250bbfda8aSnia /* Raise/stack */ 16260bbfda8aSnia if(newws == vs->wsw->currentwspc) { 16270bbfda8aSnia OtpRaise(win, WinWin); 16280bbfda8aSnia WMapRaise(win); 16290bbfda8aSnia } 16300bbfda8aSnia else { 16310bbfda8aSnia WMapRestack(newws); 16320bbfda8aSnia } 16330bbfda8aSnia break; 16340bbfda8aSnia } 16350bbfda8aSnia 16360bbfda8aSnia /* 16370bbfda8aSnia * Should actually never hit this state; only 1/2 would have 16380bbfda8aSnia * gotten this far into the code... 16390bbfda8aSnia */ 16400bbfda8aSnia default : 16410bbfda8aSnia return; 16420bbfda8aSnia } 16430bbfda8aSnia 16440bbfda8aSnia /* Clean up our temporary moving-around-in the WSM window */ 16450bbfda8aSnia XDestroyWindow(dpy, w); 16460bbfda8aSnia} 16470bbfda8aSnia 16480bbfda8aSnia 16490bbfda8aSnia 16500bbfda8aSnia 16510bbfda8aSnia/* 16520bbfda8aSnia **************************************************************** 16530bbfda8aSnia * 16540bbfda8aSnia * Functions for doing things with subwindows in the WSM in map state 16550bbfda8aSnia * 16560bbfda8aSnia **************************************************************** 16570bbfda8aSnia */ 16580bbfda8aSnia 16590bbfda8aSnia/* 16600bbfda8aSnia * Backend for mapping up windows in the WSM map. 16610bbfda8aSnia */ 16620bbfda8aSniastatic void 16630bbfda8aSniawmap_mapwin_backend(TwmWindow *win, bool handleraise) 16640bbfda8aSnia{ 16650bbfda8aSnia VirtualScreen *vs; 16660bbfda8aSnia WorkSpace *ws; 16670bbfda8aSnia WinList *wl; 16680bbfda8aSnia 16690bbfda8aSnia for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 16700bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 16710bbfda8aSnia for(wl = vs->wsw->mswl[ws->number]->wl; wl != NULL; wl = wl->next) { 16720bbfda8aSnia if(win == wl->twm_win) { 16730bbfda8aSnia /* 16740bbfda8aSnia * When called via deiconify, we might have to do 16750bbfda8aSnia * stuff related to auto-raising the window while we 16760bbfda8aSnia * de-iconify. When called via a map request, the 16770bbfda8aSnia * window is always wherever it previously was in the 16780bbfda8aSnia * stack. 16790bbfda8aSnia */ 16800bbfda8aSnia if(!handleraise || Scr->NoRaiseDeicon) { 16810bbfda8aSnia XMapWindow(dpy, wl->w); 16820bbfda8aSnia } 16830bbfda8aSnia else { 16840bbfda8aSnia XMapRaised(dpy, wl->w); 16850bbfda8aSnia } 16860bbfda8aSnia WMapRedrawName(vs, wl); 16870bbfda8aSnia break; 16880bbfda8aSnia } 16890bbfda8aSnia } 16900bbfda8aSnia } 16910bbfda8aSnia } 16920bbfda8aSnia} 16930bbfda8aSnia 16940bbfda8aSnia/* 16950bbfda8aSnia * Map up a window's subwindow in the map-mode WSM. Happens as a result 16960bbfda8aSnia * of getting (or faking) a Map request event. Notably, _not_ in the 16970bbfda8aSnia * process of de-iconifying a window; mostly as a result of _creating_ 16980bbfda8aSnia * windows, or when a client maps itself without a request from us. 16990bbfda8aSnia * 17000bbfda8aSnia * x-ref comment on WMapDeIconify() for some subtle distinctions between 17010bbfda8aSnia * the two... 17020bbfda8aSnia */ 17030bbfda8aSniavoid 17040bbfda8aSniaWMapMapWindow(TwmWindow *win) 17050bbfda8aSnia{ 17060bbfda8aSnia /* We don't do raise handling */ 17070bbfda8aSnia wmap_mapwin_backend(win, false); 17080bbfda8aSnia} 17090bbfda8aSnia 17100bbfda8aSnia 17110bbfda8aSnia/* 17120bbfda8aSnia * De-iconify a window in the WSM map. The opposite of WMapIconify(), 17130bbfda8aSnia * and different from WMapMapWindow() in complicated ways. This function 17140bbfda8aSnia * winds up getting called when a window is de-iconified via a ctwm 17150bbfda8aSnia * function. 17160bbfda8aSnia */ 17170bbfda8aSniavoid 17180bbfda8aSniaWMapDeIconify(TwmWindow *win) 17190bbfda8aSnia{ 17200bbfda8aSnia /* If it's not showing anywhere, nothing to do. Is this possible? */ 17210bbfda8aSnia if(!win->vs) { 17220bbfda8aSnia return; 17230bbfda8aSnia } 17240bbfda8aSnia 17250bbfda8aSnia /* Loop and map, handling raises if necessary */ 17260bbfda8aSnia wmap_mapwin_backend(win, true); 17270bbfda8aSnia} 17280bbfda8aSnia 17290bbfda8aSnia 17300bbfda8aSnia/* 17310bbfda8aSnia * Hide away a window in the WSM map. Happens when win is iconified; 17320bbfda8aSnia * different from destruction. 17330bbfda8aSnia */ 17340bbfda8aSniavoid 17350bbfda8aSniaWMapIconify(TwmWindow *win) 17360bbfda8aSnia{ 17370bbfda8aSnia VirtualScreen *vs; 17380bbfda8aSnia WorkSpace *ws; 17390bbfda8aSnia WinList *wl; 17400bbfda8aSnia 17410bbfda8aSnia if(!win->vs) { 17420bbfda8aSnia return; 17430bbfda8aSnia } 17440bbfda8aSnia 17450bbfda8aSnia for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 17460bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 17470bbfda8aSnia for(wl = vs->wsw->mswl[ws->number]->wl; wl != NULL; wl = wl->next) { 17480bbfda8aSnia if(win == wl->twm_win) { 17490bbfda8aSnia XUnmapWindow(dpy, wl->w); 17500bbfda8aSnia break; 17510bbfda8aSnia } 17520bbfda8aSnia } 17530bbfda8aSnia } 17540bbfda8aSnia } 17550bbfda8aSnia} 17560bbfda8aSnia 17570bbfda8aSnia 17580bbfda8aSnia/* 17590bbfda8aSnia * Position a window in the WSM. Happens as a result of moving things. 17600bbfda8aSnia */ 17610bbfda8aSniavoid 17620bbfda8aSniaWMapSetupWindow(TwmWindow *win, int x, int y, int w, int h) 17630bbfda8aSnia{ 17640bbfda8aSnia VirtualScreen *vs; 17650bbfda8aSnia 17660bbfda8aSnia /* If it's an icon manager, or not on a vscreen, nothing to do */ 17670bbfda8aSnia if(win->isiconmgr || !win->vs) { 17680bbfda8aSnia return; 17690bbfda8aSnia } 17700bbfda8aSnia 17710bbfda8aSnia /* If it's a WSM, we may be resetting size/position, but that's it */ 17720bbfda8aSnia if(win->iswspmgr) { 17730bbfda8aSnia if(w == -1) { 17740bbfda8aSnia return; 17750bbfda8aSnia } 17760bbfda8aSnia ResizeWorkSpaceManager(win->vs, win); 17770bbfda8aSnia return; 17780bbfda8aSnia } 17790bbfda8aSnia 17800bbfda8aSnia /* If it's an occupy window, ditto */ 17810bbfda8aSnia if(win == Scr->workSpaceMgr.occupyWindow->twm_win) { 17820bbfda8aSnia if(w == -1) { 17830bbfda8aSnia return; 17840bbfda8aSnia } 17850bbfda8aSnia ResizeOccupyWindow(win); 17860bbfda8aSnia return; 17870bbfda8aSnia } 17880bbfda8aSnia 17890bbfda8aSnia 17900bbfda8aSnia /* For anything else, we're potentially showing something */ 17910bbfda8aSnia for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 17920bbfda8aSnia WorkSpaceWindow *wsw = vs->wsw; 17930bbfda8aSnia WorkSpace *ws; 17940bbfda8aSnia 17950bbfda8aSnia /* Scale factors for windows in the map */ 17960bbfda8aSnia float wf = (float)(wsw->wwidth - 2) / (float) vs->w; 17970bbfda8aSnia float hf = (float)(wsw->wheight - 2) / (float) vs->h; 17980bbfda8aSnia 17990bbfda8aSnia /* 18000bbfda8aSnia * Loop around windows in each WS to find all the places the 18010bbfda8aSnia * requested window should show up. 18020bbfda8aSnia */ 18030bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 18040bbfda8aSnia MapSubwindow *msw = wsw->mswl[ws->number]; 18050bbfda8aSnia 18060bbfda8aSnia for(WinList *wl = msw->wl; wl != NULL; wl = wl->next) { 18070bbfda8aSnia if(win == wl->twm_win) { 18080bbfda8aSnia /* New positions */ 18090bbfda8aSnia wl->x = (int)(x * wf); 18100bbfda8aSnia wl->y = (int)(y * hf); 18110bbfda8aSnia 18120bbfda8aSnia /* Rescale if necessary and move */ 18130bbfda8aSnia if(w == -1) { 18140bbfda8aSnia XMoveWindow(dpy, wl->w, wl->x, wl->y); 18150bbfda8aSnia } 18160bbfda8aSnia else { 18170bbfda8aSnia wl->width = (unsigned int)((w * wf) + 0.5); 18180bbfda8aSnia wl->height = (unsigned int)((h * hf) + 0.5); 18190bbfda8aSnia if(!Scr->use3Dwmap) { 18200bbfda8aSnia wl->width -= 2; 18210bbfda8aSnia wl->height -= 2; 18220bbfda8aSnia } 18230bbfda8aSnia if(wl->width < 1) { 18240bbfda8aSnia wl->width = 1; 18250bbfda8aSnia } 18260bbfda8aSnia if(wl->height < 1) { 18270bbfda8aSnia wl->height = 1; 18280bbfda8aSnia } 18290bbfda8aSnia XMoveResizeWindow(dpy, wl->w, wl->x, wl->y, 18300bbfda8aSnia wl->width, wl->height); 18310bbfda8aSnia } 18320bbfda8aSnia break; 18330bbfda8aSnia } 18340bbfda8aSnia } 18350bbfda8aSnia } 18360bbfda8aSnia } 18370bbfda8aSnia} 18380bbfda8aSnia 18390bbfda8aSnia 18400bbfda8aSnia/* 18410bbfda8aSnia * Frontends for changing the stacking of windows in the WSM. 18420bbfda8aSnia * 18430bbfda8aSnia * Strictly speaker, we have no ability to raise or lower a window in the 18440bbfda8aSnia * map; we only draw the whole stack. And these functions don't actually 18450bbfda8aSnia * change the stacking of a window, they're called as a _result_ of 18460bbfda8aSnia * changing the stacking, to notify the WSM to re-check and update 18470bbfda8aSnia * itself. So while conceptually we maintain a separation for our 18480bbfda8aSnia * callers between various reasons this is being called, the 18490bbfda8aSnia * implementations are identical. 18500bbfda8aSnia */ 18510bbfda8aSniavoid 18520bbfda8aSniaWMapRaiseLower(TwmWindow *win) 18530bbfda8aSnia{ 18540bbfda8aSnia WorkSpace *ws; 18550bbfda8aSnia 18560bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 18570bbfda8aSnia if(OCCUPY(win, ws)) { 18580bbfda8aSnia WMapRestack(ws); 18590bbfda8aSnia } 18600bbfda8aSnia } 18610bbfda8aSnia} 18620bbfda8aSnia 18630bbfda8aSniavoid 18640bbfda8aSniaWMapLower(TwmWindow *win) 18650bbfda8aSnia{ 18660bbfda8aSnia WMapRaiseLower(win); 18670bbfda8aSnia} 18680bbfda8aSnia 18690bbfda8aSniavoid 18700bbfda8aSniaWMapRaise(TwmWindow *win) 18710bbfda8aSnia{ 18720bbfda8aSnia WMapRaiseLower(win); 18730bbfda8aSnia} 18740bbfda8aSnia 18750bbfda8aSnia 18760bbfda8aSnia/* 18770bbfda8aSnia * Backend for redoing the stacking of a window in the WSM. 18780bbfda8aSnia * 18790bbfda8aSnia * XXX Since this tends to get called iteratively, there's probably 18800bbfda8aSnia * something better we can do than doing all this relatively expensive 18810bbfda8aSnia * stuff over and over... 18820bbfda8aSnia */ 18830bbfda8aSniavoid 18840bbfda8aSniaWMapRestack(WorkSpace *ws) 18850bbfda8aSnia{ 18860bbfda8aSnia WinList *wl; 18870bbfda8aSnia Window root, parent; // Dummy 18880bbfda8aSnia Window *children, *smallws; 18890bbfda8aSnia unsigned int nchildren; 18900bbfda8aSnia 18910bbfda8aSnia /* Get a whole list of the windows on the screen */ 18920bbfda8aSnia nchildren = 0; 18930bbfda8aSnia XQueryTree(dpy, Scr->Root, &root, &parent, &children, &nchildren); 18940bbfda8aSnia 18950bbfda8aSnia /* 18960bbfda8aSnia * We're presumably dealing with a [often very small] subset of them, 18970bbfda8aSnia * but just allocate space for the whole list; easier than trying to 18980bbfda8aSnia * shrink down, and really, how big can it possibly be? 18990bbfda8aSnia */ 19000bbfda8aSnia smallws = calloc(nchildren, sizeof(Window)); 19010bbfda8aSnia 19020bbfda8aSnia /* Work it up per vscreen */ 19030bbfda8aSnia for(VirtualScreen *vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 19040bbfda8aSnia int j = 0; 19050bbfda8aSnia const MapSubwindow *msw = vs->wsw->mswl[ws->number]; 19060bbfda8aSnia 19070bbfda8aSnia /* Loop backward (from top to bottom of stack) */ 19080bbfda8aSnia for(int i = nchildren - 1; i >= 0; i--) { 19090bbfda8aSnia TwmWindow *win = GetTwmWindow(children[i]); 19100bbfda8aSnia 19110bbfda8aSnia /* 19120bbfda8aSnia * Only care about certain windows. If it's not a window we 19130bbfda8aSnia * know about, or not a frame (e.g., an icon), or doesn't 19140bbfda8aSnia * occupy this workspace, skip it. 19150bbfda8aSnia */ 19160bbfda8aSnia if(win == NULL || win->frame != children[i] || !OCCUPY(win, ws)) { 19170bbfda8aSnia continue; 19180bbfda8aSnia } 19190bbfda8aSnia 19200bbfda8aSnia /* Debug */ 19210bbfda8aSnia if(tracefile) { 19220bbfda8aSnia fprintf(tracefile, "WMapRestack : w = %lx, win = %p\n", 19230bbfda8aSnia children[i], (void *)win); 19240bbfda8aSnia fflush(tracefile); 19250bbfda8aSnia } 19260bbfda8aSnia 19270bbfda8aSnia /* Find this window in the list for the map of this WS */ 19280bbfda8aSnia for(wl = msw->wl; wl != NULL; wl = wl->next) { 19290bbfda8aSnia /* Debug */ 19300bbfda8aSnia if(tracefile) { 19310bbfda8aSnia fprintf(tracefile, "WMapRestack : wl = %p, twm_win = %p\n", 19320bbfda8aSnia (void *)wl, (void *)wl->twm_win); 19330bbfda8aSnia fflush(tracefile); 19340bbfda8aSnia } 19350bbfda8aSnia 19360bbfda8aSnia if(win == wl->twm_win) { 19370bbfda8aSnia /* There you are. Add into our list to restack. */ 19380bbfda8aSnia smallws[j++] = wl->w; 19390bbfda8aSnia break; 19400bbfda8aSnia } 19410bbfda8aSnia } 19420bbfda8aSnia } 19430bbfda8aSnia 19440bbfda8aSnia /* 19450bbfda8aSnia * Restack the windows in the map. Note that the order is 19460bbfda8aSnia * reversed from earlier; XQueryTree() returns bottom->top, 19470bbfda8aSnia * XRestackWindows() is passed top->bottom. 19480bbfda8aSnia */ 19490bbfda8aSnia XRestackWindows(dpy, smallws, j); 19500bbfda8aSnia } 19510bbfda8aSnia 19520bbfda8aSnia /* Cleanup */ 19530bbfda8aSnia XFree(children); 19540bbfda8aSnia free(smallws); 19550bbfda8aSnia return; 19560bbfda8aSnia} 19570bbfda8aSnia 19580bbfda8aSnia 19590bbfda8aSnia 19600bbfda8aSnia 19610bbfda8aSnia/* 19620bbfda8aSnia **************************************************************** 19630bbfda8aSnia * 19640bbfda8aSnia * Bits related to the actual drawing of the windows in the map. 19650bbfda8aSnia * 19660bbfda8aSnia **************************************************************** 19670bbfda8aSnia */ 19680bbfda8aSnia 19690bbfda8aSnia/* 19700bbfda8aSnia * Update stuff in the WSM when win's icon name changes 19710bbfda8aSnia */ 19720bbfda8aSniavoid 19730bbfda8aSniaWMapUpdateIconName(TwmWindow *win) 19740bbfda8aSnia{ 19750bbfda8aSnia VirtualScreen *vs; 19760bbfda8aSnia WorkSpace *ws; 19770bbfda8aSnia WinList *wl; 19780bbfda8aSnia 19790bbfda8aSnia for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 19800bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 19810bbfda8aSnia for(wl = vs->wsw->mswl[ws->number]->wl; wl != NULL; wl = wl->next) { 19820bbfda8aSnia if(win == wl->twm_win) { 19830bbfda8aSnia WMapRedrawName(vs, wl); 19840bbfda8aSnia break; 19850bbfda8aSnia } 19860bbfda8aSnia } 19870bbfda8aSnia } 19880bbfda8aSnia } 19890bbfda8aSnia} 19900bbfda8aSnia 19910bbfda8aSnia 19920bbfda8aSnia/* 19930bbfda8aSnia * Draw a window name into the window's representation in the map-state 19940bbfda8aSnia * WSM. 19950bbfda8aSnia */ 19960bbfda8aSniavoid 19970bbfda8aSniaWMapRedrawName(VirtualScreen *vs, WinList *wl) 19980bbfda8aSnia{ 19990bbfda8aSnia ColorPair cp = wl->cp; 20000bbfda8aSnia 20010bbfda8aSnia if(Scr->ReverseCurrentWorkspace && wl->wlist == vs->wsw->currentwspc) { 20020bbfda8aSnia InvertColorPair(&cp); 20030bbfda8aSnia } 20040bbfda8aSnia WMapRedrawWindow(wl->w, wl->width, wl->height, cp, wl->twm_win->icon_name); 20050bbfda8aSnia} 20060bbfda8aSnia 20070bbfda8aSnia 20080bbfda8aSnia/* 20090bbfda8aSnia * Draw up a window's representation in the map-state WSM, with the 20100bbfda8aSnia * window name. 20110bbfda8aSnia * 20120bbfda8aSnia * The drawing of the window name could probably be done a bit better. 20130bbfda8aSnia * The font size is based on a tiny fraction of the window's height, so 20140bbfda8aSnia * is probably usually too small to be useful, and often appears just as 20150bbfda8aSnia * some odd colored pixels at the top of the window. 20160bbfda8aSnia */ 20170bbfda8aSniastatic void 20180bbfda8aSniaWMapRedrawWindow(Window window, int width, int height, 20190bbfda8aSnia ColorPair cp, const char *label) 20200bbfda8aSnia{ 20210bbfda8aSnia int x, y; 20220bbfda8aSnia const MyFont font = Scr->workSpaceMgr.windowFont; 20230bbfda8aSnia 20240bbfda8aSnia /* Blank out window background color */ 20250bbfda8aSnia XClearWindow(dpy, window); 20260bbfda8aSnia 20270bbfda8aSnia /* Figure out where to position the name */ 20280bbfda8aSnia { 20290bbfda8aSnia XRectangle inc_rect; 20300bbfda8aSnia XRectangle logical_rect; 20310bbfda8aSnia int strhei, strwid; 20320bbfda8aSnia int i, descent; 20330bbfda8aSnia XFontStruct **xfonts; 20340bbfda8aSnia char **font_names; 20350bbfda8aSnia int fnum; 20360bbfda8aSnia 20370bbfda8aSnia XmbTextExtents(font.font_set, label, strlen(label), 20380bbfda8aSnia &inc_rect, &logical_rect); 20390bbfda8aSnia strwid = logical_rect.width; 20400bbfda8aSnia strhei = logical_rect.height; 20410bbfda8aSnia 20420bbfda8aSnia /* 20430bbfda8aSnia * If it's too tall to fit, just give up now. 20440bbfda8aSnia * XXX Probably should still do border stuff below... 20450bbfda8aSnia */ 20460bbfda8aSnia if(strhei > height) { 20470bbfda8aSnia return; 20480bbfda8aSnia } 20490bbfda8aSnia 20500bbfda8aSnia x = (width - strwid) / 2; 20510bbfda8aSnia if(x < 1) { 20520bbfda8aSnia x = 1; 20530bbfda8aSnia } 20540bbfda8aSnia 20550bbfda8aSnia fnum = XFontsOfFontSet(font.font_set, &xfonts, &font_names); 20560bbfda8aSnia for(i = 0, descent = 0; i < fnum; i++) { 20570bbfda8aSnia /* xf = xfonts[i]; */ 20580bbfda8aSnia descent = ((descent < (xfonts[i]->max_bounds.descent)) ? 20590bbfda8aSnia (xfonts[i]->max_bounds.descent) : descent); 20600bbfda8aSnia } 20610bbfda8aSnia 20620bbfda8aSnia y = ((height + strhei) / 2) - descent; 20630bbfda8aSnia } 20640bbfda8aSnia 20650bbfda8aSnia /* Draw up borders around the win */ 20660bbfda8aSnia if(Scr->use3Dwmap) { 20670bbfda8aSnia Draw3DBorder(window, 0, 0, width, height, 1, cp, off, true, false); 20680bbfda8aSnia FB(cp.fore, cp.back); 20690bbfda8aSnia } 20700bbfda8aSnia else { 20710bbfda8aSnia FB(cp.back, cp.fore); 20720bbfda8aSnia XFillRectangle(dpy, window, Scr->NormalGC, 0, 0, width, height); 20730bbfda8aSnia FB(cp.fore, cp.back); 20740bbfda8aSnia } 20750bbfda8aSnia 20760bbfda8aSnia /* Write in the name */ 20770bbfda8aSnia if(Scr->Monochrome != COLOR) { 20780bbfda8aSnia XmbDrawImageString(dpy, window, font.font_set, Scr->NormalGC, x, y, 20790bbfda8aSnia label, strlen(label)); 20800bbfda8aSnia } 20810bbfda8aSnia else { 20820bbfda8aSnia XmbDrawString(dpy, window, font.font_set, Scr->NormalGC, x, y, 20830bbfda8aSnia label, strlen(label)); 20840bbfda8aSnia } 20850bbfda8aSnia} 20860bbfda8aSnia 20870bbfda8aSnia 20880bbfda8aSnia 20890bbfda8aSnia 20900bbfda8aSnia/* 20910bbfda8aSnia * Processes for adding/removing windows from the WSM 20920bbfda8aSnia */ 20930bbfda8aSnia 20940bbfda8aSnia/* 20950bbfda8aSnia * Add a window into any appropriate WSMs' maps. Called during 20960bbfda8aSnia * AddWindow(). 20970bbfda8aSnia */ 20980bbfda8aSniavoid 20990bbfda8aSniaWMapAddWindow(TwmWindow *win) 21000bbfda8aSnia{ 21010bbfda8aSnia WorkSpace *ws; 21020bbfda8aSnia 21030bbfda8aSnia if(!WMapWindowMayBeAdded(win)) { 21040bbfda8aSnia return; 21050bbfda8aSnia } 21060bbfda8aSnia 21070bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 21080bbfda8aSnia if(OCCUPY(win, ws)) { 21090bbfda8aSnia WMapAddWindowToWorkspace(win, ws); 21100bbfda8aSnia } 21110bbfda8aSnia } 21120bbfda8aSnia} 21130bbfda8aSnia 21140bbfda8aSnia 21150bbfda8aSnia/* 21160bbfda8aSnia * Create WSM representation of a given window in a given WS. Called 21170bbfda8aSnia * when windows get added to a workspace, either via WMapAddWindow() 21180bbfda8aSnia * during the AddWindow() process, or via an occupation change. 21190bbfda8aSnia * 21200bbfda8aSnia * (previously: WMapAddToList()) 21210bbfda8aSnia */ 21220bbfda8aSniavoid 21230bbfda8aSniaWMapAddWindowToWorkspace(TwmWindow *win, WorkSpace *ws) 21240bbfda8aSnia{ 21250bbfda8aSnia ColorPair cp; 21260bbfda8aSnia 21270bbfda8aSnia /* Setup coloring for the window */ 21280bbfda8aSnia cp.back = win->title.back; 21290bbfda8aSnia cp.fore = win->title.fore; 21300bbfda8aSnia if(Scr->workSpaceMgr.windowcpgiven) { 21310bbfda8aSnia cp.back = Scr->workSpaceMgr.windowcp.back; 21320bbfda8aSnia GetColorFromList(Scr->workSpaceMgr.windowBackgroundL, 21330bbfda8aSnia win->name, &win->class, &cp.back); 21340bbfda8aSnia cp.fore = Scr->workSpaceMgr.windowcp.fore; 21350bbfda8aSnia GetColorFromList(Scr->workSpaceMgr.windowForegroundL, 21360bbfda8aSnia win->name, &win->class, &cp.fore); 21370bbfda8aSnia } 21380bbfda8aSnia if(Scr->use3Dwmap && !Scr->BeNiceToColormap) { 21390bbfda8aSnia GetShadeColors(&cp); 21400bbfda8aSnia } 21410bbfda8aSnia 21420bbfda8aSnia /* We need a copy in each VS */ 21430bbfda8aSnia for(VirtualScreen *vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 21440bbfda8aSnia unsigned int bw; 21450bbfda8aSnia WinList *wl; 21460bbfda8aSnia const float wf = (float)(vs->wsw->wwidth - 2) / (float) vs->w; 21470bbfda8aSnia const float hf = (float)(vs->wsw->wheight - 2) / (float) vs->h; 21480bbfda8aSnia MapSubwindow *msw = vs->wsw->mswl[ws->number]; 21490bbfda8aSnia 21500bbfda8aSnia /* Put together its winlist entry */ 21510bbfda8aSnia wl = malloc(sizeof(struct winList)); 21520bbfda8aSnia wl->wlist = ws; 21530bbfda8aSnia wl->x = (int)(win->frame_x * wf); 21540bbfda8aSnia wl->y = (int)(win->frame_y * hf); 21550bbfda8aSnia wl->width = (unsigned int)((win->frame_width * wf) + 0.5); 21560bbfda8aSnia wl->height = (unsigned int)((win->frame_height * hf) + 0.5); 21570bbfda8aSnia wl->cp = cp; 21580bbfda8aSnia wl->twm_win = win; 21590bbfda8aSnia 21600bbfda8aSnia /* Size the window bits */ 21610bbfda8aSnia bw = 0; 21620bbfda8aSnia if(!Scr->use3Dwmap) { 21630bbfda8aSnia bw = 1; 21640bbfda8aSnia wl->width -= 2; 21650bbfda8aSnia wl->height -= 2; 21660bbfda8aSnia } 21670bbfda8aSnia if(wl->width < 1) { 21680bbfda8aSnia wl->width = 1; 21690bbfda8aSnia } 21700bbfda8aSnia if(wl->height < 1) { 21710bbfda8aSnia wl->height = 1; 21720bbfda8aSnia } 21730bbfda8aSnia 21740bbfda8aSnia /* Create its little window */ 21750bbfda8aSnia wl->w = XCreateSimpleWindow(dpy, msw->w, wl->x, wl->y, 21760bbfda8aSnia wl->width, wl->height, bw, 21770bbfda8aSnia Scr->Black, cp.back); 21780bbfda8aSnia 21790bbfda8aSnia /* Setup cursor and attributes for it */ 21800bbfda8aSnia { 21810bbfda8aSnia XSetWindowAttributes attr; 21820bbfda8aSnia unsigned long attrmask; 21830bbfda8aSnia 21840bbfda8aSnia attr.cursor = handCursor; 21850bbfda8aSnia attrmask = CWCursor; 21860bbfda8aSnia 21870bbfda8aSnia if(Scr->BackingStore) { 21880bbfda8aSnia attr.backing_store = WhenMapped; 21890bbfda8aSnia attrmask |= CWBackingStore; 21900bbfda8aSnia } 21910bbfda8aSnia 21920bbfda8aSnia XChangeWindowAttributes(dpy, wl->w, attrmask, &attr); 21930bbfda8aSnia } 21940bbfda8aSnia 21950bbfda8aSnia /* Setup events and stash context bits */ 21960bbfda8aSnia XSelectInput(dpy, wl->w, ExposureMask); 21970bbfda8aSnia XSaveContext(dpy, wl->w, TwmContext, (XPointer) vs->wsw->twm_win); 21980bbfda8aSnia XSaveContext(dpy, wl->w, ScreenContext, (XPointer) Scr); 21990bbfda8aSnia XSaveContext(dpy, wl->w, MapWListContext, (XPointer) wl); 22000bbfda8aSnia 22010bbfda8aSnia /* Link it onto the front of the list */ 22020bbfda8aSnia wl->next = msw->wl; 22030bbfda8aSnia msw->wl = wl; 22040bbfda8aSnia 22050bbfda8aSnia /* 22060bbfda8aSnia * And map it, if its window is mapped. That'll kick an expose 22070bbfda8aSnia * event, which will work its way down to WMapRedrawWindow(), and 22080bbfda8aSnia * fill things in. 22090bbfda8aSnia */ 22100bbfda8aSnia if(win->mapped) { 22110bbfda8aSnia XMapWindow(dpy, wl->w); 22120bbfda8aSnia } 22130bbfda8aSnia } // And around to the next vscreen 22140bbfda8aSnia} 22150bbfda8aSnia 22160bbfda8aSnia 22170bbfda8aSnia/* 22180bbfda8aSnia * Remove a window from any WSM maps it's in. Called during window 22190bbfda8aSnia * destruction process. 22200bbfda8aSnia * 22210bbfda8aSnia * (previously: WMapDestroyWindow()) 22220bbfda8aSnia */ 22230bbfda8aSniavoid 22240bbfda8aSniaWMapRemoveWindow(TwmWindow *win) 22250bbfda8aSnia{ 22260bbfda8aSnia WorkSpace *ws; 22270bbfda8aSnia 22280bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 22290bbfda8aSnia if(OCCUPY(win, ws)) { 22300bbfda8aSnia WMapRemoveWindowFromWorkspace(win, ws); 22310bbfda8aSnia } 22320bbfda8aSnia } 22330bbfda8aSnia 22340bbfda8aSnia /* 22350bbfda8aSnia * If it's a mapped occupy window, manually hide aways its bits in 22360bbfda8aSnia * here. 22370bbfda8aSnia * 22380bbfda8aSnia * XXX Better belongs inline in caller or separate func? This is the 22390bbfda8aSnia * only thing exposing occupyWin out of occupation.c. 22400bbfda8aSnia */ 22410bbfda8aSnia if(win == occupyWin) { 22420bbfda8aSnia OccupyWindow *occwin = Scr->workSpaceMgr.occupyWindow; 22430bbfda8aSnia XUnmapWindow(dpy, occwin->twm_win->frame); 22440bbfda8aSnia occwin->twm_win->mapped = false; 22450bbfda8aSnia occwin->twm_win->occupation = 0; 22460bbfda8aSnia occupyWin = NULL; 22470bbfda8aSnia } 22480bbfda8aSnia} 22490bbfda8aSnia 22500bbfda8aSnia 22510bbfda8aSnia/* 22520bbfda8aSnia * Remove window's WSM representation. Happens from WMapRemoveWindow() 22530bbfda8aSnia * as part of the window destruction process, and in the occupation 22540bbfda8aSnia * change process. 22550bbfda8aSnia * 22560bbfda8aSnia * (previously: WMapRemoveFromList()) 22570bbfda8aSnia */ 22580bbfda8aSniavoid 22590bbfda8aSniaWMapRemoveWindowFromWorkspace(TwmWindow *win, WorkSpace *ws) 22600bbfda8aSnia{ 22610bbfda8aSnia VirtualScreen *vs; 22620bbfda8aSnia 22630bbfda8aSnia for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 22640bbfda8aSnia WinList **prev = &vs->wsw->mswl[ws->number]->wl; 22650bbfda8aSnia 22660bbfda8aSnia /* Pull it out of the list and destroy it */ 22670bbfda8aSnia for(WinList *wl = *prev ; wl != NULL ; wl = wl->next) { 22680bbfda8aSnia if(win != wl->twm_win) { 22690bbfda8aSnia /* Not it */ 22700bbfda8aSnia prev = &wl->next; 22710bbfda8aSnia continue; 22720bbfda8aSnia } 22730bbfda8aSnia 22740bbfda8aSnia /* There you are. Unlink and kill */ 22750bbfda8aSnia *prev = wl->next; 22760bbfda8aSnia 22770bbfda8aSnia XDeleteContext(dpy, wl->w, TwmContext); 22780bbfda8aSnia XDeleteContext(dpy, wl->w, ScreenContext); 22790bbfda8aSnia XDeleteContext(dpy, wl->w, MapWListContext); 22800bbfda8aSnia XDestroyWindow(dpy, wl->w); 22810bbfda8aSnia free(wl); 22820bbfda8aSnia 22830bbfda8aSnia /* Around to the next vscreen */ 22840bbfda8aSnia break; 22850bbfda8aSnia } 22860bbfda8aSnia } 22870bbfda8aSnia} 22880bbfda8aSnia 22890bbfda8aSnia 22900bbfda8aSnia 22910bbfda8aSnia 22920bbfda8aSnia/* 22930bbfda8aSnia **************************************************************** 22940bbfda8aSnia * 22950bbfda8aSnia * Utils-ish funcs 22960bbfda8aSnia * 22970bbfda8aSnia **************************************************************** 22980bbfda8aSnia */ 22990bbfda8aSnia 23000bbfda8aSnia/* 23010bbfda8aSnia * This is really more util.c fodder, but leaving it here for now because 23020bbfda8aSnia * it's only used once in WMapRedrawName(). If we start finding external 23030bbfda8aSnia * uses for it, it should be moved. 23040bbfda8aSnia */ 23050bbfda8aSniastatic void 23060bbfda8aSniaInvertColorPair(ColorPair *cp) 23070bbfda8aSnia{ 23080bbfda8aSnia Pixel save; 23090bbfda8aSnia 23100bbfda8aSnia save = cp->fore; 23110bbfda8aSnia cp->fore = cp->back; 23120bbfda8aSnia cp->back = save; 23130bbfda8aSnia save = cp->shadc; 23140bbfda8aSnia cp->shadc = cp->shadd; 23150bbfda8aSnia cp->shadd = save; 23160bbfda8aSnia} 23170bbfda8aSnia 23180bbfda8aSnia 23190bbfda8aSnia/* 23200bbfda8aSnia * Verify if a window may be added to the workspace map. 23210bbfda8aSnia * This is not allowed for 23220bbfda8aSnia * - icon managers 23230bbfda8aSnia * - the occupy window 23240bbfda8aSnia * - workspace manager windows 23250bbfda8aSnia * - or, optionally, windows with full occupation. 23260bbfda8aSnia */ 23270bbfda8aSniabool 23280bbfda8aSniaWMapWindowMayBeAdded(TwmWindow *win) 23290bbfda8aSnia{ 23300bbfda8aSnia if(win->isiconmgr) { 23310bbfda8aSnia return false; 23320bbfda8aSnia } 23330bbfda8aSnia if(win == Scr->workSpaceMgr.occupyWindow->twm_win) { 23340bbfda8aSnia return false; 23350bbfda8aSnia } 23360bbfda8aSnia if(win->iswspmgr) { 23370bbfda8aSnia return false; 23380bbfda8aSnia } 23390bbfda8aSnia if(Scr->workSpaceMgr.noshowoccupyall && 23400bbfda8aSnia win->occupation == fullOccupation) { 23410bbfda8aSnia return false; 23420bbfda8aSnia } 23430bbfda8aSnia return true; 23440bbfda8aSnia} 2345