wmi

git clone git://oldgit.suckless.org/wmi/
Log | Files | Refs | LICENSE

client.cpp (22740B)


      1 // Copyright (c) 2003 - 2009 Anselm R Garbe <anselm@garbe.us>
      2 // See LICENSE for license details.
      3 
      4 #include <sstream>
      5 
      6 extern "C" {
      7 #include <assert.h>
      8 #include <X11/Xatom.h>
      9 }
     10 
     11 #include "client.h"
     12 
     13 #include "atoms.h"
     14 #include "binder.h"
     15 #include "cursors.h"
     16 #include "draw.h"
     17 #include "clientbar.h"
     18 #include "frame.h"
     19 #include "kernel.h"
     20 #include "label.h"
     21 #include "logger.h"
     22 #include "rectangle.h"
     23 #include "statusbar.h"
     24 #include "monitor.h"
     25 #include "util.h"
     26 #include "slot.h"
     27 #include "theme.h"
     28 #include "workspace.h"
     29 #include "xcore.h"
     30 
     31 Client::Client(Monitor *monitor, Window window, XWindowAttributes *attr)
     32     : Thing(monitor, new Rectangle(), Thing::CLIENT)
     33 {
     34     clientWindow_ = window;
     35     frame_ = 0;
     36     state_ = WithdrawnState;
     37     iconName_ = "";
     38     isCentered_ = false;
     39     protocols_ = 0;
     40     hasFrame_ = false;
     41     requestsFocus_ = false;
     42     isDestroyed_ = false;
     43     hooked_ = "";
     44     workspace_ = 0;
     45 
     46     ostringstream oss;
     47     oss << "<" << monitor->nextClientId() << ">";
     48     id_ = oss.str();
     49 
     50     eventMask_ = PropertyChangeMask;
     51     XCORE->selectEvents(clientWindow_, eventMask_);
     52 
     53     setX(attr->x);
     54     setY(attr->y);
     55     setWidth(attr->width);
     56     setHeight(attr->height);
     57     borderWidth_ = attr->border_width;
     58 
     59     oss.str("");
     60     oss << "constructing new client with dimensions: " <<
     61         x() << "," << y() << "," << width() << "," << height();
     62     LOGDEBUG(oss.str());
     63 
     64     className_ = XCORE->className(clientWindow_);
     65     instanceName_ = XCORE->instanceName(clientWindow_);
     66 
     67     string value;
     68 
     69     updateTransient();
     70     if (transient_) {
     71          value = Util::get(KERNEL->sessionSettings(),
     72                      "client." + className_ + "::" + instanceName_ + ".transient-mode");
     73 
     74         if ("" == value) {
     75             value = Util::get(KERNEL->commonSettings(),
     76                               "default.transient-mode");
     77 
     78             if ("" == value) {
     79                 value = "float";
     80             }
     81         }
     82     }
     83     else {
     84         value = Util::get(KERNEL->sessionSettings(),
     85                          "client." + className_ + "::" + instanceName_ + ".mode");
     86     }
     87 
     88     if (value == "float") {
     89         mode_ = FLOAT;
     90     }
     91     else if (value == "sticky") {
     92         mode_ = STICKY;
     93     }
     94     else if (value == "max") {
     95         mode_ = MAX;
     96     }
     97 #ifdef SLOT_SUPPORT
     98     else if (value == "slot") {
     99         mode_ = SLOT;
    100     }
    101 #endif // SLOT_SUPPORT
    102     // fallback, unknown yet
    103     else if (Util::get(KERNEL->commonSettings(), "default.client-mode")
    104             == "float")
    105     {
    106         mode_ = FLOAT;
    107     }
    108     else {
    109         mode_ = MAX;
    110     }
    111 
    112     hooked_ = Util::get(KERNEL->sessionSettings(),
    113             "client." + className_ + "::" + instanceName_ + ".hooked");
    114 }
    115 
    116 Client::~Client() {
    117 }
    118 
    119 string Client::id() {
    120     return id_;
    121 }
    122 
    123 void Client::initICCCM() {
    124 
    125     state_ = XCORE->state(clientWindow_);
    126     iconName_ = XCORE->atomValue(clientWindow_, XA_WM_ICON_NAME);
    127     setName(XCORE->atomValue(clientWindow_, XA_WM_NAME) + id_);
    128     if (iconName_ == "") {
    129         iconName_ = name();
    130     }
    131     else {
    132         iconName_ += id_;
    133     }
    134     updateSize();
    135     protocols_ = XCORE->protocols(clientWindow_);
    136     if (XCORE->hasDecoration(clientWindow_) && !frameWindow()) {
    137         hasDecoration_ = true;
    138     }
    139 
    140     updateTransient();
    141 }
    142 
    143 void Client::updateSize() {
    144 
    145     unsigned int dummy;
    146     // TODO: increment handling
    147     XCORE->updateSize(clientWindow_, &dummy, &dummy,
    148                       &dummy, &dummy, &isCentered_);
    149 }
    150 
    151 void Client::updateTransient() {
    152 
    153     Window trans = XCORE->transient(clientWindow_);
    154     transient_ = KERNEL->clientForWindow(trans);
    155 }
    156 
    157 Client *Client::transient() const {
    158     return transient_;
    159 }
    160 
    161 void Client::sendConfiguration() {
    162     XConfigureEvent event;
    163 
    164     ostringstream oss;
    165 
    166     oss << "send configuration: " << clientAreaRect_.x() << ","
    167         << clientAreaRect_.y() << "," << clientAreaRect_.width()
    168         << "," << clientAreaRect_.height();
    169     LOGDEBUG(oss.str());
    170     event.type = ConfigureNotify;
    171     event.event = clientWindow_;
    172     event.window = clientWindow_;
    173     if (hasFrame_) {
    174         event.x = x() + clientAreaRect_.x();
    175         event.y = y() + clientAreaRect_.y();
    176     }
    177     else if (frame()) {
    178         event.x = frame()->x() + clientAreaRect_.x();
    179         event.y = frame()->y() + clientAreaRect_.y();
    180     }
    181     else {
    182         event.x = clientAreaRect_.x();
    183         event.y = clientAreaRect_.y();
    184     }
    185     event.width = clientAreaRect_.width();
    186     event.height = clientAreaRect_.height();
    187     event.border_width = clientBorderWidth_;
    188     event.above = None;
    189     event.override_redirect = False;
    190 
    191     XCORE->configure(clientWindow_, &event);
    192 }
    193 
    194 void Client::resize() {
    195 
    196     clientAreaRect_.copy(this);
    197 
    198     if (hasFrame_) {
    199         ostringstream oss;
    200         oss << "frame resize: x=" << x() << ", y=" << y() << ", w=" <<
    201             width() << ", h=" << height();
    202         LOGDEBUG(oss.str());
    203         XCORE->moveResize(frameWindow(), this);
    204 
    205         if (frame()) {
    206             // maximize client window
    207             clientAreaRect_.setX(0);
    208             clientAreaRect_.setY(0);
    209             clientAreaRect_.setWidth(width());
    210             clientAreaRect_.setHeight(height());
    211         }
    212         else {
    213             label_->setY(borderWidth_); // label fix for toggleBorder
    214             fitClientArea();
    215         }
    216     }
    217     XCORE->moveResize(clientWindow_, &clientAreaRect_);
    218     sendConfiguration();
    219     illuminate();
    220 }
    221 
    222 void Client::gravitate(bool invert) {
    223 
    224     int dx = 0;
    225     int dy = 0;
    226     int gravity = NorthWestGravity;
    227     XSizeHints sizeHints;
    228 
    229     XCORE->sizeHints(clientWindow_, &sizeHints);
    230 
    231     if (sizeHints.flags & PWinGravity) {
    232         gravity = sizeHints.win_gravity;
    233     }
    234 
    235     switch (gravity) {
    236     case NorthEastGravity:
    237     case EastGravity:
    238     case SouthEastGravity:
    239         dx = -borderWidth_;
    240         break;
    241     default:
    242         break;
    243     }
    244 
    245     switch (gravity) {
    246     case SouthWestGravity:
    247     case SouthGravity:
    248     case SouthEastGravity:
    249         dy = -titleBarHeight_ - borderWidth_;
    250         break;
    251     default:
    252         break;
    253     }
    254 
    255     if (invert) {
    256         dx = -dx;
    257         dy = -dy;
    258     }
    259 
    260     setX(x() + dx);
    261     setY(y() + dy);
    262 }
    263 
    264 void Client::handleConfigureRequest(XConfigureRequestEvent *event) {
    265 
    266     XWindowChanges wc;
    267 
    268     if (event->value_mask & CWStackMode) {
    269         if (attached()) {
    270             if (!isFocused()) {
    271                 requestsFocus_ = true;
    272             }
    273             if (monitor()->focused() != attached()) {
    274                 attached()->setRequestsFocus(true);
    275             }
    276         }
    277         event->value_mask &= ~CWStackMode;
    278     }
    279 
    280     event->value_mask &= ~CWSibling;
    281     if (!frame()
    282 #ifdef SLOT_SUPPORT
    283         || (mode_ == SLOT)
    284 #endif
    285        ) {
    286 
    287         // floating client
    288 
    289         gravitate(true);
    290 
    291         if (event->value_mask & CWX) {
    292             setX(event->x);
    293         }
    294         if (event->value_mask & CWY) {
    295             setY(event->y);
    296         }
    297         if (event->value_mask & CWWidth) {
    298             setWidth(event->width);
    299         }
    300         if (event->value_mask & CWHeight) {
    301             setHeight(event->height);
    302         }
    303         if (event->value_mask & CWBorderWidth) {
    304             clientBorderWidth_ = event->border_width;
    305         }
    306         ostringstream oss;
    307         oss << "configure request: x=" << x() << ", y=" << y()
    308             << ", w=" << width() << ", h=" << height();
    309         LOGDEBUG(oss.str());
    310 
    311         gravitate(false);
    312 
    313         // applied patch by Dr. J. Pfefferl
    314         if (hasFrame_) {
    315 
    316             if((event->value_mask & CWWidth)) {
    317                 setWidth(width() + 2 * borderWidth_);
    318             }
    319             if((event->value_mask & CWHeight)) {
    320                 setHeight(height() + titleBarHeight_ + 2 * borderWidth_
    321                         + (titleBarHeight_ ? 1 : 0));
    322             }
    323             if((event->value_mask & CWX)) {
    324                 setX(x() - borderWidth_);
    325             }
    326             if((event->value_mask & CWY)) {
    327                 setY(y() - titleBarHeight_ - borderWidth_);
    328             }
    329 
    330             wc.x = x();
    331             wc.y = y();
    332             wc.width = width();
    333             wc.height = height();
    334             wc.border_width = 1; // event->border_width
    335             wc.sibling = None;
    336             wc.stack_mode = event->detail;
    337             XCORE->configureWindow(frameWindow(), event->value_mask, &wc);
    338             fitClientArea();
    339             sendConfiguration();
    340         }
    341         else {
    342             // save current dimensions to client area
    343             clientAreaRect_.copy(this);
    344         }
    345     }
    346 
    347 #ifdef SLOT_SUPPORT
    348     if (mode_ == SLOT) {
    349         monitor()->slot()->manage();
    350     }
    351     else
    352 #endif // SLOT_SUPPORT
    353     {
    354         // If client is attached to a frame, the clientAreaRect_ has
    355         // the size of the frames client area.
    356         wc.x = clientAreaRect_.x();
    357         wc.y = clientAreaRect_.y();
    358         wc.width = clientAreaRect_.width();
    359         wc.height = clientAreaRect_.height();
    360         wc.border_width = 0;
    361         wc.sibling = None;
    362         event->value_mask |= CWBorderWidth;
    363 
    364         XCORE->configureWindow(clientWindow_, event->value_mask, &wc);
    365 
    366         illuminate();
    367     }
    368 }
    369 
    370 void Client::handlePropertyNotify(XPropertyEvent *event) {
    371 
    372     if (event->state == PropertyDelete) {
    373         return; // ignore delete properties
    374     }
    375 
    376     // WM atoms
    377     if (event->atom == Atoms::WM_PROTOCOLS) {
    378         protocols_ = XCORE->protocols(clientWindow_);
    379         return;
    380     }
    381     else if (event->atom == Atoms::MWM_HINTS) {
    382         if (XCORE->hasDecoration(clientWindow_) && !frameWindow()) {
    383             hasDecoration_ = true;
    384         }
    385         return;
    386     }
    387 
    388     // default atoms
    389     static string tmp;
    390     ostringstream oss;
    391     switch (event->atom) {
    392     case XA_WM_ICON_NAME:
    393         tmp = XCORE->atomValue(clientWindow_, XA_WM_ICON_NAME);
    394         if (tmp.length() > 0) {
    395             // update only if the icon name is != 0
    396             iconName_ = tmp + id_;
    397         }
    398         monitor()->clientBar()->illuminate();
    399         monitor()->statusBar()->illuminate();
    400         break;
    401     case XA_WM_NAME:
    402         tmp = XCORE->atomValue(clientWindow_, XA_WM_NAME);
    403         if (tmp.length() > 0) {
    404             // update only if the title is != 0
    405             setName(tmp + id_);
    406         }
    407         illuminate();
    408         monitor()->statusBar()->illuminate();
    409         break;
    410     case XA_WM_TRANSIENT_FOR:
    411         updateTransient();
    412         break;
    413     case XA_WM_NORMAL_HINTS:
    414         updateSize();
    415         oss << "git size: x=" << x() << ", y=" << y() << ", w=" <<
    416             width() << ", h=" << height();
    417         LOGDEBUG(oss.str());
    418         break;
    419     }
    420 }
    421 
    422 void Client::handleUnmapNotify(XUnmapEvent *event) {
    423 
    424     if (!isVisible_ || !event->send_event) {
    425        LOGDEBUG("client is already unvisible");
    426        return;
    427     }
    428 
    429     LOGDEBUG("handle unmap client: " + name());
    430     if (frameWindow()) {
    431         XCORE->hide(frameWindow());
    432     }
    433     isVisible_ = false;
    434     XCORE->setState(clientWindow_, WithdrawnState);
    435     Workspace *ws = this->attached();
    436     if (ws) {
    437         LOGDEBUG("going detaching client from workspace");
    438         ws->detachClient(this);
    439     }
    440 }
    441 
    442 void Client::show() {
    443     if (isDestroyed_) {
    444         return;
    445     }
    446     XCORE->showRaised(clientWindow_);
    447     if (hasFrame_) {
    448         XCORE->showRaised(frameWindow());
    449     }
    450     state_ = NormalState;
    451     KERNEL->installCursor(Cursors::NORMAL_CURSOR, clientWindow_);
    452     XCORE->setState(clientWindow_, state_);
    453     isVisible_ = true;
    454 }
    455 
    456 void Client::hide() {
    457     if (isDestroyed_) {
    458         return;
    459     }
    460     if (hasFrame_) {
    461         XCORE->hide(frameWindow());
    462     }
    463     XCORE->hide(clientWindow_);
    464     state_ = WithdrawnState;
    465     XCORE->setState(clientWindow_, state_);
    466     isVisible_ = false;
    467     LOGDEBUG("client state changed");
    468     XCORE->sync();
    469 }
    470 
    471 void Client::setMode(Client::Mode mode) {
    472 
    473     mode_ = mode;
    474     string modeStr;
    475 
    476     switch (mode_) {
    477     case MAX:
    478         modeStr = "max";
    479         break;
    480     case STICKY:
    481         modeStr = "sticky";
    482         break;
    483     case FLOAT:
    484         modeStr = "float";
    485         break;
    486 #ifdef SLOT_SUPPORT
    487     case SLOT:
    488         modeStr = "slot";
    489         break;
    490 #endif // SLOT_SUPPORT
    491     }
    492     if (transient_) {
    493         (*KERNEL->sessionSettings())["client." + className_ + "::" +
    494                 instanceName_ + ".transient-mode"] = modeStr;
    495     }
    496     else {
    497         (*KERNEL->sessionSettings())["client." + className_ + "::" +
    498                 instanceName_ + ".mode"] = modeStr;
    499     }
    500 }
    501 
    502 long Client::eventMask() const {
    503     return eventMask_;
    504 }
    505 
    506 string Client::className() const {
    507     return className_;
    508 }
    509 
    510 string Client::instanceName() const {
    511     return instanceName_;
    512 }
    513 
    514 string Client::iconName() const {
    515     return iconName_;
    516 }
    517 
    518 int Client::protocols() const {
    519     return protocols_;
    520 }
    521 
    522 // TODO: It would be a good idea to implement an align method
    523 //       for gravitation with value VH_CENTER
    524 bool Client::isCentered() const {
    525     return isCentered_;
    526 }
    527 
    528 Client::Mode Client::mode() const {
    529     return mode_;
    530 }
    531 
    532 int Client::state() const {
    533     return state_;
    534 }
    535 
    536 Window Client::window() {
    537     if (hasFrame_) {
    538         return frameWindow_;
    539     }
    540     else {
    541         return clientWindow_;
    542     }
    543 }
    544 
    545 void Client::reparent(Window parentWindow, int x, int y) {
    546     if (isDestroyed_) {
    547         return;
    548     }
    549     XCORE->reparent(clientWindow_, parentWindow, x, y);
    550     assert(parentWindow);
    551     hasFrame_ = (parentWindow == frameWindow());
    552 }
    553 
    554 void Client::createFrame() {
    555     initFrameWindow();
    556     fitClientArea();
    557     XCORE->sync();
    558 }
    559 
    560 bool Client::isFocused() {
    561 
    562     if (frame()) {
    563         return frame()->isFocused()
    564                && frame()->focused() == this;
    565     }
    566     else if (attached()) {
    567         return attached()->topClient() == this;
    568     }
    569     return 0;
    570 }
    571 
    572 void Client::illuminate() {
    573 
    574     if (!isVisible_) {
    575         return;
    576     }
    577 
    578     if (frame()) {
    579         frame()->illuminate();
    580         return;
    581     }
    582 
    583     if (!hasFrame_) {
    584         return;
    585     }
    586     LOGDEBUG("within client illuminate");
    587     XCORE->sync();
    588 
    589     illuminateBorder();
    590 
    591     bool foc = isFocused();
    592     unsigned int buttonWidth = 0;
    593 
    594     if (foc) {
    595         buttonWidth = monitor()->buttonWidth();
    596     }
    597 
    598     if (titleBarHeight_) {
    599         label_->setText(name());
    600         label_->setX(borderWidth_);
    601         unsigned int textWidth = label_->adjustWidth();
    602         unsigned long tabShine = 0;
    603         unsigned long tabShadow = 0;
    604         label_->setWidth(width() - label_->x() - borderWidth_);
    605         if (foc) {
    606             if (areButtonsVisible_) {
    607                 label_->setWidth(label_->width() - 3 * buttonWidth - 2);
    608             }
    609             tabShine = theme_->TAB_SHINE_ACTIVE_FOCUSSED;
    610             tabShadow = theme_->TAB_SHADOW_ACTIVE_FOCUSSED;
    611             label_->update(theme_->TAB_BACKGROUND_ACTIVE_FOCUSSED,
    612                            theme_->TAB_TEXT_ACTIVE_FOCUSSED,
    613                            tabShine, tabShadow, true, true);
    614         }
    615         else if (requestsFocus_) {
    616             tabShine = theme_->FOCUSREQ_SHINE;
    617             tabShadow = theme_->FOCUSREQ_SHADOW;
    618             label_->update(theme_->FOCUSREQ_BACKGROUND,
    619                            theme_->FOCUSREQ_TEXT,
    620                            tabShine, tabShadow, true, true);
    621         }
    622         else if (frame() && frame()->focused() == this) {
    623             tabShine = theme_->TAB_SHINE_ACTIVE_NORMAL;
    624             tabShadow = theme_->TAB_SHADOW_ACTIVE_NORMAL;
    625             label_->update(theme_->TAB_BACKGROUND_ACTIVE_NORMAL,
    626                            theme_->TAB_TEXT_ACTIVE_NORMAL,
    627                            tabShine, tabShadow, true, true);
    628         }
    629         else {
    630             tabShine = theme_->TAB_SHINE_INACTIVE_NORMAL;
    631             tabShadow = theme_->TAB_SHADOW_INACTIVE_NORMAL;
    632             label_->update(theme_->TAB_BACKGROUND_INACTIVE_NORMAL,
    633                            theme_->TAB_TEXT_INACTIVE_NORMAL,
    634                            tabShine, tabShadow, true, true);
    635         }
    636 
    637         if (mode_ == Client::STICKY) {
    638 
    639             Draw::drawStickyNotifier(frameWindow(), gc_, label_,
    640                     tabShine, tabShadow, textWidth);
    641         }
    642     }
    643 
    644     if (foc) {
    645         Draw::drawFloatBorderAnchors(frameWindow(), gc_, this,
    646                 theme_->FRAME_SHINE_FOCUSSED,
    647                 theme_->FRAME_SHADOW_FOCUSSED,
    648                 titleBarHeight_ + borderWidth_ + 1,
    649                 borderWidth_);
    650     }
    651 }
    652 
    653 void Client::handleButtonPress(XButtonEvent *event) {
    654 
    655     LOGDEBUG("entered ClientFrame::handleButtonPress");
    656 #ifdef SLOT_SUPPORT
    657     if (mode_ == SLOT) {
    658         monitor()->slot()->focusClient(this);
    659         return;
    660     }
    661 #endif
    662     if (attached() && !isFocused()) {
    663         attached()->focus(this);
    664         return;
    665     }
    666     else {
    667         XCORE->raise(window());
    668     }
    669 
    670     if (frame()) {
    671         return;
    672     }
    673 
    674     buttonState_ = NONE;
    675 
    676     if (event->button == Button1) {
    677 
    678         if (titleBarHeight_ && areButtonsVisible_ &&
    679                 (cursor_ == Cursors::NORMAL_CURSOR))
    680         {
    681             int xPosition = event->x;
    682             unsigned int buttonWidth = titleBarHeight_ + 1;
    683             unsigned int offsetButtonGroup = width() - borderWidth_ - 3 * buttonWidth;
    684             if ((xPosition > (int)offsetButtonGroup) &&
    685                     (xPosition < (int)(width() - borderWidth_ - 1)))
    686             {
    687                 xPosition -= offsetButtonGroup;
    688                 unsigned int buttonNum = xPosition / buttonWidth;
    689                 switch (buttonNum) {
    690                 case 0:
    691                     buttonState_ = MINCLIENT;
    692                     break;
    693                 case 1:
    694                     buttonState_ = DEMAX;
    695                     break;
    696                 case 2:
    697                     buttonState_ = CLOSE;
    698                     break;
    699                 }
    700                 illuminate();
    701                 return;
    702             }
    703         }
    704 
    705         if (monitor()->isThingMaximized()) {
    706             return;
    707         }
    708 
    709         Direction dir = SOUTH_EAST;
    710         if (cursor_ == Cursors::RESIZE_LEFT_CURSOR) {
    711             dir = LEFT;
    712         }
    713         else if (cursor_ == Cursors::RESIZE_RIGHT_CURSOR) {
    714             dir = RIGHT;
    715         }
    716         else if (cursor_ == Cursors::RESIZE_UP_CURSOR) {
    717             dir = UP;
    718         }
    719         else if (cursor_ == Cursors::RESIZE_DOWN_CURSOR) {
    720             dir = DOWN;
    721         }
    722         else if (cursor_ == Cursors::RESIZE_NORTH_WEST_CURSOR) {
    723             dir = NORTH_WEST;
    724         }
    725         else if (cursor_ == Cursors::RESIZE_NORTH_EAST_CURSOR) {
    726             dir = NORTH_EAST;
    727         }
    728         else if (cursor_ == Cursors::RESIZE_SOUTH_WEST_CURSOR) {
    729             dir = SOUTH_WEST;
    730         }
    731         else if (cursor_ == Cursors::RESIZE_SOUTH_EAST_CURSOR) {
    732             dir = SOUTH_EAST;
    733         }
    734 
    735         KERNEL->runResizeMode(this, event, dir,
    736                               cursor_ != Cursors::NORMAL_CURSOR);
    737     }
    738 }
    739 
    740 void Client::handleButtonRelease(XButtonEvent *event) {
    741 
    742     // TODO: make buttons customizable
    743     if (event->button == Button1) {
    744 
    745         if (titleBarHeight_ && (cursor_ == Cursors::NORMAL_CURSOR) &&
    746             (buttonState_ != NONE)) 
    747         {
    748             if (monitor()->isThingMaximized()) {
    749                 monitor()->toggleThingMaximization();
    750             }
    751             switch (buttonState_) {
    752             case MINCLIENT:
    753                 monitor()->detachClient();
    754                 break;
    755             case DEMAX:
    756                 attached()->toggleClientMode();
    757                 break;
    758             case CLOSE:
    759                 XCORE->kill(clientWindow_, protocols_);
    760                 break;
    761             default:
    762                 break;
    763             }
    764             buttonState_ = NONE;
    765             return;
    766         }
    767     }
    768 }
    769 
    770 Cursor Client::cursorForXY(int pointerX, int pointerY) {
    771 
    772     if (frame() || (borderWidth_ == 0))
    773     {
    774         return Cursors::NORMAL_CURSOR;
    775     }
    776 
    777     // rectangle attributes of client are used
    778     bool left = pointerX < clientAreaRect_.x();
    779     bool right = pointerX >= (int)(clientAreaRect_.x()
    780                                    + clientAreaRect_.width());
    781     bool up = pointerY < (int)(clientAreaRect_.y()
    782                                - titleBarHeight_ - 1);
    783     bool down = pointerY >= (int)(clientAreaRect_.y()
    784                                   + clientAreaRect_.height());
    785 
    786     bool tolLeft = pointerX < (int)(clientAreaRect_.x() + titleBarHeight_);
    787     bool tolRight = pointerX > (int)(clientAreaRect_.x()
    788                                      + clientAreaRect_.width()
    789                                      - titleBarHeight_ - 1);
    790     bool tolUp = pointerY < (int)(clientAreaRect_.y() + titleBarHeight_);
    791     bool tolDown = pointerY > (int)(clientAreaRect_.y()
    792                                     + clientAreaRect_.height()
    793                                     - titleBarHeight_ - 1);
    794 
    795     if ((left && up) || (left && tolUp) || (up && tolLeft)) {
    796         return Cursors::RESIZE_NORTH_WEST_CURSOR;
    797     }
    798     else if ((right && up) || (right && tolUp) || (up && tolRight)) {
    799         return Cursors::RESIZE_NORTH_EAST_CURSOR;
    800     }
    801     else if ((left && down) || (left && tolDown) ||
    802              (down && tolLeft))
    803     {
    804         return Cursors::RESIZE_SOUTH_WEST_CURSOR;
    805     }
    806     else if ((right && down) || (right && tolDown) || (down &&
    807                 tolRight))
    808     {
    809         return Cursors::RESIZE_SOUTH_EAST_CURSOR;
    810     }
    811 
    812     if (left) {
    813         return Cursors::RESIZE_LEFT_CURSOR;
    814     }
    815     else if (right) {
    816         return Cursors::RESIZE_RIGHT_CURSOR;
    817     }
    818     else if (up) {
    819         return Cursors::RESIZE_UP_CURSOR;
    820     }
    821     else if (down) {
    822         return Cursors::RESIZE_DOWN_CURSOR;
    823     }
    824 
    825     return Cursors::NORMAL_CURSOR;
    826 }
    827 
    828 Frame *Client::frame() const {
    829     return frame_;
    830 }
    831 
    832 void Client::setFrame(Frame *frame) {
    833      frame_ = frame;
    834 }
    835 
    836 Workspace *Client::attached() const {
    837     return workspace_;
    838 }
    839 
    840 void Client::setAttached(Workspace *workspace) {
    841      workspace_ = workspace;
    842 }
    843 
    844 Window Client::frameWindow() const {
    845     return frameWindow_;
    846 }
    847 
    848 Window Client::clientWindow() const {
    849     return clientWindow_;
    850 }
    851 
    852 bool Client::requestsFocus() const {
    853     return requestsFocus_;
    854 }
    855 
    856 void Client::setRequestsFocus(bool requestsFocus) {
    857     requestsFocus_ = requestsFocus;
    858 }
    859 
    860 void Client::setHooked(string hooked) {
    861     hooked_ = hooked;
    862     if (hooked_ != "") {
    863         (*KERNEL->sessionSettings())["client." + className_ + "::" +
    864                                     instanceName_ + ".hooked"] = hooked_;
    865     }
    866     else {
    867         Util::remove(KERNEL->sessionSettings(),
    868                      "client." + className_ + "::" + instanceName_ + ".hooked");
    869     }
    870 }
    871 
    872 string Client::hooked() const {
    873     return hooked_;
    874 }
    875 
    876 void Client::setDestroyed(bool isDestroyed) {
    877     isDestroyed_ = isDestroyed;
    878 }
    879 
    880 bool Client::isDestroyed() const {
    881     return isDestroyed_;
    882 }