// bbpager.cc for bbpager - a pager for Blackbox. // // Copyright (c) 1998-2003 by John Kennis, jkennis@chello.nl // // 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 this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // // (See the included file COPYING / GPL-2.0) // #include <string> #include "bbpager.h" #include "config.h" #include <stdio.h> extern "C" { #include <X11/cursorfont.h> } #include <iostream> using std::cout; using std::endl; using std::list; ToolWindow::ToolWindow(Configuration cml_options): bt::Application(cml_options.appName(), cml_options.displayName().c_str(), false), current_screen_info(display().screenInfo(DefaultScreen(XDisplay()))), config(cml_options) { current_screen = DefaultScreen(XDisplay()); root_window = current_screen_info.rootWindow(); number_of_desktops = 0; desktop_nr = 0; current_desktop_nr = 0; wm_init = false; row_last = column_last = 0; xa_wm_delete_window = XInternAtom(XDisplay(), "WM_DELETE_WINDOW", False); resource = new Resource(this, config.blackboxRcFilename(), config.rcFilename()); _ewmh = new bt::EWMH(display()); if (!_ewmh->readNumberOfDesktops(current_screen_info.rootWindow(), &number_of_desktops)) { delete _ewmh; delete resource; // temporary fix: 1: we could add a timer here an wait // 2: we should check for supported atoms, and not use // number of desktops. std::string error = "Please start bbpager after an EWHM complaint Window manager"; error += "\nIf you start bbpager from .xinitrc or .xsession consider delaying bbpager startup using \"sleep 5 && bbpager &\""; throw error; } frame_window = new FrameWindow(this); wminterface = new WMInterface(this); xa_wm_state = XInternAtom(XDisplay(),"WM_STATE", False); unsigned int i; for (i = 0; i < number_of_desktops; i++) { addDesktopWindow(i); } _ewmh->readCurrentDesktop(current_screen_info.rootWindow(), ¤t_desktop_nr); desktopChange(current_desktop_nr); wminterface->updateWindowList(); Window active; if (!wminterface->readActiveWindow(root_window, &active)) { cout << "Error: cannot get active window from Window Manager" << endl; } focusWindow(active); } ToolWindow::~ToolWindow() { list<DesktopWindow *>::iterator it; for (it = desktop_window_list.begin(); it != desktop_window_list.end(); it++) { delete (*it); } list<PagerWindow *>::iterator pit = pagerWindowList().begin(); for (; pit != pagerWindowList().end(); pit++) { delete (*pit); } delete wminterface; delete frame_window; delete resource; delete _ewmh; } void ToolWindow::moveWinToDesktop(PagerWindow *pager_window, unsigned int desktop_nr) { DesktopWindow *desktop = findDesktopWindow(desktop_nr); if (desktop) { if ((desktop->desktopId() != pager_window->desktopId() && !pager_window->isSticky())) { XUnmapWindow(XDisplay(), pager_window->window()); XReparentWindow(XDisplay(), pager_window->window(), desktop->window(), pager_window->x(), pager_window->y()); XMapWindow(XDisplay(), pager_window->window()); pager_window->setDesktopId(desktop_nr); } } } void ToolWindow::moveWinToDesktop(Window win, DesktopWindow *desktop) { PagerWindow *pager_window = findPagerWindow(win); if (pager_window != 0) { if ((desktop->desktopId() != pager_window->desktopId()) & (!pager_window->isSticky())) { XUnmapWindow(XDisplay(), pager_window->window()); XReparentWindow(XDisplay(), pager_window->window(), desktop->window(), pager_window->x(), pager_window->y()); XMapWindow(XDisplay(), pager_window->window()); pager_window->setDesktopId(desktop_nr); } } } PagerWindow *ToolWindow::findPagerWindow(Window win) { list<PagerWindow *>::iterator it = pager_window_list.begin(); for (; it != pager_window_list.end(); it++) { if ((*it)->realWindow() == win) { return *it; } } return NULL; } PagerWindow *ToolWindow::findPPagerWindow(Window win) { list<PagerWindow *>::iterator it = pager_window_list.begin(); for (; it != pager_window_list.end(); it++) { int i = 0; while ((*it)->window(i) != 0) { if ((*it)->window(i) == win) { return *it; } i++; } } return NULL; } PagerWindow *ToolWindow::findFocusedPagerWindow() { list<PagerWindow *>::iterator it = pager_window_list.begin(); for (; it != pager_window_list.end(); it++) { if ((*it)->isFocused()) { return *it; } } return NULL; } void ToolWindow::reconfigure(void) { //resource->Reload(); delete resource; resource = new Resource(this, config.blackboxRcFilename(), config.rcFilename()); MakeWindow(true); desktop_nr = 0; list<DesktopWindow *>::iterator dit = desktop_window_list.begin(); for (; dit != desktop_window_list.end(); dit++) { (*dit)->reconfigure(); } list<PagerWindow *>::iterator pit = pager_window_list.begin(); for (; pit != pager_window_list.end(); pit++) { (*pit)->reconfigure(); } //frame_window->reconfigure(); } // raise window in pager void ToolWindow::raiseWindow(Window win) { PagerWindow *pager_window = findPagerWindow(win); if (pager_window) XRaiseWindow(XDisplay(), pager_window->window()); } // lower window in pager void ToolWindow::lowerWindow(Window win) { PagerWindow *pager_window = findPagerWindow(win); if (pager_window) XLowerWindow(XDisplay(), pager_window->window()); } // focus window in pager void ToolWindow::focusWindow(Window win) { if (resource->getFocusStyle() != none) { PagerWindow *focus_window = findFocusedPagerWindow(); /* remove focus from previously focused window */ if (focus_window) { focus_window->clearFocus(); } PagerWindow *pager_window = findPagerWindow(win); if (pager_window) { pager_window->setFocus(); } } } void ToolWindow::desktopChange(unsigned int desktop_nr) { if (resource->getDesktopFocusStyle() != none) { DesktopWindow *desktop_window; desktop_window = findDesktopWindow(current_desktop_nr); if (desktop_window) desktop_window->clearFocus(); desktop_window = findDesktopWindow(desktop_nr); if (desktop_window) desktop_window->setFocus(); } current_desktop_nr = desktop_nr; wminterface->updateWindowStack(); } DesktopWindow *ToolWindow::findDesktopWindow(unsigned int desktop_nr) { list<DesktopWindow *>::iterator it = desktop_window_list.begin(); for (; it != desktop_window_list.end(); it++) { if ((*it)->desktopId() == desktop_nr) { return (*it); } } return NULL; } DesktopWindow *ToolWindow::findDesktopWindow(Window win) { list<DesktopWindow *>::iterator it = desktop_window_list.begin(); for (; it != desktop_window_list.end(); it++) { if ((*it)->window() == win) { return (*it); } } return NULL; } int ToolWindow::winOnDesktop(Window win) { PagerWindow *pager_window = findPagerWindow(win); if (pager_window) return pager_window->desktopId(); return(0); } void ToolWindow::addDesktopWindow(unsigned int nr) { desktop_window_list.push_back(new DesktopWindow(this, nr)); } void ToolWindow::removeDesktopWindow(void) { /* delete last */ DesktopWindow *desktop_window = desktop_window_list.back(); desktop_window_list.pop_back(); delete desktop_window; desktop_nr--; frame_window->resize(); } FrameWindow::FrameWindow(ToolWindow *toolwindow) : EventHandler(), bbtool(toolwindow) { screen = bbtool->getCurrentScreen(); display = bbtool->XDisplay(); m_pixmap = 0; buildWindow(false); bbtool->insertEventHandler(win, this); } FrameWindow::~FrameWindow() { bbtool->removeEventHandler(win); XUnmapWindow(display, win); /* destroy pixmaps */ if (m_pixmap) bt::PixmapCache::release(m_pixmap); /* destroy windows */ XDestroyWindow(display, win); } void FrameWindow::buildWindow(bool reconfigure) { calcSize(); m_pixmap = bt::PixmapCache::find(screen, bbtool->resource->frame.texture, fwidth, fheight); if (!reconfigure) { XSetWindowAttributes attrib; XWMHints wmhints; XClassHint classhints; XTextProperty windowname; unsigned long create_mask = CWBackPixmap | CWEventMask; attrib.background_pixmap = ParentRelative; attrib.event_mask = ButtonPressMask | ButtonReleaseMask | ExposureMask | FocusChangeMask | StructureNotifyMask | SubstructureRedirectMask; win = XCreateWindow(display, bbtool->getCurrentScreenInfo()->rootWindow(), fx, fy, fwidth, fheight, 0, bbtool->getCurrentScreenInfo()->depth(), InputOutput, bbtool->getCurrentScreenInfo()->visual(), create_mask, &attrib); char *name= (char *)"bbpager"; //BBTOOL; if (bbtool->configuration().isWithdrawn()) { wmhints.initial_state = WithdrawnState; } else { wmhints.initial_state = NormalState; } wmhints.flags = StateHint | InputHint; wmhints.input = False; classhints.res_name = (char *)"bbager"; // BBTOOL; classhints.res_class = (char *)"bbtools"; XStringListToTextProperty(&name, 1, &windowname); XSetWMProperties(display, win ,&windowname, NULL, bbtool->configuration().argv(), bbtool->configuration().argc(), NULL, &wmhints, &classhints); XFree(windowname.value); Atom wmproto[1]; wmproto[0] = bbtool->wmDeleteWindowAtom(); XSetWMProtocols(display, win, wmproto, 1); if (!bbtool->configuration().isDecorated() && !bbtool->configuration().isWithdrawn()) { bt::EWMH::AtomList window_type_atom; window_type_atom.push_back(bbtool->ewmh()->wmWindowTypeDock()); XChangeProperty(display, win, bbtool->ewmh()->wmWindowType(), XA_ATOM, 32, PropModeReplace, reinterpret_cast<unsigned char*>(&(window_type_atom[0])), window_type_atom.size()); } if (!bbtool->configuration().isWithdrawn()) { unsigned int dekstop_nr = static_cast<unsigned int>(-1); XChangeProperty(display, win, bbtool->ewmh()->wmDesktop(), XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<unsigned char*>(&dekstop_nr), 1); bt::EWMH::AtomList window_state_atom; window_state_atom.push_back(bbtool->ewmh()->wmStateSticky()); window_state_atom.push_back(bbtool->ewmh()->wmStateSkipTaskbar()); window_state_atom.push_back(bbtool->ewmh()->wmStateSkipPager()); XChangeProperty(display, win, bbtool->ewmh()->wmState(), XA_ATOM, 32, PropModeReplace, reinterpret_cast<unsigned char*>(&(window_state_atom[0])), window_state_atom.size()); } } else if (!bbtool->configuration().isWithdrawn()) { XMoveResizeWindow(display, win, fx, fy, fwidth, fheight); } else { XResizeWindow(display, win, fwidth, fheight); } // disable shape, until we can get it working again // if (!bbtool->configuration().isShaped()) { bt::Rect u(0, 0, fwidth, fheight); bt::drawTexture(screen, bbtool->resource->frame.texture, win, u, u, m_pixmap); // } if (!reconfigure) { XMapWindow(display, win); } } void FrameWindow::resize(void) { buildWindow(true); // reconfigure } void FrameWindow::calcSize(void) { int desktop_cols; int desktop_rows; if (bbtool->resource->position.horizontal) { desktop_cols = std::min(bbtool->numberOfDesktops(), static_cast<unsigned int>(bbtool->getResource()->columns)); desktop_rows = (int)((bbtool->numberOfDesktops() - 1) / bbtool->getResource()->columns + 1); } else { desktop_cols = (int)((bbtool->numberOfDesktops() - 1) / bbtool->getResource()->rows + 1); desktop_rows = std::min(bbtool->numberOfDesktops(), static_cast<unsigned int>(bbtool->getResource()->rows)); } int desktop_width = bbtool->getResource()->desktopSize.width + 2 * std::max(bbtool->getResource()->desktopwin.activeWidth, bbtool->getResource()->desktopwin.inactiveWidth) ; int desktop_height = bbtool->getResource()->desktopSize.height + 2 * std::max(bbtool->getResource()->desktopwin.activeWidth, bbtool->getResource()->desktopwin.inactiveWidth) ; fwidth = desktop_cols * desktop_width + (desktop_cols - 1) * bbtool->getResource()->frame.desktopMargin + 2 * bbtool->getResource()->frame.texture.borderWidth() + 2 * bbtool->getResource()->frame.bevelWidth ; fheight = desktop_rows * desktop_height + (desktop_rows - 1) * bbtool->getResource()->frame.desktopMargin + 2 * bbtool->getResource()->frame.texture.borderWidth() + 2 * bbtool->getResource()->frame.bevelWidth ; fx = bbtool->getResource()->position.x; fy = bbtool->getResource()->position.y; if (bbtool->getResource()->position.mask & XNegative) { fx = bbtool->getCurrentScreenInfo()->width() + bbtool->getResource()->position.x - fwidth; } if (bbtool->getResource()->position.mask & YNegative) { fy = bbtool->getCurrentScreenInfo()->height() + bbtool->getResource()->position.y - fheight; } } void FrameWindow::buttonPressEvent(const XButtonEvent * const event) { if (event->button == LEFT_BUTTON) { XRaiseWindow(display, win); lower = false; } if (event->button == MIDDLE_BUTTON) { XLowerWindow(display, win); lower = true; } } void FrameWindow::configureNotifyEvent(const XConfigureEvent * const event) { if (event->send_event) { if (bbtool->configuration().isWithdrawn()) bbtool->reconfigure(); int parent_x,parent_y; Window parent_root; unsigned int parent_width; unsigned int parent_height; unsigned int parent_border_width; unsigned int parent_depth; setXY( event->x, event->y); if (bbtool->configuration().isWithdrawn()) { XGetGeometry(display, event->above, &parent_root, &parent_x, &parent_y, &parent_width, &parent_height, &parent_border_width, &parent_depth); setXY(event->x + parent_x + parent_x, y() + parent_y); } else { if (bbtool->configuration().geometry().empty()) { char position[13]; sprintf(position,"+%i+%i",x(),y()); bbtool->configuration().setGeometry(position); } } } } void FrameWindow::clientMessageEvent(const XClientMessageEvent * const event) { if ((unsigned)event->data.l[0] == bbtool->wmDeleteWindowAtom()) { bbtool->shutdown(); } } void FrameWindow::exposeEvent(const XExposeEvent * const event) { bt::Rect u(0, 0, fwidth, fheight); bt::drawTexture(screen, bbtool->resource->frame.texture, win, u, u, m_pixmap); } void ToolWindow::MakeWindow(bool reconfigure) { } void ToolWindow::shutdown(void) { quit(); }