From 97b0ee49e18cc6eb1f595aeb778e8290c00ee4f6 Mon Sep 17 00:00:00 2001 From: Karol Szwed Date: Thu, 7 Jun 2001 11:35:06 +0000 Subject: [PATCH] Default style update: - Modifying the default style to use the new kwin plugin interface for proper resource management. - The new default style looks nearly the same, but adds several nice features such as titlebar height and button position customisation among others, and adds a config module for configuration. - kwin plugin loader modified to reflect the new default plugin change. The old default will be removed shortly. - oh, and never ever flicker :) svn path=/trunk/kdebase/kwin/; revision=100839 --- Makefile.am | 4 +- clients/Makefile.am | 2 +- clients/default/Makefile.am | 17 + clients/default/config/Makefile.am | 16 + clients/default/config/config.cpp | 161 +++++ clients/default/config/config.h | 57 ++ clients/default/kdedefault.cpp | 1078 ++++++++++++++++++++++++++++ clients/default/kdedefault.h | 115 +++ plugins.cpp | 202 ++---- plugins.h | 19 +- 10 files changed, 1525 insertions(+), 146 deletions(-) create mode 100644 clients/default/Makefile.am create mode 100644 clients/default/config/Makefile.am create mode 100644 clients/default/config/config.cpp create mode 100644 clients/default/config/config.h create mode 100644 clients/default/kdedefault.cpp create mode 100644 clients/default/kdedefault.h diff --git a/Makefile.am b/Makefile.am index a77a23431a..cab58d8999 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ INCLUDES = -I$(top_srcdir)/kwin/default $(all_includes) -SUBDIRS = default . pics clients +SUBDIRS = . pics clients bin_PROGRAMS = kwin lib_LTLIBRARIES = kwin.la @@ -9,7 +9,7 @@ lib_LTLIBRARIES = kwin.la kwin_la_SOURCES = workspace.cpp atoms.cpp client.cpp main.cpp \ tabbox.cpp options.cpp plugins.cpp events.cpp KWinInterface.skel \ killwindow.cpp -kwin_la_LIBADD = $(LIB_KDEUI) $(top_builddir)/kwin/default/libkwindefault.la +kwin_la_LIBADD = $(LIB_KDEUI) kwin_la_LDFLAGS = $(all_libraries) -module -avoid-version include_HEADERS = KWinInterface.h diff --git a/clients/Makefile.am b/clients/Makefile.am index c8996210bd..086e92ccdf 100644 --- a/clients/Makefile.am +++ b/clients/Makefile.am @@ -1 +1 @@ -SUBDIRS = kde1 kstep system b2 laptop riscos modernsystem win2k kwmtheme quartz icewm web mwm +SUBDIRS = default kde1 kstep system b2 laptop riscos modernsystem win2k kwmtheme quartz icewm web mwm diff --git a/clients/default/Makefile.am b/clients/default/Makefile.am new file mode 100644 index 0000000000..b330f4824e --- /dev/null +++ b/clients/default/Makefile.am @@ -0,0 +1,17 @@ + +INCLUDES = $(all_includes) + +SUBDIRS = . config + +kde_module_LTLIBRARIES = libkwindefault.la + +libkwindefault_la_SOURCES = kdedefault.cpp +libkwindefault_la_LIBADD = ../../kwin.la +libkwindefault_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) + +METASOURCES = AUTO +noinst_HEADERS = kdedefault.h + +###KMAKE-start (don't edit or delete this block) + +###KMAKE-end diff --git a/clients/default/config/Makefile.am b/clients/default/config/Makefile.am new file mode 100644 index 0000000000..7cc5d70c37 --- /dev/null +++ b/clients/default/config/Makefile.am @@ -0,0 +1,16 @@ +INCLUDES = $(all_includes) + +kde_module_LTLIBRARIES = libkwindefault_config.la + +libkwindefault_config_la_SOURCES = config.cpp +libkwindefault_config_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) +libkwindefault_config_la_LIBADD = $(LIB_KDEUI) + +METASOURCES = AUTO +noinst_HEADERS = config.h + +lnkdir = $(kde_datadir)/kwin/ + +###KMAKE-start (don't edit or delete this block) + +###KMAKE-end diff --git a/clients/default/config/config.cpp b/clients/default/config/config.cpp new file mode 100644 index 0000000000..d09a767eb0 --- /dev/null +++ b/clients/default/config/config.cpp @@ -0,0 +1,161 @@ +/* + * $Id$ + * + * KDE2 Default configuration widget + * + * Copyright (c) 2001 + * Karol Szwed + * http://gallium.n3.net/ + */ + +#include "config.h" +#include +#include +#include + +extern "C" +{ + QObject* allocate_config( KConfig* conf, QWidget* parent ) + { + return(new KDEDefaultConfig(conf, parent)); + } +} + +// NOTE: +// 'conf' is a pointer to the kwindecoration modules open kwin config, +// and is by default set to the "Style" group. +// 'parent' is the parent of the QObject, which is a VBox inside the +// Configure tab in kwindecoration + +KDEDefaultConfig::KDEDefaultConfig( KConfig* conf, QWidget* parent ) + : QObject( parent ) +{ + highcolor = QPixmap::defaultDepth() > 8; + gb = new QGroupBox( 1, Qt::Horizontal, + i18n("KDE2 Default Decoration Settings"), parent ); + + cbShowStipple = new QCheckBox( i18n("Draw titlebar &stipple effect"), gb ); + QWhatsThis::add( cbShowStipple, + i18n("When selected, active titlebars are drawn " + "with a stipple (dotted) effect. Otherwise, they are " + "drawn without the stipple.")); + + cbShowGrabBar = new QCheckBox( i18n("Draw g&rab bar below windows"), gb ); + QWhatsThis::add( cbShowGrabBar, + i18n("When selected, decorations are drawn with a \"grab bar\" " + "below windows. Otherwise, no grab bar is drawn.")); + + // Only show the gradient checkbox for highcolor displays + if (highcolor) + { + cbUseGradients = new QCheckBox( i18n("Draw gr&adients"), gb ); + QWhatsThis::add( cbUseGradients, + i18n("When selected, decorations are drawn with gradients " + "for highcolor displays, otherwise no gradients are drawn.") ); + } + + // Allow titlebar height customization + gbSlider = new QGroupBox( 1, Qt::Horizontal, i18n("TitleBar Height"), gb ); + titleBarSizeSlider = new QSlider(0, 2, 1, 0, QSlider::Horizontal, gbSlider); + QWhatsThis::add( titleBarSizeSlider, + i18n("By adjusting this slider, you can modify " + "the height of the titlebar to make room for larger fonts.")); + + hbox = new QHBox(gbSlider); + hbox->setSpacing(6); + label1 = new QLabel( i18n("Normal"), hbox ); + label2 = new QLabel( i18n("Large"), hbox ); + label2->setAlignment( AlignHCenter ); + label3 = new QLabel( i18n("Huge"), hbox ); + label3->setAlignment( AlignRight ); + + // Load configuration options + load( conf ); + + // Ensure we track user changes properly + connect( cbShowStipple, SIGNAL(clicked()), + this, SLOT(slotSelectionChanged()) ); + connect( cbShowGrabBar, SIGNAL(clicked()), + this, SLOT(slotSelectionChanged()) ); + connect( titleBarSizeSlider, SIGNAL(valueChanged(int)), + this, SLOT(slotSelectionChanged(int)) ); + if (highcolor) + connect( cbUseGradients, SIGNAL(clicked()), + this, SLOT(slotSelectionChanged()) ); + + // Make the widgets visible in kwindecoration + gb->show(); +} + + +KDEDefaultConfig::~KDEDefaultConfig() +{ + delete gb; +} + + +void KDEDefaultConfig::slotSelectionChanged() +{ + emit changed(); +} + + +void KDEDefaultConfig::slotSelectionChanged(int) +{ + emit changed(); +} + + +// Loads the configurable options from the kwinrc config file +// It is passed the open config from kwindecoration to improve efficiency +void KDEDefaultConfig::load( KConfig* conf ) +{ + conf->setGroup("KDEDefault"); + bool override = conf->readBoolEntry( "ShowTitleBarStipple", true ); + cbShowStipple->setChecked( override ); + + override = conf->readBoolEntry( "ShowGrabBar", true ); + cbShowGrabBar->setChecked( override ); + + if (highcolor) { + override = conf->readBoolEntry( "UseGradients", true ); + cbUseGradients->setChecked( override ); + } + + int size = conf->readNumEntry( "TitleBarSize", 0 ); + if (size < 0) size = 0; + if (size > 2) size = 2; + + titleBarSizeSlider->setValue(size); +} + + +// Saves the configurable options to the kwinrc config file +void KDEDefaultConfig::save( KConfig* conf ) +{ + conf->setGroup("KDEDefault"); + conf->writeEntry( "ShowTitleBarStipple", cbShowStipple->isChecked() ); + conf->writeEntry( "ShowGrabBar", cbShowGrabBar->isChecked() ); + + if (highcolor) + conf->writeEntry( "UseGradients", cbUseGradients->isChecked() ); + + conf->writeEntry( "TitleBarSize", titleBarSizeSlider->value() ); + // No need to conf->sync() - kwindecoration will do it for us +} + + +// Sets UI widget defaults which must correspond to style defaults +void KDEDefaultConfig::defaults() +{ + cbShowStipple->setChecked( true ); + cbShowGrabBar->setChecked( true ); + + if (highcolor) + cbUseGradients->setChecked( true ); + + titleBarSizeSlider->setValue(0); +} + +#include "config.moc" +// vim: ts=4 diff --git a/clients/default/config/config.h b/clients/default/config/config.h new file mode 100644 index 0000000000..e201ee333b --- /dev/null +++ b/clients/default/config/config.h @@ -0,0 +1,57 @@ +/* + * $Id$ + * + * KDE2 Default configuration widget + * + * Copyright (c) 2001 + * Karol Szwed + * http://gallium.n3.net/ + */ + +#ifndef _KDE_DEFAULT_CONFIG_H +#define _KDE_DEFAULT_CONFIG_H + +#include +#include +#include +#include +#include +#include + +class KDEDefaultConfig: public QObject +{ + Q_OBJECT + + public: + KDEDefaultConfig( KConfig* conf, QWidget* parent ); + ~KDEDefaultConfig(); + + // These public signals/slots work similar to KCM modules + signals: + void changed(); + + public slots: + void load( KConfig* conf ); + void save( KConfig* conf ); + void defaults(); + + protected slots: + void slotSelectionChanged(); // Internal use + void slotSelectionChanged(int); // Internal use + + private: + QCheckBox* cbShowStipple; + QCheckBox* cbShowGrabBar; + QCheckBox* cbUseGradients; + QSlider* titleBarSizeSlider; + QGroupBox* gb; + bool highcolor; + QLabel* label1; + QLabel* label2; + QLabel* label3; + QGroupBox* gbSlider; + QHBox* hbox; +}; + +#endif +// vim: ts=4 diff --git a/clients/default/kdedefault.cpp b/clients/default/kdedefault.cpp new file mode 100644 index 0000000000..6275036b74 --- /dev/null +++ b/clients/default/kdedefault.cpp @@ -0,0 +1,1078 @@ +/* + * $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 +#include +#include +#include +#include +#include +#include +#include "../../workspace.h" +#include "../../options.h" +#include "kdedefault.h" + +using namespace KWinInternal; + +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() +{ + readConfig(); + createPixmaps(); + KDEDefault_initialized = true; +} + + +KDEDefaultHandler::~KDEDefaultHandler() +{ + KDEDefault_initialized = false; + freePixmaps(); +} + + +void KDEDefaultHandler::reset() +{ + KDEDefault_initialized = false; + freePixmaps(); + readConfig(); + createPixmaps(); + KDEDefault_initialized = true; + Workspace::self()->slotResetAllClientsDelayed(); +} + + +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(Options::TitleBar, true).light(150)); + p.drawPoint(x, y); + maskPainter.drawPoint(x, y); + p.setPen(options->color(Options::TitleBar, 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; + + // Create titlebar gradient images if required + if(highcolor) + { + // Create the titlebar gradients + aUpperGradient = new KPixmap; + aUpperGradient->resize(128, normalTitleHeight+2); + iUpperGradient = new KPixmap; + iUpperGradient->resize(128, normalTitleHeight+2); + QColorGroup bgColor = options->colorGroup(Options::TitleBar, true); + KPixmapEffect::gradient(*aUpperGradient, + bgColor.midlight(), + bgColor.mid(), + KPixmapEffect::VerticalGradient); + bgColor = options->colorGroup(Options::TitleBar, false); + KPixmapEffect::gradient(*iUpperGradient, + bgColor.midlight(), + bgColor.mid(), + KPixmapEffect::VerticalGradient); + } else { + aUpperGradient = NULL; + iUpperGradient = NULL; + } + + // Set the sticky pin pixmaps; + QColorGroup g; + QPainter p; + + // Active pins + g = options->colorGroup( Options::ButtonBg, 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( Options::ButtonBg, 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( Options::TitleBar, true ); + drawButtonBackground( leftBtnUpPix, g, false ); + drawButtonBackground( leftBtnDownPix, g, true ); + + g = options->colorGroup( Options::ButtonBg, true ); + drawButtonBackground( rightBtnUpPix, g, false ); + drawButtonBackground( rightBtnDownPix, g, true ); + + g = options->colorGroup( Options::TitleBar, false ); + drawButtonBackground( ileftBtnUpPix, g, false ); + drawButtonBackground( ileftBtnDownPix, g, true ); + + g = options->colorGroup( Options::ButtonBg, 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(Client *parent, const char *name, + bool largeButton, 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 ); + + isMouseOver = false; + client = parent; + deco = NULL; + + large = largeButton; + isLeft = isLeftButton; + isSticky = isStickyButton; + + 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 = options->color(Options::TitleBar, 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 = options->color(Options::Frame, 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( options->color( + isLeft? Options::TitleBar : Options::ButtonBg, + 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->miniIcon(); + + // Intensify the image if required + if (isMouseOver) { + QBitmap mask = *btnpix.mask(); + btnpix.detach(); + btnpix = KPixmapEffect::intensity(btnpix, 0.8); + btnpix.setMask( mask ); + } + + // 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::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( Workspace *ws, WId w, QWidget *parent, + const char *name ) + : Client( ws, w, parent, name, WResizeNoErase | WNorthWestGravity | + WRepaintNoErase ) +{ + // No flicker thanks + 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 + QGridLayout* g = new QGridLayout(this, 0, 0, 0); + g->setResizeMode(QLayout::FreeResize); + g->addRowSpacing(0, 3); // Top grab bar + g->addRowSpacing(2, 1); // line under titlebar + g->addWidget(windowWrapper(), 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 + if ( showGrabBar && (!isTool()) ) + g->addRowSpacing(4, 8); // bottom handles + else + g->addRowSpacing(4, 4); // bottom handles + + g->addColSpacing(0, 4); + g->addColSpacing(2, 4); + + // Pack the titlebar HBox with items + hb = new QHBoxLayout(); + 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); + connect( button[BtnMenu], SIGNAL(pressed()), + this, SLOT(menuButtonPressed()) ); + hb->addWidget( button[BtnMenu] ); + } + break; + + // Sticky button + case 'S': + if (!button[BtnSticky]) + { + button[BtnSticky] = new KDEDefaultButton(this, "sticky", + largeButtons, isLeft, true, NULL); + button[BtnSticky]->turnOn( isSticky() ); + connect( button[BtnSticky], SIGNAL(clicked()), + this, SLOT(toggleSticky()) ); + hb->addWidget( button[BtnSticky] ); + } + break; + + // Help button + case 'H': + if( providesContextHelp() && (!button[BtnHelp]) ) + { + button[BtnHelp] = new KDEDefaultButton(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 KDEDefaultButton(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 KDEDefaultButton(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 KDEDefaultButton(this, "close", + largeButtons, isLeft, true, close_bits); + 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(3); + } + } +} + + +void KDEDefaultClient::iconChange() +{ + if (button[BtnMenu] && button[BtnMenu]->isVisible()) + button[BtnMenu]->repaint(false); +} + +void KDEDefaultClient::stickyChange(bool on) +{ + if (button[BtnSticky]) { + button[BtnSticky]->turnOn(on); + button[BtnSticky]->repaint(false); + } +} + +void KDEDefaultClient::slotMaximize() +{ + if ( button[BtnMax]->last_button == MidButton ) + maximize( MaximizeVertical ); + else if ( button[BtnMax]->last_button == RightButton ) + maximize( MaximizeHorizontal ); + else + maximize(); +} + + +void KDEDefaultClient::resizeEvent( QResizeEvent* e) +{ + Client::resizeEvent( e ); + doShape(); + calcHiddenButtons(); + + if (isVisibleToTLW()) + { + update(rect()); + 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 ) + update( 0, height() - dy + 1, width(), dy ); + + if ( dx ) + { + update( width() - dx + 1, 0, dx, height() ); + update( QRect( QPoint(4,4), titlebar->geometry().bottomLeft() - + QPoint(1,0) ) ); + update( QRect( titlebar->geometry().topRight(), QPoint( width() - 4, + titlebar->geometry().bottom() ) ) ); + // Titlebar needs no paint event + QApplication::postEvent( this, new QPaintEvent(titlebar->geometry(), + FALSE) ); + } + } +} + + +void KDEDefaultClient::captionChange( const QString& ) +{ + repaint( titlebar->geometry(), false ); +} + + +void KDEDefaultClient::paintEvent( QPaintEvent* ) +{ + if (!KDEDefault_initialized) + return; + + QColorGroup g; + int offset; + KPixmap* upperGradient = isActive() ? aUpperGradient : iUpperGradient; + + QPainter p(this); + + // Obtain widget bounds. + QRect r(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(Options::TitleBar, 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(Options::Frame, 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(Options::Frame, 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 && (!isTool()) ) + { + 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(Options::TitleBar, isActive() ); + QColor c2 = options->color(Options::Frame, 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()); + p2.drawTiledPixmap( r.x()+captionWidth+1, 0, r.width()-captionWidth-4, + titleHeight+1, *titlePix ); + } + + p2.setPen( options->color(Options::Font, isActive()) ); + p2.drawText(r.x(), 1, r.width(), r.height(), + AlignLeft | AlignVCenter, caption() ); + + bitBlt( this, 2, 2, titleBuffer ); + + p2.end(); + + // Ensure a shaded window has no unpainted areas + p.setPen(c2); + p.drawLine(x+4, y+titleHeight+4, x2-4, y+titleHeight+4); +} + + +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 *ev) +{ + calcHiddenButtons(); + doShape(); + Client::showEvent(ev); +} + + +void KDEDefaultClient::mouseDoubleClickEvent( QMouseEvent * e ) +{ + if (titlebar->geometry().contains( e->pos() ) ) + workspace()->performWindowOperation( this, options->operationTitlebarDblClick() ); + workspace()->requestFocus( this ); +} + + +void KDEDefaultClient::maximizeChange(bool m) +{ + if (button[BtnMax]) + button[BtnMax]->setBitmap(m ? minmax_bits : maximize_bits); +} + + +void KDEDefaultClient::activeChange(bool) +{ + for(int i=KDEDefaultClient::BtnHelp; i < KDEDefaultClient::BtnCount; i++) + if(button[i]) + button[i]->repaint(false); + repaint(false); +} + + +// 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 ? 140 : 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(); + } +} + + +Client::MousePosition KDEDefaultClient::mousePosition( const QPoint& p ) const +{ + MousePosition m = Nowhere; + + // Modify the mouse position if we are using a grab bar. + if (showGrabBar && (!isTool()) ) + if (p.y() < (height() - 8)) + m = Client::mousePosition(p); + else + { + if (p.x() >= (width() - 20)) + m = BottomRight; + else if (p.x() <= 20) + m = BottomLeft; + else + m = Bottom; + } + else + m = Client::mousePosition(p); + + return m; +} + + +// Make sure the menu button follows double click conventions set in kcontrol +void KDEDefaultClient::menuButtonPressed() +{ + static QTime* t = 0; + static KDEDefaultClient* tc = 0; + if ( !t ) + t = new QTime; + + if ( tc != this || t->elapsed() > QApplication::doubleClickInterval() ) + { + QPoint menupoint ( button[BtnMenu]->rect().bottomLeft().x()-1, + button[BtnMenu]->rect().bottomLeft().y()+2 ); + workspace()->clientPopup(this)->popup( + button[BtnMenu]->mapToGlobal( menupoint )); + } + else closeWindow(); + + t->start(); + tc = this; +} + + +// Extended KWin plugin interface +extern "C" +{ + Client *allocate(Workspace *ws, WId w, int) + { + return(new KDEDefaultClient(ws, w)); + } + + void init() + { + clientHandler = new KDEDefaultHandler(); + } + + void reset() + { + clientHandler->reset(); + } + + void deinit() + { + delete clientHandler; + } +} + +#include "kdedefault.moc" +// vim: ts=4 diff --git a/clients/default/kdedefault.h b/clients/default/kdedefault.h new file mode 100644 index 0000000000..9b900d53c9 --- /dev/null +++ b/clients/default/kdedefault.h @@ -0,0 +1,115 @@ +/* + * $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. + */ + +#ifndef _KDE_DEFAULT_H +#define _KDE_DEFAULT_H + +#include +#include +#include +#include "../../client.h" + +class QSpacerItem; +class QHBoxLayout; + +namespace KWinInternal { + + +class KDEDefaultHandler: public QObject +{ + public: + KDEDefaultHandler(); + ~KDEDefaultHandler(); + void reset(); + + private: + void readConfig(); + void createPixmaps(); + void freePixmaps(); + void drawButtonBackground(KPixmap *pix, const QColorGroup &g, bool sunken); +}; + + +class KDEDefaultButton : public QButton +{ + public: + KDEDefaultButton(Client *parent=0, const char *name=0, bool largeButton=true, + bool isLeftButton=true, bool isStickyButton=false, + const unsigned char *bitmap=NULL); + ~KDEDefaultButton(); + void setBitmap(const unsigned char *bitmap); + QSize sizeHint() const; + int last_button; + void turnOn( bool isOn ); + + protected: + void enterEvent(QEvent *){ isMouseOver=true; repaint(false); } + void leaveEvent(QEvent *){ isMouseOver=false; repaint(false); } + void mousePressEvent( QMouseEvent* e ); + void mouseReleaseEvent( QMouseEvent* e ); + void drawButton(QPainter *p); + void drawButtonLabel(QPainter*) {;} + + Client* client; + QBitmap* deco; + bool large; + bool isLeft; + bool isSticky; + bool isMouseOver; +}; + + +class KDEDefaultClient : public KWinInternal::Client +{ + Q_OBJECT + + public: + KDEDefaultClient( Workspace *ws, WId w, QWidget *parent=0, + const char *name=0 ); + ~KDEDefaultClient() {;} + + 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 stickyChange(bool on); + MousePosition mousePosition(const QPoint &) const; + + protected slots: + void slotMaximize(); + void menuButtonPressed(); + + private: + void doShape(); + void calcHiddenButtons(); + void addClientButtons( const QString& s, bool isLeft=true ); + + enum Buttons{ BtnHelp=0, BtnMax, BtnIconify, BtnClose, + BtnMenu, BtnSticky, BtnCount }; + KDEDefaultButton* button[ KDEDefaultClient::BtnCount ]; + int lastButtonWidth; + int titleHeight; + bool largeButtons; + QHBoxLayout* hb; + QSpacerItem* titlebar; +}; + +}; + +#endif +// vim: ts=4 diff --git a/plugins.cpp b/plugins.cpp index 3e796dcf6a..07eab41642 100644 --- a/plugins.cpp +++ b/plugins.cpp @@ -18,7 +18,6 @@ Copyright (C) 1999, 2000 Daniel M. Duley #include #include "plugins.h" -#include "kdedefault.h" #if 0 #define lt_ptr lt_ptr_t @@ -26,168 +25,112 @@ Copyright (C) 1999, 2000 Daniel M. Duley using namespace KWinInternal; -PluginMenu::PluginMenu(PluginMgr *manager, QWidget *parent, const char *name) - : QPopupMenu(parent, name) -{ - connect(this, SIGNAL(aboutToShow()), SLOT(slotAboutToShow())); - connect(this, SIGNAL(activated(int)), SLOT(slotActivated(int))); - mgr = manager; -} +const char* defaultPlugin = "libkwindefault"; -void PluginMenu::slotAboutToShow() -{ - clear(); - fileList.clear(); - insertItem(i18n("KDE 2"), 0); - idCount = 1; - idCurrent = 0; - - QDir dir; - dir.setFilter(QDir::Files); - const QFileInfoList *list; - int count = KGlobal::dirs()->findDirs("data", "kwin").count(); - if(count){ - dir.setPath(KGlobal::dirs()->findDirs("data", "kwin") - [count > 1 ? 1 : 0]); - if(dir.exists()){ - list = dir.entryInfoList(); - if(list){ - QFileInfoListIterator it(*list); - QFileInfo *fi; - for(; (fi = it.current()) != NULL; ++it){ - if(KDesktopFile::isDesktopFile(fi->absFilePath())) - parseDesktop(fi); - } - } - } - if(count > 1){ - dir.setPath(KGlobal::dirs()->findDirs("data", "kwin")[0]); - if(dir.exists()){ - list = dir.entryInfoList(); - if(list){ - QFileInfoListIterator it(*list); - QFileInfo *fi; - for(; (fi = it.current()) != NULL; ++it){ - if(KDesktopFile::isDesktopFile(fi->absFilePath())) - parseDesktop(fi); - } - } - } - } - } - setItemChecked(idCurrent, true); -} - -void PluginMenu::parseDesktop(QFileInfo *fi) -{ - QString tmpStr; - KSimpleConfig config(fi->absFilePath(), true); - config.setDesktopGroup(); - tmpStr = config.readEntry("X-KDE-Library", ""); - if(tmpStr.isEmpty()){ - qWarning("KWin: Invalid plugin: %s", fi->absFilePath().latin1()); - return; - } - fileList.append(tmpStr); - if (tmpStr == mgr->currentPlugin()) - idCurrent = idCount; - tmpStr = config.readEntry("Name", ""); - if(tmpStr.isEmpty()) - tmpStr = fi->baseName(); - insertItem(tmpStr, idCount); - ++idCount; -} - -void PluginMenu::slotActivated(int id) -{ - QString newPlugin; - if (id > 0) - newPlugin = fileList[id-1]; - - KConfig *config = KGlobal::config(); - config->setGroup("Style"); - config->writeEntry("PluginLib", newPlugin); - config->sync(); - // We can't do this directly because we might destruct a client - // underneath our own feet while doing so. - QTimer::singleShot(0, mgr, SLOT(updatePlugin())); -} PluginMgr::PluginMgr() : QObject() { alloc_ptr = NULL; handle = 0; - pluginStr = "standard"; + pluginStr = "kwin_undefined"; updatePlugin(); } PluginMgr::~PluginMgr() { - if(handle) + if(handle) { + // Call the plugin's cleanup function + lt_ptr_t deinit_func = lt_dlsym(handle, "deinit"); + if (deinit_func) + ((void (*)())deinit_func)(); lt_dlclose(handle); + } } -bool -PluginMgr::updatePlugin() +void PluginMgr::updatePlugin() { KConfig *config = KGlobal::config(); config->reparseConfiguration(); config->setGroup("Style"); - QString newPlugin = config->readEntry("PluginLib", "standard" ); - if (newPlugin != pluginStr) { - loadPlugin(newPlugin); - return true; - } - return false; + QString newPlugin = config->readEntry("PluginLib", defaultPlugin); + + if (newPlugin != pluginStr) + loadPlugin(newPlugin); } Client* PluginMgr::allocateClient(Workspace *ws, WId w, bool tool) { - if(alloc_ptr) + // We are guaranteed to have a plugin loaded, + // otherwise, kwin exits during loadPlugin - but verify anyway + if (alloc_ptr) return(alloc_ptr(ws, w, tool)); else - return(new KDEClient(ws, w)); + return NULL; } +// returns true if plugin was loaded successfully void PluginMgr::loadPlugin(QString nameStr) { static bool dlregistered = false; lt_dlhandle oldHandle = handle; - pluginStr = "standard"; handle = 0; - alloc_ptr = 0; - if ( !nameStr.isEmpty() && nameStr != "standard" ) { - if(!dlregistered){ - dlregistered = true; - lt_dlinit(); - } - QString path = KLibLoader::findLibrary(nameStr.latin1()); - - if( !path.isEmpty() ) { - if ( (handle = lt_dlopen(path.latin1() ) ) ) { - lt_ptr_t init_func = lt_dlsym(handle, "init"); - if (init_func) - ((void (*)())init_func)(); - lt_ptr_t alloc_func = lt_dlsym(handle, "allocate"); - if(alloc_func) { - alloc_ptr = (Client* (*)(Workspace *ws, WId w, int tool))alloc_func; - } else{ - qWarning("KWin: %s is not a KWin plugin.", path.latin1()); - lt_dlclose(handle); - handle = 0; - } - } else { - qWarning("KWin: cannot load client plugin %s.", path.latin1()); - } - } + if(!dlregistered) { + dlregistered = true; + lt_dlinit(); } - if ( alloc_ptr ) - pluginStr = nameStr; + QString path = KLibLoader::findLibrary(nameStr.latin1()); + + // If the plugin was not found, try to find the default + if (path.isEmpty()) { + nameStr = defaultPlugin; + path = KLibLoader::findLibrary(nameStr.latin1()); + } + + // If no library was found, exit kwin with an error message + if (path.isEmpty()) + shutdownKWin(i18n("No window decoration plugin library was found!")); + + // Check if this library is not already loaded. + if(pluginStr == nameStr) + return; + + // Try loading the requested plugin + handle = lt_dlopen(path.latin1()); + + // If that fails, fall back to the default plugin + if (!handle) { + nameStr = defaultPlugin; + path = KLibLoader::findLibrary(nameStr.latin1()); + if (!path.isEmpty()) + handle = lt_dlopen(path.latin1()); + } + + if (!handle) + shutdownKWin(i18n("The default decoration plugin is corrupt " + "and could not be loaded!")); + + // Call the plugin's initialisation function + lt_ptr_t init_func = lt_dlsym(handle, "init"); + if (init_func) + ((void (*)())init_func)(); + + lt_ptr_t alloc_func = lt_dlsym(handle, "allocate"); + if(alloc_func) { + alloc_ptr = (Client* (*)(Workspace *ws, WId w, int tool))alloc_func; + } else { + qWarning("KWin: The library %s is not a KWin plugin.", path.latin1()); + lt_dlclose(handle); + exit(1); + } + + pluginStr = nameStr; emit resetAllClients(); + + // Call the old plugin's cleanup function if(oldHandle) { lt_ptr_t deinit_func = lt_dlsym(oldHandle, "deinit"); if (deinit_func) @@ -203,5 +146,12 @@ void PluginMgr::resetPlugin() ((void (*)())reset_func)(); } +void PluginMgr::shutdownKWin(const QString &error_msg) +{ + qWarning( (i18n("KWin: ") + error_msg + + i18n("\nKWin will now exit...")).latin1() ); + exit(1); +} + #include "plugins.moc" diff --git a/plugins.h b/plugins.h index 47db5f6f29..ff7c6f2b09 100644 --- a/plugins.h +++ b/plugins.h @@ -27,32 +27,17 @@ public: void loadPlugin(QString name); QString currentPlugin() { return pluginStr; } public slots: - bool updatePlugin(); + void updatePlugin(); void resetPlugin(); signals: void resetAllClients(); protected: + void shutdownKWin(const QString& error_msg); Client* (*alloc_ptr)(Workspace *ws, WId w, int tool); lt_dlhandle handle; QString pluginStr; }; -class PluginMenu : public QPopupMenu -{ - Q_OBJECT -public: - PluginMenu(PluginMgr *manager, QWidget *parent=0, const char *name=0); -protected slots: - void slotAboutToShow(); - void slotActivated(int id); -protected: - void parseDesktop(QFileInfo *fi); - QStringList fileList; - int idCount; - int idCurrent; - PluginMgr *mgr; -}; - }; #endif