// // WorkspaceIndicator.hh for pekwm // Copyright © 2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include "Config.hh" #include "PixmapHandler.hh" #include "PScreen.hh" #include "ScreenResources.hh" #include "Workspaces.hh" #include "WorkspaceIndicator.hh" using std::cerr; using std::endl; using std::vector; /** * Display constructor */ WorkspaceIndicator::Display::Display(PWinObj *parent, Theme *theme) : PWinObj(), _theme(theme), _pixmap(None) { _parent = parent; // Do not give the indicator focus, it doesn't handle input _focusable = false; XSetWindowAttributes attr; attr.override_redirect = false; attr.event_mask = ButtonPressMask|ButtonReleaseMask|ButtonMotionMask| FocusChangeMask|KeyPressMask|KeyReleaseMask; _window = XCreateWindow(_dpy, _parent->getWindow(), 0, 0, 1, 1, 0, CopyFromParent, InputOutput, CopyFromParent, CWOverrideRedirect|CWEventMask, &attr); } /** * Display destructor */ WorkspaceIndicator::Display::~Display(void) { XDestroyWindow(_dpy, _window); ScreenResources::instance()->getPixmapHandler()->returnPixmap(_pixmap); } /** * Get required size to render workspaces. */ bool WorkspaceIndicator::Display::getSizeRequest(Geometry &gm) { Geometry head; uint head_nr = PScreen::instance()->getNearestHead(_parent->getX(), _parent->getY()); PScreen::instance()->getHeadInfo(head_nr, head); uint head_size = std::min(head.width, head.height) / Config::instance()->getWorkspaceIndicatorScale(); gm.x = gm.y = 0; gm.width = head_size * Workspaces::instance()->getPerRow() + getPaddingHorizontal(); gm.height = head_size * Workspaces::instance()->getRows() + getPaddingVertical(); return true; } /** * Render workspace view to pixmap */ void WorkspaceIndicator::Display::render(void) { Theme::WorkspaceIndicatorData &data(_theme->getWorkspaceIndicatorData()); // Make sure pixmap has correct size ScreenResources::instance()->getPixmapHandler()->returnPixmap(_pixmap); _pixmap = ScreenResources::instance()->getPixmapHandler()->getPixmap(_gm.width, _gm.height, PScreen::instance()->getDepth()); // Render background data.texture_background->render(_pixmap, 0, 0, _gm.width, _gm.height); // Render workspace grid, then active workspace fill and end with // rendering active workspace number and name renderWorkspaces(data.edge_padding, data.edge_padding, _gm.width - getPaddingHorizontal(), _gm.height - getPaddingVertical()); data.font->setColor(data.font_color); data.font->draw(_pixmap, data.edge_padding, _gm.height - data.edge_padding - data.font->getHeight(), Workspaces::instance()->getActiveWorkspace()->getName(), 0 /* max_chars */, _gm.width - data.edge_padding * 2 /* max_width */); // Refresh setBackgroundPixmap(_pixmap); clear(); } /** * Render workspace part of indication * * @param x X offset on drawable * @param y Y offset on drawable * @param width Allowed width to use * @param height Allowed height to use */ void WorkspaceIndicator::Display::renderWorkspaces(int x, int y, uint width, uint height) { Theme::WorkspaceIndicatorData &data(_theme->getWorkspaceIndicatorData()); uint per_row = Workspaces::instance()->getPerRow(); uint rows = Workspaces::instance()->getRows(); uint ws_width = width / per_row; uint ws_height = height / rows; // Starting positions of the workspace squares uint x_pos = x; uint y_pos = y; vector::iterator it(Workspaces::instance()->ws_begin()); for (uint row = 0; it != Workspaces::instance()->ws_end(); ++it) { // Check for next row if (Workspaces::instance()->getRow((*it)->getNumber()) > row) { row = Workspaces::instance()->getRow((*it)->getNumber()); x_pos = x; y_pos += ws_height + data.workspace_padding; } if ((*it)->getNumber() == Workspaces::instance()->getActive()) { data.texture_workspace_act->render(_pixmap, x_pos, y_pos, ws_width, ws_height); } else { data.texture_workspace->render(_pixmap, x_pos, y_pos, ws_width, ws_height); } x_pos += ws_width + data.workspace_padding; } } /** * Get horizontal padding for window around workspaces. */ uint WorkspaceIndicator::Display::getPaddingHorizontal(void) { Theme::WorkspaceIndicatorData &data(_theme->getWorkspaceIndicatorData()); return (data.edge_padding * 2 + data.workspace_padding * (Workspaces::instance()->getPerRow() - 1)); } /** * Get vertical padding for window around workspaces. */ uint WorkspaceIndicator::Display::getPaddingVertical(void) { Theme::WorkspaceIndicatorData &data(_theme->getWorkspaceIndicatorData()); return (data.edge_padding * 3 + data.font->getHeight() + data.workspace_padding * (Workspaces::instance()->getRows() - 1)); } /** * WorkspaceIndicator constructor */ WorkspaceIndicator::WorkspaceIndicator(Theme *theme, Timer &timer) : PDecor(theme, "WORKSPACEINDICATOR"), _timer(timer), _display_wo(this, theme), _timer_hide(0) { _type = PWinObj::WO_WORKSPACE_INDICATOR; setLayer(LAYER_NONE); // Make sure this goes on top of everything _hidden = true; // Do not include in workspace handling etc // Add hide action to timer action _action_hide.action_list.push_back(Action(ACTION_HIDE_WORKSPACE_INDICATOR)); // Add title titleAdd(&_title); titleSetActive(0); _title.setReal(L"Workspace"); // Add display window addChild(&_display_wo); activateChild(&_display_wo); _display_wo.mapWindow(); // Load theme data, horay for pretty colors loadTheme(); // Register ourselves Workspaces::instance()->insert(this); woListAdd(this); _wo_map[_window] = this; #ifdef OPACITY setOpacity(Config::instance()->getWorkspaceIndicatorOpacity()); #endif // OPACITY } /** * WorkspaceIndicator destructor */ WorkspaceIndicator::~WorkspaceIndicator(void) { removeChild(&_display_wo, false); // Un-register ourselves Workspaces::instance()->remove(this); _wo_map.erase(_window); woListRemove(this); } /** * Resize indicator and render */ void WorkspaceIndicator::render(void) { // Center on head Geometry head, request; PScreen::instance()->getHeadInfo(PScreen::instance()->getCurrHead(), head); _display_wo.getSizeRequest(request); resizeChild(request.width, request.height); move(head.x + (head.width - _gm.width) / 2, head.y + (head.height - _gm.height) / 2); // Render workspaces _display_wo.render(); } /** * Remove previous timer and add new hide timer for timeout seconds in * the future. */ void WorkspaceIndicator::updateHideTimer(uint timeout) { if (_timer_hide) { _timer.remove(_timer_hide); } _timer_hide = _timer.add(timeout, ActionPerformed(this, _action_hide)); }