/* * $Id$ * * KDE2 Default KWin client * * Copyright (C) 1999, 2001 Daniel Duley * Matthias Ettrich * Karol Szwed * * Draws mini titlebars for tool windows. * Many features are now customizable. */ #include "kdedefault.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Default { static unsigned char iconify_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static unsigned char close_bits[] = { 0x00, 0x00, 0x84, 0x00, 0xce, 0x01, 0xfc, 0x00, 0x78, 0x00, 0x78, 0x00, 0xfc, 0x00, 0xce, 0x01, 0x84, 0x00, 0x00, 0x00}; static unsigned char maximize_bits[] = { 0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0x86, 0x01, 0x86, 0x01, 0x86, 0x01, 0x86, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0x00, 0x00}; static unsigned char minmax_bits[] = { 0x7f, 0x00, 0x7f, 0x00, 0x63, 0x00, 0xfb, 0x03, 0xfb, 0x03, 0x1f, 0x03, 0x1f, 0x03, 0x18, 0x03, 0xf8, 0x03, 0xf8, 0x03}; static unsigned char question_bits[] = { 0x00, 0x00, 0x78, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0x60, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00}; static unsigned char pindown_white_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x1f, 0xa0, 0x03, 0xb0, 0x01, 0x30, 0x01, 0xf0, 0x00, 0x70, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static unsigned char pindown_gray_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x80, 0x07, 0xc0, 0x03, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static unsigned char pindown_dgray_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x10, 0x70, 0x20, 0x50, 0x20, 0x48, 0x30, 0xc8, 0x38, 0x08, 0x1f, 0x08, 0x18, 0x10, 0x1c, 0x10, 0x0e, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static unsigned char pindown_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x1f, 0xf0, 0x3f, 0xf0, 0x3f, 0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf0, 0x1f, 0xf0, 0x0f, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static unsigned char pinup_white_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x11, 0x3f, 0x15, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static unsigned char pinup_gray_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0a, 0xbf, 0x0a, 0x80, 0x15, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static unsigned char pinup_dgray_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x40, 0x31, 0x40, 0x2e, 0x40, 0x20, 0x40, 0x20, 0x7f, 0x2a, 0x40, 0x3f, 0xc0, 0x31, 0xc0, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static unsigned char pinup_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0xc0, 0x31, 0xc0, 0x3f, 0xff, 0x3f, 0xff, 0x3f, 0xff, 0x3f, 0xc0, 0x3f, 0xc0, 0x31, 0xc0, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // =========================================================================== QPixmap* titlePix = NULL; KPixmap* titleBuffer = NULL; KPixmap* aUpperGradient = NULL; KPixmap* iUpperGradient = NULL; KPixmap* pinDownPix = NULL; KPixmap* pinUpPix = NULL; KPixmap* ipinDownPix = NULL; KPixmap* ipinUpPix = NULL; KPixmap* rightBtnUpPix = NULL; KPixmap* rightBtnDownPix = NULL; KPixmap* irightBtnUpPix = NULL; KPixmap* irightBtnDownPix = NULL; KPixmap* leftBtnUpPix = NULL; KPixmap* leftBtnDownPix = NULL; KPixmap* ileftBtnUpPix = NULL; KPixmap* ileftBtnDownPix = NULL; KDEDefaultHandler* clientHandler; bool KDEDefault_initialized = false; bool useGradients; bool showGrabBar; bool showTitleBarStipple; bool largeToolButtons; int toolTitleHeight; int normalTitleHeight; // =========================================================================== KDEDefaultHandler::KDEDefaultHandler() { clientHandler = this; readConfig(); createPixmaps(); KDEDefault_initialized = true; } KDEDefaultHandler::~KDEDefaultHandler() { KDEDefault_initialized = false; freePixmaps(); clientHandler = NULL; } KDecoration* KDEDefaultHandler::createDecoration( KDecorationBridge* b ) { return new KDEDefaultClient( b, this ); } bool KDEDefaultHandler::reset( unsigned long changed ) { Q_UNUSED( changed ) // FRAME KDEDefault_initialized = false; freePixmaps(); readConfig(); createPixmaps(); KDEDefault_initialized = true; return true; } void KDEDefaultHandler::readConfig() { KConfig* conf = KGlobal::config(); conf->setGroup("KDEDefault"); showGrabBar = conf->readBoolEntry("ShowGrabBar", true); showTitleBarStipple = conf->readBoolEntry("ShowTitleBarStipple", true); useGradients = conf->readBoolEntry("UseGradients", true); int size = conf->readNumEntry("TitleBarSize", 0); if (size < 0) size = 0; if (size > 2) size = 2; normalTitleHeight = 16 + (4*size); toolTitleHeight = normalTitleHeight - 4; largeToolButtons = (toolTitleHeight >= 16) ? true : false; } // This paints the button pixmaps upon loading the style. void KDEDefaultHandler::createPixmaps() { bool highcolor = useGradients && (QPixmap::defaultDepth() > 8); // Make the titlebar stipple optional if (showTitleBarStipple) { QPainter p; QPainter maskPainter; int i, x, y; titlePix = new QPixmap(132, normalTitleHeight+2); QBitmap mask(132, normalTitleHeight+2); mask.fill(Qt::color0); p.begin(titlePix); maskPainter.begin(&mask); maskPainter.setPen(Qt::color1); for(i=0, y=2; i < 6; ++i, y+=4) for(x=1; x <= 132; x+=3) { p.setPen(options()->color(ColorTitleBar, true).light(150)); p.drawPoint(x, y); maskPainter.drawPoint(x, y); p.setPen(options()->color(ColorTitleBar, true).dark(150)); p.drawPoint(x+1, y+1); maskPainter.drawPoint(x+1, y+1); } maskPainter.end(); p.end(); titlePix->setMask(mask); } else titlePix = NULL; QColor activeTitleColor1(options()->color(ColorTitleBar, true)); QColor activeTitleColor2(options()->color(ColorTitleBlend, true)); QColor inactiveTitleColor1(options()->color(ColorTitleBar, false)); QColor inactiveTitleColor2(options()->color(ColorTitleBlend, false)); // Create titlebar gradient images if required aUpperGradient = NULL; iUpperGradient = NULL; if(highcolor) { // Create the titlebar gradients if (activeTitleColor1 != activeTitleColor2) { aUpperGradient = new KPixmap; aUpperGradient->resize(128, normalTitleHeight+2); KPixmapEffect::gradient(*aUpperGradient, activeTitleColor1, activeTitleColor2, KPixmapEffect::VerticalGradient); } if (inactiveTitleColor1 != inactiveTitleColor2) { iUpperGradient = new KPixmap; iUpperGradient->resize(128, normalTitleHeight+2); KPixmapEffect::gradient(*iUpperGradient, inactiveTitleColor1, inactiveTitleColor2, KPixmapEffect::VerticalGradient); } } // Set the sticky pin pixmaps; QColorGroup g; QPainter p; // Active pins g = options()->colorGroup( ColorButtonBg, true ); pinUpPix = new KPixmap(); pinUpPix->resize(16, 16); p.begin( pinUpPix ); kColorBitmaps( &p, g, 0, 0, 16, 16, true, pinup_white_bits, pinup_gray_bits, NULL, NULL, pinup_dgray_bits, NULL ); p.end(); pinUpPix->setMask( QBitmap(16, 16, pinup_mask_bits, true) ); pinDownPix = new KPixmap(); pinDownPix->resize(16, 16); p.begin( pinDownPix ); kColorBitmaps( &p, g, 0, 0, 16, 16, true, pindown_white_bits, pindown_gray_bits, NULL, NULL, pindown_dgray_bits, NULL ); p.end(); pinDownPix->setMask( QBitmap(16, 16, pindown_mask_bits, true) ); // Inactive pins g = options()->colorGroup( ColorButtonBg, false ); ipinUpPix = new KPixmap(); ipinUpPix->resize(16, 16); p.begin( ipinUpPix ); kColorBitmaps( &p, g, 0, 0, 16, 16, true, pinup_white_bits, pinup_gray_bits, NULL, NULL, pinup_dgray_bits, NULL ); p.end(); ipinUpPix->setMask( QBitmap(16, 16, pinup_mask_bits, true) ); ipinDownPix = new KPixmap(); ipinDownPix->resize(16, 16); p.begin( ipinDownPix ); kColorBitmaps( &p, g, 0, 0, 16, 16, true, pindown_white_bits, pindown_gray_bits, NULL, NULL, pindown_dgray_bits, NULL ); p.end(); ipinDownPix->setMask( QBitmap(16, 16, pindown_mask_bits, true) ); // Create a title buffer for flicker-free painting titleBuffer = new KPixmap(); // Cache all possible button states leftBtnUpPix = new KPixmap(); leftBtnUpPix->resize(16, 16); leftBtnDownPix = new KPixmap(); leftBtnDownPix->resize(16, 16); ileftBtnUpPix = new KPixmap(); ileftBtnUpPix->resize(16, 16); ileftBtnDownPix = new KPixmap(); ileftBtnDownPix->resize(16, 16); rightBtnUpPix = new KPixmap(); rightBtnUpPix->resize(16, 16); rightBtnDownPix = new KPixmap(); rightBtnDownPix->resize(16, 16); irightBtnUpPix = new KPixmap(); irightBtnUpPix->resize(16, 16); irightBtnDownPix = new KPixmap(); irightBtnDownPix->resize(16, 16); // Draw the button state pixmaps g = options()->colorGroup( ColorTitleBar, true ); drawButtonBackground( leftBtnUpPix, g, false ); drawButtonBackground( leftBtnDownPix, g, true ); g = options()->colorGroup( ColorButtonBg, true ); drawButtonBackground( rightBtnUpPix, g, false ); drawButtonBackground( rightBtnDownPix, g, true ); g = options()->colorGroup( ColorTitleBar, false ); drawButtonBackground( ileftBtnUpPix, g, false ); drawButtonBackground( ileftBtnDownPix, g, true ); g = options()->colorGroup( ColorButtonBg, false ); drawButtonBackground( irightBtnUpPix, g, false ); drawButtonBackground( irightBtnDownPix, g, true ); } void KDEDefaultHandler::freePixmaps() { // Free button pixmaps if (rightBtnUpPix) delete rightBtnUpPix; if(rightBtnDownPix) delete rightBtnDownPix; if (irightBtnUpPix) delete irightBtnUpPix; if (irightBtnDownPix) delete irightBtnDownPix; if (leftBtnUpPix) delete leftBtnUpPix; if(leftBtnDownPix) delete leftBtnDownPix; if (ileftBtnUpPix) delete ileftBtnUpPix; if (ileftBtnDownPix) delete ileftBtnDownPix; // Title images if (titleBuffer) delete titleBuffer; if (titlePix) delete titlePix; if (aUpperGradient) delete aUpperGradient; if (iUpperGradient) delete iUpperGradient; // Sticky pin images if (pinUpPix) delete pinUpPix; if (ipinUpPix) delete ipinUpPix; if (pinDownPix) delete pinDownPix; if (ipinDownPix) delete ipinDownPix; } void KDEDefaultHandler::drawButtonBackground(KPixmap *pix, const QColorGroup &g, bool sunken) { QPainter p; int w = pix->width(); int h = pix->height(); int x2 = w-1; int y2 = h-1; bool highcolor = useGradients && (QPixmap::defaultDepth() > 8); QColor c = g.background(); // Fill the background with a gradient if possible if (highcolor) KPixmapEffect::gradient(*pix, c.light(130), c.dark(130), KPixmapEffect::VerticalGradient); else pix->fill(c); p.begin(pix); // outer frame p.setPen(g.mid()); p.drawLine(0, 0, x2, 0); p.drawLine(0, 0, 0, y2); p.setPen(g.light()); p.drawLine(x2, 0, x2, y2); p.drawLine(0, x2, y2, x2); p.setPen(g.dark()); p.drawRect(1, 1, w-2, h-2); p.setPen(sunken ? g.mid() : g.light()); p.drawLine(2, 2, x2-2, 2); p.drawLine(2, 2, 2, y2-2); p.setPen(sunken ? g.light() : g.mid()); p.drawLine(x2-2, 2, x2-2, y2-2); p.drawLine(2, x2-2, y2-2, x2-2); } // =========================================================================== KDEDefaultButton::KDEDefaultButton(KDEDefaultClient *parent, const char *name, bool largeButton, bool isLeftButton, bool isStickyButton, const unsigned char *bitmap, const QString& tip ) : QButton(parent->widget(), name) { QToolTip::add( this, tip ); setBackgroundMode( QWidget::NoBackground ); setToggleButton( isStickyButton ); isMouseOver = false; deco = NULL; large = largeButton; isLeft = isLeftButton; isSticky = isStickyButton; client = parent; if (large) setFixedSize(16, 16); else setFixedSize(12, 12); if (bitmap) setBitmap(bitmap); } KDEDefaultButton::~KDEDefaultButton() { if (deco) delete deco; } QSize KDEDefaultButton::sizeHint() const { if ( large ) return( QSize(16,16) ); else return( QSize(12,12) ); } void KDEDefaultButton::setBitmap(const unsigned char *bitmap) { if (deco) delete deco; deco = new QBitmap(10, 10, bitmap, true); deco->setMask( *deco ); repaint( false ); } void KDEDefaultButton::drawButton(QPainter *p) { if (!KDEDefault_initialized) return; if (deco) { // Fill the button background with an appropriate button image KPixmap btnbg; if (isLeft) { if (isDown()) btnbg = client->isActive() ? *leftBtnDownPix : *ileftBtnDownPix; else btnbg = client->isActive() ? *leftBtnUpPix : *ileftBtnUpPix; } else { if (isDown()) btnbg = client->isActive() ? *rightBtnDownPix : *irightBtnDownPix; else btnbg = client->isActive() ? *rightBtnUpPix : *irightBtnUpPix; } // Scale the background image if required // This is slow, but we assume this isn't done too often if ( !large ) { btnbg.detach(); btnbg.convertFromImage(btnbg.convertToImage().smoothScale(12, 12)); } p->drawPixmap( 0, 0, btnbg ); } else if ( isLeft ) { // Fill the button background with an appropriate color/gradient // This is for sticky and menu buttons KPixmap* grad = client->isActive() ? aUpperGradient : iUpperGradient; if (!grad) { QColor c = KDecoration::options()->color(ColorTitleBar, client->isActive()); p->fillRect(0, 0, width(), height(), c ); } else p->drawPixmap( 0, 0, *grad, 0,((normalTitleHeight-height())/2)+1, 16, 16 ); } else { // Draw a plain background for menus or sticky buttons on RHS QColor c = KDecoration::options()->color(ColorFrame, client->isActive()); p->fillRect(0, 0, width(), height(), c); } // If we have a decoration bitmap, then draw that // otherwise we paint a menu button (with mini icon), or a sticky button. if( deco ) { // Select the appropriate button decoration color bool darkDeco = qGray( KDecoration::options()->color( isLeft? ColorTitleBar : ColorButtonBg, client->isActive()).rgb() ) > 127; if (isMouseOver) p->setPen( darkDeco ? Qt::darkGray : Qt::lightGray ); else p->setPen( darkDeco ? Qt::black : Qt::white ); int xOff = (width()-10)/2; int yOff = (height()-10)/2; p->drawPixmap(isDown() ? xOff+1: xOff, isDown() ? yOff+1 : yOff, *deco); } else { KPixmap btnpix; if (isSticky) { if (client->isActive()) btnpix = isOn() ? *pinDownPix : *pinUpPix; else btnpix = isOn() ? *ipinDownPix : *ipinUpPix; } else btnpix = client->icon().pixmap( QIconSet::Small, QIconSet::Normal ); // Intensify the image if required if (isMouseOver) { btnpix = KPixmapEffect::intensity(btnpix, 0.8); } // Smooth scale the pixmap for small titlebars // This is slow, but we assume this isn't done too often if ( !large ) btnpix.convertFromImage(btnpix.convertToImage().smoothScale(12, 12)); p->drawPixmap( 0, 0, btnpix ); } } // Make the protected member public void KDEDefaultButton::turnOn( bool isOn ) { if ( isToggleButton() ) setOn( isOn ); } void KDEDefaultButton::enterEvent(QEvent *e) { isMouseOver=true; repaint(false); QButton::enterEvent(e); } void KDEDefaultButton::leaveEvent(QEvent *e) { isMouseOver=false; repaint(false); QButton::leaveEvent(e); } void KDEDefaultButton::mousePressEvent( QMouseEvent* e ) { last_button = e->button(); QMouseEvent me( e->type(), e->pos(), e->globalPos(), LeftButton, e->state() ); QButton::mousePressEvent( &me ); } void KDEDefaultButton::mouseReleaseEvent( QMouseEvent* e ) { last_button = e->button(); QMouseEvent me( e->type(), e->pos(), e->globalPos(), LeftButton, e->state() ); QButton::mouseReleaseEvent( &me ); } // =========================================================================== KDEDefaultClient::KDEDefaultClient( KDecorationBridge* b, KDecorationFactory* f ) : KDecoration( b, f ), m_closing(false) { } void KDEDefaultClient::init() { createMainWidget( WResizeNoErase | WStaticContents | WRepaintNoErase ); widget()->installEventFilter( this ); // No flicker thanks widget()->setBackgroundMode( QWidget::NoBackground ); // Set button pointers to NULL so we can track things for(int i=0; i < KDEDefaultClient::BtnCount; i++) button[i] = NULL; // Finally, toolWindows look small if ( isTool() ) { titleHeight = toolTitleHeight; largeButtons = largeToolButtons; } else { titleHeight = normalTitleHeight; largeButtons = true; } // Pack the windowWrapper() window within a grid g = new QGridLayout(widget(), 0, 0, 0); g->setResizeMode(QLayout::FreeResize); g->addRowSpacing(0, 3); // Top grab bar g->addRowSpacing(2, 1); // line under titlebar if( isPreview()) g->addWidget( new QLabel( i18n( "
KDE2 preview
" ), widget()), 3, 1); else g->addWidget( new QWidget( widget()), 3, 1); // without the next line, unshade flickers g->addItem( new QSpacerItem( 0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding ) ); g->setRowStretch(3, 10); // Wrapped window // Determine the size of the lower grab bar spacer = new QSpacerItem(10, showGrabBar && isResizable() ? 8 : 4, QSizePolicy::Expanding, QSizePolicy::Minimum); g->addItem(spacer, 4, 1); g->addColSpacing(0, 4); g->addColSpacing(2, 4); // Pack the titlebar HBox with items hb = new QBoxLayout(0, QBoxLayout::LeftToRight, 0, 0, 0 ); hb->setResizeMode( QLayout::FreeResize ); g->addLayout ( hb, 1, 1 ); addClientButtons( options()->titleButtonsLeft() ); titlebar = new QSpacerItem( 10, titleHeight, QSizePolicy::Expanding, QSizePolicy::Minimum ); hb->addItem(titlebar); hb->addSpacing(2); addClientButtons( options()->titleButtonsRight(), false ); } void KDEDefaultClient::addClientButtons( const QString& s, bool isLeft ) { if (s.length() > 0) for(unsigned int i = 0; i < s.length(); i++) { switch( s[i].latin1() ) { // Menu button case 'M': if (!button[BtnMenu]) { button[BtnMenu] = new KDEDefaultButton(this, "menu", largeButtons, isLeft, false, NULL, i18n("Menu")); connect( button[BtnMenu], SIGNAL(pressed()), this, SLOT(menuButtonPressed()) ); connect( button[BtnMenu], SIGNAL(released()), this, SLOT(menuButtonReleased())); hb->addWidget( button[BtnMenu] ); } break; // Sticky button case 'S': if (!button[BtnSticky]) { button[BtnSticky] = new KDEDefaultButton(this, "sticky", largeButtons, isLeft, true, NULL, i18n("Sticky")); button[BtnSticky]->turnOn( isOnAllDesktops() ); connect( button[BtnSticky], SIGNAL(clicked()), this, SLOT(toggleOnAllDesktops()) ); hb->addWidget( button[BtnSticky] ); } break; // Help button case 'H': if( providesContextHelp() && (!button[BtnHelp]) ) { button[BtnHelp] = new KDEDefaultButton(this, "help", largeButtons, isLeft, true, question_bits, i18n("Help")); connect( button[BtnHelp], SIGNAL( clicked() ), this, SLOT( showContextHelp() )); hb->addWidget( button[BtnHelp] ); } break; // Minimize button case 'I': if ( (!button[BtnIconify]) && isMinimizable()) { button[BtnIconify] = new KDEDefaultButton(this, "iconify", largeButtons, isLeft, true, iconify_bits, i18n("Minimize")); connect( button[BtnIconify], SIGNAL( clicked()), this, SLOT(minimize()) ); hb->addWidget( button[BtnIconify] ); } break; // Maximize button case 'A': if ( (!button[BtnMax]) && isMaximizable()) { button[BtnMax] = new KDEDefaultButton(this, "maximize", largeButtons, isLeft, true, maximize_bits, i18n("Maximize")); connect( button[BtnMax], SIGNAL( clicked()), this, SLOT(slotMaximize()) ); hb->addWidget( button[BtnMax] ); } break; // Close button case 'X': if (!button[BtnClose] && isCloseable()) { button[BtnClose] = new KDEDefaultButton(this, "close", largeButtons, isLeft, true, close_bits, i18n("Close")); connect( button[BtnClose], SIGNAL( clicked()), this, SLOT(closeWindow()) ); hb->addWidget( button[BtnClose] ); } break; // Spacer item (only for non-tool windows) case '_': if ( !isTool() ) hb->addSpacing(2); } } } void KDEDefaultClient::iconChange() { if (button[BtnMenu] && button[BtnMenu]->isVisible()) button[BtnMenu]->repaint(false); } void KDEDefaultClient::desktopChange() { if (button[BtnSticky]) { bool on = isOnAllDesktops(); button[BtnSticky]->turnOn(on); button[BtnSticky]->repaint(false); QToolTip::remove( button[BtnSticky] ); QToolTip::add( button[BtnSticky], on ? i18n("Un-Sticky") : i18n("Sticky")); } } void KDEDefaultClient::slotMaximize() { if ( button[BtnMax]->last_button == MidButton ) maximize( maximizeMode() ^ MaximizeVertical ); else if ( button[BtnMax]->last_button == RightButton ) maximize( maximizeMode() ^ MaximizeHorizontal ); else maximize( maximizeMode() == MaximizeFull ? MaximizeRestore : MaximizeFull ); } void KDEDefaultClient::resizeEvent( QResizeEvent* e) { doShape(); calcHiddenButtons(); if ( widget()->isShown()) { widget()->update( widget()->rect()); #if 1 // what's the point of this, when paintEvent() repaints everything anyway? int dx = 0; int dy = 0; if ( e->oldSize().width() != width() ) dx = 32 + QABS( e->oldSize().width() - width() ); if ( e->oldSize().height() != height() ) dy = 8 + QABS( e->oldSize().height() - height() ); if ( dy ) widget()->update( 0, height() - dy + 1, width(), dy ); if ( dx ) { widget()->update( width() - dx + 1, 0, dx, height() ); widget()->update( QRect( QPoint(4,4), titlebar->geometry().bottomLeft() - QPoint(1,0) ) ); widget()->update( QRect( titlebar->geometry().topRight(), QPoint(width() - 4, titlebar->geometry().bottom()) ) ); // Titlebar needs no paint event QApplication::postEvent( widget(), new QPaintEvent(titlebar->geometry(), FALSE) ); } #endif } } void KDEDefaultClient::captionChange() { widget()->repaint( titlebar->geometry(), false ); } void KDEDefaultClient::paintEvent( QPaintEvent* ) { if (!KDEDefault_initialized) return; QColorGroup g; int offset; KPixmap* upperGradient = isActive() ? aUpperGradient : iUpperGradient; QPainter p(widget()); // Obtain widget bounds. QRect r(widget()->rect()); int x = r.x(); int y = r.y(); int x2 = r.width() - 1; int y2 = r.height() - 1; int w = r.width(); int h = r.height(); // Determine where to place the extended left titlebar int leftFrameStart = (h > 42) ? y+titleHeight+26: y+titleHeight; // Determine where to make the titlebar color transition r = titlebar->geometry(); int rightOffset = r.x()+r.width()+1; // Create a disposable pixmap buffer for the titlebar // very early before drawing begins so there is no lag // during painting pixels. titleBuffer->resize( rightOffset-3, titleHeight+1 ); // Draw an outer black frame p.setPen(Qt::black); p.drawRect(x,y,w,h); // Draw part of the frame that is the titlebar color g = options()->colorGroup(ColorTitleBar, isActive()); p.setPen(g.light()); p.drawLine(x+1, y+1, rightOffset-1, y+1); p.drawLine(x+1, y+1, x+1, leftFrameStart); // Draw titlebar colour separator line p.setPen(g.dark()); p.drawLine(rightOffset-1, y+1, rightOffset-1, titleHeight+2); // Finish drawing the titlebar extension p.setPen(Qt::black); p.drawLine(x+1, leftFrameStart, x+2, leftFrameStart-1); p.setPen(g.mid()); p.drawLine(x+2, y+titleHeight+3, x+2, leftFrameStart-2); // Fill out the border edges g = options()->colorGroup(ColorFrame, isActive()); p.setPen(g.light()); p.drawLine(rightOffset, y+1, x2-1, y+1); p.drawLine(x+1, leftFrameStart+1, x+1, y2-1); p.setPen(g.dark()); p.drawLine(x2-1, y+1, x2-1, y2-1); p.drawLine(x+1, y2-1, x2-1, y2-1); p.setPen(options()->color(ColorFrame, isActive())); p.drawLine(x+2, leftFrameStart, x+2, y2-2 ); p.drawLine(x2-2, y+titleHeight+3, x2-2, y2-2); // Draw the bottom handle if required if (showGrabBar && isResizable()) { if(w > 50) { qDrawShadePanel(&p, x+1, y2-6, 20, 6, g, false, 1, &g.brush(QColorGroup::Mid)); qDrawShadePanel(&p, x+21, y2-6, w-42, 6, g, false, 1, isActive() ? &g.brush(QColorGroup::Background) : &g.brush(QColorGroup::Mid)); qDrawShadePanel(&p, x2-20, y2-6, 20, 6, g, false, 1, &g.brush(QColorGroup::Mid)); } else qDrawShadePanel(&p, x+1, y2-6, w-2, 6, g, false, 1, isActive() ? &g.brush(QColorGroup::Background) : &g.brush(QColorGroup::Mid)); offset = 4; } else { p.drawLine(x+2, y2-2, x2-2, y2-2); offset = 0; } // Draw a frame around the wrapped widget. p.setPen( g.dark() ); p.drawRect( x+3, y+titleHeight+3, w-6, h-titleHeight-offset-6 ); // Draw the title bar. r = titlebar->geometry(); // Obtain titlebar blend colours QColor c1 = options()->color(ColorTitleBar, isActive() ); QColor c2 = options()->color(ColorFrame, isActive() ); // Fill with frame color behind RHS buttons p.fillRect( rightOffset, y+2, x2-rightOffset-1, titleHeight+1, c2); QPainter p2( titleBuffer, this ); // Draw the titlebar gradient if (upperGradient) p2.drawTiledPixmap(0, 0, rightOffset-3, titleHeight+1, *upperGradient); else p2.fillRect(0, 0, rightOffset-3, titleHeight+1, c1); // Draw the title text on the pixmap, and with a smaller font // for toolwindows than the default. QFont fnt = options()->font(true); if ( isTool() ) fnt.setPointSize( fnt.pointSize()-2 ); // Shrink font by 2pt p2.setFont( fnt ); // Draw the titlebar stipple if active and available if (isActive() && titlePix) { QFontMetrics fm(fnt); int captionWidth = fm.width(caption()); if (caption().isRightToLeft()) p2.drawTiledPixmap( r.x(), 0, r.width()-captionWidth-4, titleHeight+1, *titlePix ); else p2.drawTiledPixmap( r.x()+captionWidth+3, 0, r.width()-captionWidth-4, titleHeight+1, *titlePix ); } p2.setPen( options()->color(ColorFont, isActive()) ); p2.drawText(r.x(), 1, r.width()-1, r.height(), (caption().isRightToLeft() ? AlignRight : AlignLeft) | AlignVCenter, caption() ); bitBlt( widget(), 2, 2, titleBuffer ); p2.end(); // Ensure a shaded window has no unpainted areas // Is this still needed? #if 1 p.setPen(c2); p.drawLine(x+4, y+titleHeight+4, x2-4, y+titleHeight+4); #endif } void KDEDefaultClient::doShape() { QRegion mask(QRect(0, 0, width(), height())); mask -= QRect(0, 0, 1, 1); mask -= QRect(width()-1, 0, 1, 1); mask -= QRect(0, height()-1, 1, 1); mask -= QRect(width()-1, height()-1, 1, 1); setMask(mask); } void KDEDefaultClient::showEvent(QShowEvent *) { calcHiddenButtons(); doShape(); } void KDEDefaultClient::mouseDoubleClickEvent( QMouseEvent * e ) { if (titlebar->geometry().contains( e->pos() ) ) titlebarDblClickOperation(); } void KDEDefaultClient::maximizeChange() { if (button[BtnMax]) { bool m = maximizeMode() == MaximizeFull; button[BtnMax]->setBitmap(m ? minmax_bits : maximize_bits); QToolTip::remove( button[ BtnMax ] ); QToolTip::add( button[BtnMax], m ? i18n("Restore") : i18n("Maximize")); } spacer->changeSize(10, showGrabBar && isResizable() ? 8 : 4, QSizePolicy::Expanding, QSizePolicy::Minimum); g->activate(); } void KDEDefaultClient::activeChange() { for(int i=KDEDefaultClient::BtnHelp; i < KDEDefaultClient::BtnCount; i++) if(button[i]) button[i]->repaint(false); widget()->repaint(false); } void KDEDefaultClient::shadeChange() { } QSize KDEDefaultClient::minimumSize() const { return QSize( 100, 50 ); // FRAME } void KDEDefaultClient::resize( const QSize& s ) { widget()->resize( s ); } void KDEDefaultClient::borders( int& left, int& right, int& top, int& bottom ) const { // FRAME left = right = 4; // , y+titleHeight+3, w-6, h-titleHeight-offset-6 ); top = titleHeight + 4; bottom = isResizable() ? 8 : 4; } // The hiding button while shrinking, show button while expanding magic void KDEDefaultClient::calcHiddenButtons() { // Hide buttons in this order: // Sticky, Help, Maximize, Minimize, Close, Menu. KDEDefaultButton* btnArray[] = { button[BtnSticky], button[BtnHelp], button[BtnMax], button[BtnIconify], button[BtnClose], button[BtnMenu] }; int minwidth = largeButtons ? 160 : 120; // Start hiding at this width int btn_width = largeButtons ? 16 : 12; int current_width = width(); int count = 0; int i; // Find out how many buttons we need to hide. while (current_width < minwidth) { current_width += btn_width; count++; } // Bound the number of buttons to hide if (count > 6) count = 6; // Hide the required buttons... for(i = 0; i < count; i++) { if (btnArray[i] && btnArray[i]->isVisible() ) btnArray[i]->hide(); } // Show the rest of the buttons... for(i = count; i < 6; i++) { if (btnArray[i] && (!btnArray[i]->isVisible()) ) btnArray[i]->show(); } } KDecoration::MousePosition KDEDefaultClient::mousePosition( const QPoint& p ) const { MousePosition m = Nowhere; // Modify the mouse position if we are using a grab bar. if (showGrabBar && isResizable()) if (p.y() < (height() - 8)) m = KDecoration::mousePosition(p); else { if (p.x() >= (width() - 20)) m = BottomRight2; else if (p.x() <= 20) m = BottomLeft2; else m = Bottom; } else m = KDecoration::mousePosition(p); return m; } // Make sure the menu button follows double click conventions set in kcontrol void KDEDefaultClient::menuButtonPressed() { static QTime t; static KDEDefaultClient* lastClient = NULL; bool dbl = ( lastClient == this && t.elapsed() <= QApplication::doubleClickInterval()); lastClient = this; t.start(); if (dbl) { m_closing = true; return; } QPoint menupoint ( button[BtnMenu]->rect().bottomLeft().x()-1, button[BtnMenu]->rect().bottomLeft().y()+2 ); showWindowMenu( button[BtnMenu]->mapToGlobal( menupoint )); button[BtnMenu]->setDown(false); } void KDEDefaultClient::menuButtonReleased() { if (m_closing) closeWindow(); } 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 KDEDefaultClient::isTool() const { NET::WindowType type = windowType( SUPPORTED_WINDOW_TYPES_MASK ); return type == NET::Toolbar || type == NET::Utility || type == NET::Menu; } bool KDEDefaultClient::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::Show: showEvent( static_cast< QShowEvent* >( e )); return true; default: break; } return false; } } // namespace // Extended KWin plugin interface extern "C" KDecorationFactory* create_factory() { return new Default::KDEDefaultHandler(); } #include "kdedefault.moc" // vim: ts=4