/* * [ ctwm ] * * Copyright 1992 Claude Lecommandeur. * * Permission to use, copy, modify and distribute this software [ctwm] and * its documentation for any purpose is hereby granted without fee, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting documen- * tation, and that the name of Claude Lecommandeur not be used in adverti- * sing or publicity pertaining to distribution of the software without * specific, written prior permission. Claude Lecommandeur make no represen- * tations about the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty. * * Claude Lecommandeur DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO * EVENT SHALL Claude Lecommandeur BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * * Author: Claude Lecommandeur [ lecom@sic.epfl.ch ][ April 1992 ] */ #include #include #include "twm.h" #include "util.h" #include "parse.h" #include "screen.h" #include "icons.h" #include "resize.h" #include "add_window.h" #include "events.h" #include "clicktofocus.h" #include "cursor.h" #include "list.h" #include "workmgr.h" #ifdef VMS #include #include #include #include #include #else #include #include #include #include #endif #ifdef macII int strcmp(); /* missing from string.h in AUX 2.0 */ #endif #ifdef BUGGY_HP700_SERVER static void fakeRaiseLower (); #endif #ifdef GNOME # include "gnomewindefs.h" /* include GNOME hints definitions */ extern Atom _XA_WIN_WORKSPACE; extern Atom _XA_WIN_STATE; #endif /* GNOME */ extern void twmrc_error_prefix (void); /* in gram.c */ extern char *captivename; /*********************************************************************** * * Procedure: * CreateWorkSpaceManager - create the workspace manager window * for this screen. * * Returned Value: * none * * Inputs: * none * *********************************************************************** */ #define WSPCWINDOW 0 #define OCCUPYWINDOW 1 #define OCCUPYBUTTON 2 static void Vanish (virtualScreen *vs, TwmWindow *tmp_win); static void DisplayWin (virtualScreen *vs, TwmWindow *tmp_win); static void CreateWorkSpaceManagerWindow (virtualScreen *vs); static void CreateOccupyWindow (void); static unsigned int GetMaskFromResource (TwmWindow *win, char *res); static int GetPropertyFromMask (unsigned int mask, char *prop, long *gwkspc); static void PaintWorkSpaceManagerBorder (virtualScreen *vs); static void PaintButton (int which, virtualScreen *vs, Window w, char *label, ColorPair cp, int state); static void WMapRemoveFromList (TwmWindow *win, WorkSpace *ws); static int WMapWindowMayBeAdded (TwmWindow *win); static void WMapAddToList (TwmWindow *win, WorkSpace *ws); static void ResizeWorkSpaceManager (virtualScreen *vs, TwmWindow *win); static void ResizeOccupyWindow (TwmWindow *win); static WorkSpace *GetWorkspace (char *wname); static void WMapRedrawWindow (Window window, int width, int height, ColorPair cp, char *label); static int CanChangeOccupation (TwmWindow **twm_winp); void safecopy (char *dest, char *src, int size); Atom _XA_WM_OCCUPATION; Atom _XA_WM_CURRENTWORKSPACE; Atom _XA_WM_WORKSPACESLIST; Atom _XA_WM_CTWMSLIST; Atom _XA_WM_CTWM_VSCREENMAP; Atom _OL_WIN_ATTR; int fullOccupation = 0; int useBackgroundInfo = False; XContext MapWListContext = (XContext) 0; static Cursor handCursor = (Cursor) 0; static Bool DontRedirect (Window window); extern Bool donttoggleworkspacemanagerstate; extern Bool MaybeAnimate; extern FILE *tracefile; void InitWorkSpaceManager (void) { Scr->workSpaceMgr.count = 0; Scr->workSpaceMgr.workSpaceList = NULL; Scr->workSpaceMgr.initialstate = BUTTONSSTATE; Scr->workSpaceMgr.geometry = NULL; Scr->workSpaceMgr.buttonStyle = STYLE_NORMAL; Scr->workSpaceMgr.windowcp.back = Scr->White; Scr->workSpaceMgr.windowcp.fore = Scr->Black; Scr->workSpaceMgr.windowcpgiven = False; Scr->workSpaceMgr.occupyWindow = calloc(1, sizeof (OccupyWindow)); Scr->workSpaceMgr.occupyWindow->name = "Occupy Window"; Scr->workSpaceMgr.occupyWindow->icon_name = "Occupy Window Icon"; Scr->workSpaceMgr.occupyWindow->geometry = NULL; Scr->workSpaceMgr.occupyWindow->columns = 0; Scr->workSpaceMgr.occupyWindow->twm_win = (TwmWindow*) 0; Scr->workSpaceMgr.occupyWindow->vspace = Scr->WMgrVertButtonIndent; Scr->workSpaceMgr.occupyWindow->hspace = Scr->WMgrHorizButtonIndent; Scr->workSpaceMgr.curColors.back = Scr->Black; Scr->workSpaceMgr.curColors.fore = Scr->White; Scr->workSpaceMgr.defColors.back = Scr->White; Scr->workSpaceMgr.defColors.fore = Scr->Black; Scr->workSpaceMgr.curImage = None; Scr->workSpaceMgr.curPaint = False; Scr->workSpaceMgr.defImage = None; Scr->workSpaceMgr.vspace = Scr->WMgrVertButtonIndent; Scr->workSpaceMgr.hspace = Scr->WMgrHorizButtonIndent; Scr->workSpaceMgr.name = "WorkSpaceManager"; Scr->workSpaceMgr.icon_name = "WorkSpaceManager Icon"; Scr->workSpaceMgr.windowFont.basename = "-adobe-courier-medium-r-normal--10-100-75-75-m-60-iso8859-1"; /*"-adobe-courier-bold-r-normal--8-80-75-75-m-50-iso8859-1";*/ XrmInitialize (); if (MapWListContext == (XContext) 0) MapWListContext = XUniqueContext (); } void ConfigureWorkSpaceManager (void) { virtualScreen *vs; for (vs = Scr->vScreenList; vs != NULL; vs = vs->next) { /* * Make sure this is all properly initialized to nothing. Otherwise * bad and undefined behavior can show up in certain cases (e.g., * with no Workspaces {} defined in .ctwmrc, the only defined * workspace will be random memory bytes, which can causes crashes on * e.g. f.menu "TwmWindows".) */ WorkSpaceWindow *wsw = (WorkSpaceWindow*) calloc (1, sizeof (WorkSpaceWindow)); wsw->state = Scr->workSpaceMgr.initialstate; /* BUTTONSSTATE */ vs->wsw = wsw; } } void CreateWorkSpaceManager (void) { char wrkSpcList [512]; char vsmapbuf [1024], *vsmap; virtualScreen *vs; WorkSpace *ws, *fws; int len, vsmaplen; long junk; if (! Scr->workSpaceManagerActive) return; Scr->workSpaceMgr.windowFont.basename = "-adobe-courier-medium-r-normal--10-100-75-75-m-60-iso8859-1"; Scr->workSpaceMgr.buttonFont = Scr->IconManagerFont; Scr->workSpaceMgr.cp = Scr->IconManagerC; if (!Scr->BeNiceToColormap) GetShadeColors (&Scr->workSpaceMgr.cp); _XA_WM_OCCUPATION = XInternAtom (dpy, "WM_OCCUPATION", False); _XA_WM_CURRENTWORKSPACE = XInternAtom (dpy, "WM_CURRENTWORKSPACE", False); _XA_WM_CTWM_VSCREENMAP = XInternAtom (dpy, "WM_CTWM_VSCREENMAP", False); #ifdef GNOME _XA_WM_WORKSPACESLIST = XInternAtom (dpy, "_WIN_WORKSPACE_NAMES", False); #else /* GNOME */ _XA_WM_WORKSPACESLIST = XInternAtom (dpy, "WM_WORKSPACESLIST", False); #endif /* GNOME */ _OL_WIN_ATTR = XInternAtom (dpy, "_OL_WIN_ATTR", False); NewFontCursor (&handCursor, "top_left_arrow"); vsmaplen = sizeof(vsmapbuf); if(CtwmGetVScreenMap(dpy, Scr->Root, vsmapbuf, &vsmaplen) == True) vsmap = strtok(vsmapbuf, ","); else vsmap = NULL; /* * weird things can happen if the config file is changed or the atom * returned above is messed with. Sometimes windows may disappear in * that case depending on what's changed. (depending on where they were * on the actual screen. */ ws = Scr->workSpaceMgr.workSpaceList; for (vs = Scr->vScreenList; vs != NULL; vs = vs->next) { WorkSpaceWindow *wsw = vs->wsw; if(vsmap) fws = GetWorkspace(vsmap); else fws = NULL; if(fws) { wsw->currentwspc = fws; vsmap = strtok(NULL, ","); } else { wsw->currentwspc = ws; ws = ws->next; } CreateWorkSpaceManagerWindow (vs); } CreateOccupyWindow (); for (vs = Scr->vScreenList; vs != NULL; vs = vs->next) { WorkSpaceWindow *wsw = vs->wsw; WorkSpace *ws2 = wsw->currentwspc; MapSubwindow *msw = wsw->mswl [ws2->number]; if (Scr->workSpaceMgr.curImage == None) { if (Scr->workSpaceMgr.curPaint) { XSetWindowBackground (dpy, msw->w, Scr->workSpaceMgr.curColors.back); } } else { XSetWindowBackgroundPixmap (dpy, msw->w, Scr->workSpaceMgr.curImage->pixmap); } XSetWindowBorder (dpy, msw->w, Scr->workSpaceMgr.curBorderColor); XClearWindow (dpy, msw->w); if (useBackgroundInfo && ! Scr->DontPaintRootWindow) { if (ws2->image == None) XSetWindowBackground (dpy, vs->window, ws2->backcp.back); else XSetWindowBackgroundPixmap (dpy, vs->window, ws2->image->pixmap); XClearWindow (dpy, vs->window); } } len = GetPropertyFromMask (0xFFFFFFFFu, wrkSpcList, &junk); XChangeProperty (dpy, Scr->Root, _XA_WM_WORKSPACESLIST, XA_STRING, 8, PropModeReplace, (unsigned char *) wrkSpcList, len); } void GotoWorkSpaceByName (virtualScreen *vs, char *wname) { WorkSpace *ws; if (! Scr->workSpaceManagerActive) return; if (!vs) return; ws = GetWorkspace(wname); if (ws == NULL) return; GotoWorkSpace (vs, ws); } /* 6/19/1999 nhd for GNOME compliance */ void GotoWorkSpaceByNumber(virtualScreen *vs, int workspacenum) { WorkSpace *ws; if(! Scr->workSpaceManagerActive) return; if (!vs) return; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { if (ws->number == workspacenum) break; } if (ws == NULL) return; GotoWorkSpace (vs, ws); } /* */ void GotoPrevWorkSpace (virtualScreen *vs) { WorkSpace *ws1, *ws2; if (! Scr->workSpaceManagerActive) return; if (!vs) return; ws1 = Scr->workSpaceMgr.workSpaceList; if (ws1 == NULL) return; ws2 = ws1->next; while ((ws2 != vs->wsw->currentwspc) && (ws2 != NULL)) { ws1 = ws2; ws2 = ws2->next; } GotoWorkSpace (vs, ws1); } void GotoNextWorkSpace (virtualScreen *vs) { WorkSpace *ws; if (! Scr->workSpaceManagerActive) return; if (!vs) return; ws = vs->wsw->currentwspc; ws = (ws->next != NULL) ? ws->next : Scr->workSpaceMgr.workSpaceList; GotoWorkSpace (vs, ws); } void GotoRightWorkSpace (virtualScreen *vs) { WorkSpace *ws; int number, columns, count; if (!Scr->workSpaceManagerActive) return; if (!vs) return; ws = vs->wsw->currentwspc; number = ws->number; columns = Scr->workSpaceMgr.columns; count = Scr->workSpaceMgr.count; number++; if ((number % columns) == 0) number -= columns; else if (number >= count) number = (number / columns) * columns; GotoWorkSpaceByNumber(vs, number); } void GotoLeftWorkSpace (virtualScreen *vs) { WorkSpace *ws; int number, columns, count; if (!Scr->workSpaceManagerActive) return; if (!vs) return; ws = vs->wsw->currentwspc; number = ws->number; columns = Scr->workSpaceMgr.columns; count = Scr->workSpaceMgr.count; number += (number % columns) ? -1 : (columns - 1); if (number >= count) number = count - 1; GotoWorkSpaceByNumber(vs, number); } void GotoUpWorkSpace (virtualScreen *vs) { WorkSpace *ws; int number, lines, columns, count; if (!Scr->workSpaceManagerActive) return; if (!vs) return; ws = vs->wsw->currentwspc; number = ws->number; lines = Scr->workSpaceMgr.lines; columns = Scr->workSpaceMgr.columns; count = Scr->workSpaceMgr.count; number -= columns; if (number < 0) { number += lines * columns; /* If the number of workspaces is not a multiple of nr of columns */ if (number >= count) number -= columns; } GotoWorkSpaceByNumber(vs, number); } void GotoDownWorkSpace (virtualScreen *vs) { WorkSpace *ws; int number, columns, count; if (!Scr->workSpaceManagerActive) return; if (!vs) return; ws = vs->wsw->currentwspc; number = ws->number; columns = Scr->workSpaceMgr.columns; count = Scr->workSpaceMgr.count; number += columns; if (number >= count) { number %= columns; } GotoWorkSpaceByNumber(vs, number); } void ShowBackground (virtualScreen *vs) { static int state = 0; TwmWindow *twmWin; if (state) { for (twmWin = Scr->FirstWindow; twmWin != NULL; twmWin = twmWin->next) { if (twmWin->savevs == vs) { DisplayWin (vs, twmWin); } twmWin->savevs = NULL; } state = 0; } else { for (twmWin = Scr->FirstWindow; twmWin != NULL; twmWin = twmWin->next) { if (twmWin->vs == vs) { twmWin->savevs = twmWin->vs; Vanish (vs, twmWin); } } state = 1; } } void GotoWorkSpace (virtualScreen *vs, WorkSpace *ws) { TwmWindow *twmWin; WorkSpace *oldws, *newws; WList *wl, *wl1; WinList winl; XSetWindowAttributes attr; XWindowAttributes winattrs; unsigned long eventMask; IconMgr *iconmgr; Window oldw; Window neww; TwmWindow *focuswindow; TwmWindow *last_twmWin = NULL; virtualScreen *tmpvs; if (! Scr->workSpaceManagerActive) return; for (tmpvs = Scr->vScreenList; tmpvs != NULL; tmpvs = tmpvs->next) { if (ws == tmpvs->wsw->currentwspc) { XBell (dpy, 0); return; } } oldws = vs->wsw->currentwspc; newws = ws; if (oldws == newws) return; attr.backing_store = NotUseful; attr.save_under = False; if (useBackgroundInfo && ! Scr->DontPaintRootWindow) { if (newws->image == None) XSetWindowBackground (dpy, vs->window, newws->backcp.back); else XSetWindowBackgroundPixmap (dpy, vs->window, newws->image->pixmap); XClearWindow (dpy, vs->window); } /* If SaveWorkspaceFocus is on, save the focus of the last window. */ if ( Scr->SaveWorkspaceFocus ) { oldws->save_focus = Scr->Focus; } focuswindow = (TwmWindow *)NULL; for (twmWin = Scr->FirstWindow; twmWin != NULL; twmWin = twmWin->next) { if (twmWin->vs == vs) { if (!OCCUPY (twmWin, newws)) { virtualScreen *tvs; Vanish (vs, twmWin); for (tvs = Scr->vScreenList; tvs != NULL; tvs = tvs->next) { if (tvs == vs) continue; if (OCCUPY (twmWin, tvs->wsw->currentwspc)) { DisplayWin (tvs, twmWin); break; } } } else if (twmWin->hasfocusvisible) { focuswindow = twmWin; SetFocusVisualAttributes (focuswindow, False); } } } /* Move to the end of the twmWin list */ for (twmWin = Scr->FirstWindow; twmWin != NULL; twmWin = twmWin->next) { last_twmWin = twmWin; } /* Iconise in reverse order */ for (twmWin = last_twmWin; twmWin != NULL; twmWin = twmWin->prev) { if (OCCUPY (twmWin, newws) && !twmWin->vs) DisplayWin (vs, twmWin); } /* Reorganize icon manager window lists */ for (twmWin = Scr->FirstWindow; twmWin != NULL; twmWin = twmWin->next) { wl = twmWin->iconmanagerlist; if (wl == NULL) continue; if (OCCUPY (wl->iconmgr->twm_win, newws)) continue; wl1 = wl; wl = wl->nextv; while (wl != NULL) { if (OCCUPY (wl->iconmgr->twm_win, newws)) break; wl1 = wl; wl = wl->nextv; } if (wl != NULL) { wl1->nextv = wl->nextv; wl->nextv = twmWin->iconmanagerlist; twmWin->iconmanagerlist = wl; } } wl = (WList*)0; for (iconmgr = newws->iconmgr; iconmgr; iconmgr = iconmgr->next) { if (iconmgr->first) { wl = iconmgr->first; break; } } CurrentIconManagerEntry (wl); if (focuswindow) { SetFocusVisualAttributes (focuswindow, True); } vs->wsw->currentwspc = newws; if (Scr->ReverseCurrentWorkspace && vs->wsw->state == MAPSTATE) { MapSubwindow *msw = vs->wsw->mswl [oldws->number]; for (winl = msw->wl; winl != NULL; winl = winl->next) { WMapRedrawName (vs, winl); } msw = vs->wsw->mswl [newws->number]; for (winl = msw->wl; winl != NULL; winl = winl->next) { WMapRedrawName (vs, winl); } } else if (vs->wsw->state == BUTTONSSTATE) { ButtonSubwindow *bsw = vs->wsw->bswl [oldws->number]; PaintButton (WSPCWINDOW, vs, bsw->w, oldws->label, oldws->cp, off); bsw = vs->wsw->bswl [newws->number]; PaintButton (WSPCWINDOW, vs, bsw->w, newws->label, newws->cp, on); } oldws->iconmgr = Scr->iconmgr; Scr->iconmgr = newws->iconmgr; oldw = vs->wsw->mswl [oldws->number]->w; neww = vs->wsw->mswl [newws->number]->w; if (useBackgroundInfo) { if (oldws->image == None || Scr->NoImagesInWorkSpaceManager) XSetWindowBackground (dpy, oldw, oldws->backcp.back); else XSetWindowBackgroundPixmap (dpy, oldw, oldws->image->pixmap); } else { if (Scr->workSpaceMgr.defImage == None || Scr->NoImagesInWorkSpaceManager) XSetWindowBackground (dpy, oldw, Scr->workSpaceMgr.defColors.back); else XSetWindowBackgroundPixmap (dpy, oldw, Scr->workSpaceMgr.defImage->pixmap); } attr.border_pixel = Scr->workSpaceMgr.defBorderColor; XChangeWindowAttributes (dpy, oldw, CWBorderPixel, &attr); if (Scr->workSpaceMgr.curImage == None) { if (Scr->workSpaceMgr.curPaint) XSetWindowBackground (dpy, neww, Scr->workSpaceMgr.curColors.back); } else { XSetWindowBackgroundPixmap (dpy, neww, Scr->workSpaceMgr.curImage->pixmap); } attr.border_pixel = Scr->workSpaceMgr.curBorderColor; XChangeWindowAttributes (dpy, neww, CWBorderPixel, &attr); XClearWindow (dpy, oldw); XClearWindow (dpy, neww); XGetWindowAttributes(dpy, Scr->Root, &winattrs); eventMask = winattrs.your_event_mask; XSelectInput(dpy, Scr->Root, eventMask & ~PropertyChangeMask); XChangeProperty (dpy, Scr->Root, _XA_WM_CURRENTWORKSPACE, XA_STRING, 8, PropModeReplace, (unsigned char *) newws->name, strlen (newws->name)); #ifdef GNOME /* nhd 6/19/1999 for GNOME compliance * Publish which workspace the root window shows/contains. * Olaf Rhialto Seibert: However, don't do it when the root window is * captive, since it will be moved itself: for non-root windows this * property is used to indicate in which workspace it is contained. */ if (!Scr->CaptiveRoot) XChangeProperty (dpy, Scr->Root, _XA_WIN_WORKSPACE, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &(newws->number), 1); #endif /* GNOME */ XSelectInput(dpy, Scr->Root, eventMask); /* XDestroyWindow (dpy, cachew);*/ if (Scr->ChangeWorkspaceFunction.func != 0) { char *action; XEvent event; action = Scr->ChangeWorkspaceFunction.item ? Scr->ChangeWorkspaceFunction.item->action : NULL; ExecuteFunction (Scr->ChangeWorkspaceFunction.func, action, (Window) 0, (TwmWindow*) 0, &event, C_ROOT, FALSE); } /* If SaveWorkspaceFocus is on, try to restore the focus to the last window which was focused when we left this workspace. */ if (Scr->SaveWorkspaceFocus && newws->save_focus) { twmWin = newws->save_focus; if (OCCUPY(twmWin, newws)) { /* check should not even be needed anymore */ WarpToWindow(twmWin, 0); } else { newws->save_focus = NULL; } } /* keep track of the order of the workspaces across restarts */ CtwmSetVScreenMap(dpy, Scr->Root, Scr->vScreenList); XSync (dpy, 0); if (Scr->ClickToFocus || Scr->SloppyFocus) set_last_window (newws); MaybeAnimate = True; } char *GetCurrentWorkSpaceName (virtualScreen *vs) { if (! Scr->workSpaceManagerActive) return (NULL); if (!vs) vs = Scr->vScreenList; return vs->wsw->currentwspc->name; } void AddWorkSpace (char *name, char *background, char *foreground, char *backback, char *backfore, char *backpix) { WorkSpace *ws; int wsnum; Image *image; wsnum = Scr->workSpaceMgr.count; if (wsnum == MAXWORKSPACE) return; fullOccupation |= (1 << wsnum); ws = (WorkSpace*) malloc (sizeof (WorkSpace)); ws->FirstWindowRegion = NULL; #if 0 /* def VMS */ { char *ftemp; ftemp = (char *) malloc((strlen(name)+1)*sizeof(char)); ws->name = strcpy (ftemp,name); ftemp = (char *) malloc((strlen(name)+1)*sizeof(char)); ws->label = strcpy (ftemp,name); } #else ws->name = (char*) strdup (name); ws->label = (char*) strdup (name); #endif ws->clientlist = NULL; ws->save_focus = NULL; if (background == NULL) ws->cp.back = Scr->IconManagerC.back; else GetColor (Scr->Monochrome, &(ws->cp.back), background); if (foreground == NULL) ws->cp.fore = Scr->IconManagerC.fore; else GetColor (Scr->Monochrome, &(ws->cp.fore), foreground); #ifdef COLOR_BLIND_USER ws->cp.shadc = Scr->White; ws->cp.shadd = Scr->Black; #else if (!Scr->BeNiceToColormap) GetShadeColors (&ws->cp); #endif if (backback == NULL) GetColor (Scr->Monochrome, &(ws->backcp.back), "Black"); else { GetColor (Scr->Monochrome, &(ws->backcp.back), backback); useBackgroundInfo = True; } if (backfore == NULL) GetColor (Scr->Monochrome, &(ws->backcp.fore), "White"); else { GetColor (Scr->Monochrome, &(ws->backcp.fore), backfore); useBackgroundInfo = True; } if ((image = GetImage (backpix, ws->backcp)) != None) { ws->image = image; useBackgroundInfo = True; } else { ws->image = None; } ws->next = NULL; ws->number = wsnum; Scr->workSpaceMgr.count++; if (Scr->workSpaceMgr.workSpaceList == NULL) { Scr->workSpaceMgr.workSpaceList = ws; } else { WorkSpace *wstmp = Scr->workSpaceMgr.workSpaceList; while (wstmp->next != NULL) { wstmp = wstmp->next; } wstmp->next = ws; } Scr->workSpaceManagerActive = 1; } static XrmOptionDescRec table [] = { {"-xrm", NULL, XrmoptionResArg, (XPointer) NULL}, }; void SetupOccupation (TwmWindow *twm_win, int occupation_hint) /* <== [ Matthew McNeill Feb 1997 ] == */ { TwmWindow *t; unsigned char *prop; unsigned long nitems, bytesafter; Atom actual_type; int actual_format; int state; Window icon; char **cliargv = NULL; int cliargc; Bool status; char *str_type; XrmValue value; char wrkSpcList [512]; int len; WorkSpace *ws; XWindowAttributes winattrs; unsigned long eventMask; XrmDatabase db = NULL; virtualScreen *vs; long gwkspc = 0; /* for GNOME - which workspace we occupy */ if (! Scr->workSpaceManagerActive) { twm_win->occupation = 1 << 0; /* occupy workspace #0 */ /* * Choose some valid virtual screen. * InitVirtualScreens() always seems to set this to non-NULL. */ twm_win->vs = Scr->vScreenList; /* only one virtual screen */ /* more?... */ return; } if (twm_win->wspmgr) return; /*twm_win->occupation = twm_win->iswinbox ? fullOccupation : 0;*/ twm_win->occupation = 0; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { if (LookInList (ws->clientlist, twm_win->full_name, &twm_win->class)) { twm_win->occupation |= 1 << ws->number; } } if (LookInList (Scr->OccupyAll, twm_win->full_name, &twm_win->class)) { twm_win->occupation = fullOccupation; } if (XGetCommand (dpy, twm_win->w, &cliargv, &cliargc)) { XrmParseCommand (&db, table, 1, "ctwm", &cliargc, cliargv); status = XrmGetResource (db, "ctwm.workspace", "Ctwm.Workspace", &str_type, &value); if ((status == True) && (value.size != 0)) { strncpy (wrkSpcList, value.addr, value.size); twm_win->occupation = GetMaskFromResource (twm_win, wrkSpcList); } XrmDestroyDatabase (db); XFreeStringList (cliargv); } if (RestartPreviousState) { if (XGetWindowProperty (dpy, twm_win->w, _XA_WM_OCCUPATION, 0L, 2500, False, XA_STRING, &actual_type, &actual_format, &nitems, &bytesafter, &prop) == Success) { if (nitems != 0) { twm_win->occupation = GetMaskFromProperty (prop, nitems); XFree ((char *) prop); } } } if (twm_win->iconmgr) return; /* someone tried to modify occupation of icon managers */ if (! Scr->TransientHasOccupation) { if (twm_win->transient) { t = GetTwmWindow(twm_win->transientfor); if (t != NULL) twm_win->occupation = t->occupation; } else if (twm_win->group != 0) { t = GetTwmWindow(twm_win->group); if (t != NULL) twm_win->occupation = t->occupation; } } /*============[ Matthew McNeill Feb 1997 ]========================* * added in functionality of specific occupation state. The value * should be a valid occupation bit-field or 0 for the default action */ if (occupation_hint != 0) twm_win->occupation = occupation_hint; /*================================================================*/ if ((twm_win->occupation & fullOccupation) == 0) { vs = Scr->currentvs; if (vs && vs->wsw->currentwspc) twm_win->occupation = 1 << vs->wsw->currentwspc->number; else { twm_win->occupation = 1; } } twm_win->vs = NULL; for (vs = Scr->vScreenList; vs != NULL; vs = vs->next) { if (OCCUPY (twm_win, vs->wsw->currentwspc)) { twm_win->vs = vs; break; } } len = GetPropertyFromMask (twm_win->occupation, wrkSpcList, &gwkspc); if (!XGetWindowAttributes(dpy, twm_win->w, &winattrs)) return; eventMask = winattrs.your_event_mask; XSelectInput(dpy, twm_win->w, eventMask & ~PropertyChangeMask); XChangeProperty (dpy, twm_win->w, _XA_WM_OCCUPATION, XA_STRING, 8, PropModeReplace, (unsigned char *) wrkSpcList, len); #ifdef GNOME XChangeProperty (dpy, twm_win->w, _XA_WIN_WORKSPACE, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)(&gwkspc), 1); if (XGetWindowProperty (dpy, twm_win->w, _XA_WIN_STATE, 0L, 32, False, XA_CARDINAL, &actual_type, &actual_format, &nitems, &bytesafter, &prop) != Success || nitems == 0) { gwkspc = 0; } else { gwkspc = (int)*prop; XFree ((char *)prop); } if (twm_win->occupation == fullOccupation) gwkspc |= WIN_STATE_STICKY; else gwkspc &= ~WIN_STATE_STICKY; XChangeProperty (dpy, twm_win->w, _XA_WIN_STATE, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&gwkspc, 1); #endif /* GNOME */ XSelectInput (dpy, twm_win->w, eventMask); /* kludge */ state = NormalState; if (!(RestartPreviousState && GetWMState (twm_win->w, &state, &icon) && (state == NormalState || state == IconicState || state == InactiveState))) { if (twm_win->wmhints && (twm_win->wmhints->flags & StateHint)) state = twm_win->wmhints->initial_state; } if (visible (twm_win)) { if (state == InactiveState) SetMapStateProp (twm_win, NormalState); } else { if (state == NormalState) SetMapStateProp (twm_win, InactiveState); } } void safecopy(char *dest, char *src, int size) { strncpy(dest, src, size - 1); dest[size - 1] = '\0'; } Bool RedirectToCaptive (Window window) { unsigned long nitems, bytesafter; Atom actual_type; int actual_format; char **cliargv = NULL; int cliargc; Bool status; char *str_type; XrmValue value; int ret; Atom _XA_WM_CTWM_ROOT; char *atomname; Window newroot; XWindowAttributes wa; XrmDatabase db = NULL; if (DontRedirect (window)) return (False); if (!XGetCommand (dpy, window, &cliargv, &cliargc)) return (False); XrmParseCommand (&db, table, 1, "ctwm", &cliargc, cliargv); if (db == NULL) { if (cliargv) XFreeStringList (cliargv); return False; } ret = False; status = XrmGetResource (db, "ctwm.redirect", "Ctwm.Redirect", &str_type, &value); if ((status == True) && (value.size != 0)) { char cctwm [64]; Window *prop; safecopy (cctwm, value.addr, sizeof(cctwm)); atomname = (char*) malloc (strlen ("WM_CTWM_ROOT_") + strlen (cctwm) + 1); sprintf (atomname, "WM_CTWM_ROOT_%s", cctwm); _XA_WM_CTWM_ROOT = XInternAtom (dpy, atomname, False); if (XGetWindowProperty (dpy, Scr->Root, _XA_WM_CTWM_ROOT, 0L, 1L, False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytesafter, (unsigned char **)&prop) == Success) { if (actual_type == XA_WINDOW && actual_format == 32 && nitems == 1 /*&& bytesafter == 0*/) { newroot = *prop; if (XGetWindowAttributes (dpy, newroot, &wa)) { XReparentWindow (dpy, window, newroot, 0, 0); XMapWindow (dpy, window); ret = True; } } XFree ((char *)prop); } } status = XrmGetResource (db, "ctwm.rootWindow", "Ctwm.RootWindow", &str_type, &value); if ((status == True) && (value.size != 0)) { char rootw [32]; unsigned int scanned; safecopy (rootw, value.addr, sizeof(rootw)); if (sscanf (rootw, "%x", &scanned) == 1) { newroot = scanned; if (XGetWindowAttributes (dpy, newroot, &wa)) { XReparentWindow (dpy, window, newroot, 0, 0); XMapWindow (dpy, window); ret = True; } } } XrmDestroyDatabase (db); XFreeStringList (cliargv); return (ret); } /* * The window whose occupation is being manipulated. */ static TwmWindow *occupyWin = (TwmWindow*) 0; static int CanChangeOccupation(TwmWindow **twm_winp) { TwmWindow *twm_win; if (!Scr->workSpaceManagerActive) return 0; if (occupyWin != NULL) return 0; twm_win = *twm_winp; if (twm_win->iconmgr) return 0; if (!Scr->TransientHasOccupation) { if (twm_win->transient) return 0; if (twm_win->group != (Window) 0 && twm_win->group != twm_win->w) { /* * When trying to modify a group member window, * operate on the group leader instead * (and thereby on all group member windows as well). * If we can't find the group leader, pretend it isn't set. */ twm_win = GetTwmWindow(twm_win->group); if (!twm_win) return 1; *twm_winp = twm_win; } } return 1; } void Occupy (TwmWindow *twm_win) { int x, y, junkX, junkY; unsigned int junkB, junkD; unsigned int width, height; int xoffset, yoffset; Window junkW, w; unsigned int junkK; struct OccupyWindow *occupyWindow; if (!CanChangeOccupation(&twm_win)) return; occupyWindow = Scr->workSpaceMgr.occupyWindow; occupyWindow->tmpOccupation = twm_win->occupation; w = occupyWindow->w; XGetGeometry (dpy, w, &junkW, &junkX, &junkY, &width, &height, &junkB, &junkD); XQueryPointer (dpy, Scr->Root, &junkW, &junkW, &junkX, &junkY, &x, &y, &junkK); x -= (width / 2); y -= (height / 2); if (x < 0) x = 0; if (y < 0) y = 0; xoffset = width + 2 * Scr->BorderWidth; yoffset = height + 2 * Scr->BorderWidth + Scr->TitleHeight; if ((x + xoffset) > Scr->rootw) x = Scr->rootw - xoffset; if ((y + yoffset) > Scr->rooth) y = Scr->rooth - yoffset; occupyWindow->twm_win->occupation = twm_win->occupation; if (occupyWindow->twm_win->vs != Scr->currentvs) { XReparentWindow(dpy, occupyWindow->twm_win->frame, Scr->Root, x, y); occupyWindow->twm_win->vs = Scr->currentvs; } else XMoveWindow(dpy, occupyWindow->twm_win->frame, x, y); SetMapStateProp (occupyWindow->twm_win, NormalState); XMapWindow (dpy, occupyWindow->w); XMapRaised (dpy, occupyWindow->twm_win->frame); occupyWindow->twm_win->mapped = TRUE; occupyWin = twm_win; } void OccupyHandleButtonEvent (XEvent *event) { WorkSpace *ws; OccupyWindow *occupyW; Window buttonW; if (! Scr->workSpaceManagerActive) return; if (occupyWin == (TwmWindow*) 0) return; buttonW = event->xbutton.window; if (buttonW == 0) return; /* icon */ XGrabPointer (dpy, Scr->Root, True, ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, Scr->Root, None, CurrentTime); occupyW = Scr->workSpaceMgr.occupyWindow; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { if (occupyW->obuttonw [ws->number] == buttonW) break; } if (ws != NULL) { int mask = 1 << ws->number; if ((occupyW->tmpOccupation & mask) == 0) { PaintButton (OCCUPYWINDOW, NULL, occupyW->obuttonw [ws->number], ws->label, ws->cp, on); } else { PaintButton (OCCUPYWINDOW, NULL, occupyW->obuttonw [ws->number], ws->label, ws->cp, off); } occupyW->tmpOccupation ^= mask; } else if (buttonW == occupyW->OK) { if (occupyW->tmpOccupation == 0) return; ChangeOccupation (occupyWin, occupyW->tmpOccupation); XUnmapWindow (dpy, occupyW->twm_win->frame); occupyW->twm_win->mapped = FALSE; occupyW->twm_win->occupation = 0; occupyWin = (TwmWindow*) 0; XSync (dpy, 0); } else if (buttonW == occupyW->cancel) { XUnmapWindow (dpy, occupyW->twm_win->frame); occupyW->twm_win->mapped = FALSE; occupyW->twm_win->occupation = 0; occupyWin = (TwmWindow*) 0; XSync (dpy, 0); } else if (buttonW == occupyW->allworkspc) { for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { PaintButton (OCCUPYWINDOW, NULL, occupyW->obuttonw [ws->number], ws->label, ws->cp, on); } occupyW->tmpOccupation = fullOccupation; } if (ButtonPressed == -1) XUngrabPointer (dpy, CurrentTime); } void OccupyAll (TwmWindow *twm_win) { IconMgr *save; if (!CanChangeOccupation(&twm_win)) return; save = Scr->iconmgr; Scr->iconmgr = Scr->workSpaceMgr.workSpaceList->iconmgr; ChangeOccupation (twm_win, fullOccupation); Scr->iconmgr = save; } void AddToWorkSpace (char *wname, TwmWindow *twm_win) { WorkSpace *ws; int newoccupation; if (!CanChangeOccupation(&twm_win)) return; ws = GetWorkspace (wname); if (!ws) return; if (twm_win->occupation & (1 << ws->number)) return; newoccupation = twm_win->occupation | (1 << ws->number); ChangeOccupation (twm_win, newoccupation); } void RemoveFromWorkSpace (char *wname, TwmWindow *twm_win) { WorkSpace *ws; int newoccupation; if (!CanChangeOccupation(&twm_win)) return; ws = GetWorkspace (wname); if (!ws) return; newoccupation = twm_win->occupation & ~(1 << ws->number); if (!newoccupation) return; ChangeOccupation (twm_win, newoccupation); } void ToggleOccupation (char *wname, TwmWindow *twm_win) { WorkSpace *ws; int newoccupation; if (!CanChangeOccupation(&twm_win)) return; ws = GetWorkspace (wname); if (!ws) return; newoccupation = twm_win->occupation ^ (1 << ws->number); if (!newoccupation) return; ChangeOccupation (twm_win, newoccupation); } void MoveToNextWorkSpace (virtualScreen *vs, TwmWindow *twm_win) { WorkSpace *wlist1, *wlist2; int newoccupation; if (!CanChangeOccupation(&twm_win)) return; wlist1 = vs->wsw->currentwspc; wlist2 = wlist1->next; wlist2 = wlist2 ? wlist2 : Scr->workSpaceMgr.workSpaceList; newoccupation = (twm_win->occupation ^ (1 << wlist1->number)) | (1 << wlist2->number); ChangeOccupation (twm_win, newoccupation); } void MoveToNextWorkSpaceAndFollow (virtualScreen *vs, TwmWindow *twm_win) { if (!CanChangeOccupation(&twm_win)) return; MoveToNextWorkSpace(vs, twm_win); GotoNextWorkSpace(vs); #if 0 RaiseWindow(twm_win); /* XXX really do this? */ #endif } void MoveToPrevWorkSpace (virtualScreen *vs, TwmWindow *twm_win) { WorkSpace *wlist1, *wlist2; int newoccupation; if (!CanChangeOccupation(&twm_win)) return; wlist1 = Scr->workSpaceMgr.workSpaceList; wlist2 = vs->wsw->currentwspc; if (wlist1 == NULL) return; while (wlist1->next != wlist2 && wlist1->next != NULL) { wlist1 = wlist1->next; } newoccupation = (twm_win->occupation ^ (1 << wlist2->number)) | (1 << wlist1->number); ChangeOccupation (twm_win, newoccupation); } void MoveToPrevWorkSpaceAndFollow (virtualScreen *vs, TwmWindow *twm_win) { if (!CanChangeOccupation(&twm_win)) return; MoveToPrevWorkSpace(vs, twm_win); GotoPrevWorkSpace(vs); #if 0 RaiseWindow(twm_win); /* XXX really do this? */ #endif } static WorkSpace *GetWorkspace (char *wname) { WorkSpace *ws; if (!wname) return (NULL); for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { if (strcmp (ws->label, wname) == 0) break; } if (ws == NULL) { for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { if (strcmp (ws->name, wname) == 0) break; } } return (ws); } void AllocateOthersIconManagers (void) { IconMgr *p = NULL, *ip, *oldp, *oldv; WorkSpace *ws; if (! Scr->workSpaceManagerActive) return; oldp = Scr->iconmgr; for (ws = Scr->workSpaceMgr.workSpaceList->next; ws != NULL; ws = ws->next) { ws->iconmgr = (IconMgr *) malloc (sizeof (IconMgr)); *ws->iconmgr = *oldp; oldv = ws->iconmgr; oldp->nextv = ws->iconmgr; oldv->nextv = NULL; for (ip = oldp->next; ip != NULL; ip = ip->next) { p = (IconMgr *) malloc (sizeof (IconMgr)); *p = *ip; ip->nextv = p; p->next = NULL; p->prev = oldv; p->nextv = NULL; oldv->next = p; oldv = p; } for (ip = ws->iconmgr; ip != NULL; ip = ip->next) { ip->lasti = p; } oldp = ws->iconmgr; } Scr->workSpaceMgr.workSpaceList->iconmgr = Scr->iconmgr; } static void Vanish (virtualScreen *vs, TwmWindow *tmp_win) { XWindowAttributes winattrs; unsigned long eventMask; if (vs && tmp_win->vs && tmp_win->vs != vs) return; if (tmp_win->UnmapByMovingFarAway) { XMoveWindow (dpy, tmp_win->frame, Scr->rootw + 1, Scr->rooth + 1); } else if (tmp_win->mapped) { XGetWindowAttributes(dpy, tmp_win->w, &winattrs); eventMask = winattrs.your_event_mask; XSelectInput (dpy, tmp_win->w, eventMask & ~StructureNotifyMask); XUnmapWindow (dpy, tmp_win->w); XUnmapWindow (dpy, tmp_win->frame); XSelectInput (dpy, tmp_win->w, eventMask); if (!tmp_win->DontSetInactive) SetMapStateProp (tmp_win, InactiveState); } else if (tmp_win->icon_on && tmp_win->icon && tmp_win->icon->w) { XUnmapWindow (dpy, tmp_win->icon->w); IconDown (tmp_win); } /* * XXX - this may need to be tweaked to find the real window at 0x0. * Most people will setup virtualscreens left to right, but some * may not. The purpose of this is in the event of a ctwm death/restart, * geometries of windows that were on unmapped workspaces will show * up where they belong. * XXX - XReparentWindow() messes up the stacking order of windows. * It should be avoided as much as possible. This already affects * switching away from and back to a workspace. Therefore do this only * if there are at least 2 virtual screens AND the new one (firstvs) * differs from where the window currently is. (Olaf Seibert). */ if (Scr->vScreenList && Scr->vScreenList->next) { int x, y; unsigned int junk; Window junkW, w = tmp_win->frame; virtualScreen *firstvs = NULL; for (firstvs = Scr->vScreenList; firstvs; firstvs = firstvs->next) if (firstvs->x == 0 && firstvs->y == 0) break; if (firstvs && firstvs != vs) { XGetGeometry (dpy, w, &junkW, &x, &y, &junk, &junk, &junk, &junk); XReparentWindow(dpy, w, firstvs->window, x, y); tmp_win->vs = firstvs; } } tmp_win->old_parent_vs = tmp_win->vs; tmp_win->vs = NULL; } static void DisplayWin (virtualScreen *vs, TwmWindow *tmp_win) { XWindowAttributes winattrs; unsigned long eventMask; /* * A window cannot be shown in multiple virtual screens, even if * it occupies both corresponding workspaces. */ if (vs && tmp_win->vs) return; tmp_win->vs = vs; if (!tmp_win->mapped) { if (tmp_win->isicon) { if (tmp_win->icon_on) { if (tmp_win->icon && tmp_win->icon->w) { if (vs && vs != tmp_win->old_parent_vs) { int x, y; unsigned int junk; Window junkW, w = tmp_win->icon->w; XGetGeometry (dpy, w, &junkW, &x, &y, &junk, &junk, &junk, &junk); XReparentWindow (dpy, w, vs->window, x, y); } IconUp (tmp_win); XMapWindow (dpy, tmp_win->icon->w); return; } } } return; } if (tmp_win->UnmapByMovingFarAway) { if (vs) /* XXX I don't believe the handling of UnmapByMovingFarAway is quite correct */ XReparentWindow (dpy, tmp_win->frame, vs->window, tmp_win->frame_x, tmp_win->frame_y); else XMoveWindow (dpy, tmp_win->frame, tmp_win->frame_x, tmp_win->frame_y); } else { if (!tmp_win->squeezed) { XGetWindowAttributes(dpy, tmp_win->w, &winattrs); eventMask = winattrs.your_event_mask; XSelectInput (dpy, tmp_win->w, eventMask & ~StructureNotifyMask); XMapWindow (dpy, tmp_win->w); XSelectInput (dpy, tmp_win->w, eventMask); } if (vs && vs != tmp_win->old_parent_vs) { XReparentWindow (dpy, tmp_win->frame, vs->window, tmp_win->frame_x, tmp_win->frame_y); } XMapWindow (dpy, tmp_win->frame); SetMapStateProp (tmp_win, NormalState); } } void ChangeOccupation (TwmWindow *tmp_win, int newoccupation) { TwmWindow *t; virtualScreen *vs; WorkSpace *ws; int oldoccupation; char namelist [512]; int len; int final_x, final_y; XWindowAttributes winattrs; unsigned long eventMask; long gwkspc = 0; /* for gnome - the workspace of this window */ int changedoccupation; #ifdef GNOME unsigned char *prop; unsigned long bytesafter, numitems; Atom actual_type; int actual_format; #endif /* GNOME */ if ((newoccupation == 0) || /* in case the property has been broken by another client */ (newoccupation == tmp_win->occupation)) { len = GetPropertyFromMask (tmp_win->occupation, namelist, &gwkspc); XGetWindowAttributes(dpy, tmp_win->w, &winattrs); eventMask = winattrs.your_event_mask; XSelectInput(dpy, tmp_win->w, eventMask & ~PropertyChangeMask); XChangeProperty (dpy, tmp_win->w, _XA_WM_OCCUPATION, XA_STRING, 8, PropModeReplace, (unsigned char *) namelist, len); #ifdef GNOME XChangeProperty (dpy, tmp_win->w, _XA_WIN_WORKSPACE, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)(&gwkspc), 1); if (XGetWindowProperty(dpy, tmp_win->w, _XA_WIN_STATE, 0L, 32, False, XA_CARDINAL, &actual_type, &actual_format, &numitems, &bytesafter, &prop) != Success || numitems == 0) { gwkspc = 0; } else { gwkspc = (int)*prop; XFree((char *)prop); } if (tmp_win->occupation == fullOccupation) gwkspc |= WIN_STATE_STICKY; else gwkspc &= ~WIN_STATE_STICKY; XChangeProperty (dpy, tmp_win->w, _XA_WIN_STATE, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&gwkspc, 1); #endif /* GNOME */ XSelectInput (dpy, tmp_win->w, eventMask); return; } oldoccupation = tmp_win->occupation; tmp_win->occupation = newoccupation & ~oldoccupation; AddIconManager (tmp_win); tmp_win->occupation = newoccupation; RemoveIconManager (tmp_win); if (tmp_win->vs && !OCCUPY (tmp_win, tmp_win->vs->wsw->currentwspc)) { Vanish (tmp_win->vs, tmp_win); } /* * If a window occupies multiple workspaces, try to find another workspace * which is currently in another virtual screen, so that the window * can be shown there now. */ if (!tmp_win->vs) { for (vs = Scr->vScreenList; vs != NULL; vs = vs->next) { if (OCCUPY (tmp_win, vs->wsw->currentwspc)) { DisplayWin (vs, tmp_win); break; } } } for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { int mask = 1 << ws->number; if (oldoccupation & mask) { if (!(newoccupation & mask)) { RemoveWindowFromRegion (tmp_win); if (PlaceWindowInRegion (tmp_win, &final_x, &final_y)) XMoveWindow (dpy, tmp_win->frame, final_x, final_y); } break; } } len = GetPropertyFromMask (newoccupation, namelist, &gwkspc); XGetWindowAttributes(dpy, tmp_win->w, &winattrs); eventMask = winattrs.your_event_mask; XSelectInput(dpy, tmp_win->w, eventMask & ~PropertyChangeMask); XChangeProperty (dpy, tmp_win->w, _XA_WM_OCCUPATION, XA_STRING, 8, PropModeReplace, (unsigned char *) namelist, len); #ifdef GNOME /* Tell GNOME where this window lives */ XChangeProperty (dpy, tmp_win->w, _XA_WIN_WORKSPACE, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)(&gwkspc), 1); if (XGetWindowProperty (dpy, tmp_win->w, _XA_WIN_STATE, 0L, 32, False, XA_CARDINAL, &actual_type, &actual_format, &numitems, &bytesafter, &prop) != Success || numitems == 0) { gwkspc = 0; } else { gwkspc = (int)*prop; XFree ((char *)prop); } if (tmp_win->occupation == fullOccupation) gwkspc |= WIN_STATE_STICKY; else gwkspc &= ~WIN_STATE_STICKY; XChangeProperty (dpy, tmp_win->w, _XA_WIN_STATE, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&gwkspc, 1); #endif /* GNOME */ XSelectInput(dpy, tmp_win->w, eventMask); if (!WMapWindowMayBeAdded(tmp_win)) { newoccupation = 0; } if (Scr->workSpaceMgr.noshowoccupyall) { /* We can safely change new/oldoccupation here, it's only used * for WMapAddToList()/WMapRemoveFromList() from here on. */ /* if (newoccupation == fullOccupation) newoccupation = 0; */ if (oldoccupation == fullOccupation) oldoccupation = 0; } changedoccupation = oldoccupation ^ newoccupation; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { int mask = 1 << ws->number; if (changedoccupation & mask) { if (newoccupation & mask) { WMapAddToList (tmp_win, ws); } else { WMapRemoveFromList (tmp_win, ws); if (Scr->SaveWorkspaceFocus && ws->save_focus == tmp_win) { ws->save_focus = NULL; } } } } if (! Scr->TransientHasOccupation) { for (t = Scr->FirstWindow; t != NULL; t = t->next) { if (t != tmp_win && ((t->transient && t->transientfor == tmp_win->w) || t->group == tmp_win->w)) { ChangeOccupation (t, tmp_win->occupation); } } } } void WmgrRedoOccupation (TwmWindow *win) { WorkSpace *ws; int newoccupation; if (LookInList (Scr->OccupyAll, win->full_name, &win->class)) { newoccupation = fullOccupation; } else { newoccupation = 0; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { if (LookInList (ws->clientlist, win->full_name, &win->class)) { newoccupation |= 1 << ws->number; } } } if (newoccupation != 0) ChangeOccupation (win, newoccupation); } void WMgrRemoveFromCurrentWorkSpace (virtualScreen *vs, TwmWindow *win) { WorkSpace *ws; int newoccupation; ws = vs->wsw->currentwspc; if (! OCCUPY (win, ws)) return; newoccupation = win->occupation & ~(1 << ws->number); if (newoccupation == 0) return; ChangeOccupation (win, newoccupation); } void WMgrAddToCurrentWorkSpaceAndWarp (virtualScreen *vs, char *winname) { TwmWindow *tw; int newoccupation; for (tw = Scr->FirstWindow; tw != NULL; tw = tw->next) { if (match (winname, tw->full_name)) break; } if (!tw) { for (tw = Scr->FirstWindow; tw != NULL; tw = tw->next) { if (match (winname, tw->class.res_name)) break; } if (!tw) { for (tw = Scr->FirstWindow; tw != NULL; tw = tw->next) { if (match (winname, tw->class.res_class)) break; } } } if (!tw) { XBell (dpy, 0); return; } if ((! Scr->WarpUnmapped) && (! tw->mapped)) { XBell (dpy, 0); return; } if (! OCCUPY (tw, vs->wsw->currentwspc)) { newoccupation = tw->occupation | (1 << vs->wsw->currentwspc->number); ChangeOccupation (tw, newoccupation); } if (! tw->mapped) DeIconify (tw); WarpToWindow (tw, Scr->RaiseOnWarp); } static void CreateWorkSpaceManagerWindow (virtualScreen *vs) { int mask; int lines, vspace, hspace, count, columns; unsigned int width, height, bwidth, bheight; char *name, *icon_name, *geometry; int i, j; ColorPair cp; MyFont font; WorkSpace *ws; int x, y, strWid, wid; unsigned long border; TwmWindow *tmp_win; XSetWindowAttributes attr; XWindowAttributes wattr; unsigned long attrmask; XSizeHints sizehints; XWMHints wmhints; int gravity; XRectangle inc_rect; XRectangle logical_rect; name = Scr->workSpaceMgr.name; icon_name = Scr->workSpaceMgr.icon_name; geometry = Scr->workSpaceMgr.geometry; columns = Scr->workSpaceMgr.columns; vspace = Scr->workSpaceMgr.vspace; hspace = Scr->workSpaceMgr.hspace; font = Scr->workSpaceMgr.buttonFont; cp = Scr->workSpaceMgr.cp; border = Scr->workSpaceMgr.defBorderColor; count = 0; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) count++; Scr->workSpaceMgr.count = count; if (columns == 0) { lines = 2; columns = ((count - 1) / lines) + 1; } else { lines = ((count - 1) / columns) + 1; } Scr->workSpaceMgr.lines = lines; Scr->workSpaceMgr.columns = columns; strWid = 0; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { XmbTextExtents(font.font_set, ws->label, strlen (ws->label), &inc_rect, &logical_rect); wid = logical_rect.width; if (wid > strWid) strWid = wid; } if (geometry != NULL) { mask = XParseGeometry (geometry, &x, &y, &width, &height); bwidth = (mask & WidthValue) ? ((width - (columns * hspace)) / columns) : strWid + 10; bheight = (mask & HeightValue) ? ((height - (lines * vspace)) / lines) : 22; width = columns * (bwidth + hspace); height = lines * (bheight + vspace); if (! (mask & YValue)) { y = 0; mask |= YNegative; } if (mask & XValue) { if (mask & XNegative) { x += vs->w - width; gravity = (mask & YNegative) ? SouthEastGravity : NorthEastGravity; } else { gravity = (mask & YNegative) ? SouthWestGravity : NorthWestGravity; } } else { x = (vs->w - width) / 2; gravity = (mask & YValue) ? ((mask & YNegative) ? SouthGravity : NorthGravity) : SouthGravity; } if (mask & YNegative) y += vs->h - height; } else { bwidth = strWid + 2 * Scr->WMgrButtonShadowDepth + 6; bheight = 22; width = columns * (bwidth + hspace); height = lines * (bheight + vspace); x = (vs->w - width) / 2; y = vs->h - height; gravity = NorthWestGravity; } #define Dummy 1 vs->wsw->width = Dummy; vs->wsw->height = Dummy; vs->wsw->bswl = (ButtonSubwindow**) malloc (Scr->workSpaceMgr.count * sizeof (ButtonSubwindow*)); vs->wsw->mswl = (MapSubwindow**) malloc (Scr->workSpaceMgr.count * sizeof (MapSubwindow*)); vs->wsw->w = XCreateSimpleWindow (dpy, Scr->Root, x, y, width, height, 0, Scr->Black, cp.back); i = 0; j = 0; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { Window mapsw, butsw; MapSubwindow *msw; ButtonSubwindow *bsw; vs->wsw->bswl [ws->number] = bsw = (ButtonSubwindow*) malloc (sizeof (ButtonSubwindow)); vs->wsw->mswl [ws->number] = msw = (MapSubwindow*) malloc (sizeof (MapSubwindow)); butsw = bsw->w = XCreateSimpleWindow (dpy, vs->wsw->w, Dummy /* x */, Dummy /* y */, Dummy /* width */, Dummy /* height */, 0, Scr->Black, ws->cp.back); mapsw = msw->w = XCreateSimpleWindow (dpy, vs->wsw->w, Dummy /* x */, Dummy /* y */, Dummy /* width */, Dummy /* height */, 1, border, ws->cp.back); if (vs->wsw->state == BUTTONSSTATE) XMapWindow (dpy, butsw); else XMapWindow (dpy, mapsw); vs->wsw->mswl [ws->number]->wl = NULL; if (useBackgroundInfo) { if (ws->image == None || Scr->NoImagesInWorkSpaceManager) XSetWindowBackground (dpy, mapsw, ws->backcp.back); else XSetWindowBackgroundPixmap (dpy, mapsw, ws->image->pixmap); } else { if (Scr->workSpaceMgr.defImage == None || Scr->NoImagesInWorkSpaceManager) XSetWindowBackground (dpy, mapsw, Scr->workSpaceMgr.defColors.back); else XSetWindowBackgroundPixmap (dpy, mapsw, Scr->workSpaceMgr.defImage->pixmap); } XClearWindow (dpy, butsw); i++; if (i == columns) {i = 0; j++;}; } sizehints.flags = USPosition | PBaseSize | PMinSize | PResizeInc | PWinGravity; sizehints.x = x; sizehints.y = y; sizehints.base_width = columns * hspace; sizehints.base_height = lines * vspace; sizehints.width_inc = columns; sizehints.height_inc = lines; sizehints.min_width = columns * (hspace + 2); sizehints.min_height = lines * (vspace + 2); sizehints.win_gravity = gravity; XSetStandardProperties (dpy, vs->wsw->w, name, icon_name, None, NULL, 0, NULL); XSetWMSizeHints (dpy, vs->wsw->w, &sizehints, XA_WM_NORMAL_HINTS); wmhints.flags = InputHint | StateHint; wmhints.input = True; wmhints.initial_state = NormalState; XSetWMHints (dpy, vs->wsw->w, &wmhints); XSaveContext (dpy, vs->wsw->w, VirtScreenContext, (XPointer) vs); tmp_win = AddWindow (vs->wsw->w, 3, Scr->iconmgr); if (! tmp_win) { fprintf (stderr, "cannot create workspace manager window, exiting...\n"); exit (1); } tmp_win->occupation = fullOccupation; tmp_win->vs = vs; tmp_win->attr.width = width; tmp_win->attr.height = height; ResizeWorkSpaceManager(vs, tmp_win); attrmask = 0; attr.cursor = Scr->ButtonCursor; attrmask |= CWCursor; attr.win_gravity = gravity; attrmask |= CWWinGravity; XChangeWindowAttributes (dpy, vs->wsw->w, attrmask, &attr); XGetWindowAttributes (dpy, vs->wsw->w, &wattr); attrmask = wattr.your_event_mask | KeyPressMask | KeyReleaseMask | ExposureMask; XSelectInput (dpy, vs->wsw->w, attrmask); for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { Window buttonw = vs->wsw->bswl [ws->number]->w; Window mapsubw = vs->wsw->mswl [ws->number]->w; XSelectInput (dpy, buttonw, ButtonPressMask | ButtonReleaseMask | ExposureMask); XSaveContext (dpy, buttonw, TwmContext, (XPointer) tmp_win); XSaveContext (dpy, buttonw, ScreenContext, (XPointer) Scr); XSelectInput (dpy, mapsubw, ButtonPressMask | ButtonReleaseMask); XSaveContext (dpy, mapsubw, TwmContext, (XPointer) tmp_win); XSaveContext (dpy, mapsubw, ScreenContext, (XPointer) Scr); } SetMapStateProp (tmp_win, WithdrawnState); vs->wsw->twm_win = tmp_win; ws = Scr->workSpaceMgr.workSpaceList; if (useBackgroundInfo && ! Scr->DontPaintRootWindow) { if (ws->image == None) XSetWindowBackground (dpy, Scr->Root, ws->backcp.back); else XSetWindowBackgroundPixmap (dpy, Scr->Root, ws->image->pixmap); XClearWindow (dpy, Scr->Root); } PaintWorkSpaceManager (vs); } void WMgrHandleExposeEvent (virtualScreen *vs, XEvent *event) { WorkSpace *ws; Window buttonw; if (vs->wsw->state == BUTTONSSTATE) { for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { buttonw = vs->wsw->bswl [ws->number]->w; if (event->xexpose.window == buttonw) break; } if (ws == NULL) { PaintWorkSpaceManagerBorder (vs); } else if (ws == vs->wsw->currentwspc) PaintButton (WSPCWINDOW, vs, buttonw, ws->label, ws->cp, on); else PaintButton (WSPCWINDOW, vs, buttonw, ws->label, ws->cp, off); } else { WinList wl; if (XFindContext (dpy, event->xexpose.window, MapWListContext, (XPointer *) &wl) == XCNOENT) return; if (wl && wl->twm_win && wl->twm_win->mapped) { WMapRedrawName (vs, wl); } } } void PaintWorkSpaceManager (virtualScreen *vs) { WorkSpace *ws; PaintWorkSpaceManagerBorder (vs); for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { Window buttonw = vs->wsw->bswl [ws->number]->w; if (ws == vs->wsw->currentwspc) PaintButton (WSPCWINDOW, vs, buttonw, ws->label, ws->cp, on); else PaintButton (WSPCWINDOW, vs, buttonw, ws->label, ws->cp, off); } } static void PaintWorkSpaceManagerBorder (virtualScreen *vs) { int width, height; width = vs->wsw->width; height = vs->wsw->height; Draw3DBorder (vs->wsw->w, 0, 0, width, height, 2, Scr->workSpaceMgr.cp, off, True, False); } ColorPair occupyButtoncp; char *ok_string = "OK", *cancel_string = "Cancel", *everywhere_string = "All"; /* * Create the Occupy window. Do not do the layout of the parts, only * calculate the inial total size. For the layout, call ResizeOccupyWindow() * at the end. * There is only one Occupy window (per Screen), it is reparented to each * virtual screen as needed. */ static void CreateOccupyWindow (void) { int width, height, lines, columns; int bwidth, bheight, owidth, oheight, hspace, vspace; int min_bwidth, min_width; int i, j; Window w, OK, cancel, allworkspc; char *name, *icon_name; ColorPair cp; TwmWindow *tmp_win; WorkSpace *ws; XSizeHints sizehints; XWMHints wmhints; MyFont font; XSetWindowAttributes attr; XWindowAttributes wattr; unsigned long attrmask; OccupyWindow *occwin; virtualScreen *vs; XRectangle inc_rect; XRectangle logical_rect; occwin = Scr->workSpaceMgr.occupyWindow; occwin->font = Scr->IconManagerFont; occwin->cp = Scr->IconManagerC; #ifdef COLOR_BLIND_USER occwin->cp.shadc = Scr->White; occwin->cp.shadd = Scr->Black; #else if (!Scr->BeNiceToColormap) GetShadeColors (&occwin->cp); #endif vs = Scr->vScreenList; name = occwin->name; icon_name = occwin->icon_name; lines = Scr->workSpaceMgr.lines; columns = Scr->workSpaceMgr.columns; bwidth = vs->wsw->bwidth; bheight = vs->wsw->bheight; oheight = bheight; vspace = occwin->vspace; hspace = occwin->hspace; cp = occwin->cp; height = ((bheight + vspace) * lines) + oheight + (2 * vspace); font = occwin->font; XmbTextExtents(font.font_set, ok_string, strlen(ok_string), &inc_rect, &logical_rect); min_bwidth = logical_rect.width; XmbTextExtents(font.font_set, cancel_string, strlen (cancel_string), &inc_rect, &logical_rect); i = logical_rect.width; if (i > min_bwidth) min_bwidth = i; XmbTextExtents(font.font_set,everywhere_string, strlen (everywhere_string), &inc_rect, &logical_rect); i = logical_rect.width; if (i > min_bwidth) min_bwidth = i; min_bwidth = (min_bwidth + hspace); /* normal width calculation */ width = columns * (bwidth + hspace); min_width = 3 * (min_bwidth + hspace); /* width by text width */ if (columns < 3) { owidth = min_bwidth + 2 * Scr->WMgrButtonShadowDepth + 2; if (width < min_width) width = min_width; bwidth = (width - columns * hspace) / columns; } else { owidth = min_bwidth + 2 * Scr->WMgrButtonShadowDepth + 2; width = columns * (bwidth + hspace); } occwin->lines = lines; occwin->columns = columns; occwin->owidth = owidth; w = occwin->w = XCreateSimpleWindow (dpy, Scr->Root, 0, 0, width, height, 1, Scr->Black, cp.back); occwin->obuttonw = (Window*) malloc (Scr->workSpaceMgr.count * sizeof (Window)); i = 0; j = 0; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { Window bw = occwin->obuttonw [j * columns + i] = XCreateSimpleWindow(dpy, w, Dummy /* x */, Dummy /* y */, Dummy /* width */, Dummy /* height */, 0, Scr->Black, ws->cp.back); XMapWindow (dpy, bw); i++; if (i == columns) {i = 0; j++;} } GetColor (Scr->Monochrome, &(occupyButtoncp.back), "gray50"); occupyButtoncp.fore = Scr->White; if (!Scr->BeNiceToColormap) GetShadeColors (&occupyButtoncp); OK = XCreateSimpleWindow (dpy, w, Dummy, Dummy, Dummy, Dummy, 0, Scr->Black, occupyButtoncp.back); XMapWindow (dpy, OK); cancel = XCreateSimpleWindow (dpy, w, Dummy, Dummy, Dummy, Dummy, 0, Scr->Black, occupyButtoncp.back); XMapWindow (dpy, cancel); allworkspc = XCreateSimpleWindow (dpy, w, Dummy, Dummy, Dummy, Dummy, 0, Scr->Black, occupyButtoncp.back); XMapWindow (dpy, allworkspc); occwin->OK = OK; occwin->cancel = cancel; occwin->allworkspc = allworkspc; sizehints.flags = PBaseSize | PMinSize | PResizeInc; sizehints.base_width = columns; sizehints.base_height = lines; sizehints.width_inc = columns; sizehints.height_inc = lines; sizehints.min_width = 2 * columns; sizehints.min_height = 2 * lines; XSetStandardProperties (dpy, w, name, icon_name, None, NULL, 0, &sizehints); wmhints.flags = InputHint | StateHint; wmhints.input = True; wmhints.initial_state = NormalState; XSetWMHints (dpy, w, &wmhints); tmp_win = AddWindow (w, FALSE, Scr->iconmgr); if (! tmp_win) { fprintf (stderr, "cannot create occupy window, exiting...\n"); exit (1); } tmp_win->vs = None; tmp_win->occupation = 0; attrmask = 0; attr.cursor = Scr->ButtonCursor; attrmask |= CWCursor; XChangeWindowAttributes (dpy, w, attrmask, &attr); XGetWindowAttributes (dpy, w, &wattr); attrmask = wattr.your_event_mask | KeyPressMask | KeyReleaseMask | ExposureMask; XSelectInput (dpy, w, attrmask); for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { Window bw = occwin->obuttonw [ws->number]; XSelectInput (dpy, bw, ButtonPressMask | ButtonReleaseMask | ExposureMask); XSaveContext (dpy, bw, TwmContext, (XPointer) tmp_win); XSaveContext (dpy, bw, ScreenContext, (XPointer) Scr); } XSelectInput (dpy, occwin->OK, ButtonPressMask | ButtonReleaseMask | ExposureMask); XSaveContext (dpy, occwin->OK, TwmContext, (XPointer) tmp_win); XSaveContext (dpy, occwin->OK, ScreenContext, (XPointer) Scr); XSelectInput (dpy, occwin->cancel, ButtonPressMask | ButtonReleaseMask | ExposureMask); XSaveContext (dpy, occwin->cancel, TwmContext, (XPointer) tmp_win); XSaveContext (dpy, occwin->cancel, ScreenContext, (XPointer) Scr); XSelectInput (dpy, occwin->allworkspc, ButtonPressMask | ButtonReleaseMask | ExposureMask); XSaveContext (dpy, occwin->allworkspc, TwmContext, (XPointer) tmp_win); XSaveContext (dpy, occwin->allworkspc, ScreenContext, (XPointer) Scr); SetMapStateProp (tmp_win, WithdrawnState); occwin->twm_win = tmp_win; Scr->workSpaceMgr.occupyWindow = occwin; tmp_win->attr.width = width; tmp_win->attr.height = height; ResizeOccupyWindow(tmp_win); /* place all parts in the right place */ } void PaintOccupyWindow (void) { WorkSpace *ws; OccupyWindow *occwin; int width, height; occwin = Scr->workSpaceMgr.occupyWindow; width = occwin->width; height = occwin->height; Draw3DBorder (occwin->w, 0, 0, width, height, 2, occwin->cp, off, True, False); for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { Window bw = occwin->obuttonw [ws->number]; if (occwin->tmpOccupation & (1 << ws->number)) PaintButton (OCCUPYWINDOW, NULL, bw, ws->label, ws->cp, on); else PaintButton (OCCUPYWINDOW, NULL, bw, ws->label, ws->cp, off); } PaintButton (OCCUPYBUTTON, NULL, occwin->OK, ok_string, occupyButtoncp, off); PaintButton (OCCUPYBUTTON, NULL, occwin->cancel, cancel_string, occupyButtoncp, off); PaintButton (OCCUPYBUTTON, NULL, occwin->allworkspc, everywhere_string, occupyButtoncp, off); } static void PaintButton (int which, virtualScreen *vs, Window w, char *label, ColorPair cp, int state) { OccupyWindow *occwin; int bwidth, bheight; MyFont font; int strWid, strHei, hspace, vspace; XRectangle inc_rect; XRectangle logical_rect; occwin = Scr->workSpaceMgr.occupyWindow; if (which == WSPCWINDOW) { bwidth = vs->wsw->bwidth; bheight = vs->wsw->bheight; font = Scr->workSpaceMgr.buttonFont; } else if (which == OCCUPYWINDOW) { bwidth = occwin->bwidth; bheight = occwin->bheight; font = occwin->font; } else if (which == OCCUPYBUTTON) { bwidth = occwin->owidth; bheight = occwin->bheight; font = occwin->font; } else return; XmbTextExtents(font.font_set, label, strlen (label), &inc_rect, &logical_rect); strHei = logical_rect.height; vspace = ((bheight + strHei - font.descent) / 2); strWid = logical_rect.width; hspace = (bwidth - strWid) / 2; if (hspace < (Scr->WMgrButtonShadowDepth + 1)) hspace = Scr->WMgrButtonShadowDepth + 1; XClearWindow (dpy, w); if (Scr->Monochrome == COLOR) { Draw3DBorder (w, 0, 0, bwidth, bheight, Scr->WMgrButtonShadowDepth, cp, state, True, False); switch (Scr->workSpaceMgr.buttonStyle) { case STYLE_NORMAL : break; case STYLE_STYLE1 : Draw3DBorder (w, Scr->WMgrButtonShadowDepth - 1, Scr->WMgrButtonShadowDepth - 1, bwidth - 2 * Scr->WMgrButtonShadowDepth + 2, bheight - 2 * Scr->WMgrButtonShadowDepth + 2, 1, cp, (state == on) ? off : on, True, False); break; case STYLE_STYLE2 : Draw3DBorder (w, Scr->WMgrButtonShadowDepth / 2, Scr->WMgrButtonShadowDepth / 2, bwidth - Scr->WMgrButtonShadowDepth, bheight - Scr->WMgrButtonShadowDepth, 1, cp, (state == on) ? off : on, True, False); break; case STYLE_STYLE3 : Draw3DBorder (w, 1, 1, bwidth - 2, bheight - 2, 1, cp, (state == on) ? off : on, True, False); break; } FB (cp.fore, cp.back); XmbDrawString (dpy, w, font.font_set, Scr->NormalGC, hspace, vspace, label, strlen (label)); } else { Draw3DBorder (w, 0, 0, bwidth, bheight, Scr->WMgrButtonShadowDepth, cp, state, True, False); if (state == on) { FB (cp.fore, cp.back); XmbDrawImageString (dpy, w, font.font_set, Scr->NormalGC, hspace, vspace, label, strlen (label)); } else { FB (cp.back, cp.fore); XmbDrawImageString (dpy, w, font.font_set, Scr->NormalGC, hspace, vspace, label, strlen (label)); } } } static unsigned int GetMaskFromResource (TwmWindow *win, char *res) { char *name; char wrkSpcName [64]; WorkSpace *ws; int mask, num, mode; mode = 0; if (*res == '+') { mode = 1; res++; } else if (*res == '-') { mode = 2; res++; } mask = 0; while (*res != '\0') { while (*res == ' ') res++; if (*res == '\0') break; name = wrkSpcName; while ((*res != '\0') && (*res != ' ')) { if (*res == '\\') res++; *name = *res; name++; res++; } *name = '\0'; if (strcmp (wrkSpcName, "all") == 0) { mask = fullOccupation; break; } if (strcmp (wrkSpcName, "current") == 0) { virtualScreen *vs = Scr->currentvs; if (vs) mask |= (1 << vs->wsw->currentwspc->number); continue; } num = 0; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { if (strcmp (wrkSpcName, ws->label) == 0) break; num++; } if (ws != NULL) mask |= (1 << num); else { twmrc_error_prefix (); fprintf (stderr, "unknown workspace : %s\n", wrkSpcName); } } switch (mode) { case 0 : return (mask); case 1 : return (mask | win->occupation); case 2 : return (win->occupation & ~mask); } return (0); /* Never supposed to reach here, but just in case... */ } unsigned int GetMaskFromProperty (unsigned char *prop, unsigned long len) { char wrkSpcName [256]; WorkSpace *ws; unsigned int mask; int num, l; mask = 0; l = 0; while (l < len) { strcpy (wrkSpcName, (char *)prop); l += strlen ((char *)prop) + 1; prop += strlen ((char *)prop) + 1; if (strcmp (wrkSpcName, "all") == 0) { mask = fullOccupation; break; } num = 0; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { if (strcmp (wrkSpcName, ws->label) == 0) break; num++; } if (ws == NULL) { fprintf (stderr, "unknown workspace : %s\n", wrkSpcName); } else { mask |= (1 << num); } } return (mask); } static int GetPropertyFromMask (unsigned int mask, char *prop, long *gwkspc) { WorkSpace *ws; int len; char *p; if (mask == fullOccupation) { strcpy (prop, "all"); return (3); } len = 0; p = prop; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { if (mask & (1 << ws->number)) { strcpy (p, ws->label); p += strlen (ws->label) + 1; len += strlen (ws->label) + 1; *gwkspc = ws->number; } } return (len); } void AddToClientsList (char *workspace, char *client) { WorkSpace *ws; if (strcmp (workspace, "all") == 0) { for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { AddToList (&ws->clientlist, client, ""); } return; } for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { if (strcmp (ws->label, workspace) == 0) break; } if (ws == NULL) return; AddToList (&ws->clientlist, client, ""); } void WMapToggleState (virtualScreen *vs) { if (vs->wsw->state == BUTTONSSTATE) { WMapSetMapState (vs); } else { WMapSetButtonsState (vs); } } void WMapSetMapState (virtualScreen *vs) { WorkSpace *ws; if (vs->wsw->state == MAPSTATE) return; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { XUnmapWindow (dpy, vs->wsw->bswl [ws->number]->w); XMapWindow (dpy, vs->wsw->mswl [ws->number]->w); } vs->wsw->state = MAPSTATE; MaybeAnimate = True; } void WMapSetButtonsState (virtualScreen *vs) { WorkSpace *ws; if (vs->wsw->state == BUTTONSSTATE) return; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { XUnmapWindow (dpy, vs->wsw->mswl [ws->number]->w); XMapWindow (dpy, vs->wsw->bswl [ws->number]->w); } vs->wsw->state = BUTTONSSTATE; } /* * Verify if a window may be added to the workspace map. * This is not allowed for * - icon managers * - the occupy window * - workspace manager windows * - or, optionally, windows with full occupation. */ int WMapWindowMayBeAdded(TwmWindow *win) { if (win->iconmgr) return 0; if (win == Scr->workSpaceMgr.occupyWindow->twm_win) return 0; if (win->wspmgr) return 0; if (Scr->workSpaceMgr.noshowoccupyall && win->occupation == fullOccupation) return 0; return 1; } void WMapAddWindow (TwmWindow *win) { WorkSpace *ws; if (!WMapWindowMayBeAdded(win)) return; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { if (OCCUPY (win, ws)) WMapAddToList (win, ws); } } void WMapDestroyWindow (TwmWindow *win) { WorkSpace *ws; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { if (OCCUPY (win, ws)) WMapRemoveFromList (win, ws); } if (win == occupyWin) { OccupyWindow *occwin = Scr->workSpaceMgr.occupyWindow; XUnmapWindow (dpy, occwin->twm_win->frame); occwin->twm_win->mapped = FALSE; occwin->twm_win->occupation = 0; occupyWin = (TwmWindow*) 0; } } void WMapMapWindow (TwmWindow *win) { virtualScreen *vs; WorkSpace *ws; WinList wl; for (vs = Scr->vScreenList; vs != NULL; vs = vs->next) { for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { for (wl = vs->wsw->mswl [ws->number]->wl; wl != NULL; wl = wl->next) { if (wl->twm_win == win) { XMapWindow (dpy, wl->w); WMapRedrawName (vs, wl); break; } } } } } void WMapSetupWindow (TwmWindow *win, int x, int y, int w, int h) { virtualScreen *vs; WorkSpace *ws; WinList wl; float wf, hf; if (win->iconmgr) return; if (!win->vs) return; if (win->wspmgr) { if (w == -1) return; ResizeWorkSpaceManager (win->vs, win); return; } if (win == Scr->workSpaceMgr.occupyWindow->twm_win) { if (w == -1) return; ResizeOccupyWindow (win); return; } for (vs = Scr->vScreenList; vs != NULL; vs = vs->next) { WorkSpaceWindow *wsw = vs->wsw; wf = (float) (wsw->wwidth - 2) / (float) vs->w; hf = (float) (wsw->wheight - 2) / (float) vs->h; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { for (wl = wsw->mswl [ws->number]->wl; wl != NULL; wl = wl->next) { if (win == wl->twm_win) { wl->x = (int) (x * wf); wl->y = (int) (y * hf); if (w == -1) { XMoveWindow (dpy, wl->w, wl->x, wl->y); } else { wl->width = (unsigned int) ((w * wf) + 0.5); wl->height = (unsigned int) ((h * hf) + 0.5); if (!Scr->use3Dwmap) { wl->width -= 2; wl->height -= 2; } if (wl->width < 1) wl->width = 1; if (wl->height < 1) wl->height = 1; XMoveResizeWindow (dpy, wl->w, wl->x, wl->y, wl->width, wl->height); } break; } } } } } void WMapIconify (TwmWindow *win) { WorkSpace *ws; WinList wl; if (!win->vs) return; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { for (wl = win->vs->wsw->mswl [ws->number]->wl; wl != NULL; wl = wl->next) { if (win == wl->twm_win) { XUnmapWindow (dpy, wl->w); break; } } } } void WMapDeIconify (TwmWindow *win) { WorkSpace *ws; WinList wl; if (!win->vs) return; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { for (wl = win->vs->wsw->mswl [ws->number]->wl; wl != NULL; wl = wl->next) { if (win == wl->twm_win) { if (Scr->NoRaiseDeicon) XMapWindow (dpy, wl->w); else XMapRaised (dpy, wl->w); WMapRedrawName (win->vs, wl); break; } } } } void WMapRaiseLower (TwmWindow *win) { WorkSpace *ws; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { if (OCCUPY (win, ws)) WMapRestack (ws); } } void WMapLower (TwmWindow *win) { WorkSpace *ws; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { if (OCCUPY (win, ws)) WMapRestack (ws); } } void WMapRaise (TwmWindow *win) { WorkSpace *ws; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { if (OCCUPY (win, ws)) WMapRestack (ws); } } void WMapRestack (WorkSpace *ws) { virtualScreen *vs; TwmWindow *win; WinList wl; Window root; Window parent; Window *children, *smallws; unsigned int number; int i, j; number = 0; XQueryTree (dpy, Scr->Root, &root, &parent, &children, &number); smallws = (Window*) malloc (number * sizeof (Window)); for (vs = Scr->vScreenList; vs != NULL; vs = vs->next) { j = 0; for (i = number - 1; i >= 0; i--) { if (!(win = GetTwmWindow(children [i]))) { continue; } if (win->frame != children [i]) continue; /* skip icons */ if (! OCCUPY (win, ws)) continue; if (tracefile) { fprintf (tracefile, "WMapRestack : w = %lx, win = %p\n", children [i], (void *)win); fflush (tracefile); } for (wl = vs->wsw->mswl [ws->number]->wl; wl != NULL; wl = wl->next) { if (tracefile) { fprintf (tracefile, "WMapRestack : wl = %p, twm_win = %p\n", (void *)wl, (void *)wl->twm_win); fflush (tracefile); } if (win == wl->twm_win) { smallws [j++] = wl->w; break; } } } XRestackWindows (dpy, smallws, j); } XFree ((char *) children); free (smallws); return; } void WMapUpdateIconName (TwmWindow *win) { virtualScreen *vs; WorkSpace *ws; WinList wl; for (vs = Scr->vScreenList; vs != NULL; vs = vs->next) { for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { for (wl = vs->wsw->mswl [ws->number]->wl; wl != NULL; wl = wl->next) { if (win == wl->twm_win) { WMapRedrawName (vs, wl); break; } } } } } void WMgrHandleKeyReleaseEvent (virtualScreen *vs, XEvent *event) { char *keyname; KeySym keysym; keysym = XLookupKeysym ((XKeyEvent*) event, 0); if (! keysym) return; keyname = XKeysymToString (keysym); if (! keyname) return; if ((strcmp (keyname, "Control_R") == 0) || (strcmp (keyname, "Control_L") == 0)) { /* DontToggleWorkSpaceManagerState added 20040607 by dl*/ if (!donttoggleworkspacemanagerstate) { WMapToggleState (vs); } return; } } void WMgrHandleKeyPressEvent (virtualScreen *vs, XEvent *event) { WorkSpace *ws; int len, i, lname; char key [16]; unsigned char k; char name [128]; char *keyname; KeySym keysym; keysym = XLookupKeysym ((XKeyEvent*) event, 0); if (! keysym) return; keyname = XKeysymToString (keysym); if (! keyname) return; if ((strcmp (keyname, "Control_R") == 0) || (strcmp (keyname, "Control_L") == 0)) { /* DontToggleWorkSpaceManagerState added 20040607 by dl*/ if (!donttoggleworkspacemanagerstate) { WMapToggleState (vs); } return; } if (vs->wsw->state == MAPSTATE) return; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { if (vs->wsw->bswl [ws->number]->w == event->xkey.subwindow) break; } if (ws == NULL) return; strcpy (name, ws->label); lname = strlen (name); len = XLookupString (&(event->xkey), key, 16, NULL, NULL); for (i = 0; i < len; i++) { k = key [i]; if (isprint (k)) { name [lname++] = k; } else if ((k == 127) || (k == 8)) { if (lname != 0) lname--; } else break; } name [lname] = '\0'; ws->label = realloc (ws->label, (strlen (name) + 1)); strcpy (ws->label, name); if (ws == vs->wsw->currentwspc) PaintButton (WSPCWINDOW, vs, vs->wsw->bswl [ws->number]->w, ws->label, ws->cp, on); else PaintButton (WSPCWINDOW, vs, vs->wsw->bswl [ws->number]->w, ws->label, ws->cp, off); } void WMgrHandleButtonEvent (virtualScreen *vs, XEvent *event) { WorkSpaceWindow *mw; WorkSpace *ws, *oldws, *newws, *cws; WinList wl; TwmWindow *win; int occupation; unsigned int W0, H0, bw; int cont; XEvent ev; Window w, sw, parent; int X0, Y0, X1, Y1, XW, YW, XSW, YSW; Position newX = 0, newY = 0, winX = 0, winY = 0; Window junkW; unsigned int junk; unsigned int button; unsigned int modifier; XSetWindowAttributes attrs; float wf, hf; Boolean alreadyvivible, realmovemode, startincurrent; Time etime; parent = event->xbutton.window; sw = event->xbutton.subwindow; mw = vs->wsw; button = event->xbutton.button; modifier = event->xbutton.state; etime = event->xbutton.time; if (vs->wsw->state == BUTTONSSTATE) { for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { if (vs->wsw->bswl [ws->number]->w == parent) break; } if (ws == NULL) return; GotoWorkSpace (vs, ws); return; } for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { if (vs->wsw->mswl [ws->number]->w == parent) break; } if (ws == NULL) return; if (sw == (Window) 0) { GotoWorkSpace (vs, ws); return; } oldws = ws; if (XFindContext (dpy, sw, MapWListContext, (XPointer *) &wl) == XCNOENT) return; win = wl->twm_win; if ((! Scr->TransientHasOccupation) && win->transient) return; XTranslateCoordinates (dpy, Scr->Root, sw, event->xbutton.x_root, event->xbutton.y_root, &XW, &YW, &junkW); realmovemode = ( Scr->ReallyMoveInWorkspaceManager && !(modifier & ShiftMask)) || (!Scr->ReallyMoveInWorkspaceManager && (modifier & ShiftMask)); startincurrent = (oldws == vs->wsw->currentwspc); if (win->OpaqueMove) { int sw2, ss; sw2 = win->frame_width * win->frame_height; ss = vs->w * vs->h; if (sw2 > ((ss * Scr->OpaqueMoveThreshold) / 100)) Scr->OpaqueMove = FALSE; else Scr->OpaqueMove = TRUE; } else { Scr->OpaqueMove = FALSE; } switch (button) { case 1 : XUnmapWindow (dpy, sw); break; case 2 : XGetGeometry (dpy, sw, &junkW, &X0, &Y0, &W0, &H0, &bw, &junk); XTranslateCoordinates (dpy, vs->wsw->mswl [oldws->number]->w, mw->w, X0, Y0, &X1, &Y1, &junkW); attrs.event_mask = ExposureMask; attrs.background_pixel = wl->cp.back; attrs.border_pixel = wl->cp.back; w = XCreateWindow (dpy, mw->w, X1, Y1, W0, H0, bw, CopyFromParent, (unsigned int) CopyFromParent, (Visual *) CopyFromParent, CWEventMask | CWBackPixel | CWBorderPixel, &attrs); XMapRaised (dpy, w); WMapRedrawWindow (w, W0, H0, wl->cp, wl->twm_win->icon_name); if (realmovemode && Scr->ShowWinWhenMovingInWmgr) { if (Scr->OpaqueMove) { DisplayWin (vs, win); } else { MoveOutline (Scr->Root, win->frame_x - win->frame_bw, win->frame_y - win->frame_bw, win->frame_width + 2 * win->frame_bw, win->frame_height + 2 * win->frame_bw, win->frame_bw, win->title_height + win->frame_bw3D); } } break; case 3 : occupation = win->occupation & ~(1 << oldws->number); ChangeOccupation (win, occupation); return; default : return; } wf = (float) (mw->wwidth - 1) / (float) vs->w; hf = (float) (mw->wheight - 1) / (float) vs->h; XGrabPointer (dpy, mw->w, False, ButtonPressMask | ButtonMotionMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, mw->w, Scr->MoveCursor, CurrentTime); alreadyvivible = False; cont = TRUE; while (cont) { MapSubwindow *msw; XMaskEvent (dpy, ButtonPressMask | ButtonMotionMask | ButtonReleaseMask | ExposureMask, &ev); switch (ev.xany.type) { case ButtonPress : case ButtonRelease : if (ev.xbutton.button != button) break; cont = FALSE; newX = ev.xbutton.x; newY = ev.xbutton.y; case MotionNotify : if (cont) { newX = ev.xmotion.x; newY = ev.xmotion.y; } if (realmovemode) { for (cws = Scr->workSpaceMgr.workSpaceList; cws != NULL; cws = cws->next) { msw = vs->wsw->mswl [cws->number]; if ((newX >= msw->x) && (newX < msw->x + mw->wwidth) && (newY >= msw->y) && (newY < msw->y + mw->wheight)) { break; } } if (!cws) break; winX = newX - XW; winY = newY - YW; msw = vs->wsw->mswl [cws->number]; XTranslateCoordinates (dpy, mw->w, msw->w, winX, winY, &XSW, &YSW, &junkW); winX = (int) (XSW / wf); winY = (int) (YSW / hf); if (Scr->DontMoveOff) { int width = win->frame_width; int height = win->frame_height; if ((winX < Scr->BorderLeft) && ((Scr->MoveOffResistance < 0) || (winX > Scr->BorderLeft - Scr->MoveOffResistance))) { winX = Scr->BorderLeft; newX = msw->x + XW + Scr->BorderLeft * mw->wwidth / vs->w; } if (((winX + width) > vs->w - Scr->BorderRight) && ((Scr->MoveOffResistance < 0) || ((winX + width) < vs->w - Scr->BorderRight + Scr->MoveOffResistance))) { winX = vs->w - Scr->BorderRight - width; newX = msw->x + mw->wwidth * (1 - Scr->BorderRight / (double) vs->w) - wl->width + XW - 2; } if ((winY < Scr->BorderTop) && ((Scr->MoveOffResistance < 0) || (winY > Scr->BorderTop - Scr->MoveOffResistance))) { winY = Scr->BorderTop; newY = msw->y + YW + Scr->BorderTop * mw->height / vs->h; } if (((winY + height) > vs->h - Scr->BorderBottom) && ((Scr->MoveOffResistance < 0) || ((winY + height) < vs->h - Scr->BorderBottom + Scr->MoveOffResistance))) { winY = vs->h - Scr->BorderBottom - height; newY = msw->y + mw->wheight * (1 - Scr->BorderBottom / (double) vs->h) - wl->height + YW - 2; } } WMapSetupWindow (win, winX, winY, -1, -1); if (Scr->ShowWinWhenMovingInWmgr) goto movewin; if (cws == vs->wsw->currentwspc) { if (alreadyvivible) goto movewin; if (Scr->OpaqueMove) { XMoveWindow (dpy, win->frame, winX, winY); DisplayWin (vs, win); } else { MoveOutline (Scr->Root, winX - win->frame_bw, winY - win->frame_bw, win->frame_width + 2 * win->frame_bw, win->frame_height + 2 * win->frame_bw, win->frame_bw, win->title_height + win->frame_bw3D); } alreadyvivible = True; goto move; } if (!alreadyvivible) goto move; if (!OCCUPY (win, vs->wsw->currentwspc) || (startincurrent && (button == 1))) { if (Scr->OpaqueMove) { Vanish (vs, win); XMoveWindow (dpy, win->frame, winX, winY); } else { MoveOutline (Scr->Root, 0, 0, 0, 0, 0, 0); } alreadyvivible = False; goto move; } movewin: if (Scr->OpaqueMove) { XMoveWindow (dpy, win->frame, winX, winY); } else { MoveOutline (Scr->Root, winX - win->frame_bw, winY - win->frame_bw, win->frame_width + 2 * win->frame_bw, win->frame_height + 2 * win->frame_bw, win->frame_bw, win->title_height + win->frame_bw3D); } } move: XMoveWindow (dpy, w, newX - XW, newY - YW); break; case Expose : if (ev.xexpose.window == w) { WMapRedrawWindow (w, W0, H0, wl->cp, wl->twm_win->icon_name); break; } Event = ev; DispatchEvent (); break; } } if (realmovemode) { if (Scr->ShowWinWhenMovingInWmgr || alreadyvivible) { if (Scr->OpaqueMove && !OCCUPY (win, vs->wsw->currentwspc)) { Vanish (vs, win); } if (!Scr->OpaqueMove) { MoveOutline (Scr->Root, 0, 0, 0, 0, 0, 0); WMapRedrawName (vs, wl); } } SetupWindow (win, winX, winY, win->frame_width, win->frame_height, -1); } ev.xbutton.subwindow = (Window) 0; ev.xbutton.window = parent; XPutBackEvent (dpy, &ev); XUngrabPointer (dpy, CurrentTime); if ((ev.xbutton.time - etime) < 250) { KeyCode control_L_code, control_R_code; KeySym control_L_sym, control_R_sym; char keys [32]; XMapWindow (dpy, sw); XDestroyWindow (dpy, w); GotoWorkSpace (vs, ws); if (!Scr->DontWarpCursorInWMap) WarpToWindow (win, Scr->RaiseOnWarp); control_L_sym = XStringToKeysym ("Control_L"); control_R_sym = XStringToKeysym ("Control_R"); control_L_code = XKeysymToKeycode (dpy, control_L_sym); control_R_code = XKeysymToKeycode (dpy, control_R_sym); XQueryKeymap (dpy, keys); if ((keys [control_L_code / 8] & ((char) 0x80 >> (control_L_code % 8))) || keys [control_R_code / 8] & ((char) 0x80 >> (control_R_code % 8))) { WMapToggleState (vs); } return; } for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { MapSubwindow *msw = vs->wsw->mswl [ws->number]; if ((newX >= msw->x) && (newX < msw->x + mw->wwidth) && (newY >= msw->y) && (newY < msw->y + mw->wheight)) { break; } } newws = ws; switch (button) { case 1 : if ((newws == NULL) || (newws == oldws) || OCCUPY (wl->twm_win, newws)) { XMapWindow (dpy, sw); break; } occupation = (win->occupation | (1 << newws->number)) & ~(1 << oldws->number); ChangeOccupation (win, occupation); if (newws == vs->wsw->currentwspc) { RaiseWindow (win); WMapRaise (win); } else WMapRestack (newws); break; case 2 : if ((newws == NULL) || (newws == oldws) || OCCUPY (wl->twm_win, newws)) break; occupation = win->occupation | (1 << newws->number); ChangeOccupation (win, occupation); if (newws == vs->wsw->currentwspc) { RaiseWindow (win); WMapRaise (win); } else WMapRestack (newws); break; default : return; } XDestroyWindow (dpy, w); } void InvertColorPair (ColorPair *cp) { Pixel save; save = cp->fore; cp->fore = cp->back; cp->back = save; save = cp->shadc; cp->shadc = cp->shadd; cp->shadd = save; } void WMapRedrawName (virtualScreen *vs, WinList wl) { int w = wl->width; int h = wl->height; ColorPair cp; char *label; label = wl->twm_win->icon_name; cp = wl->cp; if (Scr->ReverseCurrentWorkspace && wl->wlist == vs->wsw->currentwspc) { InvertColorPair (&cp); } WMapRedrawWindow (wl->w, w, h, cp, label); } static void WMapRedrawWindow (Window window, int width, int height, ColorPair cp, char *label) { int x, y, strhei, strwid; MyFont font; XFontSetExtents *font_extents; XRectangle inc_rect; XRectangle logical_rect; XFontStruct **xfonts; char **font_names; register int i; int descent; int fnum; XClearWindow (dpy, window); font = Scr->workSpaceMgr.windowFont; font_extents = XExtentsOfFontSet(font.font_set); strhei = font_extents->max_logical_extent.height; if (strhei > height) return; XmbTextExtents(font.font_set, label, strlen (label), &inc_rect, &logical_rect); strwid = logical_rect.width; x = (width - strwid) / 2; if (x < 1) x = 1; fnum = XFontsOfFontSet(font.font_set, &xfonts, &font_names); for( i = 0, descent = 0; i < fnum; i++){ /* xf = xfonts[i]; */ descent = ((descent < (xfonts[i]->max_bounds.descent)) ? (xfonts[i]->max_bounds.descent): descent); } y = ((height + strhei) / 2) - descent; if (Scr->use3Dwmap) { Draw3DBorder (window, 0, 0, width, height, 1, cp, off, True, False); FB(cp.fore, cp.back); } else { FB (cp.back, cp.fore); XFillRectangle (dpy, window, Scr->NormalGC, 0, 0, width, height); FB (cp.fore, cp.back); } if (Scr->Monochrome != COLOR) { XmbDrawImageString (dpy, window, font.font_set, Scr->NormalGC, x, y, label, strlen (label)); } else { XmbDrawString (dpy, window, font.font_set,Scr->NormalGC, x, y, label, strlen (label)); } } static void WMapAddToList (TwmWindow *win, WorkSpace *ws) { virtualScreen *vs; WinList wl; float wf, hf; ColorPair cp; XSetWindowAttributes attr; unsigned long attrmask; unsigned int bw; cp.back = win->title.back; cp.fore = win->title.fore; if (Scr->workSpaceMgr.windowcpgiven) { cp.back = Scr->workSpaceMgr.windowcp.back; GetColorFromList (Scr->workSpaceMgr.windowBackgroundL, win->full_name, &win->class, &cp.back); cp.fore = Scr->workSpaceMgr.windowcp.fore; GetColorFromList (Scr->workSpaceMgr.windowForegroundL, win->full_name, &win->class, &cp.fore); } if (Scr->use3Dwmap && !Scr->BeNiceToColormap) { GetShadeColors (&cp); } for (vs = Scr->vScreenList; vs != NULL; vs = vs->next) { wf = (float) (vs->wsw->wwidth - 2) / (float) vs->w; hf = (float) (vs->wsw->wheight - 2) / (float) vs->h; wl = (WinList) malloc (sizeof (struct winList)); wl->wlist = ws; wl->x = (int) (win->frame_x * wf); wl->y = (int) (win->frame_y * hf); wl->width = (unsigned int) ((win->frame_width * wf) + 0.5); wl->height = (unsigned int) ((win->frame_height * hf) + 0.5); bw = 0; if (!Scr->use3Dwmap) { bw = 1; wl->width -= 2; wl->height -= 2; } if (wl->width < 1) wl->width = 1; if (wl->height < 1) wl->height = 1; wl->w = XCreateSimpleWindow (dpy, vs->wsw->mswl [ws->number]->w, wl->x, wl->y, wl->width, wl->height, bw, Scr->Black, cp.back); attrmask = 0; if (Scr->BackingStore) { attr.backing_store = WhenMapped; attrmask |= CWBackingStore; } attr.cursor = handCursor; attrmask |= CWCursor; XChangeWindowAttributes (dpy, wl->w, attrmask, &attr); XSelectInput (dpy, wl->w, ExposureMask); XSaveContext (dpy, wl->w, TwmContext, (XPointer) vs->wsw->twm_win); XSaveContext (dpy, wl->w, ScreenContext, (XPointer) Scr); XSaveContext (dpy, wl->w, MapWListContext, (XPointer) wl); wl->twm_win = win; wl->cp = cp; wl->next = vs->wsw->mswl [ws->number]->wl; vs->wsw->mswl [ws->number]->wl = wl; if (win->mapped) XMapWindow (dpy, wl->w); } } static void WMapRemoveFromList (TwmWindow *win, WorkSpace *ws) { virtualScreen *vs; WinList wl, *prev; for (vs = Scr->vScreenList; vs != NULL; vs = vs->next) { prev = &vs->wsw->mswl [ws->number]->wl; wl = *prev; while (wl != NULL) { if (win == wl->twm_win) { *prev = wl->next; XDeleteContext (dpy, wl->w, TwmContext); XDeleteContext (dpy, wl->w, ScreenContext); XDeleteContext (dpy, wl->w, MapWListContext); XDestroyWindow (dpy, wl->w); free (wl); break; } prev = &wl->next; wl = *prev; } } } static void ResizeWorkSpaceManager (virtualScreen *vs, TwmWindow *win) { int bwidth, bheight; int wwidth, wheight; int hspace, vspace; int lines, columns; int neww, newh; WorkSpace *ws; TwmWindow *tmp_win; WinList wl; int i, j; float wf, hf; neww = win->attr.width; newh = win->attr.height; if (neww == vs->wsw->width && newh == vs->wsw->height) return; hspace = Scr->workSpaceMgr.hspace; vspace = Scr->workSpaceMgr.vspace; lines = Scr->workSpaceMgr.lines; columns = Scr->workSpaceMgr.columns; bwidth = (neww - (columns * hspace)) / columns; bheight = (newh - (lines * vspace)) / lines; wwidth = neww / columns; wheight = newh / lines; wf = (float) (wwidth - 2) / (float) vs->w; hf = (float) (wheight - 2) / (float) vs->h; i = 0; j = 0; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { MapSubwindow *msw = vs->wsw->mswl [ws->number]; XMoveResizeWindow (dpy, vs->wsw->bswl [ws->number]->w, i * (bwidth + hspace) + (hspace / 2), j * (bheight + vspace) + (vspace / 2), bwidth, bheight); msw->x = i * wwidth; msw->y = j * wheight; XMoveResizeWindow (dpy, msw->w, msw->x, msw->y, wwidth - 2, wheight - 2); for (wl = msw->wl; wl != NULL; wl = wl->next) { tmp_win = wl->twm_win; wl->x = (int) (tmp_win->frame_x * wf); wl->y = (int) (tmp_win->frame_y * hf); wl->width = (unsigned int) ((tmp_win->frame_width * wf) + 0.5); wl->height = (unsigned int) ((tmp_win->frame_height * hf) + 0.5); XMoveResizeWindow (dpy, wl->w, wl->x, wl->y, wl->width, wl->height); } i++; if (i == columns) {i = 0; j++;}; } vs->wsw->bwidth = bwidth; vs->wsw->bheight = bheight; vs->wsw->width = neww; vs->wsw->height = newh; vs->wsw->wwidth = wwidth; vs->wsw->wheight = wheight; PaintWorkSpaceManager (vs); } static void ResizeOccupyWindow (TwmWindow *win) { int bwidth, bheight, owidth, oheight; int hspace, vspace; int lines, columns; int neww, newh; WorkSpace *ws; int i, j, x, y; OccupyWindow *occwin = Scr->workSpaceMgr.occupyWindow; neww = win->attr.width; newh = win->attr.height; if (occwin->width == neww && occwin->height == newh) return; hspace = occwin->hspace; vspace = occwin->vspace; lines = Scr->workSpaceMgr.lines; columns = Scr->workSpaceMgr.columns; bwidth = (neww - columns * hspace) / columns; bheight = (newh - (lines + 2) * vspace) / (lines + 1); owidth = occwin->owidth; oheight = bheight; i = 0; j = 0; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { XMoveResizeWindow (dpy, occwin->obuttonw [j * columns + i], i * (bwidth + hspace) + (hspace / 2), j * (bheight + vspace) + (vspace / 2), bwidth, bheight); i++; if (i == columns) {i = 0; j++;} } hspace = (neww - 3 * owidth) / 4; x = hspace; y = ((bheight + vspace) * lines) + ((3 * vspace) / 2); XMoveResizeWindow (dpy, occwin->OK, x, y, owidth, oheight); x += owidth + hspace; XMoveResizeWindow (dpy, occwin->cancel, x, y, owidth, oheight); x += owidth + hspace; XMoveResizeWindow (dpy, occwin->allworkspc, x, y, owidth, oheight); occwin->width = neww; occwin->height = newh; occwin->bwidth = bwidth; occwin->bheight = bheight; occwin->owidth = owidth; PaintOccupyWindow (); } void WMapCreateCurrentBackGround (char *border, char *background, char *foreground, char *pixmap) { Image *image; WorkSpaceMgr *ws = &Scr->workSpaceMgr; ws->curBorderColor = Scr->Black; ws->curColors.back = Scr->White; ws->curColors.fore = Scr->Black; ws->curImage = None; if (border == NULL) return; GetColor (Scr->Monochrome, &ws->curBorderColor, border); if (background == NULL) return; ws->curPaint = True; GetColor (Scr->Monochrome, &ws->curColors.back, background); if (foreground == NULL) return; GetColor (Scr->Monochrome, &ws->curColors.fore, foreground); if (pixmap == NULL) return; if ((image = GetImage (pixmap, Scr->workSpaceMgr.curColors)) == None) { fprintf (stderr, "Can't find pixmap %s\n", pixmap); return; } ws->curImage = image; } void WMapCreateDefaultBackGround (char *border, char *background, char *foreground, char *pixmap) { Image *image; WorkSpaceMgr *ws = &Scr->workSpaceMgr; ws->defBorderColor = Scr->Black; ws->defColors.back = Scr->White; ws->defColors.fore = Scr->Black; ws->defImage = None; if (border == NULL) return; GetColor (Scr->Monochrome, &ws->defBorderColor, border); if (background == NULL) return; GetColor (Scr->Monochrome, &ws->defColors.back, background); if (foreground == NULL) return; GetColor (Scr->Monochrome, &ws->defColors.fore, foreground); if (pixmap == NULL) return; if ((image = GetImage (pixmap, ws->defColors)) == None) return; ws->defImage = image; } Bool AnimateRoot (void) { virtualScreen *vs; ScreenInfo *scr; int scrnum; Image *image; WorkSpace *ws; Bool maybeanimate; maybeanimate = False; for (scrnum = 0; scrnum < NumScreens; scrnum++) { if ((scr = ScreenList [scrnum]) == NULL) continue; if (! scr->workSpaceManagerActive) continue; for (vs = scr->vScreenList; vs != NULL; vs = vs->next) { if (! vs->wsw->currentwspc) continue; image = vs->wsw->currentwspc->image; if ((image == None) || (image->next == None)) continue; if (scr->DontPaintRootWindow) continue; XSetWindowBackgroundPixmap (dpy, vs->window, image->pixmap); XClearWindow (dpy, scr->Root); vs->wsw->currentwspc->image = image->next; maybeanimate = True; } } for (scrnum = 0; scrnum < NumScreens; scrnum++) { if ((scr = ScreenList [scrnum]) == NULL) continue; for (vs = scr->vScreenList; vs != NULL; vs = vs->next) { if (vs->wsw->state == BUTTONSSTATE) continue; for (ws = scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { image = ws->image; if ((image == None) || (image->next == None)) continue; if (ws == vs->wsw->currentwspc) continue; XSetWindowBackgroundPixmap (dpy, vs->wsw->mswl [ws->number]->w, image->pixmap); XClearWindow (dpy, vs->wsw->mswl [ws->number]->w); ws->image = image->next; maybeanimate = True; } } } return (maybeanimate); } static char **GetCaptivesList (int scrnum) { unsigned char *prop, *p; unsigned long bytesafter; unsigned long len; Atom actual_type; int actual_format; char **ret; int count; int i, l; Window root; _XA_WM_CTWMSLIST = XInternAtom (dpy, "WM_CTWMSLIST", True); if (_XA_WM_CTWMSLIST == None) return ((char**)0); root = RootWindow (dpy, scrnum); if (XGetWindowProperty (dpy, root, _XA_WM_CTWMSLIST, 0L, 512, False, XA_STRING, &actual_type, &actual_format, &len, &bytesafter, &prop) != Success) return ((char**) 0); if (len == 0) return ((char**) 0); count = 0; p = prop; l = 0; while (l < len) { l += strlen ((char*)p) + 1; p += strlen ((char*)p) + 1; count++; } ret = (char**) malloc ((count + 1) * sizeof (char*)); p = prop; l = 0; i = 0; while (l < len) { ret [i++] = (char*) strdup ((char*) p); l += strlen ((char*)p) + 1; p += strlen ((char*)p) + 1; } ret [i] = (char*) 0; XFree ((char *)prop); return (ret); } static void SetCaptivesList (int scrnum, char **clist) { unsigned long len; char **cl; char *s, *slist; Window root = RootWindow (dpy, scrnum); _XA_WM_CTWMSLIST = XInternAtom (dpy, "WM_CTWMSLIST", False); cl = clist; len = 0; while (*cl) { len += strlen (*cl++) + 1; } if (len == 0) { XDeleteProperty (dpy, root, _XA_WM_CTWMSLIST); return; } slist = (char*) malloc (len * sizeof (char)); cl = clist; s = slist; while (*cl) { strcpy (s, *cl); s += strlen (*cl); *s++ = '\0'; cl++; } XChangeProperty (dpy, root, _XA_WM_CTWMSLIST, XA_STRING, 8, PropModeReplace, (unsigned char *) slist, len); } static void freeCaptiveList (char **clist) { while (clist && *clist) { free (*clist++); } } void AddToCaptiveList (void) { int i, count; char **clist, **cl, **newclist; int busy [32]; Atom _XA_WM_CTWM_ROOT; char *atomname; int scrnum = Scr->screen; Window croot = Scr->Root; Window root = RootWindow (dpy, scrnum); for (i = 0; i < 32; i++) { busy [i] = 0; } clist = GetCaptivesList (scrnum); cl = clist; count = 0; while (cl && *cl) { count++; if (!captivename) { if (!strncmp (*cl, "ctwm-", 5)) { int r, n; r = sscanf (*cl, "ctwm-%d", &n); cl++; if (r != 1) continue; if ((n < 0) || (n > 31)) continue; busy [n] = 1; } else cl++; continue; } if (!strcmp (*cl, captivename)) { fprintf (stderr, "A captive ctwm with name %s is already running\n", captivename); exit (1); } cl++; } if (!captivename) { for (i = 0; i < 32; i++) { if (!busy [i]) break; } if (i == 32) { /* no one can tell we didn't try hard */ fprintf (stderr, "Cannot find a suitable name for captive ctwm\n"); exit (1); } captivename = (char*) malloc (8); sprintf (captivename, "ctwm-%d", i); } newclist = (char**) malloc ((count + 2) * sizeof (char*)); for (i = 0; i < count; i++) { newclist [i] = (char*) strdup (clist [i]); } newclist [count] = (char*) strdup (captivename); newclist [count + 1] = (char*) 0; SetCaptivesList (scrnum, newclist); freeCaptiveList (clist); freeCaptiveList (newclist); free (clist); free (newclist); root = RootWindow (dpy, scrnum); atomname = (char*) malloc (strlen ("WM_CTWM_ROOT_") + strlen (captivename) +1); sprintf (atomname, "WM_CTWM_ROOT_%s", captivename); _XA_WM_CTWM_ROOT = XInternAtom (dpy, atomname, False); XChangeProperty (dpy, root, _XA_WM_CTWM_ROOT, XA_WINDOW, 32, PropModeReplace, (unsigned char *) &croot, 4); } void RemoveFromCaptiveList (void) { int count; char **clist, **cl, **newclist; Atom _XA_WM_CTWM_ROOT; char *atomname; int scrnum = Scr->screen; Window root = RootWindow (dpy, scrnum); if (!captivename) return; clist = GetCaptivesList (scrnum); cl = clist; count = 0; while (*cl) { count++; cl++; } newclist = (char**) malloc (count * sizeof (char*)); cl = clist; count = 0; while (*cl) { if (!strcmp (*cl, captivename)) { cl++; continue; } newclist [count++] = *cl; cl++; } newclist [count] = (char*) 0; SetCaptivesList (scrnum, newclist); freeCaptiveList (clist); free (clist); free (newclist); atomname = (char*) malloc (strlen ("WM_CTWM_ROOT_") + strlen (captivename) +1); sprintf (atomname, "WM_CTWM_ROOT_%s", captivename); _XA_WM_CTWM_ROOT = XInternAtom (dpy, atomname, True); if (_XA_WM_CTWM_ROOT == None) return; XDeleteProperty (dpy, root, _XA_WM_CTWM_ROOT); } void SetPropsIfCaptiveCtwm (TwmWindow *win) { Window window = win->w; Window frame = win->frame; Atom _XA_WM_CTWM_ROOT; if (!CaptiveCtwmRootWindow (window)) return; _XA_WM_CTWM_ROOT = XInternAtom (dpy, "WM_CTWM_ROOT", True); if (_XA_WM_CTWM_ROOT == None) return; XChangeProperty (dpy, frame, _XA_WM_CTWM_ROOT, XA_WINDOW, 32, PropModeReplace, (unsigned char *) &window, 4); } Window CaptiveCtwmRootWindow (Window window) { Window *prop; Window w; unsigned long bytesafter; unsigned long len; Atom actual_type; int actual_format; Atom _XA_WM_CTWM_ROOT; _XA_WM_CTWM_ROOT = XInternAtom (dpy, "WM_CTWM_ROOT", True); if (_XA_WM_CTWM_ROOT == None) return ((Window)0); if (XGetWindowProperty (dpy, window, _XA_WM_CTWM_ROOT, 0L, 1L, False, XA_WINDOW, &actual_type, &actual_format, &len, &bytesafter, (unsigned char **)&prop) != Success) return ((Window)0); if (len == 0) return ((Window)0); w = *prop; XFree ((char *)prop); return w; } CaptiveCTWM GetCaptiveCTWMUnderPointer (void) { int scrnum = Scr->screen; Window root; Window child, croot; CaptiveCTWM cctwm; root = RootWindow (dpy, scrnum); while (1) { XQueryPointer (dpy, root, &JunkRoot, &child, &JunkX, &JunkY, &JunkX, &JunkY, &JunkMask); if (child && (croot = CaptiveCtwmRootWindow (child))) { root = croot; continue; } cctwm.root = root; XFetchName (dpy, root, &cctwm.name); if (!cctwm.name) cctwm.name = (char*) strdup ("Root"); return (cctwm); } } void SetNoRedirect (Window window) { Atom _XA_WM_NOREDIRECT; _XA_WM_NOREDIRECT = XInternAtom (dpy, "WM_NOREDIRECT", False); if (_XA_WM_NOREDIRECT == None) return; XChangeProperty (dpy, window, _XA_WM_NOREDIRECT, XA_STRING, 8, PropModeReplace, (unsigned char *) "Yes", 4); } static Bool DontRedirect (Window window) { unsigned char *prop; unsigned long bytesafter; unsigned long len; Atom actual_type; int actual_format; Atom _XA_WM_NOREDIRECT; _XA_WM_NOREDIRECT = XInternAtom (dpy, "WM_NOREDIRECT", True); if (_XA_WM_NOREDIRECT == None) return (False); if (XGetWindowProperty (dpy, window, _XA_WM_NOREDIRECT, 0L, 1L, False, XA_STRING, &actual_type, &actual_format, &len, &bytesafter, &prop) != Success) return (False); if (len == 0) return (False); XFree ((char *)prop); return (True); } Bool visible (TwmWindow *tmp_win) { return (tmp_win->vs != NULL); } #ifdef BUGGY_HP700_SERVER static void fakeRaiseLower (display, window) Display *display; Window window; { Window root; Window parent; Window grandparent; Window *children; unsigned int number; XWindowChanges changes; number = 0; XQueryTree (display, window, &root, &parent, &children, &number); XFree ((char *) children); XQueryTree (display, parent, &root, &grandparent, &children, &number); changes.stack_mode = (children [number-1] == window) ? Below : Above; XFree ((char *) children); XConfigureWindow (display, window, CWStackMode, &changes); } #endif