/* Window.cc Copyright © 2003 David Reveman. This file is part of Waimea. Waimea is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. Waimea is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Waimea; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H # include "../config.h" #endif // HAVE_CONFIG_H extern "C" { #ifdef HAVE_STDIO_H # include #endif // HAVE_STDIO_H #ifdef STDC_HEADERS # include #endif // STDC_HEADERS #ifdef LIMITS_H # include #endif // LIMITS_H } #include "Window.hh" WaWindow::WaWindow(Window win_id, WaScreen *scrn) : AWindowObject(NULL, win_id, WindowType, NULL, "client") { XWindowAttributes init_attrib; XSetWindowAttributes attrib_set; ws = scrn; display = ws->display; screen_number = ws->screen_number; waimea = ws->waimea; net = waimea->net; wm_strut = NULL; move_resize = false; name = WA_STRDUP(""); wclass = WA_STRDUP(""); wclassname = WA_STRDUP(""); host = WA_STRDUP(""); pid = WA_STRDUP(""); realnamelen = 0; master = NULL; init_done = remap = outline_state = false; window_group = (Window) 0; transient_for = (Window) 0; wm_icon_image = wm_icon_svg = NULL; protocol_mask = 0; input_field = true; urgent = false; functions = FunctionAllMask; pending_unmaps = 0; attrib_set.event_mask = PropertyChangeMask | StructureNotifyMask | FocusChangeMask | EnterWindowMask | LeaveWindowMask; attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask | ButtonMotionMask; init_attrib.border_width = 0; init_attrib.colormap = ws->colormap; init_attrib.win_gravity = NorthWestGravity; init_attrib.x = 0; init_attrib.y = 0; init_attrib.width = 1; init_attrib.height = 1; XChangeWindowAttributes(display, id, CWEventMask | CWDontPropagate, &attrib_set); XGetWindowAttributes(display, id, &init_attrib); XSetWindowBorderWidth(display, id, 0); old_bw = init_attrib.border_width; attrib.colormap = init_attrib.colormap; size.win_gravity = init_attrib.win_gravity; attrib.x = init_attrib.x; attrib.y = init_attrib.y; attrib.width = init_attrib.width; attrib.height = init_attrib.height; want_focus = mapped = dontsend = deleted = hidden = false; desktop_mask = (1L << ws->current_desktop->number); top_spacing = bottom_spacing = left_spacing = right_spacing = 0; has_focus = mergedback = false; wstate = StateFocusableMask | StateTasklistMask | StateDecorTitleMask | StateDecorBorderMask | StateDecorHandlesMask | StateDecorAllMask | StateUserTimeMask; old_wstate = wstate; decormask = DecorAllMask; transient_for = (Window) 0; mergemode = NullMergeType; frame = NULL; net->getWMProtocols(this); net->getClassHint(this); if (! net->getNetName(this)) net->getXaName(this); net->getWMClientMachineHint(this); net->getWmPid(this); char namechar_tmp = name[realnamelen]; name[realnamelen] = '\0'; char window_id_str[32]; snprintf(window_id_str, 32, "0x%lx", id); rid = WA_STRDUP(window_id_str); WaStringMap *sm = new WaStringMap(); sm->add(WindowIDName, name); sm->add(WindowIDClassName, wclassname); sm->add(WindowIDClass, wclass); sm->add(WindowIDPID, pid); sm->add(WindowIDHost, host); sm->add(WindowIDWinID, rid); resetActionList(sm); frame = new WaFrameWindow(this, sm->ref()); #ifdef SHAPE shaped = false; shapeinfo = new ShapeInfo(id); frame->addShapeInfo(shapeinfo); #endif // SHAPE frame->commonStyleUpdate(); name[realnamelen] = namechar_tmp; waimea->window_table.insert(make_pair(id, this)); if (deleted) goto window_create_end; net->getWMHints(this); net->getWMNormalHints(this); initPosition(); net->getTransientForHint(this); net->getWmState(this); net->getMWMHints(this); net->getWmType(this); net->getWmIconImage(this); net->getWmIconSvg(this); net->getVirtualPos(this); net->getWmStrut(this); net->getDesktop(this); net->setDesktop(this); net->setDesktopMask(this); calcSpacing(); gravitate(ApplyGravity); reparentWin(); updateGrabs(); if (deleted) goto window_create_end; updateAllAttributes(); if (wstate & StateShadedMask) shade(); ws->wawindow_list.push_back(this); ws->wawindow_list_map_order.push_back(this); if (! (wstate & (StateAlwaysOnTopMask | StateAlwaysAtBottomMask))) frame->setStacking(NormalStackingType); ws->raiseWindow(frame->id); net->setAllowedActions(this); net->sendNotify(this, CreateWindowNotify); net->setWmState(this); window_create_end: init_done = true; drawDecor(); windowStateCheck(); } WaWindow::~WaWindow(void) { explode(); if (master) master->unmerge(this); XEvent ev; waimea->window_table.erase(id); if (! waimea->running) remap = true; if (wm_icon_image) wm_icon_image->unref(); if (wm_icon_svg) wm_icon_svg->unref(); net->sendNotify(this, DestroyWindowNotify); withdrawTransient(); gravitate(RemoveGravity); if (wstate & StateShadedMask) attrib.height = restore_shade; if (attrib.x >= (int) ws->width) attrib.x = attrib.x % ws->width; if (attrib.y >= (int) ws->height) attrib.y = attrib.y % ws->height; if (attrib.x + attrib.width <= 0) attrib.x = ws->width + (attrib.x % ws->width); if (attrib.y + attrib.height <= 0) attrib.y = ws->height + (attrib.y % ws->height); if ((! deleted) && validate_window_mapped(id)) { XChangeSaveSet(display, id, SetModeDelete); XSelectInput(display, id, NoEventMask); XSelectInput(display, frame->id, NoEventMask); XUnmapWindow(display, frame->id); XUnmapWindow(display, id); XSetWindowBorderWidth(display, id, old_bw); if (XCheckTypedWindowEvent(display, id, ReparentNotify, &ev)) remap = true; else XReparentWindow(display, id, ws->id, attrib.x, attrib.y); if (remap) XMapWindow(display, id); net->removeAllowedActions(this); net->removeVisibleName(this); } ws->smartNameRemove(this); delete [] name; delete [] wclass; delete [] wclassname; delete [] host; delete [] pid; delete [] rid; ws->wawindow_list.remove(this); ws->wawindow_list_map_order.remove(this); if (wm_strut) { ws->strut_list.remove(wm_strut); delete wm_strut; if (! ws->shutdown) ws->updateWorkarea(); } #ifdef SHAPE frame->removeShapeInfo(shapeinfo); delete shapeinfo; #endif // SHAPE delete frame; waimea->removeFromFocusHistory(id); if (! ws->shutdown) { if (has_focus) waimea->focusRevertFrom(ws, id); ws->net->setClientList(ws); ws->net->setClientListStacking(ws); } } void WaWindow::withdrawTransient(void) { if (transient_for) { if (transient_for == ws->id) { list::iterator it = ws->wawindow_list.begin(); for (; it != ws->wawindow_list.end(); ++it) if ((*it) != this) (*it)->transients.remove(id); } else { WaWindow *transfor = (WaWindow *) waimea->findWin(transient_for, WindowType); if (transfor) transfor->transients.remove(id); else if (window_group) { list::iterator it = ws->wawindow_list.begin(); for (;it != ws->wawindow_list.end(); ++it) { if ((*it) != this && (*it)->window_group == window_group && (*it)->transient_for == (Window) 0) (*it)->transients.remove(id); } } } } transient_for = (Window) 0; } void WaWindow::calcSpacing(void) { double _top_spacing, _bottom_spacing,_left_spacing, _right_spacing; calc_length(frame->style->top_spacing, frame->style->top_spacing_u, ws->vdpi, ws->height, &_top_spacing); calc_length(frame->style->bottom_spacing, frame->style->bottom_spacing_u, ws->vdpi, ws->height, &_bottom_spacing); calc_length(frame->style->left_spacing, frame->style->left_spacing_u, ws->hdpi, ws->width, &_left_spacing); calc_length(frame->style->right_spacing, frame->style->right_spacing_u, ws->hdpi, ws->width, &_right_spacing); top_spacing = WA_ROUND_U(_top_spacing); bottom_spacing = WA_ROUND_U(_bottom_spacing); left_spacing = WA_ROUND_U(_left_spacing); right_spacing = WA_ROUND_U(_right_spacing); } void WaWindow::gravitate(int multiplier) { switch (size.win_gravity) { case NorthWestGravity: attrib.x += multiplier * (left_spacing + right_spacing); case NorthEastGravity: attrib.x -= multiplier * right_spacing; case NorthGravity: attrib.y += multiplier * top_spacing; break; case SouthWestGravity: attrib.x += multiplier * (left_spacing + right_spacing); case SouthEastGravity: attrib.x -= multiplier * right_spacing; case SouthGravity: attrib.y -= multiplier * bottom_spacing; break; case CenterGravity: attrib.x += multiplier * ((left_spacing + right_spacing) / 2); attrib.y += multiplier * ((top_spacing + bottom_spacing) / 2); break; case WestGravity: attrib.x += multiplier * left_spacing; break; case EastGravity: attrib.x -= multiplier * right_spacing; case StaticGravity: break; } } void WaWindow::initPosition(void) { if (size.min_width > attrib.width) attrib.width = size.min_width; if (size.min_height > attrib.height) attrib.height = size.min_height; restore_max.x = attrib.x; restore_max.y = attrib.y; restore_max.width = attrib.width; restore_shade = restore_max.height = attrib.height; restore_max.misc0 = restore_max.misc1 = 0; old_attrib.x = old_attrib.y = INT_MIN; old_attrib.height = old_attrib.width = INT_MAX; } void WaWindow::mapWindow(void) { if (deleted) return; XMapWindow(display, id); if (desktop_mask & (1L << ws->current_desktop->number)) { if (! master) frame->mapRequest = true; } else { hidden = true; } mapped = true; } void WaWindow::show(void) { if ((! (wstate & StateMinimizedMask)) && hidden && mapped && (! master)) { XMapWindow(display, id); frame->mapRequest = true; hidden = false; frame->pushRenderEvent(); } } void WaWindow::hide(void) { if (! hidden) { if (has_focus) waimea->focusRevertFrom(ws, id); XUnmapWindow(display, frame->id); XUnmapWindow(display, id); pending_unmaps++; hidden = true; } } void WaWindow::updateAllAttributes(void) { if (master) { master->updateAllAttributes(); return; } old_attrib.x = old_attrib.y = INT_MIN; old_attrib.height = old_attrib.width = INT_MAX; gravitate(RemoveGravity); calcSpacing(); gravitate(ApplyGravity); XMoveWindow(display, id, left_spacing, top_spacing); #ifdef SHAPE frame->apply_shape = false; shapeinfo->setShapeOffset(left_spacing, top_spacing); frame->shapeUpdateNotify(); #endif // SHAPE int m_x, m_y, m_w, m_h; if (wstate & StateMaximizedMask) { m_x = restore_max.x; m_y = restore_max.y; m_w = restore_max.width; m_h = restore_max.height; wstate &= ~StateMaximizedMask; _maximize(restore_max.misc0, restore_max.misc1); restore_max.x = m_x; restore_max.y = m_y; restore_max.width = m_w; restore_max.height = m_h; } else redrawWindow(); } void WaWindow::redrawWindow(bool force_if_viewable) { if (master) { sendcf = false; master->redrawWindow(force_if_viewable); if (! sendcf) { net->setVirtualPos(this); sendConfig(); } return; } bool move = false, resizew = false, resizeh = false; if (old_attrib.x != attrib.x) { frame->attrib.x = attrib.x - left_spacing; old_attrib.x = attrib.x; move = true; } if (old_attrib.y != attrib.y) { frame->attrib.y = attrib.y - top_spacing; old_attrib.y = attrib.y; move = true; } if (old_attrib.width != attrib.width) { frame->attrib.width = left_spacing + attrib.width + right_spacing; old_attrib.width = attrib.width; list::iterator it = merged.begin(); for (; it != merged.end(); it++) { if ((*it)->mergetype == VertMergeType) frame->attrib.width += (*it)->attrib.width; } resizew = true; } if (old_attrib.height != attrib.height) { frame->attrib.height = top_spacing + attrib.height + bottom_spacing; if (! (wstate & StateShadedMask)) { list::iterator it = merged.begin(); for (; it != merged.end(); it++) { if ((*it)->attrib.height < 1) (*it)->attrib.height = 1; if ((*it)->mergetype == HorizMergeType) frame->attrib.height += (*it)->attrib.height; } } old_attrib.height = attrib.height; resizeh = true; } if (move) { if (wstate & StateMaximizedMask) { restore_max.misc0 = ws->v_x + frame->attrib.x; restore_max.misc1 = ws->v_y + frame->attrib.y; net->setWmState(this); } if (! (resizew || resizeh)) XMoveWindow(display, frame->id, frame->attrib.x, frame->attrib.y); } if ((wstate & StateMaximizedMask) && (resizew || (resizeh && (! (wstate & StateShadedMask))))) { wstate &= ~StateMaximizedMask; net->setWmState(this); } if (resizew || resizeh) { if (wstate & StateShadedMask) XResizeWindow(display, id, attrib.width, restore_shade); else XResizeWindow(display, id, attrib.width, attrib.height); XMoveResizeWindow(display, frame->id, frame->attrib.x, frame->attrib.y, frame->attrib.width, frame->attrib.height); #ifdef SHAPE XResizeWindow(display, frame->apply_shape_buffer, frame->attrib.width, frame->attrib.height); if (! shaped) { frame->apply_shape = false; frame->shapeUpdateNotify(); } #endif // SHAPE if (! (wstate & StateShadedMask)) { int cx = left_spacing + attrib.width; int cy = top_spacing + attrib.height; list::iterator mit = merged.begin(); for (; mit != merged.end(); mit++) { Window wd; switch ((*mit)->mergetype) { case VertMergeType: (*mit)->attrib.height = cy - top_spacing; XMoveResizeWindow(display, (*mit)->id, cx, top_spacing, (*mit)->attrib.width, (*mit)->attrib.height); cx += (*mit)->attrib.width; XTranslateCoordinates(display, (*mit)->id, ws->id, 0, 0, &(*mit)->attrib.x, &(*mit)->attrib.y, &wd); break; case HorizMergeType: if (! (wstate & StateShadedMask)) { (*mit)->attrib.width = cx - left_spacing; XMoveResizeWindow(display, (*mit)->id, left_spacing, cy, (*mit)->attrib.width, (*mit)->attrib.height); cy += (*mit)->attrib.height; XTranslateCoordinates(display, (*mit)->id, ws->id, 0, 0, &(*mit)->attrib.x, &(*mit)->attrib.y, &wd); } break; case CloneMergeType: (*mit)->attrib.width = attrib.width; (*mit)->attrib.height = attrib.height; XMoveResizeWindow(display, (*mit)->id, left_spacing, top_spacing, (*mit)->attrib.width, (*mit)->attrib.height); XTranslateCoordinates(display, (*mit)->id, ws->id, 0, 0, &(*mit)->attrib.x, &(*mit)->attrib.y, &wd); } } } } if ((move || resizew || resizeh) && (! (wstate & StateShadedMask)) && (! dontsend)) { net->setVirtualPos(this); if ((! resizew) && (! resizeh)) sendConfig(); } drawDecor(); } void WaWindow::reparentWin(void) { XSetWindowAttributes attrib_set; attrib_set.event_mask = PropertyChangeMask | StructureNotifyMask | FocusChangeMask | EnterWindowMask | LeaveWindowMask; attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask | ButtonMotionMask; if (validate_window_mapped(id)) { XSelectInput(display, id, NoEventMask); XReparentWindow(display, id, frame->id, left_spacing, top_spacing); XChangeSaveSet(display, id, SetModeInsert); XFlush(display); XChangeWindowAttributes(display, id, CWEventMask | CWDontPropagate, &attrib_set); #ifdef SHAPE XRectangle *dummy = NULL; int n, order; if (waimea->shape) { XShapeSelectInput(display, id, ShapeNotifyMask); dummy = XShapeGetRectangles(display, id, ShapeBounding, &n, &order); if (n > 1) { shaped = true; } } XFree(dummy); if (shaped) { shapeinfo->setShapeOffset(attrib.x, attrib.y); frame->shapeUpdateNotify(); } else { shapeinfo->setShapeOffset(attrib.x, attrib.y); frame->shapeUpdateNotify(); } #endif // SHAPE } } void WaWindow::updateGrabs(void) { XUngrabButton(display, AnyButton, AnyModifier, id); XUngrabKey(display, AnyKey, AnyModifier, id); ActionList *al = actionlists[ STATE_FROM_MASK_AND_LIST(window_state_mask, actionlists)]; list::iterator it = al->actionlist.begin(); for (; it != al->actionlist.end(); ++it) { if ((*it)->type == ButtonPress || (*it)->type == ButtonRelease || (*it)->type == DoubleClick) { XGrabButton(display, (*it)->detail ? (*it)->detail: AnyButton, AnyModifier, id, true, ButtonPressMask | ButtonReleaseMask | ButtonMotionMask, GrabModeSync, GrabModeSync, None, None); } else if ((*it)->type == KeyPress || (*it)->type == KeyRelease) { XGrabKey(display, (*it)->detail ? (*it)->detail: AnyKey, AnyModifier, id, true, GrabModeSync, GrabModeSync); } } } #ifdef SHAPE void WaWindow::shapeEvent(void) { WaFrameWindow *real_frame; if (master) real_frame = master->frame; else real_frame = frame; real_frame->shapeUpdateNotify(); } #endif // SHAPE void WaWindow::sendConfig(void) { XConfigureEvent ce; ce.type = ConfigureNotify; ce.event = id; ce.window = id; ce.x = attrib.x; ce.y = attrib.y; ce.width = attrib.width; ce.border_width = old_bw; ce.override_redirect = false; if (master) ce.above = master->frame->id; else ce.above = frame->id; if (wstate & StateShadedMask) ce.height = restore_shade; else ce.height = attrib.height; sendcf = true; XSendEvent(display, id, false, StructureNotifyMask, (XEvent *) &ce); XSendEvent(display, ws->id, false, StructureNotifyMask, (XEvent *) &ce); list::iterator mit = merged.begin(); for (; mit != merged.end(); mit++) (*mit)->sendConfig(); XFlush(display); } void WaWindow::drawOutline(int x, int y, int width, int height) { if (outline_state) clearOutline(); outline_state = true; outl_x = x - left_spacing; outl_y = y - top_spacing; outl_w = width + left_spacing + right_spacing; outl_h = height + top_spacing + bottom_spacing; XDrawRectangle(display, ws->id, ws->xor_gc, outl_x, outl_y, outl_w, outl_h); } void WaWindow::clearOutline(void) { if (! outline_state) return; outline_state = false; XDrawRectangle(display, ws->id, ws->xor_gc, outl_x, outl_y, outl_w, outl_h); } void WaWindow::drawDecor(void) { if (! init_done) return; #ifdef SHAPE frame->apply_shape = false; #endif // SHAPE frame->pushRenderEvent(); } bool WaWindow::incSizeCheck(int width, int height, unsigned int *n_w, unsigned int *n_h) { bool resize = false; if (size.max_width > size.min_width || size.max_height > size.min_height) { if (width < (int) size.min_width) width = size.min_width; if (height > 0 && height < (int) size.min_height) height = size.min_height; if (width > (int) size.max_width) width = size.max_width; if (height > (int) size.max_height) height = size.max_height; } *n_w = attrib.width; *n_h = attrib.height; if ((width >= (int) (attrib.width + size.width_inc)) || (width <= (int) (attrib.width - size.width_inc)) || (int) attrib.width == width) { if (width >= (int) size.min_width && width <= (int) size.max_width) { resize = true; if (size.width_inc == 1) *n_w = width; else *n_w = width - ((width - size.base_width) % size.width_inc); } } if ((height == 0) && top_spacing) { if (! (wstate & StateShadedMask)) { wstate |= StateShadedMask; restore_shade = attrib.height; net->setWmState(this); } *n_h = 0; return resize; } if ((height >= (int) (attrib.height + size.height_inc)) || (height <= (int) (attrib.height - size.height_inc)) || (int) attrib.height == height) { if ((height < 1) && (size.min_height <= 1) && top_spacing) { resize = true; height = 0; if (! (wstate & StateShadedMask)) { wstate |= StateShadedMask; restore_shade = attrib.height; net->setWmState(this); } *n_h = height; } else if (height > 0 && (height >= (int) size.min_height && height <= (int) size.max_height)) { resize = true; if (wstate & StateShadedMask) { wstate &= ~StateShadedMask; net->setWmState(this); } if (size.height_inc == 1) *n_h = height; else *n_h = height - ((height - size.base_height) % size.height_inc); } } if (resize && size.aspect) { if (size.base_size) { *n_w -= size.base_width; *n_h -= size.base_height; } double aspect = (double) *n_w / (double) *n_h; if (aspect < size.min_aspect) *n_w = (unsigned int) ((double) *n_h * size.min_aspect); else if (aspect > size.max_aspect) *n_h = (unsigned int) ((double) *n_w / size.max_aspect); if (size.base_size) { *n_w += size.base_width; *n_h += size.base_height; } } return resize; } void WaWindow::raise(void) { if (master) { master->raise(); return; } else { list::iterator it = merged.begin(); for (; it != merged.end(); it++) ws->raiseWindow((*it)->frame->id, false); } ws->raiseWindow(frame->id, false); ws->restackWindows(); net->setClientListStacking(ws); net->sendNotify(this, RaiseNotify); } void WaWindow::lower(void) { if (master) { master->lower(); return; } else { list::iterator it = merged.begin(); for (; it != merged.end(); it++) ws->lowerWindow((*it)->frame->id, false); } ws->lowerWindow(frame->id, false); ws->restackWindows(); net->setClientListStacking(ws); net->sendNotify(this, LowerNotify); } void WaWindow::move(XEvent *e) { WaWindow *w; XEvent event, *map_ev; int px, py, nx, ny, i; list *maprequest_list; Window wd; unsigned int ui; if (! (functions & FunctionMoveMask)) return; if (master) w = master; else w = this; XQueryPointer(display, ws->id, &wd, &wd, &px, &py, &i, &i, &ui); if (waimea->eh->move_resize != EndMoveResizeType) return; nx = w->attrib.x; ny = w->attrib.y; waimea->eh->move_resize = MoveType; setWindowState(wstate | StateMoveMask); move_resize = true; Window grab_window = frame->id; Cursor grab_cursor; DWindowObject *dwo = (DWindowObject *) waimea->findWin(e->xany.window, ANY_DECOR_WINDOW_TYPE); if (dwo) grab_cursor = dwo->sb->style->cursor; else grab_cursor = None; if (e && e->type == MapRequest) { nx = w->attrib.x = px + left_spacing; ny = w->attrib.y = py + top_spacing; drawOutline(nx, ny, w->attrib.width, w->attrib.height); } maprequest_list = new list; if (XGrabPointer(display, grab_window, true, ButtonReleaseMask | ButtonPressMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask, GrabModeAsync, GrabModeAsync, None, grab_cursor, CurrentTime) != GrabSuccess) { move_resize = false; waimea->eh->move_resize = EndMoveResizeType; setWindowState(wstate & ~StateMoveMask); delete maprequest_list; return; } if (XGrabKeyboard(display, grab_window, true, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) { move_resize = false; waimea->eh->move_resize = EndMoveResizeType; setWindowState(wstate & ~StateMoveMask); XUngrabPointer(display, CurrentTime); delete maprequest_list; return; } for (;;) { waimea->eh->eventLoop(&waimea->eh->moveresize_return_mask, &event); switch (event.type) { case MotionNotify: while (XCheckTypedWindowEvent(display, event.xmotion.window, MotionNotify, &event)); nx += event.xmotion.x_root - px; ny += event.xmotion.y_root - py; px = event.xmotion.x_root; py = event.xmotion.y_root; w->drawOutline(nx, ny, w->attrib.width, w->attrib.height); break; case LeaveNotify: case EnterNotify: if (ws->west->id == event.xcrossing.window || ws->east->id == event.xcrossing.window || ws->north->id == event.xcrossing.window || ws->south->id == event.xcrossing.window) { clearOutline(); waimea->eh->handleEvent(&event); w->drawOutline(nx, ny, w->attrib.width, w->attrib.height); } else if (event.type == LeaveNotify) { int cx, cy; XQueryPointer(display, ws->id, &wd, &wd, &cx, &cy, &i, &i, &ui); nx += cx - px; ny += cy - py; px = cx; py = cy; w->drawOutline(nx, ny, w->attrib.width, w->attrib.height); } break; case DestroyNotify: case UnmapNotify: if ((((event.type == UnmapNotify)? event.xunmap.window: event.xdestroywindow.window) == w->id)) { while (! maprequest_list->empty()) { XPutBackEvent(display, maprequest_list->front()); delete maprequest_list->front(); maprequest_list->pop_front(); } delete maprequest_list; XPutBackEvent(display, &event); w->clearOutline(); XUngrabKeyboard(display, CurrentTime); XUngrabPointer(display, CurrentTime); waimea->eh->move_resize = EndMoveResizeType; setWindowState(wstate & ~StateMoveMask); move_resize = false; return; } waimea->eh->evUnmapDestroy(&event); break; case ConfigureRequest: if (event.xconfigurerequest.window != id) waimea->eh->evConfigureRequest(&event.xconfigurerequest); break; case MapRequest: map_ev = new XEvent; *map_ev = event; maprequest_list->push_front(map_ev); break; case ButtonPress: case ButtonRelease: event.xbutton.window = w->id; case KeyPress: case KeyRelease: if (event.type == KeyPress || event.type == KeyRelease) event.xkey.window = w->id; w->clearOutline(); waimea->eh->handleEvent(&event); w->drawOutline(nx, ny, attrib.width, attrib.height); if (waimea->eh->move_resize != EndMoveResizeType) break; setWindowState(wstate & ~StateMoveMask); w->clearOutline(); w->attrib.x = nx; w->attrib.y = ny; w->redrawWindow(); checkMoveMerge(w->attrib.x, w->attrib.y); while (! maprequest_list->empty()) { XPutBackEvent(display, maprequest_list->front()); delete maprequest_list->front(); maprequest_list->pop_front(); } delete maprequest_list; move_resize = false; XUngrabKeyboard(display, CurrentTime); XUngrabPointer(display, CurrentTime); return; } } } void WaWindow::moveOpaque(XEvent *e) { int px, py, prelx, prely, i; int sw = attrib.width; int sh = attrib.height; unsigned int ui; Window wd; XEvent ed; list maprequest_list; if (! (functions & FunctionMoveMask)) return; XQueryPointer(display, ws->id, &wd, &wd, &px, &py, &i, &i, &ui); prelx = px - attrib.x; prely = py - attrib.y; int pposx = px; int pposy = py; for (;;) { bool status = _moveOpaque(e, sw, sh, pposx, pposy, &maprequest_list); if (! status) return; XQueryPointer(display, ws->id, &wd, &wd, &px, &py, &i, &i, &ui); pposx = attrib.x + prelx; pposy = attrib.y + prely; XWarpPointer(display, None, None, 0, 0, 0, 0, pposx - px, pposy - py); XSync(display, false); while (XCheckTypedEvent(display, MotionNotify, &ed)); while (XCheckTypedEvent(display, EnterNotify, &ed)); while (XCheckTypedEvent(display, LeaveNotify, &ed)); } } bool WaWindow::_moveOpaque(XEvent *e, int saved_w, int saved_h, int px, int py, list *maprequest_list) { WaWindow *w; XEvent event, *map_ev; int sx, sy, nx, ny, mnx, mny; if (master && mergemode == NullMergeType) w = master; else w = this; if (waimea->eh->move_resize != EndMoveResizeType) return false; sx = nx = mnx = attrib.x; sy = ny = mny = attrib.y; waimea->eh->move_resize = MoveOpaqueType; setWindowState(wstate | StateMoveMask); move_resize = true; if (master) { mnx = w->attrib.x; mny = w->attrib.y; } Window grab_window = frame->id; Cursor grab_cursor; DWindowObject *dwo = (DWindowObject *) waimea->findWin(e->xany.window, ANY_DECOR_WINDOW_TYPE); if (dwo) grab_cursor = dwo->sb->style->cursor; else grab_cursor = None; if (e && e->type == MapRequest) { nx = w->attrib.x = px + left_spacing; ny = w->attrib.y = py + top_spacing; w->redrawWindow(); net->setState(this, NormalState); net->setVirtualPos(this); } dontsend = true; if (XGrabPointer(display, grab_window, true, ButtonReleaseMask | ButtonPressMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask, GrabModeAsync, GrabModeAsync, None, grab_cursor, CurrentTime) != GrabSuccess) { move_resize = false; waimea->eh->move_resize = EndMoveResizeType; setWindowState(wstate & ~StateMoveMask); return false; } if (XGrabKeyboard(display, grab_window, true, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) { move_resize = false; waimea->eh->move_resize = EndMoveResizeType; setWindowState(wstate & ~StateMoveMask); XUngrabPointer(display, CurrentTime); return false; } for (;;) { waimea->eh->eventLoop(&waimea->eh->moveresize_return_mask, &event); switch (event.type) { case MotionNotify: while (XCheckTypedWindowEvent(display, event.xmotion.window, MotionNotify, &event)); nx += event.xmotion.x_root - px; ny += event.xmotion.y_root - py; if (master) { mnx += event.xmotion.x_root - px; mny += event.xmotion.y_root - py; } px = event.xmotion.x_root; py = event.xmotion.y_root; if (mergemode != NullMergeType) { if (checkMoveMerge(nx, ny, saved_w, saved_h)) { XSync(display, false); while (XCheckTypedEvent(display, FocusIn, &event)); while (XCheckTypedEvent(display, FocusOut, &event)); dontsend = move_resize = false; waimea->eh->move_resize = EndMoveResizeType; setWindowState(wstate & ~StateMoveMask); return true; } else if (! master) { w->attrib.x = nx; w->attrib.y = ny; w->redrawWindow(); } } else { if (master) { w->attrib.x = mnx; w->attrib.y = mny; } else { w->attrib.x = nx; w->attrib.y = ny; } w->redrawWindow(); } break; case LeaveNotify: case EnterNotify: if (ws->west->id == event.xcrossing.window || ws->east->id == event.xcrossing.window || ws->north->id == event.xcrossing.window || ws->south->id == event.xcrossing.window) { waimea->eh->handleEvent(&event); } else if (event.type == LeaveNotify) { unsigned int ui; Window wd; int cx, cy, i; XQueryPointer(display, ws->id, &wd, &wd, &cx, &cy, &i, &i, &ui); nx += cx - px; ny += cy - py; if (master) { mnx += cx - px; mny += cy - py; } px = cx; py = cy; if (mergemode != NullMergeType) { if (checkMoveMerge(nx, ny, saved_w, saved_h)) { XSync(display, false); while (XCheckTypedEvent(display, FocusIn, &event)); while (XCheckTypedEvent(display, FocusOut, &event)); dontsend = move_resize = false; waimea->eh->move_resize = EndMoveResizeType; setWindowState(wstate & ~StateMoveMask); return true; } else if (! master) { w->attrib.x = nx; w->attrib.y = ny; w->redrawWindow(); } } else { if (master) { w->attrib.x = mnx; w->attrib.y = mny; } else { w->attrib.x = nx; w->attrib.y = ny; } w->redrawWindow(); } } break; case DestroyNotify: case UnmapNotify: if ((((event.type == UnmapNotify)? event.xunmap.window: event.xdestroywindow.window) == w->id)) { while (! maprequest_list->empty()) { XPutBackEvent(display, maprequest_list->front()); delete maprequest_list->front(); maprequest_list->pop_front(); } XPutBackEvent(display, &event); XUngrabKeyboard(display, CurrentTime); XUngrabPointer(display, CurrentTime); waimea->eh->move_resize = EndMoveResizeType; setWindowState(wstate & ~StateMoveMask); dontsend = move_resize = false; return false; } waimea->eh->evUnmapDestroy(&event); break; case ConfigureRequest: if (event.xconfigurerequest.window != w->id) waimea->eh->evConfigureRequest(&event.xconfigurerequest); break; case MapRequest: map_ev = new XEvent; *map_ev = event; maprequest_list->push_front(map_ev); break; case ButtonPress: case ButtonRelease: event.xbutton.window = id; case KeyPress: case KeyRelease: if (event.type == KeyPress || event.type == KeyRelease) event.xkey.window = id; int merge_state = mergemode; waimea->eh->handleEvent(&event); if (merge_state != mergemode) { if (checkMoveMerge(nx, ny, saved_w, saved_h)) { XSync(display, false); while (XCheckTypedEvent(display, FocusIn, &event)); while (XCheckTypedEvent(display, FocusOut, &event)); dontsend = move_resize = false; if (waimea->eh->move_resize != EndMoveResizeType) { waimea->eh->move_resize = EndMoveResizeType; setWindowState(wstate & ~StateMoveMask); return true; } } } if (waimea->eh->move_resize != EndMoveResizeType) break; setWindowState(wstate & ~StateMoveMask); if (w->attrib.x != sx || w->attrib.y != sy) { w->sendConfig(); net->setVirtualPos(w); } while (! maprequest_list->empty()) { XPutBackEvent(display, maprequest_list->front()); delete maprequest_list->front(); maprequest_list->pop_front(); } dontsend = move_resize = false; XUngrabKeyboard(display, CurrentTime); XUngrabPointer(display, CurrentTime); return false; } } } void WaWindow::resize(XEvent *e, int how) { XEvent event, *map_ev; int px, py, width, height, n_x, o_x, n_y, o_y, i; list *maprequest_list; Window wd; unsigned int ui, n_w, n_h, o_w, o_h; WaWindow *w; if (! (functions & FunctionResizeMask)) return; if (master && mergetype == CloneMergeType) w = master; else w = this; XQueryPointer(display, ws->id, &wd, &wd, &px, &py, &i, &i, &ui); if (waimea->eh->move_resize != EndMoveResizeType) return; n_x = o_x = attrib.x; n_y = o_y = attrib.y; width = n_w = o_w = attrib.width; height = n_h = o_h = attrib.height; waimea->eh->move_resize = ResizeType; setWindowState(wstate | StateResizeMask); move_resize = true; Window grab_window = frame->id; Cursor grab_cursor; DWindowObject *dwo = (DWindowObject *) waimea->findWin(e->xany.window, ANY_DECOR_WINDOW_TYPE); if (dwo) grab_cursor = dwo->sb->style->cursor; else grab_cursor = None; if (e && e->type == MapRequest) { if (how & EastResizeTypeMask) n_x = attrib.x = px - attrib.width - left_spacing - right_spacing; else n_x = attrib.x = px; if (how & SouthResizeTypeMask) n_y = attrib.y = py - attrib.height - top_spacing - bottom_spacing; else n_y = attrib.y = py; drawOutline(n_x, n_y, n_w, n_h); } maprequest_list = new list; if (XGrabPointer(display, grab_window, true, ButtonReleaseMask | ButtonPressMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask, GrabModeAsync, GrabModeAsync, None, grab_cursor, CurrentTime) != GrabSuccess) { move_resize = false; waimea->eh->move_resize = EndMoveResizeType; setWindowState(wstate & ~StateResizeMask); delete maprequest_list; return; } if (XGrabKeyboard(display, grab_window, true, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) { move_resize = false; waimea->eh->move_resize = EndMoveResizeType; setWindowState(wstate & ~StateResizeMask); XUngrabPointer(display, CurrentTime); delete maprequest_list; return; } for (;;) { waimea->eh->eventLoop(&waimea->eh->moveresize_return_mask, &event); switch (event.type) { case MotionNotify: while (XCheckTypedWindowEvent(display, event.xmotion.window, MotionNotify, &event)); if (how & EastResizeTypeMask) width += event.xmotion.x_root - px; else if (how & WestResizeTypeMask) width -= event.xmotion.x_root - px; if (how & SouthResizeTypeMask) height += event.xmotion.y_root - py; else if (how & NorthResizeTypeMask) height -= event.xmotion.y_root - py; px = event.xmotion.x_root; py = event.xmotion.y_root; if (w->incSizeCheck(width, height, &n_w, &n_h)) { if (how & WestResizeTypeMask) n_x -= n_w - o_w; if (how & NorthResizeTypeMask) n_y -= n_h - o_h; o_x = n_x; o_y = n_y; o_w = n_w; o_h = n_h; drawOutline(n_x, n_y, n_w, n_h); } break; case LeaveNotify: case EnterNotify: if (ws->west->id == event.xcrossing.window || ws->east->id == event.xcrossing.window || ws->north->id == event.xcrossing.window || ws->south->id == event.xcrossing.window) { int old_vx = ws->v_x; int old_vy = ws->v_y; clearOutline(); waimea->eh->handleEvent(&event); px -= (ws->v_x - old_vx); py -= (ws->v_y - old_vy); n_x = attrib.x; n_y = attrib.y; if (how & WestResizeTypeMask) n_x -= n_w - attrib.width; else if (how & NorthResizeTypeMask) n_y -= n_h - attrib.height; drawOutline(n_x, n_y, n_w, n_h); } else if (event.type == LeaveNotify) { int cx, cy; XQueryPointer(display, ws->id, &wd, &wd, &cx, &cy, &i, &i, &ui); if (how & EastResizeTypeMask) width += cx - px; else if (how & WestResizeTypeMask) width -= cx - px; if (how & SouthResizeTypeMask) height += cy - py; else if (how & NorthResizeTypeMask) height -= cy - py; px = cx; py = cy; if (incSizeCheck(width, height, &n_w, &n_h)) { if (how & WestResizeTypeMask) n_x -= n_w - o_w; if (how & NorthResizeTypeMask) n_y -= n_h - o_h; o_x = n_x; o_y = n_y; o_w = n_w; o_h = n_h; drawOutline(n_x, n_y, n_w, n_h); } } break; case DestroyNotify: case UnmapNotify: if ((((event.type == UnmapNotify)? event.xunmap.window: event.xdestroywindow.window) == id)) { while (! maprequest_list->empty()) { XPutBackEvent(display, maprequest_list->front()); delete maprequest_list->front(); maprequest_list->pop_front(); } delete maprequest_list; XPutBackEvent(display, &event); clearOutline(); XUngrabKeyboard(display, CurrentTime); XUngrabPointer(display, CurrentTime); waimea->eh->move_resize = EndMoveResizeType; setWindowState(wstate & ~StateResizeMask); move_resize = false; return; } waimea->eh->evUnmapDestroy(&event); break; case ConfigureRequest: if (event.xconfigurerequest.window != id) waimea->eh->evConfigureRequest(&event.xconfigurerequest); break; case MapRequest: map_ev = new XEvent; *map_ev = event; maprequest_list->push_front(map_ev); break; case ButtonPress: case ButtonRelease: event.xbutton.window = id; case KeyPress: case KeyRelease: if (event.type == KeyPress || event.type == KeyRelease) event.xkey.window = id; clearOutline(); waimea->eh->handleEvent(&event); drawOutline(n_x, n_y, n_w, n_h); if (waimea->eh->move_resize != EndMoveResizeType) break; setWindowState(wstate & ~StateResizeMask); clearOutline(); w->attrib.width = n_w; w->attrib.height = n_h; w->attrib.x = n_x; w->attrib.y = n_y; if (master) { if (mergetype == VertMergeType) master->old_attrib.width++; if (mergetype == HorizMergeType) master->old_attrib.height++; } w->redrawWindow(); while (! maprequest_list->empty()) { XPutBackEvent(display, maprequest_list->front()); delete maprequest_list->front(); maprequest_list->pop_front(); } delete maprequest_list; move_resize = false; XUngrabKeyboard(display, CurrentTime); XUngrabPointer(display, CurrentTime); return; } } } void WaWindow::resizeOpaque(XEvent *e, int how) { XEvent event, *map_ev; int px, py, width, height, i; list *maprequest_list; Window wd; unsigned int n_w, n_h, sw, sh, ui; WaWindow *w; if (! (functions & FunctionResizeMask)) return; if (master && mergetype == CloneMergeType) w = master; else w = this; XQueryPointer(display, ws->id, &wd, &wd, &px, &py, &i, &i, &ui); if (waimea->eh->move_resize != EndMoveResizeType) return; dontsend = true; sw = width = n_w = attrib.width; sh = height = n_h = attrib.height; waimea->eh->move_resize = ResizeOpaqueType; setWindowState(wstate | StateResizeMask); move_resize = true; Window grab_window = frame->id; Cursor grab_cursor; DWindowObject *dwo = (DWindowObject *) waimea->findWin(e->xany.window, ANY_DECOR_WINDOW_TYPE); if (dwo) grab_cursor = dwo->sb->style->cursor; else grab_cursor = None; if (e && e->type == MapRequest) { if (how & EastResizeTypeMask) attrib.x = px - attrib.width - left_spacing - right_spacing; else attrib.x = px; if (how & SouthResizeTypeMask) attrib.y = py - attrib.height - top_spacing - bottom_spacing; else attrib.y = py; redrawWindow(); net->setState(this, NormalState); net->setVirtualPos(this); } maprequest_list = new list; if (XGrabPointer(display, grab_window, true, ButtonReleaseMask | ButtonPressMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask, GrabModeAsync, GrabModeAsync, None, grab_cursor, CurrentTime) != GrabSuccess) { move_resize = false; waimea->eh->move_resize = EndMoveResizeType; setWindowState(wstate & ~StateResizeMask); delete maprequest_list; return; } if (XGrabKeyboard(display, grab_window, true, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) { move_resize = false; waimea->eh->move_resize = EndMoveResizeType; setWindowState(wstate & ~StateResizeMask); XUngrabPointer(display, CurrentTime); delete maprequest_list; return; } for (;;) { waimea->eh->eventLoop(&waimea->eh->moveresize_return_mask, &event); switch (event.type) { case MotionNotify: while (XCheckTypedWindowEvent(display, event.xmotion.window, MotionNotify, &event)); if (how & EastResizeTypeMask) width += event.xmotion.x_root - px; else if (how & WestResizeTypeMask) width -= event.xmotion.x_root - px; if (how & SouthResizeTypeMask) height += event.xmotion.y_root - py; else if (how & NorthResizeTypeMask) height -= event.xmotion.y_root - py; px = event.xmotion.x_root; py = event.xmotion.y_root; if (w->incSizeCheck(width, height, &n_w, &n_h)) { if (how & WestResizeTypeMask) w->attrib.x -= n_w - attrib.width; w->attrib.width = n_w; if (how & NorthResizeTypeMask) w->attrib.y -= n_h - attrib.height; w->attrib.height = n_h; if (master) { if (mergetype == VertMergeType) master->old_attrib.width++; if (mergetype == HorizMergeType) master->old_attrib.height++; } w->redrawWindow(); } break; case LeaveNotify: case EnterNotify: if (ws->west->id == event.xcrossing.window || ws->east->id == event.xcrossing.window || ws->north->id == event.xcrossing.window || ws->south->id == event.xcrossing.window) { int old_vx = ws->v_x; int old_vy = ws->v_y; waimea->eh->handleEvent(&event); px -= (ws->v_x - old_vx); py -= (ws->v_y - old_vy); } else if (event.type == LeaveNotify) { int cx, cy; XQueryPointer(display, ws->id, &wd, &wd, &cx, &cy, &i, &i, &ui); if (how & EastResizeTypeMask) width += cx - px; else if (how & WestResizeTypeMask) width -= cx - px; if (how & SouthResizeTypeMask) height += cy - py; else if (how & NorthResizeTypeMask) height -= cy - py; px = cx; py = cy; if (w->incSizeCheck(width, height, &n_w, &n_h)) { if (how & WestResizeTypeMask) w->attrib.x -= n_w - attrib.width; w->attrib.width = n_w; if (how & NorthResizeTypeMask) w->attrib.y -= n_h - attrib.height; w->attrib.height = n_h; if (master) { if (mergetype == VertMergeType) master->old_attrib.width++; if (mergetype == HorizMergeType) master->old_attrib.height++; } w->redrawWindow(); } } break; case DestroyNotify: case UnmapNotify: if ((((event.type == UnmapNotify)? event.xunmap.window: event.xdestroywindow.window) == id)) { while (! maprequest_list->empty()) { XPutBackEvent(display, maprequest_list->front()); delete maprequest_list->front(); maprequest_list->pop_front(); } delete maprequest_list; XPutBackEvent(display, &event); XUngrabKeyboard(display, CurrentTime); XUngrabPointer(display, CurrentTime); waimea->eh->move_resize = EndMoveResizeType; setWindowState(wstate & ~StateResizeMask); dontsend = move_resize = false; return; } waimea->eh->evUnmapDestroy(&event); break; case ConfigureRequest: if (event.xconfigurerequest.window != id) waimea->eh->evConfigureRequest(&event.xconfigurerequest); break; case MapRequest: map_ev = new XEvent; *map_ev = event; maprequest_list->push_front(map_ev); break; case ButtonPress: case ButtonRelease: event.xbutton.window = id; case KeyPress: case KeyRelease: if (event.type == KeyPress || event.type == KeyRelease) event.xkey.window = id; waimea->eh->handleEvent(&event); width = w->attrib.width; height = w->attrib.height; if (waimea->eh->move_resize != EndMoveResizeType) break; setWindowState(wstate & ~StateResizeMask); if (w->attrib.width != sw || w->attrib.height != sh) { net->setVirtualPos(w); } while (! maprequest_list->empty()) { XPutBackEvent(display, maprequest_list->front()); delete maprequest_list->front(); maprequest_list->pop_front(); } delete maprequest_list; dontsend = move_resize = false; XUngrabKeyboard(display, CurrentTime); XUngrabPointer(display, CurrentTime); return; } } } void WaWindow::resizeSmart(XEvent *e) { int x, y, i; Window wd; unsigned int ui; int resize_mask = 0; XQueryPointer(display, ws->id, &wd, &wd, &x, &y, &i, &i, &ui); if (x >= (attrib.x + (int) attrib.width / 2)) resize_mask |= EastResizeTypeMask; else resize_mask |= WestResizeTypeMask; if (y >= (attrib.y + (int) attrib.height / 2)) resize_mask |= SouthResizeTypeMask; else resize_mask |= NorthResizeTypeMask; resize(e, resize_mask); } void WaWindow::resizeSmartOpaque(XEvent *e) { int x, y, i; Window wd; unsigned int ui; int resize_mask = 0; XQueryPointer(display, ws->id, &wd, &wd, &x, &y, &i, &i, &ui); if (x >= (attrib.x + (int) attrib.width / 2)) resize_mask |= EastResizeTypeMask; else resize_mask |= WestResizeTypeMask; if (y >= (attrib.y + (int) attrib.height / 2)) resize_mask |= SouthResizeTypeMask; else resize_mask |= NorthResizeTypeMask; resizeOpaque(e, resize_mask); } void WaWindow::_maximize(int x, int y) { if (master) return; int new_width, new_height; unsigned int n_w, n_h; if (! (functions & FunctionResizeMask)) return; if (! (functions & FunctionMoveMask)) return; if (wstate & StateMaximizedMask) return; int workx, worky; unsigned int workw, workh; ws->getWorkareaSize(&workx, &worky, &workw, &workh); if (wstate & StateFullscreenMask) { new_width = ws->width - left_spacing - right_spacing; new_height = ws->height - top_spacing - bottom_spacing; } else { new_width = workw - left_spacing - right_spacing; new_height = workh - top_spacing - bottom_spacing; } restore_max.width = attrib.width; restore_max.height = attrib.height; int rest_x = attrib.x; int rest_y = attrib.y; list::iterator mit = merged.begin(); for (; mit != merged.end(); mit++) { switch ((*mit)->mergetype) { case VertMergeType: new_width -= (*mit)->attrib.width; break; case HorizMergeType: new_height -= (*mit)->attrib.height; break; } } if (wstate & StateShadedMask) { restore_max.height = restore_shade; restore_shade = new_height; new_height = attrib.height; } if (incSizeCheck(new_width, new_height, &n_w, &n_h)) { attrib.x = workx; attrib.y = worky; restore_max.x = rest_x - attrib.x; restore_max.y = rest_y - attrib.y; if (x >= 0 && y >= 0) { attrib.x = (x - ws->v_x); attrib.y = (y - ws->v_y); restore_max.misc0 = x; restore_max.misc1 = y; } else { restore_max.misc0 = ws->v_x + attrib.x; restore_max.misc1 = ws->v_y + attrib.y; } if (wstate & StateFullscreenMask) { attrib.x = 0; attrib.y = 0; } attrib.x += left_spacing; attrib.y += top_spacing; attrib.width = n_w; attrib.height = n_h; redrawWindow(); wstate |= StateMaximizedMask; net->setWmState(this); } } void WaWindow::unMaximize(void) { if (master) { master->unMaximize(); return; } int rest_height, tmp_shade_height = 0; unsigned int n_w, n_h; if (wstate & StateMaximizedMask) { if (wstate & StateShadedMask) { rest_height = attrib.height; tmp_shade_height = restore_max.height; } else rest_height = restore_max.height; if (incSizeCheck(restore_max.width, rest_height, &n_w, &n_h)) { attrib.x = restore_max.x + (restore_max.misc0 - ws->v_x); attrib.y = restore_max.y + (restore_max.misc1 - ws->v_y); attrib.width = n_w; attrib.height = n_h; wstate &= ~StateMaximizedMask; redrawWindow(); if (wstate & StateShadedMask) restore_shade = tmp_shade_height; net->setWmState(this); } } } void WaWindow::toggleMaximize(void) { if (! (wstate & StateMaximizedMask)) maximize(); else unMaximize(); } void WaWindow::close(void) { XEvent ev; ev.type = ClientMessage; ev.xclient.window = id; ev.xclient.message_type = net->wm_protocols; ev.xclient.format = 32; ev.xclient.data.l[0] = net->wm_delete_window; ev.xclient.data.l[1] = CurrentTime; XSendEvent(display, id, false, NoEventMask, &ev); } void WaWindow::kill(void) { XKillClient(display, id); } void WaWindow::closeKill(void) { if (protocol_mask & DeleteWindowProtocalMask) close(); else kill(); } void WaWindow::shade(void) { if (! (functions & FunctionResizeMask)) return; if (master) { master->shade(); return; } unsigned int n_w, n_h; if (incSizeCheck(attrib.width, 0, &n_w, &n_h)) { attrib.width = n_w; attrib.height = n_h; redrawWindow(); MERGED_LOOP { if (wstate & StateShadedMask) _mw->wstate |= StateShadedMask; else _mw->wstate &= ~StateShadedMask; net->setWmState(_mw); } } } void WaWindow::unShade(void) { if (master) { master->unShade(); return; } if (wstate & StateShadedMask) { attrib.height = restore_shade; MERGED_LOOP { _mw->wstate &= ~StateShadedMask; net->setWmState(_mw); } redrawWindow(); } } void WaWindow::toggleShade(void) { if (wstate & StateShadedMask) unShade(); else shade(); } void WaWindow::sticky(void) { if (master) { master->sticky(); return; } MERGED_LOOP { _mw->wstate |= StateStickyMask; net->setWmState(_mw); } } void WaWindow::unSticky(void) { if (master) { master->unSticky(); return; } MERGED_LOOP { _mw->wstate &= ~StateStickyMask; net->setWmState(_mw); } } void WaWindow::toggleSticky(void) { if (master) { master->toggleSticky(); return; } if (wstate & StateStickyMask) wstate &= ~StateStickyMask; else wstate |= StateStickyMask; MERGED_LOOP { if (wstate & StateStickyMask) _mw->wstate |= StateStickyMask; else _mw->wstate &= ~StateStickyMask; net->setWmState(_mw); } } void WaWindow::minimize(void) { if (master) { master->minimize(); return; } if (wstate & StateMinimizedMask) return; MERGED_LOOP { net->setState(_mw, IconicState); net->setWmState(_mw); } } void WaWindow::unMinimize(void) { if (master) { master->unMinimize(); return; } if (! (wstate & StateMinimizedMask)) return; MERGED_LOOP { net->setState(_mw, NormalState); net->setWmState(_mw); } } void WaWindow::toggleMinimize(void) { if (master) { master->toggleMinimize(); return; } if (wstate & StateMinimizedMask) unMinimize(); else minimize(); } void WaWindow::fullscreenOn(void) { if (! (functions & FunctionResizeMask)) return; if (! (functions & FunctionMoveMask)) return; if (master) { master->fullscreenOn(); return; } if (wstate & StateFullscreenMask) return; wstate |= StateFullscreenMask; if (wstate & StateMaximizedMask) { wstate &= ~StateMaximizedMask; int res_x = restore_max.x; int res_y = restore_max.y; int res_w = restore_max.width; int res_h = restore_max.height; _maximize(restore_max.misc0, restore_max.misc1); restore_max.x = res_x; restore_max.y = res_y; restore_max.width = res_w; restore_max.height = res_h; } net->setWmState(this); } void WaWindow::fullscreenOff(void) { if (master) { master->fullscreenOff(); return; } if (! (wstate & StateFullscreenMask)) return; wstate &= ~StateFullscreenMask; if (wstate & StateMaximizedMask) { wstate &= ~StateMaximizedMask; int res_x = restore_max.x; int res_y = restore_max.y; int res_w = restore_max.width; int res_h = restore_max.height; _maximize(restore_max.misc0, restore_max.misc1); restore_max.x = res_x; restore_max.y = res_y; restore_max.width = res_w; restore_max.height = res_h; } net->setWmState(this); } void WaWindow::fullscreenToggle(void) { if (wstate & StateFullscreenMask) fullscreenOff(); else fullscreenOn(); } void WaWindow::setDecor(long newdecormask) { if (! (functions & FunctionSetDecorMask)) return; if (master) { master->setDecor(newdecormask); return; } if (newdecormask == decormask) return; decormask = newdecormask; MERGED_LOOP { if (! (_mw->functions & FunctionSetDecorMask)) return; _mw->decormask = decormask; if (decormask & DecorTitleMask) _mw->wstate |= StateDecorTitleMask; else _mw->wstate &= ~StateDecorTitleMask; if (decormask & DecorBorderMask) _mw->wstate |= StateDecorBorderMask; else _mw->wstate &= ~StateDecorBorderMask; if (decormask & DecorHandlesMask) _mw->wstate |= StateDecorHandlesMask; else _mw->wstate &= ~StateDecorHandlesMask; if (decormask & DecorAllMask) _mw->wstate |= StateDecorAllMask; else _mw->wstate &= ~StateDecorAllMask; net->setWmState(_mw); } } void WaWindow::alwaysontopOn(void) { if (! (functions & FunctionSetStackingMask)) return; if (master) { master->alwaysontopOn(); return; } if (wstate & StateAlwaysOnTopMask) return; MERGED_LOOP { _mw->wstate &= ~StateAlwaysAtBottomMask; _mw->wstate |= StateAlwaysOnTopMask; _mw->frame->setStacking(AlwaysOnTopStackingType); net->setWmState(_mw); } ws->restackWindows(); net->setClientListStacking(ws); } void WaWindow::alwaysatbottomOn(void) { if (! (functions & FunctionSetStackingMask)) return; if (master) { master->alwaysatbottomOn(); return; } if (wstate & StateAlwaysAtBottomMask) return; MERGED_LOOP { _mw->wstate &= ~StateAlwaysOnTopMask; _mw->wstate |= StateAlwaysAtBottomMask; _mw->frame->setStacking(AlwaysAtBottomStackingType); net->setWmState(_mw); } ws->restackWindows(); net->setClientListStacking(ws); } void WaWindow::alwaysontopOff(void) { if (master) { master->alwaysontopOff(); return; } if (! (wstate & StateAlwaysOnTopMask)) return; MERGED_LOOP { _mw->wstate &= ~StateAlwaysOnTopMask; _mw->frame->setStacking(NormalStackingType); net->setWmState(_mw); } ws->restackWindows(); net->setClientListStacking(ws); } void WaWindow::alwaysatbottomOff(void) { if (master) { master->alwaysatbottomOff(); return; } if (! (wstate & StateAlwaysAtBottomMask)) return; MERGED_LOOP { _mw->wstate &= ~StateAlwaysAtBottomMask; _mw->frame->setStacking(NormalStackingType); net->setWmState(_mw); } net->setClientListStacking(ws); } void WaWindow::alwaysontopToggle(void) { if (wstate & StateAlwaysOnTopMask) alwaysontopOff(); else alwaysontopOn(); } void WaWindow::alwaysatbottomToggle(void) { if (wstate & StateAlwaysAtBottomMask) alwaysatbottomOff(); else alwaysatbottomOn(); } void WaWindow::moveResize(char *s) { int x, y, geometry; unsigned int width, height; if (! (functions & FunctionMoveMask)) return; if (! (functions & FunctionResizeMask)) return; if (waimea->eh->move_resize != EndMoveResizeType || ! s) return; width = attrib.width; height = attrib.height; geometry = XParseGeometry(s, &x, &y, &width, &height); incSizeCheck(width, height, &attrib.width, &attrib.height); if (geometry & XValue) { if (geometry & XNegative) attrib.x = ws->width + x - attrib.width; else attrib.x = x; } if (geometry & YValue) { if (geometry & YNegative) attrib.y = ws->height + y - attrib.height; else attrib.y = y; } redrawWindow(); checkMoveMerge(attrib.x, attrib.y); } void WaWindow::moveResizeVirtual(char *s) { int x, y, geometry; unsigned int width, height; if (! (functions & FunctionMoveMask)) return; if (! (functions & FunctionResizeMask)) return; if (waimea->eh->move_resize != EndMoveResizeType || ! s) return; width = attrib.width; height = attrib.height; geometry = XParseGeometry(s, &x, &y, &width, &height); incSizeCheck(width, height, &attrib.width, &attrib.height); gravitate(RemoveGravity); if (geometry & XValue) { if (geometry & XNegative) attrib.x = ((ws->v_xmax + ws->width) + x - attrib.width) - ws->v_x; else attrib.x = x - ws->v_x; } if (geometry & YValue) { if (geometry & YNegative) attrib.y = ((ws->v_ymax + ws->height) + y - attrib.height) - ws->v_y; else attrib.y = y - ws->v_y; } gravitate(ApplyGravity); redrawWindow(); checkMoveMerge(attrib.x, attrib.y); } void WaWindow::moveWindowToPointer(XEvent *e) { if (! (functions & FunctionMoveMask)) return; attrib.x = e->xbutton.x_root - attrib.width / 2; attrib.y = e->xbutton.y_root - attrib.height / 2; int workx, worky; unsigned int workw, workh; ws->getWorkareaSize(&workx, &worky, &workw, &workh); if ((attrib.x + right_spacing + attrib.width) > (workx + workw)) attrib.x = (workx + workw) - attrib.width - right_spacing; else if (attrib.x < workx) attrib.x = workx + left_spacing; if ((attrib.y + attrib.height) > (worky + workh)) attrib.y = (worky + workh) - bottom_spacing - attrib.height; else if (attrib.y < worky) attrib.y = worky + top_spacing; redrawWindow(); checkMoveMerge(attrib.x, attrib.y); } void WaWindow::moveWindowToSmartPlace(void) { if (! (functions & FunctionMoveMask)) return; int temp_h, temp_w; int workx, worky; unsigned int workw, workh; ws->getWorkareaSize(&workx, &worky, &workw, &workh); int test_x = frame->attrib.x; int test_y = frame->attrib.y; int loc_ok = false, tw, tx, ty, th; temp_h = frame->attrib.height; temp_w = frame->attrib.width; int first = true; while (((test_y + temp_h) < (int) workh) && !loc_ok) { if (! first) test_x = 0; while (((test_x + temp_w) < (int) workw) && !loc_ok) { loc_ok = true; list::iterator it = ws->wawindow_list.begin(); for (; it != ws->wawindow_list.end() && (loc_ok == True); it++) { if ((*it != this) && ((*it)->wstate & StateTasklistMask) && (! (*it)->master) && ((*it)->desktop_mask & (1L << ws->current_desktop->number)) && ((((*it)->frame->attrib.x + (*it)->frame->attrib.width) > 0 && (*it)->frame->attrib.x < (int) workw) && (((*it)->frame->attrib.y + (*it)->frame->attrib.height) > 0 && (*it)->frame->attrib.y < (int) workh))) { th = (*it)->frame->attrib.height; tw = (*it)->frame->attrib.width; tx = (*it)->frame->attrib.x - workx; ty = (*it)->frame->attrib.y - worky; if ((tx < (test_x + temp_w)) && ((tx + tw) > test_x) && (ty < (test_y + temp_h)) && ((ty + th) > test_y)) { loc_ok = False; test_x = tx + tw; } } } test_x += 1; if ((!loc_ok) && first) { first = false; test_x = test_y = 0; } } test_y += 1; } if (loc_ok) { attrib.x = left_spacing + test_x + workx - 2; attrib.y = top_spacing + test_y + worky - 1; redrawWindow(); checkMoveMerge(attrib.x, attrib.y); } } void WaWindow::desktopMask(char *s) { if (! (functions & FunctionDesktopMask)) return; if (master) { master->desktopMask(s); return; } if (s) { if (! strncasecmp("all", s, 3)) desktop_mask = (1L << 16) - 1; else { desktop_mask = 0; char *token = strtok(s, " \t"); while (token) { unsigned int desk = (unsigned int) atoi(token); if (desk < ws->config.desktops) desktop_mask |= (1L << desk); token = strtok(NULL, " \t"); } } if (desktop_mask == 0) desktop_mask = (1L << 0); if (desktop_mask & (1L << ws->current_desktop->number)) show(); else hide(); MERGED_LOOP { _mw->desktop_mask = desktop_mask; net->setDesktop(_mw); net->setDesktopMask(_mw); } } } void WaWindow::joinDesktop(char *s) { if (! (functions & FunctionDesktopMask)) return; if (master) { master->joinDesktop(s); return; } if (s) { unsigned int desk = (unsigned int) atoi(s); if (desk < ws->config.desktops) { desktop_mask |= (1L << desk); if (desktop_mask & (1L << ws->current_desktop->number)) show(); MERGED_LOOP { _mw->desktop_mask = desktop_mask; net->setDesktop(_mw); net->setDesktopMask(_mw); } } } } void WaWindow::partDesktop(char *s) { if (! (functions & FunctionDesktopMask)) return; if (master) { master->partDesktop(s); return; } if (s) { unsigned int desk = (unsigned int) atoi(s); if (desk < ws->config.desktops) { long int new_mask = desktop_mask & ~(1L << desk); if (new_mask) { desktop_mask = new_mask; if (! (desktop_mask & (1L << ws->current_desktop->number))) hide(); MERGED_LOOP { _mw->desktop_mask = desktop_mask; net->setDesktop(_mw); net->setDesktopMask(_mw); } } } } } void WaWindow::partCurrentDesktop(void) { if (! (functions & FunctionDesktopMask)) return; if (master) { master->partCurrentDesktop(); return; } long int new_mask = desktop_mask & ~(1L << ws->current_desktop->number); if (new_mask) { desktop_mask = new_mask; hide(); MERGED_LOOP { _mw->desktop_mask = desktop_mask; net->setDesktop(_mw); net->setDesktopMask(_mw); } } } void WaWindow::joinCurrentDesktop(void) { if (! (functions & FunctionDesktopMask)) return; if (master) { master->joinCurrentDesktop(); return; } desktop_mask |= (1L << ws->current_desktop->number); show(); MERGED_LOOP { _mw->desktop_mask = desktop_mask; net->setDesktop(_mw); net->setDesktopMask(_mw); } } void WaWindow::joinAllDesktops(void) { if (! (functions & FunctionDesktopMask)) return; if (master) { master->joinAllDesktops(); return; } desktop_mask = (1L << 16) - 1; show(); MERGED_LOOP { _mw->desktop_mask = desktop_mask; net->setDesktop(_mw); net->setDesktopMask(_mw); } } void WaWindow::partAllDesktopsExceptCurrent(void) { if (! (functions & FunctionDesktopMask)) return; desktop_mask = (1L << ws->current_desktop->number); show(); MERGED_LOOP { _mw->desktop_mask = desktop_mask; net->setDesktop(_mw); net->setDesktopMask(_mw); } } void WaWindow::partCurrentJoinDesktop(char *s) { if (! (functions & FunctionDesktopMask)) return; if (master) { master->partCurrentJoinDesktop(s); return; } if (s) { unsigned int desk = (unsigned int) atoi(s); if (desk < ws->config.desktops) { desktop_mask = desktop_mask & ~(1L << ws->current_desktop->number); desktop_mask |= (1L << desk); if (desktop_mask & (1L << ws->current_desktop->number)) show(); else hide(); MERGED_LOOP { _mw->desktop_mask = desktop_mask; net->setDesktop(_mw); net->setDesktopMask(_mw); } } } } void WaWindow::merge(WaWindow *child, int mtype) { if (! (functions & FunctionMergeMask)) return; if (mtype != CloneMergeType && mtype != VertMergeType && mtype != HorizMergeType) return; if (child->master) child->master->unmerge(child); if (child == this) return; if (! child->merged.empty()) return; if (master) return; bool had_focus = child->has_focus; wa_grab_server(); if (validate_drawable(id)) { XSelectInput(display, child->id, NoEventMask); XReparentWindow(display, child->id, frame->id, -child->attrib.width, -child->attrib.height); XSelectInput(display, child->id, PropertyChangeMask | StructureNotifyMask | FocusChangeMask | EnterWindowMask | LeaveWindowMask); } else { wa_ungrab_server(); return; } wa_ungrab_server(); merged.push_back(child); child->master = this; child->mergetype = mtype; child->hide(); /* merge decorations */ if (mtype == CloneMergeType) { child->mergedback = true; if (waimea->eh) child->toFront(); } updateAllAttributes(); if (! waimea->eh) { net->getMergeOrder(this); net->getMergeAtfront(this); } net->setMergedState(child); net->setMergeOrder(this); if (had_focus) { child->has_focus = false; waimea->focusNew(child->id, false); } } void WaWindow::unmerge(WaWindow *child) { list::iterator it = merged.begin(); for (; it != merged.end() && *it != child; it++); if (it == merged.end()) return; bool had_focus = child->has_focus; wa_grab_server(); if (validate_drawable(child->id)) { XSelectInput(display, child->id, NoEventMask); XReparentWindow(display, child->id, child->frame->id, 0, child->top_spacing); XLowerWindow(display, child->id); XSelectInput(display, child->id, PropertyChangeMask | StructureNotifyMask | FocusChangeMask | EnterWindowMask | LeaveWindowMask); } wa_ungrab_server(); merged.remove(child); /* merge decorations */ if (child->mergetype == CloneMergeType && !child->mergedback) toFront(); updateAllAttributes(); child->master = NULL; child->mergetype = NullMergeType; if (child->desktop_mask & (1L << ws->current_desktop->number)) { child->hidden = true; child->show(); } child->updateAllAttributes(); if (! ws->shutdown) { net->setMergedState(child); net->setMergeOrder(this); } if (had_focus) { waimea->focusNew(child->id, false); } else child->has_focus = false; } void WaWindow::mergeWithWindow(char *s, int mtype) { if (! s) return; if (! (functions & FunctionMergeMask)) return; char *str = WA_STRDUP(s); WaWindow *mw = NULL; list awos; Tst *attr; Doing *doing = new Doing(ws); attr = short_do_string_to_tst(str); doing->applyAttributes(NULL, attr); delete attr; ws->getRegexTargets(doing->wreg, WindowType, false, &awos); if (! awos.empty()) { mw = (WaWindow *) *awos.begin(); awos.clear(); } delete doing; delete [] str; if (mw && mw != this) mw->merge(this, mtype); } void WaWindow::explode(void) { while (! merged.empty()) unmerge(merged.back()); } void WaWindow::setMergeMode(char *s) { if (s) { if (! strncasecmp(s, "vert", 4)) mergemode = VertMergeType; else if (! strncasecmp(s, "horiz", 5)) mergemode = HorizMergeType; else if (! strncasecmp(s, "clone", 5)) mergemode = CloneMergeType; else mergemode = NullMergeType; } } void WaWindow::nextMergeMode(void) { if (mergemode == VertMergeType) mergemode = NullMergeType; else mergemode++; } void WaWindow::prevMergeMode(void) { if (mergemode == NullMergeType) mergemode = VertMergeType; else mergemode--; } void WaWindow::mergeTo(XEvent *e, int mtype) { WaWindow *wt = (WaWindow *) waimea->findWin(e->xany.window, WindowType); if (wt) merge(wt, mtype); } void WaWindow::toFront(void) { if (mergedback) { list::iterator it = merged.begin(); list::iterator it_end = merged.end(); if (master) { it = master->merged.begin(); it_end = master->merged.end(); XLowerWindow(display, master->id); } for (; it != it_end; it++) { if ((*it)->id != id) XLowerWindow(display, (*it)->id); } int focused = false; if (master) { net->setMergeAtfront(master, id); master->mergedback = true; it = master->merged.begin(); for (; it != master->merged.end(); it++) { if ((*it)->mergetype == CloneMergeType) { if ((*it)->has_focus) focused = true; (*it)->mergedback = true; } } } else { net->setMergeAtfront(this, id); it = merged.begin(); for (; it != merged.end(); it++) { if ((*it)->mergetype == CloneMergeType) { if ((*it)->has_focus) focused = true; (*it)->mergedback = true; } } } mergedback = false; if (focused) waimea->focusNew(id, false); } } bool WaWindow::checkMoveMerge(int x, int y, int width, int height) { if (! merged.empty()) return false; if (! (functions & FunctionMergeMask)) return false; list matchlist; WaWindow *bestmatch = NULL; if (width == 0) width = attrib.width; if (height == 0) height = attrib.height; int _x = x + width / 2; int _y = y + height / 2; if (mergemode == NullMergeType && master) { attrib.x = x; attrib.y = y; old_attrib.width = attrib.width; old_attrib.height = attrib.height; attrib.width = width; attrib.height = height; master->unmerge(this); return true; } list::iterator it = ws->wawindow_list.begin(); for (; it != ws->wawindow_list.end(); it++) { if (*it != this && (! (*it)->master) && (! (*it)->hidden) && (! ((*it)->wstate & StateShadedMask)) && ((*it)->wstate & StateTasklistMask)) { if (_x > (*it)->frame->attrib.x && _x < ((*it)->frame->attrib.x + (int) (*it)->frame->attrib.width) && _y > (*it)->frame->attrib.y && _y < ((*it)->frame->attrib.y + (int) (*it)->frame->attrib.height)) { matchlist.push_back(*it); } } } if (! matchlist.empty()) { if (matchlist.size() > 1) { list::iterator wit = ws->aot_stacking_list.begin(); for (; !bestmatch && wit != ws->aot_stacking_list.end(); wit++) { for (it = matchlist.begin(); it != matchlist.end(); it++) if ((*it)->frame->id == *wit) { bestmatch = *it; break; } } wit = ws->stacking_list.begin(); for (; !bestmatch && wit != ws->stacking_list.end(); wit++) { for (it = matchlist.begin(); it != matchlist.end(); it++) if ((*it)->frame->id == *wit) { bestmatch = *it; break; } } wit = ws->aab_stacking_list.begin(); for (; !bestmatch && wit != ws->aab_stacking_list.end(); wit++) { for (it = matchlist.begin(); it != matchlist.end(); it++) if ((*it)->frame->id == *wit) { bestmatch = *it; break; } } } else { bestmatch = matchlist.front(); } } LISTCLEAR(matchlist); if (bestmatch) { if (master != bestmatch) { bestmatch->merge(this, mergemode); return true; } else if (mergemode != mergetype) { bestmatch->merge(this, mergemode); return true; } } else if (master) { if ((_x + 25) > master->frame->attrib.x && _x < (master->frame->attrib.x + (int) master->frame->attrib.width + 25) && (_y + 25) > master->frame->attrib.y && _y < (master->frame->attrib.y + (int) master->frame->attrib.height) + 25) { return false; } attrib.x = x; attrib.y = y; old_attrib.width = attrib.width; old_attrib.height = attrib.height; attrib.width = width; attrib.height = height; master->unmerge(this); return true; } return false; } void WaWindow::windowStateCheck(bool force) { if (! init_done) return; if (force || wstate != old_wstate) { EventDetail ed; ed.x = ed.y = INT_MAX; ed.x11mod = ed.wamod = 0; ed.type = WindowStateChangeNotify; ws->waimea->eh->evAct(NULL, frame->id, &ed); signalMonitors(); old_wstate = wstate; } } void WaWindow::setWindowState(long int newstate) { if (newstate != wstate) { wstate = newstate; windowStateCheck(); } } void WaWindow::addMonitor(AWindowObject *monitor, long int type) { EventDetail ed; ed.x = ed.y = INT_MAX; ed.x11mod = ed.wamod = 0; monitors.push_back(new FlagMonitor(monitor, type)); if (type) { if (wstate & type) ed.type = StateAddNotify; else ed.type = StateRemoveNotify; ws->waimea->eh->evAct(NULL, monitors.back()->monitor->id, &ed); } } void WaWindow::removeMonitor(AWindowObject *monitor) { list::iterator it = monitors.begin(); for (; it != monitors.end(); it++) if ((*it)->monitor == monitor) it = monitors.erase(it); } void WaWindow::signalMonitors(void) { EventDetail ed; ed.x = ed.y = INT_MAX; ed.x11mod = ed.wamod = 0; list::iterator it = monitors.begin(); for (; it != monitors.end(); it++) { ed.type = WindowStateChangeNotify; ws->waimea->eh->evAct(NULL, (*it)->monitor->id, &ed); if ((*it)->type) { if ((old_wstate & (*it)->type) != (wstate & (*it)->type)) { if (wstate & (*it)->type) ed.type = StateAddNotify; else ed.type = StateRemoveNotify; ws->waimea->eh->evAct(NULL, (*it)->monitor->id, &ed); } } } } WaFrameWindow::WaFrameWindow(WaWindow *wa_win, WaStringMap *sm) : RootWindowObject(wa_win->ws, 0, WindowFrameType, sm, "frame") { XSetWindowAttributes attrib_set; wa = wa_win; int create_mask = CWOverrideRedirect | CWEventMask | CWColormap; if (ws->screen_depth == 32) { attrib_set.background_pixmap = None; attrib_set.background_pixel = 0x00000000; attrib_set.border_pixel = 0x00000000; create_mask |= CWBackPixel | CWBorderPixel; } else { attrib_set.background_pixmap = ParentRelative; } create_mask |= CWBackPixmap; attrib_set.colormap = ws->colormap; attrib_set.override_redirect = true; attrib_set.event_mask = SubstructureRedirectMask | StructureNotifyMask | SubstructureNotifyMask | EnterWindowMask | LeaveWindowMask; attrib.x = wa->attrib.x; attrib.y = wa->attrib.y; attrib.width = wa->attrib.width; attrib.height = wa->attrib.height; id = XCreateWindow(ws->display, ws->id, attrib.x, attrib.y, attrib.width, attrib.height, 0, ws->screen_depth, InputOutput, ws->visual, create_mask, &attrib_set); #ifdef SHAPE shape_count = 0; apply_shape = false; apply_shape_buffer = XCreateWindow(ws->display, ws->id, 0, 0, attrib.width, attrib.height, 0, CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attrib_set); #endif // SHAPE wa->waimea->window_table.insert(make_pair(id, this)); } WaFrameWindow::~WaFrameWindow(void) { #ifdef SHAPE while (! shape_infos.empty()) { shape_infos.back()->in_list = false; shape_infos.pop_back(); } XDestroyWindow(ws->display, apply_shape_buffer); #endif // SHAPE wa->waimea->window_table.erase(id); } void WaFrameWindow::styleUpdate(bool, bool size_change) { if (size_change) wa->updateAllAttributes(); else wa->drawDecor(); } #ifdef SHAPE void WaFrameWindow::startRender(void) { apply_shape = false; } void WaFrameWindow::endRender(Pixmap) { apply_shape = true; applyShape(); } void WaFrameWindow::addShapeInfo(ShapeInfo *sinfo) { shape_infos.push_back(sinfo); } void WaFrameWindow::removeShapeInfo(ShapeInfo *sinfo) { shape_infos.remove(sinfo); shapeUpdateNotify(); } void WaFrameWindow::shapeUpdateNotify(void) { shape_count++; applyShape(); } void WaFrameWindow::applyShape(void) { if (! apply_shape) return; if (! shape_count) return; XShapeCombineMask(ws->display, apply_shape_buffer, ShapeBounding, 0, 0, None, ShapeSet); XRectangle rect; rect.x = rect.y = 0; rect.width = attrib.width; rect.height = attrib.height; XShapeCombineRectangles(ws->display, apply_shape_buffer, ShapeBounding, 0, 0, &rect, 1, ShapeSubtract, Unsorted); list::iterator it = shape_infos.begin(); for (; it != shape_infos.end(); it++) XShapeCombineShape(ws->display, apply_shape_buffer, ShapeBounding, (*it)->xoff, (*it)->yoff, (*it)->window, ShapeBounding, ShapeUnion); XShapeCombineShape(ws->display, id, ShapeBounding, 0, 0, apply_shape_buffer, ShapeBounding, ShapeSet); shape_count = 0; } ShapeInfo::ShapeInfo(Window _window) { xoff = 0; yoff = 0; in_list = false; window = _window; } void ShapeInfo::setShapeOffset(int newxoff, int newyoff) { xoff = newxoff; yoff = newyoff; } #endif // SHAPE