You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
967 lines
30 KiB
967 lines
30 KiB
/* |
|
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> |
|
#include <QCursor> |
|
#include <QDateTime> |
|
#include <QLabel> |
|
|
|
#include <QWidget> |
|
|
|
#include <kdebug.h> |
|
|
|
#include <kapplication.h> |
|
#include "kdecorationfactory.h" |
|
#include <klocale.h> |
|
#include <QDesktopWidget> |
|
|
|
#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(); |
|
|
|
// for flicker-free redraws |
|
widget()->setAttribute(Qt::WA_NoSystemBackground); |
|
|
|
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 every time we are in ::borders |
|
} |
|
|
|
void KCommonDecoration::updateLayout() const |
|
{ |
|
QRect r = widget()->rect(); |
|
int r_x, r_y, r_x2, r_y2; |
|
r.getCoords(&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, qobject_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, qobject_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("<center><b>%1 preview</b></center>", 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 (int n=0; n < s.length(); n++) { |
|
KCommonDecorationButton *btn = 0; |
|
switch (s[n].toAscii()) { |
|
case 'M': // Menu button |
|
if (!m_button[MenuButton]){ |
|
btn = createButton(MenuButton); |
|
if (!btn) break; |
|
btn->setTipText(i18n("Menu") ); |
|
btn->setRealizeButtons(Qt::LeftButton|Qt::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(Qt::LeftButton|Qt::MidButton|Qt::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]->isChecked()) |
|
{ |
|
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]->isChecked()) |
|
{ |
|
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() != Qt::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.getCoords(&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().getCoords(&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) |
|
: QAbstractButton(parent->widget() ), |
|
m_decoration(parent), |
|
m_type(type), |
|
m_realizeButtons(Qt::LeftButton), |
|
m_lastMouse(Qt::NoButton), |
|
m_isLeft(true) |
|
{ |
|
setCursor(Qt::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) { |
|
this->setToolTip( tip ); |
|
} |
|
|
|
void KCommonDecorationButton::setToggleButton(bool toggle) |
|
{ |
|
QAbstractButton::setCheckable(toggle); |
|
reset(ToggleChange); |
|
} |
|
|
|
void KCommonDecorationButton::setOn(bool on) |
|
{ |
|
if (on != isChecked() ) { |
|
QAbstractButton::setChecked(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->button()&m_realizeButtons)?Qt::LeftButton : Qt::NoButton, e->buttons(), e->modifiers() ); |
|
|
|
QAbstractButton::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->button()&m_realizeButtons)?Qt::LeftButton : Qt::NoButton, e->buttons(), e->modifiers() ); |
|
|
|
QAbstractButton::mouseReleaseEvent(&me); |
|
} |
|
|
|
// kate: space-indent on; indent-width 4; mixedindent off; indent-mode cstyle; |
|
|
|
|