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