news download themes documentation links










Window.cc

00001 // Window.cc for Fluxbox Window Manager
00002 // Copyright (c) 2001 - 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net)
00003 //
00004 // Window.cc for Blackbox - an X11 Window manager
00005 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes at tcac.net)
00006 //
00007 // Permission is hereby granted, free of charge, to any person obtaining a
00008 // copy of this software and associated documentation files (the "Software"),
00009 // to deal in the Software without restriction, including without limitation
00010 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
00011 // and/or sell copies of the Software, and to permit persons to whom the
00012 // Software is furnished to do so, subject to the following conditions:
00013 //
00014 // The above copyright notice and this permission notice shall be included in
00015 // all copies or substantial portions of the Software.
00016 //
00017 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00018 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00019 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
00020 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00021 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00022 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00023 // DEALINGS IN THE SOFTWARE.
00024 
00025 // $Id: Window.cc,v 1.259 2003/12/31 00:36:16 fluxgen Exp $
00026 
00027 #include "Window.hh"
00028 
00029 #include "WinClient.hh"
00030 #include "I18n.hh"
00031 #include "fluxbox.hh"
00032 #include "Screen.hh"
00033 #include "FbWinFrameTheme.hh"
00034 #include "MenuTheme.hh"
00035 #include "FbAtoms.hh"
00036 #include "RootTheme.hh"
00037 #include "Workspace.hh"
00038 #include "LayerMenu.hh"
00039 #include "FbWinFrame.hh"
00040 #include "WinButton.hh"
00041 #include "WinButtonTheme.hh"
00042 #include "SendToMenu.hh"
00043 
00044 #include "FbTk/StringUtil.hh"
00045 #include "FbTk/TextButton.hh"
00046 #include "FbTk/Compose.hh"
00047 #include "FbTk/EventManager.hh"
00048 #include "FbTk/MultiButtonMenuItem.hh"
00049 #include "FbTk/KeyUtil.hh"
00050 
00051 #ifdef HAVE_CONFIG_H
00052 #include "config.h"
00053 #endif // HAVE_CONFIG_H
00054 #ifdef SHAPE
00055 #include <X11/extensions/shape.h>
00056 #endif // SHAPE
00057 
00058 //use GNU extensions
00059 #ifndef  _GNU_SOURCE
00060 #define  _GNU_SOURCE
00061 #endif // _GNU_SOURCE
00062 
00063 #include <X11/Xatom.h>
00064 #include <X11/keysym.h>
00065 
00066 #include <cstring>
00067 #include <cstdio>
00068 #include <iostream>
00069 #include <cassert>
00070 #include <functional>
00071 #include <algorithm>
00072 
00073 using namespace std;
00074 
00075 namespace {
00076 
00077 void grabButton(Display *display, unsigned int button, 
00078                 Window window, Cursor cursor) {
00079     
00080     const int numlock = FbTk::KeyUtil::instance().numlock();
00081     const int capslock = FbTk::KeyUtil::instance().capslock();
00082     const int scrolllock = FbTk::KeyUtil::instance().scrolllock();
00083 
00084     // Grab with Mod1 and with all lock modifiers 
00085     // (num, scroll and caps)
00086 
00087     //numlock
00088     XGrabButton(display, button, Mod1Mask|numlock, window, True,
00089                 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
00090                 GrabModeAsync, None, cursor);
00091     //scrolllock
00092     XGrabButton(display, button, Mod1Mask|scrolllock, window, True,
00093                 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
00094                 GrabModeAsync, None, cursor);
00095     
00096     //capslock
00097     XGrabButton(display, button, Mod1Mask|capslock, window, True,
00098                 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
00099                 GrabModeAsync, None, cursor);
00100 
00101     //capslock+numlock
00102     XGrabButton(display, Button1, Mod1Mask|capslock|numlock, window, True,
00103                 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
00104                 GrabModeAsync, None, cursor);
00105 
00106     //capslock+scrolllock
00107     XGrabButton(display, button, Mod1Mask|capslock|scrolllock, window, True,
00108                 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
00109                 GrabModeAsync, None, cursor);
00110     
00111     //capslock+numlock+scrolllock
00112     XGrabButton(display, button, Mod1Mask|capslock|numlock|scrolllock, window, 
00113                 True,
00114                 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
00115                 GrabModeAsync, None, cursor);
00116 
00117     //numlock+scrollLock
00118     XGrabButton(display, button, Mod1Mask|numlock|scrolllock, window, True,
00119                 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
00120                 GrabModeAsync, None, cursor);
00121     
00122 }
00123 
00124 // X event scanner for enter/leave notifies - adapted from twm
00125 typedef struct scanargs {
00126     Window w;
00127     Bool leave, inferior, enter;
00128 } scanargs;
00129 
00130 // look for valid enter or leave events (that may invalidate the earlier one we are interested in)
00131 static Bool queueScanner(Display *, XEvent *e, char *args) {
00132     if (e->type == LeaveNotify &&
00133         e->xcrossing.window == ((scanargs *) args)->w &&
00134         e->xcrossing.mode == NotifyNormal) {
00135         ((scanargs *) args)->leave = true;
00136         ((scanargs *) args)->inferior = (e->xcrossing.detail == NotifyInferior);
00137     } else if (e->type == EnterNotify &&
00138                e->xcrossing.mode == NotifyUngrab)
00139         ((scanargs *) args)->enter = true;
00140 
00141     return false;
00142 }
00143 
00145 WinClient *getRootTransientFor(WinClient *client) {
00146     while (client->transientFor()) {
00147         assert(client != client->transientFor());
00148         client = client->transientFor();
00149     }
00150     return client;
00151 }
00152 
00153 
00155 void raiseFluxboxWindow(FluxboxWindow &win) {
00156     if (win.oplock) return;
00157     win.oplock = true;
00158 
00159     // we need to lock actual restacking so that raising above active transient
00160     // won't do anything nasty
00161     if (!win.winClient().transientList().empty())
00162         win.screen().layerManager().lock();
00163 
00164     if (!win.isIconic()) {
00165         win.screen().updateNetizenWindowRaise(win.clientWindow());
00166         win.layerItem().raise();
00167     }
00168 
00169     // for each transient do raise
00170     WinClient::TransientList::const_iterator it = win.winClient().transientList().begin();
00171     WinClient::TransientList::const_iterator it_end = win.winClient().transientList().end();
00172     for (; it != it_end; ++it) {
00173         if ((*it)->fbwindow() && !(*it)->fbwindow()->isIconic())
00174             // TODO: should we also check if it is the active client?
00175             raiseFluxboxWindow(*(*it)->fbwindow());
00176     }
00177     win.oplock = false;
00178 
00179     if (!win.winClient().transientList().empty())
00180         win.screen().layerManager().unlock();
00181 }
00182 
00184 void lowerFluxboxWindow(FluxboxWindow &win) {
00185     if (win.oplock) return;
00186     win.oplock = true;
00187 
00188     // we need to lock actual restacking so that raising above active transient
00189     // won't do anything nasty
00190     if (!win.winClient().transientList().empty())
00191         win.screen().layerManager().lock();
00192 
00193     if (!win.isIconic()) {
00194         win.screen().updateNetizenWindowLower(win.clientWindow());
00195         win.layerItem().lower();
00196     }
00197 
00198     WinClient::TransientList::const_iterator it = win.winClient().transientList().begin();
00199     WinClient::TransientList::const_iterator it_end = win.winClient().transientList().end();
00200     for (; it != it_end; ++it) {
00201         if ((*it)->fbwindow() && !(*it)->fbwindow()->isIconic())
00202             // TODO: should we also check if it is the active client?
00203             lowerFluxboxWindow(*(*it)->fbwindow());
00204     }
00205     win.oplock = false;
00206     if (!win.winClient().transientList().empty())
00207         win.screen().layerManager().unlock();
00208 }
00209 
00211 void tempRaiseFluxboxWindow(FluxboxWindow &win) {
00212     if (win.oplock) return;
00213     win.oplock = true;
00214 
00215     if (!win.winClient().transientList().empty())
00216         win.screen().layerManager().lock();
00217 
00218     if (!win.isIconic()) {
00219         // don't update netizen, as it is only temporary
00220         win.layerItem().tempRaise();
00221     }
00222 
00223     // for each transient do raise
00224     WinClient::TransientList::const_iterator it = win.winClient().transientList().begin();
00225     WinClient::TransientList::const_iterator it_end = win.winClient().transientList().end();
00226     for (; it != it_end; ++it) {
00227         if ((*it)->fbwindow() && !(*it)->fbwindow()->isIconic())
00228             // TODO: should we also check if it is the active client?
00229             tempRaiseFluxboxWindow(*(*it)->fbwindow());
00230     }
00231     win.oplock = false;
00232 
00233     if (!win.winClient().transientList().empty())
00234         win.screen().layerManager().unlock();
00235 
00236 }
00237 
00238 class SetClientCmd:public FbTk::Command {
00239 public:
00240     explicit SetClientCmd(WinClient &client):m_client(client) {
00241     }
00242     void execute() {
00243         if (m_client.m_win != 0)
00244             m_client.m_win->setCurrentClient(m_client);
00245     }
00246 private:
00247     WinClient &m_client;
00248 };
00249 
00250 };
00251 
00252 template <>
00253 void LayerMenuItem<FluxboxWindow>::click(int button, int time) {
00254     m_object->moveToLayer(m_layernum);
00255 }
00256 
00257 FluxboxWindow::FluxboxWindow(WinClient &client, FbWinFrameTheme &tm,
00258                              FbTk::XLayer &layer):
00259     oplock(false),
00260     m_hintsig(*this),
00261     m_statesig(*this),
00262     m_layersig(*this),
00263     m_workspacesig(*this),
00264     m_diesig(*this),
00265     m_focussig(*this),
00266     m_titlesig(*this),
00267     moving(false), resizing(false), shaded(false), 
00268     iconic(false), focused(false),
00269     stuck(false), m_managed(false),
00270     maximized(MAX_NONE),
00271     m_screen(client.screen()),
00272     display(FbTk::App::instance()->display()),
00273     m_windowmenu(client.screen().menuTheme(), client.screen().imageControl(),
00274                  *client.screen().layerManager().getLayer(Fluxbox::instance()->getMenuLayer())),
00275     m_old_decoration(DECOR_NORMAL),
00276     m_client(&client),   
00277     m_frame(tm, client.screen().imageControl(), 0, 0, 100, 100),
00278     m_layeritem(m_frame.window(), layer),
00279     m_layernum(layer.getLayerNum()),
00280     m_parent(client.screen().rootWindow()),
00281     m_resize_corner(RIGHTBOTTOM) {
00282 
00283     init();
00284 }
00285 
00286 
00287 FluxboxWindow::~FluxboxWindow() {
00288 #ifdef DEBUG
00289     cerr<<__FILE__<<"("<<__LINE__<<"): starting ~FluxboxWindow("<<this<<")"<<endl;
00290     cerr<<__FILE__<<"("<<__LINE__<<"): num clients = "<<numClients()<<endl;
00291     cerr<<__FILE__<<"("<<__LINE__<<"): curr client = "<<m_client<<endl;
00292     cerr<<__FILE__<<"("<<__LINE__<<"): m_labelbuttons.size = "<<m_labelbuttons.size()<<endl;
00293 #endif // DEBUG
00294 
00295     if (moving || resizing || m_attaching_tab) {
00296         screen().hideGeometry();
00297         XUngrabPointer(display, CurrentTime);
00298     }
00299 
00300     // no longer a valid window to do stuff with
00301     Fluxbox::instance()->removeWindowSearchGroup(frame().window().window());
00302 
00303     Client2ButtonMap::iterator it = m_labelbuttons.begin();
00304     Client2ButtonMap::iterator it_end = m_labelbuttons.end();
00305     for (; it != it_end; ++it) {
00306         frame().removeLabelButton(*(*it).second);
00307         delete (*it).second;
00308     }
00309     m_labelbuttons.clear();
00310 
00311     m_timer.stop();
00312     
00313     // notify die
00314     m_diesig.notify();
00315 
00316     if (m_client != 0)
00317         delete m_client; // this also removes client from our list
00318     m_client = 0;
00319 
00320     if (m_clientlist.size() > 1) {
00321         cerr<<__FILE__<<"("<<__FUNCTION__<<") WARNING! clientlist > 1"<<endl;
00322         while (!m_clientlist.empty()) {
00323             detachClient(*m_clientlist.back());
00324         }
00325     }
00326 
00327     // deal with extra menus
00328     ExtraMenus::iterator mit = m_extramenus.begin();
00329     ExtraMenus::iterator mit_end = m_extramenus.end();
00330     for (; mit != mit_end; ++mit) {
00331         // we set them to NOT internal so that they will be deleted when the
00332         // menu is cleaned up. We can't delete them here because they are
00333         // still in the menu
00334         // (They need to be internal for most of the time so that if we 
00335         // rebuild the menu, then they won't be removed.
00336         mit->second->setInternalMenu(false);
00337     }
00338 
00339 #ifdef DEBUG
00340     cerr<<__FILE__<<"("<<__LINE__<<"): ~FluxboxWindow("<<this<<")"<<endl;
00341 #endif // DEBUG
00342 }
00343 
00344 
00345 void FluxboxWindow::init() { 
00346     m_attaching_tab = 0;
00347 
00348     assert(m_client);
00349     m_client->m_win = this;
00350     m_client->setGroupLeftWindow(None); // nothing to the left.
00351 
00352     // check for shape extension and whether the window is shaped
00353     m_shaped = false;
00354 
00355     if (Fluxbox::instance()->haveShape()) {
00356         Shape::setShapeNotify(winClient());
00357         m_shaped = Shape::isShaped(winClient());
00358     }
00359 
00360     frame().setUseShape(!m_shaped);
00361 
00363     // we don't want to duplicate code here and in attachClient
00364     m_clientlist.push_back(m_client);
00365 #ifdef DEBUG
00366     cerr<<__FILE__<<": FluxboxWindow::init(this="<<this<<", client="<<hex<<
00367         m_client->window()<<", frame = "<<frame().window().window()<<dec<<")"<<endl;
00368 
00369 #endif // DEBUG    
00370 
00371     Fluxbox &fluxbox = *Fluxbox::instance();
00372 
00373     // setup cursors for resize grips
00374     frame().gripLeft().setCursor(frame().theme().lowerLeftAngleCursor());
00375     frame().gripRight().setCursor(frame().theme().lowerRightAngleCursor());
00376 
00377 
00378     FbTk::TextButton *btn =  new FbTk::TextButton(frame().label(), 
00379                                       frame().theme().font(),
00380                                       m_client->title());
00381     btn->setJustify(frame().theme().justify());
00382     m_labelbuttons[m_client] = btn;
00383     frame().addLabelButton(*btn);
00384     frame().setLabelButtonFocus(*btn);
00385     btn->show();    
00386     FbTk::EventManager &evm = *FbTk::EventManager::instance();
00387     // we need motion notify so we mask it
00388     btn->setEventMask(ExposureMask | ButtonPressMask | ButtonReleaseMask | 
00389                       ButtonMotionMask | EnterWindowMask);
00390 
00391     FbTk::RefCount<FbTk::Command> set_client_cmd(new SetClientCmd(*m_client));
00392     btn->setOnClick(set_client_cmd);
00393     evm.add(*this, btn->window()); // we take care of button events for this
00394     evm.add(*this, m_client->window());
00395 
00396     // redirect events from frame to us
00397 
00398     frame().setEventHandler(*this); 
00399 
00400     frame().resize(m_client->width(), m_client->height());
00401 
00402     m_last_focus_time.tv_sec = m_last_focus_time.tv_usec = 0;
00403 
00404     m_blackbox_attrib.workspace = m_workspace_number = ~0;
00405 
00406     m_blackbox_attrib.flags = m_blackbox_attrib.attrib = m_blackbox_attrib.stack = 0;
00407     m_blackbox_attrib.premax_x = m_blackbox_attrib.premax_y = 0;
00408     m_blackbox_attrib.premax_w = m_blackbox_attrib.premax_h = 0;
00409 
00410     //use tab as default
00411     decorations.tab = true;
00412     // enable decorations
00413     decorations.enabled = true;
00414 
00415     // set default values for decoration
00416     decorations.menu = true;    //override menu option
00417     // all decorations on by default
00418     decorations.titlebar = decorations.border = decorations.handle = true;
00419     decorations.maximize = decorations.close = 
00420         decorations.sticky = decorations.shade = decorations.tab = true;
00421 
00422 
00423     functions.resize = functions.move = functions.iconify = functions.maximize = true;
00424     decorations.close = false;
00425 
00426     if (m_client->getBlackboxHint() != 0)
00427         updateBlackboxHintsFromClient(*m_client);
00428     else
00429         updateMWMHintsFromClient(*m_client);
00430     
00432     // fetch client size and placement
00433     XWindowAttributes wattrib;
00434     if (! m_client->getAttrib(wattrib) ||
00435         !wattrib.screen // no screen? ??
00436         || wattrib.override_redirect) { // override redirect        
00437         return;
00438     }
00439 
00440     // save old border width so we can restore it later
00441     m_client->old_bw = wattrib.border_width;
00442     m_client->x = wattrib.x; m_client->y = wattrib.y;
00443 
00444     m_timer.setTimeout(fluxbox.getAutoRaiseDelay());
00445     FbTk::RefCount<FbTk::Command> raise_cmd(new FbTk::SimpleCommand<FluxboxWindow>(*this, &FluxboxWindow::raise));
00446     m_timer.setCommand(raise_cmd);
00447     m_timer.fireOnce(true);
00448 
00449     if (m_client->initial_state == WithdrawnState) {
00450         return;
00451     }
00452 
00453     m_managed = true; //this window is managed
00454 
00455     Fluxbox::instance()->saveWindowSearchGroup(frame().window().window(), this);
00456     
00457     // update transient infomation
00458     m_client->updateTransientInfo();
00459     
00460     // adjust the window decorations based on transience and window sizes
00461     if (m_client->isTransient()) {
00462         decorations.maximize =  functions.maximize = false;
00463         decorations.handle = false;
00464     }   
00465     
00466     if ((m_client->normal_hint_flags & PMinSize) &&
00467         (m_client->normal_hint_flags & PMaxSize) &&
00468         m_client->max_width != 0 && m_client->max_width <= m_client->min_width &&
00469         m_client->max_height != 0 && m_client->max_height <= m_client->min_height) {
00470         decorations.maximize = decorations.handle =
00471             functions.resize = functions.maximize = false;
00472         decorations.tab = false; //no tab for this window
00473     }
00474 
00475     upsize();
00476 
00477     applyDecorations(true);
00478 
00479     associateClientWindow(true, wattrib.x, wattrib.y, wattrib.width, wattrib.height);
00480 
00481     grabButtons();
00482         
00483     if (m_workspace_number < 0 || m_workspace_number >= screen().getCount())
00484         m_workspace_number = screen().currentWorkspaceID();
00485 
00486     restoreAttributes();
00487 
00488     bool place_window = true;
00489     if (fluxbox.isStartup() || m_client->isTransient() ||
00490         m_client->normal_hint_flags & (PPosition|USPosition)) {
00491 
00492         frame().gravityTranslate(wattrib.x, wattrib.y, m_client->gravity(), false);
00493 
00494         if (! fluxbox.isStartup()) {
00495 
00496             int real_x = frame().x();
00497             int real_y = frame().y();
00498 
00499             if (real_x >= 0 && 
00500                 real_y + frame().y() >= 0 &&
00501                 real_x <= (signed) screen().width() &&
00502                 real_y <= (signed) screen().height())
00503                 place_window = false;
00504 
00505         } else
00506             place_window = false;
00507 
00508     }
00509     if (wattrib.width <= 0)
00510         wattrib.width = 1;
00511     if (wattrib.height <= 0)
00512         wattrib.height = 1;
00513 
00514     // if we're a transient then we should be on the same layer as our parent
00515     if (m_client->isTransient() && 
00516         m_client->transientFor()->fbwindow() &&
00517         m_client->transientFor()->fbwindow() != this)
00518         layerItem().setLayer(m_client->transientFor()->fbwindow()->layerItem().getLayer());       
00519     else // if no parent then set default layer
00520         moveToLayer(m_layernum);
00521     
00522     if (!place_window)
00523         moveResize(frame().x(), frame().y(), frame().width(), frame().height());
00524 
00525 
00526 
00527     screen().getWorkspace(m_workspace_number)->addWindow(*this, place_window);
00528 
00529     if (shaded) { // start shaded
00530         shaded = false;
00531         shade();
00532     }
00533 
00534     if (maximized && functions.maximize) { // start maximized
00535         // This will set it to the appropriate style of maximisation
00536         int req_maximized = maximized;
00537         // NOTE: don't manually change maximized ANYWHERE else, it isn't safe
00538         maximized = MAX_NONE; // it is not maximized now
00539         maximize(req_maximized);
00540     }   
00541 
00542     if (stuck) {
00543         stuck = false;
00544         stick();
00545         deiconify(); //we're omnipresent and visible
00546     }
00547 
00548     setState(m_current_state);
00549 
00550     // add extra menus
00551     addExtraMenu("Send To...", new SendToMenu(*this));
00552     addExtraMenu("Layer...",
00553                  new LayerMenu<FluxboxWindow>(screen().menuTheme(), 
00554                                               screen().imageControl(), 
00555                                               *screen().layerManager().getLayer(Fluxbox::instance()->getMenuLayer()), 
00556                                               this,
00557                                               false));
00558 
00559     // the layermenu will get deleted as an extra menu
00560     // don't call setupWindow here as the addExtraMenu call should
00561 
00562     sendConfigureNotify();
00563     // no focus default
00564     setFocusFlag(false);
00565 
00566     if (m_shaped)
00567         shape();
00568 
00569     FbTk::App::instance()->sync(false);
00570 
00571 }
00572 
00574 void FluxboxWindow::shape() {
00575 #ifdef SHAPE
00576     if (m_shaped) {
00577         XShapeCombineShape(display,
00578                            frame().window().window(), ShapeBounding,
00579                            0, frame().clientArea().y(), // xOff, yOff
00580                            m_client->window(),
00581                            ShapeBounding, ShapeSet);
00582         XFlush(display);
00583     }
00584 #endif // SHAPE
00585 
00586 }
00587 
00588 
00590 void FluxboxWindow::attachClient(WinClient &client) {
00592     if (client.m_win == this)
00593         return;
00594 
00595     // reparent client win to this frame 
00596     frame().setClientWindow(client);
00597     FbTk::EventManager &evm = *FbTk::EventManager::instance();
00598 
00599     // get the current window on the end of our client list
00600     Window leftwin = None;
00601     if (!clientList().empty())
00602         leftwin = clientList().back()->window();
00603 
00604     client.setGroupLeftWindow(leftwin);
00605 
00606     if (client.fbwindow() != 0) {
00607         FluxboxWindow *old_win = client.fbwindow(); // store old window
00608 
00609         // make sure we set new window search for each client
00610         ClientList::iterator client_it = old_win->clientList().begin();
00611         ClientList::iterator client_it_end = old_win->clientList().end();
00612         for (; client_it != client_it_end; ++client_it) {
00613             // setup eventhandlers for client
00614             evm.add(*this, (*client_it)->window());
00615             
00616             // reparent window to this
00617             frame().setClientWindow(**client_it);
00618             moveResizeClient(**client_it, 
00619                              frame().clientArea().x(),
00620                              frame().clientArea().y(),
00621                              frame().clientArea().width(),
00622                              frame().clientArea().height());
00623 
00624             (*client_it)->m_win = this;
00625             // create a labelbutton for this client and 
00626             // associate it with the pointer
00627             FbTk::TextButton *btn = new FbTk::TextButton(frame().label(), 
00628                                              frame().theme().font(),
00629                                              (*client_it)->title());
00630             btn->setJustify(frame().theme().justify());
00631             m_labelbuttons[(*client_it)] = btn;
00632             frame().addLabelButton(*btn);
00633             btn->show();
00634             // we need motion notify so we mask it
00635             btn->setEventMask(ExposureMask | ButtonPressMask | 
00636                               ButtonReleaseMask | ButtonMotionMask | 
00637                               EnterWindowMask);
00638 
00639 
00640             FbTk::RefCount<FbTk::Command> 
00641                 set_client_cmd(new SetClientCmd(*(*client_it)));
00642             btn->setOnClick(set_client_cmd);
00643             evm.add(*this, btn->window()); // we take care of button events for this
00644 
00645             (*client_it)->saveBlackboxAttribs(m_blackbox_attrib);
00646         }
00647 
00648         // add client and move over all attached clients 
00649         // from the old window to this list
00650         // all the "left window"s will remain the same, except for the first.
00651         m_clientlist.splice(m_clientlist.end(), old_win->m_clientlist);           
00652         old_win->m_client = 0;
00653 
00654         delete old_win;
00655         
00656     } else { // client.fbwindow() == 0
00657         // create a labelbutton for this client and associate it with the pointer
00658         FbTk::TextButton *btn = new FbTk::TextButton(frame().label(), 
00659                                          frame().theme().font(),
00660                                          client.title());
00661         m_labelbuttons[&client] = btn;
00662         frame().addLabelButton(*btn);
00663         btn->show();
00664         FbTk::EventManager &evm = *FbTk::EventManager::instance();
00665         // we need motion notify so we mask it
00666         btn->setEventMask(ExposureMask | ButtonPressMask | 
00667                           ButtonReleaseMask | ButtonMotionMask | 
00668                           EnterWindowMask);
00669 
00670 
00671         FbTk::RefCount<FbTk::Command> set_client_cmd(new SetClientCmd(client));
00672         btn->setOnClick(set_client_cmd);
00673         evm.add(*this, btn->window()); // we take care of button events for this
00674 
00675         client.m_win = this;    
00676 
00677         client.saveBlackboxAttribs(m_blackbox_attrib);
00678         m_clientlist.push_back(&client);
00679     }
00680 
00681     // make sure that the state etc etc is updated for the new client
00682     // TODO: one day these should probably be neatened to only act on the
00683     // affected clients if possible
00684     m_statesig.notify();
00685     m_workspacesig.notify();
00686     m_layersig.notify();
00687 
00688     frame().reconfigure();
00689 
00690     // keep the current window on top
00691     m_client->raise();
00692 }
00693 
00694 
00696 bool FluxboxWindow::detachClient(WinClient &client) {
00697     if (client.m_win != this || numClients() <= 1)
00698         return false;
00699     
00700     // I'm not sure how to do this bit better
00701     // we need to find the window we've got, and update the
00702     // window to its right to have a left window set to the
00703     // window which is to the left of the current.
00704     // Think in terms of:
00705     // window1 <- my_window <- window2
00706     // we need to take out my_window, so update window2 leftwin to be window1
00707 
00708     Window leftwin = None;
00709     ClientList::iterator client_it_end = clientList().end();
00710     ClientList::iterator client_it = clientList().begin();
00711     ClientList::iterator client_it_before = client_it_end;
00712     ClientList::iterator client_it_after = clientList().begin();
00713     if (!clientList().empty()) {
00714         ++client_it_after;
00715         if (clientList().front() == &client) {
00716             leftwin = None;
00717         } else {
00718             ++client_it;
00719             client_it_before = clientList().begin();
00720             ++client_it_after;
00721 
00722             while (client_it != client_it_end) {
00723                 if (*client_it == &client) {
00724                     break;
00725                 }
00726                 ++client_it_before;
00727                 ++client_it;
00728                 ++client_it_after;
00729             }
00730         }
00731     }
00732 
00733     // update the leftwin of the window to the right
00734     if (client_it_before != client_it_end) 
00735         leftwin = (*client_it_before)->window();
00736 
00737     if (client_it_after != client_it_end)
00738         (*client_it_after)->setGroupLeftWindow(leftwin);
00739 
00740     removeClient(client);
00741 
00742     // m_client must be valid as there should be at least one other window 
00743     // otherwise this wouldn't be here (refer numClients() <= 1 return)
00744     client.m_win = screen().createWindow(client);
00745     m_client->raise();
00746     setInputFocus();
00747     return true;
00748 }
00749 
00750 void FluxboxWindow::detachCurrentClient() {
00751     // should only operate if we had more than one client
00752     if (numClients() <= 1)
00753         return;
00754     detachClient(*m_client);
00755 }
00756 
00758 bool FluxboxWindow::removeClient(WinClient &client) {
00759     if (client.m_win != this || numClients() == 0)
00760         return false;
00761 
00762 #ifdef DEBUG
00763     cerr<<__FILE__<<"("<<__FUNCTION__<<")["<<this<<"]"<<endl;
00764 #endif // DEBUG
00765     
00766     // if it is our active client, deal with it...
00767     if (m_client == &client) {
00768     // set next client to be focused
00769     // if the client we're about to remove is the last client then set prev client
00770         if (&client == m_clientlist.back())
00771             prevClient();
00772         else
00773             nextClient();
00774     }
00775 
00776     client.m_win = 0;
00777     m_clientlist.remove(&client);
00778 
00779     if (m_client == &client) {
00780         if (m_clientlist.empty())
00781             m_client = 0;
00782         else
00783             // this really shouldn't happen
00784             m_client = m_clientlist.back();
00785     }
00786 
00787     FbTk::EventManager &evm = *FbTk::EventManager::instance();
00788     evm.remove(client.window());
00789 
00790     FbTk::TextButton *label_btn = m_labelbuttons[&client];
00791     if (label_btn != 0) {
00792         frame().removeLabelButton(*label_btn);
00793         evm.remove(label_btn->window());
00794         delete label_btn;
00795         label_btn = 0;
00796     }
00797 
00798     m_labelbuttons.erase(&client);
00799 
00800     frame().reconfigure();
00801 
00802 #ifdef DEBUG
00803     cerr<<__FILE__<<"("<<__FUNCTION__<<")["<<this<<"] numClients = "<<numClients()<<endl;
00804 #endif // DEBUG   
00805 
00806     return true;
00807 }
00808 
00810 WinClient *FluxboxWindow::findClient(Window win) {
00811     ClientList::iterator it = find_if(clientList().begin(),
00812                                       clientList().end(),
00813                                       FbTk::Compose(bind2nd(equal_to<Window>(), win),
00814                                                     mem_fun(&WinClient::window)));
00815     return (it == clientList().end() ? 0 : *it);
00816 }
00817 
00819 void FluxboxWindow::nextClient() {
00820     if (numClients() <= 1)
00821         return;
00822 
00823     ClientList::iterator it = find(m_clientlist.begin(), m_clientlist.end(), m_client);
00824     WinClient *client = 0;
00825     if (it == m_clientlist.end()) {
00826         client = m_clientlist.front();
00827     } else {
00828         it++;
00829         if (it == m_clientlist.end())
00830             client = m_clientlist.front();
00831         else
00832             client = *it;
00833     }
00834     setCurrentClient(*client, true);
00835 }
00836 
00837 void FluxboxWindow::prevClient() {
00838     if (numClients() <= 1)
00839         return;
00840 
00841     ClientList::iterator it = find(m_clientlist.begin(), m_clientlist.end(), m_client);
00842     WinClient *client = 0;
00843     if (it == m_clientlist.end()) {
00844         client = m_clientlist.front();
00845     } else {
00846         if (it == m_clientlist.begin())
00847             client = m_clientlist.back();
00848         else
00849             client = *(--it);
00850     }
00851 
00852     setCurrentClient(*client, true);
00853 }
00854 
00855 
00856 void FluxboxWindow::moveClientLeft() {
00857     if (m_clientlist.size() == 1 ||
00858         *m_clientlist.begin() == &winClient())
00859         return;
00860     // move label button to the left
00861     frame().moveLabelButtonLeft(*m_labelbuttons[&winClient()]);
00862     // move client in clientlist to the left
00863     ClientList::iterator it = find(m_clientlist.begin(), m_clientlist.end(), &winClient());    
00864     ClientList::iterator new_pos = it;
00865     new_pos--;
00866     m_clientlist.erase(it);
00867     m_clientlist.insert(new_pos, &winClient());
00868 
00869     updateClientLeftWindow();
00870 
00871 }
00872 
00873 void FluxboxWindow::moveClientRight() {
00874     if (m_clientlist.size() == 1)
00875         return;
00876     // move label button to the right
00877     frame().moveLabelButtonRight(*m_labelbuttons[&winClient()]);
00878     // move client in clientlist to the right
00879     ClientList::iterator it = find(m_clientlist.begin(), m_clientlist.end(), &winClient());    
00880     ClientList::iterator new_pos = m_clientlist.erase(it);
00881     new_pos++;
00882     m_clientlist.insert(new_pos, &winClient());
00883 
00884     updateClientLeftWindow();
00885 }
00886 
00888 void FluxboxWindow::updateClientLeftWindow() {
00889     // It should just update the affected clients but that
00890     // would require more complex code and we're assuming
00891     // the user dont have alot of windows grouped so this 
00892     // wouldn't be too time consuming and it's easier to
00893     // implement.
00894     ClientList::iterator it = clientList().begin();
00895     ClientList::iterator it_end = clientList().end();
00896     // set no left window on first tab
00897     (*it)->setGroupLeftWindow(0);
00898     WinClient *last_client = *it;
00899     ++it;
00900     for (; it != it_end; ++it) {
00901         (*it)->setGroupLeftWindow(last_client->window());
00902         last_client = *it;
00903     }
00904 }
00905 
00906 bool FluxboxWindow::setCurrentClient(WinClient &client, bool setinput) {
00907     // make sure it's in our list
00908     if (client.m_win != this)
00909         return false;
00910 
00911     m_client = &client;
00912     m_client->raise();
00913     if (setinput && setInputFocus()) {
00914         frame().setLabelButtonFocus(*m_labelbuttons[m_client]);
00915         return true;
00916     }
00917 
00918     return false;
00919 }
00920 
00921 bool FluxboxWindow::isGroupable() const {
00922     if (isResizable() && isMaximizable() && !winClient().isTransient())
00923         return true;
00924     return false;
00925 }
00926 
00927 void FluxboxWindow::associateClientWindow(bool use_attrs, int x, int y, unsigned int width, unsigned int height) {
00928     m_client->setBorderWidth(0);
00929     updateTitleFromClient(*m_client);
00930     updateIconNameFromClient(*m_client);
00931 
00932     if (use_attrs)
00933         frame().moveResizeForClient(x, y,
00934                                     width, height);
00935     else
00936         frame().resizeForClient(m_client->width(), m_client->height());
00937 
00938     frame().setClientWindow(*m_client);
00939 }
00940 
00941 
00942 void FluxboxWindow::grabButtons() {
00943 
00944     XGrabButton(display, Button1, AnyModifier, 
00945         frame().window().window(), True, ButtonPressMask,
00946         GrabModeSync, GrabModeSync, None, None);        
00947     XUngrabButton(display, Button1, Mod1Mask|Mod2Mask|Mod3Mask, frame().window().window());
00948 
00949     if (Fluxbox::instance()->useMod1()) {
00950         XGrabButton(display, Button1, Mod1Mask, frame().window().window(), True,
00951                     ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
00952                     GrabModeAsync, None, frame().theme().moveCursor());
00953 
00954         //----grab with "all" modifiers
00955         grabButton(display, Button1, frame().window().window(), frame().theme().moveCursor());
00956    
00957         XGrabButton(display, Button2, Mod1Mask, frame().window().window(), True,
00958                     ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None);
00959         
00960         XGrabButton(display, Button3, Mod1Mask, frame().window().window(), True,
00961                     ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
00962                     GrabModeAsync, None, None);
00963     
00964         //---grab with "all" modifiers
00965         grabButton(display, Button3, frame().window().window(), None);
00966     }
00967 }
00968 
00969 
00970 void FluxboxWindow::reconfigure() {
00971 
00972     upsize();
00973 
00974     applyDecorations();
00975 
00976     setFocusFlag(focused);
00977 
00978     moveResize(frame().x(), frame().y(), frame().width(), frame().height());
00979     
00980     grabButtons();
00981 
00982     frame().setDoubleClickTime(Fluxbox::instance()->getDoubleClickInterval());
00983     frame().setUpdateDelayTime(Fluxbox::instance()->getUpdateDelayTime());
00984 
00985     frame().reconfigure();
00986 
00987     m_windowmenu.reconfigure();
00988     
00989 }
00990 
00992 void FluxboxWindow::updateTitleFromClient(WinClient &client) {
00993     client.updateTitle();
00994     // compare old title with new and see if we need to update
00995     // graphics
00996     if (m_labelbuttons[&client]->text() != client.title()) {
00997         m_labelbuttons[&client]->setText(client.title());    
00998         m_labelbuttons[&client]->clear(); // redraw text
00999         m_labelbuttons[&client]->updateTransparent();
01000     }
01001 }
01002 
01004 void FluxboxWindow::updateIconNameFromClient(WinClient &client) {
01005     client.updateIconTitle();
01006 }
01007 
01008 void FluxboxWindow::updateMWMHintsFromClient(WinClient &client) {
01009     const WinClient::MwmHints *hint = client.getMwmHint();
01010 
01011     if (!hint) return;
01012 
01013     if (hint->flags & MwmHintsDecorations) {
01014         if (hint->decorations & MwmDecorAll) {
01015             decorations.titlebar = decorations.handle = decorations.border =
01016                 decorations.iconify = decorations.maximize =
01017                 decorations.close = decorations.menu = true;
01018         } else {
01019             decorations.titlebar = decorations.handle = decorations.border =
01020                 decorations.iconify = decorations.maximize =
01021                 decorations.close = decorations.tab = false;
01022             decorations.menu = true;
01023             if (hint->decorations & MwmDecorBorder)
01024                 decorations.border = true;
01025             if (hint->decorations & MwmDecorHandle)
01026                 decorations.handle = true;
01027             if (hint->decorations & MwmDecorTitle) {                
01028                 //only tab on windows with titlebar
01029                 decorations.titlebar = decorations.tab = true;
01030             }
01031             
01032             if (hint->decorations & MwmDecorMenu)
01033                 decorations.menu = true;
01034             if (hint->decorations & MwmDecorIconify)
01035                 decorations.iconify = true;
01036             if (hint->decorations & MwmDecorMaximize)
01037                 decorations.maximize = true;
01038         }
01039     }
01040     
01041     if (hint->flags & MwmHintsFunctions) {
01042         if (hint->functions & MwmFuncAll) {
01043             functions.resize = functions.move = functions.iconify =
01044                 functions.maximize = functions.close = true;
01045         } else {
01046             functions.resize = functions.move = functions.iconify =
01047                 functions.maximize = functions.close = false;
01048 
01049             if (hint->functions & MwmFuncResize)
01050                 functions.resize = true;
01051             if (hint->functions & MwmFuncMove)
01052                 functions.move = true;
01053             if (hint->functions & MwmFuncIconify)
01054                 functions.iconify = true;
01055             if (hint->functions & MwmFuncMaximize)
01056                 functions.maximize = true;
01057             if (hint->functions & MwmFuncClose)
01058                 functions.close = true;
01059         }
01060     }
01061 }
01062 
01063 void FluxboxWindow::updateFunctions() {
01064     if (!m_client)
01065         return;
01066     bool changed = false;
01067     if (m_client->isClosable() != functions.close) {
01068         functions.close = m_client->isClosable();
01069         changed = true;
01070     }
01071 
01072     if (changed)
01073         setupWindow();
01074 }
01075 
01076 void FluxboxWindow::updateBlackboxHintsFromClient(const WinClient &client) {
01077     const FluxboxWindow::BlackboxHints *hint = client.getBlackboxHint();
01078     if (!hint) return;
01079 
01080     if (hint->flags & ATTRIB_SHADED)
01081         shaded = (hint->attrib & ATTRIB_SHADED);
01082 
01083     if ((hint->flags & ATTRIB_MAXHORIZ) &&
01084         (hint->flags & ATTRIB_MAXVERT))
01085         maximized = ((hint->attrib &
01086                       (ATTRIB_MAXHORIZ | 
01087                        ATTRIB_MAXVERT)) ? MAX_FULL : MAX_NONE);
01088     else if (hint->flags & ATTRIB_MAXVERT)
01089         maximized = ((hint->attrib & 
01090                       ATTRIB_MAXVERT) ? MAX_VERT : MAX_NONE);
01091     else if (hint->flags & ATTRIB_MAXHORIZ)
01092         maximized = ((hint->attrib & 
01093                       ATTRIB_MAXHORIZ) ? MAX_HORZ : MAX_NONE);
01094 
01095     if (hint->flags & ATTRIB_OMNIPRESENT)
01096         stuck = (hint->attrib & 
01097                  ATTRIB_OMNIPRESENT);
01098 
01099     if (hint->flags & ATTRIB_WORKSPACE)
01100         m_workspace_number = hint->workspace;
01101 
01102     if (hint->flags & ATTRIB_STACK)
01103         m_workspace_number = hint->stack;
01104 
01105     if (hint->flags & ATTRIB_DECORATION) {
01106         m_old_decoration = static_cast<Decoration>(hint->decoration);
01107         setDecoration(m_old_decoration);
01108     }
01109 }
01110 
01111 void FluxboxWindow::move(int x, int y, int gravity) {
01112     moveResize(x, y, frame().width(), frame().height(), gravity);
01113 }
01114 
01115 void FluxboxWindow::resize(unsigned int width, unsigned int height) {
01116     moveResize(frame().x(), frame().y(), width, height);
01117 }
01118 
01119 void FluxboxWindow::moveResize(int new_x, int new_y,
01120                                unsigned int new_width, unsigned int new_height, int gravity) {
01121 
01122     if (gravity != ForgetGravity) {
01123         frame().gravityTranslate(new_x, new_y, gravity, false);
01124     }
01125 
01126     bool send_event = (frame().x() != new_x || frame().y() != new_y);
01127 
01128     if (new_width != frame().width() || new_height != frame().height()) {
01129         if ((((signed) frame().width()) + new_x) < 0) 
01130             new_x = 0;
01131         if ((((signed) frame().height()) + new_y) < 0) 
01132             new_y = 0;
01133 
01134         downsize();
01135         if (!isResizable()) {
01136             new_width = width();
01137             new_height = height();
01138         }
01139 
01140         frame().moveResize(new_x, new_y, new_width, new_height);
01141         setFocusFlag(focused);
01142         
01143 
01144         shaded = false;
01145         send_event = true;
01146     } else if (send_event)
01147         frame().move(new_x, new_y);
01148 
01149     if (send_event && ! moving) {
01150         sendConfigureNotify();
01151     }
01152 
01153     shape();
01154 
01155     if (!moving) {
01156         m_last_resize_x = new_x;
01157         m_last_resize_y = new_y;
01158     }
01159 }   
01160 
01161 // returns whether the focus was "set" to this window
01162 // it doesn't guarantee that it has focus, but says that we have
01163 // tried. A FocusqIn event should eventually arrive for that
01164 // window if it actually got the focus, then setFocusedFlag is called,
01165 // which updates all the graphics etc
01166 bool FluxboxWindow::setInputFocus() {
01167 
01168     if (((signed) (frame().x() + frame().width())) < 0) {
01169         if (((signed) (frame().y() + frame().height())) < 0) {
01170             moveResize(frame().window().borderWidth(), frame().window().borderWidth(),
01171                        frame().width(), frame().height());
01172         } else if (frame().y() > (signed) screen().height()) {
01173             moveResize(frame().window().borderWidth(), screen().height() - frame().height(),
01174                        frame().width(), frame().height());
01175         } else {
01176             moveResize(frame().window().borderWidth(), frame().y() + frame().window().borderWidth(),
01177                        frame().width(), frame().height());
01178         }
01179     } else if (frame().x() > (signed) screen().width()) {
01180         if (((signed) (frame().y() + frame().height())) < 0) {
01181             moveResize(screen().width() - frame().width(), frame().window().borderWidth(),
01182                        frame().width(), frame().height());
01183         } else if (frame().y() > (signed) screen().height()) {
01184             moveResize(screen().width() - frame().width(),
01185                        screen().height() - frame().height(), 
01186                        frame().width(), frame().height());
01187         } else {
01188             moveResize(screen().width() - frame().width(),
01189                        frame().y() + frame().window().borderWidth(), 
01190                        frame().width(), frame().height());
01191         }
01192     }
01193 
01194     if (! m_client->validateClient())
01195         return false;
01196 
01197     if (!m_client->transients.empty() && m_client->isModal()) {
01198         WinClient::TransientList::iterator it = m_client->transients.begin();
01199         WinClient::TransientList::iterator it_end = m_client->transients.end();
01200         for (; it != it_end; ++it) {
01201             if ((*it)->isModal())
01202                 return (*it)->fbwindow()->setCurrentClient(**it, true);
01203         }
01204     } 
01205 
01206     bool ret = false;
01207 
01208     if (m_client->getFocusMode() == WinClient::F_LOCALLYACTIVE ||
01209         m_client->getFocusMode() == WinClient::F_PASSIVE) {
01210 
01211         m_client->setInputFocus(RevertToPointerRoot, CurrentTime);
01212 
01213         FbTk::App *app = FbTk::App::instance();
01214 
01215         XFlush(app->display());
01216 
01217         m_client->sendFocus();
01218 
01219         app->sync(false);
01220         app->sync(false);
01221 
01222         ret = true;
01223     } else {
01224         ret = m_client->sendFocus(); 
01225     }
01226 
01227                                                   
01228     return ret;
01229 }
01230 
01231 void FluxboxWindow::hide() {
01232 #ifdef DEBUG
01233     cerr<<__FILE__<<"("<<__FUNCTION__<<")["<<this<<"]"<<endl;
01234 #endif // DEBUG
01235     m_windowmenu.hide();
01236     frame().hide();
01237 }
01238 
01239 void FluxboxWindow::show() {
01240     frame().show();
01241 }
01242 
01246 void FluxboxWindow::iconify() {
01247     if (isIconic()) // no need to iconify if we're already
01248         return;
01249 
01250     menu().hide();
01251     iconic = true;
01252 
01253     setState(IconicState);
01254 
01255     frame().hide();
01256 
01257     ClientList::iterator client_it = m_clientlist.begin();
01258     const ClientList::iterator client_it_end = m_clientlist.end();
01259     for (; client_it != client_it_end; ++client_it) {
01260         WinClient &client = *(*client_it);
01261         client.setEventMask(NoEventMask);
01262         client.hide();
01263         client.setEventMask(PropertyChangeMask | StructureNotifyMask | FocusChangeMask);
01264         if (client.transientFor() &&
01265             client.transientFor()->fbwindow()) {
01266             if (!client.transientFor()->fbwindow()->isIconic()) {
01267                 client.transientFor()->fbwindow()->iconify();
01268             }
01269         }
01270 
01271         if (!client.transientList().empty()) {
01272             WinClient::TransientList::iterator it = client.transientList().begin();
01273             WinClient::TransientList::iterator it_end = client.transientList().end();
01274             for (; it != it_end; it++)
01275                 if ((*it)->fbwindow()) 
01276                     (*it)->fbwindow()->iconify();
01277         }
01278     }
01279 
01280     WinClient *focused_client = Fluxbox::instance()->getFocusedWindow();
01281     if (focused_client && focused_client->fbwindow() == this)
01282         Fluxbox::instance()->revertFocus(screen());
01283 
01284 }
01285 
01286 void FluxboxWindow::deiconify(bool reassoc, bool do_raise) {
01287     if (numClients() == 0)
01288         return;
01289 
01290     if (oplock) return;
01291     oplock = true;
01292 
01293     if (iconic || reassoc) {
01294         screen().reassociateWindow(this, screen().currentWorkspace()->workspaceID(), false);
01295     } else if (moving || m_workspace_number != screen().currentWorkspace()->workspaceID()) {
01296         oplock = false;
01297         return;
01298     }
01299 
01300     bool was_iconic = iconic;
01301 
01302     iconic = false;
01303     setState(NormalState);
01304 
01305     ClientList::iterator client_it = clientList().begin();
01306     ClientList::iterator client_it_end = clientList().end();
01307     for (; client_it != client_it_end; ++client_it) {
01308         (*client_it)->setEventMask(NoEventMask);        
01309         (*client_it)->show();
01310         (*client_it)->setEventMask(PropertyChangeMask | StructureNotifyMask | FocusChangeMask);
01311     }
01312 
01313     show();
01314 
01315     if (was_iconic && screen().doFocusNew())
01316         setInputFocus();
01317 
01318     if (reassoc && !m_client->transients.empty()) {
01319         // deiconify all transients
01320         client_it = clientList().begin();
01321         for (; client_it != client_it_end; ++client_it) {
01322             //TODO: Can this get stuck in a loop?
01323             WinClient::TransientList::iterator trans_it = 
01324                 (*client_it)->transientList().begin();
01325             WinClient::TransientList::iterator trans_it_end = 
01326                 (*client_it)->transientList().end();
01327             for (; trans_it != trans_it_end; ++trans_it) {
01328                 if ((*trans_it)->fbwindow())
01329                     (*trans_it)->fbwindow()->deiconify(true, false);
01330             }
01331         }
01332     }
01333 
01334     oplock = false;
01335 
01336     if (do_raise)
01337     raise();
01338 }
01339 
01343 void FluxboxWindow::withdraw() {
01344     iconic = false;
01345 
01346     if (isResizing())
01347         stopResizing();
01348 
01349     frame().hide();
01350 
01351     m_windowmenu.hide();
01352 }
01353 
01357 void FluxboxWindow::maximize(int type) {
01358     if (isIconic())
01359         deiconify();
01360 
01361     int head = screen().getHead(frame().window());
01362     int new_x = frame().x(),
01363         new_y = frame().y(),
01364         new_w = frame().width(),
01365         new_h = frame().height();
01366 
01367     int orig_max = maximized;
01368 
01369     // These evaluate whether we need to TOGGLE the value for that field
01370     // Why? If maximize is only set to zero outside this, 
01371     // and we only EVER toggle them, then:
01372     // 1) We will never loose the old_ values 
01373     // 2) It shouldn't get confused
01374 
01375     // Worst case being that some action will toggle the wrong way, but 
01376     // we still won't lose the state in that case.
01377 
01378     // NOTE: There is one option to the way this works - what it does when 
01379     // fully maximised and maximise(vert, horz) is selected.
01380     // There are 2 options here - either:
01381     // 1) maximiseVertical results in a vertically (not horz) maximised window, or
01382     // 2) " toggles vertical maximisation, thus resulting in a horizontally 
01383     //      maximised window.
01384     //
01385     // The current implementation uses style 1, to change this, removed the 
01386     // item corresponding to the [[ ]] comment
01387 
01388     // toggle maximize vertically?
01389     // when _don't_ we want to toggle?
01390     // - type is horizontal maximise, [[and we aren't fully maximised]] or
01391     // - [[ type is vertical maximise and we are fully maximised ]]
01392     // - type is none and we are not vertically maximised, or
01393     // - type is full and we are not horizontally maximised, but already vertically
01394     if (!(type == MAX_HORZ && orig_max != MAX_FULL ||
01395           type == MAX_VERT && orig_max == MAX_FULL ||
01396           type == MAX_NONE && !(orig_max & MAX_VERT) ||
01397           type == MAX_FULL && orig_max == MAX_VERT)) {
01398         // already maximized in that direction?
01399         if (orig_max & MAX_VERT) {
01400             new_y = m_old_pos_y;
01401             new_h = m_old_height;
01402         } else {
01403             m_old_pos_y  = new_y;
01404             m_old_height = new_h;
01405             new_y = screen().maxTop(head);
01406             new_h = screen().maxBottom(head) - new_y - 2*frame().window().borderWidth();
01407         }
01408         maximized ^= MAX_VERT;
01409     }
01410 
01411     // maximize horizontally?
01412     if (!(type == MAX_VERT && orig_max != MAX_FULL ||
01413           type == MAX_HORZ && orig_max == MAX_FULL ||
01414           type == MAX_NONE && !(orig_max & MAX_HORZ) ||
01415           type == MAX_FULL && orig_max == MAX_HORZ)) {
01416         // already maximized in that direction?
01417         if (orig_max & MAX_HORZ) {
01418             new_x = m_old_pos_x;
01419             new_w = m_old_width;
01420         } else {
01421             // only save if we weren't already maximized
01422             m_old_pos_x = new_x;
01423             m_old_width = new_w;
01424             new_x = screen().maxLeft(head);
01425             new_w = screen().maxRight(head) - new_x - 2*frame().window().borderWidth();
01426         }
01427         maximized ^= MAX_HORZ;
01428     }
01429             
01430     moveResize(new_x, new_y, new_w, new_h);
01431 
01432 }
01436 void FluxboxWindow::maximizeHorizontal() {
01437     maximize(MAX_HORZ);
01438 }
01439 
01443 void FluxboxWindow::maximizeVertical() {
01444     maximize(MAX_VERT);
01445 }
01446 
01450 void FluxboxWindow::maximizeFull() {
01451     maximize(MAX_FULL);
01452 }
01453 
01454 
01455 void FluxboxWindow::setWorkspace(int n) {
01456     unsigned int old_wkspc = m_workspace_number;
01457 
01458     m_workspace_number = n;
01459 
01460     m_blackbox_attrib.flags |= ATTRIB_WORKSPACE;
01461     m_blackbox_attrib.workspace = m_workspace_number;
01462 
01463     // notify workspace change
01464     if (!stuck && old_wkspc != m_workspace_number) {
01465 #ifdef DEBUG
01466         cerr<<this<<" notify workspace signal"<<endl;
01467 #endif // DEBUG
01468         m_workspacesig.notify();
01469     }
01470 }
01471 
01472 void FluxboxWindow::setLayerNum(int layernum) {
01473     m_layernum = layernum;
01474 
01475     m_blackbox_attrib.flags |= ATTRIB_STACK;
01476     m_blackbox_attrib.stack = layernum;
01477     saveBlackboxAttribs();
01478 
01479 #ifdef DEBUG
01480     cerr<<this<<" notify layer signal"<<endl;
01481 #endif // DEBUG
01482 
01483     m_layersig.notify();
01484 }
01485 
01486 void FluxboxWindow::shade() {
01487     // we can only shade if we have a titlebar
01488     if (!decorations.titlebar)
01489         return;
01490 
01491     frame().shade();
01492 
01493     if (shaded) {
01494         shaded = false;
01495         m_blackbox_attrib.flags ^= ATTRIB_SHADED;
01496         m_blackbox_attrib.attrib ^= ATTRIB_SHADED;
01497 
01498         setState(NormalState);
01499     } else {
01500         shaded = true;
01501         m_blackbox_attrib.flags |= ATTRIB_SHADED;
01502         m_blackbox_attrib.attrib |= ATTRIB_SHADED;
01503         // shading is the same as iconic
01504         setState(IconicState);
01505     }
01506 
01507 }
01508 
01509 
01510 void FluxboxWindow::stick() {
01511 
01512     if (stuck) {
01513         m_blackbox_attrib.flags ^= ATTRIB_OMNIPRESENT;
01514         m_blackbox_attrib.attrib ^= ATTRIB_OMNIPRESENT;
01515 
01516         stuck = false;
01517 
01518     } else {
01519         stuck = true;
01520 
01521         m_blackbox_attrib.flags |= ATTRIB_OMNIPRESENT;
01522         m_blackbox_attrib.attrib |= ATTRIB_OMNIPRESENT;
01523 
01524     }
01525  
01526     setState(m_current_state);
01527     // notify since some things consider "stuck" to be a pseudo-workspace
01528     m_workspacesig.notify();
01529 
01530 }
01531 
01532 
01533 void FluxboxWindow::raise() {
01534     if (isIconic())
01535         deiconify();
01536 
01537     // get root window
01538     WinClient *client = getRootTransientFor(m_client);
01539 
01540     // if we don't have any root window use this as root
01541     if (client == 0) 
01542         client = m_client;
01543 
01544     // raise this window and every transient in it
01545     if (client->fbwindow())
01546         raiseFluxboxWindow(*client->fbwindow());
01547 }
01548 
01549 void FluxboxWindow::lower() {
01550     if (isIconic())
01551         deiconify();
01552 
01553     // get root window
01554     WinClient *client = getRootTransientFor(m_client);
01555     
01556     // if we don't have any root window use this as root
01557     if (client == 0) 
01558         client = m_client;
01559 
01560     if (client->fbwindow())
01561         lowerFluxboxWindow(*client->fbwindow());
01562 }
01563 
01564 void FluxboxWindow::tempRaise() {
01565     if (isIconic())
01566         deiconify();
01567 
01568     // get root window
01569     WinClient *client = getRootTransientFor(m_client);
01570     
01571     // if we don't have any root window use this as root
01572     if (client == 0) 
01573         client = m_client;
01574 
01575     if (client->fbwindow())
01576         tempRaiseFluxboxWindow(*client->fbwindow());
01577 }
01578 
01579 
01580 void FluxboxWindow::raiseLayer() {
01581     // don't let it up to menu layer
01582     if (layerNum() == (Fluxbox::instance()->getMenuLayer()+1))
01583         return;
01584 
01585     // get root window
01586     WinClient *client = getRootTransientFor(m_client);
01587     
01588     // if we don't have any root window use this as root
01589     if (client == 0) 
01590         client = m_client;
01591 
01592     FluxboxWindow *win = client->fbwindow();
01593     if (!win) return;
01594 
01595     if (!win->isIconic())
01596         screen().updateNetizenWindowRaise(client->window());
01597 
01598     win->layerItem().raiseLayer();
01599 
01600     // remember number just in case a transient happens to revisit this window
01601     int layer_num = win->layerItem().getLayerNum();
01602     win->setLayerNum(layer_num);
01603 
01604     WinClient::TransientList::const_iterator it = client->transientList().begin();
01605     WinClient::TransientList::const_iterator it_end = client->transientList().end();
01606     for (; it != it_end; ++it) {
01607         win = (*it)->fbwindow();
01608         if (win && !win->isIconic()) {
01609             screen().updateNetizenWindowRaise((*it)->window());
01610             win->layerItem().moveToLayer(layer_num);
01611             win->setLayerNum(layer_num);
01612         }
01613     }
01614 }
01615 
01616 void FluxboxWindow::lowerLayer() {
01617     // get root window
01618     WinClient *client = getRootTransientFor(m_client);
01619     
01620     // if we don't have any root window use this as root
01621     if (client == 0) 
01622         client = m_client;
01623 
01624     FluxboxWindow *win = client->fbwindow();
01625     if (!win) return;
01626 
01627     if (!win->isIconic()) {
01628         screen().updateNetizenWindowLower(client->window());
01629     }
01630     win->layerItem().lowerLayer();
01631     // remember number just in case a transient happens to revisit this window
01632     int layer_num = win->layerItem().getLayerNum();
01633     win->setLayerNum(layer_num);
01634 
01635     WinClient::TransientList::const_iterator it = client->transientList().begin();
01636     WinClient::TransientList::const_iterator it_end = client->transientList().end();
01637     for (; it != it_end; ++it) {
01638         win = (*it)->fbwindow();
01639         if (win && !win->isIconic()) {
01640             screen().updateNetizenWindowLower((*it)->window());
01641             win->layerItem().moveToLayer(layer_num);
01642             win->setLayerNum(layer_num);
01643         }
01644     }
01645 }
01646 
01647 
01648 void FluxboxWindow::moveToLayer(int layernum) {
01649     Fluxbox * fluxbox = Fluxbox::instance();
01650 
01651     // don't let it set its layer into menu area
01652     if (layernum <= fluxbox->getMenuLayer()) {
01653         layernum = fluxbox->getMenuLayer() + 1;
01654     }
01655 
01656     // get root window
01657     WinClient *client = getRootTransientFor(m_client);
01658     
01659     // if we don't have any root window use this as root
01660     if (client == 0) 
01661         client = m_client;
01662 
01663     FluxboxWindow *win = client->fbwindow();
01664     if (!win) return;
01665 
01666     if (!win->isIconic()) {
01667         screen().updateNetizenWindowRaise(client->window());
01668     }
01669     win->layerItem().moveToLayer(layernum);
01670     // remember number just in case a transient happens to revisit this window
01671     layernum = win->layerItem().getLayerNum();
01672     win->setLayerNum(layernum);
01673 
01674     WinClient::TransientList::const_iterator it = client->transientList().begin();
01675     WinClient::TransientList::const_iterator it_end = client->transientList().end();
01676     for (; it != it_end; ++it) {
01677         win = (*it)->fbwindow();
01678         if (win && !win->isIconic()) {
01679             screen().updateNetizenWindowRaise((*it)->window());
01680             win->layerItem().moveToLayer(layernum);
01681             win->setLayerNum(layernum);
01682         }
01683     }
01684 }
01685 
01686 
01687 // window has actually RECEIVED focus (got a FocusIn event)
01688 // so now we make it a focused frame etc
01689 void FluxboxWindow::setFocusFlag(bool focus) {
01690     bool was_focused = isFocused();
01691     focused = focus;
01692 
01693     // Record focus timestamp for window cycling enhancements
01694     if (focused) {
01695         gettimeofday(&m_last_focus_time, 0);
01696         screen().setFocusedWindow(*m_client);
01697     }
01698 
01699     installColormap(focus);
01700 
01701     if (focus != frame().focused())
01702         frame().setFocus(focus);
01703 
01704     if ((screen().isSloppyFocus() || screen().isSemiSloppyFocus())
01705         && screen().doAutoRaise()) {
01706         if (focused)
01707             m_timer.start();
01708         else 
01709             m_timer.stop();
01710     }
01711 
01712     // did focus change? notify listeners
01713     if (was_focused != focus)
01714         m_focussig.notify();
01715 }
01716 
01717 
01718 void FluxboxWindow::installColormap(bool install) {
01719     if (m_client == 0) return;
01720 
01721     Fluxbox *fluxbox = Fluxbox::instance();
01722     fluxbox->grab();
01723     if (! m_client->validateClient())
01724         return;
01725 
01726     int i = 0, ncmap = 0;
01727     Colormap *cmaps = XListInstalledColormaps(display, m_client->window(), &ncmap);
01728     XWindowAttributes wattrib;
01729     if (cmaps) { 
01730         if (m_client->getAttrib(wattrib)) {
01731             if (install) {
01732                 // install the window's colormap
01733                 for (i = 0; i < ncmap; i++) {
01734                     if (*(cmaps + i) == wattrib.colormap) {
01735                         // this window is using an installed color map... do not install
01736                         install = false;
01737                         break; //end for-loop (we dont need to check more)
01738                     }
01739                 }
01740                 // otherwise, install the window's colormap
01741                 if (install)
01742                     XInstallColormap(display, wattrib.colormap);
01743             } else {                
01744                 for (i = 0; i &l