diff options
Diffstat (limited to 'kwin/lib/kcommondecoration.cpp')
-rw-r--r-- | kwin/lib/kcommondecoration.cpp | 966 |
1 files changed, 966 insertions, 0 deletions
diff --git a/kwin/lib/kcommondecoration.cpp b/kwin/lib/kcommondecoration.cpp new file mode 100644 index 000000000..58a95b599 --- /dev/null +++ b/kwin/lib/kcommondecoration.cpp @@ -0,0 +1,966 @@ +/* + This file is part of the KDE project. + + Copyright (C) 2005 Sandro Giessl <sandro@giessl.com> + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + */ + +#include <qapplication.h> +#include <qcursor.h> +#include <qdatetime.h> +#include <qlabel.h> +#include <qtooltip.h> +#include <qwidget.h> + +#include <kdebug.h> + +#include <kapplication.h> +#include <kdecorationfactory.h> +#include <klocale.h> + +#include "kcommondecoration.h" +#include "kcommondecoration.moc" + +KCommonDecoration::KCommonDecoration(KDecorationBridge* bridge, KDecorationFactory* factory) + : KDecoration (bridge, factory), + m_previewWidget(0), + btnHideMinWidth(200), + btnHideLastWidth(0), + closing(false) +{ + // sizeof(...) is calculated at compile time + memset(m_button, 0, sizeof(KCommonDecorationButton *) * NumButtons); +} + +KCommonDecoration::~KCommonDecoration() +{ + for (int n=0; n<NumButtons; n++) { + if (m_button[n]) delete m_button[n]; + } + delete m_previewWidget; +} + +bool KCommonDecoration::decorationBehaviour(DecorationBehaviour behaviour) const +{ + switch (behaviour) { + case DB_MenuClose: + return false; + + case DB_WindowMask: + return false; + + case DB_ButtonHide: + return true; + } + + return false; +} + +int KCommonDecoration::layoutMetric(LayoutMetric lm, bool, const KCommonDecorationButton *) const +{ + switch (lm) { + case LM_BorderLeft: + case LM_BorderRight: + case LM_BorderBottom: + case LM_TitleEdgeTop: + case LM_TitleEdgeBottom: + case LM_TitleEdgeLeft: + case LM_TitleEdgeRight: + case LM_TitleBorderLeft: + case LM_TitleBorderRight: + return 5; + + + case LM_ButtonWidth: + case LM_ButtonHeight: + case LM_TitleHeight: + return 20; + + case LM_ButtonSpacing: + return 5; + + case LM_ButtonMarginTop: + return 0; + + case LM_ExplicitButtonSpacer: + return 5; + + default: + return 0; + } +} + +void KCommonDecoration::init() +{ + createMainWidget(WNoAutoErase); + + // for flicker-free redraws + widget()->setBackgroundMode(NoBackground); + + widget()->installEventFilter( this ); + + resetLayout(); + + connect(this, SIGNAL(keepAboveChanged(bool) ), SLOT(keepAboveChange(bool) ) ); + connect(this, SIGNAL(keepBelowChanged(bool) ), SLOT(keepBelowChange(bool) ) ); + + updateCaption(); +} + +void KCommonDecoration::reset( unsigned long changed ) +{ + if (changed & SettingButtons) { + resetLayout(); + widget()->update(); + } +} + +QRegion KCommonDecoration::cornerShape(WindowCorner) +{ + return QRegion(); +} + +void KCommonDecoration::updateCaption() +{ + // This should be reimplemented in decorations for better efficiency + widget()->update(); +} + +void KCommonDecoration::borders( int& left, int& right, int& top, int& bottom ) const +{ + left = layoutMetric(LM_BorderLeft); + right = layoutMetric(LM_BorderRight); + bottom = layoutMetric(LM_BorderBottom); + top = layoutMetric(LM_TitleHeight) + + layoutMetric(LM_TitleEdgeTop) + + layoutMetric(LM_TitleEdgeBottom); + + updateLayout(); // TODO!! don't call everytime we are in ::borders +} + +void KCommonDecoration::updateLayout() const +{ + QRect r = widget()->rect(); + int r_x, r_y, r_x2, r_y2; + r.coords(&r_x, &r_y, &r_x2, &r_y2); + + // layout preview widget + if (m_previewWidget) { + const int borderLeft = layoutMetric(LM_BorderLeft); + const int borderRight = layoutMetric(LM_BorderRight); + const int borderBottom = layoutMetric(LM_BorderBottom); + const int titleHeight = layoutMetric(LM_TitleHeight); + const int titleEdgeTop = layoutMetric(LM_TitleEdgeTop); + const int titleEdgeBottom = layoutMetric(LM_TitleEdgeBottom); + + int left = r_x+borderLeft; + int top = r_y+titleEdgeTop+titleHeight+titleEdgeBottom; + int width = r_x2-borderRight-left+1; + int height = r_y2-borderBottom-top+1; + m_previewWidget->setGeometry(left, top, width, height); + moveWidget(left,top, m_previewWidget); + resizeWidget(width, height, m_previewWidget); + } + + // resize buttons... + for (int n=0; n<NumButtons; n++) { + if (m_button[n]) { + QSize newSize = QSize(layoutMetric(LM_ButtonWidth, true, m_button[n]), + layoutMetric(LM_ButtonHeight, true, m_button[n]) ); + if (newSize != m_button[n]->size() ) + m_button[n]->setSize(newSize); + } + } + + // layout buttons + int y = r_y + layoutMetric(LM_TitleEdgeTop) + layoutMetric(LM_ButtonMarginTop); + if (m_buttonsLeft.count() > 0) { + const int buttonSpacing = layoutMetric(LM_ButtonSpacing); + int x = r_x + layoutMetric(LM_TitleEdgeLeft); + for (ButtonContainer::const_iterator it = m_buttonsLeft.begin(); it != m_buttonsLeft.end(); ++it) { + bool elementLayouted = false; + if (*it) { + if (!(*it)->isHidden() ) { + moveWidget(x,y, *it); + x += layoutMetric(LM_ButtonWidth, true, ::qt_cast<KCommonDecorationButton*>(*it) ); + elementLayouted = true; + } + } else { + x+= layoutMetric(LM_ExplicitButtonSpacer); + elementLayouted = true; + } + if (elementLayouted && it != m_buttonsLeft.end() ) + x += buttonSpacing; + } + } + + if (m_buttonsRight.count() > 0) { + const int titleEdgeRightLeft = r_x2-layoutMetric(LM_TitleEdgeRight)+1; + + const int buttonSpacing = layoutMetric(LM_ButtonSpacing); + int x = titleEdgeRightLeft - buttonContainerWidth(m_buttonsRight); + for (ButtonContainer::const_iterator it = m_buttonsRight.begin(); it != m_buttonsRight.end(); ++it) { + bool elementLayouted = false; + if (*it) { + if (!(*it)->isHidden() ) { + moveWidget(x,y, *it); + x += layoutMetric(LM_ButtonWidth, true, ::qt_cast<KCommonDecorationButton*>(*it) );; + elementLayouted = true; + } + } else { + x += layoutMetric(LM_ExplicitButtonSpacer); + elementLayouted = true; + } + if (elementLayouted && it != m_buttonsRight.end() ) + x += buttonSpacing; + } + } +} + +void KCommonDecoration::updateButtons() const +{ + for (int n=0; n<NumButtons; n++) + if (m_button[n]) m_button[n]->update(); +} + +void KCommonDecoration::resetButtons() const +{ + for (int n=0; n<NumButtons; n++) + if (m_button[n]) m_button[n]->reset(KCommonDecorationButton::ManualReset); +} + +void KCommonDecoration::resetLayout() +{ + for (int n=0; n<NumButtons; n++) { + if (m_button[n]) { + delete m_button[n]; + m_button[n] = 0; + } + } + m_buttonsLeft.clear(); + m_buttonsRight.clear(); + + delete m_previewWidget; + m_previewWidget = 0; + + // shown instead of the window contents in decoration previews + if(isPreview() ) { + m_previewWidget = new QLabel(i18n("%1 is the name of window decoration style", "<center><b>%1 preview</b></center>").arg(visibleName() ), widget()); + m_previewWidget->show(); + } + + addButtons(m_buttonsLeft, + options()->customButtonPositions() ? options()->titleButtonsLeft() : defaultButtonsLeft(), + true); + addButtons(m_buttonsRight, + options()->customButtonPositions() ? options()->titleButtonsRight() : defaultButtonsRight(), + false); + + updateLayout(); + + const int minTitleBarWidth = 35; + btnHideMinWidth = buttonContainerWidth(m_buttonsLeft,true) + buttonContainerWidth(m_buttonsRight,true) + + layoutMetric(LM_TitleEdgeLeft,false) + layoutMetric(LM_TitleEdgeRight,false) + + layoutMetric(LM_TitleBorderLeft,false) + layoutMetric(LM_TitleBorderRight,false) + + minTitleBarWidth; + btnHideLastWidth = 0; +} + +int KCommonDecoration::buttonsLeftWidth() const +{ + return buttonContainerWidth(m_buttonsLeft); +} + +int KCommonDecoration::buttonsRightWidth() const +{ + return buttonContainerWidth(m_buttonsRight); +} + +int KCommonDecoration::buttonContainerWidth(const ButtonContainer &btnContainer, bool countHidden) const +{ + int explicitSpacer = layoutMetric(LM_ExplicitButtonSpacer); + + int shownElementsCount = 0; + + int w = 0; + for (ButtonContainer::const_iterator it = btnContainer.begin(); it != btnContainer.end(); ++it) { + if (*it) { + if (countHidden || !(*it)->isHidden() ) { + w += (*it)->width(); + ++shownElementsCount; + } + } else { + w += explicitSpacer; + ++shownElementsCount; + } + } + w += layoutMetric(LM_ButtonSpacing)*(shownElementsCount-1); + + return w; +} + +void KCommonDecoration::addButtons(ButtonContainer &btnContainer, const QString& s, bool isLeft) +{ + if (s.length() > 0) { + for (unsigned n=0; n < s.length(); n++) { + KCommonDecorationButton *btn = 0; + switch (s[n]) { + case 'M': // Menu button + if (!m_button[MenuButton]){ + btn = createButton(MenuButton); + if (!btn) break; + btn->setTipText(i18n("Menu") ); + btn->setRealizeButtons(LeftButton|RightButton); + connect(btn, SIGNAL(pressed()), SLOT(menuButtonPressed())); + connect(btn, SIGNAL(released()), this, SLOT(menuButtonReleased())); + + m_button[MenuButton] = btn; + } + break; + case 'S': // OnAllDesktops button + if (!m_button[OnAllDesktopsButton]){ + btn = createButton(OnAllDesktopsButton); + if (!btn) break; + const bool oad = isOnAllDesktops(); + btn->setTipText(oad?i18n("Not on all desktops"):i18n("On all desktops") ); + btn->setToggleButton(true); + btn->setOn( oad ); + connect(btn, SIGNAL(clicked()), SLOT(toggleOnAllDesktops())); + + m_button[OnAllDesktopsButton] = btn; + } + break; + case 'H': // Help button + if ((!m_button[HelpButton]) && providesContextHelp()){ + btn = createButton(HelpButton); + if (!btn) break; + btn->setTipText(i18n("Help") ); + connect(btn, SIGNAL(clicked()), SLOT(showContextHelp())); + + m_button[HelpButton] = btn; + } + break; + case 'I': // Minimize button + if ((!m_button[MinButton]) && isMinimizable()){ + btn = createButton(MinButton); + if (!btn) break; + btn->setTipText(i18n("Minimize") ); + connect(btn, SIGNAL(clicked()), SLOT(minimize())); + + m_button[MinButton] = btn; + } + break; + case 'A': // Maximize button + if ((!m_button[MaxButton]) && isMaximizable()){ + btn = createButton(MaxButton); + if (!btn) break; + btn->setRealizeButtons(LeftButton|MidButton|RightButton); + const bool max = maximizeMode()==MaximizeFull; + btn->setTipText(max?i18n("Restore"):i18n("Maximize") ); + btn->setToggleButton(true); + btn->setOn( max ); + connect(btn, SIGNAL(clicked()), SLOT(slotMaximize())); + + m_button[MaxButton] = btn; + } + break; + case 'X': // Close button + if ((!m_button[CloseButton]) && isCloseable()){ + btn = createButton(CloseButton); + if (!btn) break; + btn->setTipText(i18n("Close") ); + connect(btn, SIGNAL(clicked()), SLOT(closeWindow())); + + m_button[CloseButton] = btn; + } + break; + case 'F': // AboveButton button + if (!m_button[AboveButton]){ + btn = createButton(AboveButton); + if (!btn) break; + bool above = keepAbove(); + btn->setTipText(above?i18n("Do not keep above others"):i18n("Keep above others") ); + btn->setToggleButton(true); + btn->setOn( above ); + connect(btn, SIGNAL(clicked()), SLOT(slotKeepAbove())); + + m_button[AboveButton] = btn; + } + break; + case 'B': // BelowButton button + if (!m_button[BelowButton]){ + btn = createButton(BelowButton); + if (!btn) break; + bool below = keepBelow(); + btn->setTipText(below?i18n("Do not keep below others"):i18n("Keep below others") ); + btn->setToggleButton(true); + btn->setOn( below ); + connect(btn, SIGNAL(clicked()), SLOT(slotKeepBelow())); + + m_button[BelowButton] = btn; + } + break; + case 'L': // Shade button + if ((!m_button[ShadeButton]) && isShadeable()){ + btn = createButton(ShadeButton); + if (!btn) break; + bool shaded = isSetShade(); + btn->setTipText(shaded?i18n("Unshade"):i18n("Shade") ); + btn->setToggleButton(true); + btn->setOn( shaded ); + connect(btn, SIGNAL(clicked()), SLOT(slotShade())); + + m_button[ShadeButton] = btn; + } + break; + case '_': // Spacer item + btnContainer.append(0); + } + + + if (btn) { + btn->setLeft(isLeft); + btn->setSize(QSize(layoutMetric(LM_ButtonWidth, true, btn),layoutMetric(LM_ButtonHeight, true, btn)) ); + btn->show(); + btnContainer.append(btn); + } + + } + } +} + +void KCommonDecoration::calcHiddenButtons() +{ + if (width() == btnHideLastWidth) + return; + + btnHideLastWidth = width(); + + //Hide buttons in the following order: + KCommonDecorationButton* btnArray[] = { m_button[HelpButton], m_button[ShadeButton], m_button[BelowButton], + m_button[AboveButton], m_button[OnAllDesktopsButton], m_button[MaxButton], + m_button[MinButton], m_button[MenuButton], m_button[CloseButton] }; + const int buttonsCount = sizeof( btnArray ) / sizeof( btnArray[ 0 ] ); + + int current_width = width(); + int count = 0; + + // Hide buttons + while (current_width < btnHideMinWidth && count < buttonsCount) + { + if (btnArray[count] ) { + current_width += btnArray[count]->width(); + if (btnArray[count]->isVisible() ) + btnArray[count]->hide(); + } + count++; + } + // Show the rest of the buttons... + for(int i = count; i < buttonsCount; i++) + { + if (btnArray[i] ) { + + if (! btnArray[i]->isHidden() ) + break; // all buttons shown... + + btnArray[i]->show(); + } + } +} + +void KCommonDecoration::show() +{ + if (decorationBehaviour(DB_ButtonHide) ) + calcHiddenButtons(); + widget()->show(); +} + +void KCommonDecoration::resize( const QSize& s ) +{ + widget()->resize( s ); +} + +QSize KCommonDecoration::minimumSize() const +{ + const int minWidth = QMAX(layoutMetric(LM_TitleEdgeLeft), layoutMetric(LM_BorderLeft)) + +QMAX(layoutMetric(LM_TitleEdgeRight), layoutMetric(LM_BorderRight)) + +layoutMetric(LM_TitleBorderLeft)+layoutMetric(LM_TitleBorderRight); + return QSize(minWidth, + layoutMetric(LM_TitleEdgeTop)+layoutMetric(LM_TitleHeight) + +layoutMetric(LM_TitleEdgeBottom) + +layoutMetric(LM_BorderBottom) ); +} + +void KCommonDecoration::maximizeChange() +{ + if( m_button[MaxButton] ) { + m_button[MaxButton]->setOn( maximizeMode()==MaximizeFull); + m_button[MaxButton]->setTipText( (maximizeMode()!=MaximizeFull) ? + i18n("Maximize") + : i18n("Restore")); + m_button[MaxButton]->reset(KCommonDecorationButton::StateChange); + } + updateWindowShape(); + widget()->update(); +} + +void KCommonDecoration::desktopChange() +{ + if ( m_button[OnAllDesktopsButton] ) { + m_button[OnAllDesktopsButton]->setOn( isOnAllDesktops() ); + m_button[OnAllDesktopsButton]->setTipText( isOnAllDesktops() ? + i18n("Not on all desktops") + : i18n("On all desktops")); + m_button[OnAllDesktopsButton]->reset(KCommonDecorationButton::StateChange); + } +} + +void KCommonDecoration::shadeChange() +{ + if ( m_button[ShadeButton] ) { + bool shaded = isSetShade(); + m_button[ShadeButton]->setOn( shaded ); + m_button[ShadeButton]->setTipText( shaded ? + i18n("Unshade") + : i18n("Shade")); + m_button[ShadeButton]->reset(KCommonDecorationButton::StateChange); + } +} + +void KCommonDecoration::iconChange() +{ + if (m_button[MenuButton]) + { + m_button[MenuButton]->update(); + m_button[MenuButton]->reset(KCommonDecorationButton::IconChange); + } +} + +void KCommonDecoration::activeChange() +{ + updateButtons(); + widget()->update(); // do something similar to updateCaption here +} + +void KCommonDecoration::captionChange() +{ + updateCaption(); +} + +void KCommonDecoration::keepAboveChange(bool above) +{ + if (m_button[AboveButton]) + { + m_button[AboveButton]->setOn(above); + m_button[AboveButton]->setTipText( above?i18n("Do not keep above others"):i18n("Keep above others") ); + m_button[AboveButton]->reset(KCommonDecorationButton::StateChange); + } + + if (m_button[BelowButton] && m_button[BelowButton]->isOn()) + { + m_button[BelowButton]->setOn(false); + m_button[BelowButton]->setTipText( i18n("Keep below others") ); + m_button[BelowButton]->reset(KCommonDecorationButton::StateChange); + } +} + +void KCommonDecoration::keepBelowChange(bool below) +{ + if (m_button[BelowButton]) + { + m_button[BelowButton]->setOn(below); + m_button[BelowButton]->setTipText( below?i18n("Do not keep below others"):i18n("Keep below others") ); + m_button[BelowButton]->reset(KCommonDecorationButton::StateChange); + } + + if (m_button[AboveButton] && m_button[AboveButton]->isOn()) + { + m_button[AboveButton]->setOn(false); + m_button[AboveButton]->setTipText( i18n("Keep above others") ); + m_button[AboveButton]->reset(KCommonDecorationButton::StateChange); + } +} + +void KCommonDecoration::slotMaximize() +{ + if (m_button[MaxButton]) + { + maximize(m_button[MaxButton]->lastMousePress() ); + } +} + +void KCommonDecoration::slotShade() +{ + setShade( !isSetShade() ); +} + +void KCommonDecoration::slotKeepAbove() +{ + setKeepAbove(!keepAbove() ); +} + +void KCommonDecoration::slotKeepBelow() +{ + setKeepBelow(!keepBelow() ); +} + +void KCommonDecoration::menuButtonPressed() +{ + static QTime* t = NULL; + static KCommonDecoration* lastClient = NULL; + if (t == NULL) + t = new QTime; + bool dbl = (lastClient==this && t->elapsed() <= QApplication::doubleClickInterval()); + lastClient = this; + t->start(); + if (!dbl || !decorationBehaviour(DB_MenuClose) ) { + QRect menuRect = m_button[MenuButton]->rect(); + QPoint menutop = m_button[MenuButton]->mapToGlobal(menuRect.topLeft()); + QPoint menubottom = m_button[MenuButton]->mapToGlobal(menuRect.bottomRight())+QPoint(0,2); + KDecorationFactory* f = factory(); + showWindowMenu(QRect(menutop, menubottom)); + if( !f->exists( this )) // 'this' was deleted + return; + m_button[MenuButton]->setDown(false); + } + else + closing = true; +} + +void KCommonDecoration::menuButtonReleased() +{ + if(closing) + closeWindow(); +} + +void KCommonDecoration::resizeEvent(QResizeEvent */*e*/) +{ + if (decorationBehaviour(DB_ButtonHide) ) + calcHiddenButtons(); + + updateLayout(); + + updateWindowShape(); + // FIXME: don't update() here! this would result in two paintEvent()s + // because there is already "something" else triggering the repaint... +// widget()->update(); +} + +void KCommonDecoration::moveWidget(int x, int y, QWidget *widget) const +{ + QPoint p = widget->pos(); + int oldX = p.y(); + int oldY = p.x(); + + if (x!=oldX || y!=oldY) + widget->move(x,y); +} + +void KCommonDecoration::resizeWidget(int w, int h, QWidget *widget) const +{ + QSize s = widget->size(); + int oldW = s.width(); + int oldH = s.height(); + + if (w!=oldW || h!=oldH) + widget->resize(w,h); +} + +void KCommonDecoration::mouseDoubleClickEvent(QMouseEvent *e) +{ + if( e->button() != LeftButton ) + return; + + int tb = layoutMetric(LM_TitleEdgeTop)+layoutMetric(LM_TitleHeight)+layoutMetric(LM_TitleEdgeBottom); + // when shaded, react on double clicks everywhere to make it easier to unshade. otherwise + // react only on double clicks in the title bar region... + if (isSetShade() || e->pos().y() <= tb ) + titlebarDblClickOperation(); +} + +void KCommonDecoration::wheelEvent(QWheelEvent *e) +{ + int tb = layoutMetric(LM_TitleEdgeTop)+layoutMetric(LM_TitleHeight)+layoutMetric(LM_TitleEdgeBottom); + if (isSetShade() || e->pos().y() <= tb ) + titlebarMouseWheelOperation( e->delta()); +} + +KCommonDecoration::Position KCommonDecoration::mousePosition(const QPoint &point) const +{ + const int corner = 18+3*layoutMetric(LM_BorderBottom, false)/2; + Position pos = PositionCenter; + + QRect r = widget()->rect(); + int r_x, r_y, r_x2, r_y2; + r.coords(&r_x, &r_y, &r_x2, &r_y2); + int p_x = point.x(); + int p_y = point.y(); + const int borderLeft = layoutMetric(LM_BorderLeft); +// const int borderRight = layoutMetric(LM_BorderRight); + const int borderBottom = layoutMetric(LM_BorderBottom); + const int titleHeight = layoutMetric(LM_TitleHeight); + const int titleEdgeTop = layoutMetric(LM_TitleEdgeTop); + const int titleEdgeBottom = layoutMetric(LM_TitleEdgeBottom); + const int titleEdgeLeft = layoutMetric(LM_TitleEdgeLeft); + const int titleEdgeRight = layoutMetric(LM_TitleEdgeRight); + + const int borderBottomTop = r_y2-borderBottom+1; + const int borderLeftRight = r_x+borderLeft-1; +// const int borderRightLeft = r_x2-borderRight+1; + const int titleEdgeLeftRight = r_x+titleEdgeLeft-1; + const int titleEdgeRightLeft = r_x2-titleEdgeRight+1; + const int titleEdgeBottomBottom = r_y+titleEdgeTop+titleHeight+titleEdgeBottom-1; + const int titleEdgeTopBottom = r_y+titleEdgeTop-1; + + if (p_y <= titleEdgeTopBottom) { + if (p_x <= r_x+corner) + pos = PositionTopLeft; + else if (p_x >= r_x2-corner) + pos = PositionTopRight; + else + pos = PositionTop; + } else if (p_y <= titleEdgeBottomBottom) { + if (p_x <= titleEdgeLeftRight) + pos = PositionTopLeft; + else if (p_x >= titleEdgeRightLeft) + pos = PositionTopRight; + else + pos = PositionCenter; // title bar + } else if (p_y < borderBottomTop) { + if (p_y < r_y2-corner) { + if (p_x <= borderLeftRight) + pos = PositionLeft; + else + pos = PositionRight; + } else { + if (p_x <= borderLeftRight) + pos = PositionBottomLeft; + else + pos = PositionBottomRight; + } + } else if(p_y >= borderBottomTop) { + if (p_x <= r_x+corner) + pos = PositionBottomLeft; + else if (p_x >= r_x2-corner) + pos = PositionBottomRight; + else + pos = PositionBottom; + } + + return pos; +} + +void KCommonDecoration::updateWindowShape() +{ + // don't mask the widget... + if (!decorationBehaviour(DB_WindowMask) ) + return; + + int w = widget()->width(); + int h = widget()->height(); + + bool tl=true,tr=true,bl=true,br=true; // is there a transparent rounded corner in top-left? etc + + QDesktopWidget *desktop=KApplication::desktop(); + // no transparent rounded corners if this window corner lines up with a screen corner + for(int screen=0; screen < desktop->numScreens(); ++screen) + { + QRect fullscreen(desktop->screenGeometry(screen)); + QRect window = geometry(); + + if(window.topLeft() == fullscreen.topLeft() ) tl = false; + if(window.topRight() == fullscreen.topRight() ) tr = false; + if(window.bottomLeft() == fullscreen.bottomLeft() ) bl = false; + if(window.bottomRight()== fullscreen.bottomRight() ) br = false; + } + + QRegion mask(0, 0, w, h); + + // Remove top-left corner. + if(tl) + { + mask -= cornerShape(WC_TopLeft); + } + // Remove top-right corner. + if(tr) + { + mask -= cornerShape(WC_TopRight); + } + // Remove top-left corner. + if(bl) + { + mask -= cornerShape(WC_BottomLeft); + } + // Remove top-right corner. + if(br) + { + mask -= cornerShape(WC_BottomRight); + } + + setMask( mask ); +} + +bool KCommonDecoration::eventFilter( QObject* o, QEvent* e ) +{ + if( o != widget()) + return false; + switch( e->type()) + { + case QEvent::Resize: + resizeEvent(static_cast<QResizeEvent*>(e) ); + return true; + case QEvent::Paint: + paintEvent( static_cast< QPaintEvent* >( e )); + return true; + case QEvent::MouseButtonDblClick: + mouseDoubleClickEvent( static_cast< QMouseEvent* >( e )); + return true; + case QEvent::MouseButtonPress: + processMousePressEvent( static_cast< QMouseEvent* >( e )); + return true; + case QEvent::Wheel: + wheelEvent( static_cast< QWheelEvent* >( e )); + return true; + default: + return false; + } +} + +const int SUPPORTED_WINDOW_TYPES_MASK = NET::NormalMask | NET::DesktopMask | NET::DockMask + | NET::ToolbarMask | NET::MenuMask | NET::DialogMask /*| NET::OverrideMask*/ | NET::TopMenuMask + | NET::UtilityMask | NET::SplashMask; + +bool KCommonDecoration::isToolWindow() const +{ + NET::WindowType type = windowType( SUPPORTED_WINDOW_TYPES_MASK ); + return ((type==NET::Toolbar)||(type==NET::Utility)||(type==NET::Menu)); +} + +QRect KCommonDecoration::titleRect() const +{ + int r_x, r_y, r_x2, r_y2; + widget()->rect().coords(&r_x, &r_y, &r_x2, &r_y2); + const int titleEdgeLeft = layoutMetric(LM_TitleEdgeLeft); + const int titleEdgeTop = layoutMetric(LM_TitleEdgeTop); + const int titleEdgeRight = layoutMetric(LM_TitleEdgeRight); + const int titleEdgeBottom = layoutMetric(LM_TitleEdgeBottom); + const int titleBorderLeft = layoutMetric(LM_TitleBorderLeft); + const int titleBorderRight = layoutMetric(LM_TitleBorderRight); + const int ttlHeight = layoutMetric(LM_TitleHeight); + const int titleEdgeBottomBottom = r_y+titleEdgeTop+ttlHeight+titleEdgeBottom-1; + return QRect(r_x+titleEdgeLeft+buttonsLeftWidth()+titleBorderLeft, r_y+titleEdgeTop, + r_x2-titleEdgeRight-buttonsRightWidth()-titleBorderRight-(r_x+titleEdgeLeft+buttonsLeftWidth()+titleBorderLeft), + titleEdgeBottomBottom-(r_y+titleEdgeTop) ); +} + + +KCommonDecorationButton::KCommonDecorationButton(ButtonType type, KCommonDecoration *parent, const char *name) + : QButton(parent->widget(), name), + m_decoration(parent), + m_type(type), + m_realizeButtons(LeftButton), + m_lastMouse(NoButton), + m_isLeft(true) +{ + setCursor(ArrowCursor); +} + +KCommonDecorationButton::~KCommonDecorationButton() +{ +} + +KCommonDecoration *KCommonDecorationButton::decoration() const +{ + return m_decoration; +} + +ButtonType KCommonDecorationButton::type() const +{ + return m_type; +} + +bool KCommonDecorationButton::isLeft() const +{ + return m_isLeft; +} + +void KCommonDecorationButton::setLeft(bool left) +{ + m_isLeft = left; +} + +void KCommonDecorationButton::setRealizeButtons(int btns) +{ + m_realizeButtons = btns; +} + +void KCommonDecorationButton::setSize(const QSize &s) +{ + if (!m_size.isValid() || s != size() ) { + m_size = s; + + setFixedSize(m_size); + reset(SizeChange); + } +} + +QSize KCommonDecorationButton::sizeHint() const +{ + return m_size; +} + +void KCommonDecorationButton::setTipText(const QString &tip) { + QToolTip::remove(this ); + QToolTip::add(this, tip ); +} + +void KCommonDecorationButton::setToggleButton(bool toggle) +{ + QButton::setToggleButton(toggle); + reset(ToggleChange); +} + +void KCommonDecorationButton::setOn(bool on) +{ + if (on != isOn() ) { + QButton::setOn(on); + reset(StateChange); + } +} + +void KCommonDecorationButton::mousePressEvent(QMouseEvent* e) +{ + m_lastMouse = e->button(); + // pass on event after changing button to LeftButton + QMouseEvent me(e->type(), e->pos(), e->globalPos(), + (e->button()&m_realizeButtons)?LeftButton:NoButton, e->state()); + + QButton::mousePressEvent(&me); +} + +void KCommonDecorationButton::mouseReleaseEvent(QMouseEvent* e) +{ + m_lastMouse = e->button(); + // pass on event after changing button to LeftButton + QMouseEvent me(e->type(), e->pos(), e->globalPos(), + (e->button()&m_realizeButtons)?LeftButton:NoButton, e->state()); + + QButton::mouseReleaseEvent(&me); +} |