From 88c66f0687d2a9e2018f22407b2587dc4d87d012 Mon Sep 17 00:00:00 2001 From: simonb Date: Sun, 10 Apr 2005 18:18:14 +0000 Subject: Big changes to how transparency works Consequently rearrange lots of rendering ops, and strip calls to updateTransparent --- ChangeLog | 28 +++ src/ArrowButton.cc | 2 - src/ButtonTool.cc | 1 - src/Container.cc | 2 - src/FbTk/Button.cc | 35 +--- src/FbTk/Button.hh | 8 +- src/FbTk/FbPixmap.cc | 3 +- src/FbTk/FbWindow.cc | 115 +++++++++++-- src/FbTk/FbWindow.hh | 31 +++- src/FbTk/Menu.cc | 449 +++++++++++++----------------------------------- src/FbTk/Menu.hh | 13 +- src/FbTk/TextButton.cc | 55 +----- src/FbTk/TextButton.hh | 1 - src/FbTk/Transparent.cc | 16 +- src/FbTk/Transparent.hh | 1 + src/FbWinFrame.cc | 445 +++++++++++++++++++++++------------------------ src/FbWinFrame.hh | 55 ++++-- src/GenericTool.cc | 2 - src/Slit.cc | 2 - src/ToggleMenu.hh | 9 +- src/Toolbar.cc | 6 - src/WinButton.cc | 380 ++++++++++++++++++---------------------- src/WinButton.hh | 15 +- src/WinClient.cc | 2 +- src/Window.cc | 18 +- src/Window.hh | 2 +- src/fluxbox.cc | 8 +- src/fluxbox.hh | 3 +- 28 files changed, 751 insertions(+), 956 deletions(-) diff --git a/ChangeLog b/ChangeLog index e5039f5..d5deeb4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,33 @@ (Format: Year/Month/Day) Changes for 0.9.13 +*05/04/11: + * Rework lots of stuff relating to transparency, esp menus+frame (Simon) + + Massively reduce pixmap memory usage (view with xrestop) + + Should also improve startup+style change times, esp for large menus + + This introduces a few rendering bugs, but I'd like stuff tested + + Transparency is done differently now. People shouldn't need to + call updateTransparent. + + Do not use persistent pixmap buffers unless you're sure! + XSetWindowBackground already copies/buffers the set pixmap, so + things need to be rendered to a temp pixmap once, then can be + freed. + Known bugs (please report others to Rathnor on #fluxbox): + - different focus/unfocus transparency doesn't update labelbuttons + properly. Workaround: use same transparency for both. + - Text sometimes gets overdrawn a lot. Probably should render it to + background using a virtual hook in FbWindow::updateBackground + - Changing style resizes things, not all pixmaps updated properly + Workaround: restart fluxbox after changing style + - Probably breaks Composite support. Let me know how. + TODO: + + FbPixmap::getRootPixmap called very often. It should cache the + result and watch the relevant properties. + Changed: + FbTk/ FbWindow.hh/cc Button.hh/cc Menu.hh/cc TextButton.hh/cc + Transparent.hh/cc FbPixmap.cc + Window.hh/cc FbWinFrame.hh/cc fluxbox.hh/cc ArrowButton.cc + ButtonTool.cc Container.cc GenericTool.cc Slit.cc ToggleMenu.hh + Toolbar.cc WinButton.hh/cc WinClient.cc *05/04/09: * minor fix to startfluxbox (Mathias) *05/04/07: diff --git a/src/ArrowButton.cc b/src/ArrowButton.cc index 982133a..6f7f0f3 100644 --- a/src/ArrowButton.cc +++ b/src/ArrowButton.cc @@ -52,13 +52,11 @@ ArrowButton::ArrowButton(ArrowButton::Type arrow_type, void ArrowButton::clear() { FbTk::Button::clear(); - updateTransparent(); drawArrow(); } void ArrowButton::exposeEvent(XExposeEvent &event) { FbTk::Button::exposeEvent(event); - updateTransparent(event.x, event.y, event.width, event.height); drawArrow(); } diff --git a/src/ButtonTool.cc b/src/ButtonTool.cc index c87ce86..38ac23e 100644 --- a/src/ButtonTool.cc +++ b/src/ButtonTool.cc @@ -87,6 +87,5 @@ void ButtonTool::renderTheme(unsigned char alpha) { m_image_ctrl.removeImage(old_pm); btn.clear(); - btn.updateTransparent(); } diff --git a/src/Container.cc b/src/Container.cc index 9e9952f..8e1d41c 100644 --- a/src/Container.cc +++ b/src/Container.cc @@ -132,7 +132,6 @@ void Container::removeAll() { m_item_list.clear(); if (!m_update_lock) { clear(); - updateTransparent(); } } @@ -176,7 +175,6 @@ void Container::setAlignment(Container::Alignment a) { void Container::exposeEvent(XExposeEvent &event) { if (!m_update_lock) { clearArea(event.x, event.y, event.width, event.height); - updateTransparent(event.x, event.y, event.width, event.height); } } diff --git a/src/FbTk/Button.cc b/src/FbTk/Button.cc index c48b355..414979b 100644 --- a/src/FbTk/Button.cc +++ b/src/FbTk/Button.cc @@ -33,10 +33,9 @@ Button::Button(int screen_num, int x, int y, unsigned int width, unsigned int height): FbWindow(screen_num, x, y, width, height, ExposureMask | ButtonPressMask | ButtonReleaseMask), - m_foreground_pm(0), m_background_pm(0), m_pressed_pm(0), - m_pressed_color("black", screen_num), + m_pressed_color(), m_gc(DefaultGC(FbTk::App::instance()->display(), screen_num)), m_pressed(false) { @@ -48,10 +47,9 @@ Button::Button(const FbWindow &parent, int x, int y, unsigned int width, unsigned int height): FbWindow(parent, x, y, width, height, ExposureMask | ButtonPressMask | ButtonReleaseMask), - m_foreground_pm(0), m_background_pm(0), m_pressed_pm(0), - m_pressed_color("black", parent.screenNumber()), + m_pressed_color(), m_gc(DefaultGC(FbTk::App::instance()->display(), screenNumber())), m_pressed(false) { // add this to eventmanager @@ -70,15 +68,12 @@ void Button::setOnClick(RefCount &cmd, int button) { m_onclick[button - 1] = cmd; } -void Button::setPixmap(Pixmap pm) { - m_foreground_pm = pm; -} - void Button::setPressedPixmap(Pixmap pm) { m_pressed_pm = pm; } void Button::setPressedColor(const FbTk::Color &color) { + m_pressed_pm = None; m_pressed_color = color; } @@ -115,27 +110,16 @@ void Button::buttonReleaseEvent(XButtonEvent &event) { if (m_background_pm) { if (m_pressed_pm != 0) { update = true; - setBackgroundPixmap(m_background_pm); + FbTk::FbWindow::setBackgroundPixmap(m_background_pm); } } else if (m_pressed_color.isAllocated()) { update = true; - setBackgroundColor(m_background_color); + FbTk::FbWindow::setBackgroundColor(m_background_color); } - if (update) { + if (update) clear(); // clear background - if (m_foreground_pm) { // draw foreground pixmap - Display *disp = App::instance()->display(); - - if (m_gc == 0) // get default gc if we dont have one - m_gc = DefaultGC(disp, screenNumber()); - - XCopyArea(disp, m_foreground_pm, window(), m_gc, 0, 0, width(), height(), 0, 0); - } - - } - // finaly, execute command (this must be done last since this object might be deleted by the command) if (event.button > 0 && event.button <= 5 && event.x > 0 && event.x < static_cast(width()) && @@ -147,14 +131,7 @@ void Button::buttonReleaseEvent(XButtonEvent &event) { } void Button::exposeEvent(XExposeEvent &event) { - /* - if (m_background_pm) - setBackgroundPixmap(m_background_pm); - else - setBackgroundColor(m_background_color); - */ clearArea(event.x, event.y, event.width, event.height); - // updateTransparent(event.x, event.y, event.width, event.height); } }; // end namespace FbTk diff --git a/src/FbTk/Button.hh b/src/FbTk/Button.hh index 66cd2b5..48aff02 100644 --- a/src/FbTk/Button.hh +++ b/src/FbTk/Button.hh @@ -48,11 +48,9 @@ public: /// sets action when the button is clicked with #button mouse btn void setOnClick(RefCount &com, int button = 1); - /// sets foreground pixmap - void setPixmap(Pixmap pm); /// sets the pixmap to be viewed when the button is pressed - void setPressedPixmap(Pixmap pm); - void setPressedColor(const FbTk::Color &color); + virtual void setPressedPixmap(Pixmap pm); + virtual void setPressedColor(const FbTk::Color &color); /// sets graphic context for drawing void setGC(GC gc) { m_gc = gc; } /// sets background pixmap, this will override background color @@ -78,9 +76,7 @@ public: GC gc() const { return m_gc; } Pixmap backgroundPixmap() const { return m_background_pm; } const Color &backgroundColor() const { return m_background_color; } - Pixmap foregroundPixmap() const { return m_foreground_pm; } private: - Pixmap m_foreground_pm; ///< foreground pixmap Pixmap m_background_pm; ///< background pixmap Color m_background_color; ///< background color Pixmap m_pressed_pm; ///< pressed pixmap diff --git a/src/FbTk/FbPixmap.cc b/src/FbTk/FbPixmap.cc index ed9a771..e573945 100644 --- a/src/FbTk/FbPixmap.cc +++ b/src/FbTk/FbPixmap.cc @@ -311,13 +311,12 @@ Pixmap FbPixmap::getRootPixmap(int screen_num) { if (XGetWindowProperty(display(), RootWindow(display(), screen_num), XInternAtom(display(), prop_ids[prop], False), - 0l, 4l, + 0l, 1l, False, XA_PIXMAP, &real_type, &real_format, &items_read, &items_left, (unsigned char **) &data) == Success) { if (real_format == 32 && items_read == 1) { - if (print_error && strcmp(prop_ids[prop], "_XSETROOT_ID") == 0) { cerr<alpha(); + + if (only_if_alpha && alpha == 255) + return; + + + if (alpha != 255 && m_lastbg_pm != ParentRelative) { + // update source and destination if needed + Pixmap root = FbPixmap::getRootPixmap(screenNumber()); + if (m_transparent->source() != root) + m_transparent->setSource(root, screenNumber()); + + newbg = XCreatePixmap(display(), window(), width(), height(), depth()); + free_newbg = true; + GC gc = XCreateGC(display(), window(), 0, 0); + + if (m_lastbg_pm == None && m_lastbg_color_set) { + XSetForeground(display(), gc, m_lastbg_color); + XFillRectangle(display(), newbg, gc, 0, 0, width(), height()); + } else { + // copy from window if no color and no bg... + XCopyArea(display(), (m_lastbg_pm == None)?drawable():m_lastbg_pm, newbg, gc, + 0, 0, + width(), height(), + 0, 0); + } + XFreeGC(display(), gc); + m_transparent->setDest(newbg, screenNumber()); + + // get root position + + const FbWindow *root_parent = parent(); + // our position in parent ("root") + int root_x = x() + borderWidth(), root_y = y() + borderWidth(); + if (root_parent != 0) { + root_x += root_parent->x() + root_parent->borderWidth(); + root_y += root_parent->y() + root_parent->borderWidth(); + while (root_parent->parent() != 0) { + root_parent = root_parent->parent(); + root_x += root_parent->x() + root_parent->borderWidth(); + root_y += root_parent->y() + root_parent->borderWidth(); + } + } + + // render background image from root pos to our window + m_transparent->render(root_x, root_y, + 0, 0, + width(), height()); + m_transparent->freeDest(); // it's only temporary, don't leave it hanging around + } + + if (newbg != None) + XSetWindowBackgroundPixmap(display(), m_window, newbg); + else if (m_lastbg_color_set) + XSetWindowBackground(display(), m_window, m_lastbg_color); + + if (free_newbg) + XFreePixmap(display(), newbg); } void FbWindow::setBorderColor(const FbTk::Color &border_color) { @@ -168,6 +249,13 @@ void FbWindow::updateTransparent(int the_x, int the_y, unsigned int the_width, u if (width() == 0 || height() == 0) return; + if ((the_width == 0 && the_height == 0 || the_width == width() && the_height == height()) && + the_x <= 0 && the_y <= 0) { + // do the whole thing + updateBackground(true); + return; + } + if (the_width == 0 || the_height == 0) { the_width = width(); the_height = height(); @@ -183,14 +271,9 @@ void FbWindow::updateTransparent(int the_x, int the_y, unsigned int the_width, u if (m_transparent->source() != root) m_transparent->setSource(root, screenNumber()); - if (m_buffer_pm) { - if (m_transparent->dest() != m_buffer_pm) { - m_transparent->setDest(m_buffer_pm, screenNumber()); - } - } else if (m_transparent->dest() != window()) + if (m_transparent->dest() != window()) m_transparent->setDest(window(), screenNumber()); - // get root position const FbWindow *root_parent = parent(); @@ -414,9 +497,11 @@ void FbWindow::setOpaque(unsigned char alpha) { #endif // HAVE_XRENDER } +/* void FbWindow::setBufferPixmap(Pixmap pm) { - m_buffer_pm = pm; + m_lastbg_pm = pm; } +*/ void FbWindow::updateGeometry() { if (m_window == 0) diff --git a/src/FbTk/FbWindow.hh b/src/FbTk/FbWindow.hh index a72ea26..0c481c9 100644 --- a/src/FbTk/FbWindow.hh +++ b/src/FbTk/FbWindow.hh @@ -93,24 +93,40 @@ public: virtual void show(); virtual void showSubwindows(); + /// Notify that the parent window was moved, + /// thus the absolute position of this one moved + virtual inline void parentMoved() { + updateBackground(true); + } + virtual inline void move(int x, int y) { + if (x == m_x && y == m_y) + return; XMoveWindow(s_display, m_window, x, y); m_x = x; m_y = y; + updateBackground(true); } virtual inline void resize(unsigned int width, unsigned int height) { - XResizeWindow(s_display, m_window, width, height); - m_width = width; - m_height = height; + if (width == m_width && height == m_height) + return; + XResizeWindow(s_display, m_window, width, height); + m_width = width; + m_height = height; + updateBackground(true); } virtual inline void moveResize(int x, int y, unsigned int width, unsigned int height) { + if (x == m_x && y == m_y && width == m_width && height == m_height) + return; XMoveResizeWindow(s_display, m_window, x, y, width, height); m_x = x; m_y = y; m_width = width; m_height = height; + updateBackground(true); + } virtual void lower(); virtual void raise(); @@ -139,8 +155,6 @@ public: void deleteProperty(Atom property); - void setBufferPixmap(Pixmap pm); - std::string textProperty(Atom property) const; /// @return parent FbWindow @@ -184,6 +198,9 @@ private: bool save_unders, int depth, int class_type); + /// forces full background change, recalcing of alpha values if necessary + void updateBackground(bool only_if_alpha); + const FbWindow *m_parent; ///< parent FbWindow int m_screen_num; ///< screen num on which this window exist mutable Window m_window; ///< the X window @@ -193,7 +210,9 @@ private: int m_depth; ///< bit depth bool m_destroy; ///< wheter the x window was created before std::auto_ptr m_transparent; - Pixmap m_buffer_pm; + bool m_lastbg_color_set; + unsigned long m_lastbg_color; + Pixmap m_lastbg_pm; }; bool operator == (Window win, const FbWindow &fbwin); diff --git a/src/FbTk/Menu.cc b/src/FbTk/Menu.cc index f803709..370afb8 100644 --- a/src/FbTk/Menu.cc +++ b/src/FbTk/Menu.cc @@ -86,7 +86,6 @@ Menu::Menu(MenuTheme &tm, ImageControl &imgctrl): m_alignment(ALIGNDONTCARE), m_active_index(-1), m_need_update(true) { - // setup timers RefCount show_cmd(new SimpleCommand(*this, &Menu::openSubmenu)); @@ -286,9 +285,7 @@ void Menu::nextItem() { // since it might hide the parent if we use Menu::hide menuitems[old_which_press]->submenu()->internal_hide(); } - drawItem(old_which_press, - true, // clear - true); // transp + drawItem(old_which_press, true); // clear } // restore old in case we changed m_which_press @@ -309,9 +306,7 @@ void Menu::nextItem() { m_active_index = m_which_press; - drawItem(m_which_press, - true, // clear - true); // transp + drawItem(m_which_press, true); // clear } @@ -325,9 +320,7 @@ void Menu::prevItem() { // since it might hide the parent if we use Menu::hide menuitems[old_which_press]->submenu()->internal_hide(); } - drawItem(old_which_press, - true, // clear - true); // transp + drawItem(old_which_press, true); // clear } // restore old in case we changed m_which_press m_which_press = old_which_press - 1; @@ -347,9 +340,7 @@ void Menu::prevItem() { m_active_index = m_which_press; - drawItem(m_which_press, - true, // clear - true); // transp + drawItem(m_which_press, true); // clear } @@ -379,9 +370,7 @@ void Menu::enterParent() { submenu->internal_hide(); m_active_index = -1; - drawItem(m_which_press, - true, // clear - true); // transp + drawItem(m_which_press, true); // clear m_which_press = -1; // dont select any in this // hide self m_visible = false; @@ -399,10 +388,13 @@ void Menu::enableTitle() { } void Menu::updateMenu(int active_index) { + if (!m_visible) { + m_need_update = true; + return; + } if (m_title_vis) { menu.item_w = theme().titleFont().textWidth(menu.label.c_str(), menu.label.size()); - menu.item_w += (theme().bevelWidth() * 2); } else menu.item_w = 1; @@ -433,6 +425,9 @@ void Menu::updateMenu(int active_index) { menu.persub = 0; } + if (menu.frame.alpha() != alpha()) + menu.frame.setAlpha(alpha()); + int itmp = (theme().itemHeight() * menu.persub); menu.frame_h = itmp < 1 ? 1 : itmp; @@ -461,60 +456,16 @@ void Menu::updateMenu(int active_index) { const FbTk::Texture &tex = theme().titleTexture(); if (!tex.usePixmap()) { menu.title_pixmap = None; + menu.title.setBackgroundColor(tex.color()); } else { menu.title_pixmap = m_image_ctrl.renderImage(width(), theme().titleHeight(), tex); + // set pixmap that we have as real face to the user + menu.title.setBackgroundPixmap(menu.title_pixmap); } if (tmp) m_image_ctrl.removeImage(tmp); - - // if new size of title doesn't match our - // buffer pixmap -> resize buffer pixmap - if (m_title_pm.width() != width() || - m_title_pm.height() != theme().titleHeight()) { - - if (m_title_pm.drawable() != None) { - m_title_pm.resize(width(), theme().titleHeight()); - m_real_title_pm.resize(width(), theme().titleHeight()); - } else { - m_title_pm.create(menu.title.window(), - width(), theme().titleHeight(), - menu.title.depth()); - m_real_title_pm.create(menu.title.window(), - width(), theme().titleHeight(), - menu.title.depth()); - } - - // set pixmap that we have as real face to the user - menu.title.setBackgroundPixmap(m_real_title_pm.drawable()); - menu.title.setBufferPixmap(m_real_title_pm.drawable()); - //!! TODO: error checking? - GContext def_gc(menu.title); - if (menu.title_pixmap == 0) { - def_gc.setForeground(theme().titleTexture().color()); - m_title_pm.fillRectangle(def_gc.gc(), - 0, 0, - m_title_pm.width(), m_title_pm.height()); - m_real_title_pm.fillRectangle(def_gc.gc(), - 0, 0, - m_title_pm.width(), m_title_pm.height()); - } else { - m_title_pm.copyArea(menu.title_pixmap, - def_gc.gc(), - 0, 0, - 0, 0, - m_title_pm.width(), m_title_pm.height()); - - m_real_title_pm.copyArea(menu.title_pixmap, - def_gc.gc(), - 0, 0, - 0, 0, - m_title_pm.width(), m_title_pm.height()); - - } - - } } tmp = menu.frame_pixmap; @@ -522,9 +473,11 @@ void Menu::updateMenu(int active_index) { if (m_need_update) { if (!frame_tex.usePixmap()) { menu.frame_pixmap = None; + menu.frame.setBackgroundColor(frame_tex.color()); } else { menu.frame_pixmap = m_image_ctrl.renderImage(width(), menu.frame_h, frame_tex); + menu.frame.setBackgroundPixmap(menu.frame_pixmap); } if (tmp) @@ -563,71 +516,12 @@ void Menu::updateMenu(int active_index) { menu.title.borderWidth()*2 : 1), width(), menu.frame_h); - - if (m_need_update || m_frame_pm.width() != menu.frame.width() || - m_frame_pm.height() != menu.frame.height()){ - - if (m_frame_pm.drawable() != None) { - m_frame_pm.resize(menu.frame.width(), menu.frame.height()); - m_real_frame_pm.resize(menu.frame.width(), menu.frame.height()); - } else { - m_frame_pm.create(menu.frame.window(), - menu.frame.width(), menu.frame.height(), - menu.frame.depth()); - - m_real_frame_pm.create(menu.frame.window(), - menu.frame.width(), menu.frame.height(), - menu.frame.depth()); - } - if (m_transp.get() != 0) - m_transp->setDest(m_real_frame_pm.drawable(), screenNumber()); - - menu.frame.setBackgroundPixmap(m_real_frame_pm.drawable()); - GContext def_gc(menu.frame); - if (m_frame_pm.drawable() == 0) { - _FB_USES_NLS; - cerr<<"FbTk::Menu: "<<_FBTKTEXT(Error, CreatePixmap, "Error creating pixmap", "Couldn't create a pixmap - image - for some reason")<<" ("<< - menu.frame.window()<<", "<= 0 || m_need_update) { - - renderTransp(0, 0, - m_real_frame_pm.width(), m_real_frame_pm.height()); - for (unsigned int i = 0; i < menuitems.size(); i++) { - drawItem(i, // index - true, // clear - false); // render_trans - } - + if (m_visible && (active_index >= 0 || m_need_update)) { + redrawFrame(); } m_need_update = false; @@ -636,8 +530,13 @@ void Menu::updateMenu(int active_index) { void Menu::show() { - if (m_need_update) + if (m_visible) + return; + + if (m_need_update) { + m_visible = true; updateMenu(); + } menu.window.showSubwindows(); menu.window.show(); @@ -683,16 +582,16 @@ void Menu::grabInputFocus() { void Menu::clearWindow() { - redrawTitle(); - - if (alpha() < 255) { - renderTransp(0, 0, - menu.frame.width(), menu.frame.height()); - updateMenu(); - } + redrawTitle(); + redrawFrame(); +} - menu.title.clear(); +void Menu::redrawFrame() { menu.frame.clear(); + for (unsigned int i = 0; i < menuitems.size(); i++) { + drawItem(i, false); // no clear + } + } void Menu::internal_hide() { @@ -713,7 +612,7 @@ void Menu::internal_hide() { m_torn = m_visible = false; m_which_sub = m_which_press = m_which_sub = -1; - + menu.window.hide(); } @@ -722,33 +621,19 @@ void Menu::move(int x, int y) { if (x == this->x() && y == this->y()) return; - // if we're not m_visible and we do transparency - // we need to update transparency when we call - // show() next time - if (alpha() < 255) - m_need_update = true; - menu.window.move(x, y); + // potentially transparent children + menu.title.parentMoved(); + menu.frame.parentMoved(); if (!isVisible()) return; + if (alpha() < 255) + clearWindow(); + if (m_which_sub != -1) drawSubmenu(m_which_sub); - - if (alpha() < 255) { - redrawTitle(); - menu.title.clear(); - renderTransp(0, 0, - m_real_frame_pm.width(), m_real_frame_pm.height()); - for (size_t i=0; i < menuitems.size(); ++i) { - drawItem(i, - true, // clear - false); // transparent - } - m_need_update = false; - } - } @@ -776,16 +661,11 @@ void Menu::redrawTitle() { FbTk::GContext def_gc(menu.title); - m_real_title_pm.copyArea(m_title_pm.drawable(), - def_gc.gc(), - 0, 0, - 0, 0, - m_title_pm.width(), m_title_pm.height()); + menu.title.clear(); // difference between height based on font, and style-set height int height_offset = theme().titleHeight() - (font.height() + 2*theme().bevelWidth()); - menu.title.updateTransparent(); - font.drawText(m_real_title_pm, // drawable + font.drawText(menu.title, // drawable screenNumber(), theme().titleTextGC().gc(), // graphic context text, len, // text string with length @@ -885,17 +765,22 @@ bool Menu::hasSubmenu(unsigned int index) const { } -int Menu::drawItem(unsigned int index, bool clear, bool render_trans, +int Menu::drawItem(unsigned int index, bool clear, int x, int y, unsigned int w, unsigned int h) { if (index >= menuitems.size() || menuitems.size() == 0 || menu.persub == 0) return 0; + // don't bother if we're not showing + if (!isVisible()) + return 0; + MenuItem *item = menuitems[index]; if (! item) return 0; int sbl = index / menu.persub, i = index - (sbl * menu.persub); int item_x = (sbl * menu.item_w), item_y = (i * theme().itemHeight()); + unsigned int item_w = menu.item_w, item_h = theme().itemHeight(); int hilite_x = item_x, hilite_y = item_y, hoff_x = 0, hoff_y = 0; int sel_x = 0, sel_y = 0; unsigned int hilite_w = menu.item_w, hilite_h = theme().itemHeight(); @@ -914,50 +799,23 @@ int Menu::drawItem(unsigned int index, bool clear, bool render_trans, sel_y = item_y + quarter_w; if (clear) { - GContext def_gc(menu.frame); - if (menu.frame_pixmap == 0) { - def_gc.setForeground(theme().frameTexture().color()); - m_frame_pm.fillRectangle(def_gc.gc(), item_x, item_y, menu.item_w, theme().itemHeight()); - - } else { - - m_frame_pm.copyArea(menu.frame_pixmap, def_gc.gc(), - item_x, item_y, - item_x, item_y, - menu.item_w, theme().itemHeight()); - } - } else if (! (x == y && y == -1 && w == h && h == 0)) { - // calculate the which part of the hilite to redraw - if (!(std::max(item_x, x) <= (signed) std::min(item_x + menu.item_w, x + w) && - std::max(item_y, y) <= (signed) std::min(item_y + theme().itemHeight(), y + h))) { - hilite_x = std::max(item_x, x); - hilite_y = std::max(item_y, y); - hilite_w = std::min(item_x + menu.item_w, x + w) - hilite_x; - hilite_h = std::min(item_y + theme().itemHeight(), y + h) - hilite_y; - hoff_x = hilite_x % menu.item_w; - hoff_y = hilite_y % theme().itemHeight(); - } - + frameWindow().clearArea(item_x, item_y, + menu.item_w, theme().itemHeight(), False); } - + if (highlight && (menu.hilite_pixmap != ParentRelative)) { if (menu.hilite_pixmap) { - m_frame_pm.copyArea(menu.hilite_pixmap, + menu.frame.copyArea(menu.hilite_pixmap, theme().hiliteGC().gc(), hoff_x, hoff_y, - hilite_x, hilite_y, - hilite_w, hilite_h); - } else { - m_frame_pm.fillRectangle(theme().hiliteGC().gc(), - hilite_x, hilite_y, hilite_w, hilite_h); + item_x, item_y, + item_w, item_h); + } else { + menu.frame.fillRectangle(theme().hiliteGC().gc(), + item_x, item_y, item_w, item_h); } - - } - - - if (render_trans) { - renderTransp(item_x, item_y, - menu.item_w, theme().itemHeight()); + menu.frame.updateTransparent(item_x, item_y, item_w, item_h); } + //!! //!! TODO: Move this out to MenuItem //!! current problem: menu.sel_pixmap needs a image control instance @@ -974,7 +832,7 @@ int Menu::drawItem(unsigned int index, bool clear, bool render_trans, XSetClipOrigin(disp, gc, sel_x, item_y); // copy bullet pixmap to frame - m_real_frame_pm.copyArea(theme().selectedPixmap().pixmap().drawable(), + menu.frame.copyArea(theme().selectedPixmap().pixmap().drawable(), gc, 0, 0, sel_x, item_y, @@ -985,31 +843,24 @@ int Menu::drawItem(unsigned int index, bool clear, bool render_trans, gc, None); } else { - if (menu.sel_pixmap) { - m_real_frame_pm.copyArea(highlight ? menu.frame_pixmap : menu.sel_pixmap, + if (highlight && menu.sel_pixmap) { + menu.frame.copyArea(menu.sel_pixmap, theme().hiliteGC().gc(), 0, 0, sel_x, sel_y, half_w, half_w); } else { - m_real_frame_pm.fillRectangle(theme().hiliteGC().gc(), + menu.frame.fillRectangle(theme().hiliteGC().gc(), sel_x, sel_y, half_w, half_w); } } } - item->draw(m_real_frame_pm, theme(), highlight, + item->draw(menu.frame, theme(), highlight, item_x, item_y, menu.item_w, theme().itemHeight()); - - if (clear) { - frameWindow().clearArea(item_x, item_y, - menu.item_w, theme().itemHeight(), False); - } - - return item_y; } @@ -1104,11 +955,8 @@ void Menu::buttonPressEvent(XButtonEvent &be) { if (!item->submenu()->isVisible()) drawSubmenu(w); } else { - drawItem(w, - true, // clear - true); // render transparency + drawItem(w, true); // clear } - } } else { menu.x_move = be.x_root - x(); @@ -1126,16 +974,11 @@ void Menu::buttonReleaseEvent(XButtonEvent &re) { drawSubmenu(m_which_sub); if (alpha() < 255) { + // update these since we've (probably) moved + menu.title.parentMoved(); + menu.frame.parentMoved(); redrawTitle(); - menu.title.clear(); - renderTransp(0, 0, - m_real_frame_pm.width(), m_real_frame_pm.height()); - for (size_t i=0; i < menuitems.size(); ++i) { - drawItem(i, - true, // clear - false); // transparent - } - + redrawFrame(); } } @@ -1158,9 +1001,7 @@ void Menu::buttonReleaseEvent(XButtonEvent &re) { } } - drawItem(p, - true, // clear - true); // transparent + drawItem(p, true); // clear } } } @@ -1174,9 +1015,7 @@ void Menu::motionNotifyEvent(XMotionEvent &me) { if (! m_moving) { // if not m_moving: start m_moving operation if (m_parent && (! m_torn)) { - m_parent->drawItem(m_parent->m_which_sub, - true, // clear - true); // render transparency + m_parent->drawItem(m_parent->m_which_sub, true); // clear m_parent->m_which_sub = -1; } @@ -1207,9 +1046,7 @@ void Menu::motionNotifyEvent(XMotionEvent &me) { if (item != 0) { - drawItem(old, - true, // clear - true); // transparent + drawItem(old, true); // clear if (item->submenu()) { @@ -1247,8 +1084,7 @@ void Menu::motionNotifyEvent(XMotionEvent &me) { // draw item highlighted and // start submenu open delay - drawItem(w, - true); // clear + drawItem(w, true); // clear if (theme().menuMode() == MenuTheme::DELAY_OPEN) { // setup show menu timer @@ -1265,9 +1101,7 @@ void Menu::motionNotifyEvent(XMotionEvent &me) { // draw highlighted m_submenu_timer.stop(); if (itmp->isEnabled()) { - drawItem(w, - true, // clear - true); // transp + drawItem(w, true); // clear } } @@ -1278,9 +1112,38 @@ void Menu::motionNotifyEvent(XMotionEvent &me) { void Menu::exposeEvent(XExposeEvent &ee) { if (ee.window == menu.title) { redrawTitle(); - menu.title.clearArea(ee.x, ee.y, ee.width, ee.height); - } else if (ee.window == menu.frame) + } else if (ee.window == menu.frame) { menu.frame.clearArea(ee.x, ee.y, ee.width, ee.height); + + // find where to clear + // this is a compilicated algorithm... lets do it step by step... + // first... we see in which sub level the expose starts... and how many + // items down in that sublevel + + int sbl = (ee.x / menu.item_w), id = (ee.y / theme().itemHeight()), + // next... figure out how many sublevels over the redrawspans + sbl_d = ((ee.x + ee.width) / menu.item_w), + // then we see how many items down to redraw + id_d = ((ee.y + ee.height) / theme().itemHeight()); + + if (id_d > menu.persub) id_d = menu.persub; + // draw the sublevels and the number of items the exposure spans + int i, ii; + for (i = sbl; i <= sbl_d; i++) { + // set the iterator to the first item in the sublevel needing redrawing + int index = id + i * menu.persub; + + if (index < static_cast(menuitems.size()) && index >= 0) { + Menuitems::iterator it = menuitems.begin() + index; + Menuitems::iterator it_end = menuitems.end(); + for (ii = id; ii <= id_d && it != it_end; ++it, ii++) { + int index = ii + (i * menu.persub); + // redraw the item + drawItem(index, false); // no clear + } + } + } + } } @@ -1307,9 +1170,13 @@ void Menu::enterNotifyEvent(XCrossingEvent &ce) { } - if (m_shifted) + if (m_shifted) { menu.window.move(menu.x_shift, menu.y_shift); - + menu.title.parentMoved(); + menu.frame.parentMoved(); + clearWindow(); + } + if (validIndex(m_which_sub)) { MenuItem *tmp = menuitems[m_which_sub]; if (tmp->submenu()->isVisible()) { @@ -1319,9 +1186,7 @@ void Menu::enterNotifyEvent(XCrossingEvent &ce) { if (w != m_which_sub && (! tmp->submenu()->isTorn())) { tmp->submenu()->internal_hide(); - drawItem(m_which_sub, - true, // clear - true); // transp + drawItem(m_which_sub, true); // clear m_which_sub = -1; } } @@ -1335,9 +1200,7 @@ void Menu::leaveNotifyEvent(XCrossingEvent &ce) { if (m_which_press != -1 && m_which_sbl != -1 && menuitems.size() > 0) { int p = (m_which_sbl * menu.persub) + m_which_press; - drawItem(p, - true, // clear - true); // transp + drawItem(p, true); // clear m_which_sbl = m_which_press = -1; } @@ -1390,31 +1253,13 @@ void Menu::keyPressEvent(XKeyEvent &event) { void Menu::reconfigure() { - if (FbTk::Transparent::haveComposite()) { - if (m_transp.get() != 0) - m_transp.reset(0); - + if (FbTk::Transparent::haveComposite()) menu.window.setOpaque(alpha()); - } else if (alpha() == 255 && m_transp.get() != 0) { - m_transp.reset(0); - } else if (alpha () < 255) { - if (m_transp.get() == 0) { - m_transp.reset(new Transparent(FbPixmap::getRootPixmap(screenNumber()), - m_real_frame_pm.drawable(), alpha(), - screenNumber())); - } else { - Pixmap root = FbPixmap::getRootPixmap(screenNumber()); - if (m_transp->source() != root) - m_transp->setSource(root, screenNumber()); - - m_transp->setAlpha(alpha()); - } - } m_need_update = true; // redraw items - menu.title.setAlpha(alpha()); + menu.frame.setAlpha(alpha()); menu.window.setBorderColor(theme().borderColor()); menu.title.setBorderColor(theme().borderColor()); @@ -1423,9 +1268,9 @@ void Menu::reconfigure() { menu.window.setBorderWidth(theme().borderWidth()); menu.title.setBorderWidth(theme().borderWidth()); - - updateMenu(); - + if (m_visible) { + updateMenu(); + } } @@ -1438,8 +1283,7 @@ void Menu::openSubmenu() { if (!validIndex(item)) return; - drawItem(item, - true); // clear + drawItem(item, true); // clear if (menuitems[item]->submenu() != 0 && !menuitems[item]->submenu()->isVisible()) drawSubmenu(item); @@ -1474,61 +1318,6 @@ void Menu::update(FbTk::Subject *subj) { } -void Menu::renderTransp(int x, int y, - unsigned int width, unsigned int height) { - // even though we dont render transparency - // we do need to copy the style background - GContext def_gc(menu.frame); - m_real_frame_pm.copyArea(m_frame_pm.drawable(), - def_gc.gc(), - x, y, - x, y, - width, height); - - // no need to render transparent unless visible - // but we do need to render it if we marked it as - // need update - if (!isVisible() && !m_need_update || m_transp.get() == 0) - return; - - - // render the root background -#ifdef HAVE_XRENDER - - Pixmap root = FbPixmap::getRootPixmap(screenNumber()); - if (m_transp->source() != root) - m_transp->setSource(root, screenNumber()); - - if (m_transp->dest() != m_real_frame_pm.drawable()) - m_transp->setDest(m_real_frame_pm.drawable(), screenNumber()); - - if (m_transp->alpha() != alpha()) - m_transp->setAlpha(alpha()); - - const FbWindow *root_parent = menu.frame.parent(); - // our position in parent ("root") - int root_x = menu.frame.x() - menu.frame.borderWidth(), - root_y = menu.frame.y() - menu.frame.borderWidth(); - if (root_parent != 0) { - root_x += root_parent->x() + root_parent->borderWidth(); - root_y += root_parent->y() + root_parent->borderWidth(); - while (root_parent->parent() != 0) { - root_parent = root_parent->parent(); - root_x += root_parent->x() + root_parent->borderWidth(); - root_y += root_parent->y() + root_parent->borderWidth(); - } - - } // else toplevel window so we already have x, y set - - // render background image from root pos to our window - m_transp->render(root_x + x, root_y + y, - x, y, - width, height); - -#endif // HAVE_XRENDER - -} - void Menu::setScreen(int x, int y, int w, int h) { m_screen_x = x; m_screen_y = y; diff --git a/src/FbTk/Menu.hh b/src/FbTk/Menu.hh index f95728a..d079ba8 100644 --- a/src/FbTk/Menu.hh +++ b/src/FbTk/Menu.hh @@ -45,7 +45,6 @@ namespace FbTk { class MenuItem; class ImageControl; -class Transparent; /// Base class for menus class Menu: public FbTk::EventHandler, protected FbTk::Observer { @@ -179,15 +178,16 @@ protected: virtual void itemSelected(int button, unsigned int index) { } virtual int drawItem(unsigned int index, - bool clear = false, bool render_trans = true, + bool clear = false, int x= -1, int y= -1, unsigned int width= 0, unsigned int height= 0); virtual void redrawTitle(); + virtual void redrawFrame(); + virtual void internal_hide(); void update(FbTk::Subject *); - void renderTransp(int x, int y, - unsigned int width, unsigned int height); + private: void openSubmenu(); @@ -229,11 +229,6 @@ private: Drawable m_root_pm; static Menu *s_focused; ///< holds current input focused menu, so one can determine if a menu is focused - FbPixmap m_frame_pm, ///< buffer pixmap - m_real_frame_pm; ///< buffer pixmap (this one is shown to the user) - FbPixmap m_title_pm, ///< buffer pixmap to avoid flicker - m_real_title_pm; ///< buffer pixmap (this one is shown to the user) - std::auto_ptr m_transp; bool m_need_update; Timer m_submenu_timer; Timer m_hide_timer; diff --git a/src/FbTk/TextButton.cc b/src/FbTk/TextButton.cc index e623b9a..bdf5002 100644 --- a/src/FbTk/TextButton.cc +++ b/src/FbTk/TextButton.cc @@ -37,8 +37,7 @@ TextButton::TextButton(const FbTk::FbWindow &parent, m_text(text), m_justify(FbTk::LEFT), m_bevel(1), m_left_padding(0), - m_right_padding(0), - m_buffer(drawable(), width(), height(), depth()) { + m_right_padding(0) { } @@ -46,10 +45,6 @@ void TextButton::resize(unsigned int width, unsigned int height) { if (this->width() == width && height == this->height()) return; - m_buffer.resize(width, height); - - if (backgroundPixmap() != ParentRelative) - FbWindow::setBackgroundPixmap(m_buffer.drawable()); Button::resize(width, height); } @@ -59,12 +54,6 @@ void TextButton::moveResize(int x, int y, x == this->x() && y == this->y()) return; - if (this->width() != width || height != this->height()) - m_buffer.resize(width, height); - - if (backgroundPixmap() != ParentRelative) - FbWindow::setBackgroundPixmap(m_buffer.drawable()); - Button::moveResize(x, y, width, height); } @@ -112,37 +101,12 @@ void TextButton::clear() { void TextButton::clearArea(int x, int y, unsigned int width, unsigned int height, bool exposure) { - if (backgroundPixmap() != ParentRelative) { - if (backgroundPixmap()) { - m_buffer.copyArea(backgroundPixmap(), - gc(), - x, y, - x, y, - width, height); - - } else { // fill with background color - FbTk::GContext gc(m_buffer); - gc.setForeground(backgroundColor()); - m_buffer.fillRectangle(gc.gc(), - x, y, - width, height); - - } - drawText(); - - setBufferPixmap(m_buffer.drawable()); - FbWindow::setBackgroundPixmap(m_buffer.drawable()); - updateTransparent(x, y, width, height); - - FbWindow::clearArea(x, y, width, height, exposure); - - } else { // parent relative - FbWindow::setBufferPixmap(0); - FbWindow::setBackgroundPixmap(backgroundPixmap()); - Button::clearArea(x, y, width, height, exposure); - updateTransparent(x, y, width, height); - drawText(); - } + Button::clearArea(x, y, width, height, exposure); + // TODO: do we need to check if the text overlaps the clearing area + // and if so, then clear a rectangle that encompases all the text plus the + // requested area? + drawText(); + } unsigned int TextButton::textWidth() const { @@ -161,11 +125,8 @@ void TextButton::drawText(int x_offset, int y_offset) { // center text by default int center_pos = height()/2 + font().ascent()/2 - 1; - FbDrawable *drawable = &m_buffer; - if (backgroundPixmap() == ParentRelative) - drawable = this; - font().drawText(*drawable, + font().drawText(*this, screenNumber(), gc(), // graphic context text().c_str(), textlen, // string and string size diff --git a/src/FbTk/TextButton.hh b/src/FbTk/TextButton.hh index 14621e3..3a9407f 100644 --- a/src/FbTk/TextButton.hh +++ b/src/FbTk/TextButton.hh @@ -81,7 +81,6 @@ private: unsigned int m_left_padding; ///< space between buttonborder and text unsigned int m_right_padding; ///< space between buttonborder and text - FbTk::FbPixmap m_buffer; ///< for background buffer }; } // end namespace FbTk diff --git a/src/FbTk/Transparent.cc b/src/FbTk/Transparent.cc index 7c14849..39b0eff 100644 --- a/src/FbTk/Transparent.cc +++ b/src/FbTk/Transparent.cc @@ -206,6 +206,17 @@ void Transparent::setAlpha(unsigned char alpha) { allocAlpha(alpha); } +void Transparent::freeDest() { +#ifdef HAVE_XRENDER + if (m_dest_pic != 0) { + Display *disp = FbTk::App::instance()->display(); + XRenderFreePicture(disp, m_dest_pic); + m_dest_pic = 0; + } + m_dest = None; +#endif +} + void Transparent::setDest(Drawable dest, int screen_num) { #ifdef HAVE_XRENDER if (m_dest == dest || !s_render) @@ -213,10 +224,7 @@ void Transparent::setDest(Drawable dest, int screen_num) { Display *disp = FbTk::App::instance()->display(); - if (m_dest_pic != 0) { - XRenderFreePicture(disp, m_dest_pic); - m_dest_pic = 0; - } + freeDest(); // create new dest pic if we have a valid dest drawable if (dest != 0) { diff --git a/src/FbTk/Transparent.hh b/src/FbTk/Transparent.hh index 9dc1973..77e09c5 100644 --- a/src/FbTk/Transparent.hh +++ b/src/FbTk/Transparent.hh @@ -39,6 +39,7 @@ public: void setSource(Drawable src, int screen_num); /// sets destination drawable void setDest(Drawable dest, int screen_num); + void freeDest(); /** renders to dest from src with specified coordinates and size */ diff --git a/src/FbWinFrame.cc b/src/FbWinFrame.cc index d4a3d66..c030712 100644 --- a/src/FbWinFrame.cc +++ b/src/FbWinFrame.cc @@ -82,37 +82,14 @@ FbWinFrame::FbWinFrame(FbWinFrameTheme &theme, FbTk::ImageControl &imgctrl, m_focused(false), m_visible(false), m_button_pm(0), + m_need_render(true), m_themelistener(*this), m_shape(new Shape(m_window, theme.shapePlace())) { m_theme.reconfigSig().attach(&m_themelistener); init(); } -/* - FbWinFrame::FbWinFrame(FbWinFrameTheme &theme, FbTk::ImageControl &imgctrl, const FbTk::FbWindow &parent, int x, int y, - unsigned int width, unsigned int height): - m_theme(theme), - m_imagectrl(imgctrl), - m_window(parent, x, y, width, height, ExposureMask | StructureNotifyMask), - m_titlebar(m_window, 0, 0, 100, 16, - ExposureMask | ButtonPressMask | ButtonReleaseMask), - m_label(m_titlebar, 0, 0, 100, 16, - ExposureMask | ButtonPressMask | ButtonReleaseMask), - m_grip_right(m_window, 0, 0, 100, 100, ExposureMask | ButtonPressMask | ButtonReleaseMask), - m_grip_left(m_window, 0, 0, 100, 100, ExposureMask | ButtonPressMask | ButtonReleaseMask), - m_handle(m_window, 0, 0, 100, 100, ExposureMask | ButtonPressMask | ButtonReleaseMask), - m_clientarea(m_window, 0, 0, 100, 100, SubstructureRedirectMask), - m_bevel(1), - m_use_titlebar(true), - m_use_handles(true), - m_button_pm(0) { - - init(); - } -*/ - FbWinFrame::~FbWinFrame() { - m_update_timer.stop(); removeEventHandler(); removeAllButtons(); } @@ -141,9 +118,15 @@ void FbWinFrame::hide() { void FbWinFrame::show() { m_visible = true; + + if (m_need_render) { + renderAll(); + applyAll(); + clearAll(); + } + m_window.showSubwindows(); m_window.show(); - updateTransparent(); } /** @@ -217,14 +200,11 @@ void FbWinFrame::moveResize(int x, int y, unsigned int width, unsigned int heigh if (move && resize) { m_window.moveResize(x, y, width, height); + notifyMoved(false); // will reconfigure } else if (move) { m_window.move(x, y); // this stuff will be caught by reconfigure if resized - unsigned char alpha = (m_focused?theme().focusedAlpha():theme().unfocusedAlpha()); - if (alpha != 255) { - // restart update timer - m_update_timer.start(); - } + notifyMoved(true); } else { m_window.resize(width, height); } @@ -233,29 +213,86 @@ void FbWinFrame::moveResize(int x, int y, unsigned int width, unsigned int heigh reconfigure(); } +void FbWinFrame::notifyMoved(bool clear) { + // not important if no alpha... + unsigned char alpha = (m_focused?theme().focusedAlpha():theme().unfocusedAlpha()); + if (alpha == 255) + return; + + if (m_use_titlebar) { + m_titlebar.parentMoved(); + m_label.parentMoved(); + + for_each(m_buttons_left.begin(), + m_buttons_left.end(), + mem_fun(&FbTk::Button::parentMoved)); + for_each(m_buttons_right.begin(), + m_buttons_right.end(), + mem_fun(&FbTk::Button::parentMoved)); + for_each(m_labelbuttons.begin(), + m_labelbuttons.end(), + mem_fun(&FbTk::Button::parentMoved)); + } + + if (m_use_handle) { + m_handle.parentMoved(); + m_grip_left.parentMoved(); + m_grip_right.parentMoved(); + } + + if (clear && (m_use_handle || m_use_titlebar)) { + clearAll(); + } +} + +void FbWinFrame::clearAll() { + if (m_use_titlebar) { + redrawTitlebar(); + + for_each(m_buttons_left.begin(), + m_buttons_left.end(), + mem_fun(&FbTk::Button::clear)); + for_each(m_buttons_right.begin(), + m_buttons_right.end(), + mem_fun(&FbTk::Button::clear)); + } + + if (m_use_handle) { + m_handle.clear(); + m_grip_left.clear(); + m_grip_right.clear(); + } +} + void FbWinFrame::setFocus(bool newvalue) { if (m_focused == newvalue) return; m_focused = newvalue; + if (theme().focusedAlpha() != theme().unfocusedAlpha()) { + unsigned char alpha = (m_focused?theme().focusedAlpha():theme().unfocusedAlpha()); + if (FbTk::Transparent::haveComposite()) { + m_window.setOpaque(alpha); + } else { + LabelList::iterator btn_it = m_labelbuttons.begin(); + LabelList::iterator btn_it_end = m_labelbuttons.end(); + for (; btn_it != btn_it_end; ++btn_it) { + (*btn_it)->setAlpha(alpha); + } + } + } + if (currentLabel()) { if (newvalue) // focused - renderButtonFocus(*m_current_label); + applyFocusLabel(*m_current_label); else // unfocused - renderButtonActive(*m_current_label); + applyActiveLabel(*m_current_label); } - if (theme().focusedAlpha() != theme().unfocusedAlpha() && FbTk::Transparent::haveComposite()) { - if (m_focused) - m_window.setOpaque(theme().focusedAlpha()); - else - m_window.setOpaque(theme().unfocusedAlpha()); - } - - renderTitlebar(); - renderButtons(); // parent relative buttons -> need render after titlebar - renderHandles(); + applyTitlebar(); + applyHandles(); + clearAll(); } void FbWinFrame::setDoubleClickTime(unsigned int time) { @@ -266,7 +303,7 @@ void FbWinFrame::addLeftButton(FbTk::Button *btn) { if (btn == 0) // valid button? return; - setupButton(*btn); // setup theme and other stuff + applyButton(*btn); // setup theme and other stuff m_buttons_left.push_back(btn); } @@ -275,7 +312,7 @@ void FbWinFrame::addRightButton(FbTk::Button *btn) { if (btn == 0) // valid button? return; - setupButton(*btn); // setup theme and other stuff + applyButton(*btn); // setup theme and other stuff m_buttons_right.push_back(btn); } @@ -470,14 +507,14 @@ void FbWinFrame::setLabelButtonFocus(FbTk::TextButton &btn) { // render label buttons if (currentLabel() != 0) - renderButtonUnfocus(*m_current_label); + applyUnfocusLabel(*m_current_label); m_current_label = *it; // current focused button if (m_focused) - renderButtonFocus(*m_current_label); + applyFocusLabel(*m_current_label); else - renderButtonActive(*m_current_label); + applyActiveLabel(*m_current_label); } void FbWinFrame::setClientWindow(FbTk::FbWindow &win) { @@ -571,9 +608,11 @@ bool FbWinFrame::showHandle() { if (m_use_handle || theme().handleWidth() == 0) return false; + // weren't previously rendered... + renderHandles(); + m_use_handle = true; - renderHandles(); m_handle.show(); m_handle.showSubwindows(); // shows grips @@ -691,19 +730,14 @@ void FbWinFrame::buttonReleaseEvent(XButtonEvent &event) { void FbWinFrame::exposeEvent(XExposeEvent &event) { if (m_titlebar == event.window) { m_titlebar.clearArea(event.x, event.y, event.width, event.height); - m_titlebar.updateTransparent(event.x, event.y, event.width, event.height); } else if (m_label == event.window) { m_label.clearArea(event.x, event.y, event.width, event.height); - m_label.updateTransparent(event.x, event.y, event.width, event.height); } else if (m_handle == event.window) { m_handle.clearArea(event.x, event.y, event.width, event.height); - m_handle.updateTransparent(event.x, event.y, event.width, event.height); } else if (m_grip_left == event.window) { m_grip_left.clearArea(event.x, event.y, event.width, event.height); - m_grip_left.updateTransparent(event.x, event.y, event.width, event.height); } else if (m_grip_right == event.window) { m_grip_right.clearArea(event.x, event.y, event.width, event.height); - m_grip_right.updateTransparent(event.x, event.y, event.width, event.height); } else { // create compare function // that we should use with find_if @@ -819,9 +853,8 @@ void FbWinFrame::reconfigure() { // render the theme - renderButtons(); - if (!m_shaded) - renderHandles(); + renderAll(); + applyAll(); if (m_shape.get() && theme().shapePlace() == Shape::NONE || m_disable_shape) m_shape.reset(0); @@ -914,20 +947,15 @@ void FbWinFrame::redrawTitle() { dx - border_width, label().height() + border_width); - } if (isVisible()) { for_each(m_labelbuttons.begin(), m_labelbuttons.end(), - mem_fun(&FbTk::Button::clear)); - } + mem_fun(&FbTk::TextButton::clear)); - if (isVisible()) { m_label.clear(); - m_label.updateTransparent(); m_titlebar.clear(); - m_titlebar.updateTransparent(); } } @@ -964,12 +992,13 @@ void FbWinFrame::reconfigureTitlebar() { unsigned int button_size = buttonHeight(); m_button_size = button_size; for (size_t i=0; i < m_buttons_left.size(); i++, next_x += button_size + m_bevel) { + //cerr<<"m_buttons_left["<moveResize(next_x="<moveResize(next_x, m_bevel, button_size, button_size); } next_x += m_bevel; - + // space left on titlebar between left and right buttons unsigned int space_left = m_titlebar.width() - next_x; if (!m_buttons_right.empty()) @@ -989,14 +1018,33 @@ void FbWinFrame::reconfigureTitlebar() { button_size, button_size); } - renderTitlebar(); +// renderTitlebar(); // gets done outside m_titlebar.raise(); // always on top } +void FbWinFrame::renderAll() { + m_need_render = false; + + renderTitlebar(); + renderHandles(); + renderLabelButtons(); +} + +void FbWinFrame::applyAll() { + applyTitlebar(); + applyHandles(); + applyLabelButtons(); +} + void FbWinFrame::renderTitlebar() { if (!m_use_titlebar) return; + if (!isVisible()) { + m_need_render = true; + return; + } + // render pixmaps render(m_theme.titleFocusTexture(), m_title_focused_color, m_title_focused_pm, @@ -1006,7 +1054,6 @@ void FbWinFrame::renderTitlebar() { m_title_unfocused_pm, m_titlebar.width(), m_titlebar.height()); - render(m_theme.labelFocusTexture(), m_label_focused_color, m_label_focused_pm, m_label.width(), m_label.height()); @@ -1016,12 +1063,12 @@ void FbWinFrame::renderTitlebar() { m_label_unfocused_pm, m_label.width(), m_label.height()); - render(m_theme.labelActiveTexture(), m_label_active_color, - m_label_active_pm, - m_label.width(), m_label.height()); + renderButtons(); +} +void FbWinFrame::applyTitlebar() { - // finaly set up pixmaps for titlebar windows + // set up pixmaps for titlebar windows Pixmap label_pm = None; Pixmap title_pm = None; FbTk::Color label_color; @@ -1029,6 +1076,10 @@ void FbWinFrame::renderTitlebar() { getCurrentFocusPixmap(label_pm, title_pm, label_color, title_color); + unsigned char alpha = (m_focused?theme().focusedAlpha():theme().unfocusedAlpha()); + m_titlebar.setAlpha(alpha); + m_label.setAlpha(alpha); + if (label_pm != 0) m_label.setBackgroundPixmap(label_pm); else @@ -1039,18 +1090,7 @@ void FbWinFrame::renderTitlebar() { else m_titlebar.setBackgroundColor(title_color); - unsigned char alpha = (m_focused?theme().focusedAlpha():theme().unfocusedAlpha()); - m_titlebar.setAlpha(alpha); - m_label.setAlpha(alpha); - - LabelList::iterator btn_it = m_labelbuttons.begin(); - LabelList::iterator btn_it_end = m_labelbuttons.end(); - for (; btn_it != btn_it_end; ++btn_it) { - (*btn_it)->setAlpha(alpha); - } - - renderLabelButtons(); - redrawTitlebar(); + applyButtons(); } @@ -1058,6 +1098,11 @@ void FbWinFrame::renderHandles() { if (!m_use_handle) return; + if (!isVisible()) { + m_need_render = true; + return; + } + render(m_theme.handleFocusTexture(), m_handle_focused_color, m_handle_focused_pm, m_handle.width(), m_handle.height()); @@ -1066,20 +1111,6 @@ void FbWinFrame::renderHandles() { m_handle_unfocused_pm, m_handle.width(), m_handle.height()); - if (m_focused) { - if (m_handle_focused_pm) { - m_handle.setBackgroundPixmap(m_handle_focused_pm); - } else { - m_handle.setBackgroundColor(m_handle_focused_color); - } - } else { - if (m_handle_unfocused_pm) { - m_handle.setBackgroundPixmap(m_handle_unfocused_pm); - } else { - m_handle.setBackgroundColor(m_handle_unfocused_color); - } - } - render(m_theme.gripFocusTexture(), m_grip_focused_color, m_grip_focused_pm, m_grip_left.width(), m_grip_left.height()); @@ -1087,7 +1118,23 @@ void FbWinFrame::renderHandles() { m_grip_unfocused_pm, m_grip_left.width(), m_grip_left.height()); +} + +void FbWinFrame::applyHandles() { + + unsigned char alpha = (m_focused?theme().focusedAlpha():theme().unfocusedAlpha()); + m_handle.setAlpha(alpha); + m_grip_left.setAlpha(alpha); + m_grip_right.setAlpha(alpha); + if (m_focused) { + + if (m_handle_focused_pm) { + m_handle.setBackgroundPixmap(m_handle_focused_pm); + } else { + m_handle.setBackgroundColor(m_handle_focused_color); + } + if (m_grip_focused_pm) { m_grip_left.setBackgroundPixmap(m_grip_focused_pm); m_grip_right.setBackgroundPixmap(m_grip_focused_pm); @@ -1095,7 +1142,15 @@ void FbWinFrame::renderHandles() { m_grip_left.setBackgroundColor(m_grip_focused_color); m_grip_right.setBackgroundColor(m_grip_focused_color); } + } else { + + if (m_handle_unfocused_pm) { + m_handle.setBackgroundPixmap(m_handle_unfocused_pm); + } else { + m_handle.setBackgroundColor(m_handle_unfocused_color); + } + if (m_grip_unfocused_pm) { m_grip_left.setBackgroundPixmap(m_grip_unfocused_pm); m_grip_right.setBackgroundPixmap(m_grip_unfocused_pm); @@ -1105,23 +1160,17 @@ void FbWinFrame::renderHandles() { } } - unsigned char alpha = (m_focused?theme().focusedAlpha():theme().unfocusedAlpha()); - m_handle.setAlpha(alpha); - m_grip_left.setAlpha(alpha); - m_grip_right.setAlpha(alpha); - - m_grip_left.clear(); - m_grip_left.updateTransparent(); - m_grip_right.clear(); - m_grip_right.updateTransparent(); - m_handle.clear(); - m_handle.updateTransparent(); - } void FbWinFrame::renderButtons() { - render(m_theme.buttonFocusTexture(), m_button_color, m_button_pm, + if (!isVisible()) { + m_need_render = true; + return; + } + + render(m_theme.buttonFocusTexture(), m_button_color, + m_button_pm, m_button_size, m_button_size); render(m_theme.buttonUnfocusTexture(), m_button_unfocused_color, @@ -1131,23 +1180,15 @@ void FbWinFrame::renderButtons() { render(m_theme.buttonPressedTexture(), m_button_pressed_color, m_button_pressed_pm, m_button_size, m_button_size); +} +void FbWinFrame::applyButtons() { // setup left and right buttons for (size_t i=0; i < m_buttons_left.size(); ++i) - setupButton(*m_buttons_left[i]); + applyButton(*m_buttons_left[i]); for (size_t i=0; i < m_buttons_right.size(); ++i) - setupButton(*m_buttons_right[i]); - - if (isVisible()) { - for_each(m_buttons_left.begin(), - m_buttons_left.end(), - mem_fun(&FbTk::Button::clear)); - for_each(m_buttons_right.begin(), - m_buttons_right.end(), - mem_fun(&FbTk::Button::clear)); - } - + applyButton(*m_buttons_right[i]); } void FbWinFrame::init() { @@ -1157,13 +1198,6 @@ void FbWinFrame::init() { m_window.setOpaque(theme().focusedAlpha()); else m_window.setOpaque(theme().unfocusedAlpha()); - } else { - // setup update timer - FbTk::RefCount update_transp(new FbTk::SimpleCommand(*this, - &FbWinFrame::updateTransparent)); - m_update_timer.setCommand(update_transp); - m_update_timer.setTimeout(10L); - m_update_timer.fireOnce(true); } if (theme().handleWidth() == 0) @@ -1177,7 +1211,8 @@ void FbWinFrame::init() { // clear pixmaps m_title_focused_pm = m_title_unfocused_pm = 0; - m_label_focused_pm = m_label_unfocused_pm = m_label_active_pm = 0; + m_label_focused_pm = m_label_unfocused_pm = 0; + m_labelbutton_focused_pm = m_labelbutton_unfocused_pm = m_labelbutton_active_pm = 0; m_handle_focused_pm = m_handle_unfocused_pm = 0; m_button_pm = m_button_unfocused_pm = m_button_pressed_pm = 0; m_grip_unfocused_pm = m_grip_focused_pm = 0; @@ -1200,27 +1235,28 @@ void FbWinFrame::init() { /** Setups upp background, pressed pixmap/color of the button to current theme */ -void FbWinFrame::setupButton(FbTk::Button &btn) { +void FbWinFrame::applyButton(FbTk::Button &btn) { if (m_button_pressed_pm) btn.setPressedPixmap(m_button_pressed_pm); - - //!! TODO button pressed color + else + btn.setPressedColor(m_button_pressed_color); if (focused()) { // focused + btn.setAlpha(theme().focusedAlpha()); + btn.setGC(m_theme.buttonPicFocusGC()); if (m_button_pm) btn.setBackgroundPixmap(m_button_pm); else btn.setBackgroundColor(m_button_color); - btn.setAlpha(theme().focusedAlpha()); } else { // unfocused + btn.setAlpha(theme().unfocusedAlpha()); + btn.setGC(m_theme.buttonPicUnfocusGC()); if (m_button_unfocused_pm) btn.setBackgroundPixmap(m_button_unfocused_pm); else btn.setBackgroundColor(m_button_unfocused_color); - - btn.setAlpha(theme().unfocusedAlpha()); } } @@ -1244,10 +1280,10 @@ void FbWinFrame::render(const FbTk::Texture &tex, FbTk::Color &col, Pixmap &pm, void FbWinFrame::getCurrentFocusPixmap(Pixmap &label_pm, Pixmap &title_pm, FbTk::Color &label_color, FbTk::Color &title_color) { if (m_focused) { - if (m_label_focused_pm != 0) - label_pm = m_label_focused_pm; + if (m_labelbutton_focused_pm != 0) + label_pm = m_labelbutton_focused_pm; else - label_color = m_label_focused_color; + label_color = m_labelbutton_focused_color; if (m_title_focused_pm != 0) title_pm = m_title_focused_pm; @@ -1266,10 +1302,10 @@ void FbWinFrame::getActiveLabelPixmap(Pixmap &label_pm, Pixmap &title_pm, FbTk::Color &label_color, FbTk::Color &title_color) { - if (m_label_active_pm != 0) - label_pm = m_label_active_pm; + if (m_labelbutton_active_pm != 0) + label_pm = m_labelbutton_active_pm; else - label_color = m_label_active_color; + label_color = m_labelbutton_active_color; if (m_title_unfocused_pm != 0) title_pm = m_title_unfocused_pm; @@ -1278,36 +1314,39 @@ void FbWinFrame::getActiveLabelPixmap(Pixmap &label_pm, Pixmap &title_pm, } void FbWinFrame::renderLabelButtons() { + if (!isVisible()) { + m_need_render = true; + return; + } - Pixmap label_pm = 0; - Pixmap not_used_pm = 0; - FbTk::Color label_color; - FbTk::Color not_used_color; - getCurrentFocusPixmap(label_pm, not_used_pm, - label_color, not_used_color); + render(m_theme.labelFocusTexture(), m_labelbutton_focused_color, + m_labelbutton_focused_pm, + m_label.width(), m_label.height()); + + + render(m_theme.labelUnfocusTexture(), m_labelbutton_unfocused_color, + m_labelbutton_unfocused_pm, + m_label.width(), m_label.height()); + + render(m_theme.labelActiveTexture(), m_labelbutton_active_color, + m_labelbutton_active_pm, + m_label.width(), m_label.height()); + +} + +void FbWinFrame::applyLabelButtons() { LabelList::iterator btn_it = m_labelbuttons.begin(); LabelList::iterator btn_it_end = m_labelbuttons.end(); for (; btn_it != btn_it_end; ++btn_it) { if (*btn_it == m_current_label) { if (m_focused) - renderButtonFocus(**btn_it); + applyFocusLabel(**btn_it); else - renderButtonActive(**btn_it); + applyActiveLabel(**btn_it); } else - renderButtonUnfocus(**btn_it); - + applyUnfocusLabel(**btn_it); } - - if (m_current_label != 0) { - - if (label_pm) { - m_current_label->setBackgroundPixmap(label_pm); - } else - m_current_label->setBackgroundColor(label_color); - - } - } void FbWinFrame::setBorderWidth(unsigned int border_width) { @@ -1338,50 +1377,48 @@ void FbWinFrame::setBorderWidth(unsigned int border_width) { resize(width(), height() + bw_changes); } -void FbWinFrame::renderButtonFocus(FbTk::TextButton &button) { +void FbWinFrame::applyFocusLabel(FbTk::TextButton &button) { button.setGC(theme().labelTextFocusGC()); button.setJustify(theme().justify()); button.setBorderWidth(1); + button.setAlpha(m_focused?theme().focusedAlpha():theme().unfocusedAlpha()); - if (m_label_focused_pm != 0) { - // already set - if (button.backgroundPixmap() != m_label_focused_pm) - button.setBackgroundPixmap(m_label_focused_pm); + if (m_labelbutton_focused_pm != 0) { + button.setBackgroundPixmap(m_labelbutton_focused_pm); } else - button.setBackgroundColor(m_label_focused_color); + button.setBackgroundColor(m_labelbutton_focused_color); } -void FbWinFrame::renderButtonActive(FbTk::TextButton &button) { +void FbWinFrame::applyActiveLabel(FbTk::TextButton &button) { button.setGC(theme().labelTextActiveGC()); button.setJustify(theme().justify()); button.setBorderWidth(1); + button.setAlpha(m_focused?theme().focusedAlpha():theme().unfocusedAlpha()); - if (m_label_active_pm != 0) { - // already set - if (button.backgroundPixmap() != m_label_active_pm) - button.setBackgroundPixmap(m_label_active_pm); + if (m_labelbutton_active_pm != 0) { + button.setBackgroundPixmap(m_labelbutton_active_pm); } else - button.setBackgroundColor(m_label_active_color); + button.setBackgroundColor(m_labelbutton_active_color); } -void FbWinFrame::renderButtonUnfocus(FbTk::TextButton &button) { +void FbWinFrame::applyUnfocusLabel(FbTk::TextButton &button) { button.setGC(theme().labelTextUnfocusGC()); button.setJustify(theme().justify()); button.setBorderWidth(1); + button.setAlpha(m_focused?theme().focusedAlpha():theme().unfocusedAlpha()); - if (m_label_unfocused_pm != 0) { - // already set - if (button.backgroundPixmap() != m_label_unfocused_pm) - button.setBackgroundPixmap(m_label_unfocused_pm); + if (m_labelbutton_unfocused_pm != 0) { + button.setBackgroundPixmap(m_labelbutton_unfocused_pm); } else - button.setBackgroundColor(m_label_unfocused_color); + button.setBackgroundColor(m_labelbutton_unfocused_color); } + namespace { class IgnoreEvent { public: @@ -1403,58 +1440,6 @@ private: }; } -void FbWinFrame::updateTransparent() { - if (FbTk::Transparent::haveComposite()) - return; - - m_label.clear(); - m_label.updateTransparent(); - m_titlebar.clear(); - m_titlebar.updateTransparent(); - - for_each(m_labelbuttons.begin(), - m_labelbuttons.end(), - mem_fun(&FbTk::Button::clear)); - - for_each(m_buttons_left.begin(), - m_buttons_left.end(), - mem_fun(&FbTk::Button::clear)); - - for_each(m_buttons_right.begin(), - m_buttons_right.end(), - mem_fun(&FbTk::Button::clear)); - // ignore exposure events, since we already cleared - // and redrawn the windows - IgnoreEvent ign(ExposureMask); - - // base windows - ign(m_label.window()); - ign(m_titlebar.window()); - - // labels - for_each(m_labelbuttons.begin(), - m_labelbuttons.end(), - FbTk::Compose(ign, mem_fun(&FbTk::Button::window))); - // win buttons - for_each(m_buttons_right.begin(), - m_buttons_right.end(), - FbTk::Compose(ign, mem_fun(&FbTk::Button::window))); - for_each(m_buttons_left.begin(), - m_buttons_left.end(), - FbTk::Compose(ign, mem_fun(&FbTk::Button::window))); - - m_grip_left.clear(); - m_grip_left.updateTransparent(); - ign(m_grip_left.window()); - m_grip_right.clear(); - m_grip_right.updateTransparent(); - ign(m_grip_right.window()); - m_handle.clear(); - m_handle.updateTransparent(); - ign(m_handle.window()); -} - - // this function translates its arguments according to win_gravity // if win_gravity is negative, it does an inverse translation // This function should be used when a window is mapped/unmapped/pos configured diff --git a/src/FbWinFrame.hh b/src/FbWinFrame.hh index 768f733..7582f2c 100644 --- a/src/FbWinFrame.hh +++ b/src/FbWinFrame.hh @@ -30,7 +30,6 @@ #include "FbTk/Observer.hh" #include "FbTk/Color.hh" #include "FbTk/FbPixmap.hh" -#include "FbTk/Timer.hh" #include #include @@ -87,6 +86,11 @@ public: // can elect to ignore move or resize (mainly for use of move/resize individual functions void moveResize(int x, int y, unsigned int width, unsigned int height, bool move = true, bool resize = true, int win_gravity=ForgetGravity); + /// some outside move/resize happened, and we need to notify all of our windows + /// in case of transparency + void notifyMoved(bool clear); + void clearAll(); + /// set focus/unfocus style void setFocus(bool newvalue); void setDoubleClickTime(unsigned int time); @@ -151,8 +155,6 @@ public: void reconfigure(); void setUseShape(bool value); - void setUpdateDelayTime(long t) { m_update_timer.setTimeout(t); } - /** @name accessors */ @@ -199,31 +201,43 @@ private: @name render helper functions */ //@{ + void renderAll(); void renderTitlebar(); void renderHandles(); - void renderButtons(); - // focused => has focus - void renderButtonFocus(FbTk::TextButton &button); - // unfocus => has no focus, label not the active one - void renderButtonUnfocus(FbTk::TextButton &button); - // active => doesn't have keybaord focus, but is the active tab - void renderButtonActive(FbTk::TextButton &button); - void renderLabel(); + void renderLabelButtons(); + + void renderButtons(); // subset of renderTitlebar - don't call directly + /// renders to pixmap or sets color void render(const FbTk::Texture &tex, FbTk::Color &col, Pixmap &pm, unsigned int width, unsigned int height); + + //@} + + /** + @name apply pixmaps depending on focus + */ + //@{ + void applyAll(); + void applyTitlebar(); + void applyHandles(); + void applyLabelButtons(); + void applyFocusLabel(FbTk::TextButton &button); + void applyUnfocusLabel(FbTk::TextButton &button); + void applyActiveLabel(FbTk::TextButton &button); + void applyButtons(); // only called within applyTitlebar + void getActiveLabelPixmap(Pixmap &label_pm, Pixmap &title_pm, FbTk::Color &label_color, FbTk::Color &title_color); void getCurrentFocusPixmap(Pixmap &label_pm, Pixmap &title_pm, FbTk::Color &label_color, FbTk::Color &title_color); - void renderLabelButtons(); + + /// initiate inserted button for current theme + void applyButton(FbTk::Button &btn); //@} /// initiate some commont variables void init(); - /// initiate inserted buttons for current theme - void setupButton(FbTk::Button &btn); - void updateTransparent(); FbWinFrameTheme &m_theme; ///< theme to be used FbTk::ImageControl &m_imagectrl; ///< Image control for rendering @@ -265,8 +279,13 @@ private: FbTk::Color m_label_focused_color; ///< color for focused label Pixmap m_label_unfocused_pm; ///< pixmap for unfocused label FbTk::Color m_label_unfocused_color; ///< color for unfocued label - Pixmap m_label_active_pm; ///< pixmap for active label - FbTk::Color m_label_active_color; ///< color for active label + + Pixmap m_labelbutton_focused_pm; ///< pixmap for focused label + FbTk::Color m_labelbutton_focused_color; ///< color for focused label + Pixmap m_labelbutton_unfocused_pm; ///< pixmap for unfocused label + FbTk::Color m_labelbutton_unfocused_color; ///< color for unfocued label + Pixmap m_labelbutton_active_pm; ///< pixmap for active label + FbTk::Color m_labelbutton_active_color; ///< color for active label FbTk::Color m_handle_focused_color, m_handle_unfocused_color; Pixmap m_handle_focused_pm, m_handle_unfocused_pm; @@ -285,6 +304,7 @@ private: FbTk::Color m_grip_unfocused_color; ///< unfocused color for grip if no pixmap is given //@} + bool m_need_render; int m_button_size; ///< size for all titlebar buttons unsigned int m_width_before_shade, ///< width before shade, so we can restore it when we unshade m_height_before_shade; ///< height before shade, so we can restore it when we unshade @@ -309,7 +329,6 @@ private: ThemeListener m_themelistener; std::auto_ptr m_shape; bool m_disable_shape; - FbTk::Timer m_update_timer; }; #endif // FBWINFRAME_HH diff --git a/src/GenericTool.cc b/src/GenericTool.cc index 7d8e7fd..b23e871 100644 --- a/src/GenericTool.cc +++ b/src/GenericTool.cc @@ -79,10 +79,8 @@ unsigned int GenericTool::borderWidth() const { void GenericTool::renderTheme(unsigned char alpha) { m_window->setAlpha(alpha); m_window->clear(); - m_window->updateTransparent(); } void GenericTool::update(FbTk::Subject *subj) { m_window->clear(); - m_window->updateTransparent(); } diff --git a/src/Slit.cc b/src/Slit.cc index 05f76d6..ea70e6b 100644 --- a/src/Slit.cc +++ b/src/Slit.cc @@ -1084,7 +1084,6 @@ void Slit::exposeEvent(XExposeEvent &ev) { // we don't need to clear the entire window // just the are that gets exposed frame.window.clearArea(ev.x, ev.y, ev.width, ev.height); - frame.window.updateTransparent(ev.x, ev.y, ev.width, ev.height); } void Slit::update(FbTk::Subject *subj) { @@ -1093,7 +1092,6 @@ void Slit::update(FbTk::Subject *subj) { void Slit::clearWindow() { frame.window.clear(); - frame.window.updateTransparent(); } void Slit::toggleHidden() { diff --git a/src/ToggleMenu.hh b/src/ToggleMenu.hh index 1b489d6..b2d9e54 100644 --- a/src/ToggleMenu.hh +++ b/src/ToggleMenu.hh @@ -48,15 +48,12 @@ public: // so that the last toggled item gets redrawn as // not toggled. if (ev.window == frameWindow()) { - renderTransp(0, 0, width(), frameWindow().height()); - + frameWindow().clear(); for (size_t i = 0; i < numberOfItems(); ++i) { - drawItem(i, // index - true, // clear - false); // render transparent + drawItem(i, // index + false); // clear } - frameWindow().clear(); } } diff --git a/src/Toolbar.cc b/src/Toolbar.cc index a9b4c9d..dad91aa 100644 --- a/src/Toolbar.cc +++ b/src/Toolbar.cc @@ -462,7 +462,6 @@ void Toolbar::reconfigure() { frame.window.setAlpha(alpha()); } frame.window.clear(); - frame.window.updateTransparent(); if (theme().shape() && m_shape.get()) m_shape->update(); @@ -563,8 +562,6 @@ void Toolbar::exposeEvent(XExposeEvent &ee) { if (ee.window == frame.window) { frame.window.clearArea(ee.x, ee.y, ee.width, ee.height); - frame.window.updateTransparent(ee.x, ee.y, - ee.width, ee.height); } } @@ -1028,8 +1025,6 @@ void Toolbar::rearrangeItems() { // unlock m_resize_lock = false; frame.window.clear(); - frame.window.updateTransparent(); - } void Toolbar::deleteItems() { @@ -1047,7 +1042,6 @@ void Toolbar::updateAlpha() { } else { frame.window.setAlpha(*m_rc_alpha); frame.window.clear(); - frame.window.updateTransparent(); ItemList::iterator item_it = m_item_list.begin(); ItemList::iterator item_it_end = m_item_list.end(); diff --git a/src/WinButton.cc b/src/WinButton.cc index f9e6fe2..9ae2593 100644 --- a/src/WinButton.cc +++ b/src/WinButton.cc @@ -25,6 +25,7 @@ #include "App.hh" #include "Window.hh" #include "WinButtonTheme.hh" +#include "FbTk/Color.hh" WinButton::WinButton(const FluxboxWindow &listen_to, WinButtonTheme &theme, @@ -32,261 +33,206 @@ WinButton::WinButton(const FluxboxWindow &listen_to, int x, int y, unsigned int width, unsigned int height): FbTk::Button(parent, x, y, width, height), - m_type(buttontype), m_listen_to(listen_to), m_theme(theme) { + m_type(buttontype), m_listen_to(listen_to), m_theme(theme), + overrode_bg(false), overrode_pressed(false) { theme.reconfigSig().attach(this); } void WinButton::exposeEvent(XExposeEvent &event) { FbTk::Button::exposeEvent(event); - drawType(false, false); + drawType(); } void WinButton::buttonReleaseEvent(XButtonEvent &event) { FbTk::Button::buttonReleaseEvent(event); } -// clear is used to force this to clear the window (e.g. called from clear()) -void WinButton::drawType(bool clear, bool no_trans) { - bool used = false; +// when someone else tries to set the background, we may override it +void WinButton::setBackgroundPixmap(Pixmap pm) { + Pixmap my_pm = getBackgroundPixmap(); - // if it's odd and we're centring, we need to add one - int oddW = width()%2; - int oddH = height()%2; - - switch (m_type) { - case MAXIMIZE: + if (my_pm != 0) { + overrode_bg = true; + pm = my_pm; + } else { + overrode_bg = false; + } - if (pressed() && m_theme.maximizePressedPixmap().pixmap().drawable() != 0) { - FbTk::FbWindow::setBackgroundPixmap(m_theme. - maximizePressedPixmap(). - pixmap().drawable()); - used = true; - } else { - // check focus - if (!m_listen_to.isFocused()) { - if (m_theme.maximizeUnfocusPixmap().pixmap().drawable() != 0) { - // not focused - FbTk::FbWindow::setBackgroundPixmap(m_theme. - maximizeUnfocusPixmap(). - pixmap().drawable()); - used = true; - } - } else if (m_theme.maximizePixmap().pixmap().drawable() != 0) { - FbTk::FbWindow::setBackgroundPixmap(m_theme. - maximizePixmap(). - pixmap().drawable()); - used = true; - } - } - if (used || clear) - FbTk::FbWindow::clear(); - - // if no pixmap was used, use old style - if (!used) { - if (gc() == 0) // must have valid graphic context - return; + FbTk::Button::setBackgroundPixmap(pm); +} - drawRectangle(gc(), - 2, 2, width() - 5, height() - 5); - drawLine(gc(), - 2, 3, width() - 3, 3); - } - break; - case MINIMIZE: +void WinButton::setBackgroundColor(const FbTk::Color &color) { + Pixmap my_pm = getBackgroundPixmap(); - if (pressed() && m_theme.iconifyPressedPixmap().pixmap().drawable() != 0) { - FbTk::FbWindow::setBackgroundPixmap(m_theme. - iconifyPressedPixmap(). - pixmap().drawable()); - used = true; - } else { - if (m_theme.iconifyPixmap().pixmap().drawable()){ - // check focus - if (!m_listen_to.isFocused()) { - if (m_theme.iconifyUnfocusPixmap().pixmap().drawable() != 0) { - // not focused - FbTk::FbWindow::setBackgroundPixmap(m_theme. - iconifyUnfocusPixmap(). - pixmap().drawable()); - used = true; - } - } else if (m_theme.iconifyPixmap().pixmap().drawable() != 0) { - FbTk::FbWindow::setBackgroundPixmap(m_theme. - iconifyPixmap(). - pixmap().drawable()); - used = true; - } - } + if (my_pm != 0) { + overrode_bg = true; + FbTk::Button::setBackgroundPixmap(my_pm); + } else { + overrode_bg = false; + FbTk::Button::setBackgroundColor(color); + } +} - } +void WinButton::setPressedPixmap(Pixmap pm) { + Pixmap my_pm = getPressedPixmap(); - if (used || clear) { - FbTk::FbWindow::clear(); - } - if (!used && gc() != 0) { // must have valid graphic context - FbTk::FbWindow::drawRectangle(gc(), - 2, height() - 5, width() - 5, 2); - } - break; - case STICK: + if (my_pm != 0) { + overrode_pressed = true; + pm = my_pm; + } else { + overrode_pressed = false; + } - if (m_listen_to.isStuck() && !pressed()) { - if ( m_theme.stuckPixmap().pixmap().drawable() && - ! pressed()) { // we're using the same pixmap for pressed as in not stuck - // check focus - if (!m_listen_to.isFocused()) { - if ( m_theme.stuckUnfocusPixmap().pixmap().drawable() != 0) { - // not focused - FbTk::FbWindow::setBackgroundPixmap(m_theme. - stuckUnfocusPixmap(). - pixmap().drawable()); - used = true; - } - } else if (m_theme.stuckPixmap().pixmap().drawable() != 0) { - // focused - FbTk::FbWindow::setBackgroundPixmap(m_theme. - stuckPixmap(). - pixmap().drawable()); - used = true; - } - } - } else { // not stuck and pressed - if (pressed()) { - if (m_theme.stickPressedPixmap().pixmap().drawable() != 0) { - FbTk::FbWindow::setBackgroundPixmap(m_theme. - stickPressedPixmap(). - pixmap().drawable()); - used = true; - } - } else { // not pressed - // check focus - if (!m_listen_to.isFocused()) { - if (m_theme.stickUnfocusPixmap().pixmap().drawable() != 0) { - // not focused - FbTk::FbWindow::setBackgroundPixmap(m_theme. - stickUnfocusPixmap(). - pixmap().drawable()); - used = true; - } - } else if (m_theme.stickPixmap().pixmap().drawable()) { // focused - FbTk::FbWindow::setBackgroundPixmap(m_theme. - stickPixmap(). - pixmap().drawable()); - used = true; - } + FbTk::Button::setBackgroundPixmap(pm); +} - } - - } +void WinButton::setPressedColor(const FbTk::Color &color) { + Pixmap my_pm = getPressedPixmap(); - if (used || clear) - FbTk::FbWindow::clear(); + if (my_pm != 0) { + overrode_pressed = true; + FbTk::Button::setPressedPixmap(my_pm); + } else { + overrode_pressed = false; + FbTk::Button::setPressedColor(color); + } +} - if (!used && gc() != 0) { - // width/4 != width/2, so we use /4*2 so that it's properly centred - if (m_listen_to.isStuck()) { - fillRectangle(gc(), - width()/2 - width()/4, height()/2 - height()/4, - width()/4*2 + oddW, height()/4*2 + oddH); - } else { - fillRectangle(gc(), - width()/2 - width()/10, height()/2 - height()/10, - width()/10*2 + oddW, height()/10*2 + oddH); - } +Pixmap WinButton::getBackgroundPixmap() const { + bool focused = m_listen_to.isFocused(); + switch(m_type) { + case MAXIMIZE: + if (focused) + return m_theme.maximizePixmap().pixmap().drawable(); + else + return m_theme.maximizeUnfocusPixmap().pixmap().drawable(); + break; + case MINIMIZE: + if (focused) + return m_theme.iconifyPixmap().pixmap().drawable(); + else + return m_theme.iconifyUnfocusPixmap().pixmap().drawable(); + break; + case STICK: { + bool stuck = m_listen_to.isStuck(); + if (stuck) { + if (focused) + return m_theme.stuckPixmap().pixmap().drawable(); + else + return m_theme.stuckUnfocusPixmap().pixmap().drawable(); + } else { + if (focused) + return m_theme.stickPixmap().pixmap().drawable(); + else + return m_theme.stickUnfocusPixmap().pixmap().drawable(); } + } break; case CLOSE: - - if (pressed()) { - if (m_theme.closePressedPixmap().pixmap().drawable()) { - FbTk::FbWindow::setBackgroundPixmap(m_theme. - closePressedPixmap(). - pixmap().drawable()); - used = true; - } - } else { // not pressed - // check focus - if (!m_listen_to.isFocused()) { - if (m_theme.closeUnfocusPixmap().pixmap().drawable() != 0) { - // not focused - FbTk::FbWindow::setBackgroundPixmap(m_theme. - closeUnfocusPixmap(). - pixmap().drawable()); - used = true; - } - } else if (m_theme.closePixmap().pixmap().drawable() != 0) { // focused - FbTk::FbWindow::setBackgroundPixmap(m_theme. - closePixmap(). - pixmap().drawable()); - used = true; - } - } + if (focused) + return m_theme.closePixmap().pixmap().drawable(); + else + return m_theme.closeUnfocusPixmap().pixmap().drawable(); + break; + case SHADE: + if (focused) + return m_theme.shadePixmap().pixmap().drawable(); + else + return m_theme.shadeUnfocusPixmap().pixmap().drawable(); + break; + } + return None; +} - - if (used || clear) - FbTk::FbWindow::clear(); +Pixmap WinButton::getPressedPixmap() const { + switch(m_type) { + case MAXIMIZE: + return m_theme.maximizePressedPixmap().pixmap().drawable(); + case MINIMIZE: + return m_theme.iconifyPressedPixmap().pixmap().drawable(); + case STICK: + return m_theme.stickPressedPixmap().pixmap().drawable(); + case CLOSE: + return m_theme.closePressedPixmap().pixmap().drawable(); + case SHADE: + return m_theme.shadePressedPixmap().pixmap().drawable(); + } + return None; +} - if (!used && gc() != 0) { // must have valid graphic context +// clear is used to force this to clear the window (e.g. called from clear()) +void WinButton::drawType() { + bool used = false; - drawLine(gc(), - 2, 2, - width() - 3, height() - 3); - // I can't figure out why this second one needs a y offset of 1????? - // but it does - at least on my box: - // XFree86 Version 4.2.1.1 (Debian 4.2.1-12.1 20031003005825) - // (protocol Version 11, revision 0, vendor release 6600) - // But not on mine? It's wonky. Put back to the same coords. - // was width-2, 1 in the second drawline - // Perhaps some X versions don't draw the endpoint? - // Mine: - // XFree86 Version 4.3.0.1 (Debian 4.3.0.dfsg.1-1 20040428170728) - // (X Protocol Version 11, Revision 0, Release 6.6) + // if it's odd and we're centring, we need to add one + int oddW = width()%2; + int oddH = height()%2; + + bool is_pressed = pressed(); + if (is_pressed && overrode_pressed) + return; + if (!is_pressed && overrode_bg) + return; + if (gc() == 0) + return; + // otherwise draw old style imagery + switch (m_type) { + case MAXIMIZE: + // if no pixmap was used, use old style + if (gc() == 0) // must have valid graphic context + return; - drawLine(gc(), - 2, height() - 3, - width() - 3, 2); + drawRectangle(gc(), + 2, 2, width() - 5, height() - 5); + drawLine(gc(), + 2, 3, width() - 3, 3); + break; + case MINIMIZE: + FbTk::FbWindow::drawRectangle(gc(), + 2, height() - 5, width() - 5, 2); + break; + case STICK: + // width/4 != width/2, so we use /4*2 so that it's properly centred + if (m_listen_to.isStuck()) { + fillRectangle(gc(), + width()/2 - width()/4, height()/2 - height()/4, + width()/4*2 + oddW, height()/4*2 + oddH); + } else { + fillRectangle(gc(), + width()/2 - width()/10, height()/2 - height()/10, + width()/10*2 + oddW, height()/10*2 + oddH); } break; + case CLOSE: + drawLine(gc(), + 2, 2, + width() - 3, height() - 3); + // I can't figure out why this second one needs a y offset of 1????? + // but it does - at least on my box: + // XFree86 Version 4.2.1.1 (Debian 4.2.1-12.1 20031003005825) + // (protocol Version 11, revision 0, vendor release 6600) + // But not on mine? It's wonky. Put back to the same coords. + // was width-2, 1 in the second drawline + // Perhaps some X versions don't draw the endpoint? + // Mine: + // XFree86 Version 4.3.0.1 (Debian 4.3.0.dfsg.1-1 20040428170728) + // (X Protocol Version 11, Revision 0, Release 6.6) + + drawLine(gc(), + 2, height() - 3, + width() - 3, 2); + break; case SHADE: - - if (pressed()) { - if (m_theme.shadePressedPixmap().pixmap().drawable()) { - FbTk::FbWindow::setBackgroundPixmap(m_theme. - shadePressedPixmap(). - pixmap().drawable()); - used = true; - } - } else { // not pressed - // check focus - if (!m_listen_to.isFocused()) { - if ( m_theme.shadeUnfocusPixmap().pixmap().drawable() != 0) { - // not focused - FbTk::FbWindow::setBackgroundPixmap(m_theme. - shadeUnfocusPixmap(). - pixmap().drawable()); - used = true; - } - } else if (m_theme.shadePixmap().pixmap().drawable() != 0) { // focused - FbTk::FbWindow::setBackgroundPixmap(m_theme. - shadePixmap(). - pixmap().drawable()); - used = true; - } - } - - if (used || clear) - FbTk::FbWindow::clear(); - + // no cute image defined break; } - // if ((used || clear) && !no_trans) - updateTransparent(); } void WinButton::clear() { - drawType(true, true); + FbTk::Button::clear(); + drawType(); } void WinButton::update(FbTk::Subject *subj) { diff --git a/src/WinButton.hh b/src/WinButton.hh index eb3ccad..e0036af 100644 --- a/src/WinButton.hh +++ b/src/WinButton.hh @@ -27,6 +27,10 @@ class FluxboxWindow; class WinButtonTheme; +namespace FbTk{ +class Color; +} + /// draws and handles basic window button graphic class WinButton:public FbTk::Button, public FbTk::Observer { public: @@ -39,13 +43,20 @@ public: /// override for drawing void exposeEvent(XExposeEvent &event); void buttonReleaseEvent(XButtonEvent &event); + void setBackgroundPixmap(Pixmap pm); + void setPressedPixmap(Pixmap pm); + void setBackgroundColor(const FbTk::Color &color); + void setPressedColor(const FbTk::Color &color); + + Pixmap getBackgroundPixmap() const; + Pixmap getPressedPixmap() const; /// override for redrawing void clear(); void update(FbTk::Subject *subj); private: - void drawType(bool clear, bool no_trans); // don't update transparency (eg in clear) + void drawType(); Type m_type; ///< the button type const FluxboxWindow &m_listen_to; WinButtonTheme &m_theme; - + bool overrode_bg, overrode_pressed; }; diff --git a/src/WinClient.cc b/src/WinClient.cc index fce858b..97f9082 100644 --- a/src/WinClient.cc +++ b/src/WinClient.cc @@ -358,7 +358,7 @@ void WinClient::updateIconTitle() { void WinClient::saveBlackboxAttribs(FluxboxWindow::BlackboxAttributes &blackbox_attribs) { changeProperty(FbAtoms::instance()->getFluxboxAttributesAtom(), - PropModeReplace, XA_CARDINAL, 32, + XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&blackbox_attribs, FluxboxWindow::PropBlackboxAttributesElements ); diff --git a/src/Window.cc b/src/Window.cc index e1fea07..1914195 100644 --- a/src/Window.cc +++ b/src/Window.cc @@ -1194,7 +1194,6 @@ void FluxboxWindow::reconfigure() { grabButtons(); frame().setDoubleClickTime(Fluxbox::instance()->getDoubleClickInterval()); - frame().setUpdateDelayTime(Fluxbox::instance()->getUpdateDelayTime()); frame().reconfigure(); @@ -1210,7 +1209,7 @@ void FluxboxWindow::updateTitleFromClient(WinClient &client) { if (m_labelbuttons[&client]->text() != client.title()) { m_labelbuttons[&client]->setText(client.title()); m_labelbuttons[&client]->clear(); // redraw text - m_labelbuttons[&client]->updateTransparent(); + //m_labelbuttons[&client]->updateTransparent(); } } @@ -1341,8 +1340,9 @@ void FluxboxWindow::resize(unsigned int width, unsigned int height) { moveResize(frame().x(), frame().y(), width, height); } +// send_event is just an override void FluxboxWindow::moveResize(int new_x, int new_y, - unsigned int new_width, unsigned int new_height, int gravity) { + unsigned int new_width, unsigned int new_height, int gravity, bool send_event) { // magic to detect if moved during initialisation if (!isInitialized()) @@ -1352,7 +1352,7 @@ void FluxboxWindow::moveResize(int new_x, int new_y, frame().gravityTranslate(new_x, new_y, gravity, false); } - bool send_event = (frame().x() != new_x || frame().y() != new_y); + send_event = send_event || (frame().x() != new_x || frame().y() != new_y); if (new_width != frame().width() || new_height != frame().height()) { if ((((signed) frame().width()) + new_x) < 0) @@ -1368,7 +1368,6 @@ void FluxboxWindow::moveResize(int new_x, int new_y, frame().moveResize(new_x, new_y, new_width, new_height); setFocusFlag(focused); - shaded = false; send_event = true; } else if (send_event) @@ -2848,7 +2847,9 @@ void FluxboxWindow::motionNotifyEvent(XMotionEvent &me) { m_last_move_x = dx; m_last_move_y = dy; } else { - moveResize(dx, dy, frame().width(), frame().height()); + //moveResize(dx, dy, frame().width(), frame().height()); + // need to move the base window without interfering with transparency + frame().window().moveResize(dx, dy, frame().width(), frame().height()); } screen().showPosition(dx, dy); @@ -3216,7 +3217,6 @@ void FluxboxWindow::stopMoving(bool interrupted) { fluxbox->maskWindowEvents(0, 0); - if (! screen().doOpaqueMove()) { parent().drawRectangle(screen().rootTheme().opGC(), m_last_move_x, m_last_move_y, @@ -3231,8 +3231,8 @@ void FluxboxWindow::stopMoving(bool interrupted) { } fluxbox->ungrab(); } else if (!interrupted) { - moveResize(frame().x(), frame().y(), frame().width(), frame().height()); - sendConfigureNotify(); + moveResize(frame().x(), frame().y(), frame().width(), frame().height(), ForgetGravity, true); + frame().notifyMoved(true); } diff --git a/src/Window.hh b/src/Window.hh index f4a038a..53b6041 100644 --- a/src/Window.hh +++ b/src/Window.hh @@ -232,7 +232,7 @@ public: /// resize frame to width, height void resize(unsigned int width, unsigned int height); /// move and resize frame to pox x,y and size width, height - void moveResize(int x, int y, unsigned int width, unsigned int height, int gravity = ForgetGravity); + void moveResize(int x, int y, unsigned int width, unsigned int height, int gravity = ForgetGravity, bool send_event = false); /// move to pos x,y and resize client window to size width, height void moveResizeForClient(int x, int y, unsigned int width, unsigned int height, int gravity = ForgetGravity); void setWorkspace(int n); diff --git a/src/fluxbox.cc b/src/fluxbox.cc index ede9a5a..dcc947a 100644 --- a/src/fluxbox.cc +++ b/src/fluxbox.cc @@ -200,7 +200,6 @@ Fluxbox::Fluxbox(int argc, char **argv, const char *dpy_name, const char *rcfile "session.colorsPerChannel", "Session.ColorsPerChannel"), m_rc_numlayers(m_resourcemanager, 13, "session.numLayers", "Session.NumLayers"), m_rc_double_click_interval(m_resourcemanager, 250, "session.doubleClickInterval", "Session.DoubleClickInterval"), - m_rc_update_delay_time(m_resourcemanager, 0, "session.updateDelayTime", "Session.UpdateDelayTime"), m_rc_stylefile(m_resourcemanager, DEFAULTSTYLE, "session.styleFile", "Session.StyleFile"), m_rc_menufile(m_resourcemanager, DEFAULTMENU, "session.menuFile", "Session.MenuFile"), m_rc_keyfile(m_resourcemanager, DEFAULTKEYSFILE, "session.keyFile", "Session.KeyFile"), @@ -278,7 +277,7 @@ Fluxbox::Fluxbox(int argc, char **argv, const char *dpy_name, const char *rcfile m_reconfig_timer.setTimeout(to); m_reconfig_timer.setCommand(reconfig_cmd); m_reconfig_timer.fireOnce(true); - //XSynchronize(disp, True); +// XSynchronize(disp, True); s_singleton = this; m_have_shape = false; @@ -377,8 +376,7 @@ Fluxbox::Fluxbox(int argc, char **argv, const char *dpy_name, const char *rcfile // setup theme manager to have our style file ready to be scanned FbTk::ThemeManager::instance().load(FbTk::StringUtil::expandFilename(getStyleFilename())); - XSynchronize(disp, False); - //XSynchronize(disp, True); + //XSynchronize(disp, False); sync(false); m_reconfigure_wait = m_reread_menu_wait = false; @@ -1854,7 +1852,6 @@ void Fluxbox::setFocusedWindow(WinClient *client) { m_focused_window = 0; - if (screen != 0) { screen->updateNetizenWindowFocus(); for (AtomHandlerContainerIt it= m_atomhandler.begin(); @@ -1871,7 +1868,6 @@ void Fluxbox::setFocusedWindow(WinClient *client) { it != m_atomhandler.end(); it++) (*it).first->updateFocusedWindow(*old_screen, 0); } - } /** diff --git a/src/fluxbox.hh b/src/fluxbox.hh index 17d9124..a995bd5 100644 --- a/src/fluxbox.hh +++ b/src/fluxbox.hh @@ -102,7 +102,6 @@ public: BScreen *searchScreen(Window w); inline unsigned int getDoubleClickInterval() const { return *m_rc_double_click_interval; } - inline unsigned int getUpdateDelayTime() const { return *m_rc_update_delay_time; } inline Time getLastTime() const { return m_last_time; } AtomHandler *getAtomHandler(const std::string &name); @@ -260,7 +259,7 @@ private: FbTk::Resource m_rc_tabs, m_rc_ignoreborder; FbTk::Resource m_rc_pseudotrans; FbTk::Resource m_rc_colors_per_channel, m_rc_numlayers, - m_rc_double_click_interval, m_rc_update_delay_time, + m_rc_double_click_interval, m_rc_tabs_padding, m_rc_focused_tab_min_width; FbTk::Resource m_rc_stylefile, -- cgit v0.11.2