// Window.cc for Fluxbox Window Manager // Copyright (c) 2001 - 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net) // // Window.cc for Blackbox - an X11 Window manager // Copyright (c) 1997 - 2000 Brad Hughes (bhughes at tcac.net) // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // $Id: Window.cc,v 1.152 2003/04/27 12:31:43 fluxgen Exp $ #include "Window.hh" #include "WinClient.hh" #include "i18n.hh" #include "fluxbox.hh" #include "Screen.hh" #include "StringUtil.hh" #include "Netizen.hh" #include "FbWinFrameTheme.hh" #include "MenuTheme.hh" #include "TextButton.hh" #include "EventManager.hh" #include "FbAtoms.hh" #include "RootTheme.hh" #include "Workspace.hh" #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H //use GNU extensions #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif // _GNU_SOURCE #include #include #include #include #include #include using namespace std; namespace { void grabButton(Display *display, unsigned int button, Window window, Cursor cursor) { //numlock XGrabButton(display, button, Mod1Mask|Mod2Mask, window, True, ButtonReleaseMask | ButtonMotionMask, GrabModeAsync, GrabModeAsync, None, cursor); //scrolllock XGrabButton(display, button, Mod1Mask|Mod5Mask, window, True, ButtonReleaseMask | ButtonMotionMask, GrabModeAsync, GrabModeAsync, None, cursor); //capslock XGrabButton(display, button, Mod1Mask|LockMask, window, True, ButtonReleaseMask | ButtonMotionMask, GrabModeAsync, GrabModeAsync, None, cursor); //capslock+numlock XGrabButton(display, Button1, Mod1Mask|LockMask|Mod2Mask, window, True, ButtonReleaseMask | ButtonMotionMask, GrabModeAsync, GrabModeAsync, None, cursor); //capslock+scrolllock XGrabButton(display, button, Mod1Mask|LockMask|Mod5Mask, window, True, ButtonReleaseMask | ButtonMotionMask, GrabModeAsync, GrabModeAsync, None, cursor); //capslock+numlock+scrolllock XGrabButton(display, button, Mod1Mask|LockMask|Mod2Mask|Mod5Mask, window, True, ButtonReleaseMask | ButtonMotionMask, GrabModeAsync, GrabModeAsync, None, cursor); //numlock+scrollLock XGrabButton(display, button, Mod1Mask|Mod2Mask|Mod5Mask, window, True, ButtonReleaseMask | ButtonMotionMask, GrabModeAsync, GrabModeAsync, None, cursor); } // X event scanner for enter/leave notifies - adapted from twm typedef struct scanargs { Window w; Bool leave, inferior, enter; } scanargs; // look for valid enter or leave events (that may invalidate the earlier one we are interested in) static Bool queueScanner(Display *, XEvent *e, char *args) { if (e->type == LeaveNotify && e->xcrossing.window == ((scanargs *) args)->w && e->xcrossing.mode == NotifyNormal) { ((scanargs *) args)->leave = true; ((scanargs *) args)->inferior = (e->xcrossing.detail == NotifyInferior); } else if (e->type == EnterNotify && e->xcrossing.mode == NotifyUngrab) ((scanargs *) args)->enter = true; return false; } /// raise window and do the same for each transient it holds void raiseFluxboxWindow(FluxboxWindow &win) { if (!win.isIconic()) { win.getScreen().updateNetizenWindowRaise(win.getClientWindow()); win.getLayerItem().raise(); } // for each transient do raise std::list::const_iterator it = win.getTransients().begin(); std::list::const_iterator it_end = win.getTransients().end(); for (; it != it_end; ++it) { if (!(*it)->isIconic()) raiseFluxboxWindow(*(*it)); } } /// lower window and do the same for each transient it holds void lowerFluxboxWindow(FluxboxWindow &win) { if (!win.isIconic()) { win.getScreen().updateNetizenWindowLower(win.getClientWindow()); win.getLayerItem().lower(); } // for each transient do lower std::list::const_iterator it = win.getTransients().begin(); std::list::const_iterator it_end = win.getTransients().end(); for (; it != it_end; ++it) { if (!(*it)->isIconic()) lowerFluxboxWindow(*(*it)); } } /// raise window and do the same for each transient it holds void tempRaiseFluxboxWindow(FluxboxWindow &win) { if (!win.isIconic()) { // don't update netizen, as it is only temporary win.getLayerItem().tempRaise(); } // for each transient do raise std::list::const_iterator it = win.getTransients().begin(); std::list::const_iterator it_end = win.getTransients().end(); for (; it != it_end; ++it) { if (!(*it)->isIconic()) tempRaiseFluxboxWindow(*(*it)); } } class SetClientCmd:public FbTk::Command { public: explicit SetClientCmd(WinClient &client):m_client(client) { } void execute() { if (m_client.m_win != 0) m_client.m_win->setCurrentClient(m_client); } private: WinClient &m_client; }; }; template <> void LayerMenuItem::click(int button, int time) { m_object->moveToLayer(m_layernum); } FluxboxWindow::FluxboxWindow(WinClient &client, BScreen &scr, FbWinFrameTheme &tm, FbTk::MenuTheme &menutheme, FbTk::XLayer &layer): m_hintsig(*this), m_statesig(*this), m_layersig(*this), m_workspacesig(*this), m_diesig(*this), moving(false), resizing(false), shaded(false), maximized(false), visible(false), iconic(false), transient(false), focused(false), stuck(false), modal(false), send_focus_message(false), m_managed(false), screen(scr), timer(this), display(0), lastButtonPressTime(0), m_windowmenu(menutheme, scr.getScreenNumber(), *scr.getImageControl()), m_layermenu(menutheme, scr.getScreenNumber(), *scr.getImageControl(), *scr.layerManager().getLayer(Fluxbox::instance()->getMenuLayer()), this, false), old_decoration(DECOR_NORMAL), m_client(&client), m_frame(tm, *scr.getImageControl(), scr.getScreenNumber(), 0, 0, 100, 100), m_layeritem(m_frame.window(), layer), m_layernum(layer.getLayerNum()) { init(); } FluxboxWindow::FluxboxWindow(Window w, BScreen &scr, FbWinFrameTheme &tm, FbTk::MenuTheme &menutheme, FbTk::XLayer &layer): m_hintsig(*this), m_statesig(*this), m_layersig(*this), m_workspacesig(*this), m_diesig(*this), moving(false), resizing(false), shaded(false), maximized(false), visible(false), iconic(false), transient(false), focused(false), stuck(false), modal(false), send_focus_message(false), m_managed(false), screen(scr), timer(this), display(0), lastButtonPressTime(0), m_windowmenu(menutheme, scr.getScreenNumber(), *scr.getImageControl()), m_layermenu(menutheme, scr.getScreenNumber(), *scr.getImageControl(), *scr.layerManager().getLayer(Fluxbox::instance()->getMenuLayer()), this, false), old_decoration(DECOR_NORMAL), m_client(new WinClient(w, *this)), m_frame(tm, *scr.getImageControl(), scr.getScreenNumber(), 0, 0, 100, 100), m_layeritem(m_frame.window(), layer), m_layernum(layer.getLayerNum()) { assert(w != 0); init(); } FluxboxWindow::~FluxboxWindow() { #ifdef DEBUG cerr<<__FILE__<<"("<<__LINE__<<"): starting ~FluxboxWindow("< 1) { cerr<<__FILE__<<"("<<__FUNCTION__<<") WARNING! clientlist > 1"<removeWindowSearch(m_frame.window().window()); #ifdef DEBUG cerr<<__FILE__<<"("<<__LINE__<<"): ~FluxboxWindow("<width(), m_client->height()); TextButton *btn = new TextButton(m_frame.label(), m_frame.theme().font(), m_client->title()); btn->setJustify(m_frame.theme().justify()); m_labelbuttons[m_client] = btn; m_frame.addLabelButton(*btn); m_frame.setLabelButtonFocus(*btn); btn->show(); FbTk::EventManager &evm = *FbTk::EventManager::instance(); // we need motion notify so we mask it btn->window().setEventMask(ExposureMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask); FbTk::RefCount set_client_cmd(new SetClientCmd(*m_client)); btn->setOnClick(set_client_cmd); evm.add(*this, btn->window()); // we take care of button events for this // m_frame.reconfigure(); // redirect events from frame to us m_frame.setEventHandler(*this); lastFocusTime.tv_sec = lastFocusTime.tv_usec = 0; // display connection display = FbTk::App::instance()->display(); blackbox_attrib.workspace = workspace_number = move_ws = window_number = -1; blackbox_attrib.flags = blackbox_attrib.attrib = blackbox_attrib.stack = 0; blackbox_attrib.premax_x = blackbox_attrib.premax_y = 0; blackbox_attrib.premax_w = blackbox_attrib.premax_h = 0; //use tab as default decorations.tab = true; // enable decorations decorations.enabled = true; // set default values for decoration decorations.menu = true; //override menu option // all decorations on by default decorations.titlebar = decorations.border = decorations.handle = true; decorations.maximize = decorations.close = decorations.sticky = decorations.shade = decorations.tab = true; functions.resize = functions.move = functions.iconify = functions.maximize = true; functions.close = decorations.close = false; getBlackboxHints(); if (! m_client->blackbox_hint) getMWMHints(); // get size, aspect, minimum/maximum size and other hints set // by the client getWMProtocols(); getWMHints(); getWMNormalHints(); //!! // fetch client size and placement XWindowAttributes wattrib; if (! m_client->getAttrib(wattrib) || !wattrib.screen // no screen? ?? || wattrib.override_redirect) { // override redirect return; } // save old border width so we can restore it later m_client->old_bw = wattrib.border_width; m_client->x = wattrib.x; m_client->y = wattrib.y; Fluxbox *fluxbox = Fluxbox::instance(); fluxbox->saveWindowSearch(m_frame.window().window(), this); timer.setTimeout(fluxbox->getAutoRaiseDelay()); timer.fireOnce(true); if (m_client->initial_state == WithdrawnState) { return; } m_managed = true; //this window is managed // update transient infomation updateTransientInfo(); // adjust the window decorations based on transience and window sizes if (transient) { decorations.maximize = functions.maximize = false; decorations.handle = decorations.border = false; } if ((m_client->normal_hint_flags & PMinSize) && (m_client->normal_hint_flags & PMaxSize) && m_client->max_width != 0 && m_client->max_width <= m_client->min_width && m_client->max_height != 0 && m_client->max_height <= m_client->min_height) { decorations.maximize = decorations.handle = functions.resize = functions.maximize = false; decorations.tab = false; //no tab for this window } upsize(); bool place_window = true; if (fluxbox->isStartup() || transient || m_client->normal_hint_flags & (PPosition|USPosition)) { setGravityOffsets(); if (! fluxbox->isStartup()) { int real_x = m_frame.x(); int real_y = m_frame.y(); if (real_x >= 0 && real_y + m_frame.y() >= 0 && real_x <= (signed) screen.getWidth() && real_y <= (signed) screen.getHeight()) place_window = false; } else place_window = false; } associateClientWindow(); grabButtons(); positionWindows(); if (workspace_number < 0 || workspace_number >= screen.getCount()) workspace_number = screen.getCurrentWorkspaceID(); restoreAttributes(); m_frame.move(wattrib.x, wattrib.y); m_frame.resizeForClient(wattrib.width, wattrib.height); // if we're a transient then we should be on the same layer as our parent if (isTransient()) getLayerItem().setLayer(getTransientFor()->getLayerItem().getLayer()); else // if no parent then set default layer moveToLayer(m_layernum); if (!place_window) moveResize(m_frame.x(), m_frame.y(), m_frame.width(), m_frame.height()); screen.getWorkspace(workspace_number)->addWindow(*this, place_window); if (shaded) { // start shaded shaded = false; shade(); } if (maximized && functions.maximize) { // start maximized maximized = false; maximize(); } if (stuck) { stuck = false; stick(); deiconify(); //we're omnipresent and visible } setState(current_state); m_frame.reconfigure(); sendConfigureNotify(); // no focus default setFocusFlag(false); } /// attach a client to this window and destroy old window void FluxboxWindow::attachClient(WinClient &client) { //!! TODO: check for isGroupable in client if (client.m_win == this) return; // reparent client win to this frame m_frame.setClientWindow(client); if (client.fbwindow() != 0) { FluxboxWindow *old_win = client.fbwindow(); // store old window Fluxbox *fb = Fluxbox::instance(); // make sure we set new window search for each client ClientList::iterator client_it = old_win->clientList().begin(); ClientList::iterator client_it_end = old_win->clientList().end(); for (; client_it != client_it_end; ++client_it) { fb->saveWindowSearch((*client_it)->window(), this); // reparent window to this m_frame.setClientWindow(**client_it); resizeClient(**client_it, m_frame.clientArea().width(), m_frame.clientArea().height()); (*client_it)->m_win = this; // create a labelbutton for this client and // associate it with the pointer TextButton *btn = new TextButton(m_frame.label(), m_frame.theme().font(), (*client_it)->title()); btn->setJustify(m_frame.theme().justify()); m_labelbuttons[(*client_it)] = btn; m_frame.addLabelButton(*btn); btn->show(); FbTk::EventManager &evm = *FbTk::EventManager::instance(); // we need motion notify so we mask it btn->window().setEventMask(ExposureMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask); FbTk::RefCount set_client_cmd(new SetClientCmd(*(*client_it))); btn->setOnClick(set_client_cmd); evm.add(*this, btn->window()); // we take care of button events for this // update transients in client to have this as transient_for WinClient::TransientList::iterator trans_it = (*client_it)->transientList().begin(); WinClient::TransientList::iterator trans_it_end = (*client_it)->transientList().end(); for (; trans_it != trans_it_end; ++trans_it) { (*trans_it)->m_client->transient_for = this; } } // add client and move over all attached clients // from the old window to this list m_clientlist.splice(m_clientlist.end(), old_win->m_clientlist); old_win->m_client = 0; delete old_win; } else { // create a labelbutton for this client and associate it with the pointer TextButton *btn = new TextButton(m_frame.label(), m_frame.theme().font(), client.title()); m_labelbuttons[&client] = btn; m_frame.addLabelButton(*btn); btn->show(); FbTk::EventManager &evm = *FbTk::EventManager::instance(); // we need motion notify so we mask it btn->window().setEventMask(ExposureMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask); FbTk::RefCount set_client_cmd(new SetClientCmd(client)); btn->setOnClick(set_client_cmd); evm.add(*this, btn->window()); // we take care of button events for this client.m_win = this; // update transients in client to have this as transient_for WinClient::TransientList::iterator trans_it = client.transientList().begin(); WinClient::TransientList::iterator trans_it_end = client.transientList().end(); for (; trans_it != trans_it_end; ++trans_it) { (*trans_it)->m_client->transient_for = this; } Fluxbox::instance()->saveWindowSearch(client.window(), this); } m_frame.reconfigure(); // keep the current window on top m_client->raise(); } /// detach client from window and create a new window for it bool FluxboxWindow::detachClient(WinClient &client) { if (client.m_win != this || numClients() <= 1) return false; removeClient(client); client.m_win = screen.createWindow(client); m_client->raise(); setInputFocus(); return true; } void FluxboxWindow::detachCurrentClient() { // should only operate if we had more than one client if (numClients() <= 1) return; detachClient(*m_client); } /// removes client from client list, does not create new fluxboxwindow for it bool FluxboxWindow::removeClient(WinClient &client) { if (client.m_win != this || numClients() == 0) return false; #ifdef DEBUG cerr<<__FILE__<<"("<<__FUNCTION__<<")["<remove(label_btn->window()); delete label_btn; label_btn = 0; } m_labelbuttons.erase(&client); #ifdef DEBUG cerr<<__FILE__<<"("<<__FUNCTION__<<")["<getMoveCursor()); XGrabButton(display, Button2, Mod1Mask, m_frame.window().window(), True, ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None); XGrabButton(display, Button3, Mod1Mask, m_frame.window().window(), True, ButtonReleaseMask | ButtonMotionMask, GrabModeAsync, GrabModeAsync, None, fluxbox->getLowerRightAngleCursor()); //---grab with "all" modifiers grabButton(display, Button3, m_frame.window().window(), fluxbox->getLowerRightAngleCursor()); } void FluxboxWindow::reconfigure() { upsize(); positionWindows(); setFocusFlag(focused); moveResize(m_frame.x(), m_frame.y(), m_frame.width(), m_frame.height()); grabButtons(); m_frame.setDoubleClickTime(Fluxbox::instance()->getDoubleClickInterval()); m_windowmenu.reconfigure(); } void FluxboxWindow::positionWindows() { m_frame.window().setBorderWidth(screen.rootTheme().borderWidth()); m_frame.clientArea().setBorderWidth(0); // client area bordered by other things m_frame.titlebar().setBorderWidth(screen.rootTheme().borderWidth()); if (decorations.titlebar) { m_frame.showTitlebar(); } else { m_frame.hideTitlebar(); } m_frame.handle().setBorderWidth(screen.rootTheme().borderWidth()); m_frame.gripLeft().setBorderWidth(screen.rootTheme().borderWidth()); m_frame.gripRight().setBorderWidth(screen.rootTheme().borderWidth()); if (decorations.handle) m_frame.showHandle(); else m_frame.hideHandle(); m_frame.reconfigure(); } /// update current client title and title in our frame void FluxboxWindow::updateTitleFromClient() { m_client->updateTitle(); m_labelbuttons[m_client]->setText(m_client->title()); m_labelbuttons[m_client]->clear(); // redraw text } /// update icon title from client void FluxboxWindow::updateIconNameFromClient() { m_client->updateIconTitle(); } void FluxboxWindow::getWMProtocols() { Atom *proto = 0; int num_return = 0; FbAtoms *fbatoms = FbAtoms::instance(); if (XGetWMProtocols(display, m_client->window(), &proto, &num_return)) { for (int i = 0; i < num_return; ++i) { if (proto[i] == fbatoms->getWMDeleteAtom()) functions.close = true; else if (proto[i] == fbatoms->getWMTakeFocusAtom()) send_focus_message = true; else if (proto[i] == fbatoms->getFluxboxStructureMessagesAtom()) screen.addNetizen(new Netizen(&screen, m_client->window())); } XFree(proto); } else { cerr<<"Warning: Failed to read WM Protocols. "<window()); if (! wmhint) { visible = true; iconic = false; focus_mode = F_PASSIVE; m_client->window_group = None; m_client->initial_state = NormalState; } else { m_client->wm_hint_flags = wmhint->flags; if (wmhint->flags & InputHint) { if (wmhint->input) { if (send_focus_message) focus_mode = F_LOCALLYACTIVE; else focus_mode = F_PASSIVE; } else { if (send_focus_message) focus_mode = F_GLOBALLYACTIVE; else focus_mode = F_NOINPUT; } } else focus_mode = F_PASSIVE; if (wmhint->flags & StateHint) m_client->initial_state = wmhint->initial_state; else m_client->initial_state = NormalState; if (wmhint->flags & WindowGroupHint) { if (! m_client->window_group) { m_client->window_group = wmhint->window_group; Fluxbox::instance()->saveGroupSearch(m_client->window_group, this); } } else m_client->window_group = None; XFree(wmhint); } } void FluxboxWindow::getWMNormalHints() { long icccm_mask; XSizeHints sizehint; if (! XGetWMNormalHints(display, m_client->window(), &sizehint, &icccm_mask)) { m_client->min_width = m_client->min_height = m_client->base_width = m_client->base_height = m_client->width_inc = m_client->height_inc = 1; m_client->max_width = 0; // unbounded m_client->max_height = 0; m_client->min_aspect_x = m_client->min_aspect_y = m_client->max_aspect_x = m_client->max_aspect_y = 1; m_client->win_gravity = NorthWestGravity; } else { m_client->normal_hint_flags = sizehint.flags; if (sizehint.flags & PMinSize) { m_client->min_width = sizehint.min_width; m_client->min_height = sizehint.min_height; } else m_client->min_width = m_client->min_height = 1; if (sizehint.flags & PMaxSize) { m_client->max_width = sizehint.max_width; m_client->max_height = sizehint.max_height; } else { m_client->max_width = 0; // unbounded m_client->max_height = 0; } if (sizehint.flags & PResizeInc) { m_client->width_inc = sizehint.width_inc; m_client->height_inc = sizehint.height_inc; } else m_client->width_inc = m_client->height_inc = 1; if (sizehint.flags & PAspect) { m_client->min_aspect_x = sizehint.min_aspect.x; m_client->min_aspect_y = sizehint.min_aspect.y; m_client->max_aspect_x = sizehint.max_aspect.x; m_client->max_aspect_y = sizehint.max_aspect.y; } else m_client->min_aspect_x = m_client->min_aspect_y = m_client->max_aspect_x = m_client->max_aspect_y = 1; if (sizehint.flags & PBaseSize) { m_client->base_width = sizehint.base_width; m_client->base_height = sizehint.base_height; } else m_client->base_width = m_client->base_height = 0; if (sizehint.flags & PWinGravity) m_client->win_gravity = sizehint.win_gravity; else m_client->win_gravity = NorthWestGravity; } } void FluxboxWindow::getMWMHints() { int format; Atom atom_return; unsigned long num, len; Atom motif_wm_hints = XInternAtom(display, "_MOTIF_WM_HINTS", False); if (!XGetWindowProperty(display, m_client->window(), motif_wm_hints, 0, PropMwmHintsElements, false, motif_wm_hints, &atom_return, &format, &num, &len, (unsigned char **) &m_client->mwm_hint) == Success && m_client->mwm_hint) { return; } if (num != PropMwmHintsElements) return; if (m_client->mwm_hint->flags & MwmHintsDecorations) { if (m_client->mwm_hint->decorations & MwmDecorAll) { decorations.titlebar = decorations.handle = decorations.border = decorations.iconify = decorations.maximize = decorations.close = decorations.menu = true; } else { decorations.titlebar = decorations.handle = decorations.border = decorations.iconify = decorations.maximize = decorations.close = decorations.tab = false; decorations.menu = true; if (m_client->mwm_hint->decorations & MwmDecorBorder) decorations.border = true; if (m_client->mwm_hint->decorations & MwmDecorHandle) decorations.handle = true; if (m_client->mwm_hint->decorations & MwmDecorTitle) { //only tab on windows with titlebar decorations.titlebar = decorations.tab = true; } if (m_client->mwm_hint->decorations & MwmDecorMenu) decorations.menu = true; if (m_client->mwm_hint->decorations & MwmDecorIconify) decorations.iconify = true; if (m_client->mwm_hint->decorations & MwmDecorMaximize) decorations.maximize = true; } } if (m_client->mwm_hint->flags & MwmHintsFunctions) { if (m_client->mwm_hint->functions & MwmFuncAll) { functions.resize = functions.move = functions.iconify = functions.maximize = functions.close = true; } else { functions.resize = functions.move = functions.iconify = functions.maximize = functions.close = false; if (m_client->mwm_hint->functions & MwmFuncResize) functions.resize = true; if (m_client->mwm_hint->functions & MwmFuncMove) functions.move = true; if (m_client->mwm_hint->functions & MwmFuncIconify) functions.iconify = true; if (m_client->mwm_hint->functions & MwmFuncMaximize) functions.maximize = true; if (m_client->mwm_hint->functions & MwmFuncClose) functions.close = true; } } } void FluxboxWindow::getBlackboxHints() { int format; Atom atom_return; unsigned long num, len; FbAtoms *atoms = FbAtoms::instance(); if (XGetWindowProperty(display, m_client->window(), atoms->getFluxboxHintsAtom(), 0, PropBlackboxHintsElements, False, atoms->getFluxboxHintsAtom(), &atom_return, &format, &num, &len, (unsigned char **) &m_client->blackbox_hint) == Success && m_client->blackbox_hint) { if (num == PropBlackboxHintsElements) { if (m_client->blackbox_hint->flags & BaseDisplay::ATTRIB_SHADED) shaded = (m_client->blackbox_hint->attrib & BaseDisplay::ATTRIB_SHADED); if ((m_client->blackbox_hint->flags & BaseDisplay::ATTRIB_MAXHORIZ) && (m_client->blackbox_hint->flags & BaseDisplay::ATTRIB_MAXVERT)) maximized = ((m_client->blackbox_hint->attrib & (BaseDisplay::ATTRIB_MAXHORIZ | BaseDisplay::ATTRIB_MAXVERT)) ? 1 : 0); else if (m_client->blackbox_hint->flags & BaseDisplay::ATTRIB_MAXVERT) maximized = ((m_client->blackbox_hint->attrib & BaseDisplay::ATTRIB_MAXVERT) ? 2 : 0); else if (m_client->blackbox_hint->flags & BaseDisplay::ATTRIB_MAXHORIZ) maximized = ((m_client->blackbox_hint->attrib & BaseDisplay::ATTRIB_MAXHORIZ) ? 3 : 0); if (m_client->blackbox_hint->flags & BaseDisplay::ATTRIB_OMNIPRESENT) stuck = (m_client->blackbox_hint->attrib & BaseDisplay::ATTRIB_OMNIPRESENT); if (m_client->blackbox_hint->flags & BaseDisplay::ATTRIB_WORKSPACE) workspace_number = m_client->blackbox_hint->workspace; if (m_client->blackbox_hint->flags & BaseDisplay::ATTRIB_STACK) workspace_number = m_client->blackbox_hint->stack; if (m_client->blackbox_hint->flags & BaseDisplay::ATTRIB_DECORATION) { old_decoration = static_cast(m_client->blackbox_hint->decoration); setDecoration(old_decoration); } } } } void FluxboxWindow::move(int x, int y) { moveResize(x, y, m_frame.width(), m_frame.height()); } void FluxboxWindow::resize(unsigned int width, unsigned int height) { moveResize(m_frame.x(), m_frame.y(), width, height); } void FluxboxWindow::moveResize(int new_x, int new_y, unsigned int new_width, unsigned int new_height) { bool send_event = (m_frame.x() != new_x || m_frame.y() != new_y); if (new_width != m_frame.width() || new_height != m_frame.height()) { if ((((signed) m_frame.width()) + new_x) < 0) new_x = 0; if ((((signed) m_frame.height()) + new_y) < 0) new_y = 0; downsize(); m_frame.moveResize(new_x, new_y, new_width, new_height); setFocusFlag(focused); shaded = false; send_event = true; } else { m_frame.move(new_x, new_y); send_event = true; } if (send_event && ! moving) { sendConfigureNotify(); } } bool FluxboxWindow::setInputFocus() { //TODO hint skip focus if (((signed) (m_frame.x() + m_frame.width())) < 0) { if (((signed) (m_frame.y() + m_frame.height())) < 0) { moveResize(screen.rootTheme().borderWidth(), screen.rootTheme().borderWidth(), m_frame.width(), m_frame.height()); } else if (m_frame.y() > (signed) screen.getHeight()) { moveResize(screen.rootTheme().borderWidth(), screen.getHeight() - m_frame.height(), m_frame.width(), m_frame.height()); } else { moveResize(screen.rootTheme().borderWidth(), m_frame.y() + screen.rootTheme().borderWidth(), m_frame.width(), m_frame.height()); } } else if (m_frame.x() > (signed) screen.getWidth()) { if (((signed) (m_frame.y() + m_frame.height())) < 0) { moveResize(screen.getWidth() - m_frame.width(), screen.rootTheme().borderWidth(), m_frame.width(), m_frame.height()); } else if (m_frame.y() > (signed) screen.getHeight()) { moveResize(screen.getWidth() - m_frame.width(), screen.getHeight() - m_frame.height(), m_frame.width(), m_frame.height()); } else { moveResize(screen.getWidth() - m_frame.width(), m_frame.y() + screen.rootTheme().borderWidth(), m_frame.width(), m_frame.height()); } } if (! validateClient()) return false; bool ret = false; if (m_client->transients.size() && modal) { std::list::iterator it = m_client->transients.begin(); std::list::iterator it_end = m_client->transients.end(); for (; it != it_end; ++it) { if ((*it)->modal) return (*it)->setInputFocus(); } } else { if (focus_mode == F_LOCALLYACTIVE || focus_mode == F_PASSIVE) { XSetInputFocus(display, m_client->window(), RevertToPointerRoot, CurrentTime); } else { return false; } m_frame.setFocus(true); screen.setFocusedWindow(*m_client); Fluxbox::instance()->setFocusedWindow(this); if (send_focus_message) m_client->sendFocus(); if ((screen.isSloppyFocus() || screen.isSemiSloppyFocus()) && screen.doAutoRaise()) timer.start(); ret = true; } return ret; } void FluxboxWindow::hide() { #ifdef DEBUG cerr<<__FILE__<<"("<<__FUNCTION__<<")["<isIconic()) { client.transientFor()->iconify(); } } if (client.transientList().size()) { for_each(client.transientList().begin(), client.transientList().end(), mem_fun(&FluxboxWindow::iconify)); } } } void FluxboxWindow::deiconify(bool reassoc, bool do_raise) { if (iconic || reassoc) { screen.reassociateWindow(this, screen.getCurrentWorkspace()->workspaceID(), false); } else if (moving || workspace_number != screen.getCurrentWorkspace()->workspaceID()) return; bool was_iconic = iconic; iconic = false; visible = true; setState(NormalState); ClientList::iterator client_it = clientList().begin(); ClientList::iterator client_it_end = clientList().end(); for (; client_it != client_it_end; ++client_it) { (*client_it)->setEventMask(NoEventMask); (*client_it)->show(); (*client_it)->setEventMask(PropertyChangeMask | StructureNotifyMask | FocusChangeMask); } m_frame.show(); if (was_iconic && screen.doFocusNew()) setInputFocus(); if (focused != m_frame.focused()) m_frame.setFocus(focused); if (reassoc && m_client->transients.size()) { // deiconify all transients client_it = clientList().begin(); for (; client_it != client_it_end; ++client_it) { std::list::iterator trans_it = (*client_it)->transientList().begin(); std::list::iterator trans_it_end = (*client_it)->transientList().end(); for (; trans_it != trans_it_end; ++trans_it) { (*trans_it)->deiconify(true, false); } } } if (do_raise) raise(); } /** Send close request to client window */ void FluxboxWindow::close() { #ifdef DEBUG cerr<<__FILE__<<"("<<__FUNCTION__<<")"<sendClose(); } /** Set window in withdrawn state */ void FluxboxWindow::withdraw() { visible = false; iconic = false; if (isResizing()) stopResizing(); m_frame.hide(); m_windowmenu.hide(); } /** Maximize window both horizontal and vertical */ void FluxboxWindow::maximize() { if (isIconic()) deiconify(); if (!maximized) { // save old values m_old_width = frame().width(); m_old_height = frame().height(); m_old_pos_x = frame().x(); m_old_pos_y = frame().y(); unsigned int left_x = screen.getMaxLeft(); unsigned int max_width = screen.getMaxRight(); unsigned int max_top = screen.getMaxTop(); moveResize(left_x, max_top, max_width - left_x, screen.getMaxBottom() - max_top - m_frame.window().borderWidth()); } else { // demaximize, restore to old values moveResize(m_old_pos_x, m_old_pos_y, m_old_width, m_old_height); } // toggle maximize maximized = !maximized; } void FluxboxWindow::maximizeHorizontal() { unsigned int left_x = screen.getMaxLeft(); unsigned int max_width = screen.getMaxRight(); moveResize(left_x, m_frame.y(), max_width - left_x, m_frame.height() - m_frame.window().borderWidth()); } /** Maximize window horizontal */ void FluxboxWindow::maximizeVertical() { unsigned int max_top = screen.getMaxTop(); moveResize(m_frame.x(), max_top, m_frame.width() - m_frame.window().borderWidth(), screen.getMaxBottom() - max_top); } void FluxboxWindow::setWorkspace(int n) { workspace_number = n; blackbox_attrib.flags |= BaseDisplay::ATTRIB_WORKSPACE; blackbox_attrib.workspace = workspace_number; // notify workspace change #ifdef DEBUG cerr<getTransientFor()) { win = win->getTransientFor(); assert(win != win->getTransientFor()); } // if we don't have any root window use this as root if (win == 0) win = this; // raise this window and every transient in it raiseFluxboxWindow(*win); } void FluxboxWindow::lower() { if (isIconic()) deiconify(); // get root window (i.e the bottom window) FluxboxWindow *bottom = this; while (bottom->getTransientFor()) { bottom = bottom->getTransientFor(); assert(bottom != bottom->getTransientFor()); } if (bottom == 0) bottom = this; lowerFluxboxWindow(*bottom); } void FluxboxWindow::tempRaise() { if (isIconic()) deiconify(); // get root window FluxboxWindow *win = this; while (win->getTransientFor()) { win = win->getTransientFor(); assert(win != win->getTransientFor()); } // if we don't have any root window use this as root if (win == 0) win = this; // raise this window and every transient in it tempRaiseFluxboxWindow(*win); } void FluxboxWindow::raiseLayer() { // don't let it up to menu layer if (getLayerNum() == (Fluxbox::instance()->getMenuLayer()+1)) return; FluxboxWindow *win = this; while (win->getTransientFor()) { win = win->getTransientFor(); assert(win != win->getTransientFor()); } if (!win->isIconic()) { screen.updateNetizenWindowRaise(win->getClientWindow()); win->getLayerItem().raiseLayer(); win->setLayerNum(win->getLayerItem().getLayerNum()); } std::list::const_iterator it = win->getTransients().begin(); std::list::const_iterator it_end = win->getTransients().end(); for (; it != it_end; ++it) { if (!(*it)->isIconic()) { screen.updateNetizenWindowRaise((*it)->getClientWindow()); (*it)->getLayerItem().raiseLayer(); (*it)->setLayerNum((*it)->getLayerItem().getLayerNum()); } } } void FluxboxWindow::lowerLayer() { FluxboxWindow *win = (FluxboxWindow *) 0, *bottom = this; while (bottom->getTransientFor()) { bottom = bottom->getTransientFor(); assert(bottom != bottom->getTransientFor()); } win = bottom; if (!win->isIconic()) { screen.updateNetizenWindowLower(win->getClientWindow()); win->getLayerItem().lowerLayer(); win->setLayerNum(win->getLayerItem().getLayerNum()); } std::list::const_iterator it = win->getTransients().begin(); std::list::const_iterator it_end = win->getTransients().end(); for (; it != it_end; ++it) { if (!(*it)->isIconic()) { screen.updateNetizenWindowLower((*it)->getClientWindow()); (*it)->getLayerItem().lowerLayer(); (*it)->setLayerNum((*it)->getLayerItem().getLayerNum()); } } } void FluxboxWindow::moveToLayer(int layernum) { Fluxbox * fluxbox = Fluxbox::instance(); FluxboxWindow *win = this; // don't let it set its layer into menu area if (layernum <= fluxbox->getMenuLayer()) { layernum = fluxbox->getMenuLayer() + 1; } while (win->getTransientFor()) { win = win->getTransientFor(); assert(win != win->getTransientFor()); } if (!win->isIconic()) { screen.updateNetizenWindowRaise(win->getClientWindow()); win->getLayerItem().moveToLayer(layernum); win->setLayerNum(win->getLayerItem().getLayerNum()); } std::list::const_iterator it = win->getTransients().begin(); std::list::const_iterator it_end = win->getTransients().end(); for (; it != it_end; ++it) { if (!(*it)->isIconic()) { screen.updateNetizenWindowRaise((*it)->getClientWindow()); (*it)->getLayerItem().moveToLayer(layernum); (*it)->setLayerNum((*it)->getLayerItem().getLayerNum()); } } } void FluxboxWindow::setFocusFlag(bool focus) { focused = focus; // Record focus timestamp for window cycling enhancements if (focused) gettimeofday(&lastFocusTime, 0); m_frame.setFocus(focus); if ((screen.isSloppyFocus() || screen.isSemiSloppyFocus()) && screen.doAutoRaise()) timer.stop(); } void FluxboxWindow::installColormap(bool install) { Fluxbox *fluxbox = Fluxbox::instance(); fluxbox->grab(); if (! validateClient()) return; int i = 0, ncmap = 0; Colormap *cmaps = XListInstalledColormaps(display, m_client->window(), &ncmap); XWindowAttributes wattrib; if (cmaps) { //!! if (m_client->getAttrib(wattrib)) { if (install) { // install the window's colormap for (i = 0; i < ncmap; i++) { if (*(cmaps + i) == wattrib.colormap) { // this window is using an installed color map... do not install install = false; break; //end for-loop (we dont need to check more) } } // otherwise, install the window's colormap if (install) XInstallColormap(display, wattrib.colormap); } else { for (i = 0; i < ncmap; i++) { // uninstall the window's colormap if (*(cmaps + i) == wattrib.colormap) XUninstallColormap(display, wattrib.colormap); } } } XFree(cmaps); } fluxbox->ungrab(); } /** Saves blackbox hints for every client in our list */ void FluxboxWindow::saveBlackboxHints() { for_each(m_clientlist.begin(), m_clientlist.end(), FbTk::ChangeProperty(display, FbAtoms::instance()->getFluxboxAttributesAtom(), PropModeReplace, (unsigned char *)&blackbox_attrib, PropBlackboxAttributesElements)); } /** Sets state on each client in our list */ void FluxboxWindow::setState(unsigned long new_state) { current_state = new_state; unsigned long state[2]; state[0] = (unsigned long) current_state; state[1] = (unsigned long) None; for_each(m_clientlist.begin(), m_clientlist.end(), FbTk::ChangeProperty(display, FbAtoms::instance()->getWMStateAtom(), PropModeReplace, (unsigned char *)state, 2)); saveBlackboxHints(); //notify state changed m_statesig.notify(); } bool FluxboxWindow::getState() { current_state = 0; Atom atom_return; bool ret = false; int foo; unsigned long *state, ulfoo, nitems; if ((XGetWindowProperty(display, m_client->window(), FbAtoms::instance()->getWMStateAtom(), 0l, 2l, false, FbAtoms::instance()->getWMStateAtom(), &atom_return, &foo, &nitems, &ulfoo, (unsigned char **) &state) != Success) || (! state)) { return false; } if (nitems >= 1) { current_state = static_cast(state[0]); ret = true; } XFree(static_cast(state)); return ret; } //!! TODO: this functions looks odd void FluxboxWindow::setGravityOffsets() { int newx = m_frame.x(); int newy = m_frame.y(); // translate x coordinate switch (m_client->win_gravity) { // handle Westward gravity case NorthWestGravity: case WestGravity: case SouthWestGravity: default: #ifdef DEBUG cerr<<__FILE__<<": Default gravity: SouthWest, NorthWest, West"<win_gravity) { // handle Northbound gravity case NorthWestGravity: case NorthGravity: case NorthEastGravity: default: newy = m_frame.y(); break; // handle Southbound gravity case SouthWestGravity: case SouthGravity: case SouthEastGravity: newy = m_frame.y() + m_frame.clientArea().height() - m_frame.height(); break; // no y translation desired - default case StaticGravity: case ForgetGravity: case CenterGravity: newy = m_frame.y(); break; } // finaly move the frame if (m_frame.x() != newx || m_frame.y() != newy) m_frame.move(newx, newy); } /** * Sets the attributes to what they should be * but doesn't change the actual state * (so the caller can set defaults etc as well) */ void FluxboxWindow::restoreAttributes() { if (!getState()) current_state = NormalState; Atom atom_return; int foo; unsigned long ulfoo, nitems; FbAtoms *fbatoms = FbAtoms::instance(); BaseDisplay::BlackboxAttributes *net; if (XGetWindowProperty(display, m_client->window(), fbatoms->getFluxboxAttributesAtom(), 0l, PropBlackboxAttributesElements, false, fbatoms->getFluxboxAttributesAtom(), &atom_return, &foo, &nitems, &ulfoo, (unsigned char **) &net) == Success && net && nitems == PropBlackboxAttributesElements) { blackbox_attrib.flags = net->flags; blackbox_attrib.attrib = net->attrib; blackbox_attrib.workspace = net->workspace; blackbox_attrib.stack = net->stack; blackbox_attrib.premax_x = net->premax_x; blackbox_attrib.premax_y = net->premax_y; blackbox_attrib.premax_w = net->premax_w; blackbox_attrib.premax_h = net->premax_h; XFree(static_cast(net)); } else return; if (blackbox_attrib.flags & BaseDisplay::ATTRIB_SHADED && blackbox_attrib.attrib & BaseDisplay::ATTRIB_SHADED) { int save_state = ((current_state == IconicState) ? NormalState : current_state); shaded = true; current_state = save_state; } if (( blackbox_attrib.workspace != screen.getCurrentWorkspaceID()) && ( blackbox_attrib.workspace < screen.getCount())) { workspace_number = blackbox_attrib.workspace; if (current_state == NormalState) current_state = WithdrawnState; } else if (current_state == WithdrawnState) current_state = NormalState; if (blackbox_attrib.flags & BaseDisplay::ATTRIB_OMNIPRESENT && blackbox_attrib.attrib & BaseDisplay::ATTRIB_OMNIPRESENT) { stuck = true; current_state = NormalState; } if (blackbox_attrib.flags & BaseDisplay::ATTRIB_STACK) { //!! TODO check value? m_layernum = blackbox_attrib.stack; } if ((blackbox_attrib.flags & BaseDisplay::ATTRIB_MAXHORIZ) || (blackbox_attrib.flags & BaseDisplay::ATTRIB_MAXVERT)) { int x = blackbox_attrib.premax_x, y = blackbox_attrib.premax_y; unsigned int w = blackbox_attrib.premax_w, h = blackbox_attrib.premax_h; maximized = false; if ((blackbox_attrib.flags & BaseDisplay::ATTRIB_MAXHORIZ) && (blackbox_attrib.flags & BaseDisplay::ATTRIB_MAXVERT)) maximized = true; else if (blackbox_attrib.flags & BaseDisplay::ATTRIB_MAXVERT) maximizeVertical(); else if (blackbox_attrib.flags & BaseDisplay::ATTRIB_MAXHORIZ) maximizeHorizontal(); blackbox_attrib.premax_x = x; blackbox_attrib.premax_y = y; blackbox_attrib.premax_w = w; blackbox_attrib.premax_h = h; } setState(current_state); } /** Show the window menu at pos mx, my */ void FluxboxWindow::showMenu(int mx, int my) { m_windowmenu.move(mx, my); m_windowmenu.show(); m_windowmenu.raise(); } /** Moves the menu to last button press position and shows it, if it's already visible it'll be hidden */ void FluxboxWindow::popupMenu() { if (m_windowmenu.isVisible()) { m_windowmenu.hide(); return; } // move menu directly under titlebar int diff_y = m_frame.titlebar().height() + m_frame.titlebar().borderWidth(); if (!decorations.titlebar) // if we don't have any titlebar diff_y = 0; m_windowmenu.move(m_last_button_x, m_frame.y() + diff_y); m_windowmenu.show(); m_windowmenu.raise(); } void FluxboxWindow::restoreGravity() { // restore x coordinate switch (m_client->win_gravity) { // handle Westward gravity case NorthWestGravity: case WestGravity: case SouthWestGravity: default: m_client->x = m_frame.x(); break; // handle Eastward gravity case NorthEastGravity: case EastGravity: case SouthEastGravity: m_client->x = (m_frame.x() + m_frame.width()) - m_client->width(); break; } // restore y coordinate switch (m_client->win_gravity) { // handle Northbound gravity case NorthWestGravity: case NorthGravity: case NorthEastGravity: default: m_client->y = m_frame.y(); break; // handle Southbound gravity case SouthWestGravity: case SouthGravity: case SouthEastGravity: m_client->y = (m_frame.y() + m_frame.height()) - m_client->height(); break; } } /** Determine if this is the lowest tab of them all */ bool FluxboxWindow::isLowerTab() const { cerr<<__FILE__<<"("<<__FUNCTION__<<") TODO!"<window()) return; Fluxbox *fluxbox = Fluxbox::instance(); bool get_state_ret = getState(); if (! (get_state_ret && fluxbox->isStartup())) { if ((m_client->wm_hint_flags & StateHint) && (! (current_state == NormalState || current_state == IconicState))) { current_state = m_client->initial_state; } else current_state = NormalState; } else if (iconic) current_state = NormalState; switch (current_state) { case IconicState: iconify(); break; case WithdrawnState: withdraw(); break; case NormalState: // check WM_CLASS only when we changed state to NormalState from // WithdrawnState (ICCC 4.1.2.5) XClassHint ch; if (XGetClassHint(display, getClientWindow(), &ch) == 0) { cerr<<"Failed to read class hint!"<(ch.res_name); XFree(ch.res_name); } else m_instance_name = ""; if (ch.res_class != 0) { m_class_name = const_cast(ch.res_class); XFree(ch.res_class); } else m_class_name = ""; /* Workspace *wsp = screen.getWorkspace(workspace_number); // we must be resizable AND maximizable to be autogrouped //!! TODO: there should be an isGroupable() function if (wsp != 0 && isResizable() && isMaximizable()) { wsp->checkGrouping(*this); } */ } deiconify(false); break; case InactiveState: case ZoomState: default: deiconify(false); break; } } void FluxboxWindow::mapNotifyEvent(XMapEvent &ne) { WinClient *client = findClient(ne.window); if (client == 0) return; if (!ne.override_redirect && visible) { Fluxbox *fluxbox = Fluxbox::instance(); fluxbox->grab(); if (! validateClient()) return; setState(NormalState); if (transient || screen.doFocusNew()) setInputFocus(); else setFocusFlag(false); if (focused) m_frame.setFocus(true); visible = true; iconic = false; // Auto-group from tab? if (!transient) { cerr<<__FILE__<<"("<<__FUNCTION__<<") TODO check grouping here"<ungrab(); } } /** Unmaps frame window and client window if event.window == m_client->window Returns true if *this should die else false */ void FluxboxWindow::unmapNotifyEvent(XUnmapEvent &ue) { WinClient *client = findClient(ue.window); if (client == 0) return; #ifdef DEBUG cerr<<__FILE__<<"("<<__FUNCTION__<<"): 0x"<window()<window()<reparent(screen.getRootWindow(), m_frame.x(), m_frame.y()); } if (remap) client->show(); delete client; #ifdef DEBUG cerr<<__FILE__<<"("<<__FUNCTION__<<"): numClients() = "<transientFor() ? true : false); } bool FluxboxWindow::hasTransient() const { if (m_client == 0) return false; return (m_client->transients.size() ? true : false); } const std::list &FluxboxWindow::getTransients() const { return m_client->transients; } std::list &FluxboxWindow::getTransients() { return m_client->transients; } const FluxboxWindow *FluxboxWindow::getTransientFor() const { if (m_client == 0) return 0; return m_client->transient_for; } FluxboxWindow *FluxboxWindow::getTransientFor() { if (m_client == 0) return 0; return m_client->transient_for; } Window FluxboxWindow::getClientWindow() const { if (m_client == 0) return 0; return m_client->window(); } const std::string &FluxboxWindow::getTitle() const { static string empty_string(""); if (m_client == 0) return empty_string; return m_client->title(); } const std::string &FluxboxWindow::getIconTitle() const { static string empty_string(""); if (m_client == 0) return empty_string; return m_client->iconTitle(); } int FluxboxWindow::getXClient() const { return m_client->x; } int FluxboxWindow::getYClient() const { return m_client->y; } unsigned int FluxboxWindow::getClientHeight() const { return m_client->height(); } unsigned int FluxboxWindow::getClientWidth() const { return m_client->width(); } int FluxboxWindow::initialState() const { return m_client->initial_state; } void FluxboxWindow::changeBlackboxHints(const BaseDisplay::BlackboxHints &net) { if ((net.flags & BaseDisplay::ATTRIB_SHADED) && ((blackbox_attrib.attrib & BaseDisplay::ATTRIB_SHADED) != (net.attrib & BaseDisplay::ATTRIB_SHADED))) shade(); if ((net.flags & (BaseDisplay::ATTRIB_MAXVERT | BaseDisplay::ATTRIB_MAXHORIZ)) && ((blackbox_attrib.attrib & (BaseDisplay::ATTRIB_MAXVERT | BaseDisplay::ATTRIB_MAXHORIZ)) != (net.attrib & (BaseDisplay::ATTRIB_MAXVERT | BaseDisplay::ATTRIB_MAXHORIZ)))) { if (maximized) { maximize(); } else { if ((net.flags & BaseDisplay::ATTRIB_MAXHORIZ) && (net.flags & BaseDisplay::ATTRIB_MAXVERT)) maximize(); else if (net.flags & BaseDisplay::ATTRIB_MAXVERT) maximizeVertical(); else if (net.flags & BaseDisplay::ATTRIB_MAXHORIZ) maximizeHorizontal(); } } if ((net.flags & BaseDisplay::ATTRIB_OMNIPRESENT) && ((blackbox_attrib.attrib & BaseDisplay::ATTRIB_OMNIPRESENT) != (net.attrib & BaseDisplay::ATTRIB_OMNIPRESENT))) stick(); if ((net.flags & BaseDisplay::ATTRIB_WORKSPACE) && (workspace_number != net.workspace)) { screen.reassociateWindow(this, net.workspace, true); if (screen.getCurrentWorkspaceID() != net.workspace) withdraw(); else deiconify(); } if (net.flags & BaseDisplay::ATTRIB_STACK) { if ((unsigned int) m_layernum != net.stack) { moveToLayer(net.stack); } } if (net.flags & BaseDisplay::ATTRIB_DECORATION) { old_decoration = static_cast(net.decoration); setDecoration(old_decoration); } } void FluxboxWindow::upsize() { m_frame.setBevel(screen.rootTheme().bevelWidth()); m_frame.handle().resize(m_frame.handle().width(), screen.rootTheme().handleWidth()); m_frame.gripLeft().resize(m_frame.buttonHeight(), screen.rootTheme().handleWidth()); m_frame.gripRight().resize(m_frame.gripLeft().width(), m_frame.gripLeft().height()); } ///TODO void FluxboxWindow::downsize() { } void FluxboxWindow::right_fixsize(int *gx, int *gy) { // calculate the size of the client window and conform it to the // size specified by the size hints of the client window... int dx = last_resize_w - m_client->base_width; int titlebar_height = (decorations.titlebar ? frame().titlebar().height() + frame().titlebar().borderWidth() : 0); int handle_height = (decorations.handle ? frame().handle().height() + frame().handle().borderWidth() : 0); int dy = last_resize_h - m_client->base_height - titlebar_height - handle_height; if (dx < (signed) m_client->min_width) dx = m_client->min_width; if (dy < (signed) m_client->min_height) dy = m_client->min_height; if (m_client->max_width > 0 && (unsigned) dx > m_client->max_width) dx = m_client->max_width; if (m_client->max_height > 0 && (unsigned) dy > m_client->max_height) dy = m_client->max_height; // make it snap if (m_client->width_inc == 0) m_client->width_inc = 1; if (m_client->height_inc == 0) m_client->height_inc = 1; dx /= m_client->width_inc; dy /= m_client->height_inc; if (gx) *gx = dx; if (gy) *gy = dy; dx = (dx * m_client->width_inc) + m_client->base_width; dy = (dy * m_client->height_inc) + m_client->base_height + titlebar_height + handle_height; last_resize_w = dx; last_resize_h = dy; } void FluxboxWindow::left_fixsize(int *gx, int *gy) { int titlebar_height = (decorations.titlebar ? frame().titlebar().height() + frame().titlebar().borderWidth() : 0); int handle_height = (decorations.handle ? frame().handle().height() + frame().handle().borderWidth() : 0); int decoration_height = titlebar_height + handle_height; // dx is new width = current width + difference between new and old x values int dx = m_frame.width() + m_frame.x() - last_resize_x; // dy = new height (w/o decorations), similarly int dy = last_resize_h - m_client->base_height - decoration_height; // check minimum size if (dx < static_cast(m_client->min_width)) dx = m_client->min_width; if (dy < static_cast(m_client->min_height)) dy = m_client->min_height; // check maximum size if (m_client->max_width > 0 && dx > static_cast(m_client->max_width)) dx = m_client->max_width; if (m_client->max_height > 0 && dy > static_cast(m_client->max_height)) dy = m_client->max_height; // make sure we have valid increment if (m_client->width_inc == 0) m_client->width_inc = 1; if (m_client->height_inc == 0) m_client->height_inc = 1; // set snapping dx /= m_client->width_inc; dy /= m_client->height_inc; // set return values if (gx != 0) *gx = dx; if (gy != 0) *gy = dy; // snapping dx = dx * m_client->width_inc + m_client->base_width; dy = dy * m_client->height_inc + m_client->base_height + decoration_height; // update last resize last_resize_w = dx; last_resize_h = dy; last_resize_x = m_frame.x() + m_frame.width() - last_resize_w; } void FluxboxWindow::resizeClient(WinClient &client, unsigned int height, unsigned int width) { client.resize(m_frame.clientArea().width(), m_frame.clientArea().height()); client.updateRect(m_frame.x() + m_frame.clientArea().x(), m_frame.y() + m_frame.clientArea().y(), m_frame.clientArea().width(), m_frame.clientArea().height()); } void FluxboxWindow::sendConfigureNotify() { ClientList::iterator client_it = m_clientlist.begin(); ClientList::iterator client_it_end = m_clientlist.end(); for (; client_it != client_it_end; ++client_it) { WinClient &client = *(*client_it); /* Send event telling where the root position of the client window is. (ie frame pos + client pos inside the frame = send pos) */ //!! client.x = m_frame.x(); client.y = m_frame.y(); resizeClient(client, m_frame.clientArea().width(), m_frame.clientArea().height()); XEvent event; event.type = ConfigureNotify; event.xconfigure.display = display; event.xconfigure.event = client.window(); event.xconfigure.window = client.window(); event.xconfigure.x = m_frame.x() + m_frame.clientArea().x(); event.xconfigure.y = m_frame.y() + m_frame.clientArea().y(); event.xconfigure.width = client.width(); event.xconfigure.height = client.height(); event.xconfigure.border_width = client.old_bw; event.xconfigure.above = m_frame.window().window(); event.xconfigure.override_redirect = false; screen.updateNetizenConfigNotify(&event); } // end for }