wmi

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

slot.cpp (12112B)


      1 // Copyright (c) 2003 - 2009 Anselm R Garbe <anselm@garbe.us>
      2 // See LICENSE for license details.
      3 
      4 #include "slot.h"
      5 
      6 #ifdef SLOT_SUPPORT
      7 
      8 #include <map>
      9 #include <string>
     10 #include <sstream>
     11 
     12 #include "binder.h"
     13 #include "client.h"
     14 #include "cursors.h"
     15 #include "draw.h"
     16 #include "kernel.h"
     17 #include "label.h"
     18 #include "logger.h"
     19 #include "monitor.h"
     20 #include "theme.h"
     21 #include "util.h"
     22 #include "workspace.h"
     23 #include "xcore.h"
     24 #include "xfont.h"
     25 
     26 /// slot tab
     27 Tab::Tab(const string name) {
     28     name_ = name;
     29     focused_ = 0;
     30 }
     31 
     32 Tab::~Tab() {
     33 }
     34 
     35 string Tab::name() const {
     36     return name_;
     37 }
     38 
     39 LClient *Tab::clients() {
     40     return &clients_;
     41 }
     42 
     43 void Tab::addClient(Client *client) {
     44     focused_ = client;
     45     clients_.push_back(client);
     46 }
     47 
     48 void Tab::removeClient(Client *client) {
     49     clients_.remove(client);
     50     if (focused_ == client) {
     51         if (clients_.size()) {
     52             focused_ = clients_.front();
     53         }
     54         else {
     55             focused_ = 0;
     56         }
     57     }
     58 }
     59 
     60 bool Tab::isVisible() const {
     61     return isVisible_;
     62 }
     63 
     64 void Tab::show() {
     65     isVisible_ = true;
     66     for (LClient::iterator it = clients_.begin();
     67             it != clients_.end(); it++)
     68     {
     69         Client *client = *it;
     70         client->show();
     71     }
     72 }
     73 
     74 void Tab::hide() {
     75     isVisible_ = false;
     76     for (LClient::iterator it = clients_.begin();
     77             it != clients_.end(); it++)
     78     {
     79         Client *client = *it;
     80         client->hide();
     81     }
     82 }
     83 
     84 Client *Tab::focused() const {
     85     return focused_;
     86 }
     87 
     88 void Tab::focus(Client *client) {
     89     focused_ = client;
     90 }
     91 
     92 /// Slot implementation
     93 
     94 Slot::Slot(Monitor *monitor, Rectangle *rect, Direction align)
     95     : Widget(monitor, rect),
     96       Container<Monitor, LTab, LTab::iterator, Tab>(monitor)
     97 {
     98     align_ = align;
     99     theme_ = this->monitor()->theme();
    100     isGrabFocus_ = false;
    101 
    102     isSolid_ = (Util::get(KERNEL->commonSettings(), "slot.style") == "solid");
    103     initTabs();
    104 
    105     label_ = new Label(this->monitor(), window(), Label::CENTER, gc());
    106     label_->setX(1);
    107     label_->setY(1);
    108     label_->setWidth(width() - 2);
    109     label_->setHeight(this->monitor()->titleBarHeight());
    110 }
    111 
    112 Slot::~Slot() {
    113 }
    114 
    115 void Slot::initTabs() {
    116 
    117     string tabs = Util::get(KERNEL->commonSettings(), "slot.tabs");
    118 
    119     string name = "";
    120     for (string::iterator it = tabs.begin(); it != tabs.end(); ) {
    121 
    122         char c = *it;
    123         it++;
    124         bool isEndReached = it == tabs.end();
    125 
    126         if ((c == ',') || isEndReached) {
    127             if (isEndReached) {
    128                 name += c;
    129             }
    130             if (name != "") {
    131                 attach(new Tab(name));
    132                 name = "";
    133             }
    134         }
    135         else {
    136             name += c;
    137         }
    138     }
    139 
    140     if (!size()) {
    141         attach(new Tab("default"));
    142     }
    143 }
    144 
    145 void Slot::show(string tabName) {
    146 
    147     if (isVisible()
    148         && tabName == this->tabName()
    149         && hasClients())
    150     {
    151         illuminate();
    152         return;
    153     }
    154     isVisible_ = true;
    155     for (LTab::iterator it = begin(); it != end(); it++) {
    156         Tab *tab = *it;
    157         tab->hide();
    158         if (tab->name() == tabName) {
    159             focus(tab);
    160         }
    161     }
    162     focused()->show();
    163     XCORE->show(window());
    164 }
    165 
    166 void Slot::hide() {
    167     isVisible_ = false;
    168     focused()->hide();
    169     XCORE->hide(window());
    170     monitor()->matchWorkspace(monitor()->focused(), align_);
    171 }
    172 
    173 Direction Slot::alignment() const {
    174     return align_;
    175 }
    176 
    177 void Slot::illuminate() {
    178 
    179     if (!isVisible() || width() == 1) {
    180         return;
    181     }
    182 
    183     if (isSolid_) {
    184         Rectangle rect(*this);
    185         rect.setX(0);
    186         rect.setY(0);
    187         LOGDEBUG("drawing solid background");
    188         // draw solid background
    189         XCORE->setForeground(gc(), theme_->BAR_BACKGROUND);
    190         XCORE->fillRectangle(window(), gc(), &rect);
    191         Draw::drawRectBorder(window(), gc(), &rect,
    192                              theme_->BAR_SHINE, theme_->BAR_BACKGROUND);
    193     }
    194     else {
    195         XCORE->clearWindow(window());
    196     }
    197 
    198     label_->setWidth(width() - 2);
    199     unsigned int offsetY = 1;
    200     unsigned int i = 0;
    201     for (LTab::iterator it = begin(); it != end(); it++) {
    202         Tab *tab = *it;
    203         label_->setY(offsetY + (i * label_->height()));
    204         label_->setText(tab->name());
    205         if (tab == focused()) {
    206             label_->update(theme_->LABEL_BACKGROUND_FOCUSSED,
    207                        theme_->LABEL_TEXT_FOCUSSED,
    208                        theme_->LABEL_SHINE_FOCUSSED,
    209                        theme_->LABEL_SHADOW_FOCUSSED,
    210                        true, true);
    211         }
    212         else {
    213             label_->update(theme_->LABEL_BACKGROUND_NORMAL,
    214                            theme_->LABEL_TEXT_NORMAL,
    215                            theme_->LABEL_SHINE_NORMAL,
    216                            theme_->LABEL_SHADOW_NORMAL,
    217                            true, true);
    218         }
    219         i++;
    220     }
    221 
    222     LClient *clients = focused()->clients();
    223     for (LClient::iterator it = clients->begin();
    224             it != clients->end(); it++)
    225     {
    226         Client *client = *it;
    227         Rectangle rect(*client);
    228         rect.setX(rect.x() - 1);
    229         rect.setY(rect.y() - 1);
    230         rect.setWidth(rect.width() + 2);
    231         rect.setHeight(rect.height() + 2);
    232 
    233         if (client == focused()->focused()) {
    234             Draw::drawRectBorder(window(), gc(), &rect,
    235                                  theme_->TAB_SHINE_ACTIVE_FOCUSSED,
    236                                  theme_->TAB_SHADOW_ACTIVE_FOCUSSED);
    237         }
    238         else {
    239             Draw::drawRectBorder(window(), gc(), &rect,
    240                                  theme_->TAB_SHINE_ACTIVE_NORMAL,
    241                                  theme_->TAB_SHADOW_ACTIVE_NORMAL);
    242         }
    243     }
    244 }
    245 
    246 bool Slot::hasClients() {
    247 
    248     for (LTab::iterator it = begin(); it != end(); it++) {
    249         Tab *tab = *it;
    250         if (tab->clients()->size()) {
    251             return true;
    252         }
    253     }
    254     return false;
    255 }
    256 
    257 void Slot::manage() {
    258 
    259     if (!isVisible()) {
    260         return;
    261     }
    262 
    263     static bool isSlotOverlap =
    264         Util::get(KERNEL->commonSettings(), "slot.mode") == "overlap";
    265     unsigned int cHeight = 0;
    266     unsigned int maxWidth = 1;
    267     LClient *clients = focused()->clients();
    268     if (!clients->size() && hasClients()) {
    269         maxWidth = width();
    270     }
    271     for (LClient::iterator it = clients->begin();
    272             it != clients->end(); it++)
    273     {
    274         Client *client = *it;
    275         cHeight += client->height();
    276         if (maxWidth < client->width()) {
    277             maxWidth = client->width() + 2;
    278         }
    279     }
    280 
    281     if (align_ == RIGHT) {
    282         setX(monitor()->width() - maxWidth);
    283     }
    284     setWidth(maxWidth);
    285 
    286     // apps are centered
    287     unsigned int tabPagerHeight = (size() * label_->height()) + 3;
    288     int offsetY = tabPagerHeight;
    289 
    290     for (LClient::iterator it = clients->begin();
    291             it != clients->end(); it++)
    292     {
    293         Client *client = *it;
    294         client->setY(offsetY);
    295         client->setX((width() - client->width()) / 2);
    296         client->resize();
    297         offsetY += client->height() + 2;
    298     }
    299 
    300     if (isSolid_ && !isSlotOverlap) {
    301         setHeight(monitor()->focused()->height());
    302     }
    303     else {
    304         setHeight(offsetY);
    305     }
    306     monitor()->matchWorkspace(monitor()->focused(), align_);
    307     XCORE->moveResize(window(), this);
    308     illuminate();
    309 }
    310 
    311 Tab *Slot::tabForName(string name) {
    312 
    313     for (LTab::iterator it = begin(); it != end(); it++) {
    314         Tab *tab = *it;
    315         if (tab->name() == name) {
    316             return tab;
    317         }
    318     }
    319 
    320     return 0;
    321 }
    322 
    323 void Slot::attachClient(Client *client) {
    324 
    325     if (width() < client->width()) {
    326         setWidth(client->width());
    327     }
    328 
    329     Binder::instance()->ungrabButtons(client->clientWindow());
    330     Binder::instance()->grabButtons(client->clientWindow(), AnyModifier);
    331 
    332     if (client->hooked() != "") {
    333         Tab *tab = tabForName(client->hooked());
    334         if (tab && (tab != focused())) {
    335             focused()->hide();
    336             focus(tab);
    337             tab->show();
    338         }
    339     }
    340 
    341     focused()->addClient(client);
    342     client->reparent(window(), 0, 0);
    343 
    344     if (isVisible()) {
    345         client->show();
    346     }
    347     manage();
    348 }
    349 
    350 void Slot::detachClient(Client *client) {
    351 
    352     for (LTab::iterator it = begin(); it != end(); it++) {
    353         Tab *tab = *it;
    354         LClient *clients = tab->clients();
    355         bool found = false;
    356         for (LClient::iterator cit = clients->begin();
    357              cit != clients->end(); cit++)
    358         {
    359             found = (client == *cit);
    360             if (found) {
    361                 break;
    362             }
    363         }
    364         if (found) {
    365             tab->removeClient(client);
    366             break;
    367         }
    368     }
    369     if (!client->isDestroyed()) {
    370         if (client->isVisible()) {
    371             client->hide();
    372         }
    373         client->reparent(monitor()->rootWindow(), 0, 0);
    374     }
    375     manage();
    376 }
    377 
    378 void Slot::handleButtonPress(XButtonEvent *event) {
    379 
    380     if (event->button == Button1) {
    381         unsigned int tabPagerHeight = (size() * label_->height()) + 3;
    382 
    383         XCORE->raise(window());
    384         if (event->y < (int)tabPagerHeight) {
    385             unsigned int selTab = event->y / label_->height();
    386             ostringstream oss;
    387             oss << "select tab #" << selTab << " of " << size() << " tabs ";
    388             LOGDEBUG(oss.str());
    389             unsigned int i = 0;
    390             for (LTab::iterator it = begin(); it != end(); it++) {
    391                 if (selTab == i) {
    392                     if (focused() != *it) {
    393                         focused()->hide();
    394                         focus(*it);
    395                         focused()->show();
    396                         manage();
    397                     }
    398                     return;
    399                 }
    400                 i++;
    401             }
    402         }
    403     }
    404     else if (event->button == Button4) {
    405         monitor()->cycleSlotTabPrev();
    406     }
    407     else if (event->button == Button5) {
    408         monitor()->cycleSlotTabNext();
    409     }
    410 }
    411 
    412 void Slot::handleMotionNotify(XMotionEvent *event) {
    413 }
    414 
    415 string Slot::tabName() {
    416     return focused()->name();
    417 }
    418 
    419 bool Slot::isGrabFocus() const {
    420     return isGrabFocus_;
    421 }
    422 
    423 void Slot::setGrabFocus(bool grabFocus) {
    424     Client *client = focused()->focused();
    425     if (isGrabFocus_ && !grabFocus) {
    426         // workspace grabs back the focus
    427         if (client) {
    428             Binder::instance()->ungrabButtons(client->clientWindow());
    429             Binder::instance()->grabButtons(client->clientWindow(), AnyModifier);
    430         }
    431     }
    432     isGrabFocus_ = grabFocus;
    433 }
    434 
    435 void Slot::focusClient(Client *client) {
    436 
    437     for (LTab::iterator it = begin(); it != end(); it++) {
    438         Tab *tab = *it;
    439         LClient *clients = tab->clients();
    440         for (LClient::iterator cit = clients->begin();
    441                 cit != clients->end(); cit++)
    442         {
    443             if (*cit == client) {
    444                 if (tab != focused()) {
    445                     focused()->hide();
    446                     focus(tab);
    447                     tab->show();
    448                     manage();
    449                 }
    450                 Client *old = focused()->focused();
    451                 if (old != client) {
    452                     Binder::instance()->ungrabButtons(old->clientWindow());
    453                     Binder::instance()->grabButtons(old->clientWindow(),
    454                                                     AnyModifier);
    455                 }
    456                 Client *tc = monitor()->focused()->topClient();
    457                 isGrabFocus_ = true;
    458                 if (tc) {
    459                     // unfocus topClient() of workspace, because the
    460                     // slot grabs focus control now
    461                     Binder::instance()->ungrabButtons(tc->clientWindow());
    462                     Binder::instance()->grabButtons(tc->clientWindow(),
    463                                                     AnyModifier);
    464                     monitor()->focused()->illuminate();
    465                 }
    466                 focused()->focus(client);
    467                 Binder::instance()->ungrabButtons(client->clientWindow());
    468                 XCORE->setInputFocus(client->clientWindow());
    469                 illuminate();
    470                 return;
    471             }
    472         }
    473     }
    474 }
    475 #endif // SLOT_SUPPORT