diff options
Diffstat (limited to 'kwin/lib')
-rw-r--r-- | kwin/lib/Makefile.am | 20 | ||||
-rw-r--r-- | kwin/lib/kcommondecoration.cpp | 966 | ||||
-rw-r--r-- | kwin/lib/kcommondecoration.h | 367 | ||||
-rw-r--r-- | kwin/lib/kdecoration.cpp | 444 | ||||
-rw-r--r-- | kwin/lib/kdecoration.h | 887 | ||||
-rw-r--r-- | kwin/lib/kdecoration_p.cpp | 235 | ||||
-rw-r--r-- | kwin/lib/kdecoration_p.h | 111 | ||||
-rw-r--r-- | kwin/lib/kdecoration_plugins_p.cpp | 199 | ||||
-rw-r--r-- | kwin/lib/kdecoration_plugins_p.h | 77 | ||||
-rw-r--r-- | kwin/lib/kdecorationfactory.cpp | 85 | ||||
-rw-r--r-- | kwin/lib/kdecorationfactory.h | 120 |
11 files changed, 3511 insertions, 0 deletions
diff --git a/kwin/lib/Makefile.am b/kwin/lib/Makefile.am new file mode 100644 index 000000000..bb584e25a --- /dev/null +++ b/kwin/lib/Makefile.am @@ -0,0 +1,20 @@ +# FRAME libkwin??? +lib_LTLIBRARIES = libkdecorations.la + +libkdecorations_la_SOURCES = kdecoration.cpp kdecoration_p.cpp kdecoration_plugins_p.cpp \ + kdecorationfactory.cpp kcommondecoration.cpp +libkdecorations_la_LIBADD = $(LIB_KDECORE) +libkdecorations_la_LDFLAGS = $(all_libraries) -version-info 1:0:0 -no-undefined + +# FRAME +include_HEADERS = kdecoration.h kdecoration_p.h kdecoration_plugins_p.h \ + kdecorationfactory.h kcommondecoration.h + +INCLUDES = $(all_includes) +METASOURCES = AUTO + +include ../../admin/Doxyfile.am + +messages: rc.cpp + $(XGETTEXT) `find . -name \*.cpp` -o $(podir)/kwin_lib.pot + -rm rc.cpp 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); +} diff --git a/kwin/lib/kcommondecoration.h b/kwin/lib/kcommondecoration.h new file mode 100644 index 000000000..9495cf148 --- /dev/null +++ b/kwin/lib/kcommondecoration.h @@ -0,0 +1,367 @@ +/* + 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. + */ + +#ifndef KCOMMONDECORATION_H +#define KCOMMONDECORATION_H + +#include <qbutton.h> +#include <qvaluevector.h> + +#include "kdecoration.h" + +class KDecorationBridge; +class KDecorationFactory; + +enum ButtonType { + HelpButton=0, + MaxButton, + MinButton, + CloseButton, + MenuButton, + OnAllDesktopsButton, + AboveButton, + BelowButton, + ShadeButton, + NumButtons +}; + +class KCommonDecorationButton; + +class KCommonDecorationButtonPrivate; +class KCommonDecorationPrivate; + +/** + * This class eases development of decorations by implementing parts of KDecoration + * which are error prone and common for most decorations. + * It takes care of the window layout, button/action handling, and window mask creation. + */ +class KWIN_EXPORT KCommonDecoration : public KDecoration +{ + Q_OBJECT + + public: + KCommonDecoration(KDecorationBridge* bridge, KDecorationFactory* factory); + virtual ~KCommonDecoration(); + + /** + * Used to calculate the decoration layout. The basic layout looks like this: + * + * Window: + * _______________________________________________________________ + * | LM_TitleEdgeTop | + * |_______________________________________________________________| + * | LM_TitleEdgeLeft | [title] | LM_TitleEdgeRight | + * |__________________|________________________|___________________| + * | LM_TitleEdgeBottom | + * |_______________________________________________________________| + * | | | | + * | | | | + * | | | | + * |LM_BorderLeft LM_BorderRight| + * |_|___________________________________________________________|_| + * | LM_BorderBottom | + * |_______________________________________________________________| + * + * Title: + * ___________________________________________________________________________________ + * | LM_ButtonMarginTop | | LM_ButtonMarginTop | + * |________________________________| |_________________________________| + * | [Buttons] | LM_TitleBorderLeft | LM_TitleHeight | LM_TitleBorderRight | [Buttons] | + * |___________|____________________|________________|_____________________|___________| + * + * Buttons: + * _____________________________________________________________________________________________ + * | button | spacing | button | spacing | explicit spacer | spacing | ... | spacing | button | + * |________|_________|________|_________|_________________|_________|________|_________|________| + * + * @see layoutMetric() + */ + enum LayoutMetric + { + LM_BorderLeft, + LM_BorderRight, + LM_BorderBottom, + LM_TitleHeight, + LM_TitleBorderLeft, + LM_TitleBorderRight, + LM_TitleEdgeLeft, + LM_TitleEdgeRight, + LM_TitleEdgeTop, + LM_TitleEdgeBottom, + LM_ButtonWidth, + LM_ButtonHeight, + LM_ButtonSpacing, + LM_ExplicitButtonSpacer, + LM_ButtonMarginTop + }; + + enum DecorationBehaviour + { + DB_MenuClose, ///< Close window on double clicking the menu + DB_WindowMask, ///< Set a mask on the window + DB_ButtonHide ///< Hide buttons when there is not enough space in the titlebar + }; + + enum WindowCorner + { + WC_TopLeft, + WC_TopRight, + WC_BottomLeft, + WC_BottomRight + }; + + /** + * The name of the decoration used in the decoration preview. + */ + virtual QString visibleName() const = 0; + /** + * The default title button order on the left. + * @see KDecoration::titleButtonsLeft() + * @see KDecoration::titleButtonsRight() + */ + virtual QString defaultButtonsLeft() const = 0; + /** + * The default title button order on the left. + * @see KDecoration::titleButtonsLeft() + * @see KDecoration::titleButtonsRight() + */ + virtual QString defaultButtonsRight() const = 0; + + /** + * This controls whether some specific behaviour should be enabled or not. + * @see DecorationBehaviour + */ + virtual bool decorationBehaviour(DecorationBehaviour behaviour) const; + + /** + * This controls the layout of the decoration in various ways. It is + * possible to have a different layout for different window states. + * @param lm The layout element. + * @param respectWindowState Whether window states should be taken into account or a "default" state should be assumed. + * @param button For LM_ButtonWidth and LM_ButtonHeight, the button. + */ + virtual int layoutMetric(LayoutMetric lm, bool respectWindowState = true, const KCommonDecorationButton *button = 0) const; + + /** + * Create a new title bar button. KCommonDecoration takes care of memory management. + * @return a pointer to the button, or 0 if the button should not be created. + */ + virtual KCommonDecorationButton *createButton(ButtonType type) = 0; + + /** + * @return the mask for the specific window corner. + */ + virtual QRegion cornerShape(WindowCorner corner); + + /** + * This updates the window mask using the information provided by + * cornerShape(). Edges which are aligned to screen corners are not + * shaped for better usability (remember to paint these areas in paintEvent(), too). + * You normally don't want/need to reimplement updateWindowShape(). + * @see cornerShape() + */ + virtual void updateWindowShape(); + + /** + * Draw the window decoration. + */ + virtual void paintEvent(QPaintEvent *e) = 0; + + /** + * This is used to update the painting of the title bar after the caption has been changed. + * Reimplement for a more efficient implementation (default calls update() on the whole decoration). + */ + virtual void updateCaption(); + + int buttonsLeftWidth() const; + int buttonsRightWidth() const; + + /** + * TODO: remove? + */ + void updateLayout() const; + /** + * Makes sure all buttons are repainted. + */ + void updateButtons() const; + /** + * Manually call reset() on each button. + */ + void resetButtons() const; + + /** + * Convenience method. + * @returns true if the window type is NET::Toolbar, NET::Utility, or NET::Menu + */ + bool isToolWindow() const; + /** + * Convenience method. + * @returns the title rect. + */ + QRect titleRect() const; + + public: + /** + * Handles widget and layout creation, call the base implementation when subclassing this member. + */ + virtual void init(); + /** + * Handles SettingButtons, call the base implementation when subclassing this member. + */ + virtual void reset( unsigned long changed ); + virtual void borders( int& left, int& right, int& top, int& bottom ) const; + virtual void show(); + virtual void resize(const QSize& s); + virtual QSize minimumSize() const; + virtual void maximizeChange(); + virtual void desktopChange(); + virtual void shadeChange(); + virtual void iconChange(); + virtual void activeChange(); + virtual void captionChange(); + public slots: + void keepAboveChange(bool above); + void keepBelowChange(bool below); + void slotMaximize(); + void slotShade(); + void slotKeepAbove(); + void slotKeepBelow(); + void menuButtonPressed(); + void menuButtonReleased(); + public: + virtual Position mousePosition(const QPoint &point) const; + + virtual bool eventFilter( QObject* o, QEvent* e ); + virtual void resizeEvent(QResizeEvent *e); + virtual void mouseDoubleClickEvent(QMouseEvent *e); + virtual void wheelEvent(QWheelEvent *e); + + private: + void resetLayout(); + + void moveWidget(int x, int y, QWidget *widget) const; + void resizeWidget(int w, int h, QWidget *widget) const; + + typedef QValueVector <KCommonDecorationButton*> ButtonContainer; ///< If the entry is 0, it's a spacer. + int buttonContainerWidth(const ButtonContainer &btnContainer, bool countHidden = false) const; + void addButtons(ButtonContainer &btnContainer, const QString& buttons, bool isLeft); + + KCommonDecorationButton *m_button[NumButtons]; + + ButtonContainer m_buttonsLeft; + ButtonContainer m_buttonsRight; + + QWidget *m_previewWidget; + + // button hiding for small windows + void calcHiddenButtons(); + int btnHideMinWidth; + int btnHideLastWidth; + + bool closing; // for menu doubleclick closing... + + KCommonDecorationPrivate *d; +}; + +/** + * Title bar buttons of KCommonDecoration need to inherit this class. + */ +class KWIN_EXPORT KCommonDecorationButton : public QButton +{ + friend class KCommonDecoration; + + public: + KCommonDecorationButton(ButtonType type, KCommonDecoration *parent, const char *name); + virtual ~KCommonDecorationButton(); + + /** + * These flags specify what has changed, e.g. the reason for a reset(). + */ + enum + { + ManualReset = 1 << 0, ///< The button might want to do a full reset for some reason... + SizeChange = 1 << 1, ///< The button size changed @see setSize() + ToggleChange = 1 << 2, ///< The button toggle state has changed @see setToggleButton() + StateChange = 1 << 3, ///< The button has been set pressed or not... @see setOn() + IconChange = 1 << 4, ///< The window icon has been changed + DecorationReset = 1 << 5 ///< E.g. when decoration colors have changed + }; + /** + * Initialize the button after size change etc. + */ + virtual void reset(unsigned long changed) = 0; + /** + * @returns the KCommonDecoration the button belongs to. + */ + KCommonDecoration *decoration() const; + /** + * @returns the button type. + * @see ButtonType + */ + ButtonType type() const; + + /** + * Whether the button is left of the titlebar or not. + */ + bool isLeft() const; + + /** + * Set which mouse buttons the button should honor. Used e.g. to prevent accidental right mouse clicks. + */ + void setRealizeButtons(int btns); + /** + * Set the button size. + */ + void setSize(const QSize &s); + /** + * Set/update the button's tool tip + */ + void setTipText(const QString &tip); + /** + * The mouse button that has been clicked last time. + */ + ButtonState lastMousePress() const { return m_lastMouse; } + + QSize sizeHint() const; + + protected: + void setToggleButton(bool toggle); + void setOn(bool on); + void setLeft(bool left); + void mousePressEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + + private: + KCommonDecoration *m_decoration; + ButtonType m_type; + int m_realizeButtons; + QSize m_size; + ButtonState m_lastMouse; + + bool m_isLeft; + + KCommonDecorationButtonPrivate *d; +}; + +#endif // KCOMMONDECORATION_H diff --git a/kwin/lib/kdecoration.cpp b/kwin/lib/kdecoration.cpp new file mode 100644 index 000000000..c7b3d6929 --- /dev/null +++ b/kwin/lib/kdecoration.cpp @@ -0,0 +1,444 @@ +/***************************************************************** +This file is part of the KDE project. + +Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org> + +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 "kdecoration.h" + +#include <kdebug.h> +#include <qapplication.h> +#include <kglobal.h> +#include <assert.h> +#if defined Q_WS_X11 && ! defined K_WS_QTONLY +#include <X11/Xlib.h> +#include <fixx11h.h> +#endif + +#include "kdecoration_p.h" +#include "kdecorationfactory.h" + +KDecorationOptions* KDecoration::options_; + +KDecoration::KDecoration( KDecorationBridge* bridge, KDecorationFactory* factory ) + : bridge_( bridge ), + w_( NULL ), + factory_( factory ) + { + factory->addDecoration( this ); + } + +KDecoration::~KDecoration() + { + factory()->removeDecoration( this ); + delete w_; + } + +const KDecorationOptions* KDecoration::options() + { + return options_; + } + +void KDecoration::createMainWidget( WFlags flags ) + { + // FRAME check flags? + setMainWidget( new QWidget( initialParentWidget(), "decoration widget", initialWFlags() | flags )); + } + +void KDecoration::setMainWidget( QWidget* w ) + { + assert( w_ == NULL ); + w_ = w; + w->setMouseTracking( true ); + widget()->resize( geometry().size()); + } + +QWidget* KDecoration::initialParentWidget() const + { + return bridge_->initialParentWidget(); + } + +Qt::WFlags KDecoration::initialWFlags() const + { + return bridge_->initialWFlags(); + } + +bool KDecoration::isActive() const + { + return bridge_->isActive(); + } + +bool KDecoration::isCloseable() const + { + return bridge_->isCloseable(); + } + +bool KDecoration::isMaximizable() const + { + return bridge_->isMaximizable(); + } + +KDecoration::MaximizeMode KDecoration::maximizeMode() const + { + return bridge_->maximizeMode(); + } + +bool KDecoration::isMinimizable() const + { + return bridge_->isMinimizable(); + } + +bool KDecoration::providesContextHelp() const + { + return bridge_->providesContextHelp(); + } + +int KDecoration::desktop() const + { + return bridge_->desktop(); + } + +bool KDecoration::isModal() const + { + return bridge_->isModal(); + } + +bool KDecoration::isShadeable() const + { + return bridge_->isShadeable(); + } + +bool KDecoration::isShade() const + { + return bridge_->isShade(); + } + +bool KDecoration::isSetShade() const + { + return bridge_->isSetShade(); + } + +bool KDecoration::keepAbove() const + { + return bridge_->keepAbove(); + } + +bool KDecoration::keepBelow() const + { + return bridge_->keepBelow(); + } + +bool KDecoration::isMovable() const + { + return bridge_->isMovable(); + } + +bool KDecoration::isResizable() const + { + return bridge_->isResizable(); + } + +NET::WindowType KDecoration::windowType( unsigned long supported_types ) const + { // this one is also duplicated in KDecorationFactory + return bridge_->windowType( supported_types ); + } + +QIconSet KDecoration::icon() const + { + return bridge_->icon(); + } + +QString KDecoration::caption() const + { + return bridge_->caption(); + } + +void KDecoration::processMousePressEvent( QMouseEvent* e ) + { + return bridge_->processMousePressEvent( e ); + } + +void KDecoration::showWindowMenu( const QRect &pos ) + { + bridge_->showWindowMenu( pos ); + } + +void KDecoration::showWindowMenu( QPoint pos ) + { + bridge_->showWindowMenu( pos ); + } + +void KDecoration::performWindowOperation( WindowOperation op ) + { + bridge_->performWindowOperation( op ); + } + +void KDecoration::setMask( const QRegion& reg, int mode ) + { + bridge_->setMask( reg, mode ); + } + +void KDecoration::clearMask() + { + bridge_->setMask( QRegion(), 0 ); + } + +bool KDecoration::isPreview() const + { + return bridge_->isPreview(); + } + +QRect KDecoration::geometry() const + { + return bridge_->geometry(); + } + +QRect KDecoration::iconGeometry() const + { + return bridge_->iconGeometry(); + } + +QRegion KDecoration::unobscuredRegion( const QRegion& r ) const + { + return bridge_->unobscuredRegion( r ); + } + +QWidget* KDecoration::workspaceWidget() const + { + return bridge_->workspaceWidget(); + } + +WId KDecoration::windowId() const + { + return bridge_->windowId(); + } + +void KDecoration::closeWindow() + { + bridge_->closeWindow(); + } + +void KDecoration::maximize( ButtonState button ) + { + performWindowOperation( options()->operationMaxButtonClick( button )); + } + +void KDecoration::maximize( MaximizeMode mode ) + { + bridge_->maximize( mode ); + } + +void KDecoration::minimize() + { + bridge_->minimize(); + } + +void KDecoration::showContextHelp() + { + bridge_->showContextHelp(); + } + +void KDecoration::setDesktop( int desktop ) + { + bridge_->setDesktop( desktop ); + } + +void KDecoration::toggleOnAllDesktops() + { + if( isOnAllDesktops()) + setDesktop( bridge_->currentDesktop()); + else + setDesktop( NET::OnAllDesktops ); + } + +void KDecoration::titlebarDblClickOperation() + { + bridge_->titlebarDblClickOperation(); + } + +void KDecoration::titlebarMouseWheelOperation( int delta ) + { + bridge_->titlebarMouseWheelOperation( delta ); + } + +void KDecoration::setShade( bool set ) + { + bridge_->setShade( set ); + } + +void KDecoration::setKeepAbove( bool set ) + { + bridge_->setKeepAbove( set ); + } + +void KDecoration::setKeepBelow( bool set ) + { + bridge_->setKeepBelow( set ); + } + +bool KDecoration::drawbound( const QRect&, bool ) + { + return false; + } + +bool KDecoration::animateMinimize( bool ) + { + return false; + } + +bool KDecoration::windowDocked( Position ) + { + return false; + } + +void KDecoration::helperShowHide( bool show ) + { + bridge_->helperShowHide( show ); + } + +void KDecoration::reset( unsigned long ) + { + } + +void KDecoration::grabXServer() + { + bridge_->grabXServer( true ); + } + +void KDecoration::ungrabXServer() + { + bridge_->grabXServer( false ); + } + +KDecoration::Position KDecoration::mousePosition( const QPoint& p ) const +{ + const int range = 16; + int bleft, bright, btop, bbottom; + borders( bleft, bright, btop, bbottom ); + btop = KMIN( btop, 4 ); // otherwise whole titlebar would have resize cursor + + Position m = PositionCenter; + + if ( ( p.x() > bleft && p.x() < widget()->width() - bright ) + && ( p.y() > btop && p.y() < widget()->height() - bbottom ) ) + return PositionCenter; + + if ( p.y() <= KMAX( range, btop ) && p.x() <= KMAX( range, bleft )) + m = PositionTopLeft; + else if ( p.y() >= widget()->height()- KMAX( range, bbottom ) + && p.x() >= widget()->width()- KMAX( range, bright )) + m = PositionBottomRight; + else if ( p.y() >= widget()->height()- KMAX( range, bbottom ) && p.x() <= KMAX( range, bleft )) + m = PositionBottomLeft; + else if ( p.y() <= KMAX( range, btop ) && p.x() >= widget()->width()- KMAX( range, bright )) + m = PositionTopRight; + else if ( p.y() <= btop ) + m = PositionTop; + else if ( p.y() >= widget()->height()-bbottom ) + m = PositionBottom; + else if ( p.x() <= bleft ) + m = PositionLeft; + else if ( p.x() >= widget()->width()-bright ) + m = PositionRight; + else + m = PositionCenter; + return m; +} + +KDecorationOptions::KDecorationOptions() + { + assert( KDecoration::options_ == NULL ); + KDecoration::options_ = this; + } + +KDecorationOptions::~KDecorationOptions() + { + assert( KDecoration::options_ == this ); + KDecoration::options_ = NULL; + } + +const QColor& KDecorationOptions::color(ColorType type, bool active) const +{ + return(d->colors[type + (active ? 0 : NUM_COLORS)]); +} + +const QFont& KDecorationOptions::font(bool active, bool small) const +{ + if ( small ) + return(active ? d->activeFontSmall : d->inactiveFontSmall); + else + return(active ? d->activeFont : d->inactiveFont); +} + +const QColorGroup& KDecorationOptions::colorGroup(ColorType type, bool active) const +{ + int idx = type + (active ? 0 : NUM_COLORS); + if(d->cg[idx]) + return(*d->cg[idx]); + d->cg[idx] = new QColorGroup(Qt::black, d->colors[idx], d->colors[idx].light(150), + d->colors[idx].dark(), d->colors[idx].dark(120), + Qt::black, QApplication::palette().active(). + base()); + return(*d->cg[idx]); +} + +bool KDecorationOptions::customButtonPositions() const +{ + return d->custom_button_positions; +} + +QString KDecorationOptions::titleButtonsLeft() const +{ + return d->title_buttons_left; +} + +QString KDecorationOptions::titleButtonsRight() const +{ + return d->title_buttons_right; +} + +bool KDecorationOptions::showTooltips() const +{ + return d->show_tooltips; +} + +KDecorationOptions::BorderSize KDecorationOptions::preferredBorderSize( KDecorationFactory* factory ) const +{ + assert( factory != NULL ); + if( d->cached_border_size == BordersCount ) // invalid + d->cached_border_size = d->findPreferredBorderSize( d->border_size, + factory->borderSizes()); + return d->cached_border_size; +} + +bool KDecorationOptions::moveResizeMaximizedWindows() const +{ + return d->move_resize_maximized_windows; +} + +KDecorationDefines::WindowOperation KDecorationOptions::operationMaxButtonClick( Qt::ButtonState button ) const + { + return button == Qt::RightButton? d->OpMaxButtonRightClick : + button == Qt::MidButton? d->OpMaxButtonMiddleClick : + d->OpMaxButtonLeftClick; + } + +#include "kdecoration.moc" diff --git a/kwin/lib/kdecoration.h b/kwin/lib/kdecoration.h new file mode 100644 index 000000000..2fd1fc451 --- /dev/null +++ b/kwin/lib/kdecoration.h @@ -0,0 +1,887 @@ +/***************************************************************** +This file is part of the KDE project. + +Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org> + +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. +******************************************************************/ + +#ifndef KDECORATION_H +#define KDECORATION_H + +#include <qcolor.h> +#include <qfont.h> +#include <qobject.h> +#include <qiconset.h> +#include <netwm_def.h> +#include <kdeversion.h> + +class KDecorationOptionsPrivate; +class KDecorationBridge; +class KDecorationPrivate; +class KDecorationFactory; + +#define KWIN_EXPORT KDE_EXPORT + +/** + * This class provides a namespace for all decoration related classes. + * All shared types are defined here. + * @since 3.2 + */ +class KWIN_EXPORT KDecorationDefines +{ +public: + /** + * These values represent positions inside an area + */ + enum Position + { // without prefix, they'd conflict with Qt::TopLeft etc. :( + PositionCenter = 0x00, + PositionLeft = 0x01, + PositionRight = 0x02, + PositionTop = 0x04, + PositionBottom = 0x08, + PositionTopLeft = PositionLeft | PositionTop, + PositionTopRight = PositionRight | PositionTop, + PositionBottomLeft = PositionLeft | PositionBottom, + PositionBottomRight = PositionRight | PositionBottom + }; + /** + * Maximize mode. These values specify how a window is maximized. + */ + // these values are written to session files, don't change the order + enum MaximizeMode + { + MaximizeRestore = 0, ///< The window is not maximized in any direction. + MaximizeVertical = 1, ///< The window is maximized vertically. + MaximizeHorizontal = 2, ///< The window is maximized horizontally. + /// Equal to @p MaximizeVertical | @p MaximizeHorizontal + MaximizeFull = MaximizeVertical | MaximizeHorizontal + }; + + enum WindowOperation + { + MaximizeOp = 5000, + RestoreOp, + MinimizeOp, + MoveOp, + UnrestrictedMoveOp, + ResizeOp, + UnrestrictedResizeOp, + CloseOp, + OnAllDesktopsOp, + ShadeOp, + KeepAboveOp, + KeepBelowOp, + OperationsOp, + WindowRulesOp, + ToggleStoreSettingsOp = WindowRulesOp, ///< @obsolete + HMaximizeOp, + VMaximizeOp, + LowerOp, + FullScreenOp, + NoBorderOp, + NoOp, + SetupWindowShortcutOp, + ApplicationRulesOp ///< @since 3.5 + }; + /** + * Basic color types that should be recognized by all decoration styles. + * Decorations are not required to implement all the colors, but for the ones that + * are implemented the color setting for them should be obeyed. + */ + enum ColorType + { + ColorTitleBar, ///< The color for the titlebar + ColorTitleBlend, ///< The blend color for the titlebar + ColorFont, ///< The titlebar text color + ColorButtonBg, ///< The color to use for the titlebar buttons + ColorFrame, ///< The color for the window frame (border) + ColorHandle, ///< The color for the resize handle + NUM_COLORS + }; + + /** + * These flags specify which settings changed when rereading settings. + * Each setting in class KDecorationOptions specifies its matching flag. + */ + enum + { + SettingDecoration = 1 << 0, ///< The decoration was changed + SettingColors = 1 << 1, ///< The color palette was changed + SettingFont = 1 << 2, ///< The titlebar font was changed + SettingButtons = 1 << 3, ///< The button layout was changed + SettingTooltips = 1 << 4, ///< The tooltip setting was changed + SettingBorder = 1 << 5 ///< The border size setting was changed + }; + + /** + * Border size. KDecorationOptions::preferredBorderSize() returns + * one of these values. + */ + enum BorderSize + { + BorderTiny, ///< Minimal borders + BorderNormal, ///< Standard size borders, the default setting + BorderLarge, ///< Larger borders + BorderVeryLarge, ///< Very large borders + BorderHuge, ///< Huge borders + BorderVeryHuge, ///< Very huge borders + BorderOversized, ///< Oversized borders + BordersCount ///< @internal + }; + + /** + * Used to find out which features the decoration supports. + * @see KDecorationFactory::supports() + */ + enum Ability + { + AbilityAnnounceButtons = 0, ///< decoration supports AbilityButton* values (always use) + AbilityButtonMenu = 1000, ///< decoration supports the menu button + AbilityButtonOnAllDesktops = 1001, ///< decoration supports the on all desktops button + AbilityButtonSpacer = 1002, ///< decoration supports inserting spacers between buttons + AbilityButtonHelp = 1003, ///< decoration supports what's this help button + AbilityButtonMinimize = 1004, ///< decoration supports a minimize button + AbilityButtonMaximize = 1005, ///< decoration supports a maximize button + AbilityButtonClose = 1006, ///< decoration supports a close button + AbilityButtonAboveOthers = 1007, ///< decoration supports an above button + AbilityButtonBelowOthers = 1008, ///< decoration supports a below button + AbilityButtonShade = 1009, ///< decoration supports a shade button + AbilityButtonResize = 1010, ///< decoration supports a resize button + ABILITY_DUMMY = 10000000 + }; + + enum Requirement { REQUIREMENT_DUMMY = 1000000 }; +}; + +class KDecorationProvides + : public KDecorationDefines + { + public: + virtual bool provides( Requirement req ) = 0; + }; + +/** + * This class holds various configuration settings for the decoration. + * It is accessible from the decorations either as KDecoration::options() + * or KDecorationFactory::options(). + * @since 3.2 + */ +class KWIN_EXPORT KDecorationOptions : public KDecorationDefines + { +public: + KDecorationOptions(); + virtual ~KDecorationOptions(); + /** + * Returns the color that should be used for the given part of the decoration. + * The changed flags for this setting is SettingColors. + * + * @param type The requested color type. + * @param active Whether the color should be for active or inactive windows. + */ + const QColor& color(ColorType type, bool active=true) const; + /** + * Returns a colorgroup using the given decoration color as the background. + * The changed flags for this setting is SettingColors. + * + * @param type The requested color type. + * @param active Whether to return the color for active or inactive windows. + */ + const QColorGroup& colorGroup(ColorType type, bool active=true) const; + /** + * Returns the active or inactive decoration font. + * The changed flags for this setting is SettingFont. + * + * @param active Whether to return the color for active or inactive windows. + * @param small If @a true, returns a font that's suitable for tool windows. + */ + const QFont& font(bool active=true, bool small = false) const; + /** + * Returns @a true if the style should use custom button positions + * The changed flags for this setting is SettingButtons. + * + * @see titleButtonsLeft + * @see titleButtonsRight + */ + bool customButtonPositions() const; + /** + * If customButtonPositions() returns true, titleButtonsLeft + * returns which buttons should be on the left side of the titlebar from left + * to right. Characters in the returned string have this meaning : + * @li 'M' menu button + * @li 'S' on_all_desktops button + * @li 'H' quickhelp button + * @li 'I' minimize ( iconify ) button + * @li 'A' maximize button + * @li 'X' close button + * @li 'F' keep_above_others button + * @li 'B' keep_below_others button + * @li 'L' shade button + * @li 'R' resize button + * @li '_' spacer + * + * The default ( which is also returned if customButtonPositions returns false ) + * is "MS". + * Unknown buttons in the returned string must be ignored. + * The changed flags for this setting is SettingButtons. + */ + QString titleButtonsLeft() const; + /** + * If customButtonPositions() returns true, titleButtonsRight + * returns which buttons should be on the right side of the titlebar from left + * to right. Characters in the return string have the same meaning like + * in titleButtonsLeft(). + * + * The default ( which is also returned if customButtonPositions returns false ) + * is "HIAX". + * Unknown buttons in the returned string must be ignored. + * The changed flags for this setting is SettingButtons. + */ + QString titleButtonsRight() const; + + /** + * @returns true if the style should use tooltips for window buttons + * The changed flags for this setting is SettingTooltips. + */ + bool showTooltips() const; + + /** + * The preferred border size selected by the user, e.g. for accessibility + * reasons, or when using high resolution displays. It's up to the decoration + * to decide which borders or if any borders at all will obey this setting. + * It is guaranteed that the returned value will be one of those + * returned by KDecorationFactory::borderSizes(), so if that one hasn't been + * reimplemented, BorderNormal is always returned. + * The changed flags for this setting is SettingBorder. + * @param factory the decoration factory used + */ + BorderSize preferredBorderSize( KDecorationFactory* factory ) const; + + /* + * When this functions returns false, moving and resizing of maximized windows + * is not allowed, and therefore the decoration is allowed to turn off (some of) + * its borders. + * The changed flags for this setting is SettingButtons. + */ + bool moveResizeMaximizedWindows() const; + + /** + * @internal + */ + WindowOperation operationMaxButtonClick( Qt::ButtonState button ) const; + + /** + * @internal + */ + virtual unsigned long updateSettings() = 0; // returns SettingXYZ mask + +protected: + /** + * @internal + */ + KDecorationOptionsPrivate* d; + }; + + +/** + * This is the base class for a decoration object. It provides functions + * that give various information about the decorated window, and also + * provides pure virtual functions for controlling the decoration that + * every decoration should implement. + * @since 3.2 + */ +class KWIN_EXPORT KDecoration + : public QObject, public KDecorationDefines + { + Q_OBJECT + public: + /** + * Constructs a KDecoration object. Both the arguments are passed from + * KDecorationFactory. Note that the initialization code of the decoration + * should be done in the init() method. + */ + KDecoration( KDecorationBridge* bridge, KDecorationFactory* factory ); + /** + * Destroys the KDecoration. + */ + virtual ~KDecoration(); + + // requests from decoration + + /** + * Returns the KDecorationOptions object, which is used to access + * configuration settings for the decoration. + */ + static const KDecorationOptions* options(); + /** + * Returns @a true if the decorated window is currently active. + */ + bool isActive() const; + /** + * Returns @a true if the decoration window can be closed by the user. + */ + bool isCloseable() const; + /** + * Returns @a true if the decorated window can be maximized. + */ + bool isMaximizable() const; + /** + * Returns the current maximization mode of the decorated window. + * Note that only fully maximized windows should be treated + * as "maximized" (e.g. if the maximize button has only two states). + */ + MaximizeMode maximizeMode() const; + /** + * Returns @a true if the decorated window can be minimized by the user. + */ + bool isMinimizable() const; + /** + * Return @a true if the decorated window can show context help + * (i.e. the decoration should provide the context help button). + */ + bool providesContextHelp() const; + /** + * Returns the number of the virtual desktop the decorated window + * is currently on (including NET::OnAllDesktops for being on all + * desktops). + */ + int desktop() const; + /** + * Convenience function that returns @a true if the window is on all + * virtual desktops. + */ + bool isOnAllDesktops() const; // convenience + /** + * Returns @a true if the decoration window is modal (usually a modal dialog). + */ + bool isModal() const; + /** + * Returns @a true if the decorated window can be shaded. + */ + bool isShadeable() const; + /** + * Returns @a true if the decorated window is currently shaded. + * If the window is e.g. hover unshaded, it's not considered to be shaded. + * This function should not be used for the shade titlebar button, use + * @ref isSetShade() instead. + * + * @see isSetShade + */ + bool isShade() const; + /** + * Returns @a true if the decorated window was set to be shaded. This function + * returns also true if the window is e.g. hover unshaded, so it doesn't + * always correspond to the actual window state. + * + * @see isShade + */ + bool isSetShade() const; + /** + * Returns @a true if the decorated window should be kept above other windows. + */ + bool keepAbove() const; + /** + * Returns @a true if the decorated window should be kept below other windows. + */ + bool keepBelow() const; + /** + * Returns @a true if the decorated window can be moved by the user. + */ + bool isMovable() const; + /** + * Returns @a true if the decorated window can be resized by the user. + */ + bool isResizable() const; + /** + * This function returns the window type of the decorated window. + * The argument to this function is a mask of all window types + * the decoration knows about (as the list of valid window types + * is extended over time, and fallback types are specified in order + * to support older code). For a description of all window types, + * see the definition of the NET::WindowType type. Note that + * some window types never have decorated windows. + * + * An example of usage: + * @code + * const unsigned long supported_types = NET::NormalMask | NET::DesktopMask + * | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask + * | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask; + * + * NET::WindowType type = windowType( supported_types ); + * + * if( type == NET::Utility || type == NET::Menu || type == NET::Toolbar ) + * // ... use smaller decorations for tool window types + * else + * // ... use normal decorations + * @endcode + */ + NET::WindowType windowType( unsigned long supported_types ) const; + /** + * Returns an icon set with the decorated window's icon. + */ + QIconSet icon() const; + /** + * Returns the decorated window's caption that should be shown in the titlebar. + */ + QString caption() const; + /** + * This function invokes the window operations menu. + * \param pos specifies the place on the screen where the menu should + * show up. The menu pops up at the bottom-left corner of the specified + * rectangle, unless there is no space, in which case the menu is + * displayed above the rectangle. + * + * \note Decorations that enable a double-click operation for the menu + * button must ensure to call \a showWindowMenu() with the \a pos + * rectangle set to the menu button geometry. + * IMPORTANT: As a result of this function, the decoration object that + * called it may be destroyed after the function returns. This means + * that the decoration object must either return immediately after + * calling showWindowMenu(), or it must use + * KDecorationFactory::exists() to check it's still valid. For example, + * the code handling clicks on the menu button should look similarly + * like this: + * + * \code + * KDecorationFactory* f = factory(); // needs to be saved before + * showWindowMenu( button[MenuButton]->mapToGlobal( menuPoint )); + * if( !f->exists( this )) // destroyed, return immediately + * return; + * button[MenuButton]->setDown(false); + * \endcode + */ + void showWindowMenu( const QRect &pos ); + + /** + * Overloaded version of the above. + */ + void showWindowMenu( QPoint pos ); + /** + * This function performs the given window operation. This function may destroy + * the current decoration object, just like showWindowMenu(). + */ + void performWindowOperation( WindowOperation op ); + /** + * If the decoration is non-rectangular, this function needs to be called + * to set the shape of the decoration. + * + * @param reg The shape of the decoration. + * @param mode The X11 values Unsorted, YSorted, YXSorted and YXBanded that specify + * the sorting of the rectangles, default value is Unsorted. + */ + void setMask( const QRegion& reg, int mode = 0 ); + /** + * This convenience function resets the shape mask. + */ + void clearMask(); // convenience + /** + * If this function returns @a true, the decorated window is used as a preview + * e.g. in the configuration module. In such case, the decoration can e.g. + * show some information in the window area. + */ + bool isPreview() const; + /** + * Returns the geometry of the decoration. + */ + QRect geometry() const; + /** + * Returns the icon geometry for the window, i.e. the geometry of the taskbar + * entry. This is used mainly for window minimize animations. Note that + * the geometry may be null. + */ + QRect iconGeometry() const; + /** + * Returns the intersection of the given region with the region left + * unobscured by the windows stacked above the current one. You can use + * this function to, for example, try to keep the titlebar visible if + * there is a hole available. The region returned is in the coordinate + * space of the decoration. + * @param r The region you want to check for holes + */ + QRegion unobscuredRegion( const QRegion& r ) const; + /** + * Returns the main workspace widget. The main purpose of this function is to + * allow painting the minimize animation or the transparent move bound on it. + */ + QWidget* workspaceWidget() const; + /** + * Returns the handle of the window that is being decorated. It is possible + * the returned value will be 0. + * IMPORTANT: This function is meant for special purposes, and it + * usually should not be used. The main purpose is finding out additional + * information about the window's state. Also note that different kinds + * of windows are decorated: Toplevel windows managed by the window manager, + * test window in the window manager decoration module, and possibly also + * other cases. + * Careless abuse of this function will usually sooner or later lead + * to problems. + * @since 3.4 + */ + WId windowId() const; + /** + * Convenience function that returns the width of the decoration. + */ + int width() const; // convenience + /** + * Convenience function that returns the height of the decoration. + */ + int height() const; // convenience + /** + * This function is the default handler for mouse events. All mouse events + * that are not handled by the decoration itself should be passed to it + * in order to make work operations like window resizing by dragging borders etc. + */ + void processMousePressEvent( QMouseEvent* e ); + + // requests to decoration + + /** + * This function is called immediately after the decoration object is created. + * Due to some technical reasons, initialization should be done here + * instead of in the constructor. + */ + virtual void init() = 0; // called once right after created + + /** + * This function should return mouse cursor position in the decoration. + * Positions at the edge will result in window resizing with mouse button + * pressed, center position will result in moving. + */ + virtual Position mousePosition( const QPoint& p ) const = 0; + + /** + * This function should return the distance from each window side to the inner + * window. The sizes may depend on the state of the decorated window, such as + * whether it's shaded. Decorations often turn off their bottom border when the + * window is shaded, and turn off their left/right/bottom borders when + * the window is maximized and moving and resizing of maximized windows is disabled. + * This function mustn't do any repaints or resizes. Also, if the sizes returned + * by this function don't match the real values, this may result in drawing errors + * or other problems. + * + * @see KDecorationOptions::moveResizeMaximizedWindows() + */ + // mustn't do any repaints, resizes or anything like that + virtual void borders( int& left, int& right, int& top, int& bottom ) const = 0; + /** + * This method is called by kwin when the style should resize the decoration window. + * The usual implementation is to resize the main widget of the decoration to the + * given size. + * + * @param s Specifies the new size of the decoration window. + */ + virtual void resize( const QSize& s ) = 0; + /** + * This function should return the minimum required size for the decoration. + * Note that the returned size shouldn't be too large, because it will be + * used to keep the decorated window at least as large. + */ + virtual QSize minimumSize() const = 0; + /** + * This function is called whenever the window either becomes or stops being active. + * Use isActive() to find out the current state. + */ + virtual void activeChange() = 0; + /** + * This function is called whenever the caption changes. Use caption() to get it. + */ + virtual void captionChange() = 0; + /** + * This function is called whenever the window icon changes. Use icon() to get it. + */ + virtual void iconChange() = 0; + /** + * This function is called whenever the maximalization state of the window changes. + * Use maximizeMode() to get the current state. + */ + virtual void maximizeChange() = 0; + /** + * This function is called whenever the desktop for the window changes. Use + * desktop() or isOnAllDesktops() to find out the current desktop + * on which the window is. + */ + virtual void desktopChange() = 0; + /** + * This function is called whenever the window is shaded or unshaded. Use + * isShade() to get the current state. + */ + virtual void shadeChange() = 0; +#if KDE_IS_VERSION( 3, 90, 0 ) +#warning Redo all the XYZChange() virtuals as signals. +#endif + signals: + /** + * This signal is emitted whenever the window's keep-above state changes. + * @since 3.3 + */ + void keepAboveChanged( bool ); + /** + * This signal is emitted whenever the window's keep-below state changes. + * @since 3.3 + */ + void keepBelowChanged( bool ); + public: + /** + * This function may be reimplemented to provide custom bound drawing + * for transparent moving or resizing of the window. + * @a False should be returned if the default implementation should be used. + * Note that if you e.g. paint the outline using a 5 pixels wide line, + * you should compensate for the 2 pixels that would make the window + * look larger. + * + * @param geom The geometry at this the bound should be drawn + * @param clear @a true if the bound should be cleared + * + * @see workspaceWidget() and geometry(). + */ + virtual bool drawbound( const QRect& geom, bool clear ); + /** + * This function may be reimplemented to provide custom minimize/restore animations + * The reimplementation is allowed to perform X server grabs if necessary + * (only using the functions provided by this API, no direct Xlib calls), but no + * futher event processing is allowed (i.e. no kapp->processEvents()). + * @a False should be returned if the default implementation should be used. + * Note that you should not use this function to force disabling of the animation. + * + * @see workspaceWidget(), geometry() and helperShowHide(). + */ + virtual bool animateMinimize( bool minimize ); + /** + * @internal Reserved. + */ + // TODO position will need also values for top+left+bottom etc. docking ? + virtual bool windowDocked( Position side ); + /** + * This function is called to reset the decoration on settings changes. + * It is usually invoked by calling KDecorationFactory::resetDecorations(). + * + * @param changed Specifies which settings were changed, given by the SettingXXX masks + */ + virtual void reset( unsigned long changed ); + + // special + + /** + * This should be the first function called in init() to specify + * the main widget of the decoration. The widget should be created + * with parent specified by initialParentWidget() and flags + * specified by initialWFlags(). + */ + void setMainWidget( QWidget* ); + /** + * Convenience functions that creates and sets a main widget as necessary. + * In such case, it's usually needed to install an event filter + * on the main widget to receive important events on it. + * + * @param flags Additional widget flags for the main widget. Note that only + * flags that affect widget drawing are allowed. Window type flags + * like WX11BypassWM or WStyle_NoBorder are forbidden. + */ + void createMainWidget( WFlags flags = 0 ); + /** + * The parent widget that should be used for the main widget. + */ + QWidget* initialParentWidget() const; + /** + * The flags that should be used when creating the main widget. + * It is possible to add more flags when creating the main widget, but only flags + * that affect widget drawing are allowed. Window type flags like WX11BypassWM + * or WStyle_NoBorder are forbidden. + */ + WFlags initialWFlags() const; + /** + * This function is only allowed to be called once from animateMinimize(). + * It can be used if the window should be shown or hidden at a specific + * time during the animation. It is forbidden to use this function + * for other purposes. + */ + void helperShowHide( bool show ); + /** + * Returns the main widget for the decoration. + */ + QWidget* widget(); + /** + * Returns the main widget for the decoration. + */ + const QWidget* widget() const; + /** + * Returns the factory that created this decoration. + */ + KDecorationFactory* factory() const; + /** + * Performs X server grab. It is safe to call it several times in a row. + */ + void grabXServer(); + /** + * Ungrabs X server (if the number of ungrab attempts matches the number of grab attempts). + */ + void ungrabXServer(); + public slots: + // requests from decoration + + /** + * This function can be called by the decoration to request + * closing of the decorated window. Note that closing the window + * also involves destroying the decoration. + * IMPORTANT: This function may destroy the current decoration object, + * just like showWindowMenu(). + */ + void closeWindow(); + /* + * Changes the maximize mode of the decorated window. This function should + * be preferred to the other maximize() overload for reacting on clicks + * on the maximize titlebar button. + * NOTE: This function is new in KDE3.3. In order to support also KDE3.2, + * it is recommended to use code like this: + * \code + * ButtonState button = ... ; + * #if KDE_IS_VERSION( 3, 3, 0 ) + * maximize( button ); + * #else + * if( button == MidButton ) + * maximize( maximizeMode() ^ MaximizeVertical ); + * else if( button == RightButton ) + * maximize( maximizeMode() ^ MaximizeHorizontal ); + * else + * maximize( maximizeMode() == MaximizeFull ? MaximizeRestore : MaximizeFull ); + * #endif + * \endcode + * @since 3.3 + */ +#if KDE_IS_VERSION( 3, 90, 0 ) +#warning Update the docs. +#endif + void maximize( ButtonState button ); + /** + * Set the maximize mode of the decorated window. + * @param mode The maximization mode to be set. + */ + void maximize( MaximizeMode mode ); + /** + * Minimize the decorated window. + */ + void minimize(); + /** + * Start showing context help in the window (i.e. the mouse will enter + * the what's this mode). + */ + void showContextHelp(); + /** + * Moves the window to the given desktop. Use NET::OnAllDesktops for making + * the window appear on all desktops. + */ + void setDesktop( int desktop ); + /** + * This function toggles the on-all-desktops state of the decorated window. + */ + void toggleOnAllDesktops(); // convenience + /** + * This function performs the operation configured as titlebar double click + * operation. + */ + void titlebarDblClickOperation(); + /** + * This function performs the operation configured as titlebar wheel mouse + * operation. + * @param delta the mouse wheel delta + * @since 3.5 + */ + void titlebarMouseWheelOperation( int delta ); + /** + * Shades or unshades the decorated window. + * @param set Whether the window should be shaded + */ + void setShade( bool set ); + /** + * Sets or reset keeping this window above others. + * @param set Whether to keep the window above others + */ + void setKeepAbove( bool set ); + /** + * Sets or reset keeping this window below others. + * @param set Whether to keep the window below others + */ + void setKeepBelow( bool set ); + /** + * @internal + */ + void emitKeepAboveChanged( bool above ) { emit keepAboveChanged( above ); } + /** + * @internal + */ + void emitKeepBelowChanged( bool below ) { emit keepBelowChanged( below ); } + private: + KDecorationBridge* bridge_; + QWidget* w_; + KDecorationFactory* factory_; + friend class KDecorationOptions; // for options_ + static KDecorationOptions* options_; + KDecorationPrivate* d; + }; + +inline +KDecorationDefines::MaximizeMode operator^( KDecorationDefines::MaximizeMode m1, KDecorationDefines::MaximizeMode m2 ) + { + return KDecorationDefines::MaximizeMode( int(m1) ^ int(m2) ); + } + +inline +KDecorationDefines::MaximizeMode operator&( KDecorationDefines::MaximizeMode m1, KDecorationDefines::MaximizeMode m2 ) + { + return KDecorationDefines::MaximizeMode( int(m1) & int(m2) ); + } + +inline +KDecorationDefines::MaximizeMode operator|( KDecorationDefines::MaximizeMode m1, KDecorationDefines::MaximizeMode m2 ) + { + return KDecorationDefines::MaximizeMode( int(m1) | int(m2) ); + } + +inline QWidget* KDecoration::widget() + { + return w_; + } + +inline const QWidget* KDecoration::widget() const + { + return w_; + } + +inline KDecorationFactory* KDecoration::factory() const + { + return factory_; + } + +inline bool KDecoration::isOnAllDesktops() const + { + return desktop() == NET::OnAllDesktops; + } + +inline int KDecoration::width() const + { + return geometry().width(); + } + +inline int KDecoration::height() const + { + return geometry().height(); + } + +#endif diff --git a/kwin/lib/kdecoration_p.cpp b/kwin/lib/kdecoration_p.cpp new file mode 100644 index 000000000..0117e4ec4 --- /dev/null +++ b/kwin/lib/kdecoration_p.cpp @@ -0,0 +1,235 @@ +/***************************************************************** +This file is part of the KDE project. + +Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org> + +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 "kdecoration_p.h" + +#include <kconfig.h> +#include <kglobalsettings.h> +#include <qpalette.h> +#include <qapplication.h> +#include <assert.h> + +KDecorationOptionsPrivate::KDecorationOptionsPrivate() + { + for(int i=0; i < NUM_COLORS*2; ++i) + cg[i] = NULL; + } + +KDecorationOptionsPrivate::~KDecorationOptionsPrivate() + { + int i; + for(i=0; i < NUM_COLORS*2; ++i) + { + if(cg[i]) + { + delete cg[i]; + cg[i] = NULL; + } + } + } + +void KDecorationOptionsPrivate::defaultKWinSettings() + { + title_buttons_left = "MS"; + title_buttons_right = "HIAX"; + custom_button_positions = false; + show_tooltips = true; + border_size = BorderNormal; + cached_border_size = BordersCount; // invalid + move_resize_maximized_windows = true; + OpMaxButtonRightClick = MaximizeOp; + OpMaxButtonMiddleClick = VMaximizeOp; + OpMaxButtonLeftClick = HMaximizeOp; + } + +unsigned long KDecorationOptionsPrivate::updateKWinSettings( KConfig* config ) + { + unsigned long changed = 0; + QString old_group = config->group(); + config->setGroup( "WM" ); + +// SettingColors + QColor old_colors[NUM_COLORS*2]; + for( int i = 0; + i < NUM_COLORS*2; + ++i ) + old_colors[ i ] = colors[ i ]; + + QPalette pal = QApplication::palette(); + // normal colors + colors[ColorFrame] = pal.active().background(); + colors[ColorFrame] = config->readColorEntry("frame", &colors[ColorFrame]); + colors[ColorHandle] = colors[ColorFrame]; + colors[ColorHandle] = config->readColorEntry("handle", &colors[ColorHandle]); + + // full button configuration (background, blend, and foreground + if(QPixmap::defaultDepth() > 8) + colors[ColorButtonBg] = colors[ColorFrame].light(130); + else + colors[ColorButtonBg] = colors[ColorFrame]; + colors[ColorButtonBg] = config->readColorEntry("activeTitleBtnBg", + &colors[ColorFrame]); + colors[ColorTitleBar] = pal.active().highlight(); + colors[ColorTitleBar] = config->readColorEntry("activeBackground", + &colors[ColorTitleBar]); + if(QPixmap::defaultDepth() > 8) + colors[ColorTitleBlend] = colors[ ColorTitleBar ].dark(110); + else + colors[ColorTitleBlend] = colors[ ColorTitleBar ]; + colors[ColorTitleBlend] = config->readColorEntry("activeBlend", + &colors[ColorTitleBlend]); + + colors[ColorFont] = pal.active().highlightedText(); + colors[ColorFont] = config->readColorEntry("activeForeground", &colors[ColorFont]); + + // inactive + colors[ColorFrame+NUM_COLORS] = config->readColorEntry("inactiveFrame", + &colors[ColorFrame]); + colors[ColorTitleBar+NUM_COLORS] = colors[ColorFrame]; + colors[ColorTitleBar+NUM_COLORS] = config-> + readColorEntry("inactiveBackground", &colors[ColorTitleBar+NUM_COLORS]); + + if(QPixmap::defaultDepth() > 8) + colors[ColorTitleBlend+NUM_COLORS] = colors[ ColorTitleBar+NUM_COLORS ].dark(110); + else + colors[ColorTitleBlend+NUM_COLORS] = colors[ ColorTitleBar+NUM_COLORS ]; + colors[ColorTitleBlend+NUM_COLORS] = + config->readColorEntry("inactiveBlend", &colors[ColorTitleBlend+NUM_COLORS]); + + // full button configuration + if(QPixmap::defaultDepth() > 8) + colors[ColorButtonBg+NUM_COLORS] = colors[ColorFrame+NUM_COLORS].light(130); + else + colors[ColorButtonBg+NUM_COLORS] = colors[ColorFrame+NUM_COLORS]; + colors[ColorButtonBg+NUM_COLORS] = + config->readColorEntry("inactiveTitleBtnBg", + &colors[ColorButtonBg]); + + colors[ColorHandle+NUM_COLORS] = + config->readColorEntry("inactiveHandle", &colors[ColorHandle]); + + colors[ColorFont+NUM_COLORS] = colors[ColorFrame].dark(); + colors[ColorFont+NUM_COLORS] = config->readColorEntry("inactiveForeground", + &colors[ColorFont+NUM_COLORS]); + + for( int i = 0; + i < NUM_COLORS*2; + ++i ) + if( old_colors[ i ] != colors[ i ] ) + changed |= SettingColors; + +// SettingFont + QFont old_activeFont = activeFont; + QFont old_inactiveFont = inactiveFont; + QFont old_activeFontSmall = activeFontSmall; + QFont old_inactiveFontSmall = inactiveFontSmall; + + QFont activeFontGuess = KGlobalSettings::windowTitleFont(); + + activeFont = config->readFontEntry("activeFont", &activeFontGuess); + inactiveFont = config->readFontEntry("inactiveFont", &activeFont); + + activeFontSmall = activeFont; + activeFontSmall.setPointSize(activeFont.pointSize() - 2); + activeFontSmall = config->readFontEntry("activeFontSmall", &activeFontSmall); + inactiveFontSmall = config->readFontEntry("inactiveFontSmall", &activeFontSmall); + + if( old_activeFont != activeFont + || old_inactiveFont != inactiveFont + || old_activeFontSmall != activeFontSmall + || old_inactiveFontSmall != inactiveFontSmall ) + changed |= SettingFont; + + config->setGroup( "Style" ); +// SettingsButtons + QString old_title_buttons_left = title_buttons_left; + QString old_title_buttons_right = title_buttons_right; + bool old_custom_button_positions = custom_button_positions; + custom_button_positions = config->readBoolEntry("CustomButtonPositions", false); + if (custom_button_positions) + { + title_buttons_left = config->readEntry("ButtonsOnLeft", "MS"); + title_buttons_right = config->readEntry("ButtonsOnRight", "HIAX"); + } + else + { + title_buttons_left = "MS"; + title_buttons_right = "HIAX"; + } + if( old_custom_button_positions != custom_button_positions + || ( custom_button_positions && + ( old_title_buttons_left != title_buttons_left + || old_title_buttons_right != title_buttons_right ))) + changed |= SettingButtons; + +// SettingTooltips + bool old_show_tooltips = show_tooltips; + show_tooltips = config->readBoolEntry("ShowToolTips", true); + if( old_show_tooltips != show_tooltips ) + changed |= SettingTooltips; + +// SettingBorder + + BorderSize old_border_size = border_size; + int border_size_num = config->readNumEntry( "BorderSize", BorderNormal ); + if( border_size_num >= 0 && border_size_num < BordersCount ) + border_size = static_cast< BorderSize >( border_size_num ); + else + border_size = BorderNormal; + if( old_border_size != border_size ) + changed |= SettingBorder; + cached_border_size = BordersCount; // invalid + + config->setGroup( "Windows" ); + bool old_move_resize_maximized_windows = move_resize_maximized_windows; + move_resize_maximized_windows = config->readBoolEntry( "MoveResizeMaximizedWindows", false ); + if( old_move_resize_maximized_windows != move_resize_maximized_windows ) + changed |= SettingBorder; + +// destroy cached values + int i; + for(i=0; i < NUM_COLORS*2; ++i) + { + if(cg[i]) + { + delete cg[i]; + cg[i] = NULL; + } + } + + config->setGroup( old_group ); + + return changed; + } + +KDecorationDefines::BorderSize KDecorationOptionsPrivate::findPreferredBorderSize( BorderSize size, + QValueList< BorderSize > sizes ) const + { + for( QValueList< BorderSize >::ConstIterator it = sizes.begin(); + it != sizes.end(); + ++it ) + if( size <= *it ) // size is either a supported size, or *it is the closest larger supported + return *it; + return sizes.last(); // size is larger than all supported ones, return largest + } diff --git a/kwin/lib/kdecoration_p.h b/kwin/lib/kdecoration_p.h new file mode 100644 index 000000000..8d0e5e15a --- /dev/null +++ b/kwin/lib/kdecoration_p.h @@ -0,0 +1,111 @@ +/***************************************************************** +This file is part of the KDE project. + +Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org> + +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. +******************************************************************/ + +#ifndef KDECORATION_P_H +#define KDECORATION_P_H + +// +// This header file is internal. I mean it. +// + +#include "kdecoration.h" +#include <qwidget.h> +#include <qvaluelist.h> + +class KConfig; + +class KWIN_EXPORT KDecorationOptionsPrivate : public KDecorationDefines + { + public: + KDecorationOptionsPrivate(); + virtual ~KDecorationOptionsPrivate(); + void defaultKWinSettings(); // shared implementation + unsigned long updateKWinSettings( KConfig* ); // shared implementation + BorderSize findPreferredBorderSize( BorderSize size, QValueList< BorderSize > ) const; // shared implementation + + QColor colors[NUM_COLORS*2]; + QColorGroup *cg[NUM_COLORS*2]; + QFont activeFont, inactiveFont, activeFontSmall, inactiveFontSmall; + QString title_buttons_left; + QString title_buttons_right; + bool custom_button_positions; + bool show_tooltips; + BorderSize border_size, cached_border_size; + bool move_resize_maximized_windows; + WindowOperation OpMaxButtonRightClick; + WindowOperation OpMaxButtonMiddleClick; + WindowOperation OpMaxButtonLeftClick; + }; + +class KDecorationBridge : public KDecorationDefines + { + public: + virtual bool isActive() const = 0; + virtual bool isCloseable() const = 0; + virtual bool isMaximizable() const = 0; + virtual MaximizeMode maximizeMode() const = 0; + virtual bool isMinimizable() const = 0; + virtual bool providesContextHelp() const = 0; + virtual int desktop() const = 0; + virtual bool isModal() const = 0; + virtual bool isShadeable() const = 0; + virtual bool isShade() const = 0; + virtual bool isSetShade() const = 0; + virtual bool keepAbove() const = 0; + virtual bool keepBelow() const = 0; + virtual bool isMovable() const = 0; + virtual bool isResizable() const = 0; + virtual NET::WindowType windowType( unsigned long supported_types ) const = 0; + virtual QIconSet icon() const = 0; + virtual QString caption() const = 0; + virtual void processMousePressEvent( QMouseEvent* ) = 0; + virtual void showWindowMenu( const QRect &) = 0; + virtual void showWindowMenu( QPoint ) = 0; + virtual void performWindowOperation( WindowOperation ) = 0; + virtual void setMask( const QRegion&, int ) = 0; + virtual bool isPreview() const = 0; + virtual QRect geometry() const = 0; + virtual QRect iconGeometry() const = 0; + virtual QRegion unobscuredRegion( const QRegion& r ) const = 0; + virtual QWidget* workspaceWidget() const = 0; + virtual WId windowId() const = 0; + virtual void closeWindow() = 0; + virtual void maximize( MaximizeMode mode ) = 0; + virtual void minimize() = 0; + virtual void showContextHelp() = 0; + virtual void setDesktop( int desktop ) = 0; + virtual void titlebarDblClickOperation() = 0; + virtual void titlebarMouseWheelOperation( int delta ) = 0; + virtual void setShade( bool set ) = 0; + virtual void setKeepAbove( bool ) = 0; + virtual void setKeepBelow( bool ) = 0; + // not part of public API + virtual int currentDesktop() const = 0; + virtual QWidget* initialParentWidget() const = 0; + virtual Qt::WFlags initialWFlags() const = 0; + virtual void helperShowHide( bool ) = 0; + virtual void grabXServer( bool grab ) = 0; + }; + +#endif diff --git a/kwin/lib/kdecoration_plugins_p.cpp b/kwin/lib/kdecoration_plugins_p.cpp new file mode 100644 index 000000000..85d496105 --- /dev/null +++ b/kwin/lib/kdecoration_plugins_p.cpp @@ -0,0 +1,199 @@ +/***************************************************************** +This file is part of the KDE project. + +Copyright (C) 1999, 2000 Daniel M. Duley <mosfet@kde.org> +Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org> + +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 "kdecoration_plugins_p.h" + +#include <kconfig.h> +#include <kdebug.h> +#include <klocale.h> +#include <klibloader.h> +#include <assert.h> + +#include <qdir.h> +#include <qfile.h> + +#include "kdecorationfactory.h" + +KDecorationPlugins::KDecorationPlugins( KConfig* cfg ) + : create_ptr( NULL ), + library( NULL ), + fact( NULL ), + old_library( NULL ), + old_fact( NULL ), + pluginStr( "kwin3_undefined " ), + config( cfg ) + { + } + +KDecorationPlugins::~KDecorationPlugins() + { + if(library) + { + assert( fact != NULL ); + delete fact; + library->unload(); + } + if(old_library) + { + assert( old_fact != NULL ); + delete old_fact; + old_library->unload(); + } + } + +bool KDecorationPlugins::reset( unsigned long changed ) + { + QString oldPlugin = pluginStr; + config->reparseConfiguration(); + bool ret = false; + if(( !loadPlugin( "" ) && library ) // "" = read the one in cfg file + || oldPlugin == pluginStr ) + { // no new plugin loaded, reset the old one + assert( fact != NULL ); + ret = fact->reset( changed ); + } + return ret || oldPlugin != pluginStr; + } + +KDecorationFactory* KDecorationPlugins::factory() + { + return fact; + } + +// convenience +KDecoration* KDecorationPlugins::createDecoration( KDecorationBridge* bridge ) + { + if( fact != NULL ) + return fact->createDecoration( bridge ); + return NULL; + } + +// returns true if plugin was loaded successfully +bool KDecorationPlugins::loadPlugin( QString nameStr ) + { + if( nameStr.isEmpty()) + { + KConfigGroupSaver saver( config, "Style" ); + nameStr = config->readEntry("PluginLib", defaultPlugin ); + } + // make sure people can switch between HEAD and kwin_iii branch + if( nameStr.startsWith( "kwin_" )) + nameStr = "kwin3_" + nameStr.mid( 5 ); + + KLibrary *oldLibrary = library; + KDecorationFactory* oldFactory = fact; + + QString path = KLibLoader::findLibrary(QFile::encodeName(nameStr)); + + // If the plugin was not found, try to find the default + if (path.isEmpty()) + { + nameStr = defaultPlugin; + path = KLibLoader::findLibrary(QFile::encodeName(nameStr)); + } + + // If no library was found, exit kwin with an error message + if (path.isEmpty()) + { + error( i18n("No window decoration plugin library was found." )); + return false; + } + + // Check if this library is not already loaded. + if(pluginStr == nameStr) + return true; + + // Try loading the requested plugin + library = KLibLoader::self()->library(QFile::encodeName(path)); + + // If that fails, fall back to the default plugin + if (!library) + { + kdDebug() << " could not load library, try default plugin again" << endl; + nameStr = defaultPlugin; + if ( pluginStr == nameStr ) + return true; + path = KLibLoader::findLibrary(QFile::encodeName(nameStr)); + if (!path.isEmpty()) + library = KLibLoader::self()->library(QFile::encodeName(path)); + } + + if (!library) + { + error( i18n("The default decoration plugin is corrupt " + "and could not be loaded." )); + return false; + } + + create_ptr = NULL; + if( library->hasSymbol("create_factory")) + { + void* create_func = library->symbol("create_factory"); + if(create_func) + create_ptr = (KDecorationFactory* (*)())create_func; + } + if(!create_ptr) + { + error( i18n( "The library %1 is not a KWin plugin." ).arg( path )); + library->unload(); + return false; + } + fact = create_ptr(); + fact->checkRequirements( this ); // let it check what is supported + + pluginStr = nameStr; + + // For clients in kdeartwork + QString catalogue = nameStr; + catalogue.replace( "kwin3_", "kwin_" ); + KGlobal::locale()->insertCatalogue( catalogue ); + // For KCommonDecoration based clients + KGlobal::locale()->insertCatalogue( "kwin_lib" ); + // For clients in kdebase + KGlobal::locale()->insertCatalogue( "kwin_clients" ); + // For clients in kdeartwork + KGlobal::locale()->insertCatalogue( "kwin_art_clients" ); + + old_library = oldLibrary; // save for delayed destroying + old_fact = oldFactory; + + return true; +} + +void KDecorationPlugins::destroyPreviousPlugin() +{ + // Destroy the old plugin + if(old_library) + { + delete old_fact; + old_fact = NULL; + old_library->unload(); + old_library = NULL; + } +} + +void KDecorationPlugins::error( const QString& ) + { + } diff --git a/kwin/lib/kdecoration_plugins_p.h b/kwin/lib/kdecoration_plugins_p.h new file mode 100644 index 000000000..b82f7f914 --- /dev/null +++ b/kwin/lib/kdecoration_plugins_p.h @@ -0,0 +1,77 @@ +/***************************************************************** +This file is part of the KDE project. + +Copyright (C) 1999, 2000 Daniel M. Duley <mosfet@kde.org> +Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org> + +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. +******************************************************************/ + +#ifndef KDECORATION_PLUGINS_H +#define KDECORATION_PLUGINS_H + +// +// This header file is internal. I mean it. +// + +#include <qcstring.h> +#include <qstring.h> +#include <qwidget.h> + +#include "kdecoration.h" + +class KLibrary; +class KConfig; +class KDecoration; +class KDecorationBridge; +class KDecorationFactory; + +class KWIN_EXPORT KDecorationPlugins + : public KDecorationProvides + { + public: + KDecorationPlugins( KConfig* cfg ); + virtual ~KDecorationPlugins(); + bool loadPlugin( QString name ); + void destroyPreviousPlugin(); + KDecorationFactory* factory(); + KDecoration* createDecoration( KDecorationBridge* ); + QString currentPlugin() { return pluginStr; } + bool reset( unsigned long changed ); // returns true if decorations need to be recreated + protected: + virtual void error( const QString& error_msg ); + QCString defaultPlugin; // FRAME normalne protected? + private: + KDecorationFactory* (*create_ptr)(); + KLibrary *library; + KDecorationFactory* fact; + KLibrary *old_library; + KDecorationFactory* old_fact; + QString pluginStr; + KConfig* config; + }; + +/* + + Plugins API: + KDecorationFactory* create_factory(); - called once after loading + +*/ + +#endif diff --git a/kwin/lib/kdecorationfactory.cpp b/kwin/lib/kdecorationfactory.cpp new file mode 100644 index 000000000..74508501b --- /dev/null +++ b/kwin/lib/kdecorationfactory.cpp @@ -0,0 +1,85 @@ +/***************************************************************** +This file is part of the KDE project. + +Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org> + +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 "kdecorationfactory.h" + +#include <assert.h> + +#include "kdecoration_p.h" + +KDecorationFactory::KDecorationFactory() + { + } + +KDecorationFactory::~KDecorationFactory() + { + assert( _decorations.count() == 0 ); + } + +bool KDecorationFactory::reset( unsigned long ) + { + return false; + } + +bool KDecorationFactory::supports( Ability ) + { + return false; + } + +void KDecorationFactory::checkRequirements( KDecorationProvides* ) + { + } + +QValueList< KDecorationDefines::BorderSize > KDecorationFactory::borderSizes() const + { + return QValueList< BorderSize >() << BorderNormal; + } + +bool KDecorationFactory::exists( const KDecoration* deco ) const + { + return _decorations.contains( const_cast< KDecoration* >( deco )); + } + +void KDecorationFactory::addDecoration( KDecoration* deco ) + { + _decorations.append( deco ); + } + +void KDecorationFactory::removeDecoration( KDecoration* deco ) + { + _decorations.remove( deco ); + } + +void KDecorationFactory::resetDecorations( unsigned long changed ) + { + for( QValueList< KDecoration* >::ConstIterator it = _decorations.begin(); + it != _decorations.end(); + ++it ) + (*it)->reset( changed ); + } + +NET::WindowType KDecorationFactory::windowType( unsigned long supported_types, KDecorationBridge* bridge ) const + { + return bridge->windowType( supported_types ); + } diff --git a/kwin/lib/kdecorationfactory.h b/kwin/lib/kdecorationfactory.h new file mode 100644 index 000000000..08e733c8b --- /dev/null +++ b/kwin/lib/kdecorationfactory.h @@ -0,0 +1,120 @@ +/***************************************************************** +This file is part of the KDE project. + +Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org> + +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. +******************************************************************/ + +#ifndef KDECORATIONFACTORY_H +#define KDECORATIONFACTORY_H + +#include "kdecoration.h" + +class KDecoration; +class KDecorationBridge; +class KDecorationFactoryPrivate; + +class KWIN_EXPORT KDecorationFactory + : public KDecorationDefines + { + public: + /** + * Constructor. Called after loading the decoration plugin. All global + * initialization of the plugin should be done in the factory constructor. + */ + KDecorationFactory(); + /** + * Destructor. Called before unloading the decoration plugin. All global + * cleanup of the plugin should be done in the factory destructor. + */ + virtual ~KDecorationFactory(); + /** + * This function must be reimplemented to create decoration objects. + * The argument should be passed to the KDecoration constructor, the second + * KDecoration argument should be this factory object. + */ + virtual KDecoration* createDecoration( KDecorationBridge* bridge ) = 0; + /** + * This function is called when the configuration settings changed. + * The argument specifies what has changed, using the SettingXXX masks. + * It should be determined whether the decorations need to be completely + * remade, in which case true should be returned, or whether only e.g. + * a repaint will be sufficient, in which case false should be returned, + * and resetDecorations() can be called to reset all decoration objects. + * Note that true should be returned only when really necessary. + */ + virtual bool reset( unsigned long changed ); // returns true if the decoration needs to be recreated + + /** + * Reimplement this function if your decoration supports more border sizes than + * the default one (BorderNormal). The returned list must contain all supported + * sizes, ordered from the smallest to the largest one. By default, only + * BorderNormal is returned. + */ + virtual QValueList< BorderSize > borderSizes() const; + + virtual bool supports( Ability ability ); + + virtual void checkRequirements( KDecorationProvides* provides ); + /** + * Returns the KDecorationOptions object, which is used to access + * configuration settings for the decoration. + */ + const KDecorationOptions* options(); // convenience + /** + * Returns true if the given decoration object still exists. This is necessary + * e.g. when calling KDecoration::showWindowMenu(), which may cause the decoration + * to be destroyed. Note that this function is reliable only if called immediately + * after such actions. + */ + bool exists( const KDecoration* deco ) const; + /** + * @internal + */ + void addDecoration( KDecoration* ); + /** + * @internal + */ + void removeDecoration( KDecoration* ); + protected: + /** + * Convenience function that calls KDecoration::reset() for all decoration + * objects. + */ + void resetDecorations( unsigned long changed ); // convenience + /** + * This function has the same functionality like KDecoration::windowType(). + * It can be used in createDecoration() to return different KDecoration + * inherited classes depending on the window type, as at that time + * KDecoration::windowType() is not available yet. The additional argument + * is the one passed to createDecoration(). + */ + NET::WindowType windowType( unsigned long supported_types, KDecorationBridge* bridge ) const; + private: + QValueList< KDecoration* > _decorations; + KDecorationFactoryPrivate* d; + }; + +inline const KDecorationOptions* KDecorationFactory::options() + { + return KDecoration::options(); + } + +#endif |