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 }