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