/* * desktop.cc * * Copyright (C) 1995, 1996, 1997, 1997, 1998, 1999, 2000, 2001, 2002 Kenichi Kourai * Copyright (C) 1999, 2000, 2001, 2002 Luiz Blanes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with blwm; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include "main.h" #include "blwm.h" #include "desktop.h" #include "focus_mgr.h" #include "paging.h" #include "icon.h" #include "indicator.h" #include "taskbar.h" #include "startmenu.h" #include "switcher.h" #include "pager.h" #include "exit_dialog.h" #include "confirm_dialog.h" #include "hash.h" #include "blwmrc.h" #include "gnome.h" #include "mini.h" #include "image.h" #include "callback.h" #include "accessory.h" #include "session.h" #include "fbutton.h" #include "remote_cmd.h" Desktop::Desktop() { initPos = 0; imgDesktop = NULL; curCmap = None; curCmapBlwm = NULL; } /* * LookInList -- * Return the pointer if the window exists in blwm list; * otherwise, return NULL. */ Blwm* Desktop::LookInList(Window w) { List::Iterator i(&blwmList); Blwm* blWm; for (blWm = i.GetHead(); blWm; blWm = i.GetNext()) if (w == blWm->GetWin()) break; if (blWm) { blWm->CalcWindowPos(blWm->GetOrigRect()); Rect rect = blWm->GetRect(); if (Intersect(rect, rootBlwm->GetRect())) Gnome::ResetState(blWm, WIN_STATE_HID_WORKSPACE); else Gnome::SetState(blWm, WIN_STATE_HID_WORKSPACE); } return blWm; } /* * CaptureAllWindows -- * Decorate all windows. */ void Desktop::CaptureAllWindows() { Blwm* blWm; Window junkRoot, junkParent, *children; unsigned int nChildren; long state; XWMHints* wmHints; if (!XQueryTree(display, root, &junkRoot, &junkParent, &children, &nChildren)) return; for (int i = 0; i < (int)nChildren; i++) { if (children[i] && MappedNotOverride(children[i], &state)) { blWm = new Blwm(children[i], True); blwmList.InsertTail(blWm); if (blWm->CheckFlags(CLOSE_SOON)) { XReparentWindow(display, children[i], root, rcScreen.x + rcScreen.width, rcScreen.y + rcScreen.height); blWm->CloseWindow(); blwmList.Remove(blWm); delete blWm; continue; } wmHints = blWm->GetWMHints(); if (!restart) { if (state == IconicState) blWm->MinimizeWindow(False, False); else if (wmHints && (wmHints->flags & StateHint) && wmHints->initial_state == IconicState) blWm->MinimizeWindow(False, False); else if (blWm->CheckFlags(INIT_MINIMIZE)) blWm->MinimizeWindow(False, False); else if (blWm->CheckFlags(INIT_MAXIMIZE)) { blWm->fButton[1]->ChangeImage(FrameButton::RESTORE); blWm->MaximizeWindow(False, False); } else blWm->MapWindows(); } else blWm->MapWindows(); ASSERT(blWm->tButton); blWm->tButton->MapButton(); if (!blWm->CheckStatus(MINIMIZE_WINDOW)) { if (ClickToFocus) blWm->SetFocus(); } else focusMgr.InsertUnmapList(blWm); } } Gnome::ChangeClientList(); ChangeFocusToCursor(); if (nChildren) XFree(children); } /* * Decide placement of a window with size. * SmartPlacement seems to have a bug... */ Point Desktop::GetNextPlace(const Dim& size, const Point& pageoff) { Point pt; if (SmartPlacement) { List::Iterator i(&blwmList); Blwm* tmpBlwm; int miny; Rect rcTmp; Bool found; for (pt.y = pageoff.y + rcScreen.y; pt.y + size.height < pageoff.y + rcScreen.y + rcScreen.height; pt.y = miny) { miny = pageoff.y + rcScreen.y + rcScreen.height; for (pt.x = pageoff.x + rcScreen.x; pt.x + size.width < pageoff.x + rcScreen.x + rcScreen.width; pt.x++) { // assume this position is ok found = True; for (tmpBlwm = i.GetHead(); tmpBlwm; tmpBlwm = i.GetNext()) { if (!(tmpBlwm->CheckStatus(MINIMIZE_WINDOW)) && tmpBlwm->CheckMapped()) { rcTmp = tmpBlwm->GetRect(); if (rcTmp.x < pt.x + size.width && rcTmp.x + rcTmp.width > pt.x && rcTmp.y < pt.y + size.height && rcTmp.y + rcTmp.height > pt.y) { found = False; // overlap pt.x = rcTmp.x + rcTmp.width - 1; miny = Min(miny, rcTmp.y + rcTmp.height); break; } } } if (found) return pt; } } } // when not SmartPlacement or not found if (initPos + size.width + Blwm::BORDER_WIDTH * 2 > rcScreen.width || initPos + size.height + Blwm::TITLE_HEIGHT + Blwm::TOP_BORDER + Blwm::BORDER_WIDTH > rcScreen.height) initPos = 0; pt.x = initPos + rcScreen.x + pageoff.x; pt.y = initPos + rcScreen.y + pageoff.y; initPos += Blwm::TITLE_HEIGHT + Blwm::TOP_BORDER; return pt; } /* * RecalcAllWindows -- * Recalculate the position of all windows. */ void Desktop::RecalcAllWindows() { List::Iterator i(&blwmList); for (Blwm* blWm = i.GetHead(); blWm; blWm = i.GetNext()) blWm->RecalcWindow(); } static void TrapChild2(int sig); static int FinishErrorHandler(Display* display, XErrorEvent* ev); /* * FinishBlwm -- * Free all resources and finish blwm. */ void Desktop::FinishBlwm(Bool reStart) { // when parse error before a start flag is set if (!start) { XCloseDisplay(display); return; } ASSERT(paging); /* * Restore default page. */ paging->PagingProc(Point(0, 0)); XGrabServer(display); signal(SIGCHLD, TrapChild2); XSetErrorHandler(FinishErrorHandler); /* * Delete all blwms. */ List::Iterator i1(&blwmList); for (Blwm* blWm = i1.GetHead(); blWm; blWm = i1.Remove()) { XWindowAttributes attr; Rect rcOrig = blWm->GetOrigRect(); XGetWindowAttributes(display, blWm->GetWin(), &attr); if (attr.map_state != IsUnmapped || blWm->CheckStatus(MINIMIZE_WINDOW)) XReparentWindow(display, blWm->GetWin(), root, rcOrig.x, rcOrig.y); else { /* * Adjust the position of a window unmapped by an application, * preparing for the next map. */ Rect rcRoot = rootBlwm->GetRect(); XReparentWindow(display, blWm->GetWin(), root, rcOrig.x % rcRoot.width, rcOrig.y % rcRoot.height); } XSetWindowBorderWidth(display, blWm->GetWin(), blWm->GetOrigBW()); delete blWm; } XUngrabServer(display); // Delete all icons. List::Iterator i2(&iconList); for (Icon* icon = i2.GetHead(); icon; icon = i2.Remove()) delete icon; // Delete all accessories. List::Iterator i4(&accList); for (Accessory* acc = i4.GetHead(); acc; acc = i4.Remove()) delete acc; // Delete all indicators. List::Iterator i3(&Indicator::indList); for (Indicator* ind = i3.GetHead(); ind; ind = i3.Remove()) delete ind; // free fonts int fsNum = (UseBoldFont) ? FsNum : FsNum - 1; for (int i = 0; i < fsNum; i++) { if (*fsSet[i].fs == fsDefault) continue; Bool match = False; for (int j = 0; j < i; j++) { if (*fsSet[i].fs == *fsSet[j].fs) { match = True; break; } } if (!match) XFreeFontSet(display, *fsSet[i].fs); } XFreeFontSet(display, fsDefault); #ifdef USE_XSMP delete session; #endif delete rootBlwm; delete taskBar; delete startMenu; delete taskSwitcher; delete paging; delete pager; delete ::ctrlMenu; delete exitDlg; delete confirmDlg; delete Blwm::appHashTable; #ifdef ALLOW_RMTCMD delete remoteCmd; #endif BlImage::Destroy(imgDesktop); XSetInputFocus(display, root, RevertToNone, CurrentTime); XUndefineCursor(display, root); XClearWindow(display, root); if (!reStart) { XCloseDisplay(display); exit(0); } else XCloseDisplay(display); } static void TrapChild2(int sig) { while (waitpid(-1, NULL, WNOHANG) > 0) ; signal(SIGCHLD, TrapChild2); } /* * FinishErrorHandler -- * Jump to here when error happens in FinishBlwm. This error is ignored. */ static int FinishErrorHandler(Display* display, XErrorEvent* ev) { return 0; } /* * ChangeFocusToCursor -- * Give the focus to the window where cursor exists. */ void Desktop::ChangeFocusToCursor() { Window junkRoot, junkChild, w; Point ptRoot, ptJunk; unsigned int mask; Blwm* blWm; XQueryPointer(display, root, &junkRoot, &junkChild, &ptRoot.x, &ptRoot.y, &ptJunk.x, &ptJunk.y, &mask); XTranslateCoordinates(display, root, root, ptRoot.x, ptRoot.y, &ptJunk.x, &ptJunk.y, &w); if (XFindContext(display, w, Blwm::context, (caddr_t *)&blWm) == XCSUCCESS) { blWm->SetFocus(); if (AutoRaise) blWm->RaiseWindow(False); } else rootBlwm->SetFocus(); /* w == None, i.e. cursor on the root window */ } /* * CreateIcons -- * Create shortcut icons. */ void Desktop::CreateIcons() { if (ShortCutItem == NULL) return; Icon* icon; BlImage* img; MenuElem* mItem = ShortCutItem; MenuElem* tmpItem; while (mItem) { if (strcmp(mItem->file, "") == 0) img = Icon::imgIcon->Duplicate(); else { img = CreateImageFromFile(mItem->file, timer); if (img == NULL) img = Icon::imgIcon->Duplicate(); } if (strcmp(mItem->exec, "") != 0) icon = new Icon(img, mItem->name, mItem->exec, mItem->x, mItem->y); else icon = new Icon(img, mItem->name, mItem->func, mItem->x, mItem->y); desktop.GetIconList().InsertTail(icon); icon->MoveIcon(Point(-(IconSize + IconHorizontalSpacing), -(IconSize + IconVerticalSpacing))); icon->MapIcon(); tmpItem = mItem; mItem = mItem->next; delete tmpItem; } } /* * RedrawAllIcons -- * Redraw all icons in icon list. */ void Desktop::RedrawAllIcons() { List::Iterator i(&iconList); int count = 0; int iconColumnNum; iconColumnNum = rcScreen.height / (IconSize + IconVerticalSpacing); for (Icon* tmpIcon = i.GetHead(); tmpIcon; tmpIcon = i.GetNext()) { Rect rcVirt = tmpIcon->GetVirtRect(); if (rcVirt.x == -1) rcVirt.x = (IconSize + IconHorizontalSpacing) * (count / iconColumnNum); else if (rcVirt.x >= Icon::SFACTOR) rcVirt.x = (IconSize + IconHorizontalSpacing) * (rcVirt.x - Icon::SFACTOR); if (rcVirt.y == -1) rcVirt.y = (IconSize + IconVerticalSpacing) * (count % iconColumnNum); else if (rcVirt.y >= Icon::SFACTOR) rcVirt.y = (IconSize + IconVerticalSpacing) * (rcVirt.y - Icon::SFACTOR); tmpIcon->SetVirtRect(rcVirt); Rect rc = tmpIcon->GetRect(); rc.x = rcScreen.x + rcVirt.x; rc.y = rcScreen.y + rcVirt.y; tmpIcon->SetRect(rc); tmpIcon->MoveIcon(Point(rc.x, rc.y)); count++; } } /* * LineUpAllIcons -- * Line up all icons in icon list. */ void Desktop::LineUpAllIcons() { List::Iterator i(&iconList); int modulo = 0; for (Icon* tmpIcon = i.GetHead(); tmpIcon; tmpIcon = i.GetNext()) { Rect rcVirt = tmpIcon->GetVirtRect(); modulo = rcVirt.x % (IconSize + IconHorizontalSpacing); rcVirt.x += (modulo > (IconSize + IconHorizontalSpacing) / 2) ? IconSize + IconHorizontalSpacing - modulo : -modulo; modulo = rcVirt.y % (IconSize + IconVerticalSpacing); rcVirt.y += (modulo > (IconSize + IconVerticalSpacing) / 2) ? IconSize + IconVerticalSpacing - modulo : -modulo; tmpIcon->SetVirtRect(rcVirt); Rect rc = tmpIcon->GetRect(); rc.x = rcScreen.x + rcVirt.x; rc.y = rcScreen.y + rcVirt.y; tmpIcon->SetRect(rc); tmpIcon->MoveIcon(Point(rc.x, rc.y)); } } /* * GetDesktopArea -- * Devide screen to 4 areas of up, down, left and right, and return the * position where a given point belongs to. */ Taskbar::TaskbarPos Desktop::GetDesktopArea(const Point& pt) { Rect rcRoot = rootBlwm->GetRect(); int x1, x2; int y1, y2; x1 = int(double(rcRoot.width - 1) / (rcRoot.height - 1) * pt.y); x2 = (rcRoot.width - 1) - x1; if (x2 < pt.x && pt.x < x1) return Taskbar::BOTTOM; else if (x1 < pt.x && pt.x < x2) return Taskbar::TOP; y1 = int(double(rcRoot.height - 1) / (rcRoot.width - 1) * pt.x); y2 = (rcRoot.height - 1) - y1; if (y1 < pt.y && pt.y < y2) return Taskbar::LEFT; else if (y2 < pt.y && pt.y < y1) return Taskbar::RIGHT; return Taskbar::BOTTOM; } /* * SetWallPaper -- * Read wall paper(pixmap only), and make it be background of root window. */ void Desktop::SetWallPaper() { if (strcmp(WallPaper, "Windows98") == 0 || strcmp(WallPaper, "Windows95") == 0) { XSetWindowBackground(display, root, DesktopColor.pixel); XClearWindow(display, root); } else if (strcmp(WallPaper, "") != 0) { imgDesktop = CreateImageFromFile(WallPaper, timer); if (imgDesktop) { imgDesktop->SetBackground(root); XClearWindow(display, root); } } } // before creating accessories void Desktop::CreateTopWindow() { XSetWindowAttributes attributes; unsigned long valueMask; attributes.override_redirect = True; valueMask = CWOverrideRedirect; topWin = XCreateWindow(display, root, -1, -1, 1, 1, 0, CopyFromParent, InputOutput, CopyFromParent, valueMask, &attributes); XMapRaised(display, topWin); } void Desktop::CreateAccessories() { List::Iterator li(&accList); Accessory* acc = li.GetHead(); while (acc) { acc->CreateAccessory(); acc = li.GetNext(); } } void Desktop::SetFocus() { XSetInputFocus(display, topWin, RevertToParent, CurrentTime); }