X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fclient.cc;h=e626081ce19e871a2fe37e25653f5f257ee69ed0;hb=d011a51039c4c4f4cf81db5f086a0fff192157b3;hp=0fd5787b8669be2c2b92a88532731108089ccc4e;hpb=1fa445c88033e564a25d907a7f478e76bff9e89e;p=chaz%2Fopenbox diff --git a/src/client.cc b/src/client.cc index 0fd5787b..e626081c 100644 --- a/src/client.cc +++ b/src/client.cc @@ -6,6 +6,7 @@ #include "client.hh" #include "frame.hh" +#include "screen.hh" #include "bbscreen.hh" #include "openbox.hh" #include "otk/display.hh" @@ -25,13 +26,12 @@ namespace ob { OBClient::OBClient(int screen, Window window) : otk::OtkEventHandler(), - _screen(screen), _window(window) + OBWidget(OBWidget::Type_Client), + frame(0), _screen(screen), _window(window) { assert(screen >= 0); assert(window); - Openbox::instance->registerHandler(_window, this); - ignore_unmaps = 0; // update EVERYTHING the first time!! @@ -40,6 +40,8 @@ OBClient::OBClient(int screen, Window window) _wmstate = NormalState; // no default decors or functions, each has to be enabled _decorations = _functions = 0; + // start unfocused + _focused = false; getArea(); getDesktop(); @@ -372,6 +374,7 @@ void OBClient::updateNormalHints() { XSizeHints size; long ret; + int oldgravity = _gravity; // defaults _gravity = NorthWestGravity; @@ -389,7 +392,7 @@ void OBClient::updateNormalHints() if (size.flags & PWinGravity) _gravity = size.win_gravity; - + if (size.flags & PMinSize) _min_size.setPoint(size.min_width, size.min_height); @@ -402,6 +405,15 @@ void OBClient::updateNormalHints() if (size.flags & PResizeInc) _size_inc.setPoint(size.width_inc, size.height_inc); } + + // if the client has a frame, i.e. has already been mapped and is + // changing its gravity + if (frame && _gravity != oldgravity) { + // move our idea of the client's position based on its new gravity + int x, y; + frame->frameGravity(x, y); + _area.setPos(x, y); + } } @@ -450,6 +462,9 @@ void OBClient::updateTitle() if (_title.empty()) _title = _("Unnamed Window"); + + if (frame) + frame->setTitle(_title); } @@ -652,6 +667,53 @@ void OBClient::setState(StateAction action, long data1, long data2) } +void OBClient::toggleClientBorder(bool addborder) +{ + // adjust our idea of where the client is, based on its border. When the + // border is removed, the client should now be considered to be in a + // different position. + // when re-adding the border to the client, the same operation needs to be + // reversed. + int x = _area.x(), y = _area.y(); + switch(_gravity) { + case NorthWestGravity: + case WestGravity: + case SouthWestGravity: + break; + case NorthEastGravity: + case EastGravity: + case SouthEastGravity: + if (addborder) x -= _border_width * 2; + else x += _border_width * 2; + break; + } + switch(_gravity) { + case NorthWestGravity: + case NorthGravity: + case NorthEastGravity: + break; + case SouthWestGravity: + case SouthGravity: + case SouthEastGravity: + if (addborder) y -= _border_width * 2; + else y += _border_width * 2; + break; + default: + // no change for StaticGravity etc. + break; + } + _area.setPos(x, y); + + if (addborder) { + XSetWindowBorderWidth(otk::OBDisplay::display, _window, _border_width); + + // move the client so it is back it the right spot _with_ its border! + XMoveWindow(otk::OBDisplay::display, _window, x, y); + } else + XSetWindowBorderWidth(otk::OBDisplay::display, _window, 0); +} + + void OBClient::clientMessageHandler(const XClientMessageEvent &e) { otk::OtkEventHandler::clientMessageHandler(e); @@ -717,6 +779,11 @@ void OBClient::resize(Corner anchor, int w, int h) w -= _base_size.x(); h -= _base_size.y(); + // for interactive resizing. have to move half an increment in each + // direction. + w += _size_inc.x() / 2; + h += _size_inc.y() / 2; + // is the window resizable? if it is not, then don't check its sizes, the // client can do what it wants and the user can't change it anyhow if (_min_size.x() <= _max_size.x() && _min_size.y() <= _max_size.y()) { @@ -739,26 +806,29 @@ void OBClient::resize(Corner anchor, int w, int h) w += _base_size.x(); h += _base_size.y(); - + + int x = _area.x(), y = _area.y(); switch (anchor) { case TopLeft: break; case TopRight: - _area.setX(_area.x() - _area.width() - w); + x -= w - _area.width(); break; case BottomLeft: - _area.setY(_area.y() - _area.height() - h); + y -= h - _area.height(); break; case BottomRight: - _area.setX(_area.x() - _area.width() - w); - _area.setY(_area.y() - _area.height() - h); + x -= w - _area.width(); + y -= h - _area.height(); break; } _area.setSize(w, h); + XResizeWindow(otk::OBDisplay::display, _window, w, h); - // resize the frame to match - frame->adjust(); + // resize the frame to match the request + frame->adjustSize(); + move(x, y); } @@ -766,12 +836,93 @@ void OBClient::move(int x, int y) { _area.setPos(x, y); // move the frame to be in the requested position - frame->applyGravity(); + frame->adjustPosition(); +} + + +void OBClient::close() +{ + XEvent ce; + const otk::OBProperty *property = Openbox::instance->property(); + + if (!(_functions & Func_Close)) return; + + // XXX: itd be cool to do timeouts and shit here for killing the client's + // process off + + ce.xclient.type = ClientMessage; + ce.xclient.message_type = property->atom(otk::OBProperty::wm_protocols); + ce.xclient.display = otk::OBDisplay::display; + ce.xclient.window = _window; + ce.xclient.format = 32; + ce.xclient.data.l[0] = property->atom(otk::OBProperty::wm_delete_window); + ce.xclient.data.l[1] = CurrentTime; + ce.xclient.data.l[2] = 0l; + ce.xclient.data.l[3] = 0l; + ce.xclient.data.l[4] = 0l; + XSendEvent(otk::OBDisplay::display, _window, False, NoEventMask, &ce); +} + + +bool OBClient::focus() +{ + if (!_can_focus || _focused) return false; + + XSetInputFocus(otk::OBDisplay::display, _window, RevertToNone, CurrentTime); + return true; +} + + +void OBClient::unfocus() +{ + if (!_focused) return; + + assert(Openbox::instance->focusedClient() == this); + Openbox::instance->setFocusedClient(0); +} + + +void OBClient::focusHandler(const XFocusChangeEvent &e) +{ +#ifdef DEBUG + printf("FocusIn for 0x%lx\n", e.window); +#endif // DEBUG + + OtkEventHandler::focusHandler(e); + + frame->focus(); + _focused = true; + + Openbox::instance->setFocusedClient(this); +} + + +void OBClient::unfocusHandler(const XFocusChangeEvent &e) +{ +#ifdef DEBUG + printf("FocusOut for 0x%lx\n", e.window); +#endif // DEBUG + + OtkEventHandler::unfocusHandler(e); + + frame->unfocus(); + _focused = false; + + if (Openbox::instance->focusedClient() == this) { + printf("UNFOCUSED!\n"); + Openbox::instance->setFocusedClient(this); + } } void OBClient::configureRequestHandler(const XConfigureRequestEvent &e) { +#ifdef DEBUG + printf("ConfigureRequest for 0x%lx\n", e.window); +#endif // DEBUG + + OtkEventHandler::configureRequestHandler(e); + // XXX: if we are iconic (or shaded? (fvwm does that)) ignore the event if (e.value_mask & CWBorderWidth) @@ -825,4 +976,57 @@ void OBClient::configureRequestHandler(const XConfigureRequestEvent &e) } +void OBClient::unmapHandler(const XUnmapEvent &e) +{ +#ifdef DEBUG + printf("UnmapNotify for 0x%lx\n", e.window); +#endif // DEBUG + + if (ignore_unmaps) { + ignore_unmaps--; + return; + } + + OtkEventHandler::unmapHandler(e); + + // this deletes us etc + Openbox::instance->screen(_screen)->unmanageWindow(this); +} + + +void OBClient::destroyHandler(const XDestroyWindowEvent &e) +{ +#ifdef DEBUG + printf("DestroyNotify for 0x%lx\n", e.window); +#endif // DEBUG + + OtkEventHandler::destroyHandler(e); + + // this deletes us etc + Openbox::instance->screen(_screen)->unmanageWindow(this); +} + + +void OBClient::reparentHandler(const XReparentEvent &e) +{ + // this is when the client is first taken captive in the frame + if (e.parent == frame->plate()) return; + +#ifdef DEBUG + printf("ReparentNotify for 0x%lx\n", e.window); +#endif // DEBUG + + OtkEventHandler::reparentHandler(e); + + /* + This event is quite rare and is usually handled in unmapHandler. + However, if the window is unmapped when the reparent event occurs, + the window manager never sees it because an unmap event is not sent + to an already unmapped window. + */ + + // this deletes us etc + Openbox::instance->screen(_screen)->unmanageWindow(this); +} + }