wmi

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

frame.cpp (14200B)


      1 // Copyright (c) 2003 - 2009 Anselm R Garbe <anselm@garbe.us>
      2 // See LICENSE for license details.
      3 
      4 extern "C" {
      5 #include <assert.h>
      6 }
      7 
      8 #include <sstream>
      9 
     10 #include "frame.h"
     11 
     12 #include "client.h"
     13 #include "cursors.h"
     14 #include "draw.h"
     15 #include "frame.h"
     16 #include "kernel.h"
     17 #include "label.h"
     18 #include "logger.h"
     19 #include "monitor.h"
     20 #include "split.h"
     21 #include "theme.h"
     22 #include "tree.h"
     23 #include "util.h"
     24 #include "workspace.h"
     25 #include "xcore.h"
     26 
     27 Frame::Frame(Workspace *workspace, Rectangle *rect)
     28     : Thing(workspace->attached(), rect, Thing::FRAME),
     29       Container<Workspace, LClient, LClient::iterator, Client>(workspace)
     30 {
     31     ostringstream oss;
     32     oss << "<" << workspace->nextFrameId() << ">";
     33     setName(oss.str());
     34     isTiled_ = Util::get(KERNEL->commonSettings(), "frame.mode") == "tiled";
     35 }
     36 
     37 Frame::~Frame() {
     38 }
     39 
     40 bool Frame::isFocused() {
     41     bool result = attached() && attached()->focusedFrame() == this;
     42     if (focused()) {
     43         result = result && (focused() == attached()->topClient());
     44     }
     45     return result;
     46 }
     47 
     48 void Frame::focus(Client *client) {
     49 
     50     Container<Workspace, LClient, LClient::iterator, Client>
     51           ::focus(client);
     52     XCORE->raise(client->clientWindow());
     53 }
     54 
     55 void Frame::illuminate() {
     56 
     57     if (!isVisible()) {
     58         return;
     59     }
     60 
     61     illuminateBorder();
     62 
     63     bool foc = this->isFocused();
     64 
     65     if (titleBarHeight_) {
     66 
     67         unsigned int buttonWidth = 0;
     68         unsigned int labelsWidth = width() - 2 * borderWidth_;
     69         unsigned int offsetX = borderWidth_;
     70         if (foc && areButtonsVisible_) {
     71             buttonWidth = monitor()->buttonWidth();
     72             labelsWidth -= (3 * buttonWidth) - 3;
     73         }
     74 
     75         unsigned int labelWidth = size() ? labelsWidth / size() : labelsWidth;
     76 
     77         unsigned int i = 0;
     78         label_->setWidth(labelWidth);
     79         for (LClient::iterator it = begin(); it != end(); ) {
     80 
     81             Client *client = *it;
     82             it++;
     83 
     84             label_->setText(client->name());
     85             label_->setX(offsetX + i * labelWidth);
     86             if (it == end()) {
     87                 // FIX for right button panel irretations
     88                 label_->setWidth(
     89                         width() - label_->x() - 3 * buttonWidth -
     90                         ((foc && areButtonsVisible_) ? 3 + borderWidth_ : borderWidth_));
     91             }
     92             i++;
     93             if (foc) { // FOCUSSED
     94                 if (client == focused()) {
     95                     label_->update(theme_->TAB_BACKGROUND_ACTIVE_FOCUSSED,
     96                                    theme_->TAB_TEXT_ACTIVE_FOCUSSED,
     97                                    theme_->TAB_SHINE_ACTIVE_FOCUSSED,
     98                                    theme_->TAB_SHADOW_ACTIVE_FOCUSSED,
     99                                    true, true);
    100                 }
    101                 else if (client->requestsFocus()) {
    102                     label_->update(theme_->FOCUSREQ_BACKGROUND,
    103                                    theme_->FOCUSREQ_TEXT,
    104                                    theme_->FOCUSREQ_SHINE,
    105                                    theme_->FOCUSREQ_SHADOW,
    106                                    true, true);
    107                 }
    108                 else {
    109                     label_->update(theme_->TAB_BACKGROUND_INACTIVE_FOCUSSED,
    110                                    theme_->TAB_TEXT_INACTIVE_FOCUSSED,
    111                                    theme_->TAB_SHINE_INACTIVE_FOCUSSED,
    112                                    theme_->TAB_SHADOW_INACTIVE_FOCUSSED,
    113                                    true, true);
    114                 }
    115             }
    116             else { // NORMAL
    117                 if (client == focused()) {
    118                     label_->update(theme_->TAB_BACKGROUND_ACTIVE_NORMAL,
    119                                    theme_->TAB_TEXT_ACTIVE_NORMAL,
    120                                    theme_->TAB_SHINE_ACTIVE_NORMAL,
    121                                    theme_->TAB_SHADOW_ACTIVE_NORMAL,
    122                                    true, true);
    123                 }
    124                 else if (client->requestsFocus()) {
    125                     label_->update(theme_->FOCUSREQ_BACKGROUND,
    126                                    theme_->FOCUSREQ_TEXT,
    127                                    theme_->FOCUSREQ_SHINE,
    128                                    theme_->FOCUSREQ_SHADOW,
    129                                    true, true);
    130                 }
    131                 else {
    132                     label_->update(theme_->TAB_BACKGROUND_INACTIVE_NORMAL,
    133                                    theme_->TAB_TEXT_INACTIVE_NORMAL,
    134                                    theme_->TAB_SHINE_INACTIVE_NORMAL,
    135                                    theme_->TAB_SHADOW_INACTIVE_NORMAL,
    136                                    true, true);
    137                 }
    138             }
    139         }
    140         if (!size()) {
    141             label_->setText("<empty>" + name());
    142             if (foc) { // FOCUSSED
    143                 label_->update(theme_->TAB_BACKGROUND_ACTIVE_FOCUSSED,
    144                         theme_->TAB_TEXT_ACTIVE_FOCUSSED,
    145                         theme_->TAB_SHINE_ACTIVE_FOCUSSED,
    146                         theme_->TAB_SHADOW_ACTIVE_FOCUSSED,
    147                         true, true);
    148             }
    149             else { // NORMAL
    150                 label_->update(theme_->TAB_BACKGROUND_ACTIVE_NORMAL,
    151                         theme_->TAB_TEXT_ACTIVE_NORMAL,
    152                         theme_->TAB_SHINE_ACTIVE_NORMAL,
    153                         theme_->TAB_SHADOW_ACTIVE_NORMAL,
    154                         true, true);
    155             }
    156         }
    157     }
    158     if (isTiled_) {
    159         unsigned shine, shadow;
    160         for (LClient::iterator it = begin(); it != end(); it++) {
    161             Client *client = *it;
    162             if (foc && client == focused()) {
    163                 shine = theme_->TILED_SHINE_FOCUSSED;
    164                 shadow = theme_->TILED_SHADOW_FOCUSSED;
    165             }
    166             else {
    167                 shine = theme_->TILED_SHINE_NORMAL;
    168                 shadow = theme_->TILED_SHADOW_NORMAL;
    169             }
    170             Rectangle rect;
    171             rect.setX(client->x() - 1);
    172             rect.setY(client->y() - 1);
    173             rect.setWidth(client->width() + 2);
    174             rect.setHeight(client->height() + 2);
    175             Draw::drawRectBorder(frameWindow_, gc_, &rect, shine, shadow);
    176         }
    177     }
    178 }
    179 
    180 void Frame::resize() {
    181 
    182     label_->setY(borderWidth_);
    183     XCORE->clearWindow(window());
    184     XCORE->moveResize(window(), this);
    185 
    186     fitClientArea();
    187     if (isTiled_ && size() > 1) {
    188         unsigned int colWidth =
    189             Util::strToUInt(Util::get(KERNEL->commonSettings(), "frame.colwidth"));
    190 
    191         colWidth = (clientAreaRect_.width() * colWidth) / 100;
    192         unsigned int stackHeight = clientAreaRect_.height() / (size() - 1);
    193         unsigned int i = 0;
    194 
    195         for (LClient::iterator it = begin(); it != end(); it++) {
    196             Client *client = *it;
    197             if (it == begin()) {
    198                 // left column
    199                 client->copy(&clientAreaRect_);
    200                 client->setX(clientAreaRect_.x() + 1);
    201                 client->setY(clientAreaRect_.y() + 1);
    202                 client->setWidth(colWidth - 2);
    203                 client->setHeight(clientAreaRect_.height() - 2);
    204             }
    205             else {
    206                 // right column
    207                 client->setX(clientAreaRect_.x() + colWidth + 1);
    208                 client->setY(i * stackHeight + clientAreaRect_.y() + 1);
    209                 client->setHeight(stackHeight - 2);
    210                 client->setWidth(clientAreaRect_.width() - colWidth - 2);
    211                 i++;
    212             }
    213             client->resize();
    214         }
    215     }
    216     else {
    217         for (LClient::iterator it = begin(); it != end(); it++) {
    218             Client *client = *it;
    219             matchClientSize(client);
    220         }
    221     }
    222     illuminate();
    223 }
    224 
    225 void Frame::matchClientSize(Client *client)
    226 {
    227     client->copy(&clientAreaRect_);
    228     client->resize();
    229 }
    230 
    231 void Frame::attach(Client *client) {
    232 
    233     if (client->frame() == this) {
    234         LOGWARN("frame already attached.");
    235         return;
    236     }
    237     Container<Workspace, LClient, LClient::iterator, Client>
    238         ::attach(client);
    239     client->setFrame(this);
    240     client->prevRectangle()->copy(client);
    241     client->reparent(window(), clientAreaRect_.x(), clientAreaRect_.y());
    242     XCORE->sync();
    243     if (isVisible()) {
    244         client->show();
    245     }
    246     childs()->remove(client);
    247     childs()->push_front(client);
    248     resize();
    249     LOGDEBUG("attached client to frame");
    250 }
    251 
    252 Client *Frame::detach(Client *client) {
    253 
    254     assert(size() > 0);
    255     XCORE->sync();
    256     LOGDEBUG("detaching clientframe");
    257     Client *next = Container<Workspace, LClient, LClient::iterator, Client>
    258                     ::detach(client);
    259     if (client->isVisible()) {
    260         client->hide();
    261     }
    262     if (size() > 0) {
    263         assert(next);
    264     }
    265     client->reparent(monitor()->rootWindow(), client->x(), client->y());
    266     client->copy(client->prevRectangle());
    267     client->setFrame(0);
    268     if (next) {
    269         resize();
    270     }
    271     return next;
    272 }
    273 
    274 void Frame::handleButtonPress(XButtonEvent *event) {
    275 
    276     // TODO: make buttons customizable
    277     if (event->button == Button1) {
    278 
    279         if (!isFocused()) {
    280             attached()->focus(focused());
    281             return;
    282         }
    283         else {
    284             XCORE->raise(window());
    285         }
    286 
    287         buttonState_ = NONE;
    288         if (titleBarHeight_ && (cursor_ == Cursors::NORMAL_CURSOR) && size()) {
    289             LOGDEBUG("normal cursor / switching client");
    290             int xPosition = event->x;
    291             unsigned int buttonWidth = titleBarHeight_ + 1;
    292             if (areButtonsVisible_) {
    293                 unsigned int offsetButtonGroup = width() - borderWidth_ - 3 * buttonWidth;
    294                 if ((xPosition > (int)offsetButtonGroup) &&
    295                         (xPosition < (int)(width() - borderWidth_ - 1)))
    296                 {
    297                     xPosition -= offsetButtonGroup;
    298                     unsigned int buttonNum = xPosition / buttonWidth;
    299                     switch (buttonNum) {
    300                     case 0:
    301                         buttonState_ = MINCLIENT;
    302                         break;
    303                     case 1:
    304                         buttonState_ = DEMAX;
    305                         break;
    306                     case 2:
    307                         buttonState_ = CLOSE;
    308                         break;
    309                     }
    310                     illuminate();
    311                     return;
    312                 }
    313             }
    314 
    315             // handle label click
    316             xPosition -= borderWidth_;
    317             unsigned int labelsWidth = width() - 2 * borderWidth_
    318                 - (areButtonsVisible_ ? (3 * buttonWidth) - 2 : 0);
    319             unsigned int labelWidth = labelsWidth / size();
    320 
    321             unsigned int clientNum = xPosition / labelWidth;
    322             unsigned int i = 0;
    323 
    324             for (LClient::iterator it = begin(); it != end(); it++) {
    325 
    326                 if (i == clientNum) {
    327                     attached()->focus(*it);
    328                     return;
    329                 }
    330                 i++;
    331             }
    332         }
    333 
    334         if (monitor()->isThingMaximized()) {
    335             return;
    336         }
    337 
    338         Direction dir = DOWN;
    339         if (cursor_ == Cursors::RESIZE_LEFT_CURSOR) {
    340             dir = LEFT;
    341         }
    342         else if (cursor_ == Cursors::RESIZE_RIGHT_CURSOR) {
    343             dir = RIGHT;
    344         }
    345         else if (cursor_ == Cursors::RESIZE_UP_CURSOR) {
    346             dir = UP;
    347         }
    348         else if (cursor_ == Cursors::RESIZE_DOWN_CURSOR) {
    349             dir = DOWN;
    350         }
    351 
    352         // Patch applied by Christof Musik
    353         if (cursor_ != Cursors::NORMAL_CURSOR) {
    354 
    355             if (Split::neighbor(attached()->root(), tree_, dir)) {
    356                 Kernel::instance()->runResizeMode(this, event, dir);
    357             }
    358             else if (event->button == Button4) {
    359                 monitor()->focused()->cycleClientPrev();
    360             } else if (event->button == Button5) {
    361                 monitor()->focused()->cycleClientNext();
    362             }
    363         }
    364     }
    365 }
    366 
    367 void Frame::handleButtonRelease(XButtonEvent *event) {
    368 
    369     if (titleBarHeight_ && (event->button == Button1))
    370     {
    371         if ((buttonState_ != NONE) && monitor()->isThingMaximized()) {
    372             monitor()->toggleThingMaximization();
    373         }
    374         InvertButton state = buttonState_;
    375         buttonState_ = NONE;
    376         switch (state) {
    377         case MINCLIENT:
    378             monitor()->detachClient();
    379             break;
    380         case DEMAX:
    381             attached()->toggleClientMode();
    382             break;
    383         case CLOSE:
    384             XCORE->kill(focused()->clientWindow(), focused()->protocols());
    385             break;
    386         case NONE:
    387             break;
    388         }
    389     }
    390  
    391 }
    392 
    393 Cursor Frame::cursorForXY(int pointerX, int pointerY) {
    394 
    395     if (borderWidth_ == 0) {
    396         return Cursors::NORMAL_CURSOR;
    397     }
    398     bool left = pointerX < clientAreaRect_.x();
    399     bool right = pointerX >=
    400         (int)(clientAreaRect_.x() + clientAreaRect_.width());
    401     bool up;
    402     if (titleBarHeight_) {
    403         up = pointerY <
    404             (int)(clientAreaRect_.y() - titleBarHeight_ - 1);
    405     }
    406     else {
    407         up = pointerY < clientAreaRect_.y();
    408     }
    409     bool down = pointerY >=
    410         (int)(clientAreaRect_.y() + clientAreaRect_.height());
    411 
    412     if (left && Split::neighbor(attached()->root(), tree_, LEFT)) {
    413         return Cursors::RESIZE_LEFT_CURSOR;
    414     }
    415     else if (right && Split::neighbor(attached()->root(), tree_, RIGHT)) {
    416         return Cursors::RESIZE_RIGHT_CURSOR;
    417     }
    418     else if (up && Split::neighbor(attached()->root(), tree_, UP)) {
    419         return Cursors::RESIZE_UP_CURSOR;
    420     }
    421     else if (down && Split::neighbor(attached()->root(), tree_, DOWN)) {
    422         return Cursors::RESIZE_DOWN_CURSOR;
    423     }
    424 
    425     return Cursors::NORMAL_CURSOR;
    426 }
    427 
    428 Tree *Frame::tree() const {
    429     return tree_;
    430 }
    431 
    432 void Frame::setTree(Tree *t) {
    433     tree_ = t;
    434 }
    435 
    436 Window Frame::window() {
    437     return frameWindow_;
    438 }
    439 
    440 void Frame::toggleTiled() {
    441     isTiled_ = !isTiled_;
    442     resize();
    443 }
    444 
    445 void Frame::zoomClient() {
    446     if (focused() && size() > 1) {
    447         if (focused() == *begin()) {
    448             attached()->focus(next());
    449         }
    450         Client *client = focused();
    451         childs()->remove(client);
    452         childs()->push_front(client);
    453         resize();
    454     }
    455 }
    456