kcommondecoration.cpp

00001 /*
00002   This file is part of the KDE project.
00003 
00004   Copyright (C) 2005 Sandro Giessl <sandro@giessl.com>
00005 
00006   Permission is hereby granted, free of charge, to any person obtaining a
00007   copy of this software and associated documentation files (the "Software"),
00008   to deal in the Software without restriction, including without limitation
00009   the rights to use, copy, modify, merge, publish, distribute, sublicense,
00010   and/or sell copies of the Software, and to permit persons to whom the
00011   Software is furnished to do so, subject to the following conditions:
00012 
00013   The above copyright notice and this permission notice shall be included in
00014   all copies or substantial portions of the Software.
00015 
00016   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00017   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00018   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
00019   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00020   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00021   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00022   DEALINGS IN THE SOFTWARE.
00023  */
00024 
00025 #include <qapplication.h>
00026 #include <qcursor.h>
00027 #include <qdatetime.h>
00028 #include <qlabel.h>
00029 #include <qtooltip.h>
00030 #include <qwidget.h>
00031 
00032 #include <kdebug.h>
00033 
00034 #include <kapplication.h>
00035 #include <kdecorationfactory.h>
00036 #include <klocale.h>
00037 
00038 #include "kcommondecoration.h"
00039 #include "kcommondecoration.moc"
00040 
00041 KCommonDecoration::KCommonDecoration(KDecorationBridge* bridge, KDecorationFactory* factory)
00042     : KDecoration (bridge, factory),
00043         m_previewWidget(0),
00044         btnHideMinWidth(200),
00045         btnHideLastWidth(0),
00046         closing(false)
00047 {
00048     // sizeof(...) is calculated at compile time
00049     memset(m_button, 0, sizeof(KCommonDecorationButton *) * NumButtons);
00050 }
00051 
00052 KCommonDecoration::~KCommonDecoration()
00053 {
00054     for (int n=0; n<NumButtons; n++) {
00055         if (m_button[n]) delete m_button[n];
00056     }
00057     delete m_previewWidget;
00058 }
00059 
00060 bool KCommonDecoration::decorationBehaviour(DecorationBehaviour behaviour) const
00061 {
00062     switch (behaviour) {
00063         case DB_MenuClose:
00064             return false;
00065 
00066         case DB_WindowMask:
00067             return false;
00068 
00069         case DB_ButtonHide:
00070             return true;
00071     }
00072 
00073     return false;
00074 }
00075 
00076 int KCommonDecoration::layoutMetric(LayoutMetric lm, bool, const KCommonDecorationButton *) const
00077 {
00078     switch (lm) {
00079         case LM_BorderLeft:
00080         case LM_BorderRight:
00081         case LM_BorderBottom:
00082         case LM_TitleEdgeTop:
00083         case LM_TitleEdgeBottom:
00084         case LM_TitleEdgeLeft:
00085         case LM_TitleEdgeRight:
00086         case LM_TitleBorderLeft:
00087         case LM_TitleBorderRight:
00088             return 5;
00089 
00090 
00091         case LM_ButtonWidth:
00092         case LM_ButtonHeight:
00093         case LM_TitleHeight:
00094             return 20;
00095 
00096         case LM_ButtonSpacing:
00097             return 5;
00098 
00099         case LM_ButtonMarginTop:
00100             return 0;
00101 
00102         case LM_ExplicitButtonSpacer:
00103             return 5;
00104 
00105         default:
00106             return 0;
00107     }
00108 }
00109 
00110 void KCommonDecoration::init()
00111 {
00112     createMainWidget(WNoAutoErase);
00113 
00114     // for flicker-free redraws
00115     widget()->setBackgroundMode(NoBackground);
00116 
00117     widget()->installEventFilter( this );
00118 
00119     resetLayout();
00120 
00121     connect(this, SIGNAL(keepAboveChanged(bool) ), SLOT(keepAboveChange(bool) ) );
00122     connect(this, SIGNAL(keepBelowChanged(bool) ), SLOT(keepBelowChange(bool) ) );
00123 
00124     updateCaption();
00125 }
00126 
00127 void KCommonDecoration::reset( unsigned long changed )
00128 {
00129     if (changed & SettingButtons) {
00130         resetLayout();
00131         widget()->update();
00132     }
00133 }
00134 
00135 QRegion KCommonDecoration::cornerShape(WindowCorner)
00136 {
00137     return QRegion();
00138 }
00139 
00140 void KCommonDecoration::updateCaption()
00141 {
00142     // This should be reimplemented in decorations for better efficiency
00143     widget()->update();
00144 }
00145 
00146 void KCommonDecoration::borders( int& left, int& right, int& top, int& bottom ) const
00147 {
00148     left = layoutMetric(LM_BorderLeft);
00149     right = layoutMetric(LM_BorderRight);
00150     bottom = layoutMetric(LM_BorderBottom);
00151     top = layoutMetric(LM_TitleHeight) +
00152             layoutMetric(LM_TitleEdgeTop) +
00153             layoutMetric(LM_TitleEdgeBottom);
00154 
00155     updateLayout(); // TODO!! don't call everytime we are in ::borders
00156 }
00157 
00158 void KCommonDecoration::updateLayout() const
00159 {
00160     QRect r = widget()->rect();
00161     int r_x, r_y, r_x2, r_y2;
00162     r.coords(&r_x, &r_y, &r_x2, &r_y2);
00163 
00164     // layout preview widget
00165     if (m_previewWidget) {
00166         const int borderLeft = layoutMetric(LM_BorderLeft);
00167         const int borderRight = layoutMetric(LM_BorderRight);
00168         const int borderBottom = layoutMetric(LM_BorderBottom);
00169         const int titleHeight = layoutMetric(LM_TitleHeight);
00170         const int titleEdgeTop = layoutMetric(LM_TitleEdgeTop);
00171         const int titleEdgeBottom = layoutMetric(LM_TitleEdgeBottom);
00172 
00173         int left = r_x+borderLeft;
00174         int top = r_y+titleEdgeTop+titleHeight+titleEdgeBottom;
00175         int width = r_x2-borderRight-left+1;
00176         int height = r_y2-borderBottom-top+1;
00177         m_previewWidget->setGeometry(left, top, width, height);
00178         moveWidget(left,top, m_previewWidget);
00179         resizeWidget(width, height, m_previewWidget);
00180     }
00181 
00182     // resize buttons...
00183     for (int n=0; n<NumButtons; n++) {
00184         if (m_button[n]) {
00185             QSize newSize = QSize(layoutMetric(LM_ButtonWidth, true, m_button[n]),
00186                                   layoutMetric(LM_ButtonHeight, true, m_button[n]) );
00187             if (newSize != m_button[n]->size() )
00188                 m_button[n]->setSize(newSize);
00189         }
00190     }
00191 
00192     // layout buttons
00193     int y = r_y + layoutMetric(LM_TitleEdgeTop) + layoutMetric(LM_ButtonMarginTop);
00194     if (m_buttonsLeft.count() > 0) {
00195         const int buttonSpacing = layoutMetric(LM_ButtonSpacing);
00196         int x = r_x + layoutMetric(LM_TitleEdgeLeft);
00197         for (ButtonContainer::const_iterator it = m_buttonsLeft.begin(); it != m_buttonsLeft.end(); ++it) {
00198             bool elementLayouted = false;
00199             if (*it) {
00200                 if (!(*it)->isHidden() ) {
00201                     moveWidget(x,y, *it);
00202                     x += layoutMetric(LM_ButtonWidth, true, ::qt_cast<KCommonDecorationButton*>(*it) );
00203                     elementLayouted = true;
00204                 }
00205             } else {
00206                 x+= layoutMetric(LM_ExplicitButtonSpacer);
00207                 elementLayouted = true;
00208             }
00209             if (elementLayouted && it != m_buttonsLeft.end() )
00210                 x += buttonSpacing;
00211         }
00212     }
00213 
00214     if (m_buttonsRight.count() > 0) {
00215         const int titleEdgeRightLeft = r_x2-layoutMetric(LM_TitleEdgeRight)+1;
00216 
00217         const int buttonSpacing = layoutMetric(LM_ButtonSpacing);
00218         int x = titleEdgeRightLeft - buttonContainerWidth(m_buttonsRight);
00219         for (ButtonContainer::const_iterator it = m_buttonsRight.begin(); it != m_buttonsRight.end(); ++it) {
00220             bool elementLayouted = false;
00221             if (*it) {
00222                 if (!(*it)->isHidden() ) {
00223                     moveWidget(x,y, *it);
00224                     x += layoutMetric(LM_ButtonWidth, true, ::qt_cast<KCommonDecorationButton*>(*it) );;
00225                     elementLayouted = true;
00226                 }
00227             } else {
00228                 x += layoutMetric(LM_ExplicitButtonSpacer);
00229                 elementLayouted = true;
00230             }
00231             if (elementLayouted && it != m_buttonsRight.end() )
00232                 x += buttonSpacing;
00233         }
00234     }
00235 }
00236 
00237 void KCommonDecoration::updateButtons() const
00238 {
00239     for (int n=0; n<NumButtons; n++)
00240         if (m_button[n]) m_button[n]->update();
00241 }
00242 
00243 void KCommonDecoration::resetButtons() const
00244 {
00245     for (int n=0; n<NumButtons; n++)
00246         if (m_button[n]) m_button[n]->reset(KCommonDecorationButton::ManualReset);
00247 }
00248 
00249 void KCommonDecoration::resetLayout()
00250 {
00251     for (int n=0; n<NumButtons; n++) {
00252         if (m_button[n]) {
00253             delete m_button[n];
00254             m_button[n] = 0;
00255         }
00256     }
00257     m_buttonsLeft.clear();
00258     m_buttonsRight.clear();
00259 
00260     delete m_previewWidget;
00261     m_previewWidget = 0;
00262 
00263     // shown instead of the window contents in decoration previews
00264     if(isPreview() ) {
00265         m_previewWidget = new QLabel(i18n("%1 is the name of window decoration style", "<center><b>%1 preview</b></center>").arg(visibleName() ), widget());
00266         m_previewWidget->show();
00267     }
00268 
00269     addButtons(m_buttonsLeft,
00270                options()->customButtonPositions() ? options()->titleButtonsLeft() : defaultButtonsLeft(),
00271                true);
00272     addButtons(m_buttonsRight,
00273                options()->customButtonPositions() ? options()->titleButtonsRight() : defaultButtonsRight(),
00274                false);
00275 
00276     updateLayout();
00277 
00278     const int minTitleBarWidth = 35;
00279     btnHideMinWidth = buttonContainerWidth(m_buttonsLeft,true) + buttonContainerWidth(m_buttonsRight,true) +
00280             layoutMetric(LM_TitleEdgeLeft,false) + layoutMetric(LM_TitleEdgeRight,false) +
00281             layoutMetric(LM_TitleBorderLeft,false) + layoutMetric(LM_TitleBorderRight,false) +
00282             minTitleBarWidth;
00283     btnHideLastWidth = 0;
00284 }
00285 
00286 int KCommonDecoration::buttonsLeftWidth() const
00287 {
00288     return buttonContainerWidth(m_buttonsLeft);
00289 }
00290 
00291 int KCommonDecoration::buttonsRightWidth() const
00292 {
00293     return buttonContainerWidth(m_buttonsRight);
00294 }
00295 
00296 int KCommonDecoration::buttonContainerWidth(const ButtonContainer &btnContainer, bool countHidden) const
00297 {
00298     int explicitSpacer = layoutMetric(LM_ExplicitButtonSpacer);
00299 
00300     int shownElementsCount = 0;
00301 
00302     int w = 0;
00303     for (ButtonContainer::const_iterator it = btnContainer.begin(); it != btnContainer.end(); ++it) {
00304         if (*it) {
00305             if (countHidden || !(*it)->isHidden() ) {
00306                 w += (*it)->width();
00307                 ++shownElementsCount;
00308             }
00309         } else {
00310             w += explicitSpacer;
00311             ++shownElementsCount;
00312         }
00313     }
00314     w += layoutMetric(LM_ButtonSpacing)*(shownElementsCount-1);
00315 
00316     return w;
00317 }
00318 
00319 void KCommonDecoration::addButtons(ButtonContainer &btnContainer, const QString& s, bool isLeft)
00320 {
00321     if (s.length() > 0) {
00322         for (unsigned n=0; n < s.length(); n++) {
00323             KCommonDecorationButton *btn = 0;
00324             switch (s[n]) {
00325               case 'M': // Menu button
00326                   if (!m_button[MenuButton]){
00327                       btn = createButton(MenuButton);
00328                       if (!btn) break;
00329                       btn->setTipText(i18n("Menu") );
00330                       btn->setRealizeButtons(LeftButton|RightButton);
00331                       connect(btn, SIGNAL(pressed()), SLOT(menuButtonPressed()));
00332                       connect(btn, SIGNAL(released()), this, SLOT(menuButtonReleased()));
00333 
00334                       m_button[MenuButton] = btn;
00335                   }
00336                   break;
00337               case 'S': // OnAllDesktops button
00338                   if (!m_button[OnAllDesktopsButton]){
00339                       btn = createButton(OnAllDesktopsButton);
00340                       if (!btn) break;
00341                       const bool oad = isOnAllDesktops();
00342                       btn->setTipText(oad?i18n("Not on all desktops"):i18n("On all desktops") );
00343                       btn->setToggleButton(true);
00344                       btn->setOn( oad );
00345                       connect(btn, SIGNAL(clicked()), SLOT(toggleOnAllDesktops()));
00346 
00347                       m_button[OnAllDesktopsButton] = btn;
00348                   }
00349                   break;
00350               case 'H': // Help button
00351                   if ((!m_button[HelpButton]) && providesContextHelp()){
00352                       btn = createButton(HelpButton);
00353                       if (!btn) break;
00354                       btn->setTipText(i18n("Help") );
00355                       connect(btn, SIGNAL(clicked()), SLOT(showContextHelp()));
00356 
00357                       m_button[HelpButton] = btn;
00358                   }
00359                   break;
00360               case 'I': // Minimize button
00361                   if ((!m_button[MinButton]) && isMinimizable()){
00362                       btn = createButton(MinButton);
00363                       if (!btn) break;
00364                       btn->setTipText(i18n("Minimize") );
00365                       connect(btn, SIGNAL(clicked()), SLOT(minimize()));
00366 
00367                       m_button[MinButton] = btn;
00368                   }
00369                   break;
00370               case 'A': // Maximize button
00371                   if ((!m_button[MaxButton]) && isMaximizable()){
00372                       btn = createButton(MaxButton);
00373                       if (!btn) break;
00374                       btn->setRealizeButtons(LeftButton|MidButton|RightButton);
00375                       const bool max = maximizeMode()==MaximizeFull;
00376                       btn->setTipText(max?i18n("Restore"):i18n("Maximize") );
00377                       btn->setToggleButton(true);
00378                       btn->setOn( max );
00379                       connect(btn, SIGNAL(clicked()), SLOT(slotMaximize()));
00380 
00381                       m_button[MaxButton] = btn;
00382                   }
00383                   break;
00384               case 'X': // Close button
00385                   if ((!m_button[CloseButton]) && isCloseable()){
00386                       btn = createButton(CloseButton);
00387                       if (!btn) break;
00388                       btn->setTipText(i18n("Close") );
00389                       connect(btn, SIGNAL(clicked()), SLOT(closeWindow()));
00390 
00391                       m_button[CloseButton] = btn;
00392                   }
00393                   break;
00394               case 'F': // AboveButton button
00395                   if (!m_button[AboveButton]){
00396                       btn = createButton(AboveButton);
00397                       if (!btn) break;
00398                       bool above = keepAbove();
00399                       btn->setTipText(above?i18n("Do not keep above others"):i18n("Keep above others") );
00400                       btn->setToggleButton(true);
00401                       btn->setOn( above );
00402                       connect(btn, SIGNAL(clicked()), SLOT(slotKeepAbove()));
00403 
00404                       m_button[AboveButton] = btn;
00405                   }
00406                   break;
00407               case 'B': // BelowButton button
00408                   if (!m_button[BelowButton]){
00409                       btn = createButton(BelowButton);
00410                       if (!btn) break;
00411                       bool below = keepBelow();
00412                       btn->setTipText(below?i18n("Do not keep below others"):i18n("Keep below others") );
00413                       btn->setToggleButton(true);
00414                       btn->setOn( below );
00415                       connect(btn, SIGNAL(clicked()), SLOT(slotKeepBelow()));
00416 
00417                       m_button[BelowButton] = btn;
00418                   }
00419                   break;
00420               case 'L': // Shade button
00421                   if ((!m_button[ShadeButton]) && isShadeable()){
00422                       btn = createButton(ShadeButton);
00423                       if (!btn) break;
00424                       bool shaded = isSetShade();
00425                       btn->setTipText(shaded?i18n("Unshade"):i18n("Shade") );
00426                       btn->setToggleButton(true);
00427                       btn->setOn( shaded );
00428                       connect(btn, SIGNAL(clicked()), SLOT(slotShade()));
00429 
00430                       m_button[ShadeButton] = btn;
00431                   }
00432                   break;
00433               case '_': // Spacer item
00434                   btnContainer.append(0);
00435             }
00436 
00437 
00438             if (btn) {
00439                 btn->setLeft(isLeft);
00440                 btn->setSize(QSize(layoutMetric(LM_ButtonWidth, true, btn),layoutMetric(LM_ButtonHeight, true, btn)) );
00441                 btn->show();
00442                 btnContainer.append(btn);
00443             }
00444 
00445         }
00446     }
00447 }
00448 
00449 void KCommonDecoration::calcHiddenButtons()
00450 {
00451     if (width() == btnHideLastWidth)
00452         return;
00453 
00454     btnHideLastWidth = width();
00455 
00456     //Hide buttons in the following order:
00457     KCommonDecorationButton* btnArray[] = { m_button[HelpButton], m_button[ShadeButton], m_button[BelowButton],
00458         m_button[AboveButton], m_button[OnAllDesktopsButton], m_button[MaxButton],
00459         m_button[MinButton], m_button[MenuButton], m_button[CloseButton] };
00460     const int buttonsCount = sizeof( btnArray ) / sizeof( btnArray[ 0 ] );
00461 
00462     int current_width = width();
00463     int count = 0;
00464 
00465     // Hide buttons
00466     while (current_width < btnHideMinWidth && count < buttonsCount)
00467     {
00468         if (btnArray[count] ) {
00469             current_width += btnArray[count]->width();
00470             if (btnArray[count]->isVisible() )
00471                 btnArray[count]->hide();
00472         }
00473         count++;
00474     }
00475     // Show the rest of the buttons...
00476     for(int i = count; i < buttonsCount; i++)
00477     {
00478         if (btnArray[i] ) {
00479 
00480             if (! btnArray[i]->isHidden() )
00481                 break; // all buttons shown...
00482 
00483             btnArray[i]->show();
00484         }
00485     }
00486 }
00487 
00488 void KCommonDecoration::show()
00489 {
00490     if (decorationBehaviour(DB_ButtonHide) )
00491         calcHiddenButtons();
00492     widget()->show();
00493 }
00494 
00495 void KCommonDecoration::resize( const QSize& s )
00496 {
00497     widget()->resize( s );
00498 }
00499 
00500 QSize KCommonDecoration::minimumSize() const
00501 {
00502     const int minWidth = QMAX(layoutMetric(LM_TitleEdgeLeft), layoutMetric(LM_BorderLeft))
00503             +QMAX(layoutMetric(LM_TitleEdgeRight), layoutMetric(LM_BorderRight))
00504             +layoutMetric(LM_TitleBorderLeft)+layoutMetric(LM_TitleBorderRight);
00505     return QSize(minWidth,
00506                  layoutMetric(LM_TitleEdgeTop)+layoutMetric(LM_TitleHeight)
00507                          +layoutMetric(LM_TitleEdgeBottom)
00508                          +layoutMetric(LM_BorderBottom) );
00509 }
00510 
00511 void KCommonDecoration::maximizeChange()
00512 {
00513     if( m_button[MaxButton] ) {
00514         m_button[MaxButton]->setOn( maximizeMode()==MaximizeFull);
00515         m_button[MaxButton]->setTipText( (maximizeMode()!=MaximizeFull) ?
00516                 i18n("Maximize")
00517             : i18n("Restore"));
00518         m_button[MaxButton]->reset(KCommonDecorationButton::StateChange);
00519     }
00520     updateWindowShape();
00521     widget()->update();
00522 }
00523 
00524 void KCommonDecoration::desktopChange()
00525 {
00526     if ( m_button[OnAllDesktopsButton] ) {
00527         m_button[OnAllDesktopsButton]->setOn( isOnAllDesktops() );
00528         m_button[OnAllDesktopsButton]->setTipText( isOnAllDesktops() ?
00529                 i18n("Not on all desktops")
00530             : i18n("On all desktops"));
00531         m_button[OnAllDesktopsButton]->reset(KCommonDecorationButton::StateChange);
00532     }
00533 }
00534 
00535 void KCommonDecoration::shadeChange()
00536 {
00537     if ( m_button[ShadeButton] ) {
00538         bool shaded = isSetShade();
00539         m_button[ShadeButton]->setOn( shaded );
00540         m_button[ShadeButton]->setTipText( shaded ?
00541                 i18n("Unshade")
00542             : i18n("Shade"));
00543         m_button[ShadeButton]->reset(KCommonDecorationButton::StateChange);
00544     }
00545 }
00546 
00547 void KCommonDecoration::iconChange()
00548 {
00549     if (m_button[MenuButton])
00550     {
00551         m_button[MenuButton]->update();
00552         m_button[MenuButton]->reset(KCommonDecorationButton::IconChange);
00553     }
00554 }
00555 
00556 void KCommonDecoration::activeChange()
00557 {
00558     updateButtons();
00559     widget()->update(); // do something similar to updateCaption here
00560 }
00561 
00562 void KCommonDecoration::captionChange()
00563 {
00564     updateCaption();
00565 }
00566 
00567 void KCommonDecoration::keepAboveChange(bool above)
00568 {
00569     if (m_button[AboveButton])
00570     {
00571         m_button[AboveButton]->setOn(above);
00572         m_button[AboveButton]->setTipText( above?i18n("Do not keep above others"):i18n("Keep above others") );
00573         m_button[AboveButton]->reset(KCommonDecorationButton::StateChange);
00574     }
00575 
00576     if (m_button[BelowButton] && m_button[BelowButton]->isOn())
00577     {
00578         m_button[BelowButton]->setOn(false);
00579         m_button[BelowButton]->setTipText( i18n("Keep below others") );
00580         m_button[BelowButton]->reset(KCommonDecorationButton::StateChange);
00581     }
00582 }
00583 
00584 void KCommonDecoration::keepBelowChange(bool below)
00585 {
00586     if (m_button[BelowButton])
00587     {
00588         m_button[BelowButton]->setOn(below);
00589         m_button[BelowButton]->setTipText( below?i18n("Do not keep below others"):i18n("Keep below others") );
00590         m_button[BelowButton]->reset(KCommonDecorationButton::StateChange);
00591     }
00592 
00593     if (m_button[AboveButton] && m_button[AboveButton]->isOn())
00594     {
00595         m_button[AboveButton]->setOn(false);
00596         m_button[AboveButton]->setTipText( i18n("Keep above others") );
00597         m_button[AboveButton]->reset(KCommonDecorationButton::StateChange);
00598     }
00599 }
00600 
00601 void KCommonDecoration::slotMaximize()
00602 {
00603     if (m_button[MaxButton])
00604     {
00605         maximize(m_button[MaxButton]->lastMousePress() );
00606     }
00607 }
00608 
00609 void KCommonDecoration::slotShade()
00610 {
00611     setShade( !isSetShade() );
00612 }
00613 
00614 void KCommonDecoration::slotKeepAbove()
00615 {
00616     setKeepAbove(!keepAbove() );
00617 }
00618 
00619 void KCommonDecoration::slotKeepBelow()
00620 {
00621     setKeepBelow(!keepBelow() );
00622 }
00623 
00624 void KCommonDecoration::menuButtonPressed()
00625 {
00626     static QTime* t = NULL;
00627     static KCommonDecoration* lastClient = NULL;
00628     if (t == NULL)
00629         t = new QTime;
00630     bool dbl = (lastClient==this && t->elapsed() <= QApplication::doubleClickInterval());
00631     lastClient = this;
00632     t->start();
00633     if (!dbl || !decorationBehaviour(DB_MenuClose) ) {
00634         QRect menuRect = m_button[MenuButton]->rect();
00635         QPoint menutop = m_button[MenuButton]->mapToGlobal(menuRect.topLeft());
00636         QPoint menubottom = m_button[MenuButton]->mapToGlobal(menuRect.bottomRight())+QPoint(0,2);
00637         KDecorationFactory* f = factory();
00638         showWindowMenu(QRect(menutop, menubottom));
00639         if( !f->exists( this )) // 'this' was deleted
00640             return;
00641         m_button[MenuButton]->setDown(false);
00642     }
00643     else
00644         closing = true;
00645 }
00646 
00647 void KCommonDecoration::menuButtonReleased()
00648 {
00649     if(closing)
00650         closeWindow();
00651 }
00652 
00653 void KCommonDecoration::resizeEvent(QResizeEvent */*e*/)
00654 {
00655     if (decorationBehaviour(DB_ButtonHide) )
00656         calcHiddenButtons();
00657 
00658     updateLayout();
00659 
00660     updateWindowShape();
00661     // FIXME: don't update() here! this would result in two paintEvent()s
00662     // because there is already "something" else triggering the repaint...
00663 //     widget()->update();
00664 }
00665 
00666 void KCommonDecoration::moveWidget(int x, int y, QWidget *widget) const
00667 {
00668     QPoint p = widget->pos();
00669     int oldX = p.y();
00670     int oldY = p.x();
00671 
00672     if (x!=oldX || y!=oldY)
00673         widget->move(x,y);
00674 }
00675 
00676 void KCommonDecoration::resizeWidget(int w, int h, QWidget *widget) const
00677 {
00678     QSize s = widget->size();
00679     int oldW = s.width();
00680     int oldH = s.height();
00681 
00682     if (w!=oldW || h!=oldH)
00683         widget->resize(w,h);
00684 }
00685 
00686 void KCommonDecoration::mouseDoubleClickEvent(QMouseEvent *e)
00687 {
00688     if( e->button() != LeftButton )
00689         return;
00690 
00691     int tb = layoutMetric(LM_TitleEdgeTop)+layoutMetric(LM_TitleHeight)+layoutMetric(LM_TitleEdgeBottom);
00692     // when shaded, react on double clicks everywhere to make it easier to unshade. otherwise
00693     // react only on double clicks in the title bar region...
00694     if (isSetShade() || e->pos().y() <= tb )
00695         titlebarDblClickOperation();
00696 }
00697 
00698 void KCommonDecoration::wheelEvent(QWheelEvent *e)
00699 {
00700     int tb = layoutMetric(LM_TitleEdgeTop)+layoutMetric(LM_TitleHeight)+layoutMetric(LM_TitleEdgeBottom);
00701     if (isSetShade() || e->pos().y() <= tb )
00702         titlebarMouseWheelOperation( e->delta());
00703 }
00704 
00705 KCommonDecoration::Position KCommonDecoration::mousePosition(const QPoint &point) const
00706 {
00707     const int corner = 18+3*layoutMetric(LM_BorderBottom, false)/2;
00708     Position pos = PositionCenter;
00709 
00710     QRect r = widget()->rect();
00711     int r_x, r_y, r_x2, r_y2;
00712     r.coords(&r_x, &r_y, &r_x2, &r_y2);
00713     int p_x = point.x();
00714     int p_y = point.y();
00715     const int borderLeft = layoutMetric(LM_BorderLeft);
00716 //     const int borderRight = layoutMetric(LM_BorderRight);
00717     const int borderBottom = layoutMetric(LM_BorderBottom);
00718     const int titleHeight = layoutMetric(LM_TitleHeight);
00719     const int titleEdgeTop = layoutMetric(LM_TitleEdgeTop);
00720     const int titleEdgeBottom = layoutMetric(LM_TitleEdgeBottom);
00721     const int titleEdgeLeft = layoutMetric(LM_TitleEdgeLeft);
00722     const int titleEdgeRight = layoutMetric(LM_TitleEdgeRight);
00723 
00724     const int borderBottomTop = r_y2-borderBottom+1;
00725     const int borderLeftRight = r_x+borderLeft-1;
00726 //     const int borderRightLeft = r_x2-borderRight+1;
00727     const int titleEdgeLeftRight = r_x+titleEdgeLeft-1;
00728     const int titleEdgeRightLeft = r_x2-titleEdgeRight+1;
00729     const int titleEdgeBottomBottom = r_y+titleEdgeTop+titleHeight+titleEdgeBottom-1;
00730     const int titleEdgeTopBottom = r_y+titleEdgeTop-1;
00731 
00732     if (p_y <= titleEdgeTopBottom) {
00733         if (p_x <= r_x+corner)
00734             pos = PositionTopLeft;
00735         else if (p_x >= r_x2-corner)
00736             pos = PositionTopRight;
00737         else
00738             pos = PositionTop;
00739     } else if (p_y <= titleEdgeBottomBottom) {
00740         if (p_x <= titleEdgeLeftRight)
00741             pos = PositionTopLeft;
00742         else if (p_x >= titleEdgeRightLeft)
00743             pos = PositionTopRight;
00744         else
00745             pos = PositionCenter; // title bar
00746     } else if (p_y < borderBottomTop) {
00747         if      (p_y < r_y2-corner) {
00748             if (p_x <= borderLeftRight)
00749                 pos = PositionLeft;
00750             else
00751                 pos = PositionRight;
00752         } else {
00753             if (p_x <= borderLeftRight)
00754                 pos = PositionBottomLeft;
00755             else
00756                 pos = PositionBottomRight;
00757         }
00758     } else if(p_y >= borderBottomTop) {
00759         if (p_x <= r_x+corner)
00760             pos = PositionBottomLeft;
00761         else if (p_x >= r_x2-corner)
00762             pos = PositionBottomRight;
00763         else
00764             pos = PositionBottom;
00765     }
00766 
00767     return pos;
00768 }
00769 
00770 void KCommonDecoration::updateWindowShape()
00771 {
00772     // don't mask the widget...
00773     if (!decorationBehaviour(DB_WindowMask) )
00774         return;
00775 
00776     int w = widget()->width();
00777     int h = widget()->height();
00778 
00779     bool tl=true,tr=true,bl=true,br=true; // is there a transparent rounded corner in top-left? etc
00780 
00781     QDesktopWidget *desktop=KApplication::desktop();
00782     // no transparent rounded corners if this window corner lines up with a screen corner
00783     for(int screen=0; screen < desktop->numScreens(); ++screen)
00784     {
00785         QRect fullscreen(desktop->screenGeometry(screen));
00786         QRect window = geometry();
00787 
00788         if(window.topLeft()    == fullscreen.topLeft() ) tl = false;
00789         if(window.topRight()   == fullscreen.topRight() ) tr = false;
00790         if(window.bottomLeft() == fullscreen.bottomLeft() ) bl = false;
00791         if(window.bottomRight()== fullscreen.bottomRight() ) br = false;
00792     }
00793 
00794     QRegion mask(0, 0, w, h);
00795 
00796     // Remove top-left corner.
00797     if(tl)
00798     {
00799         mask -= cornerShape(WC_TopLeft);
00800     }
00801     // Remove top-right corner.
00802     if(tr)
00803     {
00804         mask -= cornerShape(WC_TopRight);
00805     }
00806         // Remove top-left corner.
00807     if(bl)
00808     {
00809         mask -= cornerShape(WC_BottomLeft);
00810     }
00811     // Remove top-right corner.
00812     if(br)
00813     {
00814         mask -= cornerShape(WC_BottomRight);
00815     }
00816 
00817     setMask( mask );
00818 }
00819 
00820 bool KCommonDecoration::eventFilter( QObject* o, QEvent* e )
00821 {
00822     if( o != widget())
00823         return false;
00824     switch( e->type())
00825     {
00826         case QEvent::Resize:
00827             resizeEvent(static_cast<QResizeEvent*>(e) );
00828             return true;
00829         case QEvent::Paint:
00830             paintEvent( static_cast< QPaintEvent* >( e ));
00831             return true;
00832         case QEvent::MouseButtonDblClick:
00833             mouseDoubleClickEvent( static_cast< QMouseEvent* >( e ));
00834             return true;
00835         case QEvent::MouseButtonPress:
00836             processMousePressEvent( static_cast< QMouseEvent* >( e ));
00837             return true;
00838         case QEvent::Wheel:
00839             wheelEvent( static_cast< QWheelEvent* >( e ));
00840             return true;
00841         default:
00842             return false;
00843     }
00844 }
00845 
00846 const int SUPPORTED_WINDOW_TYPES_MASK = NET::NormalMask | NET::DesktopMask | NET::DockMask
00847         | NET::ToolbarMask | NET::MenuMask | NET::DialogMask /*| NET::OverrideMask*/ | NET::TopMenuMask
00848         | NET::UtilityMask | NET::SplashMask;
00849 
00850 bool KCommonDecoration::isToolWindow() const
00851 {
00852     NET::WindowType type = windowType( SUPPORTED_WINDOW_TYPES_MASK );
00853     return ((type==NET::Toolbar)||(type==NET::Utility)||(type==NET::Menu));
00854 }
00855 
00856 QRect KCommonDecoration::titleRect() const
00857 {
00858     int r_x, r_y, r_x2, r_y2;
00859     widget()->rect().coords(&r_x, &r_y, &r_x2, &r_y2);
00860     const int titleEdgeLeft = layoutMetric(LM_TitleEdgeLeft);
00861     const int titleEdgeTop = layoutMetric(LM_TitleEdgeTop);
00862     const int titleEdgeRight = layoutMetric(LM_TitleEdgeRight);
00863     const int titleEdgeBottom = layoutMetric(LM_TitleEdgeBottom);
00864     const int titleBorderLeft = layoutMetric(LM_TitleBorderLeft);
00865     const int titleBorderRight = layoutMetric(LM_TitleBorderRight);
00866     const int ttlHeight = layoutMetric(LM_TitleHeight);
00867     const int titleEdgeBottomBottom = r_y+titleEdgeTop+ttlHeight+titleEdgeBottom-1;
00868     return QRect(r_x+titleEdgeLeft+buttonsLeftWidth()+titleBorderLeft, r_y+titleEdgeTop,
00869               r_x2-titleEdgeRight-buttonsRightWidth()-titleBorderRight-(r_x+titleEdgeLeft+buttonsLeftWidth()+titleBorderLeft),
00870               titleEdgeBottomBottom-(r_y+titleEdgeTop) );
00871 }
00872 
00873 
00874 KCommonDecorationButton::KCommonDecorationButton(ButtonType type, KCommonDecoration *parent, const char *name)
00875     : QButton(parent->widget(), name),
00876         m_decoration(parent),
00877         m_type(type),
00878         m_realizeButtons(LeftButton),
00879         m_lastMouse(NoButton),
00880         m_isLeft(true)
00881 {
00882     setCursor(ArrowCursor);
00883 }
00884 
00885 KCommonDecorationButton::~KCommonDecorationButton()
00886 {
00887 }
00888 
00889 KCommonDecoration *KCommonDecorationButton::decoration() const
00890 {
00891     return m_decoration;
00892 }
00893 
00894 ButtonType KCommonDecorationButton::type() const
00895 {
00896     return m_type;
00897 }
00898 
00899 bool KCommonDecorationButton::isLeft() const
00900 {
00901     return m_isLeft;
00902 }
00903 
00904 void KCommonDecorationButton::setLeft(bool left)
00905 {
00906     m_isLeft = left;
00907 }
00908 
00909 void KCommonDecorationButton::setRealizeButtons(int btns)
00910 {
00911     m_realizeButtons = btns;
00912 }
00913 
00914 void KCommonDecorationButton::setSize(const QSize &s)
00915 {
00916     if (!m_size.isValid() || s != size() ) {
00917         m_size = s;
00918 
00919         setFixedSize(m_size);
00920         reset(SizeChange);
00921     }
00922 }
00923 
00924 QSize KCommonDecorationButton::sizeHint() const
00925 {
00926     return m_size;
00927 }
00928 
00929 void KCommonDecorationButton::setTipText(const QString &tip) {
00930     QToolTip::remove(this );
00931     QToolTip::add(this, tip );
00932 }
00933 
00934 void KCommonDecorationButton::setToggleButton(bool toggle)
00935 {
00936     QButton::setToggleButton(toggle);
00937     reset(ToggleChange);
00938 }
00939 
00940 void KCommonDecorationButton::setOn(bool on)
00941 {
00942     if (on != isOn() ) {
00943         QButton::setOn(on);
00944         reset(StateChange);
00945     }
00946 }
00947 
00948 void KCommonDecorationButton::mousePressEvent(QMouseEvent* e)
00949 {
00950     m_lastMouse = e->button();
00951     // pass on event after changing button to LeftButton
00952     QMouseEvent me(e->type(), e->pos(), e->globalPos(),
00953                    (e->button()&m_realizeButtons)?LeftButton:NoButton, e->state());
00954 
00955     QButton::mousePressEvent(&me);
00956 }
00957 
00958 void KCommonDecorationButton::mouseReleaseEvent(QMouseEvent* e)
00959 {
00960     m_lastMouse = e->button();
00961     // pass on event after changing button to LeftButton
00962     QMouseEvent me(e->type(), e->pos(), e->globalPos(),
00963                    (e->button()&m_realizeButtons)?LeftButton:NoButton, e->state());
00964 
00965     QButton::mouseReleaseEvent(&me);
00966 }
KDE Home | KDE Accessibility Home | Description of Access Keys