/** * @file Window.cc * @author David Reveman * @date 02-May-2001 21:43:03 * * @brief Implementation of WaWindow and WaChildWindow classes * * An instance if this class manages one window. Contains functions for * creating window decorations, reading window hints and controlling the * window. * * Copyright (C) David Reveman. All rights reserved. * */ #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 } #include "Window.hh" /** * @fn WaWindow(Window win_id, WaScreen *scrn) : * WindowObject(win_id, WindowType) * @brief Constructor for WaWindow class * * Reparents the window, reads window hints and creates decorations ... * * @param win_id Resource ID of window to manage * @param scrn The screen the window should be displayed on */ WaWindow::WaWindow(Window win_id, WaScreen *scrn) : WindowObject(win_id, WindowType) { XWindowAttributes init_attrib; char *__m_wastrdup_tmp; id = win_id; wascreen = scrn; display = wascreen->display; screen_number = wascreen->screen_number; waimea = wascreen->waimea; ic = wascreen->ic; net = waimea->net; wm_strut = NULL; move_resize = false; classhint = NULL; name = __m_wastrdup(""); XGrabServer(display); if (validatedrawable(id)) XGetWindowAttributes(display, id, &init_attrib); else deleted = true; XUngrabServer(display); 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 = ign_config_req = hidden = false; desktop_mask = (1L << wascreen->current_desktop->number); #ifdef SHAPE shaped = false; #endif //SHAPE #ifdef RENDER render_if_opacity = false; #endif // RENDER border_w = title_w = handle_w = 0; has_focus = false; flags.sticky = flags.shaded = flags.max = flags.title = flags.handle = flags.border = flags.all = flags.alwaysontop = flags.alwaysatbottom = flags.forcedatbottom = false; flags.focusable = flags.tasklist = true; frameacts = awinacts = pwinacts = titleacts = labelacts = handleacts = lgacts = rgacts = NULL; transient_for = (Window) 0; host = pid = NULL; int i; bacts = new list*[wascreen->wstyle.b_num]; for (i = 0; i < wascreen->wstyle.b_num; i++) bacts[i] = NULL; net->GetWMHints(this); net->GetMWMHints(this); net->GetWMNormalHints(this); net->GetWmPid(this); Gravitate(ApplyGravity); InitPosition(); frame = new WaChildWindow(this, wascreen->id, FrameType); handle = new WaChildWindow(this, frame->id, HandleType); grip_l = new WaChildWindow(this, frame->id, LGripType); grip_r = new WaChildWindow(this, frame->id, RGripType); title = new WaChildWindow(this, frame->id, TitleType); WaChildWindow *button; int left_end = 2; int right_end = -2; int tw = (signed) wascreen->wstyle.title_height; list::iterator bit = wascreen->wstyle.buttonstyles.begin(); for (i = 0; bit != wascreen->wstyle.buttonstyles.end(); ++bit, ++i) { button = new WaChildWindow(this, title->id, ButtonType); button->bstyle = *bit; button->f_texture = &(*bit)->t_focused; button->u_texture = &(*bit)->t_unfocused; if ((*bit)->autoplace == WestType) button->g_x = left_end; else if ((*bit)->autoplace == EastType) button->g_x = right_end; else button->g_x = (*bit)->x; if (button->g_x > 0 && (button->g_x + (tw - 2)) > left_end) left_end = button->g_x + (tw - 2); else if ((button->g_x - (tw - 2)) < right_end) right_end = button->g_x - (tw - 2); buttons.push_back(button); } label = new WaChildWindow(this, title->id, LabelType); label->g_x = left_end + 2; label->g_x2 = right_end - 2; if (deleted) { delete this; return; } net->GetWmState(this); net->GetWmType(this); net->GetVirtualPos(this); net->GetWmStrut(this); net->GetDesktop(this); net->SetDesktop(this); net->SetDesktopMask(this); ReparentWin(); if (! net->GetNetName(this)) net->GetXaName(this); if (*name == '\0') SetActionLists(); UpdateGrabs(); #ifdef SHAPE Shape(); #endif // SHAPE if (deleted) { delete this; return; } UpdateAllAttributes(); if (flags.shaded) Shade(NULL, NULL); waimea->window_table.insert(make_pair(id, this)); wascreen->wawindow_list.push_back(this); wascreen->wawindow_list_map_order.push_back(this); if ((! flags.alwaysontop) && (! flags.alwaysatbottom) && (! flags.forcedatbottom)) wascreen->wa_list_stacking.push_back(this); if (deleted) delete this; } /** * @fn ~WaWindow(void) * @brief Destructor of WaWindow class * * Reparents the window back to the root window if it still exists. Destroys * all windows used for decorations. */ WaWindow::~WaWindow(void) { waimea->window_table.erase(id); if (transient_for) { if (transient_for == wascreen->id) { list::iterator it = wascreen->wawindow_list.begin(); for (;it != wascreen->wawindow_list.end(); ++it) (*it)->transients.remove(id); } else { map::iterator hit; if ((hit = waimea->window_table.find(transient_for)) != waimea->window_table.end()) { if (((*hit).second)->type == WindowType) ((WaWindow *) (*hit).second)->transients.remove(id); } } } XGrabServer(display); if (validatedrawable(id) && validateclient_mapped(id)) { XRemoveFromSaveSet(display, id); Gravitate(RemoveGravity); if (flags.shaded) attrib.height = restore_shade; if (attrib.x >= wascreen->width) attrib.x = attrib.x % wascreen->width; if (attrib.y >= wascreen->height) attrib.y = attrib.y % wascreen->height; if (attrib.x + attrib.width <= 0) attrib.x = wascreen->width + (attrib.x % wascreen->width); if (attrib.y + attrib.height <= 0) attrib.y = wascreen->height + (attrib.y % wascreen->height); XReparentWindow(display, id, wascreen->id, attrib.x, attrib.y); } XUngrabServer(display); list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) delete *bit; delete grip_l; delete grip_r; delete handle; delete label; delete title; if (name) delete [] name; if (host) delete [] host; if (pid) delete [] pid; if (classhint && classhint->res_name) XFree(classhint->res_name); if (classhint && classhint->res_class) XFree(classhint->res_class); delete [] bacts; wascreen->wawindow_list.remove(this); wascreen->wawindow_list_map_order.remove(this); wascreen->wa_list_stacking.remove(this); if (flags.alwaysontop) wascreen->wawindow_list_stacking_aot.remove(this); if (flags.forcedatbottom) { wascreen->always_at_bottom_list.remove(frame->id); } else if (flags.alwaysatbottom) wascreen->wawindow_list_stacking_aab.remove(this); if (wm_strut) { wascreen->strut_list.remove(wm_strut); delete wm_strut; if (! wascreen->shutdown) wascreen->UpdateWorkarea(); } delete frame; if (! wascreen->shutdown) { wascreen->net->SetClientList(wascreen); wascreen->net->SetClientListStacking(wascreen); if (! wascreen->wawindow_list.empty()) wascreen->wawindow_list.front()->Focus(false); } } /** * @fn GetActionList(list *e) * @brief Finds individual action list * * Matches windows class name, class and title with WaActionExtLists. Returns * WaActionExtLists action list if a match is found. If no match is found, * NULL is returned. * * @param e List with WaActionExtLists to try to match with */ list *WaWindow::GetActionList(list *e) { list::iterator it; for (it = e->begin(); it != e->end(); ++it) { if (classhint) { if (classhint->res_name && (*it)->name->Match(classhint->res_name)) return &((*it)->list); else if (classhint->res_class && (*it)->cl->Match(classhint->res_class)) return &((*it)->list); } if ((*it)->title->Match(name)) return &((*it)->list); } return NULL; } /** * @fn SetActionLists(void) * @brief Set all actions lists * * Updates all action lists for the window. */ void WaWindow::SetActionLists(void) { if (has_focus) { actionlist = GetActionList(&wascreen->config.ext_awinacts); if (! actionlist) actionlist = &wascreen->config.awinacts; } else { actionlist = GetActionList(&wascreen->config.ext_pwinacts); if (! actionlist) actionlist = &wascreen->config.pwinacts; } frame->actionlist = GetActionList(&wascreen->config.ext_frameacts); if (! frame->actionlist) frame->actionlist = &wascreen->config.frameacts; title->actionlist = GetActionList(&wascreen->config.ext_titleacts); if (! title->actionlist) title->actionlist = &wascreen->config.titleacts; label->actionlist = GetActionList(&wascreen->config.ext_labelacts); if (! label->actionlist) label->actionlist = &wascreen->config.labelacts; handle->actionlist = GetActionList(&wascreen->config.ext_handleacts); if (! handle->actionlist) handle->actionlist = &wascreen->config.handleacts; grip_l->actionlist = GetActionList(&wascreen->config.ext_lgacts); if (! grip_l->actionlist) grip_l->actionlist = &wascreen->config.lgacts; grip_r->actionlist = GetActionList(&wascreen->config.ext_rgacts); if (! grip_r->actionlist) grip_r->actionlist = &wascreen->config.rgacts; int i; list::iterator it = buttons.begin(); for (i = 0; it != buttons.end(); ++it, ++i) { (*it)->actionlist = GetActionList(wascreen->config.ext_bacts[i]); if (! (*it)->actionlist) (*it)->actionlist = wascreen->config.bacts[i]; } } /** * @fn Gravitate(int multiplier) * @brief Applies or removes window gravity * * If multiplier parameter is RemoveGravity when we set the window * attributes so that the frame will match the windows position. * If multiplier parameter is ApplyGravity when we set the window * attributes so that the window will match the frames position. * * @param multiplier ApplyGravity or RemoveGravity */ void WaWindow::Gravitate(int multiplier) { switch (size.win_gravity) { case NorthWestGravity: attrib.x += multiplier * border_w * 2; case NorthEastGravity: attrib.x -= multiplier * border_w; case NorthGravity: attrib.y += multiplier * border_w; if (title_w) attrib.y += multiplier * (title_w + border_w); break; case SouthWestGravity: attrib.x += multiplier * border_w * 2; case SouthEastGravity: attrib.x -= multiplier * border_w; case SouthGravity: attrib.y -= multiplier * border_w; if (handle_w) attrib.y -= multiplier * (handle_w + border_w); break; case CenterGravity: attrib.x += multiplier * (border_w / 2); attrib.y += multiplier * (border_w / 2); if (title_w) attrib.y += multiplier * ((title_w + border_w) / 2); break; case StaticGravity: break; } } /** * @fn InitPosition(void) * @brief Sets window position * * Initializes position for the window. */ 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 = old_attrib.height = old_attrib.width = - 0xffff; } /** * @fn MapWindow(void) * @brief Map window * * Map client window and all child windows. */ void WaWindow::MapWindow(void) { XGrabServer(display); if (validatedrawable(id)) { XMapWindow(display, id); RedrawWindow(); } else DELETED; XUngrabServer(display); if (flags.handle) { XMapRaised(display, grip_l->id); XMapRaised(display, handle->id); XMapRaised(display, grip_r->id); } else { XUnmapWindow(display, grip_l->id); XUnmapWindow(display, handle->id); XUnmapWindow(display, grip_r->id); } if (flags.title) { XMapRaised(display, title->id); XMapRaised(display, label->id); list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) XMapRaised(display, (*bit)->id); } else { XUnmapWindow(display, title->id); XUnmapWindow(display, label->id); list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) XUnmapWindow(display, (*bit)->id); } if (desktop_mask & (1L << wascreen->current_desktop->number)) XMapWindow(display, frame->id); else { hidden = true; } mapped = true; } /** * @fn Show(void) * @brief Show window * * Map frame window if not mapped. */ void WaWindow::Show(void) { if (hidden && mapped) { XMapWindow(display, frame->id); hidden = false; } } /** * @fn Hide(void) * @brief Hide window * * Unmap frame window if mapped. */ void WaWindow::Hide(void) { if (! hidden) { XUnmapWindow(display, frame->id); hidden = true; } } /** * @fn UpdateAllAttributes(void) * @brief Updates all window attrubutes * * Updates all positions and sizes of all windows in the frame. */ void WaWindow::UpdateAllAttributes(void) { Gravitate(RemoveGravity); border_w = (flags.border * wascreen->wstyle.border_width); title_w = (flags.title * wascreen->wstyle.title_height); handle_w = (flags.handle * wascreen->wstyle.handle_width); Gravitate(ApplyGravity); frame->attrib.x = attrib.x - border_w; frame->attrib.y = attrib.y - border_w; if (flags.title) frame->attrib.y -= title_w + border_w; frame->attrib.width = attrib.width; frame->attrib.height = attrib.height; if (flags.title) frame->attrib.height += title_w + border_w; if (flags.handle) frame->attrib.height += handle_w + border_w; XSetWindowBorderWidth(display, frame->id, border_w); if (! flags.shaded) XResizeWindow(display, frame->id, frame->attrib.width, frame->attrib.height); XMoveWindow(display, frame->id, frame->attrib.x, frame->attrib.y); if (flags.title) { title->attrib.x = - border_w; title->attrib.y = - border_w; title->attrib.width = attrib.width; title->attrib.height = title_w; XSetWindowBorderWidth(display, title->id, border_w); XMoveResizeWindow(display, title->id, title->attrib.x, title->attrib.y, title->attrib.width, title->attrib.height); label->attrib.x = label->g_x; label->attrib.y = 2; label->attrib.width = attrib.width + label->g_x2 - label->g_x; if (label->attrib.width < 1) label->attrib.width = 1; label->attrib.height = title_w - 4; XMoveResizeWindow(display, label->id, label->attrib.x, label->attrib.y, label->attrib.width, label->attrib.height); list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) { (*bit)->attrib.x = ((*bit)->g_x > 0)? (*bit)->g_x: (attrib.width + (*bit)->g_x - (title_w - 4)); (*bit)->attrib.y = 2; (*bit)->attrib.width = title_w - 4; (*bit)->attrib.height = title_w - 4; XMoveResizeWindow(display, (*bit)->id, (*bit)->attrib.x, (*bit)->attrib.y, (*bit)->attrib.width, (*bit)->attrib.height); } DrawTitlebar(true); } if (flags.handle) { handle->attrib.x = 25; handle->attrib.y = frame->attrib.height - handle_w - border_w; handle->attrib.width = attrib.width - 50 - border_w * 2; if (handle->attrib.width < 1) handle->attrib.width = 1; handle->attrib.height = wascreen->wstyle.handle_width; XSetWindowBorderWidth(display, handle->id, border_w); XMoveResizeWindow(display, handle->id, handle->attrib.x, handle->attrib.y, handle->attrib.width, handle->attrib.height); grip_l->attrib.x = - border_w; grip_l->attrib.y = frame->attrib.height - handle_w - border_w; grip_l->attrib.width = 25; grip_l->attrib.height = wascreen->wstyle.handle_width; XSetWindowBorderWidth(display, grip_l->id, border_w); XMoveResizeWindow(display, grip_l->id, grip_l->attrib.x, grip_l->attrib.y, grip_l->attrib.width, grip_l->attrib.height); grip_r->attrib.x = attrib.width - 25 - border_w; grip_r->attrib.y = frame->attrib.height - handle_w - border_w; grip_r->attrib.width = 25; grip_r->attrib.height = wascreen->wstyle.handle_width; XSetWindowBorderWidth(display, grip_r->id, border_w); XMoveResizeWindow(display, grip_r->id, grip_r->attrib.x, grip_r->attrib.y, grip_r->attrib.width, grip_r->attrib.height); DrawHandlebar(true); } XGrabServer(display); if (validatedrawable(id)) { if (flags.title) XMoveWindow(display, id, 0, title_w + border_w); else XMoveWindow(display, id, 0, title_w); } else DELETED; XUngrabServer(display); int m_x, m_y, m_w, m_h; if (flags.max) { m_x = restore_max.x; m_y = restore_max.y; m_w = restore_max.width; m_h = restore_max.height; flags.max = false; _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(); #ifdef SHAPE Shape(); #endif // SHAPE } /** * @fn RedrawWindow(bool force_if_viewable) * @brief Redraws Window * * Redraws the window at it's correct position with it's correct size. * We only redraw those things that need to be redrawn. * * @param force_if_viewable Force redraw if window is viewable */ void WaWindow::RedrawWindow(bool force_if_viewable) { Bool move = false, resize = false; if (old_attrib.x != attrib.x) { frame->attrib.x = attrib.x - border_w; old_attrib.x = attrib.x; move = true; } if (old_attrib.y != attrib.y) { frame->attrib.y = attrib.y - border_w; if (flags.title) frame->attrib.y -= title_w + border_w; old_attrib.y = attrib.y; move = true; } if (old_attrib.width != attrib.width) { frame->attrib.width = attrib.width; old_attrib.width = attrib.width; resize = true; if (flags.title) { title->attrib.width = attrib.width; label->attrib.width = attrib.width + label->g_x2 - label->g_x; if (label->attrib.width < 1) label->attrib.width = 1; list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) { (*bit)->attrib.x = ((*bit)->g_x > 0)? (*bit)->g_x: (attrib.width + (*bit)->g_x - (title_w - 4)); XMoveResizeWindow(display, (*bit)->id, (*bit)->attrib.x, (*bit)->attrib.y, (*bit)->attrib.width, (*bit)->attrib.height); } XResizeWindow(display, title->id, title->attrib.width, title->attrib.height); XResizeWindow(display, label->id, label->attrib.width, label->attrib.height); #ifdef XFT if (wascreen->config.db) { Region region = XCreateRegion(); XRectangle xrect; xrect.x = label->g_x; xrect.y = 2; xrect.width = label->attrib.width; xrect.height = label->attrib.height; XUnionRectWithRegion(&xrect, region, region); XftDrawSetClip(title->xftdraw, region); XDestroyRegion(region); } #endif // XFT if (! force_if_viewable) DrawTitlebar(); } if (flags.handle) { handle->attrib.width = attrib.width - 50 - border_w * 2; if (handle->attrib.width < 1) handle->attrib.width = 1; grip_r->attrib.x = attrib.width - 25 - border_w; XMoveWindow(display, grip_r->id, grip_r->attrib.x, grip_r->attrib.y); XResizeWindow(display, handle->id, handle->attrib.width, handle->attrib.height); if (! force_if_viewable) DrawHandlebar(); } } if (old_attrib.height != attrib.height) { frame->attrib.height = attrib.height; if (flags.title) frame->attrib.height += title_w + border_w; if (flags.handle) frame->attrib.height += handle_w + border_w; old_attrib.height = attrib.height; resize = true; if (flags.handle) { handle->attrib.y = frame->attrib.height - handle_w - border_w; grip_l->attrib.y = frame->attrib.height - handle_w - border_w; grip_r->attrib.y = frame->attrib.height - handle_w - border_w; XMoveWindow(display, handle->id, handle->attrib.x, handle->attrib.y); XMoveWindow(display, grip_l->id, grip_l->attrib.x, grip_l->attrib.y); XMoveWindow(display, grip_r->id, grip_r->attrib.x, grip_r->attrib.y); } } if (move) { if (flags.max) { restore_max.misc0 = wascreen->v_x + frame->attrib.x; restore_max.misc1 = wascreen->v_y + frame->attrib.y; net->SetWmState(this); } XMoveWindow(display, frame->id, frame->attrib.x, frame->attrib.y); #ifdef RENDER if (! resize && ! force_if_viewable) { if (! wascreen->config.lazy_trans) { render_if_opacity = true; DrawTitlebar(); DrawHandlebar(); render_if_opacity = false; } } #endif // RENDER } if (force_if_viewable) { DrawTitlebar(); DrawHandlebar(); } if (resize) { if (flags.max && (old_attrib.width != attrib.width || ! flags.shaded)) { flags.max = false; net->SetWmState(this); if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) { if ((*bit)->bstyle->cb == ShadeCBoxType) (*bit)->Render(); } } wascreen->UpdateCheckboxes(MaxCBoxType); } XGrabServer(display); if (validatedrawable(id)) { if (flags.shaded) XResizeWindow(display, id, attrib.width, restore_shade); else XResizeWindow(display, id, attrib.width, attrib.height); XResizeWindow(display, frame->id, frame->attrib.width, frame->attrib.height); } else DELETED; XUngrabServer(display); #ifdef SHAPE Shape(); #endif // SHAPE } if ((move || resize) && (! flags.shaded) && (! dontsend)) { #ifdef RENDER if (wascreen->config.lazy_trans) { render_if_opacity = true; DrawTitlebar(); DrawHandlebar(); render_if_opacity = false; } #endif // RENDER net->SetVirtualPos(this); SendConfig(); } } /** * @fn ReparentWin(void) * @brief Reparents the window into the frame * * Sets the input mask for the managed window so that it will report * FocusChange and PropertyChange events. Then we reparent the window into * our frame and activates needed grab buttons. */ void WaWindow::ReparentWin(void) { XSetWindowAttributes attrib_set; XGrabServer(display); if (validatedrawable(id)) { XSelectInput(display, id, NoEventMask); XSetWindowBorderWidth(display, id, 0); XReparentWindow(display, id, frame->id, 0, title_w + border_w); XChangeSaveSet(display, id, SetModeInsert); XFlush(display); attrib_set.event_mask = PropertyChangeMask | StructureNotifyMask | FocusChangeMask; attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask | ButtonMotionMask; 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); #endif // SHAPE } else DELETED; XUngrabServer(display); } /** * @fn UpdateGrabs(void) * @brief Update window grabs * * Updates passive window grabs for the window. */ void WaWindow::UpdateGrabs(void) { XGrabServer(display); if (validateclient_mapped(id)) { XUngrabButton(display, AnyButton, AnyModifier, id); XUngrabKey(display, AnyKey, AnyModifier, id); list::iterator it = actionlist->begin(); for (; it != 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); } } } else DELETED; XUngrabServer(display); } #ifdef SHAPE /** * @fn Shape(void) * @brief Set Shape of frame window * * Shapes frame window after shape of client. */ void WaWindow::Shape(void) { int n; XRectangle xrect[2]; if (shaped) { XGrabServer(display); if (validatedrawable(id)) { XShapeCombineShape(display, frame->id, ShapeBounding, border_w, title_w + border_w, id, ShapeBounding, ShapeSet); n = 0; if (title_w) { xrect[n].x = -border_w; xrect[n].y = -border_w; xrect[n].width = attrib.width + border_w * 2; xrect[n].height = title_w + border_w * 2; n++; } if (handle_w) { xrect[n].x = -border_w; xrect[n].y = attrib.height + title_w; if (title_w) xrect[n].y += border_w; xrect[n].width = attrib.width + border_w * 2; xrect[n].height = handle_w + border_w * 2; n++; } XShapeCombineRectangles(display, frame->id, ShapeBounding, 0, 0, xrect, n, ShapeUnion, Unsorted); } else DELETED; XUngrabServer(display); } } #endif // SHAPE /** * @fn SendConfig(void) * @brief Sends ConfigureNotify to window * * Sends a ConfigureNotify event to the window with all the current * window attributes. */ 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 = 0; ce.above = frame->id; ce.override_redirect = false; if (flags.shaded) ce.height = restore_shade; else ce.height = attrib.height; XGrabServer(display); if (validatedrawable(id)) { XSendEvent(display, id, false, StructureNotifyMask, (XEvent *) &ce); XSendEvent(display, wascreen->id, false, StructureNotifyMask, (XEvent *) &ce); } else DELETED; XUngrabServer(display); } /** * @fn CreateOutline(void) * @brief Creates window outline * * Creates four windows used for displaying an outline when doing * non opaque moving and resizing of the window. */ void WaWindow::CreateOutline(void) { XSetWindowAttributes attrib_set; int create_mask = CWOverrideRedirect | CWBackPixel | CWEventMask | CWColormap; attrib_set.background_pixel = wascreen->wstyle.outline_color.getPixel(); attrib_set.colormap = wascreen->colormap; attrib_set.override_redirect = true; attrib_set.event_mask = NoEventMask; o_west = XCreateWindow(display, wascreen->id, 0, 0, 1, 1, 0, screen_number, CopyFromParent, wascreen->visual, create_mask, &attrib_set); o_east = XCreateWindow(display, wascreen->id, 0, 0, 1, 1, 0, screen_number, CopyFromParent, wascreen->visual, create_mask, &attrib_set); o_north = XCreateWindow(display, wascreen->id, 0, 0, 1, 1, 0, screen_number, CopyFromParent, wascreen->visual, create_mask, &attrib_set); o_south = XCreateWindow(display, wascreen->id, 0, 0, 1, 1, 0, screen_number, CopyFromParent, wascreen->visual, create_mask, &attrib_set); wascreen->always_on_top_list.push_back(o_west); wascreen->always_on_top_list.push_back(o_east); wascreen->always_on_top_list.push_back(o_north); wascreen->always_on_top_list.push_back(o_south); XMapWindow(display, o_west); XMapWindow(display, o_east); XMapWindow(display, o_north); XMapWindow(display, o_south); wascreen->WaRaiseWindow(0); } /** * @fn DestroyOutline(void) * @brief Destroys window outline * * Destorys the four outline windows. */ void WaWindow::DestroyOutline(void) { wascreen->always_on_top_list.remove(o_west); wascreen->always_on_top_list.remove(o_east); wascreen->always_on_top_list.remove(o_north); wascreen->always_on_top_list.remove(o_south); XDestroyWindow(display, o_west); XDestroyWindow(display, o_east); XDestroyWindow(display, o_north); XDestroyWindow(display, o_south); } /** * @fn DrawOutline(int x, int y, int width, int height) * @brief Draw window outline * * Draws an outer line for a window with the parameters given. * * @param x The x position * @param y The y position * @param width The width * @param height The height */ void WaWindow::DrawOutline(int x, int y, int width, int height) { int bw = (border_w) ? border_w: 2; XResizeWindow(display, o_west, bw, bw * 2 + title_w + handle_w + height + border_w * 2); XResizeWindow(display, o_east, bw, bw * 2 + title_w + handle_w + height + border_w * 2); XResizeWindow(display, o_north, width + bw * 2, bw); XResizeWindow(display, o_south, width + bw * 2, bw); XMoveWindow(display, o_west, x - bw, y - title_w - border_w - bw); XMoveWindow(display, o_east, x + width, y - title_w - border_w - bw); XMoveWindow(display, o_north, x - bw, y - title_w - border_w - bw); XMoveWindow(display, o_south, x - bw, y + height + handle_w + border_w); } /** * @fn DrawTitlebar(bool force) * @brief Draw window titlebar * * Renders titlebar pixmaps and draws titlebar foreground. * * @param force True if rendering should be forced */ void WaWindow::DrawTitlebar(bool force) { if (force || (title_w && ((attrib.x + attrib.width) > 0 && attrib.x < wascreen->width) && ((attrib.y - border_w) > 0 && (attrib.y - border_w - title_w) < wascreen->height))) { title->Render(); label->Render(); list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) (*bit)->Render(); } } /** * @fn DrawHandlebar(bool force) * @brief Draw window handlebar * * Renders handlebar pixmaps and draws handlebar foreground. * * @param force True if rendering should be forced */ void WaWindow::DrawHandlebar(bool force) { if (force || (handle_w && ((attrib.x + attrib.width) > 0 && attrib.x < wascreen->width) && (attrib.y + attrib.height + border_w + handle_w) > 0 && (attrib.y + attrib.height + border_w) < wascreen->height)) { handle->Render(); grip_r->Render(); grip_l->Render(); } } /** * @fn FocusWin(void) * @brief Sets window to have the look of a focused window * * Sets window decoration pointers to point so that window decorations will * represent a focused window. Redraws needed graphics. */ void WaWindow::FocusWin(void) { if (has_focus) return; has_focus = true; if (title_w) DrawTitlebar(true); if (handle_w) DrawHandlebar(true); } /** * @fn UnFocusWin(void) * @brief Sets window to have the look of a unfocused window * * Sets window decoration pointers to point so that window decorations will * represent an unfocused window. Redraws needed graphics. */ void WaWindow::UnFocusWin(void) { if (! has_focus) return; has_focus = false; if (title_w) DrawTitlebar(true); if (handle_w) DrawHandlebar(true); } /** * @fn ButtonPressed(int type) * @brief Titlebar buttonpress * * Performes button press animation on one of the titlebar buttons. * * @param button WaChildWindow pointer to button that should be pressed */ void WaWindow::ButtonPressed(WaChildWindow *button) { XEvent e; bool in_window = true; if (waimea->eh->move_resize != EndMoveResizeType) return; XUngrabButton(display, AnyButton, AnyModifier, id); XUngrabKey(display, AnyKey, AnyModifier, id); button->pressed = true; button->Render(); for (;;) { XMaskEvent(display, ButtonReleaseMask | EnterWindowMask | LeaveWindowMask, &e); switch (e.type) { case EnterNotify: in_window = true; button->pressed = true; button->Render(); break; case LeaveNotify: button->pressed = false; button->Render(); in_window = false; break; case ButtonRelease: button->pressed = false; button->Render(); if (in_window) XPutBackEvent(display, &e); UpdateGrabs(); waimea->eh->move_resize = EndMoveResizeType; return; } } } /** * @fn IncSizeCheck(int width, int height, int *n_w, int *n_h) * @brief Calculate increasement sizes * * Given a new width and height this functions calculates if the windows * increasement sizes allows a resize of the window. The n_w parameter * is used for returning allowed width and the n_h parameter is used for * returning allowed height. * * @param width Width we want to resize to * @param height Height we want to resize to * @param n_w Return of allowed width * @param n_h Return of allowed height * * @return True if a resize is allowed otherwise false */ bool WaWindow::IncSizeCheck(int width, int height, int *n_w, int *n_h) { bool resize = false; *n_w = attrib.width; *n_h = attrib.height; if ((width >= (attrib.width + size.width_inc)) || (width <= (attrib.width - size.width_inc)) || attrib.width == width) { if (width >= size.min_width && width <= 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 <= -(handle_w + border_w * 2)) && title_w) { if (! flags.shaded) { flags.shaded = true; restore_shade = attrib.height; net->SetWmState(this); if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) if ((*bit)->bstyle->cb == ShadeCBoxType) (*bit)->Render(); } wascreen->UpdateCheckboxes(ShadeCBoxType); } *n_h = -(handle_w + border_w); if (handle_w) *n_h -= border_w; return resize; } if ((height >= (attrib.height + size.height_inc)) || (height <= (attrib.height - size.height_inc)) || attrib.height == height) { if ((height < 1) && (size.min_height <= 1) && title_w) { resize = true; if (! flags.shaded) { flags.shaded = true; restore_shade = attrib.height; net->SetWmState(this); if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) if ((*bit)->bstyle->cb == ShadeCBoxType) (*bit)->Render(); } wascreen->UpdateCheckboxes(ShadeCBoxType); } if (size.height_inc == 1) *n_h = height; else *n_h = height - ((height - size.base_height) % size.height_inc); } else if (height >= size.min_height && height <= size.max_height) { resize = true; if (flags.shaded) { flags.shaded = false; net->SetWmState(this); if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) if ((*bit)->bstyle->cb == ShadeCBoxType) (*bit)->Render(); } wascreen->UpdateCheckboxes(ShadeCBoxType); } if (size.height_inc == 1) *n_h = height; else *n_h = height - ((height - size.base_height) % size.height_inc); } } return resize; } /** * @fn Raise(XEvent *, WaAction *) * @brief Raises the window * * Raises the window to the top of the display stack and redraws window * foreground. */ void WaWindow::Raise(XEvent *, WaAction *) { if (flags.forcedatbottom) return; if (! flags.alwaysontop && ! flags.alwaysatbottom) { wascreen->wa_list_stacking.remove(this); wascreen->wa_list_stacking.push_front(this); if (! transients.empty()) { list::iterator it = transients.begin(); for (;it != transients.end(); ++it) { WaWindow *ww = (WaWindow *) waimea->FindWin(*it, WindowType); if (ww) { wascreen->wa_list_stacking.remove(ww); wascreen->wa_list_stacking.push_front(ww); } else { transients.erase(it); it = transients.begin(); } } } wascreen->WaLowerWindow((Window) 0); net->SetClientListStacking(wascreen); } } /** * @fn Lower(XEvent *, WaAction *) * @brief Lowers the window * * Lowers the window to the bottom of the display stack */ void WaWindow::Lower(XEvent *, WaAction *) { if (flags.forcedatbottom) return; if (! flags.alwaysontop && ! flags.alwaysatbottom) { wascreen->wa_list_stacking.remove(this); wascreen->wa_list_stacking.push_back(this); wascreen->WaLowerWindow(frame->id); net->SetClientListStacking(wascreen); } } /** * @fn Focus(bool vis) * @brief Sets input focus to the window * * Gives window keyboard input focus. If vis parameter is true we make sure * the window is viewable. * * @param vis True if we should make sure the window is viewable */ void WaWindow::Focus(bool vis) { int newvx, newvy, x, y; XEvent e; if (! flags.focusable || ((! vis) && hidden)) return; if (mapped) { if (vis) { if (! (desktop_mask & (1L << wascreen->current_desktop->number))) { list::iterator dit = wascreen->desktop_list.begin(); for (; dit != wascreen->desktop_list.end(); dit++) if (desktop_mask & (1L << (*dit)->number)) { wascreen->GoToDesktop((*dit)->number); break; } } bool x_toolarge = false, y_toolarge = false; if ((wascreen->v_x + attrib.x) >= (wascreen->v_xmax + wascreen->width)) x_toolarge = true; if ((wascreen->v_y + attrib.y) >= (wascreen->v_ymax + wascreen->height)) y_toolarge = true; if (x_toolarge || y_toolarge) { int bw = flags.border * border_w; int handleh = handle_w + flags.handle * bw; int th = attrib.height + bw + handleh; int tw = attrib.width + bw; if (x_toolarge) attrib.x = (wascreen->v_xmax + wascreen->width - wascreen->v_x) - tw; if (y_toolarge) attrib.y = (wascreen->v_ymax + wascreen->height - wascreen->v_y) - th; RedrawWindow(); } if (attrib.x >= wascreen->width || attrib.y >= wascreen->height || (attrib.x + attrib.width) <= 0 || (attrib.y + attrib.height) <= 0) { x = wascreen->v_x + attrib.x; y = wascreen->v_y + attrib.y; newvx = (x / wascreen->width) * wascreen->width; newvy = (y / wascreen->height) * wascreen->height; wascreen->MoveViewportTo(newvx, newvy); XSync(display, false); while (XCheckTypedEvent(display, EnterNotify, &e)); } } XInstallColormap(display, attrib.colormap); XGrabServer(display); if (validateclient_mapped(id)) { XSetInputFocus(display, id, RevertToPointerRoot, CurrentTime); } else DELETED; XUngrabServer(display); } else want_focus = true; } /** * @fn Move(XEvent *e) * @brief Moves the window * * Moves the window through displaying an outline of the window while dragging * the mouse. * * @param e XEvent causing start of move */ void WaWindow::Move(XEvent *e, WaAction *) { XEvent event, *map_ev; int px, py, nx, ny, i; list *maprequest_list; bool started = false; Window w; unsigned int ui; XQueryPointer(display, wascreen->id, &w, &w, &px, &py, &i, &i, &ui); if (waimea->eh->move_resize != EndMoveResizeType) return; nx = attrib.x; ny = attrib.y; waimea->eh->move_resize = MoveType; move_resize = true; if (e->type == MapRequest) { nx = attrib.x = px + border_w; ny = attrib.y = py + title_w + border_w; CreateOutline(); DrawOutline(nx, ny, attrib.width, attrib.height); started = true; } maprequest_list = new list; XGrabServer(display); if (validatedrawable(id)) { if (XGrabPointer(display, (mapped && !hidden) ? id: wascreen->id, true, ButtonReleaseMask | ButtonPressMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask, GrabModeAsync, GrabModeAsync, None, waimea->move_cursor, CurrentTime) != GrabSuccess) { move_resize = false; waimea->eh->move_resize = EndMoveResizeType; return; } if (XGrabKeyboard(display, (mapped && !hidden) ? id: wascreen->id, true, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) { move_resize = false; waimea->eh->move_resize = EndMoveResizeType; return; } } else DELETED; XUngrabServer(display); 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; if (! started) { CreateOutline(); started = true; } DrawOutline(nx, ny, attrib.width, attrib.height); break; case LeaveNotify: case EnterNotify: if (wascreen->west->id == event.xcrossing.window || wascreen->east->id == event.xcrossing.window || wascreen->north->id == event.xcrossing.window || wascreen->south->id == event.xcrossing.window) { waimea->eh->HandleEvent(&event); } else if (event.type == LeaveNotify) { int cx, cy; XQueryPointer(display, wascreen->id, &w, &w, &cx, &cy, &i, &i, &ui); nx += cx - px; ny += cy - py; px = cx; py = cy; if (! started) { CreateOutline(); started = true; } DrawOutline(nx, ny, attrib.width, attrib.height); } 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); if (started) DestroyOutline(); XUngrabKeyboard(display, CurrentTime); XUngrabPointer(display, CurrentTime); waimea->eh->move_resize = EndMoveResizeType; 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); DrawOutline(nx, ny, attrib.width, attrib.height); if (waimea->eh->move_resize != EndMoveResizeType) break; if (started) DestroyOutline(); attrib.x = nx; attrib.y = ny; 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; } } } /** * @fn MoveOpaque(XEvent *e, WaAction *) * @brief Moves the window * * Moves the window using the opaque moving process, which means that the * window is moved after the mouse pointers every motion event. * * @param e XEvent causing start of move */ void WaWindow::MoveOpaque(XEvent *e, WaAction *) { XEvent event, *map_ev; int sx, sy, px, py, nx, ny, i; list *maprequest_list; Window w; unsigned int ui; if (waimea->eh->move_resize != EndMoveResizeType) return; sx = nx = attrib.x; sy = ny = attrib.y; waimea->eh->move_resize = MoveOpaqueType; move_resize = true; XQueryPointer(display, wascreen->id, &w, &w, &px, &py, &i, &i, &ui); if (e->type == MapRequest) { nx = attrib.x = px + border_w; ny = attrib.y = py + title_w + border_w; RedrawWindow(); net->SetState(this, NormalState); net->SetVirtualPos(this); } dontsend = true; maprequest_list = new list; XGrabServer(display); if (validatedrawable(id)) { if (XGrabPointer(display, (mapped && !hidden) ? id: wascreen->id, true, ButtonReleaseMask | ButtonPressMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask, GrabModeAsync, GrabModeAsync, None, waimea->move_cursor, CurrentTime) != GrabSuccess) { move_resize = false; waimea->eh->move_resize = EndMoveResizeType; return; } if (XGrabKeyboard(display, (mapped && !hidden) ? id: wascreen->id, true, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) { move_resize = false; waimea->eh->move_resize = EndMoveResizeType; return; } } else DELETED; XUngrabServer(display); 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; attrib.x = nx; attrib.y = ny; RedrawWindow(); break; case LeaveNotify: case EnterNotify: if (wascreen->west->id == event.xcrossing.window || wascreen->east->id == event.xcrossing.window || wascreen->north->id == event.xcrossing.window || wascreen->south->id == event.xcrossing.window) { waimea->eh->HandleEvent(&event); } else if (event.type == LeaveNotify) { int cx, cy; XQueryPointer(display, wascreen->id, &w, &w, &cx, &cy, &i, &i, &ui); nx += cx - px; ny += cy - py; px = cx; py = cy; attrib.x = nx; attrib.y = ny; 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; 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); if (waimea->eh->move_resize != EndMoveResizeType) break; if (attrib.x != sx || attrib.y != sy) { #ifdef RENDER if (wascreen->config.lazy_trans) { render_if_opacity = true; DrawTitlebar(); DrawHandlebar(); render_if_opacity = false; } #endif // RENDER SendConfig(); net->SetVirtualPos(this); } 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; } } } /** * @fn Resize(XEvent *e, int how) * @brief Resizes the window * * Resizes the window through displaying a outline of the window while dragging * the mouse. If how parameter is RightType when the window is resized in * south-east direction and if how parameter is LeftType the resize is * being performed in south-west direction. * * @param e XEvent causing start of resize */ void WaWindow::Resize(XEvent *e, int how) { XEvent event, *map_ev; int px, py, width, height, n_w, n_h, o_w, o_h, n_x, o_x, i; list *maprequest_list; bool started = false; Window w; unsigned int ui; XQueryPointer(display, wascreen->id, &w, &w, &px, &py, &i, &i, &ui); if (waimea->eh->move_resize != EndMoveResizeType) return; n_x = o_x = attrib.x; width = n_w = o_w = attrib.width; height = n_h = o_h = attrib.height; waimea->eh->move_resize = ResizeType; move_resize = true; if (e->type == MapRequest) { if (how > 0) n_x = attrib.x = px - attrib.width - border_w * 2; else n_x = attrib.x = px; attrib.y = py - attrib.height - title_w - border_w * 4; CreateOutline(); DrawOutline(n_x, attrib.y, n_w, n_h); started = true; } maprequest_list = new list; XGrabServer(display); if (validatedrawable(id)) { if (XGrabPointer(display, (mapped && !hidden) ? id: wascreen->id, true, ButtonReleaseMask | ButtonPressMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask, GrabModeAsync, GrabModeAsync, None, (how > 0) ? waimea->resizeright_cursor: waimea->resizeleft_cursor, CurrentTime) != GrabSuccess) { move_resize = false; waimea->eh->move_resize = EndMoveResizeType; return; } if (XGrabKeyboard(display, (mapped && !hidden) ? id: wascreen->id, true, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) { move_resize = false; waimea->eh->move_resize = EndMoveResizeType; return; } } else DELETED; XUngrabServer(display); for (;;) { waimea->eh->EventLoop(waimea->eh->moveresize_return_mask, &event); switch (event.type) { case MotionNotify: while (XCheckTypedWindowEvent(display, event.xmotion.window, MotionNotify, &event)); width += (event.xmotion.x_root - px) * how; height += event.xmotion.y_root - py; px = event.xmotion.x_root; py = event.xmotion.y_root; if (IncSizeCheck(width, height, &n_w, &n_h)) { if (how == WestType) n_x -= n_w - o_w; if (! started) { CreateOutline(); started = true; } o_x = n_x; o_w = n_w; o_h = n_h; DrawOutline(n_x, attrib.y, n_w, n_h); } break; case LeaveNotify: case EnterNotify: if (wascreen->west->id == event.xcrossing.window || wascreen->east->id == event.xcrossing.window || wascreen->north->id == event.xcrossing.window || wascreen->south->id == event.xcrossing.window) { int old_vx = wascreen->v_x; int old_vy = wascreen->v_y; waimea->eh->HandleEvent(&event); px -= (wascreen->v_x - old_vx); py -= (wascreen->v_y - old_vy); n_x = attrib.x; if (how == WestType) n_x -= n_w - attrib.width; DrawOutline(n_x, attrib.y, n_w, n_h); } else if (event.type == LeaveNotify) { int cx, cy; XQueryPointer(display, wascreen->id, &w, &w, &cx, &cy, &i, &i, &ui); width += (cx - px) * how; height += cy - py; px = cx; py = cy; if (IncSizeCheck(width, height, &n_w, &n_h)) { if (how == WestType) n_x -= n_w - o_w; if (! started) { CreateOutline(); started = true; } o_x = n_x; o_w = n_w; o_h = n_h; DrawOutline(n_x, attrib.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); if (started) DestroyOutline(); XUngrabKeyboard(display, CurrentTime); XUngrabPointer(display, CurrentTime); waimea->eh->move_resize = EndMoveResizeType; 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); if (waimea->eh->move_resize != EndMoveResizeType) break; if (started) DestroyOutline(); attrib.width = n_w; attrib.height = n_h; attrib.x = n_x; 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; } } } /** * @fn ResizeOpaque(XEvent *e, int how) * @brief Resizes the window * * Resizes the window using the opaque resizing process, which means that * the window is resized after the mouse pointers every motion event. * If how parameter is RightType when the window is resized in * south-east direction and if how parameter is LeftType the resize is * being performed in south-west direction. * * @param e XEvent causing start of resize */ void WaWindow::ResizeOpaque(XEvent *e, int how) { XEvent event, *map_ev; int px, py, width, height, n_w, n_h, i, sw, sh; list *maprequest_list; Window w; unsigned int ui; XQueryPointer(display, wascreen->id, &w, &w, &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; move_resize = true; if (e->type == MapRequest) { if (how > 0) attrib.x = px - attrib.width - border_w * 2; else attrib.x = px; attrib.y = py - attrib.height - title_w - border_w * 4; RedrawWindow(); net->SetState(this, NormalState); net->SetVirtualPos(this); } maprequest_list = new list; XGrabServer(display); if (validatedrawable(id)) { if (XGrabPointer(display, (mapped && !hidden) ? id: wascreen->id, true, ButtonReleaseMask | ButtonPressMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask, GrabModeAsync, GrabModeAsync, None, (how > 0) ? waimea->resizeright_cursor: waimea->resizeleft_cursor, CurrentTime) != GrabSuccess) { move_resize = false; waimea->eh->move_resize = EndMoveResizeType; return; } if (XGrabKeyboard(display, (mapped && !hidden) ? id: wascreen->id, true, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) { move_resize = false; waimea->eh->move_resize = EndMoveResizeType; return; } } else DELETED; XUngrabServer(display); for (;;) { waimea->eh->EventLoop(waimea->eh->moveresize_return_mask, &event); switch (event.type) { case MotionNotify: while (XCheckTypedWindowEvent(display, event.xmotion.window, MotionNotify, &event)); width += (event.xmotion.x_root - px) * how; height += event.xmotion.y_root - py; px = event.xmotion.x_root; py = event.xmotion.y_root; if (IncSizeCheck(width, height, &n_w, &n_h)) { if (how == WestType) attrib.x -= n_w - attrib.width; attrib.width = n_w; attrib.height = n_h; RedrawWindow(); } break; case LeaveNotify: case EnterNotify: if (wascreen->west->id == event.xcrossing.window || wascreen->east->id == event.xcrossing.window || wascreen->north->id == event.xcrossing.window || wascreen->south->id == event.xcrossing.window) { int old_vx = wascreen->v_x; int old_vy = wascreen->v_y; waimea->eh->HandleEvent(&event); px -= (wascreen->v_x - old_vx); py -= (wascreen->v_y - old_vy); } else if (event.type == LeaveNotify) { int cx, cy; XQueryPointer(display, wascreen->id, &w, &w, &cx, &cy, &i, &i, &ui); width += (cx - px) * how; height += cy - py; px = cx; py = cy; if (IncSizeCheck(width, height, &n_w, &n_h)) { if (how == WestType) attrib.x -= n_w - attrib.width; attrib.width = n_w; attrib.height = n_h; 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; 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 = attrib.width; height = attrib.height; if (waimea->eh->move_resize != EndMoveResizeType) break; if (attrib.width != sw || attrib.height != sh) { SendConfig(); net->SetVirtualPos(this); } 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; } } } /** * @fn EndMoveResize(XEvent *e, WaAction *) * @brief Ends move/resize * * Ends moving and resizing process. */ void WaWindow::EndMoveResize(XEvent *, WaAction *) { waimea->eh->move_resize = EndMoveResizeType; } /** * @fn _Maximize(int x, int y) * @brief Maximize the window * * Maximizes the window so that the window with it's decorations fills up * the hole workarea. * * @param x Virtual x pos where window should be maximized, ignored if negative * @param y Virtual y pos where window should be maximized, ignored if negative */ void WaWindow::_Maximize(int x, int y) { int n_w, n_h, new_width, new_height; if (flags.max) return; int workx, worky, workw, workh; wascreen->GetWorkareaSize(&workx, &worky, &workw, &workh); new_width = workw - (flags.border * border_w * 2); new_height = workh - (flags.border * border_w * 2) - title_w - handle_w - (border_w * flags.title) - (border_w * flags.handle); restore_max.width = attrib.width; restore_max.height = attrib.height; int rest_x = attrib.x; int rest_y = attrib.y; if (flags.shaded) { 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 - wascreen->v_x); attrib.y = (y - wascreen->v_y); restore_max.misc0 = x; restore_max.misc1 = y; } else { restore_max.misc0 = wascreen->v_x + attrib.x; restore_max.misc1 = wascreen->v_y + attrib.y; } attrib.x += border_w; attrib.y += title_w + border_w + (border_w * flags.title); attrib.width = n_w; attrib.height = n_h; RedrawWindow(); flags.max = true; if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) if ((*bit)->bstyle->cb == MaxCBoxType) (*bit)->Render(); } net->SetWmState(this); wascreen->UpdateCheckboxes(MaxCBoxType); } } /** * @fn UnMaximize(XEvent *, WaAction *) * @brief Unmaximize the window * * Restores size and position of maximized window. */ void WaWindow::UnMaximize(XEvent *, WaAction *) { int n_w, n_h, rest_height, tmp_shade_height = 0; if (flags.max) { if (flags.shaded) { 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 - wascreen->v_x); attrib.y = restore_max.y + (restore_max.misc1 - wascreen->v_y); attrib.width = n_w; attrib.height = n_h; flags.max = false; RedrawWindow(); if (flags.shaded) restore_shade = tmp_shade_height; if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) if ((*bit)->bstyle->cb == MaxCBoxType) (*bit)->Render(); } net->SetWmState(this); wascreen->UpdateCheckboxes(MaxCBoxType); } } } /** * @fn ToggleMaximize(XEvent *, WaAction *) * @brief Maximizes or unmaximize window * * If window isn't maximized this function maximizes it and if it is already * maximized then function will unmaximized window. */ void WaWindow::ToggleMaximize(XEvent *, WaAction *) { if (! flags.max) Maximize(NULL, NULL); else UnMaximize(NULL, NULL); } /** * @fn Close(XEvent *, WaAction *) * @brief Close the window * * Sends a delete message to the client window. A normal running X window * should accept this event and destroy itself. */ void WaWindow::Close(XEvent *, WaAction *) { XEvent ev; ev.type = ClientMessage; ev.xclient.window = id; ev.xclient.message_type = XInternAtom(display, "WM_PROTOCOLS", false); ev.xclient.format = 32; ev.xclient.data.l[0] = XInternAtom(display, "WM_DELETE_WINDOW", false); ev.xclient.data.l[1] = CurrentTime; XGrabServer(display); if (validatedrawable(id)) XSendEvent(display, id, false, NoEventMask, &ev); else DELETED; XUngrabServer(display); } /** * @fn Kill(XEvent *, WaAction *) * @brief Kill the window * * Tells the the X server to remove the window from the screen through * killing the process that created it. */ void WaWindow::Kill(XEvent *, WaAction *) { XGrabServer(display); if (validatedrawable(id)) XKillClient(display, id); else DELETED; XUngrabServer(display); } /** * @fn CloseKill(XEvent *e, WaAction *ac) * @brief Close/Kill the window * * Checks if the window will accept a delete message. If it will, then we * use that method for closing the window otherwise we use the kill method. * * @param e XEvent causing close/kill of window * @param ac WaAction object */ void WaWindow::CloseKill(XEvent *e, WaAction *ac) { int i, n; bool close = false; Atom *protocols; Atom del_atom = XInternAtom(display, "WM_DELETE_WINDOW", false); XGrabServer(display); if (validatedrawable(id)) { if (XGetWMProtocols(display, id, &protocols, &n)) { for (i = 0; i < n; i++) if (protocols[i] == del_atom) close = true; XFree(protocols); } } else DELETED; XUngrabServer(display); if (close) Close(e, ac); else Kill(e, ac); } /** * @fn MenuMap(XEvent *e, WaAction *ac) * @brief Maps a menu * * Links the window to the menu and maps it at the position of the button * event causing mapping. If menu is already mapped nothing is done. * * @param ac WaAction object * @param bool True if we should focus first item in menu */ void WaWindow::MenuMap(XEvent *, WaAction *ac, bool focus) { Window w; int i, x, y, exp; unsigned int ui; WaMenu *menu = wascreen->GetMenuNamed(ac->param); if (! menu) return; if (waimea->eh->move_resize != EndMoveResizeType) return; int workx, worky, workw, workh; wascreen->GetWorkareaSize(&workx, &worky, &workw, &workh); if (XQueryPointer(display, wascreen->id, &w, &w, &x, &y, &i, &i, &ui)) { if (menu->tasksw) menu->Build(wascreen); menu->wf = id; menu->ftype = MenuWFuncMask; list::iterator it = menu->item_list.begin(); for (exp = 0; it != menu->item_list.end(); ++it) exp += (*it)->ExpandAll(this); if (exp) menu->Build(wascreen); if ((y + menu->height + wascreen->mstyle.border_width * 2) > (unsigned int) (workh + worky)) y -= (menu->height + wascreen->mstyle.border_width * 2); if ((x + menu->width + wascreen->mstyle.border_width * 2) > (unsigned int) (workw + workx)) x -= (menu->width + wascreen->mstyle.border_width * 2); menu->Map(x, y); if (focus) menu->FocusFirst(); } } /** * @fn MenuRemap(XEvent *e) * @brief Remaps a menu * * Links the window to the menu and maps it at the position of the button * event causing mapping. If the window is already mapped then we just move * it to the new position. * * @param ac WaAction object * @param bool True if we should focus first item in menu */ void WaWindow::MenuRemap(XEvent *, WaAction *ac, bool focus) { Window w; int i, x, y, exp; unsigned int ui; WaMenu *menu = wascreen->GetMenuNamed(ac->param); if (! menu) return; if (menu->dynamic && menu->mapped) { menu->Unmap(menu->has_focus); if (! (menu = wascreen->CreateDynamicMenu(ac->param))) return; } if (waimea->eh->move_resize != EndMoveResizeType) return; int workx, worky, workw, workh; wascreen->GetWorkareaSize(&workx, &worky, &workw, &workh); if (XQueryPointer(display, wascreen->id, &w, &w, &x, &y, &i, &i, &ui)) { if (menu->tasksw) menu->Build(wascreen); menu->wf = id; menu->ftype = MenuWFuncMask; list::iterator it = menu->item_list.begin(); for (exp = 0; it != menu->item_list.end(); ++it) exp += (*it)->ExpandAll(this); if (exp) menu->Build(wascreen); if ((y + menu->height + wascreen->mstyle.border_width * 2) > (unsigned int) (workh + worky)) y -= (menu->height + wascreen->mstyle.border_width * 2); if ((x + menu->width + wascreen->mstyle.border_width * 2) > (unsigned int) (workw + workx)) x -= (menu->width + wascreen->mstyle.border_width * 2); menu->ignore = true; menu->ReMap(x, y); menu->ignore = false; if (focus) menu->FocusFirst(); } } /** * @fn MenuUnmap(XEvent *, WaAction *ac, bool focus) * @brief Unmaps a menu * * Unmaps a menu and all its submenus. * * @param ac WaAction object * @param bool True if we should focus root item */ void WaWindow::MenuUnmap(XEvent *, WaAction *ac, bool focus) { WaMenu *menu = wascreen->GetMenuNamed(ac->param); if (! menu) return; if (waimea->eh->move_resize != EndMoveResizeType) return; menu->Unmap(focus); menu->UnmapSubmenus(focus); } /** * @fn Shade(XEvent *, WaAction *) * @brief Shade window * * Resizes window to so that only the titlebar is shown. Remembers previous * height of window that will be restored when unshading. */ void WaWindow::Shade(XEvent *, WaAction *) { int n_w, n_h; if (IncSizeCheck(attrib.width, -(handle_w + border_w * 2), &n_w, &n_h)) { attrib.width = n_w; attrib.height = n_h; RedrawWindow(); net->SetWmState(this); if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) if ((*bit)->bstyle->cb == ShadeCBoxType) (*bit)->Render(); } wascreen->UpdateCheckboxes(ShadeCBoxType); } } /** * @fn UnShade(XEvent *, WaAction *) * @brief Unshade window * * Restores height of shaded window. */ void WaWindow::UnShade(XEvent *, WaAction *) { if (flags.shaded) { attrib.height = restore_shade; RedrawWindow(); flags.shaded = false; net->SetWmState(this); if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) if ((*bit)->bstyle->cb == ShadeCBoxType) (*bit)->Render(); } wascreen->UpdateCheckboxes(ShadeCBoxType); } } /** * @fn ToggleShade(XEvent *, WaAction *) * @brief Shades window or unshades it * * If window isn't shaded this function will shade it and if it is already * shaded function unshades it. */ void WaWindow::ToggleShade(XEvent *, WaAction *) { if (flags.shaded) UnShade(NULL, NULL); else Shade(NULL, NULL); } /** * @fn Sticky(XEvent *, WaAction *) * @brief Makes window sticky * * Sets the sticky flag to true. This makes viewport moving functions * to ignore this window. */ void WaWindow::Sticky(XEvent *, WaAction *) { flags.sticky = true; net->SetWmState(this); if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) if ((*bit)->bstyle->cb == StickCBoxType) (*bit)->Render(); } wascreen->UpdateCheckboxes(StickCBoxType); } /** * @fn UnSticky(XEvent *, WaAction *) * @brief Makes window normal * * Sets the sticky flag to false. This makes viewport moving functions * treat this window as a normal window. */ void WaWindow::UnSticky(XEvent *, WaAction *) { flags.sticky = false; net->SetWmState(this); if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) if ((*bit)->bstyle->cb == StickCBoxType) (*bit)->Render(); } wascreen->UpdateCheckboxes(StickCBoxType); } /** * @fn ToggleSticky(XEvent *, WaAction *) * @brief Toggles sticky flag * * Inverts the sticky flag. */ void WaWindow::ToggleSticky(XEvent *, WaAction *) { flags.sticky = !flags.sticky; net->SetWmState(this); if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) if ((*bit)->bstyle->cb == StickCBoxType) (*bit)->Render(); } wascreen->UpdateCheckboxes(StickCBoxType); } /** * @fn TaskSwitcher(XEvent *, WaAction *) * @brief Maps task switcher menu * * Maps task switcher menu at middle of screen and sets input focus to * first window in list. */ void WaWindow::TaskSwitcher(XEvent *, WaAction *) { if (waimea->eh->move_resize != EndMoveResizeType) return; int workx, worky, workw, workh; wascreen->GetWorkareaSize(&workx, &worky, &workw, &workh); wascreen->window_menu->Build(wascreen); wascreen->window_menu->ReMap(workx + (workw / 2 - wascreen->window_menu->width / 2), worky + (workh / 2 - wascreen->window_menu->height / 2)); wascreen->window_menu->FocusFirst(); } /** * @fn PreviousTask(XEvent *, WaAction *) * @brief Switches to previous task * * Switches to the previous focused window. */ void WaWindow::PreviousTask(XEvent *, WaAction *) { if (waimea->eh->move_resize != EndMoveResizeType) return; list::iterator it = wascreen->wawindow_list.begin(); it++; (*it)->Raise(NULL, NULL); (*it)->FocusVis(NULL, NULL); } /** * @fn NextTask(XEvent *, WaAction *) * @brief Switches to next task * * Switches to the window that haven't had focus for longest time. */ void WaWindow::NextTask(XEvent *, WaAction *) { if (waimea->eh->move_resize != EndMoveResizeType) return; wascreen->wawindow_list.back()->Raise(NULL, NULL); wascreen->wawindow_list.back()->FocusVis(NULL, NULL); } /** * @fn DecorTitleOn(XEvent *, WaAction *) * @brief Turn on title decoration * * Turn on titlebar decorations for the window. */ void WaWindow::DecorTitleOn(XEvent *, WaAction *) { if (flags.title) return; flags.title = true; flags.all = flags.title && flags.handle && flags.border; UpdateAllAttributes(); MapWindow(); net->SetWmState(this); if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) if ((*bit)->bstyle->cb == TitleCBoxType || (flags.all && (*bit)->bstyle->cb == AllCBoxType)) (*bit)->Render(); } wascreen->UpdateCheckboxes(TitleCBoxType); if (flags.all) wascreen->UpdateCheckboxes(AllCBoxType); } /** * @fn DecorHandleOn(XEvent *, WaAction *) * @brief Turn on handle decoration * * Turn on handlebar decorations for the window. */ void WaWindow::DecorHandleOn(XEvent *, WaAction *) { if (flags.handle) return; flags.handle = true; flags.all = flags.title && flags.handle && flags.border; UpdateAllAttributes(); MapWindow(); net->SetWmState(this); if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) if ((*bit)->bstyle->cb == TitleCBoxType || (flags.all && (*bit)->bstyle->cb == AllCBoxType)) (*bit)->Render(); } wascreen->UpdateCheckboxes(HandleCBoxType); if (flags.all) wascreen->UpdateCheckboxes(AllCBoxType); } /** * @fn DecorBorderOn(XEvent *, WaAction *) * @brief Turn on border decoration * * Turn on border decorations for the window. */ void WaWindow::DecorBorderOn(XEvent *, WaAction *) { if (flags.border) return; flags.border = true; flags.all = flags.title && flags.handle && flags.border; UpdateAllAttributes(); MapWindow(); net->SetWmState(this); if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) if ((*bit)->bstyle->cb == BorderCBoxType || (flags.all && (*bit)->bstyle->cb == AllCBoxType)) (*bit)->Render(); } wascreen->UpdateCheckboxes(BorderCBoxType); if (flags.all) wascreen->UpdateCheckboxes(AllCBoxType); } /** * @fn DecorAllOn(XEvent *, WaAction *) * @brief Turn on all decorations * * Turn on all decorations for the window. */ void WaWindow::DecorAllOn(XEvent *, WaAction *) { if (flags.all) return; flags.all = true; flags.border = true; flags.title = true; flags.handle = true; UpdateAllAttributes(); MapWindow(); net->SetWmState(this); if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) if ((*bit)->bstyle->cb == TitleCBoxType || (*bit)->bstyle->cb == HandleCBoxType || (*bit)->bstyle->cb == BorderCBoxType || (*bit)->bstyle->cb == AllCBoxType) (*bit)->Render(); } wascreen->UpdateCheckboxes(TitleCBoxType); wascreen->UpdateCheckboxes(HandleCBoxType); wascreen->UpdateCheckboxes(BorderCBoxType); wascreen->UpdateCheckboxes(AllCBoxType); } /** * @fn DecorTitleOff(XEvent *, WaAction *) * @brief Turn off title decoration * * Turn off title decorations for the window. */ void WaWindow::DecorTitleOff(XEvent *, WaAction *) { if (flags.shaded || ! flags.title) return; flags.title = false; flags.all = false; UpdateAllAttributes(); MapWindow(); net->SetWmState(this); if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) if ((*bit)->bstyle->cb == TitleCBoxType || (flags.all && (*bit)->bstyle->cb == AllCBoxType)) (*bit)->Render(); } wascreen->UpdateCheckboxes(TitleCBoxType); wascreen->UpdateCheckboxes(AllCBoxType); } /** * @fn DecorHandleOff(XEvent *, WaAction *) * @brief Turn off hendle decoration * * Turn off handlebar decorations for the window. */ void WaWindow::DecorHandleOff(XEvent *, WaAction *) { if (! flags.handle) return; flags.handle = false; flags.all = false; UpdateAllAttributes(); MapWindow(); net->SetWmState(this); if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) if ((*bit)->bstyle->cb == HandleCBoxType || (flags.all && (*bit)->bstyle->cb == AllCBoxType)) (*bit)->Render(); } wascreen->UpdateCheckboxes(HandleCBoxType); wascreen->UpdateCheckboxes(AllCBoxType); } /** * @fn DecorBorderOff(XEvent *, WaAction *) * @brief Turn off border decoration * * Turn off border decorations for the window. */ void WaWindow::DecorBorderOff(XEvent *, WaAction *) { if (! flags.border) return; flags.border = false; flags.all = false; UpdateAllAttributes(); MapWindow(); net->SetWmState(this); if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) if ((*bit)->bstyle->cb == BorderCBoxType || (flags.all && (*bit)->bstyle->cb == AllCBoxType)) (*bit)->Render(); } wascreen->UpdateCheckboxes(BorderCBoxType); wascreen->UpdateCheckboxes(AllCBoxType); } /** * @fn DecorAllOff(XEvent *, WaAction *) * @brief Turn off all decorations * * Turn off all decorations for the window. */ void WaWindow::DecorAllOff(XEvent *, WaAction *) { if (flags.shaded || ! flags.all) return; flags.all = false; flags.border = false; flags.title = false; flags.handle = false; UpdateAllAttributes(); MapWindow(); net->SetWmState(this); if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) if ((*bit)->bstyle->cb == TitleCBoxType || (*bit)->bstyle->cb == HandleCBoxType || (*bit)->bstyle->cb == BorderCBoxType || (*bit)->bstyle->cb == AllCBoxType) (*bit)->Render(); } wascreen->UpdateCheckboxes(TitleCBoxType); wascreen->UpdateCheckboxes(HandleCBoxType); wascreen->UpdateCheckboxes(BorderCBoxType); wascreen->UpdateCheckboxes(AllCBoxType); } /** * @fn DecorTitleToggle(XEvent *, WaAction *) * @brief Toggle title decoration * * Toggle titlebar decorations for the window. */ void WaWindow::DecorTitleToggle(XEvent *, WaAction *) { if (flags.title) DecorTitleOff(NULL, NULL); else DecorTitleOn(NULL, NULL); } /** * @fn DecorHandleToggle(XEvent *, WaAction *) * @brief Toggle handle decoration * * Toggle handlebar decorations for the window. */ void WaWindow::DecorHandleToggle(XEvent *, WaAction *) { if (flags.handle) DecorHandleOff(NULL, NULL); else DecorHandleOn(NULL, NULL); } /** * @fn DecorBorderToggle(XEvent *, WaAction *) * @brief Toggle border decoration * * Toggle border decorations for the window. */ void WaWindow::DecorBorderToggle(XEvent *, WaAction *) { if (flags.border) DecorBorderOff(NULL, NULL); else DecorBorderOn(NULL, NULL); } /** * @fn AlwaysontopOn(XEvent *, WaAction *) * @brief Make window always on top * * Add window to list of always on top windows and update always on top * windows. */ void WaWindow::AlwaysontopOn(XEvent *, WaAction *) { if (flags.forcedatbottom) return; flags.alwaysontop = true; flags.alwaysatbottom = false; wascreen->wa_list_stacking.remove(this); wascreen->wawindow_list_stacking_aab.remove(this); wascreen->wawindow_list_stacking_aot.push_back(this); wascreen->WaRaiseWindow(0); net->SetWmState(this); if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) if ((*bit)->bstyle->cb == AOTCBoxType || (*bit)->bstyle->cb == AABCBoxType) (*bit)->Render(); } wascreen->UpdateCheckboxes(AOTCBoxType); wascreen->UpdateCheckboxes(AABCBoxType); net->SetClientListStacking(wascreen); } /** * @fn AlwaysatbottomOn(XEvent *, WaAction *) * @brief Make window always at bottom * * Add window to list of always at bottom windows and update always at bottom * windows. */ void WaWindow::AlwaysatbottomOn(XEvent *, WaAction *) { if (flags.forcedatbottom) return; flags.alwaysontop = false; flags.alwaysatbottom = true; wascreen->wa_list_stacking.remove(this); wascreen->wawindow_list_stacking_aot.remove(this); wascreen->wawindow_list_stacking_aab.push_back(this); wascreen->WaLowerWindow(frame->id); net->SetWmState(this); if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) if ((*bit)->bstyle->cb == AOTCBoxType || (*bit)->bstyle->cb == AABCBoxType) (*bit)->Render(); } wascreen->UpdateCheckboxes(AOTCBoxType); wascreen->UpdateCheckboxes(AABCBoxType); net->SetClientListStacking(wascreen); } /** * @fn AlwaysontopOff(XEvent *, WaAction *) * @brief Make window not always on top * * Removes window from list of always on top windows. */ void WaWindow::AlwaysontopOff(XEvent *, WaAction *) { if (flags.forcedatbottom) return; flags.alwaysontop = false; wascreen->wawindow_list_stacking_aot.remove(this); wascreen->wa_list_stacking.push_front(this); wascreen->WaRaiseWindow(0); net->SetWmState(this); if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) if ((*bit)->bstyle->cb == AOTCBoxType) (*bit)->Render(); } wascreen->UpdateCheckboxes(AOTCBoxType); net->SetClientListStacking(wascreen); } /** * @fn AlwaysatbottomOff(XEvent *, WaAction *) * @brief Make window not always at bottom * * Removes window from list of always at bottom windows. */ void WaWindow::AlwaysatbottomOff(XEvent *, WaAction *) { if (flags.forcedatbottom) return; flags.alwaysatbottom = false; wascreen->wawindow_list_stacking_aab.remove(this); wascreen->wa_list_stacking.push_back(this); wascreen->WaLowerWindow(frame->id); net->SetWmState(this); if (title_w) { list::iterator bit = buttons.begin(); for (; bit != buttons.end(); ++bit) if ((*bit)->bstyle->cb == AABCBoxType) (*bit)->Render(); } wascreen->UpdateCheckboxes(AABCBoxType); net->SetClientListStacking(wascreen); } /** * @fn AlwaysontopToggle(XEvent *, WaAction *) * @brief Toggle always on top flag * * If window is always on top we removed it from always on top list, or if * window isn't always on top we add it to always on top list. */ void WaWindow::AlwaysontopToggle(XEvent *, WaAction *) { if (flags.alwaysontop) AlwaysontopOff(NULL, NULL); else AlwaysontopOn(NULL, NULL); } /** * @fn AlwaysatbottomToggle(XEvent *, WaAction *) * @brief Toggle always at bottom flag * * If window is always at bottom we removed it from always at bottom list, * or if window isn't always at bottom we add it to always at bottom list. */ void WaWindow::AlwaysatbottomToggle(XEvent *, WaAction *) { if (flags.alwaysatbottom) AlwaysatbottomOff(NULL, NULL); else AlwaysatbottomOn(NULL, NULL); } /** * @fn AcceptConfigRequestOn(XEvent *, WaAction *) * @brief Accept ConfigureRequests from this window * * Sets flag so the configure request events from this window are handled as * usual. */ void WaWindow::AcceptConfigRequestOn(XEvent *, WaAction *) { ign_config_req = false; } /** * @fn AcceptConfigRequestOff(XEvent *, WaAction *) * @brief Don't accept ConfigureRequests from this window * * Sets flag so the configure request events from this window are ignored. */ void WaWindow::AcceptConfigRequestOff(XEvent *, WaAction *) { ign_config_req = true; } /** * @fn AcceptConfigRequestToggle(XEvent *, WaAction *) * @brief Toggle ign_config_req flag * * Toggles configure request ignore flag. */ void WaWindow::AcceptConfigRequestToggle(XEvent *, WaAction *) { ign_config_req = !ign_config_req; } /** * @fn MoveResize(XEvent *e, WaAction *ac) * @brief Moves and resizes window * * X geomtry string as WaAction parameter. Moves and resizes window to * the size and position in the actual screen area specified by X geometry * string. * * @param e XEvent causing function call * @param ac WaAction object */ void WaWindow::MoveResize(XEvent *e, WaAction *ac) { int x, y, geometry; unsigned int width, height; if (waimea->eh->move_resize != EndMoveResizeType || ! ac->param) return; width = attrib.width; height = attrib.height; geometry = XParseGeometry(ac->param, &x, &y, &width, &height); IncSizeCheck(width, height, &attrib.width, &attrib.height); if (geometry & XValue) { if (geometry & XNegative) attrib.x = wascreen->width + x - attrib.width; else attrib.x = x; } if (geometry & YValue) { if (geometry & YNegative) attrib.y = wascreen->height + y - attrib.height; else attrib.y = y; } RedrawWindow(); } /** * @fn MoveResizeVirtual(XEvent *e, WaAction *ac) * @brief Moves and resizes window * * X geomtry string as WaAction parameter. Moves and resizes window to * the size and position in the virtual screen area specified by X geometry * string. * * @param e XEvent causing function call * @param ac WaAction object */ void WaWindow::MoveResizeVirtual(XEvent *e, WaAction *ac) { int x, y, geometry; unsigned int width, height; if (waimea->eh->move_resize != EndMoveResizeType || ! ac->param) return; width = attrib.width; height = attrib.height; geometry = XParseGeometry(ac->param, &x, &y, &width, &height); IncSizeCheck(width, height, &attrib.width, &attrib.height); if (geometry & XValue) { if (geometry & XNegative) attrib.x = ((wascreen->v_xmax + wascreen->width) + x - attrib.width) - wascreen->v_x; else attrib.x = x - wascreen->v_x; } if (geometry & YValue) { if (geometry & YNegative) attrib.y = ((wascreen->v_ymax + wascreen->height) + y - attrib.height) - wascreen->v_y; else attrib.y = y - wascreen->v_y; } RedrawWindow(); } /** * @fn MoveWindowToPointer(XEvent *e, WaAction *) * @brief Moves window to pointer position * * Moves window to mouse pointer position and makes sure that it isn't * moved outside screen. * * @param e XEvent causing function call */ void WaWindow::MoveWindowToPointer(XEvent *e, WaAction *) { int total_h = border_w * 2; if (title_w) total_h += border_w; if (handle_w) total_h += border_w; total_h += attrib.height; attrib.x = e->xbutton.x_root - attrib.width / 2; attrib.y = e->xbutton.y_root - attrib.height / 2; if (attrib.x + border_w * 2 + attrib.width > wascreen->width) attrib.x = wascreen->width - attrib.width - border_w; else if (attrib.x < 0) attrib.x = border_w; if (attrib.y + total_h > wascreen->height) attrib.y = wascreen->height - handle_w - border_w - attrib.height - ((handle_w)? border_w: 0); else if (attrib.y < 0) attrib.y = title_w + border_w + ((title_w)? border_w: 0); RedrawWindow(); } /** * @fn MoveWindowToSmartPlace(XEvent *, WaAction *) * @brief Moves window to smart position * * Moves window using Smart Placement algorithm. */ void WaWindow::MoveWindowToSmartPlace(XEvent *, WaAction *) { int temp_h, temp_w; Gravitate(RemoveGravity); int workx, worky, workw, workh; wascreen->GetWorkareaSize(&workx, &worky, &workw, &workh); int test_x = attrib.x - workx; int test_y = attrib.y - worky - 1; int loc_ok = False, tw, tx, ty, th; int bw = flags.border * border_w; int titleh = title_w + flags.title * bw; int handleh = handle_w + flags.handle * bw; temp_h = attrib.height + bw * 2 + titleh + handleh; temp_w = attrib.width + bw * 2; while (((test_y + temp_h) < workh) && !loc_ok) { test_x = 0; while (((test_x + temp_w) < workw) && !loc_ok) { loc_ok = True; list::iterator it = wascreen->wawindow_list.begin(); for (; it != wascreen->wawindow_list.end() && (loc_ok == True); it++) { if ((*it != this) && ((*it)->flags.tasklist) && ((*it)->desktop_mask & (1L << wascreen->current_desktop->number)) && ((((*it)->attrib.x + (*it)->attrib.width) > 0 && (*it)->attrib.x < workw) && (((*it)->attrib.y + (*it)->attrib.height) > 0 && (*it)->attrib.y < workh))) { bw = (*it)->flags.border * (*it)->border_w; titleh = (*it)->title_w + (*it)->flags.title * bw; handleh = (*it)->handle_w + (*it)->flags.handle * bw; th = (*it)->attrib.height + bw * 2 + titleh + handleh; tw = (*it)->attrib.width + bw * 2; (*it)->Gravitate(RemoveGravity); tx = (*it)->attrib.x - workx - 1; ty = (*it)->attrib.y - worky - 1; (*it)->Gravitate(ApplyGravity); 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; } test_y += 1; } if (loc_ok != False) { attrib.x = test_x + workx - 1; attrib.y = test_y + worky; Gravitate(ApplyGravity); RedrawWindow(); } else Gravitate(ApplyGravity); } /** * @fn DesktopMask(XEvent *, WaAction *ac) * @brief Set desktop mask * * Sets the mask for in which desktops the window should be a member. * * @param ac WaAction object */ void WaWindow::DesktopMask(XEvent *, WaAction *ac) { if (ac->param) { if (! strncasecmp("all", ac->param, 3)) desktop_mask = (1L << 16) - 1; else { desktop_mask = 0; char *token = strtok(ac->param, " \t"); while (token) { unsigned int desk = (unsigned int) atoi(token); if (desk < wascreen->config.desktops) desktop_mask |= (1L << desk); token = strtok(NULL, " \t"); } } if (desktop_mask == 0) desktop_mask = (1L << 0); if (desktop_mask & (1L << wascreen->current_desktop->number)) Show(); else Hide(); net->SetDesktop(this); net->SetDesktopMask(this); } } /** * @fn JoinDesktop(XEvent *, WaAction *ac) * @brief Join desktop * * Join window to desktop specified by action parameter. * * @param ac WaAction object */ void WaWindow::JoinDesktop(XEvent *, WaAction *ac) { if (ac->param) { unsigned int desk = (unsigned int) atoi(ac->param); if (desk < wascreen->config.desktops) { desktop_mask |= (1L << desk); if (desktop_mask & (1L << wascreen->current_desktop->number)) Show(); net->SetDesktop(this); net->SetDesktopMask(this); } } } /** * @fn PartDesktop(XEvent *, WaAction *ac) * @brief Part desktop * * Part window from desktop specified by action parameter. * * @param ac WaAction object */ void WaWindow::PartDesktop(XEvent *, WaAction *ac) { if (ac->param) { unsigned int desk = (unsigned int) atoi(ac->param); if (desk < wascreen->config.desktops) { long int new_mask = desktop_mask & ~(1L << desk); if (new_mask) { desktop_mask = new_mask; if (! (desktop_mask & (1L << wascreen->current_desktop->number))) Hide(); net->SetDesktop(this); net->SetDesktopMask(this); } } } } /** * @fn PartCurrentDesktop(XEvent *, WaAction *) * @brief Part current desktop * * Part window from current desktop if window is part of another desktop. */ void WaWindow::PartCurrentDesktop(XEvent *, WaAction *) { long int new_mask = desktop_mask & ~(1L << wascreen->current_desktop->number); if (new_mask) { desktop_mask = new_mask; Hide(); net->SetDesktop(this); net->SetDesktopMask(this); } } /** * @fn JoinAllDesktops(XEvent *, WaAction *) * @brief Join all desktops * * Join window to all desktops. */ void WaWindow::JoinAllDesktops(XEvent *, WaAction *) { desktop_mask = (1L << 16) - 1; Show(); net->SetDesktop(this); net->SetDesktopMask(this); } /** * @fn PartAllDesktopsExceptCurrent(XEvent *, WaAction *) * @brief Part all desktops * * Part window from all desktops except current desktop. */ void WaWindow::PartAllDesktopsExceptCurrent(XEvent *, WaAction *) { desktop_mask = (1L << wascreen->current_desktop->number); Show(); net->SetDesktop(this); net->SetDesktopMask(this); } /** * @fn PartCurrentJoinDesktop(XEvent *, WaAction *ac) * @brief Part current desktop and join desktop * * Part current desktop and join desktop specified by parameter. * * @param ac WaAction object */ void WaWindow::PartCurrentJoinDesktop(XEvent *, WaAction *ac) { if (ac->param) { unsigned int desk = (unsigned int) atoi(ac->param); if (desk < wascreen->config.desktops) { desktop_mask = desktop_mask & ~(1L << wascreen->current_desktop->number); desktop_mask |= (1L << desk); if (desktop_mask & (1L << wascreen->current_desktop->number)) Show(); else Hide(); net->SetDesktop(this); net->SetDesktopMask(this); } } } /** * @fn EvAct(XEvent *e, EventDetail *ed, list *acts, * int etype) * @brief Calls WaWindow function * * Tries to match an occurred X event with the actions in an action list. * If we have a match then we execute that action. * * @param e X event that have occurred * @param ed Event details * @param acts List with actions to match event with * @param etype Type of window event occurred on */ void WaWindow::EvAct(XEvent *e, EventDetail *ed, list *acts, int etype) { XEvent fev; bool replay = false, wait_release = false, match = false; list::iterator it = acts->begin(); if (waimea->eh->move_resize != EndMoveResizeType) ed->mod |= MoveResizeMask; else if (etype == WindowType) { if (ed->type == ButtonPress) { for (; it != acts->end(); ++it) { if ((*it)->type == ButtonRelease && (*it)->detail == ed->detail && (! ((*it)->mod & MoveResizeMask))) wait_release = match = true; } } else if (ed->type == KeyPress) { for (; it != acts->end(); ++it) { if ((*it)->type == KeyRelease && (*it)->detail == ed->detail && (! ((*it)->mod & MoveResizeMask))) { wait_release = match = true; XAutoRepeatOff(display); } } } } it = acts->begin(); for (; it != acts->end(); ++it) { if (eventmatch(*it, ed)) { match = true; XAutoRepeatOn(display); if ((*it)->replay && ! wait_release) replay = true; if ((*it)->delay.tv_sec || (*it)->delay.tv_usec) { Interrupt *i = new Interrupt(*it, e, id); waimea->timer->AddInterrupt(i); } else { if ((*it)->exec) waexec((*it)->exec, wascreen->displaystring); else ((*this).*((*it)->winfunc))(e, *it); } } } if (waimea->eh->move_resize != EndMoveResizeType) { if (deleted) delete this; return; } XSync(display, false); while (XCheckTypedEvent(display, FocusOut, &fev)) waimea->eh->EvFocus(&fev.xfocus); while (XCheckTypedEvent(display, FocusIn, &fev)) waimea->eh->EvFocus(&fev.xfocus); switch (etype) { case WindowType: if (ed->type == ButtonPress || ed->type == ButtonRelease || ed->type == DoubleClick) { if (replay || ! match) XAllowEvents(display, ReplayPointer, e->xbutton.time); else XAllowEvents(display, AsyncPointer, e->xbutton.time); } else if (ed->type == KeyPress || ed->type == KeyRelease) { if (replay || ! match) XAllowEvents(display, ReplayKeyboard, e->xbutton.time); else XAllowEvents(display, AsyncKeyboard, e->xbutton.time); } else if (ed->type == MapRequest && ! mapped) { net->SetState(this, NormalState); net->SetVirtualPos(this); } break; } if (deleted) delete this; } /** * @fn WaChildWindow(WaWindow *wa_win, Window parent, int bw, int type) : * WindowObject(0, type) * @brief Constructor for WaChildWindow class * * Creates a child window, could be of one of these types: FrameType, * TitleType, LabelType, HandleType, CButtonType, IButtonType, MButtonType, * LGripType, RGripType. * * @param wa_win WaWindow who wish to use the child window * @param parent Parent window to child window * @param bw Border width * @param type Type of window */ WaChildWindow::WaChildWindow(WaWindow *wa_win, Window parent, int type) : WindowObject(0, type) { XSetWindowAttributes attrib_set; wa = wa_win; wascreen = wa->wascreen; display = wa->display; ic = wascreen->ic; pressed = false; int create_mask = CWOverrideRedirect | CWBorderPixel | CWEventMask | CWColormap; attrib_set.border_pixel = wa->wascreen->wstyle.border_color.getPixel(); attrib_set.colormap = wa->wascreen->colormap; attrib_set.override_redirect = true; attrib_set.event_mask = ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask; attrib.x = 0; attrib.y = 0; attrib.width = 1; attrib.height = 1; switch (type) { case FrameType: attrib_set.event_mask |= SubstructureRedirectMask; create_mask |= CWBackPixmap; attrib_set.background_pixmap = ParentRelative; attrib.x = wa->attrib.x - wa->border_w; attrib.y = wa->attrib.y - wa->title_w - wa->border_w * 2; attrib.width = wa->attrib.width; attrib.height = wa->attrib.height + wa->title_w + wa->handle_w + wa->border_w * 2; break; case LabelType: f_texture = &wascreen->wstyle.l_focus; u_texture = &wascreen->wstyle.l_unfocus; attrib_set.event_mask |= ExposureMask; break; case TitleType: f_texture = &wascreen->wstyle.t_focus; u_texture = &wascreen->wstyle.t_unfocus; break; case HandleType: f_texture = &wascreen->wstyle.h_focus; u_texture = &wascreen->wstyle.h_unfocus; break; case ButtonType: attrib_set.event_mask |= ExposureMask; break; case LGripType: f_texture = &wascreen->wstyle.g_focus; u_texture = &wascreen->wstyle.g_unfocus; create_mask |= CWCursor; attrib_set.cursor = wa->waimea->resizeleft_cursor; break; case RGripType: f_texture = &wascreen->wstyle.g_focus; u_texture = &wascreen->wstyle.g_unfocus; create_mask |= CWCursor; attrib_set.cursor = wa->waimea->resizeright_cursor; break; } id = XCreateWindow(display, parent, attrib.x, attrib.y, attrib.width, attrib.height, 0, CopyFromParent, CopyFromParent, CopyFromParent, create_mask, &attrib_set); #ifdef XFT if (type == LabelType || type == TitleType) { xftdraw = XftDrawCreate(display, (Drawable) id, wascreen->visual, wascreen->colormap); } #endif // XFT wa->waimea->window_table.insert(make_pair(id, this)); } /** * @fn ~WaChildWindow() * @brief Destructor for WaChildWindow class * * Destroys the window and removes it from the window_table hash_map. */ WaChildWindow::~WaChildWindow(void) { #ifdef XFT if (type == LabelType) XftDrawDestroy(xftdraw); #endif // XFT wa->waimea->window_table.erase(id); XDestroyWindow(display, id); } /** * @fn Render(void) * @brief Render WaChildWindow background * * Renders WaChildWindow background pixmap for the current window state. */ void WaChildWindow::Render(void) { bool done = false; WaTexture *texture = (wa->has_focus)? f_texture: u_texture; Pixmap pixmap = None; #ifdef RENDER Pixmap xpixmap; int pos_x = wa->attrib.x + attrib.x + wa->border_w; int pos_y = wa->attrib.y - wa->title_w + attrib.y; if (texture->getOpacity()) { xpixmap = XCreatePixmap(wascreen->pdisplay, wascreen->id, attrib.width, attrib.height, wascreen->screen_depth); } else if (wa->render_if_opacity && IsDrawable()) return; #endif // RENDER switch (type) { case ButtonType: { bool flag = false; done = true; switch (bstyle->cb) { case MaxCBoxType: flag = wa->flags.max; break; case ShadeCBoxType: flag = wa->flags.shaded; break; case StickCBoxType: flag = wa->flags.sticky; break; case TitleCBoxType: flag = wa->flags.title; break; case HandleCBoxType: flag = wa->flags.handle; break; case BorderCBoxType: flag = wa->flags.border; break; case AllCBoxType: flag = wa->flags.all; break; case AOTCBoxType: flag = wa->flags.alwaysontop; break; case AABCBoxType: flag = wa->flags.alwaysatbottom; break; } if (flag) { pixmap = (pressed) ? bstyle->p_pressed2: ((wa->has_focus)? bstyle->p_focused2: bstyle->p_unfocused2); texture = (pressed) ? &bstyle->t_pressed2: ((wa->has_focus)? &bstyle->t_focused2: &bstyle->t_unfocused2); } else { pixmap = (pressed) ? bstyle->p_pressed: ((wa->has_focus)? bstyle->p_focused: bstyle->p_unfocused); texture = (pressed) ? &bstyle->t_pressed: ((wa->has_focus)? &bstyle->t_focused: &bstyle->t_unfocused); } #ifdef RENDER if (texture->getOpacity()) pixmap = ic->xrender(pixmap, attrib.width, attrib.height, texture, wascreen->xrootpmap_id, pos_x, pos_y, xpixmap); #endif // RENDER } break; case LGripType: case RGripType: done = true; #ifdef RENDER if (texture->getOpacity()) pixmap = ic->xrender((wa->has_focus)? wascreen->fgrip: wascreen->ugrip, attrib.width, attrib.height, texture, wascreen->xrootpmap_id, pos_x, pos_y, xpixmap); else #endif // RENDER pixmap = (wa->has_focus)? wascreen->fgrip: wascreen->ugrip; break; } if (! done) { if (texture->getTexture() == (WaImage_Flat | WaImage_Solid)) { pixmap = None; #ifdef RENDER if (texture->getOpacity()) pixmap = ic->xrender(None, attrib.width, attrib.height, texture, wascreen->xrootpmap_id, pos_x, pos_y, xpixmap); #endif // RENDER } else pixmap = ic->renderImage(attrib.width, attrib.height, texture #ifdef RENDER , wascreen->xrootpmap_id, pos_x, pos_y, xpixmap #endif // RENDER ); } if (pixmap) { if (wascreen->config.db) Draw((Drawable) pixmap); else XSetWindowBackgroundPixmap(display, id, pixmap); #ifdef PIXMAP if ( #ifdef RENDER (! texture->getOpacity()) && #endif // RENDER (texture->getTexture() & WaImage_Pixmap)) { XSync(display, false); imlib_context_push(*texture->getContext()); imlib_free_pixmap_and_mask(pixmap); imlib_context_pop(); pixmap = None; } #endif // PIXMAP } else { if (wascreen->config.db) Draw((Drawable) 2); else XSetWindowBackground(display, id, texture->getColor()->getPixel()); } if (! wascreen->config.db) Draw(); #ifdef RENDER if (pixmap && texture->getOpacity()) { XSync(display, false); XFreePixmap(wascreen->pdisplay, pixmap); } #endif // RENDER } /** * @fn Draw(Drawable drawable) * @brief Draw text/decorations * * Draws text in window title window and button graphics for button windows. * If drawable is other then NULL then we draw on this instead. * * @param drawable Drawable to draw on */ void WaChildWindow::Draw(Drawable drawable) { int x = 0, y = 0, length, text_w; if (! drawable) XClearWindow(display, id); switch (type) { case TitleType: if (! drawable) return; if (wa->label->IsDrawable()) { if (drawable == (Drawable) 2) { WaTexture *texture = (wa->has_focus)? f_texture: u_texture; XSetWindowBackground(display, id, texture->getColor()->getPixel()); } else XSetWindowBackgroundPixmap(display, id, drawable); XClearWindow(display, id); return; } x = wa->label->g_x; y = 2; case LabelType: { if (type == LabelType && drawable) { if (drawable == ParentRelative) { if (wa->title->IsDrawable()) { XSetWindowBackgroundPixmap(display, id, drawable); XClearWindow(display, id); return; } drawable = 0; } } Pixmap p_tmp; if (drawable) { p_tmp = XCreatePixmap(display, wascreen->id, attrib.width, attrib.height, wascreen->screen_depth); if (drawable == (Drawable) 2) { XGCValues values; WaTexture *texture = (wa->has_focus)? f_texture: u_texture; values.foreground = texture->getColor()->getPixel(); GC gc = XCreateGC(display, wascreen->id, GCForeground, &values); XFillRectangle(display, p_tmp, gc, 0, 0, attrib.width, attrib.height); XFreeGC(display, gc); } else { GC gc = DefaultGC(display, wascreen->screen_number); XCopyArea(display, drawable, p_tmp, gc, 0, 0, attrib.width, attrib.height, 0, 0); } } length = strlen(wa->name); WaFont *wafont = (wa->has_focus)? &wascreen->wstyle.wa_font: &wascreen->wstyle.wa_font_u; text_w = wafont->Width(display, wa->name, length); if (text_w > (wa->label->attrib.width - 10)) x += 2; else { switch (wascreen->wstyle.justify) { case LeftJustify: x += 2; break; case CenterJustify: x += (wa->label->attrib.width / 2) - (text_w / 2); break; case RightJustify: x += (wa->label->attrib.width - text_w) - 2; break; } } y += wascreen->wstyle.y_pos; #ifdef XFT if (drawable) XftDrawChange(xftdraw, p_tmp); #endif // XFT wafont->Draw(display, (drawable)? p_tmp : id, #ifdef XFT xftdraw, #endif // XFT x, y, wa->name, length); if (drawable) { XSetWindowBackgroundPixmap(display, id, p_tmp); XClearWindow(display, id); XFreePixmap(display, p_tmp); } } break; case ButtonType: { if (drawable) { if (drawable == (Drawable) 2) { WaTexture *texture = (wa->has_focus)? f_texture: u_texture; XSetWindowBackground(display, id, texture->getColor()->getPixel()); } else XSetWindowBackgroundPixmap(display, id, drawable); XClearWindow(display, id); } GC *gc; if (bstyle->fg) { bool flag = false; switch (bstyle->cb) { case MaxCBoxType: flag = wa->flags.max; break; case ShadeCBoxType: flag = wa->flags.shaded; break; case StickCBoxType: flag = wa->flags.sticky; break; case TitleCBoxType: flag = wa->flags.title; break; case HandleCBoxType: flag = wa->flags.handle; break; case BorderCBoxType: flag = wa->flags.border; break; case AllCBoxType: flag = wa->flags.all; break; case AOTCBoxType: flag = wa->flags.alwaysontop; break; case AABCBoxType: flag = wa->flags.alwaysatbottom; break; } if (flag) { gc = (pressed) ? &bstyle->g_pressed2: ((wa->has_focus)? &bstyle->g_focused2: &bstyle->g_unfocused2); } else { gc = (pressed) ? &bstyle->g_pressed: ((wa->has_focus)? &bstyle->g_focused: &bstyle->g_unfocused); } switch (bstyle->cb) { case ShadeCBoxType: XDrawRectangle(display, id, *gc, 2, 3, wa->title_w - 9, 2); break; case CloseCBoxType: XDrawLine(display, id, *gc, 2, 2, wa->title_w - 7, wa->title_w - 7); XDrawLine(display, id, *gc, 2, wa->title_w - 7, wa->title_w - 7, 2); break; case MaxCBoxType: if (wa->flags.max) { int w = (2*(wa->title_w - 8))/3; int h = (2*(wa->title_w - 8))/3 - 1; int y = (wa->title_w - 8) - h + 1; int x = (wa->title_w - 8) - w + 1; XDrawRectangle(display, id, *gc, 2, y, w,h); XDrawLine(display, id, *gc, 2, y + 1, 2 + w, y + 1); XDrawLine(display, id, *gc, x, 2, x + w, 2); XDrawLine(display, id, *gc, x, 3, x + w, 3); XDrawLine(display, id, *gc, x, 2, x, y); XDrawLine(display, id, *gc, x + w, 2, x + w, 2 + h); XDrawLine(display, id, *gc, 2 + w, 2 + h, x + w, 2 + h); } else { XDrawRectangle(display, id, *gc, 2, 2, wa->title_w - 9, wa->title_w - 9); XDrawLine(display, id, *gc, 2, 3, wa->title_w - 8, 3); } break; default: XFillRectangle(display, id, *gc, 4, 4, wa->title_w - 11, wa->title_w - 11); } } } break; default: if (drawable) { if (drawable == (Drawable) 2) { WaTexture *texture = (wa->has_focus)? f_texture: u_texture; XSetWindowBackground(display, id, texture->getColor()->getPixel()); } else XSetWindowBackgroundPixmap(display, id, drawable); XClearWindow(display, id); } } } /** * @fn IsDrawable(void) * @brief Check if drawable * * Checks if if window is double buffer drawable (if it will have a pixmap * background). */ bool WaChildWindow::IsDrawable(void) { WaTexture *texture = (wa->has_focus)? f_texture: u_texture; if (texture->getTexture() & WaImage_ParentRelative) return false; else return true; } /** * Wrapper functions */ void WaWindow::ViewportMove(XEvent *e, WaAction *wa) { wascreen->ViewportMove(e, wa); } void WaWindow::ViewportRelativeMove(XEvent *e, WaAction *wa) { wascreen->ViewportRelativeMove(e, wa); } void WaWindow::ViewportFixedMove(XEvent *e, WaAction *wa) { wascreen->ViewportFixedMove(e, wa); } void WaWindow::MoveViewportLeft(XEvent *, WaAction *) { wascreen->MoveViewport(WestDirection); } void WaWindow::MoveViewportRight(XEvent *, WaAction *) { wascreen->MoveViewport(EastDirection); } void WaWindow::MoveViewportUp(XEvent *, WaAction *) { wascreen->MoveViewport(NorthDirection); } void WaWindow::MoveViewportDown(XEvent *, WaAction *) { wascreen->MoveViewport(SouthDirection); } void WaWindow::PointerRelativeWarp(XEvent *e, WaAction *ac) { wascreen->PointerRelativeWarp(e, ac); } void WaWindow::PointerFixedWarp(XEvent *e, WaAction *ac) { wascreen->PointerFixedWarp(e, ac); } void WaWindow::GoToDesktop(XEvent *, WaAction *ac) { if (ac->param) wascreen->GoToDesktop((unsigned int) atoi(ac->param)); } void WaWindow::NextDesktop(XEvent *, WaAction *) { wascreen->NextDesktop(NULL, NULL); } void WaWindow::PreviousDesktop(XEvent *, WaAction *) { wascreen->PreviousDesktop(NULL, NULL); } void WaWindow::Restart(XEvent *e, WaAction *ac) { wascreen->Restart(e, ac); } void WaWindow::Exit(XEvent *e, WaAction *ac) { wascreen->Exit(e, ac); }