From be5a517b8a951e137168e2212be58c494c5eb353 Mon Sep 17 00:00:00 2001 From: Karol Szwed Date: Sun, 22 Apr 2001 09:31:42 +0000 Subject: [PATCH] Updating my Quartz client by adding customizable button positions, and converted it to use the new kwin plugin interface. svn path=/trunk/kdebase/kwin/; revision=93391 --- clients/quartz/quartz.cpp | 774 ++++++++++++++++++++++---------------- clients/quartz/quartz.h | 128 ++++--- 2 files changed, 518 insertions(+), 384 deletions(-) diff --git a/clients/quartz/quartz.cpp b/clients/quartz/quartz.cpp index 02675ea21d..cf3d06674c 100644 --- a/clients/quartz/quartz.cpp +++ b/clients/quartz/quartz.cpp @@ -9,50 +9,24 @@ KDE default client. Includes mini titlebars for ToolWindow Support. + Button positions are now customizable. */ -#include "quartz.h" +#include +#include +#include +#include #include #include #include -#include -#include -#include #include #include "../../workspace.h" #include "../../options.h" +#include "quartz.h" using namespace KWinInternal; -static const char *kdelogo[] = { -/* columns rows colors chars-per-pixel */ -"16 16 8 1", -" c None", -". c #000000", -"+ c #A0A0A4", -"@ c #FFFFFF", -"# c #585858", -"$ c #C0C0C0", -"% c #808080", -"& c #DCDCDC", -" ", -" .. .. ", -" .+@. .@#. ", -" .@@@. .@@@# ", -" .@@@..$@@$. ", -" .@@@.@@@$. ", -" .@@@%@@$. ", -" .@@@&@@. ", -" .@@@@@@. ", -" .@@@$@@&. ", -" .@@@.@@@. ", -" .@@@.+@@@. ", -" .@@@..$@@&. ", -" .@@%. .@@@. ", -" .... ... ", -" "}; - static unsigned char iconify_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -73,135 +47,247 @@ static unsigned char question_bits[] = { 0x00, 0x00, 0x3c, 0x00, 0x66, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 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}; -// Up / Down titlebar button images -// ================================= -// We don't make them dynamic, as we want this memory freed upon unloading -// this library from kwin. We get no notice upon being unloaded, so there's -// no way to free dynamic images. If they're not dynamic, the freeing of -// memory is made when the library in unloaded. +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 KPixmap *btnPix1; -static KPixmap *iBtnPix1; -static KPixmap *btnDownPix1; -static KPixmap *iBtnDownPix1; -static KPixmap *titleBlocks; -static KPixmap *ititleBlocks; -static QPixmap *defaultMenuPix; -static bool pixmaps_created = false; +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 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}; -// This does the colour transition magic. (You say "Oh, is that it?") -// In future, we may make this customisable, so we can have gears, blocks or -// any other eye candy via an alphapainter to perserve custom colour settings. -static void drawBlocks( KPixmap *pi, KPixmap &p, const QColor &c1, const QColor &c2 ) +/////////////////////////////////////////////////////////////////////////// + +// Titlebar button positions +QString quartzButtonsLeft; +QString quartzButtonsRight; +bool stickyButtonOnLeft = true; + +KPixmap* titleBlocks = NULL; +KPixmap* ititleBlocks = NULL; +KPixmap* pinDownPix = NULL; +KPixmap* pinUpPix = NULL; +KPixmap* ipinDownPix = NULL; +KPixmap* ipinUpPix = NULL; + +QuartzHandler* clientHandler; + +/////////////////////////////////////////////////////////////////////////// + + +QuartzHandler::QuartzHandler() { - QPainter px; - - px.begin( pi ); - - // Draw a background gradient first - KPixmapEffect::gradient(p, c1, c2, KPixmapEffect::HorizontalGradient); - - px.fillRect( 2, 1, 3, 3, c1.light(120) ); - px.fillRect( 2, 5, 3, 3, c1 ); - px.fillRect( 2, 9, 3, 3, c1.light(110) ); - px.fillRect( 2, 13, 3, 3, c1 ); - - px.fillRect( 6, 1, 3, 3, c1.light(110) ); - px.fillRect( 6, 5, 3, 3, c2.light(110) ); - px.fillRect( 6, 9, 3, 3, c1.light(120) ); - px.fillRect( 6, 13, 3, 3, c2.light(130) ); - - px.fillRect( 10, 5, 3, 3, c1.light(110) ); - px.fillRect( 10, 9, 3, 3, c2.light(120) ); - px.fillRect( 10, 13, 3, 3, c2.light(150) ); - - px.fillRect( 14, 1, 3, 3, c1.dark(110) ); - px.fillRect( 14, 9, 3, 3, c2.light(120) ); - px.fillRect( 14, 13, 3, 3, c1.dark(120) ); - - px.fillRect( 18, 5, 3, 3, c1.light(110) ); - px.fillRect( 18, 13, 3, 3, c1.dark(110) ); - - px.fillRect( 22, 9, 3, 3, c2.light(120)); - px.fillRect( 22, 13, 3, 3, c2.light(110) ); + readConfig(); + createPixmaps(); + connect( options, SIGNAL(resetClients()), this, SLOT(slotReset()) ); } +QuartzHandler::~QuartzHandler() +{ + freePixmaps(); +} + + +void QuartzHandler::slotReset() +{ + freePixmaps(); + readConfig(); + createPixmaps(); + + // Make kwin create new clients for each window + Workspace::self()->slotResetAllClientsDelayed(); +} + + +void QuartzHandler::readConfig() +{ + KConfig* conf = KGlobal::config(); + conf->setGroup("Style"); + + // Do we want to use custom button positions? + if( conf->readBoolEntry("CustomButtonPositions", false) ) + { + // Read the positions from the config file... + quartzButtonsLeft = conf->readEntry("ButtonsOnLeft", "MS"); + quartzButtonsRight = conf->readEntry("ButtonsOnRight", "HIAX"); + } else + { + // Use defaults + quartzButtonsLeft = "MS"; + quartzButtonsRight = "HIAX"; + } + + // A small hack to make the sticky button look nicer + stickyButtonOnLeft = (bool)quartzButtonsLeft.contains( 'S' ); +} + + +// This does the colour transition magic. (You say "Oh, is that it?") +// This may be made configurable at a later stage +void QuartzHandler::drawBlocks( KPixmap *pi, KPixmap &p, const QColor &c1, const QColor &c2 ) +{ + QPainter px; + + px.begin( pi ); + + // Draw a background gradient first + KPixmapEffect::gradient(p, c1, c2, KPixmapEffect::HorizontalGradient); + + px.fillRect( 2, 1, 3, 3, c1.light(120) ); + px.fillRect( 2, 5, 3, 3, c1 ); + px.fillRect( 2, 9, 3, 3, c1.light(110) ); + px.fillRect( 2, 13, 3, 3, c1 ); + + px.fillRect( 6, 1, 3, 3, c1.light(110) ); + px.fillRect( 6, 5, 3, 3, c2.light(110) ); + px.fillRect( 6, 9, 3, 3, c1.light(120) ); + px.fillRect( 6, 13, 3, 3, c2.light(130) ); + + px.fillRect( 10, 5, 3, 3, c1.light(110) ); + px.fillRect( 10, 9, 3, 3, c2.light(120) ); + px.fillRect( 10, 13, 3, 3, c2.light(150) ); + + px.fillRect( 14, 1, 3, 3, c1.dark(110) ); + px.fillRect( 14, 9, 3, 3, c2.light(120) ); + px.fillRect( 14, 13, 3, 3, c1.dark(120) ); + + px.fillRect( 18, 5, 3, 3, c1.light(110) ); + px.fillRect( 18, 13, 3, 3, c1.dark(110) ); + + px.fillRect( 22, 9, 3, 3, c2.light(120)); + px.fillRect( 22, 13, 3, 3, c2.light(110) ); +} + // This paints the button pixmaps upon loading the style. -static void create_pixmaps() +void QuartzHandler::createPixmaps() { - if(pixmaps_created) - return; - - pixmaps_created = true; - - btnPix1 = new KPixmap; - iBtnPix1 = new KPixmap; - btnDownPix1 = new KPixmap; - iBtnDownPix1 = new KPixmap; - titleBlocks = new KPixmap; - ititleBlocks = new KPixmap; - defaultMenuPix = new QPixmap( kdelogo ); - - // It does not matter that we don't resize thesei for mini-buttons - btnPix1->resize(16, 16); - btnDownPix1->resize(16, 16); - iBtnPix1->resize(16, 16); - iBtnDownPix1->resize(16, 16); - - // Fill the buttons with colour - QColorGroup g = options->colorGroup(Options::TitleBlend, true ); - QColor c = g.background(); - btnPix1->fill(c.rgb()); - btnDownPix1->fill(c.rgb()); - - g = options->colorGroup(Options::TitleBlend, false); - c = g.background(); - iBtnPix1->fill(c.rgb()); - iBtnDownPix1->fill(c.rgb()); - // Obtain titlebar blend colours, and create the block stuff on pixmaps. QColorGroup g2 = options->colorGroup(Options::TitleBlend, true); QColor c2 = g2.background(); - g = options->colorGroup(Options::TitleBar, true ); - c = g.background().light(130); + g2 = options->colorGroup(Options::TitleBar, true ); + QColor c = g2.background().light(130); + + titleBlocks = new KPixmap(); titleBlocks->resize( 25, 18 ); drawBlocks( titleBlocks, *titleBlocks, c, c2 ); g2 = options->colorGroup(Options::TitleBlend, false); c2 = g2.background(); - g = options->colorGroup(Options::TitleBar, false ); - c = g.background().light(130); + g2 = options->colorGroup(Options::TitleBar, false ); + c = g2.background().light(130); + + ititleBlocks = new KPixmap(); ititleBlocks->resize( 25, 18 ); drawBlocks( ititleBlocks, *ititleBlocks, c, c2 ); + + // Set the sticky pin pixmaps; + QPainter p; + + g2 = options->colorGroup( stickyButtonOnLeft ? Options::TitleBar : Options::TitleBlend, true ); + if ( stickyButtonOnLeft ) + c = g2.background().light(130); + else + c = g2.background(); + pinUpPix = new KPixmap(); + pinUpPix->resize(16, 16); + p.begin( pinUpPix ); + p.fillRect( 0, 0, 16, 16, c); + kColorBitmaps( &p, g2, 0, 0, 16, 16, true, pinup_white_bits, pinup_gray_bits, NULL, + pinup_dgray_bits, NULL, NULL ); + p.end(); + + pinDownPix = new KPixmap(); + pinDownPix->resize(16, 16); + p.begin( pinDownPix ); + p.fillRect( 0, 0, 16, 16, c); + kColorBitmaps( &p, g2, 0, 0, 16, 16, true, pindown_white_bits, pindown_gray_bits, NULL, + pindown_dgray_bits, NULL, NULL ); + p.end(); + + + // Inactive pins + g2 = options->colorGroup( stickyButtonOnLeft ? Options::TitleBar : Options::TitleBlend, false ); + if ( stickyButtonOnLeft ) + c = g2.background().light(130); + else + c = g2.background(); + ipinUpPix = new KPixmap(); + ipinUpPix->resize(16, 16); + p.begin( ipinUpPix ); + p.fillRect( 0, 0, 16, 16, c); + kColorBitmaps( &p, g2, 0, 0, 16, 16, true, pinup_white_bits, pinup_gray_bits, NULL, + pinup_dgray_bits, NULL, NULL ); + p.end(); + + ipinDownPix = new KPixmap(); + ipinDownPix->resize(16, 16); + p.begin( ipinDownPix ); + p.fillRect( 0, 0, 16, 16, c); + kColorBitmaps( &p, g2, 0, 0, 16, 16, true, pindown_white_bits, pindown_gray_bits, NULL, + pindown_dgray_bits, NULL, NULL ); + p.end(); } -static void delete_pixmaps() + +void QuartzHandler::freePixmaps() { - btnPix1 = new KPixmap; - iBtnPix1 = new KPixmap; - btnDownPix1 = new KPixmap; - iBtnDownPix1 = new KPixmap; - titleBlocks = new KPixmap; - ititleBlocks = new KPixmap; - defaultMenuPix = new QPixmap( kdelogo ); - pixmaps_created = false; + // Title images + if (titleBlocks) + delete titleBlocks; + if (ititleBlocks) + delete ititleBlocks; + + // Sticky pin images + if (pinUpPix) + delete pinUpPix; + if (ipinUpPix) + delete ipinUpPix; + if (pinDownPix) + delete pinDownPix; + if (ipinDownPix) + delete ipinDownPix; } + QuartzButton::QuartzButton(Client *parent, const char *name, bool largeButton, - const unsigned char *bitmap) + bool isLeftButton, bool isStickyButton, const unsigned char *bitmap ) : QButton(parent, name, WStyle_Customize | WRepaintNoErase | WResizeNoErase | WStyle_NoBorder ) { // Eliminate any possible background flicker setBackgroundMode( QWidget::NoBackground ); + setToggleButton( isStickyButton ); client = parent; + deco = NULL; large = largeButton; + isLeft = isLeftButton; + isSticky = isStickyButton; if ( large ) setFixedSize(16, 16); @@ -213,6 +299,13 @@ QuartzButton::QuartzButton(Client *parent, const char *name, bool largeButton, } +QuartzButton::~QuartzButton() +{ + if (deco) + delete deco; +} + + QSize QuartzButton::sizeHint() const { if ( large ) @@ -222,104 +315,127 @@ QSize QuartzButton::sizeHint() const } -void QuartzButton::reset() -{ - repaint(false); -} - - void QuartzButton::setBitmap(const unsigned char *bitmap) { - pix.resize(0, 0); - deco = QBitmap(10, 10, bitmap, true); - deco.setMask(deco); - repaint( false ); -} - - -void QuartzButton::setPixmap( const QPixmap &p ) -{ - deco.resize(0, 0); - pix = p; - - if ( large ) - setMask( QRect(0, 0, 16, 16) ); - else - setMask( QRect(0, 0, 10, 10) ); + if (deco) + delete deco; + deco = new QBitmap(10, 10, bitmap, true); + deco->setMask( *deco ); repaint( false ); } void QuartzButton::drawButton(QPainter *p) { - // Draw a button bg for bitmaps only - if(pix.isNull()) - { - if(client->isActive()) - { - if(isDown()) - p->drawPixmap(0, 0, *btnDownPix1); - else - p->drawPixmap(0, 0, *btnPix1); - } else - { - if(isDown()) - p->drawPixmap(0, 0, *iBtnDownPix1); - else - p->drawPixmap(0, 0, *iBtnPix1); - } + QColor c; - int xOff = (width()-10)/2; - int yOff = (height()-10)/2; - p->setPen( Qt::black ); - p->drawPixmap(isDown() ? xOff+2: xOff+1, isDown() ? yOff+2 : yOff+1, deco); - p->setPen( options->color(Options::ButtonBg, client->isActive()).light(150) ); - p->drawPixmap(isDown() ? xOff+1: xOff, isDown() ? yOff+1 : yOff, deco); + if (isLeft) + c = options->color(Options::TitleBar, client->isActive()).light(130); + else + c = options->color(Options::TitleBlend, client->isActive()); - } - else - { - // This is the menu button, which has a pixmap. - p->fillRect(0, 0, width(), height(), - options->color(Options::TitleBar, client->isActive()).light(130) ); - - // Shrink the miniIcon for tiny titlebars. - if ( !large ) - { - QPixmap tmpPix; + // Fill the button background with an appropriate color + p->fillRect(0, 0, width(), height(), c ); - // Smooth scale the image - tmpPix.convertFromImage( pix.convertToImage().smoothScale(10, 10)); - - p->drawPixmap( 0, 0, tmpPix ); - } - else - p->drawPixmap( 0, 0, pix ); - - } + // If we have a decoration bitmap, then draw that + // otherwise we paint a menu button (with mini icon), or a sticky button. + if( deco ) + { + int xOff = (width()-10)/2; + int yOff = (height()-10)/2; + p->setPen( Qt::black ); + p->drawPixmap(isDown() ? xOff+2: xOff+1, isDown() ? yOff+2 : yOff+1, *deco); + p->setPen( options->color(Options::ButtonBg, client->isActive()).light(150) ); + p->drawPixmap(isDown() ? xOff+1: xOff, isDown() ? yOff+1 : yOff, *deco); + } else + { + QPixmap btnpix; + int Offset = 0; + + if (isSticky) + { + if (isDown()) + Offset = 1; + + // Select the right sticky button to paint + if (client->isActive()) + { + if (isOn()) + btnpix = *pinDownPix; + else + btnpix = *pinUpPix; + } else { + if (isOn()) + btnpix = *ipinDownPix; + else + btnpix = *ipinUpPix; + } + } else + btnpix = client->miniIcon(); + + // Shrink the miniIcon for tiny titlebars. + if ( !large ) + { + QPixmap tmpPix; + + // Smooth scale the image + tmpPix.convertFromImage( btnpix.convertToImage().smoothScale(10, 10)); + p->drawPixmap( 0, 0, tmpPix ); + } else + p->drawPixmap( Offset, Offset, btnpix ); + } } +// Make the protected member public +void QuartzButton::turnOn( bool isOn ) +{ + if ( isToggleButton() ) + setOn( isOn ); +} + + +void QuartzButton::mousePressEvent( QMouseEvent* e ) +{ + last_button = e->button(); + QMouseEvent me( e->type(), e->pos(), e->globalPos(), + LeftButton, e->state() ); + QButton::mousePressEvent( &me ); +} + + +void QuartzButton::mouseReleaseEvent( QMouseEvent* e ) +{ + last_button = e->button(); + QMouseEvent me( e->type(), e->pos(), e->globalPos(), + LeftButton, e->state() ); + QButton::mouseReleaseEvent( &me ); +} + + +/////////////////////////////////////////////////////////////////////////// + QuartzClient::QuartzClient( Workspace *ws, WId w, QWidget *parent, const char *name ) : Client( ws, w, parent, name, WResizeNoErase | WNorthWestGravity | WRepaintNoErase ) { + // No flicker thanks setBackgroundMode( QWidget::NoBackground ); - // Finally, toolWindows look small - if ( isTool() ) - { - titleHeight = 12; - largeButtons = false; - } - else - { - titleHeight = 18; - largeButtons = true; - } + // Set button pointers to NULL so we can track things + for(int i=0; i < QuartzClient::BtnCount; i++) + button[i] = NULL; - lastButtonWidth = 0; + // Finally, toolWindows look small + if ( isTool() ) { + titleHeight = 12; + largeButtons = false; + } + else { + titleHeight = 18; + largeButtons = true; + } // Pack the windowWrapper() window within a grid QGridLayout* g = new QGridLayout(this, 0, 0, 0); @@ -332,79 +448,100 @@ QuartzClient::QuartzClient( Workspace *ws, WId w, QWidget *parent, g->addColSpacing(0, 4); g->addColSpacing(2, 4); - // Create the required buttons - button[BtnMenu] = new QuartzButton(this, "menu", largeButtons, NULL); - button[BtnClose] = new QuartzButton(this, "close", largeButtons, close_bits); - button[BtnIconify] = new QuartzButton(this, "iconify", largeButtons, iconify_bits); - button[BtnMax] = new QuartzButton(this, "maximize", largeButtons, maximize_bits); - - // Connect required stuff together - connect( button[BtnMenu], SIGNAL( pressed() ), this, SLOT( menuButtonPressed() )); - connect( button[BtnClose], SIGNAL( clicked() ), this, SLOT( closeWindow() )); - connect( button[BtnIconify], SIGNAL( clicked() ), this, SLOT( iconify() )); - connect( button[BtnMax], SIGNAL( clicked() ), this, SLOT( slotMaximize() )); - connect( options, SIGNAL(resetClients()), this, SLOT( slotReset() )); - // Pack the titlebar HBox with items hb = new QHBoxLayout(); hb->setResizeMode( QLayout::FreeResize ); g->addLayout ( hb, 1, 1 ); - hb->addWidget( button[BtnMenu] ); - titlebar = new QSpacerItem( 10, titleHeight, QSizePolicy::Expanding, - QSizePolicy::Minimum ); + + addClientButtons( quartzButtonsLeft ); + + titlebar = new QSpacerItem( 10, titleHeight, QSizePolicy::Expanding, QSizePolicy::Minimum ); hb->addItem(titlebar); hb->addSpacing(2); - // Add a help button if required - if( providesContextHelp() ) - { - button[BtnHelp] = new QuartzButton(this, "help", largeButtons, question_bits); - connect( button[BtnHelp], SIGNAL( clicked() ), this, SLOT( contextHelp() )); - hb->addWidget( button[BtnHelp] ); - } else - button[BtnHelp] = NULL; + addClientButtons( quartzButtonsRight, false ); - hb->addWidget( button[BtnIconify] ); - hb->addWidget( button[BtnMax] ); - hb->addWidget( button[BtnClose] ); hb->addSpacing(2); - - // Hide buttons which are not required - // We can un-hide them if required later - if ( !isMinimizable() ) - button[BtnIconify]->hide(); - if ( !isMaximizable() ) - button[BtnMax]->hide(); - - hiddenItems = false; - - // Make sure that the menu button uses the correct mini-icon - iconChange(); } -void QuartzClient::slotReset() +void QuartzClient::addClientButtons( const QString& s, bool isLeft ) { - // ( 4 buttons - Help, Max, Iconify, Close ) - for(int i = QuartzClient::BtnHelp; i <= QuartzClient::BtnClose; i++) - if(button[i]) - button[i]->reset(); + 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 QuartzButton(this, "menu", largeButtons, isLeft, false, NULL); + connect( button[BtnMenu], SIGNAL(pressed()), this, SLOT(menuButtonPressed()) ); + hb->addWidget( button[BtnMenu] ); + } + break; - // iconChange() resets the menu button so we don't have to do this here. + // Sticky button + case 'S': + if (!button[BtnSticky]) + { + button[BtnSticky] = new QuartzButton(this, "menu", largeButtons, isLeft, true, NULL); + button[BtnSticky]->turnOn( isSticky() ); + connect( button[BtnSticky], SIGNAL(clicked()), this, SLOT(toggleSticky()) ); + hb->addSpacing(1); + hb->addWidget( button[BtnSticky] ); + hb->addSpacing(1); + } + break; - repaint( false ); + // Help button + case 'H': + if( providesContextHelp() && (!button[BtnHelp]) ) + { + button[BtnHelp] = new QuartzButton(this, "help", largeButtons, isLeft, true, question_bits); + connect( button[BtnHelp], SIGNAL( clicked() ), this, SLOT( contextHelp() )); + hb->addWidget( button[BtnHelp] ); + } + break; + + // Minimize button + case 'I': + if ( (!button[BtnIconify]) && isMinimizable()) + { + button[BtnIconify] = new QuartzButton(this, "iconify", largeButtons, isLeft, true, iconify_bits); + connect( button[BtnIconify], SIGNAL( clicked()), this, SLOT(iconify()) ); + hb->addWidget( button[BtnIconify] ); + } + break; + + // Maximize button + case 'A': + if ( (!button[BtnMax]) && isMaximizable()) + { + button[BtnMax] = new QuartzButton(this, "maximize", largeButtons, isLeft, true, maximize_bits); + connect( button[BtnMax], SIGNAL( clicked()), this, SLOT(slotMaximize()) ); + hb->addWidget( button[BtnMax] ); + } + break; + + // Close button + case 'X': + if (!button[BtnClose]) + { + button[BtnClose] = new QuartzButton(this, "close", largeButtons, isLeft, true, close_bits); + connect( button[BtnClose], SIGNAL( clicked()), this, SLOT(closeWindow()) ); + hb->addWidget( button[BtnClose] ); + } + } + } } void QuartzClient::iconChange() { - if(!miniIcon().isNull()) - button[BtnMenu]->setPixmap(miniIcon()); - else - button[BtnMenu]->setPixmap(*defaultMenuPix); - - if (button[BtnMenu]->isVisible()) - button[BtnMenu]->repaint(false); + if (button[BtnMenu] && button[BtnMenu]->isVisible()) + button[BtnMenu]->repaint(false); } @@ -502,7 +639,6 @@ void QuartzClient::paintEvent( QPaintEvent* ) // Draw the title bar. // =================== r = titlebar->geometry(); - QFontMetrics fm(options->font(true)); // Obtain titlebar blend colours QColor c1 = options->color(Options::TitleBar, isActive() ).light(130); @@ -514,14 +650,16 @@ void QuartzClient::paintEvent( QPaintEvent* ) QPainter p2( titleBuffer, this ); - p2.fillRect( 0, 0, r.width(), r.height(), c1 ); - p2.fillRect( r.width(), 0, w-r.width()-6, r.height(), c2 ); + int rightoffset = r.x()+r.width()-25-4; // subtract titleBlocks pixmap width and some + + p2.fillRect( 0, 0, w, r.height(), c1 ); + p2.fillRect( rightoffset, 0, w-rightoffset-6, r.height(), c2 ); // 8 bit displays will be a bit dithered, but they still look ok. if ( isActive() ) - p2.drawPixmap( r.width()-10, 0, *titleBlocks ); - else - p2.drawPixmap( r.width()-10, 0, *ititleBlocks ); + p2.drawPixmap( rightoffset, 0, *titleBlocks ); + else + p2.drawPixmap( rightoffset, 0, *ititleBlocks ); // Draw the title text on the pixmap, and with a smaller font // for toolwindows than the default. @@ -562,76 +700,57 @@ void QuartzClient::mouseDoubleClickEvent( QMouseEvent * e ) void QuartzClient::maximizeChange(bool m) { - button[BtnMax]->setBitmap(m ? minmax_bits : maximize_bits); + if (button[BtnMax]) + button[BtnMax]->setBitmap(m ? minmax_bits : maximize_bits); } void QuartzClient::activeChange(bool) { - - if(!miniIcon().isNull()) - button[BtnMenu]->setPixmap(miniIcon()); - else - button[BtnMenu]->setPixmap(kdelogo); - - for(int i=QuartzClient::BtnHelp; i < QuartzClient::BtnMenu; i++) - { + for(int i=QuartzClient::BtnHelp; i < QuartzClient::BtnCount; i++) if(button[i]) - button[i]->reset(); - } + button[i]->repaint(false); repaint(false); } - // The hiding button while shrinking, show button while expanding magic void QuartzClient::calcHiddenButtons() { - // order of hiding is help, maximize, minimize, close, then menu; - int minWidth = 32 + 16*4 + (providesContextHelp() ? 16*2 : 16 ); + //Hide buttons in this order - Sticky, Help, Maximize, Menu, Minimize, Close. + QuartzButton* btnArray[] = { button[BtnSticky], button[BtnHelp], button[BtnMax], + button[BtnMenu], button[BtnIconify], button[BtnClose] }; - if(lastButtonWidth > width()) // Shrinking - { - lastButtonWidth = width(); - if(width() < minWidth) - { - hiddenItems = true; + int minwidth = largeButtons ? 180 : 140; // Start hiding buttons at this width + int btn_width = largeButtons ? 16 : 10; + int current_width = width(); + int count = 0; + int i; - for(int i = QuartzClient::BtnHelp; i <= QuartzClient::BtnMenu; i++) - if(button[i]) - { - if( !button[i]->isHidden() ) - button[i]->hide(); + // Find out how many buttons we have to hide. + while (current_width < minwidth) + { + current_width += btn_width; + count++; + } - minWidth -= button[i]->sizeHint().width(); - if(width() >= minWidth) - return; - } - } - } else - if(hiddenItems) // Expanding - { - lastButtonWidth = width(); - int totalSize = 16*3; + // Bound the number of buttons to hide + if (count > 6) count = 6; - for(int i = QuartzClient::BtnMenu; i >= QuartzClient::BtnHelp; i--) - if(button[i]) - { - if(button[i]->sizeHint().width() + totalSize <= width()) - { - totalSize += button[i]->sizeHint().width(); - button[i]->resize(button[i]->sizeHint()); - button[i]->show(); - } - else return; - } + // Hide the required buttons... + for(i = 0; i < count; i++) + { + if (btnArray[i] && btnArray[i]->isVisible() ) + btnArray[i]->hide(); + } - // all items shown now - hiddenItems = false; - } - else - lastButtonWidth = width(); + // Show the rest of the buttons... + for(i = count; i < 6; i++) + { + if (btnArray[i] && (!btnArray[i]->isVisible()) ) + btnArray[i]->show(); + } } @@ -655,25 +774,32 @@ void QuartzClient::menuButtonPressed() tc = this; } + +// Extended KWin plugin interface +///////////////////////////////// extern "C" { Client *allocate(Workspace *ws, WId w, int) { return(new QuartzClient(ws, w)); } - void init() - { - create_pixmaps(); - } - void reset() - { - delete_pixmaps(); - create_pixmaps(); - } - void deinit() - { - delete_pixmaps(); - } + + void init() + { + clientHandler = new QuartzHandler(); + } + + void reset() + { + // QuartzHandler takes care of this for us + } + + void deinit() + { + delete clientHandler; + } } + + #include "quartz.moc" diff --git a/clients/quartz/quartz.h b/clients/quartz/quartz.h index 90f08f6e2f..8b01cf71bd 100644 --- a/clients/quartz/quartz.h +++ b/clients/quartz/quartz.h @@ -9,6 +9,7 @@ KDE default client. Includes mini titlebars for ToolWindow Support. + Button positions are now customizable. */ #ifndef __KDEGALLIUM_QUARTZ_H @@ -18,86 +19,93 @@ #include #include #include "../../client.h" + class QLabel; class QSpacerItem; class QHBoxLayout; +class QGridLayout; + namespace KWinInternal { + +class QuartzHandler: public QObject +{ + Q_OBJECT + public: + QuartzHandler(); + ~QuartzHandler(); + + public slots: + void slotReset(); + + private: + void readConfig(); + void initTheme(); + void createPixmaps(); + void freePixmaps(); + void drawBlocks(KPixmap* pi, KPixmap &p, const QColor &c1, const QColor &c2); +}; + + class QuartzButton : public QButton { + public: + QuartzButton(Client *parent=0, const char *name=0, bool largeButton=true, + bool isLeftButton=true, bool isStickyButton=false, const unsigned char *bitmap=NULL); + ~QuartzButton(); + void setBitmap(const unsigned char *bitmap); + QSize sizeHint() const; + int last_button; + void turnOn( bool isOn ); -public: - QuartzButton(Client *parent=0, const char *name=0, bool largeButton=true, - const unsigned char *bitmap=NULL ); - void setBitmap(const unsigned char *bitmap); - void setPixmap(const QPixmap &p); - void reset(); + protected: + void mousePressEvent( QMouseEvent* e ); + void mouseReleaseEvent( QMouseEvent* e ); + virtual void drawButton(QPainter *p); + void drawButtonLabel(QPainter*) {;} - QSize sizeHint() const; - int last_button; - -protected: - void mousePressEvent( QMouseEvent* e ) - { - last_button = e->button(); - QMouseEvent me ( e->type(), e->pos(), e->globalPos(), - LeftButton, e->state() ); - QButton::mousePressEvent( &me ); - } - - void mouseReleaseEvent( QMouseEvent* e ) - { - last_button = e->button(); - QMouseEvent me ( e->type(), e->pos(), e->globalPos(), - LeftButton, e->state() ); - QButton::mouseReleaseEvent( &me ); - } - - virtual void drawButton(QPainter *p); - void drawButtonLabel(QPainter *){;} - - QBitmap deco; - QPixmap pix; - Client* client; - bool large; + Client* client; + QBitmap* deco; + bool large; + bool isLeft; + bool isSticky; }; class QuartzClient : public KWinInternal::Client { - Q_OBJECT + Q_OBJECT -public: - enum Buttons{ BtnHelp=0, BtnMax, BtnIconify, BtnClose, BtnMenu, BtnCount }; - QuartzClient( Workspace *ws, WId w, QWidget *parent=0, const char *name=0 ); - ~QuartzClient() {;} - int titleHeight; + public: + enum Buttons{ BtnHelp=0, BtnMax, BtnIconify, BtnClose, BtnMenu, BtnSticky, BtnCount }; + QuartzClient( Workspace *ws, WId w, QWidget *parent=0, const char *name=0 ); + ~QuartzClient() {;} -protected: - void resizeEvent( QResizeEvent* ); - void paintEvent( QPaintEvent* ); - void showEvent( QShowEvent* ); - void mouseDoubleClickEvent( QMouseEvent * ); - void captionChange( const QString& name ); - void maximizeChange(bool m); - void activeChange(bool); - void iconChange(); + protected: + void resizeEvent( QResizeEvent* ); + void paintEvent( QPaintEvent* ); + void showEvent( QShowEvent* ); + void mouseDoubleClickEvent( QMouseEvent * ); + void captionChange( const QString& name ); + void maximizeChange(bool m); + void activeChange(bool); + void iconChange(); - void calcHiddenButtons(); + protected slots: + void slotMaximize(); + void menuButtonPressed(); -protected slots: - void slotReset(); - void slotMaximize(); - void menuButtonPressed(); + private: + void calcHiddenButtons(); + void addClientButtons( const QString& s, bool isLeft=true ); -private: - QuartzButton* button[ QuartzClient::BtnCount ]; - int lastButtonWidth; - QSpacerItem* titlebar; - bool hiddenItems; - QHBoxLayout* hb; - bool largeButtons; + QuartzButton* button[ QuartzClient::BtnCount ]; + int lastButtonWidth; + int titleHeight; + bool largeButtons; + QHBoxLayout* hb; + QSpacerItem* titlebar; }; };