news download themes documentation links










FbWinFrame.cc

00001 // FbWinFrame.cc for Fluxbox Window Manager
00002 // Copyright (c) 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net)
00003 //
00004 // Permission is hereby granted, free of charge, to any person obtaining a
00005 // copy of this software and associated documentation files (the "Software"),
00006 // to deal in the Software without restriction, including without limitation
00007 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
00008 // and/or sell copies of the Software, and to permit persons to whom the
00009 // Software is furnished to do so, subject to the following conditions:
00010 //
00011 // The above copyright notice and this permission notice shall be included in
00012 // all copies or substantial portions of the Software.
00013 //
00014 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
00017 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00018 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00019 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00020 // DEALINGS IN THE SOFTWARE.
00021 
00022 // $Id: FbWinFrame.cc,v 1.70 2004/01/10 20:22:05 rathnor Exp $
00023 
00024 #include "FbWinFrame.hh"
00025 
00026 #include "FbTk/ImageControl.hh"
00027 #include "FbTk/EventManager.hh"
00028 #include "FbTk/TextButton.hh"
00029 #include "FbTk/App.hh"
00030 #include "FbTk/Compose.hh"
00031 #include "FbTk/SimpleCommand.hh"
00032 
00033 #include "FbWinFrameTheme.hh"
00034 #ifdef SHAPE
00035 #include "Shape.hh"
00036 #endif // SHAPE
00037 
00038 
00039 #include <algorithm>
00040 #include <iostream>
00041 #include <X11/X.h>
00042 
00043 using namespace std;
00044 
00045 FbWinFrame::FbWinFrame(FbWinFrameTheme &theme, FbTk::ImageControl &imgctrl, 
00046                        int x, int y,
00047                        unsigned int width, unsigned int height):
00048     m_theme(theme),
00049     m_imagectrl(imgctrl),
00050     m_window(theme.screenNum(), x, y, width, height,  ButtonPressMask | ButtonReleaseMask |
00051              ButtonMotionMask | EnterWindowMask, true),
00052     m_titlebar(m_window, 0, 0, 100, 16, 
00053                ButtonPressMask | ButtonReleaseMask |
00054                ButtonMotionMask | ExposureMask |
00055                EnterWindowMask | LeaveWindowMask),
00056     m_label(m_titlebar, 0, 0, 100, 16,
00057         ButtonPressMask | ButtonReleaseMask |
00058             ButtonMotionMask | ExposureMask |
00059             EnterWindowMask | LeaveWindowMask),
00060     m_handle(m_window, 0, 0, 100, 5,
00061              ButtonPressMask | ButtonReleaseMask |
00062              ButtonMotionMask | ExposureMask |
00063              EnterWindowMask | LeaveWindowMask),
00064     m_grip_right(m_handle, 0, 0, 10, 4,
00065                  ButtonPressMask | ButtonReleaseMask |
00066                  ButtonMotionMask | ExposureMask |
00067                  EnterWindowMask | LeaveWindowMask),
00068     m_grip_left(m_handle, 0, 0, 10, 4,
00069         ButtonPressMask | ButtonReleaseMask |
00070         ButtonMotionMask | ExposureMask |
00071         EnterWindowMask | LeaveWindowMask),
00072     m_clientarea(m_window, 0, 0, 100, 100,
00073                  ButtonPressMask | ButtonReleaseMask |
00074                  ButtonMotionMask | ExposureMask |
00075                  EnterWindowMask | LeaveWindowMask),
00076     m_bevel(1),
00077     m_use_titlebar(true), 
00078     m_use_handle(true),
00079     m_focused(false),
00080     m_visible(false),
00081     m_button_pm(0),
00082     m_themelistener(*this),
00083     m_shape(new Shape(m_window, theme.shapePlace())) {
00084     m_theme.reconfigSig().attach(&m_themelistener);
00085     init();
00086 }
00087 
00088 /*
00089   FbWinFrame::FbWinFrame(FbWinFrameTheme &theme, FbTk::ImageControl &imgctrl, const FbTk::FbWindow &parent, int x, int y,
00090   unsigned int width, unsigned int height):
00091   m_theme(theme),
00092   m_imagectrl(imgctrl),
00093   m_window(parent, x, y, width, height, ExposureMask | StructureNotifyMask),
00094   m_titlebar(m_window, 0, 0, 100, 16, 
00095   ExposureMask | ButtonPressMask | ButtonReleaseMask),
00096   m_label(m_titlebar, 0, 0, 100, 16,
00097   ExposureMask | ButtonPressMask | ButtonReleaseMask),
00098   m_grip_right(m_window, 0, 0, 100, 100, ExposureMask | ButtonPressMask | ButtonReleaseMask),
00099   m_grip_left(m_window, 0, 0, 100, 100, ExposureMask | ButtonPressMask | ButtonReleaseMask),
00100   m_handle(m_window, 0, 0, 100, 100, ExposureMask | ButtonPressMask | ButtonReleaseMask),
00101   m_clientarea(m_window, 0, 0, 100, 100, SubstructureRedirectMask),
00102   m_bevel(1),
00103   m_use_titlebar(true), 
00104   m_use_handles(true),
00105   m_button_pm(0) {
00106 
00107   init();
00108   }
00109 */
00110 
00111 FbWinFrame::~FbWinFrame() {
00112     m_update_timer.stop();
00113     removeEventHandler();
00114     removeAllButtons();
00115 }
00116 
00117 bool FbWinFrame::setOnClickTitlebar(FbTk::RefCount<FbTk::Command> &ref, int mousebutton_num, 
00118                             bool double_click, bool pressed) {
00119     // find mousebutton_num
00120     if (mousebutton_num < 1 || mousebutton_num > 5)
00121         return false;
00122     if (double_click)
00123         m_commands[mousebutton_num - 1].double_click = ref;
00124     else {
00125         if (pressed)
00126             m_commands[mousebutton_num - 1].click_pressed = ref;
00127         else
00128             m_commands[mousebutton_num - 1].click = ref;
00129     }
00130 
00131     return true;
00132 }
00133 
00134 void FbWinFrame::hide() {
00135     m_window.hide();
00136     m_visible = false;
00137 }
00138 
00139 void FbWinFrame::show() {
00140     m_visible = true;
00141     m_window.showSubwindows();
00142     m_window.show();
00143 }
00144 
00148 void FbWinFrame::shade() {
00149     if (!m_use_titlebar)
00150         return;
00151 
00152     // toggle shade
00153     m_shaded = !m_shaded;
00154     if (m_shaded) { // i.e. should be shaded now
00155         m_width_before_shade = m_window.width();
00156         m_height_before_shade = m_window.height();
00157         m_window.resize(m_window.width(), m_titlebar.height());
00158     } else { // should be unshaded
00159         m_window.resize(m_width_before_shade, m_height_before_shade);
00160         reconfigure();
00161     }
00162 }
00163 
00164 
00165 void FbWinFrame::move(int x, int y) {
00166     moveResize(x, y, 0, 0, true, false);
00167 }
00168 
00169 void FbWinFrame::resize(unsigned int width, unsigned int height) {
00170     moveResize(0, 0, width, height, false, true);
00171 }
00172 
00173 // need an atomic moveresize where possible
00174 void FbWinFrame::moveResizeForClient(int x, int y, unsigned int width, unsigned int height, bool move, bool resize) {
00175     // total height for frame
00176 
00177     unsigned int total_height = height;
00178 
00179     if (resize) {
00180         // having a titlebar = 1 extra border + titlebar height
00181         if (m_use_titlebar)
00182             total_height += m_titlebar.height() + m_titlebar.borderWidth();
00183         // having a handle = 1 extra border + handle height
00184         if (m_use_handle)
00185             total_height += m_handle.height() + m_handle.borderWidth();
00186     }
00187     moveResize(x, y, width, total_height, move, resize);
00188 }
00189 
00190 void FbWinFrame::resizeForClient(unsigned int width, unsigned int height) {
00191     moveResizeForClient(0, 0, width, height, false, true);
00192 }
00193 
00194 void FbWinFrame::moveResize(int x, int y, unsigned int width, unsigned int height, bool move, bool resize) {
00195     if (move && x == window().x() && y == window().y()) 
00196         move = false;
00197 
00198     if (resize && width == FbWinFrame::width() && height == FbWinFrame::height()) 
00199         resize = false;
00200 
00201     if (!move && !resize)
00202         return;
00203 
00204     if (resize && m_shaded) {
00205         // update unshaded size if  we're in shaded state and just resize width
00206         m_width_before_shade = width;
00207         m_height_before_shade = height;
00208         height = m_window.height();
00209     }
00210 
00211     if (move && resize) {
00212         m_window.moveResize(x, y, width, height);
00213     } else if (move) {
00214         m_window.move(x, y);
00215         // this stuff will be caught by reconfigure if resized
00216         if (theme().alpha() != 255) {
00217             // restart update timer
00218             m_update_timer.start();
00219         }
00220     } else {
00221         m_window.resize(width, height);
00222     }
00223 
00224     if (resize)
00225         reconfigure();
00226 }
00227 
00228 void FbWinFrame::setFocus(bool newvalue) {
00229     if (m_focused == newvalue)
00230         return;
00231 
00232     m_focused = newvalue;
00233 
00234     if (currentLabel()) {
00235         if (newvalue) // focused
00236             renderButtonFocus(*m_current_label);       
00237         else // unfocused
00238             renderButtonActive(*m_current_label);
00239     }
00240 
00241     renderTitlebar();
00242     renderButtons(); // parent relative buttons -> need render after titlebar
00243     renderHandles();
00244 }
00245 
00246 void FbWinFrame::setDoubleClickTime(unsigned int time) {
00247     m_double_click_time = time;
00248 }
00249 
00250 void FbWinFrame::addLeftButton(FbTk::Button *btn) {
00251     if (btn == 0) // valid button?
00252         return;
00253 
00254     setupButton(*btn); // setup theme and other stuff
00255     
00256     m_buttons_left.push_back(btn);
00257 }
00258 
00259 void FbWinFrame::addRightButton(FbTk::Button *btn) {
00260     if (btn == 0) // valid button?
00261         return;
00262 
00263     setupButton(*btn); // setup theme and other stuff
00264 
00265     m_buttons_right.push_back(btn);
00266 }
00267 
00268 void FbWinFrame::removeAllButtons() {
00269     // destroy left side
00270     while (!m_buttons_left.empty()) {
00271         delete m_buttons_left.back();
00272         m_buttons_left.pop_back();
00273     }
00274     // destroy right side
00275     while (!m_buttons_right.empty()) {
00276         delete m_buttons_right.back();
00277         m_buttons_right.pop_back();
00278     }
00279 }
00280 
00281 void FbWinFrame::addLabelButton(FbTk::TextButton &btn) {
00282     LabelList::iterator found_it = find(m_labelbuttons.begin(),
00283                                         m_labelbuttons.end(),
00284                                         &btn);
00285     
00286     if (found_it != m_labelbuttons.end())
00287         return;
00288     
00289     m_labelbuttons.push_back(&btn);
00290 
00291     if (currentLabel() == 0)
00292         setLabelButtonFocus(btn);
00293 }
00294 
00295 void FbWinFrame::removeLabelButton(FbTk::TextButton &btn) {
00296     LabelList::iterator erase_it = remove(m_labelbuttons.begin(),
00297                                           m_labelbuttons.end(),
00298                                           &btn);
00299     if (erase_it == m_labelbuttons.end())
00300         return;
00301 
00302     m_labelbuttons.erase(erase_it);
00303 
00304     if (*erase_it == m_current_label)
00305         m_current_label = 0;
00306 }
00307 
00308 
00309 void FbWinFrame::moveLabelButtonLeft(const FbTk::TextButton &btn) {
00310     LabelList::iterator it = find(m_labelbuttons.begin(),
00311                                   m_labelbuttons.end(),
00312                                   &btn);
00313     // make sure we found it and we're not at the begining
00314     if (it == m_labelbuttons.end() || it == m_labelbuttons.begin())
00315         return;
00316 
00317     LabelList::iterator new_pos = it;
00318     new_pos--;
00319     FbTk::TextButton *item = *it;
00320     // remove from list
00321     m_labelbuttons.erase(it); 
00322     // insert on the new place
00323     m_labelbuttons.insert(new_pos, item);
00324     // update titlebar
00325     redrawTitle();
00326 }
00327 
00328 void FbWinFrame::moveLabelButtonRight(const FbTk::TextButton &btn) {
00329     LabelList::iterator it = find(m_labelbuttons.begin(),
00330                                   m_labelbuttons.end(),
00331                                   &btn);
00332     // make sure we found it and we're not at the last item
00333     if (it == m_labelbuttons.end() || *it == m_labelbuttons.back())
00334         return;
00335 
00336     FbTk::TextButton *item = *it;
00337     // remove from list
00338     LabelList::iterator new_pos = m_labelbuttons.erase(it); 
00339     new_pos++;
00340     // insert on the new place
00341     m_labelbuttons.insert(new_pos, item);
00342     // update titlebar
00343     redrawTitle();
00344 }
00345 
00346 void FbWinFrame::setLabelButtonFocus(FbTk::TextButton &btn) {
00347     if (&btn == currentLabel())
00348         return;
00349     LabelList::iterator it = find(m_labelbuttons.begin(),
00350                                   m_labelbuttons.end(),
00351                                   &btn);
00352     if (it == m_labelbuttons.end())
00353         return;
00354 
00355     // render label buttons
00356     if (currentLabel() != 0)
00357         renderButtonUnfocus(*m_current_label);
00358 
00359     m_current_label = *it; // current focused button
00360 
00361     if (m_focused)
00362         renderButtonFocus(*m_current_label);
00363     else
00364         renderButtonActive(*m_current_label);
00365 }
00366 
00367 void FbWinFrame::setClientWindow(FbTk::FbWindow &win) {
00368 
00369     Display *display = FbTk::App::instance()->display();
00370 
00371     win.setBorderWidth(0);
00372 
00373     XChangeSaveSet(display, win.window(), SetModeInsert);
00374 
00375     m_window.setEventMask(NoEventMask);
00376 
00377     // we need to mask this so we don't get unmap event
00378     win.setEventMask(NoEventMask);
00379     win.reparent(m_window, 0, clientArea().y());
00380     // remask window so we get events
00381     win.setEventMask(PropertyChangeMask | StructureNotifyMask | 
00382                      FocusChangeMask);
00383 
00384     m_window.setEventMask(ButtonPressMask | ButtonReleaseMask |
00385                           ButtonMotionMask | EnterWindowMask | SubstructureRedirectMask);
00386 
00387     XFlush(display);
00388 
00389     XSetWindowAttributes attrib_set;
00390     attrib_set.event_mask = PropertyChangeMask | StructureNotifyMask | FocusChangeMask;
00391     attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask | 
00392         ButtonMotionMask;
00393 
00394     XChangeWindowAttributes(display, win.window(), CWEventMask|CWDontPropagate, &attrib_set);
00395 
00396     m_clientarea.raise();
00397     win.raise();
00398     m_window.showSubwindows();
00399 }
00400 
00401 bool FbWinFrame::hideTitlebar() {
00402     if (!m_use_titlebar)
00403         return false;
00404 
00405     m_titlebar.hide();
00406     m_use_titlebar = false;
00407 
00408     // only take away one borderwidth (as the other border is still the "top" border)
00409     m_window.resize(m_window.width(), m_window.height() - m_titlebar.height() -
00410                     m_titlebar.borderWidth());
00411     return true;
00412 }
00413 
00414 bool FbWinFrame::showTitlebar() {
00415     if (m_use_titlebar)
00416         return false;
00417 
00418     m_titlebar.show();
00419     m_use_titlebar = true;
00420 
00421     // only add one borderwidth (as the other border is still the "top" border)
00422     m_window.resize(m_window.width(), m_window.height() + m_titlebar.height() +
00423                     m_titlebar.borderWidth());
00424     return true;
00425 
00426 }
00427 
00428 bool FbWinFrame::hideHandle() {
00429     if (!m_use_handle)
00430         return false;
00431     m_handle.hide();
00432     m_grip_left.hide();
00433     m_grip_right.hide();
00434     m_use_handle = false;
00435     m_window.resize(m_window.width(), m_window.height() - m_handle.height() -
00436                     m_handle.borderWidth());
00437     return true;
00438 
00439 }
00440 
00441 bool FbWinFrame::showHandle() {
00442     if (m_use_handle || theme().handleWidth() == 0)
00443         return false;
00444 
00445     m_handle.show();
00446     m_handle.showSubwindows(); // shows grips
00447 
00448     m_use_handle = true;
00449     m_window.resize(m_window.width(), m_window.height() + m_handle.height() +
00450                     m_handle.borderWidth());
00451     return true;
00452 }
00453 
00454 bool FbWinFrame::hideAllDecorations() {
00455     bool changed = false;
00456     changed |= hideHandle();
00457     changed |= hideTitlebar();
00458     // resize done by hide*
00459     reconfigure();
00460 
00461     return changed;
00462 }
00463 
00464 bool FbWinFrame::showAllDecorations() {
00465     bool changed = false;
00466     if (!m_use_handle)
00467         changed |= showHandle();
00468     if (!m_use_titlebar)
00469         changed |= showTitlebar();
00470     // resize shouldn't be necessary
00471     reconfigure();
00472 
00473     return changed;
00474 }
00475 
00479 void FbWinFrame::setEventHandler(FbTk::EventHandler &evh) {
00480 
00481     FbTk::EventManager &evm = *FbTk::EventManager::instance();
00482     evm.add(evh, m_label);
00483     evm.add(evh, m_titlebar);
00484     evm.add(evh, m_handle);
00485     evm.add(evh, m_grip_right);
00486     evm.add(evh, m_grip_left);
00487     evm.add(evh, m_window);
00488     evm.add(evh, m_clientarea);
00489 }
00490 
00494 void FbWinFrame::removeEventHandler() {
00495     FbTk::EventManager &evm = *FbTk::EventManager::instance();
00496     evm.remove(m_label);
00497     evm.remove(m_titlebar);
00498     evm.remove(m_handle);
00499     evm.remove(m_grip_right);
00500     evm.remove(m_grip_left);
00501     evm.remove(m_window);
00502     evm.remove(m_clientarea);
00503 }
00504 
00505 void FbWinFrame::buttonPressEvent(XButtonEvent &event) {
00506     // we can ignore which window the event was generated for
00507     LabelList::iterator btn_it = m_labelbuttons.begin();
00508     LabelList::iterator btn_it_end = m_labelbuttons.end();
00509     for (; btn_it != btn_it_end; ++btn_it) {
00510         if ((*btn_it)->window() == event.window) {
00511             (*btn_it)->buttonPressEvent(event);
00512             break;
00513         }
00514     }
00515     if (event.window == m_grip_right.window() ||
00516         event.window == m_grip_left.window() ||
00517         event.window == m_clientarea.window() ||
00518         event.window == m_handle.window() ||
00519         event.window == m_window.window())
00520         return;
00521     // we handle only buttons 0 to 5
00522     if (event.button > 5 || event.button < 1)
00523         return;
00524 
00525     if (*m_commands[event.button - 1].click_pressed)
00526         m_commands[event.button - 1].click_pressed->execute();
00527 }
00528 
00529 void FbWinFrame::buttonReleaseEvent(XButtonEvent &event) {
00530     // we can ignore which window the event was generated for
00531     
00532     LabelList::iterator button_it = find_if(m_labelbuttons.begin(),
00533                                             m_labelbuttons.end(),
00534                                             FbTk::Compose(bind2nd(equal_to<Window>(), event.window),
00535                                                           mem_fun(&FbTk::Button::window)));
00536     if (button_it != m_labelbuttons.end())
00537         (*button_it)->buttonReleaseEvent(event);
00538 
00539 
00540     if (event.window == m_grip_right.window() ||
00541         event.window == m_grip_left.window() ||
00542         event.window == m_clientarea.window() ||
00543         event.window == m_handle.window() ||
00544         event.window == m_window.window())
00545         return;
00546 
00547     if (event.button < 1 || event.button > 5)
00548         return;
00549 
00550     static int last_release_time = 0;
00551     bool double_click = (event.time - last_release_time <= m_double_click_time);
00552     last_release_time = event.time;
00553     int real_button = event.button - 1;
00554     
00555     if (double_click && *m_commands[real_button].double_click)
00556         m_commands[real_button].double_click->execute();
00557     else if (*m_commands[real_button].click)
00558         m_commands[real_button].click->execute();
00559 
00560 }
00561 
00562 void FbWinFrame::exposeEvent(XExposeEvent &event) {
00563     if (m_titlebar == event.window) {
00564         m_titlebar.clearArea(event.x, event.y, event.width, event.height);
00565         m_titlebar.updateTransparent(event.x, event.y, event.width, event.height);
00566     } else if (m_label == event.window) {
00567         m_label.clearArea(event.x, event.y, event.width, event.height);
00568         m_label.updateTransparent(event.x, event.y, event.width, event.height);
00569     } else if (m_handle == event.window) {
00570         m_handle.clearArea(event.x, event.y, event.width, event.height);
00571         m_handle.updateTransparent(event.x, event.y, event.width, event.height);
00572     } else if (m_grip_left == event.window) {
00573         m_grip_left.clearArea(event.x, event.y, event.width, event.height);
00574         m_grip_left.updateTransparent(event.x, event.y, event.width, event.height);
00575     } else if (m_grip_right == event.window) {
00576         m_grip_right.clearArea(event.x, event.y, event.width, event.height);
00577         m_grip_right.updateTransparent(event.x, event.y, event.width, event.height);
00578     } else {
00579         // create compare function
00580         // that we should use with find_if
00581         FbTk::Compose_base<std::binder2nd<std::equal_to<Window> >,
00582             std::const_mem_fun_t<Window, FbTk::FbWindow> > 
00583             compare = FbTk::Compose(bind2nd(equal_to<Window>(), event.window),
00584                                     mem_fun(&FbTk::Button::window));
00585 
00586         LabelList::iterator btn_it = find_if(m_labelbuttons.begin(),
00587                                              m_labelbuttons.end(),
00588                                              compare);
00589         if (btn_it != m_labelbuttons.end()) {
00590             (*btn_it)->exposeEvent(event);
00591             return;
00592         }
00593 
00594         ButtonList::iterator it = find_if(m_buttons_left.begin(),
00595                                           m_buttons_left.end(),
00596                                           compare);
00597         if (it != m_buttons_left.end()) {
00598             (*it)->exposeEvent(event);
00599             return;
00600         }
00601 
00602         it = find_if(m_buttons_right.begin(),
00603                      m_buttons_right.end(),
00604                      compare);
00605 
00606         if (it != m_buttons_right.end())
00607             (*it)->exposeEvent(event);
00608     }
00609 
00610 }
00611 
00612 void FbWinFrame::handleEvent(XEvent &event) {
00613     if (event.type == ConfigureNotify && event.xconfigure.window == window().window())
00614         configureNotifyEvent(event.xconfigure);
00615 }
00616 
00617 void FbWinFrame::configureNotifyEvent(XConfigureEvent &event) {
00618     resize(event.width, event.height);
00619 }
00620 
00621 void FbWinFrame::reconfigure() {
00622     if (m_labelbuttons.size() == 0)
00623         return;
00624 
00625     m_bevel = theme().bevelWidth();
00626 
00627     handle().resize(handle().width(), 
00628                     theme().handleWidth());
00629     gripLeft().resize(buttonHeight(), 
00630                       theme().handleWidth());
00631     gripRight().resize(gripLeft().width(), 
00632                        gripLeft().height());
00633 
00634     // align titlebar and render it
00635     if (m_use_titlebar) {
00636         reconfigureTitlebar();
00637         m_titlebar.raise();
00638     } else 
00639         m_titlebar.lower();
00640 
00641 
00642     // leave client+grips alone if we're shaded (it'll get fixed when we unshade)
00643     if (!m_shaded) {
00644         int client_top = 0;
00645         int client_height = m_window.height();
00646         if (m_use_titlebar) {
00647             // only one borderwidth as titlebar is really at -borderwidth
00648             int titlebar_height = m_titlebar.height() + m_titlebar.borderWidth();
00649             client_top += titlebar_height;
00650             client_height -= titlebar_height;
00651         }
00652         
00653         if (m_use_handle) {
00654             // align handle and grips
00655             const int grip_height = m_handle.height();
00656             const int grip_width = 20; //TODO
00657             const int handle_bw = static_cast<signed>(m_handle.borderWidth());
00658 
00659             const int ypos = m_window.height() - grip_height - m_handle.borderWidth();
00660             m_handle.moveResize(-handle_bw, ypos,
00661                                 m_window.width(), grip_height);
00662         
00663             m_grip_left.moveResize(-handle_bw, -handle_bw,
00664                                    grip_width, grip_height);
00665 
00666             m_grip_right.moveResize(m_handle.width() - grip_width - handle_bw, -handle_bw,
00667                                     grip_width, grip_height);
00668             m_handle.raise();
00669 
00670             client_height -= m_handle.height() + m_handle.borderWidth();
00671 
00672         } else {
00673             m_handle.lower();
00674         }
00675 
00676         m_clientarea.moveResize(0, client_top,
00677                                 m_window.width(), client_height);
00678         
00679     }
00680 
00681 
00682     // render the theme
00683     renderButtons();
00684     if (!m_shaded)
00685         renderHandles();
00686 
00687     if (m_shape.get() && theme().shapePlace() == Shape::NONE  || m_disable_shape)
00688         m_shape.reset(0);
00689     else if (m_shape.get() == 0 && theme().shapePlace() != Shape::NONE)
00690         m_shape.reset(new Shape(window(), theme().shapePlace()));
00691     else if (m_shape.get())
00692         m_shape->setPlaces(theme().shapePlace());
00693 
00694     if (m_shape.get())
00695         m_shape->update();
00696 
00697     // titlebar stuff rendered already by reconftitlebar
00698 
00699 }
00700 
00701 void FbWinFrame::setUseShape(bool value) {
00702     m_disable_shape = !value;
00703 
00704     if (m_shape.get() && m_disable_shape)
00705         m_shape.reset(0);
00706     else if (m_shape.get() == 0 && !m_disable_shape)
00707         m_shape.reset(new Shape(window(), theme().shapePlace()));
00708 }
00709 
00710 unsigned int FbWinFrame::buttonHeight() const {
00711     return m_titlebar.height() - m_bevel*2;
00712 }
00713 
00714 //--------------------- private area
00715 
00719 void FbWinFrame::redrawTitle() {
00720     if (m_labelbuttons.size() == 0)
00721         return;
00722 
00723     int button_width = label().width()/m_labelbuttons.size();
00724     int rounding_error = label().width() - m_labelbuttons.size()*button_width;
00726     //int border_width = m_labelbuttons.front()->window().borderWidth();
00727     int border_width =  m_labelbuttons.size() != 0 ?
00728         m_labelbuttons.front()->borderWidth() : 0;
00729 
00730     LabelList::iterator btn_it = m_labelbuttons.begin();
00731     LabelList::iterator btn_it_end = m_labelbuttons.end();
00732     int extra = 0;
00733     for (unsigned int last_x = 0;
00734          btn_it != btn_it_end; 
00735          ++btn_it, last_x += button_width + border_width + extra) {
00736         // since we add border width pixel we should remove
00737         // the same size for inside width so we can fit all buttons into label
00738         if (rounding_error != 0) {
00739             extra = 1;
00740             --rounding_error;
00741         } else
00742             extra = 0;
00743 
00744         (*btn_it)->moveResize(last_x - border_width, - border_width,
00745                               button_width + extra, 
00746                               label().height() + border_width);
00747         if (isVisible()) {
00748             (*btn_it)->clear();
00749             (*btn_it)->updateTransparent();
00750         }
00751     }
00752 
00753     if (isVisible()) {
00754         m_label.clear();
00755         m_label.updateTransparent();
00756         m_titlebar.clear();
00757         m_titlebar.updateTransparent();
00758     }
00759 }
00760 
00761 void FbWinFrame::redrawTitlebar() {
00762     if (!m_use_titlebar)
00763         return;
00764 
00765     redrawTitle();
00766 
00767  }
00768 
00772 void FbWinFrame::reconfigureTitlebar() {
00773     if (!m_use_titlebar)
00774         return;
00775 
00776     int orig_height = m_titlebar.height();
00777     // resize titlebar to window size with font height
00778     int title_height = m_theme.font().height() == 0 ? 16 : 
00779         m_theme.font().height() + m_bevel*2 + 2;
00780     if (m_theme.titleHeight() != 0)
00781         title_height = m_theme.titleHeight();
00782 
00783     // if the titlebar grows in size, make sure the whole window does too
00784     if (orig_height != title_height) 
00785         m_window.resize(m_window.width(), m_window.height()-orig_height+title_height);
00786     m_titlebar.moveResize(-m_titlebar.borderWidth(), -m_titlebar.borderWidth(),
00787                           m_window.width(), title_height);
00788 
00789     // draw left buttons first
00790     unsigned int next_x = m_bevel; 
00791     unsigned int button_size = buttonHeight();
00792     m_button_size = button_size;
00793     for (size_t i=0; i < m_buttons_left.size(); i++, next_x += button_size + m_bevel) {
00794         m_buttons_left[i]->moveResize(next_x, m_bevel, 
00795                                       button_size, button_size);
00796     }
00797     
00798     next_x += m_bevel;
00799     
00800     // space left on titlebar between left and right buttons
00801     unsigned int space_left = m_titlebar.width() - next_x;
00802     if (m_buttons_right.size() != 0)
00803         space_left -= m_buttons_right.size() * (button_size + m_bevel);
00804 
00805     space_left -= m_bevel;
00806     
00807     m_label.moveResize(next_x, m_bevel,
00808                        space_left, button_size);
00809 
00810     next_x += m_label.width() + m_bevel;;
00811 
00812     // finaly set new buttons to the right
00813     for (size_t i=0; i < m_buttons_right.size(); 
00814          ++i, next_x += button_size + m_bevel) {
00815         m_buttons_right[i]->moveResize(next_x, m_bevel,
00816                                        button_size, button_size);
00817     }
00818 
00819     renderTitlebar();
00820     m_titlebar.raise(); // always on top
00821 }
00822 
00823 void FbWinFrame::renderTitlebar() {
00824     if (!m_use_titlebar)
00825         return;
00826 
00827     // render pixmaps
00828     render(m_theme.titleFocusTexture(), m_title_focused_color, 
00829            m_title_focused_pm,
00830            m_titlebar.width(), m_titlebar.height());
00831 
00832     render(m_theme.titleUnfocusTexture(), m_title_unfocused_color, 
00833            m_title_unfocused_pm,
00834            m_titlebar.width(), m_titlebar.height());
00835 
00836 
00837     render(m_theme.labelFocusTexture(), m_label_focused_color, 
00838            m_label_focused_pm,
00839            m_label.width(), m_label.height());
00840         
00841 
00842     render(m_theme.labelUnfocusTexture(), m_label_unfocused_color, 
00843            m_label_unfocused_pm,
00844            m_label.width(), m_label.height());
00845 
00846     render(m_theme.labelActiveTexture(), m_label_active_color, 
00847            m_label_active_pm,
00848            m_label.width(), m_label.height());
00849 
00850 
00851     // finaly set up pixmaps for titlebar windows
00852     Pixmap label_pm = None;
00853     Pixmap title_pm = None;    
00854     FbTk::Color label_color;
00855     FbTk::Color title_color;
00856     getCurrentFocusPixmap(label_pm, title_pm,
00857                           label_color, title_color);
00858 
00859     if (label_pm != 0)
00860         m_label.setBackgroundPixmap(label_pm);
00861     else            
00862         m_label.setBackgroundColor(label_color);
00863     
00864     if (title_pm != 0)
00865         m_titlebar.setBackgroundPixmap(title_pm);
00866     else
00867         m_titlebar.setBackgroundColor(title_color);
00868 
00869     m_titlebar.setAlpha(theme().alpha());
00870     m_label.setAlpha(theme().alpha());
00871 
00872     renderLabelButtons();
00873     redrawTitlebar();
00874 }
00875 
00876 
00877 void FbWinFrame::renderHandles() {
00878     if (!m_use_handle)
00879         return;
00880 
00881     render(m_theme.handleFocusTexture(), m_handle_focused_color, 
00882            m_handle_focused_pm,
00883            m_handle.width(), m_handle.height());
00884     
00885     render(m_theme.handleUnfocusTexture(), m_handle_unfocused_color, 
00886            m_handle_unfocused_pm,
00887            m_handle.width(), m_handle.height());
00888 
00889     if (m_focused) {
00890         if (m_handle_focused_pm) {
00891             m_handle.setBackgroundPixmap(m_handle_focused_pm);
00892         } else {
00893             m_handle.setBackgroundColor(m_handle_focused_color);
00894         }                
00895     } else {
00896         if (m_handle_unfocused_pm) {
00897             m_handle.setBackgroundPixmap(m_handle_unfocused_pm);
00898         } else {
00899             m_handle.setBackgroundColor(m_handle_unfocused_color);
00900         }                
00901     }
00902 
00903     render(m_theme.gripFocusTexture(), m_grip_focused_color, m_grip_focused_pm,
00904            m_grip_left.width(), m_grip_left.height());
00905 
00906     render(m_theme.gripUnfocusTexture(), m_grip_unfocused_color, 
00907            m_grip_unfocused_pm,
00908            m_grip_left.width(), m_grip_left.height());
00909 
00910     if (m_focused) {
00911         if (m_grip_focused_pm) {
00912             m_grip_left.setBackgroundPixmap(m_grip_focused_pm);
00913             m_grip_right.setBackgroundPixmap(m_grip_focused_pm);
00914         } else {
00915             m_grip_left.setBackgroundColor(m_grip_focused_color);
00916             m_grip_right.setBackgroundColor(m_grip_focused_color);
00917         }                
00918     } else {
00919         if (m_grip_unfocused_pm) {
00920             m_grip_left.setBackgroundPixmap(m_grip_unfocused_pm);
00921             m_grip_right.setBackgroundPixmap(m_grip_unfocused_pm);
00922         } else {
00923             m_grip_left.setBackgroundColor(m_grip_unfocused_color);
00924             m_grip_right.setBackgroundColor(m_grip_unfocused_color);
00925         }                
00926     }
00927 
00928     m_handle.setAlpha(theme().alpha());
00929     m_grip_left.setAlpha(theme().alpha());
00930     m_grip_right.setAlpha(theme().alpha());
00931 
00932     m_grip_left.clear();
00933     m_grip_left.updateTransparent();
00934     m_grip_right.clear();
00935     m_grip_right.updateTransparent();
00936     m_handle.clear();
00937     m_handle.updateTransparent();
00938 
00939 }
00940 
00941 void FbWinFrame::renderButtons() {
00942 
00943     render(m_theme.buttonFocusTexture(), m_button_color, m_button_pm,
00944            m_button_size, m_button_size);
00945 
00946     render(m_theme.buttonUnfocusTexture(), m_button_unfocused_color, 
00947            m_button_unfocused_pm,
00948            m_button_size, m_button_size);
00949         
00950     render(m_theme.buttonPressedTexture(), m_button_pressed_color, 
00951            m_button_pressed_pm,
00952            m_button_size, m_button_size);
00953 
00954     // setup left and right buttons
00955     for (size_t i=0; i < m_buttons_left.size(); ++i) {        
00956         setupButton(*m_buttons_left[i]);
00957         if (isVisible()) {
00958             m_buttons_left[i]->clear();
00959             m_buttons_left[i]->updateTransparent();
00960         }
00961     }
00962 
00963     for (size_t i=0; i < m_buttons_right.size(); ++i) {
00964         setupButton(*m_buttons_right[i]);
00965         if (isVisible()) {
00966             m_buttons_right[i]->clear();
00967             m_buttons_right[i]->updateTransparent();
00968         }
00969     }
00970     
00971 }
00972 
00973 void FbWinFrame::init() {
00974 
00975     // setup update timer
00976     FbTk::RefCount<FbTk::Command> update_transp(new FbTk::SimpleCommand<FbWinFrame>(*this, 
00977                                                                                     &FbWinFrame::updateTransparent));
00978     m_update_timer.setCommand(update_transp);
00979     m_update_timer.setTimeout(10L);
00980     m_update_timer.fireOnce(true);
00981 
00982     if (theme().handleWidth() == 0)
00983         m_use_handle = false;
00984 
00985     m_disable_shape = false;
00986 
00987     m_current_label = 0; // no focused button at first
00988 
00989     m_handle.showSubwindows();
00990 
00991     // clear pixmaps
00992     m_title_focused_pm = m_title_unfocused_pm = 0;
00993     m_label_focused_pm = m_label_unfocused_pm = m_label_active_pm = 0;
00994     m_handle_focused_pm = m_handle_unfocused_pm = 0;
00995     m_button_pm = m_button_unfocused_pm = m_button_pressed_pm = 0;
00996     m_grip_unfocused_pm = m_grip_focused_pm = 0;
00997 
00998     m_double_click_time = 200;
00999     m_button_size = 26;
01000 
01001     m_clientarea.setBorderWidth(0);
01002     m_shaded = false;
01003     m_label.show();
01004 
01005     showHandle();
01006     showTitlebar();
01007 
01008     // Note: we don't show clientarea yet
01009 
01010     setEventHandler(*this);
01011 }
01012 
01016 void FbWinFrame::setupButton(FbTk::Button &btn) {
01017     if (m_button_pressed_pm)
01018         btn.setPressedPixmap(m_button_pressed_pm);
01019 
01021 
01022     if (focused()) { // focused
01023         btn.setGC(m_theme.buttonPicFocusGC());
01024         if (m_button_pm)
01025             btn.setBackgroundPixmap(m_button_pm);
01026         else
01027             btn.setBackgroundColor(m_button_color);
01028     } else { // unfocused
01029         btn.setGC(m_theme.buttonPicUnfocusGC());
01030         if (m_button_unfocused_pm)
01031             btn.setBackgroundPixmap(m_button_unfocused_pm);
01032         else
01033             btn.setBackgroundColor(m_button_unfocused_color);
01034 
01035     }
01036 
01037     btn.setAlpha(theme().alpha());
01038 }
01039 
01040 void FbWinFrame::render(const FbTk::Texture &tex, FbTk::Color &col, Pixmap &pm,
01041                         unsigned int w, unsigned int h) {
01042 
01043     Pixmap tmp = pm;
01044     if (!tex.usePixmap()) {
01045         pm = None;
01046         col = tex.color();
01047     } else {
01048         pm = m_imagectrl.renderImage(w, h, tex);
01049     }
01050 
01051     if (tmp) 
01052         m_imagectrl.removeImage(tmp);
01053 
01054 }
01055 
01056 void FbWinFrame::getCurrentFocusPixmap(Pixmap &label_pm, Pixmap &title_pm,
01057                                        FbTk::Color &label_color, FbTk::Color &title_color) {
01058     if (m_focused) {
01059         if (m_label_focused_pm != 0)
01060             label_pm = m_label_focused_pm;
01061         else
01062             label_color = m_label_focused_color;
01063     
01064         if (m_title_focused_pm != 0)
01065             title_pm = m_title_focused_pm;
01066         else
01067             title_color = m_title_focused_color;
01068      
01069     } else {
01070         getActiveLabelPixmap(label_pm, title_pm,
01071                              label_color, title_color);
01072     }
01073 
01074 }
01075 
01076 // only called if not focused
01077 void FbWinFrame::getActiveLabelPixmap(Pixmap &label_pm, Pixmap &title_pm,
01078                                   FbTk::Color &label_color, 
01079                                   FbTk::Color &title_color) {
01080 
01081     if (m_label_active_pm != 0)
01082         label_pm = m_label_active_pm;            
01083     else
01084         label_color = m_label_active_color;
01085 
01086     if (m_title_unfocused_pm != 0)
01087         title_pm  = m_title_unfocused_pm;
01088     else
01089         title_color = m_title_unfocused_color;
01090 }
01091 
01092 void FbWinFrame::renderLabelButtons() {
01093 
01094     Pixmap label_pm = 0;
01095     Pixmap not_used_pm = 0;
01096     FbTk::Color label_color;
01097     FbTk::Color not_used_color;
01098     getCurrentFocusPixmap(label_pm, not_used_pm,
01099                           label_color, not_used_color);
01100 
01101     LabelList::iterator btn_it = m_labelbuttons.begin();
01102     LabelList::iterator btn_it_end = m_labelbuttons.end();        
01103     for (; btn_it != btn_it_end; ++btn_it) {
01104         if (*btn_it == m_current_label) {
01105             if (m_focused)
01106                 renderButtonFocus(**btn_it);
01107             else
01108                 renderButtonActive(**btn_it);
01109         } else
01110             renderButtonUnfocus(**btn_it);
01111 
01112     }
01113     
01114     if (m_current_label != 0) {
01115 
01116         if (label_pm) {
01117             m_current_label->setBackgroundPixmap(label_pm);
01118         } else
01119             m_current_label->setBackgroundColor(label_color);
01120 
01121     }
01122 
01123 }
01124 
01125 void FbWinFrame::setBorderWidth(unsigned int border_width) {
01126     int bw_changes = 0;
01127     // we need to change the size of the window 
01128     // if the border width changes...
01129     if (m_use_titlebar) 
01130         bw_changes += static_cast<signed>(border_width - titlebar().borderWidth());
01131     if (m_use_handle) 
01132         bw_changes += static_cast<signed>(border_width - handle().borderWidth());
01133 
01134     window().setBorderWidth(border_width);
01135     window().setBorderColor(theme().border().color());
01136 
01137     titlebar().setBorderWidth(border_width);
01138     titlebar().setBorderColor(theme().border().color());
01139 
01140     handle().setBorderWidth(border_width);
01141     handle().setBorderColor(theme().border().color());
01142 
01143     gripLeft().setBorderWidth(border_width);
01144     gripLeft().setBorderColor(theme().border().color());
01145 
01146     gripRight().setBorderWidth(border_width);
01147     gripRight().setBorderColor(theme().border().color());
01148 
01149     if (bw_changes != 0)
01150         resize(width(), height() + bw_changes);
01151 }
01152 
01153 void FbWinFrame::renderButtonFocus(FbTk::TextButton &button) {
01154 
01155     button.setGC(theme().labelTextFocusGC());
01156     button.setJustify(theme().justify());
01157     button.setBorderWidth(1);
01158     button.setAlpha(theme().alpha());
01159 
01160     if (m_label_focused_pm != 0) {
01161         // already set
01162         if (button.backgroundPixmap() != m_label_focused_pm)
01163             button.setBackgroundPixmap(m_label_focused_pm);
01164     } else
01165         button.setBackgroundColor(m_label_focused_color);
01166 
01167 }
01168 
01169 void FbWinFrame::renderButtonActive(FbTk::TextButton &button) {
01170 
01171     button.setGC(theme().labelTextActiveGC());
01172     button.setJustify(theme().justify());
01173     button.setBorderWidth(1);
01174     button.setAlpha(theme().alpha());
01175 
01176     if (m_label_active_pm != 0) {
01177         // already set
01178         if (button.backgroundPixmap() != m_label_active_pm)
01179             button.setBackgroundPixmap(m_label_active_pm);
01180     } else
01181         button.setBackgroundColor(m_label_active_color);
01182 
01183 }
01184 
01185 void FbWinFrame::renderButtonUnfocus(FbTk::TextButton &button) {
01186 
01187     button.setGC(theme().labelTextUnfocusGC());
01188     button.setJustify(theme().justify());
01189     button.setBorderWidth(1);
01190     button.setAlpha(theme().alpha());
01191 
01192     if (m_label_unfocused_pm != 0) {
01193         // already set
01194         if (button.backgroundPixmap() != m_label_unfocused_pm)
01195             button.setBackgroundPixmap(m_label_unfocused_pm);
01196     } else
01197         button.setBackgroundColor(m_label_unfocused_color);
01198 
01199 }
01200 
01201 void FbWinFrame::updateTransparent() {
01202     redrawTitlebar();
01203     
01204     ButtonList::iterator button_it = m_buttons_left.begin();
01205     ButtonList::iterator button_it_end = m_buttons_left.end();
01206     for (; button_it != button_it_end; ++button_it) {
01207         (*button_it)->clear();
01208         (*button_it)->updateTransparent();
01209     }
01210 
01211     button_it = m_buttons_right.begin();
01212     button_it_end = m_buttons_right.end();
01213     for (; button_it != button_it_end; ++button_it) {
01214         (*button_it)->clear();
01215         (*button_it)->updateTransparent();
01216     }
01217 
01218     m_grip_left.clear();
01219     m_grip_left.updateTransparent();
01220     m_grip_right.clear();
01221     m_grip_right.updateTransparent();
01222     m_handle.clear();
01223     m_handle.updateTransparent();
01224 
01225 }
01226 
01227 
01228 // this function translates its arguments according to win_gravity
01229 // if win_gravity is negative, it does an inverse translation
01230 // This function should be used when a window is mapped/unmapped/pos configured
01231 void FbWinFrame::gravityTranslate(int &x, int &y, int win_gravity, bool move_frame) {
01232     bool invert = false;
01233     if (win_gravity < 0) {
01234         invert = true;
01235         win_gravity = -win_gravity; // make +ve
01236     }
01237 
01238     /* Ok, so, gravity says which point of the frame is put where the 
01239      * corresponding bit of window would have been
01240      * Thus, x,y always refers to where top left of the WINDOW would be placed
01241      * but given that we're wrapping it in a frame, we actually place
01242      * it so that the given reference point is in the same spot as the
01243      * window's reference point would have been.
01244      * i.e. east gravity says that the centre of the right hand side of the 
01245      * frame is placed where the centre of the rhs of the window would
01246      * have been if there was no frame.
01247      * Hope that makes enough sense.
01248      *
01249      * If you get confused with the calculations, draw a picture.
01250      *
01251      */
01252 
01253     // We calculate offsets based on the gravity and frame aspects
01254     // and at the end apply those offsets +ve or -ve depending on 'invert'
01255 
01256     int x_offset = 0;
01257     int y_offset = 0;
01258 
01259     // mostly no X offset, since we don't have extra frame on the sides
01260     switch (win_gravity) {
01261     case NorthWestGravity:
01262     case NorthGravity:
01263     case NorthEastGravity:
01264         // no offset, since the top point is still the same
01265         break;
01266     case SouthWestGravity:
01267     case SouthGravity:
01268     case SouthEastGravity:
01269         // window shifted down by height of titlebar, and the handle
01270         // since that's necessary to get the bottom of the frame
01271         // all the way up
01272         if (m_use_titlebar)
01273             y_offset -= m_titlebar.height() + m_titlebar.borderWidth();
01274         if (m_use_handle)
01275             y_offset -= m_handle.height() + m_handle.borderWidth();
01276         break;
01277     case WestGravity:
01278     case EastGravity:
01279     case CenterGravity:
01280         // these centered ones are a little more interesting
01281         if (m_use_titlebar)
01282             y_offset -= m_titlebar.height() + m_titlebar.borderWidth();
01283         if (m_use_handle)
01284             y_offset -= m_handle.height() + m_handle.borderWidth();
01285         y_offset /= 2;
01286         break;
01287     case StaticGravity:
01288         if (m_use_titlebar)
01289             y_offset -= m_titlebar.height() + m_titlebar.borderWidth();
01290         // static is the only one that also has the
01291         // border taken into account
01292         x_offset -= m_window.borderWidth();
01293         y_offset -= m_window.borderWidth();
01294         break;
01295     }
01296 
01297     if (invert) {
01298         x_offset = -x_offset;
01299         y_offset = -y_offset;
01300     }
01301 
01302     x += x_offset;
01303     y += y_offset;
01304 
01305     if (move_frame && (x_offset != 0 || y_offset != 0)) {
01306         move(x,y);
01307     }
01308 }

Fluxbox CVS-Jan-2003




      



Got comments about the page? Send them to webmaster.
If you have general Fluxbox related questions ask them on our irc channel or mailing lists.

Show Source








Designed by aLEczapKA