00001
00002
00003 #ifdef HAVE_CONFIG_H
00004 # include "../config.h"
00005 #endif
00006
00007 #include "client.hh"
00008 #include "frame.hh"
00009 #include "screen.hh"
00010 #include "openbox.hh"
00011 #include "bindings.hh"
00012 #include "otk/display.hh"
00013 #include "otk/property.hh"
00014
00015 extern "C" {
00016 #include <X11/Xlib.h>
00017 #include <X11/Xutil.h>
00018 #include <X11/Xatom.h>
00019
00020 #include <assert.h>
00021
00022 #include "gettext.h"
00023 #define _(str) gettext(str)
00024 }
00025
00026 #include <algorithm>
00027
00028 namespace ob {
00029
00030 Client::Client(int screen, Window window)
00031 : otk::EventHandler(),
00032 WidgetBase(WidgetBase::Type_Client),
00033 frame(0), _screen(screen), _window(window)
00034 {
00035 assert(screen >= 0);
00036 assert(window);
00037
00038 ignore_unmaps = 0;
00039
00040
00041
00042
00043 _wmstate = NormalState;
00044 _focused = false;
00045 _transient_for = 0;
00046 _layer = Layer_Normal;
00047 _urgent = false;
00048 _positioned = false;
00049 _disabled_decorations = 0;
00050 _modal_child = 0;
00051 _group = None;
00052 _desktop = 0;
00053
00054 getArea();
00055 getDesktop();
00056 getState();
00057 getShaped();
00058
00059 updateTransientFor();
00060 getMwmHints();
00061 getType();
00062
00063 updateProtocols();
00064
00065 getGravity();
00066 updateNormalHints();
00067
00068
00069
00070
00071 setupDecorAndFunctions();
00072
00073
00074
00075
00076 updateWMHints(openbox->state() != Openbox::State_Starting);
00077 updateTitle();
00078 updateIconTitle();
00079 updateClass();
00080 updateStrut();
00081
00082
00083 if ( _type == Type_Desktop)
00084 _desktop = 0xffffffff;
00085
00086
00087
00088 otk::Property::set(_window, otk::Property::atoms.net_wm_desktop,
00089 otk::Property::atoms.cardinal, (unsigned)_desktop);
00090
00091 changeState();
00092 }
00093
00094
00095 Client::~Client()
00096 {
00097
00098 while (!_transients.empty()) {
00099 _transients.front()->_transient_for = 0;
00100 _transients.pop_front();
00101 }
00102
00103
00104 if (_transient_for)
00105 _transient_for->_transients.remove(this);
00106
00107 if (openbox->state() != Openbox::State_Exiting) {
00108
00109 otk::Property::erase(_window, otk::Property::atoms.net_wm_desktop);
00110 otk::Property::erase(_window, otk::Property::atoms.net_wm_state);
00111 } else {
00112
00113
00114 if (_iconic)
00115 XMapWindow(**otk::display, _window);
00116 }
00117 }
00118
00119
00120 bool Client::validate() const
00121 {
00122 XSync(**otk::display, false);
00123
00124 XEvent e;
00125 if (XCheckTypedWindowEvent(**otk::display, _window, DestroyNotify, &e) ||
00126 XCheckTypedWindowEvent(**otk::display, _window, UnmapNotify, &e)) {
00127 XPutBackEvent(**otk::display, &e);
00128 return false;
00129 }
00130
00131 return true;
00132 }
00133
00134
00135 void Client::getGravity()
00136 {
00137 XWindowAttributes wattrib;
00138 Status ret;
00139
00140 ret = XGetWindowAttributes(**otk::display, _window, &wattrib);
00141 assert(ret != BadWindow);
00142 _gravity = wattrib.win_gravity;
00143 }
00144
00145
00146 void Client::getDesktop()
00147 {
00148
00149 _desktop = openbox->screen(_screen)->desktop();
00150
00151 if (otk::Property::get(_window, otk::Property::atoms.net_wm_desktop,
00152 otk::Property::atoms.cardinal,
00153 (long unsigned*)&_desktop)) {
00154 #ifdef DEBUG
00155
00156 #endif
00157 }
00158 }
00159
00160
00161 void Client::getType()
00162 {
00163 _type = (WindowType) -1;
00164
00165 unsigned long *val;
00166 unsigned long num = (unsigned) -1;
00167 if (otk::Property::get(_window, otk::Property::atoms.net_wm_window_type,
00168 otk::Property::atoms.atom, &num, &val)) {
00169
00170 for (unsigned long i = 0; i < num; ++i) {
00171 if (val[i] == otk::Property::atoms.net_wm_window_type_desktop)
00172 _type = Type_Desktop;
00173 else if (val[i] == otk::Property::atoms.net_wm_window_type_dock)
00174 _type = Type_Dock;
00175 else if (val[i] == otk::Property::atoms.net_wm_window_type_toolbar)
00176 _type = Type_Toolbar;
00177 else if (val[i] == otk::Property::atoms.net_wm_window_type_menu)
00178 _type = Type_Menu;
00179 else if (val[i] == otk::Property::atoms.net_wm_window_type_utility)
00180 _type = Type_Utility;
00181 else if (val[i] == otk::Property::atoms.net_wm_window_type_splash)
00182 _type = Type_Splash;
00183 else if (val[i] == otk::Property::atoms.net_wm_window_type_dialog)
00184 _type = Type_Dialog;
00185 else if (val[i] == otk::Property::atoms.net_wm_window_type_normal)
00186 _type = Type_Normal;
00187 else if (val[i] == otk::Property::atoms.kde_net_wm_window_type_override){
00188
00189 _mwmhints.flags &= MwmFlag_Functions | MwmFlag_Decorations;
00190 _mwmhints.decorations = 0;
00191 _mwmhints.functions = 0;
00192 }
00193 if (_type != (WindowType) -1)
00194 break;
00195 }
00196 delete val;
00197 }
00198
00199 if (_type == (WindowType) -1) {
00200
00201
00202
00203
00204 if (_transient_for)
00205 _type = Type_Dialog;
00206 else
00207 _type = Type_Normal;
00208 }
00209 }
00210
00211
00212 void Client::setupDecorAndFunctions()
00213 {
00214
00215 _decorations = Decor_Titlebar | Decor_Handle | Decor_Border |
00216 Decor_AllDesktops | Decor_Iconify | Decor_Maximize;
00217 _functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize |
00218 Func_Shade;
00219 if (_delete_window) {
00220 _decorations |= Decor_Close;
00221 _functions |= Func_Close;
00222 }
00223
00224 if (!(_min_size.x() < _max_size.x() || _min_size.y() < _max_size.y())) {
00225 _decorations &= ~(Decor_Maximize | Decor_Handle);
00226 _functions &= ~(Func_Resize | Func_Maximize);
00227 }
00228
00229 switch (_type) {
00230 case Type_Normal:
00231
00232
00233 _functions |= Func_Fullscreen;
00234 break;
00235
00236 case Type_Dialog:
00237
00238 _decorations &= ~Decor_Maximize;
00239 _functions &= ~Func_Maximize;
00240 break;
00241
00242 case Type_Menu:
00243 case Type_Toolbar:
00244 case Type_Utility:
00245
00246 _decorations &= ~(Decor_Iconify | Decor_Handle);
00247 _functions &= ~(Func_Iconify | Func_Resize);
00248 break;
00249
00250 case Type_Desktop:
00251 case Type_Dock:
00252 case Type_Splash:
00253
00254 _decorations = 0;
00255 _functions = 0;
00256 break;
00257 }
00258
00259
00260
00261 if (_mwmhints.flags & MwmFlag_Decorations) {
00262 if (! (_mwmhints.decorations & MwmDecor_All)) {
00263 if (! (_mwmhints.decorations & MwmDecor_Border))
00264 _decorations &= ~Decor_Border;
00265 if (! (_mwmhints.decorations & MwmDecor_Handle))
00266 _decorations &= ~Decor_Handle;
00267 if (! (_mwmhints.decorations & MwmDecor_Title)) {
00268 _decorations &= ~Decor_Titlebar;
00269
00270 _functions &= ~Func_Shade;
00271 }
00272 if (! (_mwmhints.decorations & MwmDecor_Iconify))
00273 _decorations &= ~Decor_Iconify;
00274 if (! (_mwmhints.decorations & MwmDecor_Maximize))
00275 _decorations &= ~Decor_Maximize;
00276 }
00277 }
00278
00279 if (_mwmhints.flags & MwmFlag_Functions) {
00280 if (! (_mwmhints.functions & MwmFunc_All)) {
00281 if (! (_mwmhints.functions & MwmFunc_Resize))
00282 _functions &= ~Func_Resize;
00283 if (! (_mwmhints.functions & MwmFunc_Move))
00284 _functions &= ~Func_Move;
00285 if (! (_mwmhints.functions & MwmFunc_Iconify))
00286 _functions &= ~Func_Iconify;
00287 if (! (_mwmhints.functions & MwmFunc_Maximize))
00288 _functions &= ~Func_Maximize;
00289
00290
00291
00292 }
00293 }
00294
00295
00296 if (!((_functions & Func_Move) && (_functions & Func_Resize)))
00297 _functions &= ~Func_Maximize;
00298
00299
00300
00301 if (_disabled_decorations & Decor_Titlebar)
00302 _decorations &= ~Decor_Titlebar;
00303 if (_disabled_decorations & Decor_Handle)
00304 _decorations &= ~Decor_Handle;
00305 if (_disabled_decorations & Decor_Border)
00306 _decorations &= ~Decor_Border;
00307 if (_disabled_decorations & Decor_Iconify)
00308 _decorations &= ~Decor_Iconify;
00309 if (_disabled_decorations & Decor_Maximize)
00310 _decorations &= ~Decor_Maximize;
00311 if (_disabled_decorations & Decor_AllDesktops)
00312 _decorations &= ~Decor_AllDesktops;
00313 if (_disabled_decorations & Decor_Close)
00314 _decorations &= ~Decor_Close;
00315
00316
00317 if (!(_decorations & Decor_Titlebar))
00318 _functions &= ~Func_Shade;
00319
00320 changeAllowedActions();
00321
00322 if (frame) {
00323 frame->adjustSize();
00324 frame->adjustPosition();
00325
00326 }
00327 }
00328
00329
00330 void Client::getMwmHints()
00331 {
00332 unsigned long num = MwmHints::elements;
00333 unsigned long *hints;
00334
00335 _mwmhints.flags = 0;
00336
00337 if (!otk::Property::get(_window, otk::Property::atoms.motif_wm_hints,
00338 otk::Property::atoms.motif_wm_hints, &num,
00339 (unsigned long **)&hints))
00340 return;
00341
00342 if (num >= MwmHints::elements) {
00343
00344 _mwmhints.flags = hints[0];
00345 _mwmhints.functions = hints[1];
00346 _mwmhints.decorations = hints[2];
00347 }
00348
00349 delete [] hints;
00350 }
00351
00352
00353 void Client::getArea()
00354 {
00355 XWindowAttributes wattrib;
00356 Status ret;
00357
00358 ret = XGetWindowAttributes(**otk::display, _window, &wattrib);
00359 assert(ret != BadWindow);
00360
00361 _area.setRect(wattrib.x, wattrib.y, wattrib.width, wattrib.height);
00362 _border_width = wattrib.border_width;
00363 }
00364
00365
00366 void Client::getState()
00367 {
00368 _modal = _shaded = _max_horz = _max_vert = _fullscreen = _above = _below =
00369 _iconic = _skip_taskbar = _skip_pager = false;
00370
00371 unsigned long *state;
00372 unsigned long num = (unsigned) -1;
00373
00374 if (otk::Property::get(_window, otk::Property::atoms.net_wm_state,
00375 otk::Property::atoms.atom, &num, &state)) {
00376 for (unsigned long i = 0; i < num; ++i) {
00377 if (state[i] == otk::Property::atoms.net_wm_state_modal)
00378 _modal = true;
00379 else if (state[i] == otk::Property::atoms.net_wm_state_shaded)
00380 _shaded = true;
00381 else if (state[i] == otk::Property::atoms.net_wm_state_hidden)
00382 _iconic = true;
00383 else if (state[i] == otk::Property::atoms.net_wm_state_skip_taskbar)
00384 _skip_taskbar = true;
00385 else if (state[i] == otk::Property::atoms.net_wm_state_skip_pager)
00386 _skip_pager = true;
00387 else if (state[i] == otk::Property::atoms.net_wm_state_fullscreen)
00388 _fullscreen = true;
00389 else if (state[i] == otk::Property::atoms.net_wm_state_maximized_vert)
00390 _max_vert = true;
00391 else if (state[i] == otk::Property::atoms.net_wm_state_maximized_horz)
00392 _max_horz = true;
00393 else if (state[i] == otk::Property::atoms.net_wm_state_above)
00394 _above = true;
00395 else if (state[i] == otk::Property::atoms.net_wm_state_below)
00396 _below = true;
00397 }
00398
00399 delete [] state;
00400 }
00401 }
00402
00403
00404 void Client::getShaped()
00405 {
00406 _shaped = false;
00407 #ifdef SHAPE
00408 if (otk::display->shape()) {
00409 int foo;
00410 unsigned int ufoo;
00411 int s;
00412
00413 XShapeSelectInput(**otk::display, _window, ShapeNotifyMask);
00414
00415 XShapeQueryExtents(**otk::display, _window, &s, &foo,
00416 &foo, &ufoo, &ufoo, &foo, &foo, &foo, &ufoo, &ufoo);
00417 _shaped = (s != 0);
00418 }
00419 #endif // SHAPE
00420 }
00421
00422
00423 void Client::calcLayer() {
00424 StackLayer l;
00425
00426 if (_iconic) l = Layer_Icon;
00427 else if (_fullscreen) l = Layer_Fullscreen;
00428 else if (_type == Type_Desktop) l = Layer_Desktop;
00429 else if (_type == Type_Dock) {
00430 if (!_below) l = Layer_Top;
00431 else l = Layer_Normal;
00432 }
00433 else if (_above) l = Layer_Above;
00434 else if (_below) l = Layer_Below;
00435 else l = Layer_Normal;
00436
00437 if (l != _layer) {
00438 _layer = l;
00439 if (frame) {
00440
00441
00442
00443
00444 openbox->screen(_screen)->raiseWindow(this);
00445 }
00446 }
00447 }
00448
00449
00450 void Client::updateProtocols()
00451 {
00452 Atom *proto;
00453 int num_return = 0;
00454
00455 _focus_notify = false;
00456 _delete_window = false;
00457
00458 if (XGetWMProtocols(**otk::display, _window, &proto, &num_return)) {
00459 for (int i = 0; i < num_return; ++i) {
00460 if (proto[i] == otk::Property::atoms.wm_delete_window) {
00461
00462 _delete_window = true;
00463 } else if (proto[i] == otk::Property::atoms.wm_take_focus)
00464
00465
00466 _focus_notify = true;
00467 }
00468 XFree(proto);
00469 }
00470 }
00471
00472
00473 void Client::updateNormalHints()
00474 {
00475 XSizeHints size;
00476 long ret;
00477 int oldgravity = _gravity;
00478
00479
00480 _min_ratio = 0.0;
00481 _max_ratio = 0.0;
00482 _size_inc.setPoint(1, 1);
00483 _base_size.setPoint(0, 0);
00484 _min_size.setPoint(0, 0);
00485 _max_size.setPoint(INT_MAX, INT_MAX);
00486
00487
00488 if (XGetWMNormalHints(**otk::display, _window, &size, &ret)) {
00489 _positioned = (size.flags & (PPosition|USPosition));
00490
00491 if (size.flags & PWinGravity) {
00492 _gravity = size.win_gravity;
00493
00494
00495
00496 if (frame && _gravity != oldgravity) {
00497
00498 int x = frame->rect().x(), y = frame->rect().y();
00499 frame->frameGravity(x, y);
00500 _area.setPos(x, y);
00501 }
00502 }
00503
00504 if (size.flags & PAspect) {
00505 if (size.min_aspect.y) _min_ratio = size.min_aspect.x/size.min_aspect.y;
00506 if (size.max_aspect.y) _max_ratio = size.max_aspect.x/size.max_aspect.y;
00507 }
00508
00509 if (size.flags & PMinSize)
00510 _min_size.setPoint(size.min_width, size.min_height);
00511
00512 if (size.flags & PMaxSize)
00513 _max_size.setPoint(size.max_width, size.max_height);
00514
00515 if (size.flags & PBaseSize)
00516 _base_size.setPoint(size.base_width, size.base_height);
00517
00518 if (size.flags & PResizeInc)
00519 _size_inc.setPoint(size.width_inc, size.height_inc);
00520 }
00521 }
00522
00523
00524 void Client::updateWMHints(bool initstate)
00525 {
00526 XWMHints *hints;
00527
00528
00529 _can_focus = true;
00530 bool ur = false;
00531
00532 if ((hints = XGetWMHints(**otk::display, _window)) != NULL) {
00533 if (hints->flags & InputHint)
00534 _can_focus = hints->input;
00535
00536
00537 if (initstate && (hints->flags & StateHint))
00538 _iconic = hints->initial_state == IconicState;
00539
00540 if (hints->flags & XUrgencyHint)
00541 ur = true;
00542
00543 if (hints->flags & WindowGroupHint) {
00544 if (hints->window_group != _group) {
00545
00546 _group = hints->window_group;
00547
00548 }
00549 } else
00550 _group = None;
00551
00552 XFree(hints);
00553 }
00554
00555 if (ur != _urgent) {
00556 _urgent = ur;
00557 #ifdef DEBUG
00558 printf("DEBUG: Urgent Hint for 0x%lx: %s\n",
00559 (long)_window, _urgent ? "ON" : "OFF");
00560 #endif
00561
00562
00563 if (frame)
00564 fireUrgent();
00565 }
00566 }
00567
00568
00569 void Client::updateTitle()
00570 {
00571 _title = "";
00572
00573
00574 if (!otk::Property::get(_window, otk::Property::atoms.net_wm_name,
00575 otk::Property::utf8, &_title)) {
00576
00577 otk::Property::get(_window, otk::Property::atoms.wm_name,
00578 otk::Property::ascii, &_title);
00579 }
00580
00581 if (_title.empty())
00582 _title = _("Unnamed Window");
00583
00584 if (frame)
00585 frame->setTitle(_title);
00586 }
00587
00588
00589 void Client::updateIconTitle()
00590 {
00591 _icon_title = "";
00592
00593
00594 if (!otk::Property::get(_window, otk::Property::atoms.net_wm_icon_name,
00595 otk::Property::utf8, &_icon_title)) {
00596
00597 otk::Property::get(_window, otk::Property::atoms.wm_icon_name,
00598 otk::Property::ascii, &_icon_title);
00599 }
00600
00601 if (_title.empty())
00602 _icon_title = _("Unnamed Window");
00603 }
00604
00605
00606 void Client::updateClass()
00607 {
00608
00609 _app_name = _app_class = _role = "";
00610
00611 otk::Property::StringVect v;
00612 unsigned long num = 2;
00613
00614 if (otk::Property::get(_window, otk::Property::atoms.wm_class,
00615 otk::Property::ascii, &num, &v)) {
00616 if (num > 0) _app_name = v[0].c_str();
00617 if (num > 1) _app_class = v[1].c_str();
00618 }
00619
00620 v.clear();
00621 num = 1;
00622 if (otk::Property::get(_window, otk::Property::atoms.wm_window_role,
00623 otk::Property::ascii, &num, &v)) {
00624 if (num > 0) _role = v[0].c_str();
00625 }
00626 }
00627
00628
00629 void Client::updateStrut()
00630 {
00631 unsigned long num = 4;
00632 unsigned long *data;
00633 if (!otk::Property::get(_window, otk::Property::atoms.net_wm_strut,
00634 otk::Property::atoms.cardinal, &num, &data))
00635 return;
00636
00637 if (num == 4) {
00638 _strut.left = data[0];
00639 _strut.right = data[1];
00640 _strut.top = data[2];
00641 _strut.bottom = data[3];
00642
00643
00644
00645 if (frame)
00646 openbox->screen(_screen)->updateStrut();
00647 }
00648
00649 delete [] data;
00650 }
00651
00652
00653 void Client::updateTransientFor()
00654 {
00655 Window t = 0;
00656 Client *c = 0;
00657
00658 if (XGetTransientForHint(**otk::display, _window, &t) &&
00659 t != _window) {
00660 c = openbox->findClient(t);
00661 assert(c != this);
00662
00663 if (!c ) {
00664
00665 if (
00666 t == None ||
00667 t == otk::display->screenInfo(_screen)->rootWindow()) {
00668
00669
00670
00671 }
00672 }
00673 }
00674
00675
00676 if (c != _transient_for) {
00677 bool m = _modal;
00678 if (_modal)
00679 setModal(false);
00680
00681 if (_transient_for)
00682 _transient_for->_transients.remove(this);
00683 _transient_for = c;
00684 if (_transient_for)
00685 _transient_for->_transients.push_back(this);
00686
00687 if (m)
00688 setModal(true);
00689 }
00690 }
00691
00692
00693 void Client::propertyHandler(const XPropertyEvent &e)
00694 {
00695 otk::EventHandler::propertyHandler(e);
00696
00697
00698 if (!validate()) return;
00699
00700
00701 XEvent ce;
00702 while (XCheckTypedEvent(**otk::display, e.type, &ce)) {
00703
00704
00705 if (ce.xproperty.atom != e.atom) {
00706 XPutBackEvent(**otk::display, &ce);
00707 break;
00708 }
00709 }
00710
00711 if (e.atom == XA_WM_NORMAL_HINTS) {
00712 updateNormalHints();
00713 setupDecorAndFunctions();
00714 } else if (e.atom == XA_WM_HINTS)
00715 updateWMHints();
00716 else if (e.atom == XA_WM_TRANSIENT_FOR) {
00717 updateTransientFor();
00718 getType();
00719 calcLayer();
00720 setupDecorAndFunctions();
00721 }
00722 else if (e.atom == otk::Property::atoms.net_wm_name ||
00723 e.atom == otk::Property::atoms.wm_name)
00724 updateTitle();
00725 else if (e.atom == otk::Property::atoms.net_wm_icon_name ||
00726 e.atom == otk::Property::atoms.wm_icon_name)
00727 updateIconTitle();
00728 else if (e.atom == otk::Property::atoms.wm_class)
00729 updateClass();
00730 else if (e.atom == otk::Property::atoms.wm_protocols) {
00731 updateProtocols();
00732 setupDecorAndFunctions();
00733 }
00734 else if (e.atom == otk::Property::atoms.net_wm_strut)
00735 updateStrut();
00736 }
00737
00738
00739 void Client::setWMState(long state)
00740 {
00741 if (state == _wmstate) return;
00742
00743 switch (state) {
00744 case IconicState:
00745 setDesktop(ICONIC_DESKTOP);
00746 break;
00747 case NormalState:
00748 setDesktop(openbox->screen(_screen)->desktop());
00749 break;
00750 }
00751 }
00752
00753
00754 void Client::setDesktop(long target)
00755 {
00756 if (target == _desktop) return;
00757
00758 printf("Setting desktop %ld\n", target);
00759
00760 if (!(target >= 0 || target == (signed)0xffffffff ||
00761 target == ICONIC_DESKTOP))
00762 return;
00763
00764 _desktop = target;
00765
00766
00767 if (_desktop != ICONIC_DESKTOP)
00768 otk::Property::set(_window, otk::Property::atoms.net_wm_desktop,
00769 otk::Property::atoms.cardinal, (unsigned)_desktop);
00770
00771
00772 if (_desktop == openbox->screen(_screen)->desktop() ||
00773 _desktop == (signed)0xffffffff)
00774 frame->show();
00775 else
00776 frame->hide();
00777
00778
00779
00780
00781 bool i = _desktop == ICONIC_DESKTOP;
00782 if (i != _iconic) {
00783 _iconic = i;
00784 if (_iconic) {
00785 _wmstate = IconicState;
00786 ignore_unmaps++;
00787
00788
00789 XUnmapWindow(**otk::display, _window);
00790 } else {
00791 _wmstate = NormalState;
00792 XMapWindow(**otk::display, _window);
00793 }
00794 changeState();
00795 }
00796
00797 frame->adjustState();
00798 }
00799
00800
00801 Client *Client::findModalChild(Client *skip) const
00802 {
00803 Client *ret = 0;
00804
00805
00806 List::const_iterator it, end = _transients.end();
00807 for (it = _transients.begin(); it != end; ++it)
00808 if ((*it)->_modal && *it != skip)
00809 return *it;
00810
00811 for (it = _transients.begin(); it != end; ++it)
00812 if ((ret = (*it)->findModalChild()))
00813 return ret;
00814 return ret;
00815 }
00816
00817
00818 void Client::setModal(bool modal)
00819 {
00820 if (modal == _modal) return;
00821
00822 if (modal) {
00823 Client *c = this;
00824 while (c->_transient_for) {
00825 c = c->_transient_for;
00826 if (c->_modal_child) break;
00827 c->_modal_child = this;
00828 }
00829 } else {
00830
00831 Client *replacement = 0;
00832
00833 Client *c = this;
00834 while (c->_transient_for)
00835 c = c->_transient_for;
00836 replacement = c->findModalChild(this);
00837
00838 c = this;
00839 while (c->_transient_for) {
00840 c = c->_transient_for;
00841 if (c->_modal_child != this) break;
00842 c->_modal_child = replacement;
00843 }
00844 }
00845 _modal = modal;
00846 }
00847
00848
00849 void Client::setState(StateAction action, long data1, long data2)
00850 {
00851 bool shadestate = _shaded;
00852 bool fsstate = _fullscreen;
00853 bool maxh = _max_horz;
00854 bool maxv = _max_vert;
00855 bool modal = _modal;
00856
00857 if (!(action == State_Add || action == State_Remove ||
00858 action == State_Toggle))
00859 return;
00860
00861 for (int i = 0; i < 2; ++i) {
00862 Atom state = i == 0 ? data1 : data2;
00863
00864 if (! state) continue;
00865
00866
00867 if (action == State_Toggle) {
00868 if (state == otk::Property::atoms.net_wm_state_modal)
00869 action = _modal ? State_Remove : State_Add;
00870 else if (state == otk::Property::atoms.net_wm_state_maximized_vert)
00871 action = _max_vert ? State_Remove : State_Add;
00872 else if (state == otk::Property::atoms.net_wm_state_maximized_horz)
00873 action = _max_horz ? State_Remove : State_Add;
00874 else if (state == otk::Property::atoms.net_wm_state_shaded)
00875 action = _shaded ? State_Remove : State_Add;
00876 else if (state == otk::Property::atoms.net_wm_state_skip_taskbar)
00877 action = _skip_taskbar ? State_Remove : State_Add;
00878 else if (state == otk::Property::atoms.net_wm_state_skip_pager)
00879 action = _skip_pager ? State_Remove : State_Add;
00880 else if (state == otk::Property::atoms.net_wm_state_fullscreen)
00881 action = _fullscreen ? State_Remove : State_Add;
00882 else if (state == otk::Property::atoms.net_wm_state_above)
00883 action = _above ? State_Remove : State_Add;
00884 else if (state == otk::Property::atoms.net_wm_state_below)
00885 action = _below ? State_Remove : State_Add;
00886 }
00887
00888 if (action == State_Add) {
00889 if (state == otk::Property::atoms.net_wm_state_modal) {
00890 if (_modal) continue;
00891 modal = true;
00892 } else if (state == otk::Property::atoms.net_wm_state_maximized_vert) {
00893 maxv = true;
00894 } else if (state == otk::Property::atoms.net_wm_state_maximized_horz) {
00895 if (_max_horz) continue;
00896 maxh = true;
00897 } else if (state == otk::Property::atoms.net_wm_state_shaded) {
00898 shadestate = true;
00899 } else if (state == otk::Property::atoms.net_wm_state_skip_taskbar) {
00900 _skip_taskbar = true;
00901 } else if (state == otk::Property::atoms.net_wm_state_skip_pager) {
00902 _skip_pager = true;
00903 } else if (state == otk::Property::atoms.net_wm_state_fullscreen) {
00904 fsstate = true;
00905 } else if (state == otk::Property::atoms.net_wm_state_above) {
00906 if (_above) continue;
00907 _above = true;
00908 } else if (state == otk::Property::atoms.net_wm_state_below) {
00909 if (_below) continue;
00910 _below = true;
00911 }
00912
00913 } else {
00914 if (state == otk::Property::atoms.net_wm_state_modal) {
00915 if (!_modal) continue;
00916 modal = false;
00917 } else if (state == otk::Property::atoms.net_wm_state_maximized_vert) {
00918 maxv = false;
00919 } else if (state == otk::Property::atoms.net_wm_state_maximized_horz) {
00920 maxh = false;
00921 } else if (state == otk::Property::atoms.net_wm_state_shaded) {
00922 shadestate = false;
00923 } else if (state == otk::Property::atoms.net_wm_state_skip_taskbar) {
00924 _skip_taskbar = false;
00925 } else if (state == otk::Property::atoms.net_wm_state_skip_pager) {
00926 _skip_pager = false;
00927 } else if (state == otk::Property::atoms.net_wm_state_fullscreen) {
00928 fsstate = false;
00929 } else if (state == otk::Property::atoms.net_wm_state_above) {
00930 if (!_above) continue;
00931 _above = false;
00932 } else if (state == otk::Property::atoms.net_wm_state_below) {
00933 if (!_below) continue;
00934 _below = false;
00935 }
00936 }
00937 }
00938 if (maxh != _max_horz || maxv != _max_vert) {
00939 if (maxh != _max_horz && maxv != _max_vert) {
00940 if (maxh == maxv) {
00941 maximize(maxh, 0, true);
00942 } else {
00943 maximize(maxh, 1, true);
00944 maximize(maxv, 2, true);
00945 }
00946 } else {
00947 if (maxh != _max_horz)
00948 maximize(maxh, 1, true);
00949 else
00950 maximize(maxv, 2, true);
00951 }
00952 }
00953 if (modal != _modal)
00954 setModal(modal);
00955
00956
00957 if (fsstate != _fullscreen)
00958 fullscreen(fsstate, true);
00959 if (shadestate != _shaded)
00960 shade(shadestate);
00961 calcLayer();
00962 changeState();
00963 }
00964
00965
00966 void Client::toggleClientBorder(bool addborder)
00967 {
00968
00969
00970
00971
00972
00973 int oldx = _area.x(), oldy = _area.y();
00974 int x = oldx, y = oldy;
00975 switch(_gravity) {
00976 default:
00977 case NorthWestGravity:
00978 case WestGravity:
00979 case SouthWestGravity:
00980 break;
00981 case NorthEastGravity:
00982 case EastGravity:
00983 case SouthEastGravity:
00984 if (addborder) x -= _border_width * 2;
00985 else x += _border_width * 2;
00986 break;
00987 case NorthGravity:
00988 case SouthGravity:
00989 case CenterGravity:
00990 case ForgetGravity:
00991 case StaticGravity:
00992 if (addborder) x -= _border_width;
00993 else x += _border_width;
00994 break;
00995 }
00996 switch(_gravity) {
00997 default:
00998 case NorthWestGravity:
00999 case NorthGravity:
01000 case NorthEastGravity:
01001 break;
01002 case SouthWestGravity:
01003 case SouthGravity:
01004 case SouthEastGravity:
01005 if (addborder) y -= _border_width * 2;
01006 else y += _border_width * 2;
01007 break;
01008 case WestGravity:
01009 case EastGravity:
01010 case CenterGravity:
01011 case ForgetGravity:
01012 case StaticGravity:
01013 if (addborder) y -= _border_width;
01014 else y += _border_width;
01015 break;
01016 }
01017 _area.setPos(x, y);
01018
01019 if (addborder) {
01020 XSetWindowBorderWidth(**otk::display, _window, _border_width);
01021
01022
01023 if (x != oldx || y != oldy)
01024 XMoveWindow(**otk::display, _window, x, y);
01025 } else
01026 XSetWindowBorderWidth(**otk::display, _window, 0);
01027 }
01028
01029
01030 void Client::clientMessageHandler(const XClientMessageEvent &e)
01031 {
01032 otk::EventHandler::clientMessageHandler(e);
01033
01034
01035 if (!validate()) return;
01036
01037 if (e.format != 32) return;
01038
01039 if (e.message_type == otk::Property::atoms.wm_change_state) {
01040
01041 bool compress = false;
01042 XEvent ce;
01043 while (XCheckTypedEvent(**otk::display, e.type, &ce)) {
01044
01045
01046 if (ce.xclient.message_type != e.message_type) {
01047 XPutBackEvent(**otk::display, &ce);
01048 break;
01049 }
01050 compress = true;
01051 }
01052 if (compress)
01053 setWMState(ce.xclient.data.l[0]);
01054 else
01055 setWMState(e.data.l[0]);
01056 } else if (e.message_type == otk::Property::atoms.net_wm_desktop) {
01057
01058 bool compress = false;
01059 XEvent ce;
01060 while (XCheckTypedEvent(**otk::display, e.type, &ce)) {
01061
01062
01063 if (ce.xclient.message_type != e.message_type) {
01064 XPutBackEvent(**otk::display, &ce);
01065 break;
01066 }
01067 compress = true;
01068 }
01069 if (compress)
01070 setDesktop(e.data.l[0]);
01071 else
01072 setDesktop(e.data.l[0]);
01073 } else if (e.message_type == otk::Property::atoms.net_wm_state) {
01074
01075 #ifdef DEBUG
01076 printf("net_wm_state %s %ld %ld for 0x%lx\n",
01077 (e.data.l[0] == 0 ? "Remove" : e.data.l[0] == 1 ? "Add" :
01078 e.data.l[0] == 2 ? "Toggle" : "INVALID"),
01079 e.data.l[1], e.data.l[2], _window);
01080 #endif
01081 setState((StateAction)e.data.l[0], e.data.l[1], e.data.l[2]);
01082 } else if (e.message_type == otk::Property::atoms.net_close_window) {
01083 #ifdef DEBUG
01084 printf("net_close_window for 0x%lx\n", _window);
01085 #endif
01086 close();
01087 } else if (e.message_type == otk::Property::atoms.net_active_window) {
01088 #ifdef DEBUG
01089 printf("net_active_window for 0x%lx\n", _window);
01090 #endif
01091 if (_iconic)
01092 setDesktop(openbox->screen(_screen)->desktop());
01093 if (_shaded)
01094 shade(false);
01095 focus();
01096 openbox->screen(_screen)->raiseWindow(this);
01097 } else if (e.message_type == otk::Property::atoms.openbox_active_window) {
01098 if (_iconic)
01099 setDesktop(openbox->screen(_screen)->desktop());
01100 if (e.data.l[0] && _shaded)
01101 shade(false);
01102 focus();
01103 if (e.data.l[1])
01104 openbox->screen(_screen)->raiseWindow(this);
01105 }
01106 }
01107
01108
01109 #if defined(SHAPE)
01110 void Client::shapeHandler(const XShapeEvent &e)
01111 {
01112 otk::EventHandler::shapeHandler(e);
01113
01114 if (e.kind == ShapeBounding) {
01115 _shaped = e.shaped;
01116 frame->adjustShape();
01117 }
01118 }
01119 #endif
01120
01121
01122 void Client::resize(Corner anchor, int w, int h)
01123 {
01124 if (!(_functions & Func_Resize)) return;
01125 internal_resize(anchor, w, h);
01126 }
01127
01128
01129 void Client::internal_resize(Corner anchor, int w, int h, bool user,
01130 int x, int y)
01131 {
01132 w -= _base_size.x();
01133 h -= _base_size.y();
01134
01135 if (user) {
01136
01137
01138 int mw = w % _size_inc.x();
01139 int mh = h % _size_inc.y();
01140 int aw = _size_inc.x() / 2;
01141 int ah = _size_inc.y() / 2;
01142
01143 if (mw + aw >= _size_inc.x()) aw = _size_inc.x() - mw - 1;
01144 if (mh + ah >= _size_inc.y()) ah = _size_inc.y() - mh - 1;
01145 w += aw;
01146 h += ah;
01147
01148
01149
01150
01151
01152 if (w < _min_size.x()) w = _min_size.x();
01153 else if (w > _max_size.x()) w = _max_size.x();
01154 if (h < _min_size.y()) h = _min_size.y();
01155 else if (h > _max_size.y()) h = _max_size.y();
01156
01157
01158 if (_min_ratio)
01159 if (h * _min_ratio > w) h = static_cast<int>(w / _min_ratio);
01160 if (_max_ratio)
01161 if (h * _max_ratio < w) h = static_cast<int>(w / _max_ratio);
01162 }
01163
01164
01165 w /= _size_inc.x();
01166 h /= _size_inc.y();
01167
01168
01169 if (w < 1) w = 1;
01170 if (h < 1) h = 1;
01171
01172
01173 _logical_size.setPoint(w, h);
01174
01175 w *= _size_inc.x();
01176 h *= _size_inc.y();
01177
01178 w += _base_size.x();
01179 h += _base_size.y();
01180
01181 if (x == INT_MIN || y == INT_MIN) {
01182 x = _area.x();
01183 y = _area.y();
01184 switch (anchor) {
01185 case TopLeft:
01186 break;
01187 case TopRight:
01188 x -= w - _area.width();
01189 break;
01190 case BottomLeft:
01191 y -= h - _area.height();
01192 break;
01193 case BottomRight:
01194 x -= w - _area.width();
01195 y -= h - _area.height();
01196 break;
01197 }
01198 }
01199
01200 _area.setSize(w, h);
01201
01202 XResizeWindow(**otk::display, _window, w, h);
01203
01204
01205 frame->adjustSize();
01206 internal_move(x, y);
01207 }
01208
01209
01210 void Client::move(int x, int y)
01211 {
01212 if (!(_functions & Func_Move)) return;
01213 frame->frameGravity(x, y);
01214
01215 internal_move(x, y);
01216 }
01217
01218
01219 void Client::internal_move(int x, int y)
01220 {
01221 _area.setPos(x, y);
01222
01223
01224 if (frame) {
01225 frame->adjustPosition();
01226
01227
01228
01229 XEvent event;
01230 event.type = ConfigureNotify;
01231 event.xconfigure.display = **otk::display;
01232 event.xconfigure.event = _window;
01233 event.xconfigure.window = _window;
01234
01235
01236 event.xconfigure.x = x - _border_width + frame->size().left;
01237 event.xconfigure.y = y - _border_width + frame->size().top;
01238
01239 event.xconfigure.width = _area.width();
01240 event.xconfigure.height = _area.height();
01241 event.xconfigure.border_width = _border_width;
01242 event.xconfigure.above = frame->plate();
01243 event.xconfigure.override_redirect = False;
01244 XSendEvent(event.xconfigure.display, event.xconfigure.window, False,
01245 StructureNotifyMask, &event);
01246 #if 0//def DEBUG
01247 printf("Sent synthetic ConfigureNotify %d,%d %d,%d to 0x%lx\n",
01248 event.xconfigure.x, event.xconfigure.y, event.xconfigure.width,
01249 event.xconfigure.height, event.xconfigure.window);
01250 #endif
01251 }
01252 }
01253
01254
01255 void Client::close()
01256 {
01257 XEvent ce;
01258
01259 if (!(_functions & Func_Close)) return;
01260
01261
01262
01263
01264
01265
01266
01267 ce.xclient.type = ClientMessage;
01268 ce.xclient.message_type = otk::Property::atoms.wm_protocols;
01269 ce.xclient.display = **otk::display;
01270 ce.xclient.window = _window;
01271 ce.xclient.format = 32;
01272 ce.xclient.data.l[0] = otk::Property::atoms.wm_delete_window;
01273 ce.xclient.data.l[1] = CurrentTime;
01274 ce.xclient.data.l[2] = 0l;
01275 ce.xclient.data.l[3] = 0l;
01276 ce.xclient.data.l[4] = 0l;
01277 XSendEvent(**otk::display, _window, false, NoEventMask, &ce);
01278 }
01279
01280
01281 void Client::changeState()
01282 {
01283 unsigned long state[2];
01284 state[0] = _wmstate;
01285 state[1] = None;
01286 otk::Property::set(_window, otk::Property::atoms.wm_state,
01287 otk::Property::atoms.wm_state, state, 2);
01288
01289 Atom netstate[10];
01290 int num = 0;
01291 if (_modal)
01292 netstate[num++] = otk::Property::atoms.net_wm_state_modal;
01293 if (_shaded)
01294 netstate[num++] = otk::Property::atoms.net_wm_state_shaded;
01295 if (_iconic)
01296 netstate[num++] = otk::Property::atoms.net_wm_state_hidden;
01297 if (_skip_taskbar)
01298 netstate[num++] = otk::Property::atoms.net_wm_state_skip_taskbar;
01299 if (_skip_pager)
01300 netstate[num++] = otk::Property::atoms.net_wm_state_skip_pager;
01301 if (_fullscreen)
01302 netstate[num++] = otk::Property::atoms.net_wm_state_fullscreen;
01303 if (_max_vert)
01304 netstate[num++] = otk::Property::atoms.net_wm_state_maximized_vert;
01305 if (_max_horz)
01306 netstate[num++] = otk::Property::atoms.net_wm_state_maximized_horz;
01307 if (_above)
01308 netstate[num++] = otk::Property::atoms.net_wm_state_above;
01309 if (_below)
01310 netstate[num++] = otk::Property::atoms.net_wm_state_below;
01311 otk::Property::set(_window, otk::Property::atoms.net_wm_state,
01312 otk::Property::atoms.atom, netstate, num);
01313
01314 calcLayer();
01315
01316 if (frame)
01317 frame->adjustState();
01318 }
01319
01320
01321 void Client::changeAllowedActions(void)
01322 {
01323 Atom actions[9];
01324 int num = 0;
01325
01326 actions[num++] = otk::Property::atoms.net_wm_action_change_desktop;
01327
01328 if (_functions & Func_Shade)
01329 actions[num++] = otk::Property::atoms.net_wm_action_shade;
01330 if (_functions & Func_Close)
01331 actions[num++] = otk::Property::atoms.net_wm_action_close;
01332 if (_functions & Func_Move)
01333 actions[num++] = otk::Property::atoms.net_wm_action_move;
01334 if (_functions & Func_Iconify)
01335 actions[num++] = otk::Property::atoms.net_wm_action_minimize;
01336 if (_functions & Func_Resize)
01337 actions[num++] = otk::Property::atoms.net_wm_action_resize;
01338 if (_functions & Func_Fullscreen)
01339 actions[num++] = otk::Property::atoms.net_wm_action_fullscreen;
01340 if (_functions & Func_Maximize) {
01341 actions[num++] = otk::Property::atoms.net_wm_action_maximize_horz;
01342 actions[num++] = otk::Property::atoms.net_wm_action_maximize_vert;
01343 }
01344
01345 otk::Property::set(_window, otk::Property::atoms.net_wm_allowed_actions,
01346 otk::Property::atoms.atom, actions, num);
01347 }
01348
01349
01350 void Client::remaximize()
01351 {
01352 int dir;
01353 if (_max_horz && _max_vert)
01354 dir = 0;
01355 else if (_max_horz)
01356 dir = 1;
01357 else if (_max_vert)
01358 dir = 2;
01359 else
01360 return;
01361 _max_horz = _max_vert = false;
01362 maximize(true, dir, false);
01363 }
01364
01365
01366 void Client::applyStartupState()
01367 {
01368
01369
01370 if (_modal) {
01371 _modal = false;
01372 setModal(true);
01373 }
01374
01375 if (_iconic) {
01376 _iconic = false;
01377 setDesktop(ICONIC_DESKTOP);
01378 }
01379 if (_fullscreen) {
01380 _fullscreen = false;
01381 fullscreen(true, false);
01382 }
01383 if (_shaded) {
01384 _shaded = false;
01385 shade(true);
01386 }
01387 if (_urgent)
01388 fireUrgent();
01389
01390 if (_max_vert && _max_horz) {
01391 _max_vert = _max_horz = false;
01392 maximize(true, 0, false);
01393 } else if (_max_vert) {
01394 _max_vert = false;
01395 maximize(true, 2, false);
01396 } else if (_max_horz) {
01397 _max_horz = false;
01398 maximize(true, 1, false);
01399 }
01400
01401 if (_skip_taskbar);
01402 if (_skip_pager);
01403 if (_modal);
01404 if (_above);
01405 if (_below);
01406 }
01407
01408
01409 void Client::fireUrgent()
01410 {
01411
01412 EventData data(_screen, this, EventAction::UrgentWindow, 0);
01413 openbox->bindings()->fireEvent(&data);
01414 }
01415
01416
01417 void Client::shade(bool shade)
01418 {
01419 if (!(_functions & Func_Shade) ||
01420 _shaded == shade) return;
01421
01422
01423 if (!_iconic)
01424 _wmstate = shade ? IconicState : NormalState;
01425 _shaded = shade;
01426 changeState();
01427 frame->adjustSize();
01428 }
01429
01430
01431 void Client::maximize(bool max, int dir, bool savearea)
01432 {
01433 assert(dir == 0 || dir == 1 || dir == 2);
01434 if (!(_functions & Func_Maximize)) return;
01435
01436
01437 if (max) {
01438 if (dir == 0 && _max_horz && _max_vert) return;
01439 if (dir == 1 && _max_horz) return;
01440 if (dir == 2 && _max_vert) return;
01441 } else {
01442 if (dir == 0 && !_max_horz && !_max_vert) return;
01443 if (dir == 1 && !_max_horz) return;
01444 if (dir == 2 && !_max_vert) return;
01445 }
01446
01447 const otk::Rect &a = openbox->screen(_screen)->area();
01448 int x = frame->rect().x(), y = frame->rect().y(),
01449 w = _area.width(), h = _area.height();
01450
01451 if (max) {
01452 if (savearea) {
01453 long dimensions[4];
01454 long *readdim;
01455 unsigned long n = 4;
01456
01457 dimensions[0] = x;
01458 dimensions[1] = y;
01459 dimensions[2] = w;
01460 dimensions[3] = h;
01461
01462
01463
01464 if (otk::Property::get(_window, otk::Property::atoms.openbox_premax,
01465 otk::Property::atoms.cardinal, &n,
01466 (long unsigned**) &readdim)) {
01467 if (n >= 4) {
01468 if (_max_horz) {
01469 dimensions[0] = readdim[0];
01470 dimensions[2] = readdim[2];
01471 }
01472 if (_max_vert) {
01473 dimensions[1] = readdim[1];
01474 dimensions[3] = readdim[3];
01475 }
01476 }
01477 delete readdim;
01478 }
01479
01480 otk::Property::set(_window, otk::Property::atoms.openbox_premax,
01481 otk::Property::atoms.cardinal,
01482 (long unsigned*)dimensions, 4);
01483 }
01484 if (dir == 0 || dir == 1) {
01485 x = a.x();
01486 w = a.width();
01487 }
01488 if (dir == 0 || dir == 2) {
01489 y = a.y();
01490 h = a.height() - frame->size().top - frame->size().bottom;
01491 }
01492 } else {
01493 long *dimensions;
01494 long unsigned n = 4;
01495
01496 if (otk::Property::get(_window, otk::Property::atoms.openbox_premax,
01497 otk::Property::atoms.cardinal, &n,
01498 (long unsigned**) &dimensions)) {
01499 if (n >= 4) {
01500 if (dir == 0 || dir == 1) {
01501 x = (signed int)dimensions[0];
01502 w = (signed int)dimensions[2];
01503 }
01504 if (dir == 0 || dir == 2) {
01505 y = (signed int)dimensions[1];
01506 h = (signed int)dimensions[3];
01507 }
01508 }
01509 delete dimensions;
01510 } else {
01511
01512 if (dir == 0 || dir == 1) {
01513 x = a.x() + a.width() / 4;
01514 w = a.width() / 2;
01515 }
01516 if (dir == 0 || dir == 2) {
01517 y = a.y() + a.height() / 4;
01518 h = a.height() / 2;
01519 }
01520 }
01521 }
01522
01523 if (dir == 0 || dir == 1)
01524 _max_horz = max;
01525 if (dir == 0 || dir == 2)
01526 _max_vert = max;
01527
01528 if (!_max_horz && !_max_vert)
01529 otk::Property::erase(_window, otk::Property::atoms.openbox_premax);
01530
01531 changeState();
01532
01533 frame->frameGravity(x, y);
01534 internal_resize(TopLeft, w, h, true, x, y);
01535 }
01536
01537
01538 void Client::fullscreen(bool fs, bool savearea)
01539 {
01540 static FunctionFlags saved_func;
01541 static DecorationFlags saved_decor;
01542
01543 if (!(_functions & Func_Fullscreen) ||
01544 _fullscreen == fs) return;
01545
01546 _fullscreen = fs;
01547 changeState();
01548
01549 int x = _area.x(), y = _area.y(), w = _area.width(), h = _area.height();
01550
01551 if (fs) {
01552
01553 saved_func = _functions;
01554 _functions = _functions & (Func_Close | Func_Fullscreen | Func_Iconify);
01555
01556 saved_decor = _decorations;
01557 _decorations = 0;
01558 if (savearea) {
01559 long dimensions[4];
01560 dimensions[0] = _area.x();
01561 dimensions[1] = _area.y();
01562 dimensions[2] = _area.width();
01563 dimensions[3] = _area.height();
01564 otk::Property::set(_window, otk::Property::atoms.openbox_premax,
01565 otk::Property::atoms.cardinal,
01566 (long unsigned*)dimensions, 4);
01567 }
01568 const otk::ScreenInfo *info = otk::display->screenInfo(_screen);
01569 x = 0;
01570 y = 0;
01571 w = info->width();
01572 h = info->height();
01573 } else {
01574 _functions = saved_func;
01575 _decorations = saved_decor;
01576
01577 long *dimensions;
01578 long unsigned n = 4;
01579
01580 if (otk::Property::get(_window, otk::Property::atoms.openbox_premax,
01581 otk::Property::atoms.cardinal, &n,
01582 (long unsigned**) &dimensions)) {
01583 if (n >= 4) {
01584 x = dimensions[0];
01585 y = dimensions[1];
01586 w = dimensions[2];
01587 h = dimensions[3];
01588 }
01589 delete dimensions;
01590 } else {
01591
01592 const otk::Rect &a = openbox->screen(_screen)->area();
01593 x = a.x() + a.width() / 4;
01594 y = a.y() + a.height() / 4;
01595 w = a.width() / 2;
01596 h = a.height() / 2;
01597 }
01598 }
01599
01600 changeAllowedActions();
01601
01602
01603 internal_resize(TopLeft, w, h, !fs, x, y);
01604
01605
01606 openbox->screen(_screen)->raiseWindow(this);
01607
01608
01609 if (fs) focus();
01610 }
01611
01612
01613 void Client::disableDecorations(DecorationFlags flags)
01614 {
01615 _disabled_decorations = flags;
01616 setupDecorAndFunctions();
01617 }
01618
01619
01620 void Client::installColormap(bool install) const
01621 {
01622 XWindowAttributes wa;
01623 if (XGetWindowAttributes(**otk::display, _window, &wa)) {
01624 if (install)
01625 XInstallColormap(**otk::display, wa.colormap);
01626 else
01627 XUninstallColormap(**otk::display, wa.colormap);
01628 }
01629 }
01630
01631
01632 bool Client::focus()
01633 {
01634
01635 if (_modal_child)
01636 return _modal_child->focus();
01637
01638
01639
01640 if (!(frame->isVisible() && (_can_focus || _focus_notify))) return false;
01641
01642 if (_focused) return true;
01643
01644
01645
01646
01647 XEvent ev;
01648 if (XCheckTypedWindowEvent(**otk::display, _window, DestroyNotify, &ev)) {
01649 XPutBackEvent(**otk::display, &ev);
01650 return false;
01651 }
01652 while (XCheckTypedWindowEvent(**otk::display, _window, UnmapNotify, &ev)) {
01653 if (ignore_unmaps) {
01654 unmapHandler(ev.xunmap);
01655 } else {
01656 XPutBackEvent(**otk::display, &ev);
01657 return false;
01658 }
01659 }
01660
01661 if (_can_focus)
01662 XSetInputFocus(**otk::display, _window,
01663 RevertToNone, CurrentTime);
01664
01665 if (_focus_notify) {
01666 XEvent ce;
01667 ce.xclient.type = ClientMessage;
01668 ce.xclient.message_type = otk::Property::atoms.wm_protocols;
01669 ce.xclient.display = **otk::display;
01670 ce.xclient.window = _window;
01671 ce.xclient.format = 32;
01672 ce.xclient.data.l[0] = otk::Property::atoms.wm_take_focus;
01673 ce.xclient.data.l[1] = openbox->lastTime();
01674 ce.xclient.data.l[2] = 0l;
01675 ce.xclient.data.l[3] = 0l;
01676 ce.xclient.data.l[4] = 0l;
01677 XSendEvent(**otk::display, _window, False, NoEventMask, &ce);
01678 }
01679
01680 XSync(**otk::display, False);
01681 return true;
01682 }
01683
01684
01685 void Client::unfocus() const
01686 {
01687 if (!_focused) return;
01688
01689 assert(openbox->focusedClient() == this);
01690 openbox->setFocusedClient(0);
01691 }
01692
01693
01694 void Client::focusHandler(const XFocusChangeEvent &e)
01695 {
01696 #ifdef DEBUG
01697
01698 #endif // DEBUG
01699
01700 otk::EventHandler::focusHandler(e);
01701
01702 frame->focus();
01703 _focused = true;
01704
01705 openbox->setFocusedClient(this);
01706 }
01707
01708
01709 void Client::unfocusHandler(const XFocusChangeEvent &e)
01710 {
01711 #ifdef DEBUG
01712
01713 #endif // DEBUG
01714
01715 otk::EventHandler::unfocusHandler(e);
01716
01717 frame->unfocus();
01718 _focused = false;
01719
01720 if (openbox->focusedClient() == this)
01721 openbox->setFocusedClient(0);
01722 }
01723
01724
01725 void Client::configureRequestHandler(const XConfigureRequestEvent &e)
01726 {
01727 #ifdef DEBUG
01728 printf("ConfigureRequest for 0x%lx\n", e.window);
01729 #endif // DEBUG
01730
01731 otk::EventHandler::configureRequestHandler(e);
01732
01733
01734 if (_iconic || _shaded) return;
01735
01736 if (e.value_mask & CWBorderWidth)
01737 _border_width = e.border_width;
01738
01739
01740 if (e.value_mask & (CWWidth | CWHeight)) {
01741 int w = (e.value_mask & CWWidth) ? e.width : _area.width();
01742 int h = (e.value_mask & CWHeight) ? e.height : _area.height();
01743
01744 Corner corner;
01745 switch (_gravity) {
01746 case NorthEastGravity:
01747 case EastGravity:
01748 corner = TopRight;
01749 break;
01750 case SouthWestGravity:
01751 case SouthGravity:
01752 corner = BottomLeft;
01753 break;
01754 case SouthEastGravity:
01755 corner = BottomRight;
01756 break;
01757 default:
01758 corner = TopLeft;
01759 }
01760
01761
01762 if (e.value_mask & (CWX | CWY)) {
01763 int x = (e.value_mask & CWX) ? e.x : _area.x();
01764 int y = (e.value_mask & CWY) ? e.y : _area.y();
01765 internal_resize(corner, w, h, false, x, y);
01766 } else
01767 internal_resize(corner, w, h, false);
01768 } else if (e.value_mask & (CWX | CWY)) {
01769 int x = (e.value_mask & CWX) ? e.x : _area.x();
01770 int y = (e.value_mask & CWY) ? e.y : _area.y();
01771 internal_move(x, y);
01772 }
01773
01774 if (e.value_mask & CWStackMode) {
01775 switch (e.detail) {
01776 case Below:
01777 case BottomIf:
01778 openbox->screen(_screen)->lowerWindow(this);
01779 break;
01780
01781 case Above:
01782 case TopIf:
01783 default:
01784 openbox->screen(_screen)->raiseWindow(this);
01785 break;
01786 }
01787 }
01788 }
01789
01790
01791 void Client::unmapHandler(const XUnmapEvent &e)
01792 {
01793 if (ignore_unmaps) {
01794 #ifdef DEBUG
01795
01796 #endif // DEBUG
01797 ignore_unmaps--;
01798 return;
01799 }
01800
01801 #ifdef DEBUG
01802 printf("UnmapNotify for 0x%lx\n", e.window);
01803 #endif // DEBUG
01804
01805 otk::EventHandler::unmapHandler(e);
01806
01807
01808 openbox->screen(_screen)->unmanageWindow(this);
01809 }
01810
01811
01812 void Client::destroyHandler(const XDestroyWindowEvent &e)
01813 {
01814 #ifdef DEBUG
01815 printf("DestroyNotify for 0x%lx\n", e.window);
01816 #endif // DEBUG
01817
01818 otk::EventHandler::destroyHandler(e);
01819
01820
01821 openbox->screen(_screen)->unmanageWindow(this);
01822 }
01823
01824
01825 void Client::reparentHandler(const XReparentEvent &e)
01826 {
01827
01828 if (e.parent == frame->plate()) return;
01829
01830 #ifdef DEBUG
01831 printf("ReparentNotify for 0x%lx\n", e.window);
01832 #endif // DEBUG
01833
01834 otk::EventHandler::reparentHandler(e);
01835
01836
01837
01838
01839
01840
01841
01842
01843
01844
01845 XEvent ev;
01846 ev.xreparent = e;
01847 XPutBackEvent(**otk::display, &ev);
01848
01849
01850 openbox->screen(_screen)->unmanageWindow(this);
01851 }
01852
01853 void Client::mapRequestHandler(const XMapRequestEvent &e)
01854 {
01855 #ifdef DEBUG
01856 printf("MapRequest for already managed 0x%lx\n", e.window);
01857 #endif // DEBUG
01858
01859 assert(_iconic);
01860
01861
01862 setDesktop(openbox->screen(_screen)->desktop());
01863
01864 }
01865
01866 }