summaryrefslogtreecommitdiffstats
path: root/kwin/clients/keramik
diff options
context:
space:
mode:
Diffstat (limited to 'kwin/clients/keramik')
-rw-r--r--kwin/clients/keramik/Makefile.am44
-rw-r--r--kwin/clients/keramik/config/Makefile.am13
-rw-r--r--kwin/clients/keramik/config/config.cpp110
-rw-r--r--kwin/clients/keramik/config/config.h57
-rw-r--r--kwin/clients/keramik/config/keramikconfig.ui76
-rw-r--r--kwin/clients/keramik/embedtool.cpp230
-rw-r--r--kwin/clients/keramik/keramik.cpp1834
-rw-r--r--kwin/clients/keramik/keramik.desktop31
-rw-r--r--kwin/clients/keramik/keramik.h201
-rw-r--r--kwin/clients/keramik/pics/border-left.pngbin0 -> 139 bytes
-rw-r--r--kwin/clients/keramik/pics/border-right.pngbin0 -> 142 bytes
-rw-r--r--kwin/clients/keramik/pics/bottom-center.pngbin0 -> 149 bytes
-rw-r--r--kwin/clients/keramik/pics/bottom-left.pngbin0 -> 158 bytes
-rw-r--r--kwin/clients/keramik/pics/bottom-right.pngbin0 -> 160 bytes
-rw-r--r--kwin/clients/keramik/pics/caption-large-center.pngbin0 -> 176 bytes
-rw-r--r--kwin/clients/keramik/pics/caption-large-left.pngbin0 -> 394 bytes
-rw-r--r--kwin/clients/keramik/pics/caption-large-right.pngbin0 -> 498 bytes
-rw-r--r--kwin/clients/keramik/pics/caption-small-center.pngbin0 -> 177 bytes
-rw-r--r--kwin/clients/keramik/pics/caption-small-left.pngbin0 -> 425 bytes
-rw-r--r--kwin/clients/keramik/pics/caption-small-right.pngbin0 -> 504 bytes
-rw-r--r--kwin/clients/keramik/pics/grabbar-center.pngbin0 -> 167 bytes
-rw-r--r--kwin/clients/keramik/pics/grabbar-left.pngbin0 -> 211 bytes
-rw-r--r--kwin/clients/keramik/pics/grabbar-right.pngbin0 -> 208 bytes
-rw-r--r--kwin/clients/keramik/pics/titlebar-center.pngbin0 -> 160 bytes
-rw-r--r--kwin/clients/keramik/pics/titlebar-left.pngbin0 -> 240 bytes
-rw-r--r--kwin/clients/keramik/pics/titlebar-right.pngbin0 -> 288 bytes
-rw-r--r--kwin/clients/keramik/pics/titlebutton-round-huge.pngbin0 -> 7868 bytes
-rw-r--r--kwin/clients/keramik/pics/titlebutton-round-large.pngbin0 -> 4380 bytes
-rw-r--r--kwin/clients/keramik/pics/titlebutton-round.pngbin0 -> 1789 bytes
-rw-r--r--kwin/clients/keramik/pics/titlebutton-square-huge.pngbin0 -> 4656 bytes
-rw-r--r--kwin/clients/keramik/pics/titlebutton-square-large.pngbin0 -> 2725 bytes
-rw-r--r--kwin/clients/keramik/pics/titlebutton-square.pngbin0 -> 1082 bytes
32 files changed, 2596 insertions, 0 deletions
diff --git a/kwin/clients/keramik/Makefile.am b/kwin/clients/keramik/Makefile.am
new file mode 100644
index 000000000..d5969643c
--- /dev/null
+++ b/kwin/clients/keramik/Makefile.am
@@ -0,0 +1,44 @@
+INCLUDES = -I$(srcdir)/../../lib $(all_includes)
+
+SUBDIRS = . config
+
+noinst_PROGRAMS = embedtool
+
+noinst_HEADERS = tiles.h
+
+embedtool_SOURCES = embedtool.cpp
+embedtool_LDADD = $(LIB_QT)
+embedtool_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+
+kde_module_LTLIBRARIES = kwin3_keramik.la
+
+kwin3_keramik_la_SOURCES = keramik.cpp
+kwin3_keramik_la_COMPILE_FIRST = tiles.h
+kwin3_keramik_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+kwin3_keramik_la_LIBADD = $(LIB_KDEUI) ../../lib/libkdecorations.la
+#kwin3_keramik_la_LDFLAGS = $(all_libraries) -avoid-version -module $(KDE_RPATH) $(KDE_MT_LDFLAGS)
+
+METASOURCES = AUTO
+noinst_headers = keramik.h tiles.h
+
+lnkdir = $(kde_datadir)/kwin
+lnk_DATA = keramik.desktop
+
+EXTRA_DIST = $(lnk_DATA)
+
+tiles.h: pics/caption-large-left.png pics/caption-small-right.png pics/titlebar-center.png \
+ pics/titlebutton-square.png pics/border-left.png pics/caption-large-right.png \
+ pics/grabbar-center.png pics/titlebar-left.png pics/border-right.png \
+ pics/caption-small-center.png pics/grabbar-left.png pics/titlebar-right.png \
+ pics/caption-large-center.png pics/caption-small-left.png pics/grabbar-right.png \
+ pics/titlebutton-round.png pics/bottom-left.png pics/bottom-right.png \
+ pics/bottom-center.png \
+ pics/titlebutton-square-large.png pics/titlebutton-square-huge.png \
+ pics/titlebutton-round-large.png pics/titlebutton-round-huge.png
+
+tiles.h: embedtool
+ pics=`ls $(srcdir)/pics/*.png 2>/dev/null` ;\
+ ./embedtool $$pics
+
+keramik.lo: tiles.h
+
diff --git a/kwin/clients/keramik/config/Makefile.am b/kwin/clients/keramik/config/Makefile.am
new file mode 100644
index 000000000..3021635ca
--- /dev/null
+++ b/kwin/clients/keramik/config/Makefile.am
@@ -0,0 +1,13 @@
+INCLUDES = $(all_includes)
+
+kde_module_LTLIBRARIES = kwin_keramik_config.la
+
+kwin_keramik_config_la_SOURCES = config.cpp keramikconfig.ui
+kwin_keramik_config_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+kwin_keramik_config_la_LIBADD = $(LIB_KDEUI)
+
+METASOURCES = AUTO
+noinst_HEADERS = config.h keramikconfig.h
+
+lnkdir = $(kde_datadir)/kwin
+
diff --git a/kwin/clients/keramik/config/config.cpp b/kwin/clients/keramik/config/config.cpp
new file mode 100644
index 000000000..c548ca184
--- /dev/null
+++ b/kwin/clients/keramik/config/config.cpp
@@ -0,0 +1,110 @@
+/*
+ *
+ * Keramik KWin client configuration module
+ *
+ * Copyright (C) 2002 Fredrik Hglund <fredrik@kde.org>
+ *
+ * Based on the Quartz configuration module,
+ * Copyright (c) 2001 Karol Szwed <gallium@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the license, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <kglobal.h>
+#include <klocale.h>
+
+#include <qcheckbox.h>
+
+#include "config.h"
+#include "config.moc"
+
+extern "C"
+{
+ KDE_EXPORT QObject* allocate_config( KConfig* conf, QWidget* parent )
+ {
+ return ( new KeramikConfig( 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
+ */
+
+KeramikConfig::KeramikConfig( KConfig* conf, QWidget* parent )
+ : QObject( parent )
+{
+ KGlobal::locale()->insertCatalogue("kwin_clients");
+ c = new KConfig( "kwinkeramikrc" );
+
+ ui = new KeramikConfigUI( parent );
+ connect( ui->showAppIcons, SIGNAL(clicked()), SIGNAL(changed()) );
+ connect( ui->smallCaptions, SIGNAL(clicked()), SIGNAL(changed()) );
+ connect( ui->largeGrabBars, SIGNAL(clicked()), SIGNAL(changed()) );
+ connect( ui->useShadowedText, SIGNAL(clicked()), SIGNAL(changed()) );
+
+ load( conf );
+ ui->show();
+}
+
+
+KeramikConfig::~KeramikConfig()
+{
+ delete ui;
+ delete c;
+}
+
+
+// Loads the configurable options from the kwinrc config file
+// It is passed the open config from kwindecoration to improve efficiency
+void KeramikConfig::load( KConfig* )
+{
+ c->setGroup("General");
+ ui->showAppIcons->setChecked( c->readBoolEntry("ShowAppIcons", true) );
+ ui->smallCaptions->setChecked( c->readBoolEntry("SmallCaptionBubbles", false) );
+ ui->largeGrabBars->setChecked( c->readBoolEntry("LargeGrabBars", true) );
+ ui->useShadowedText->setChecked( c->readBoolEntry("UseShadowedText", true) );
+}
+
+
+// Saves the configurable options to the kwinrc config file
+void KeramikConfig::save( KConfig* )
+{
+ c->setGroup( "General" );
+ c->writeEntry( "ShowAppIcons", ui->showAppIcons->isChecked() );
+ c->writeEntry( "SmallCaptionBubbles", ui->smallCaptions->isChecked() );
+ c->writeEntry( "LargeGrabBars", ui->largeGrabBars->isChecked() );
+ c->writeEntry( "UseShadowedText", ui->useShadowedText->isChecked() );
+ c->sync();
+}
+
+
+// Sets UI widget defaults which must correspond to style defaults
+void KeramikConfig::defaults()
+{
+ ui->showAppIcons->setChecked( true );
+ ui->smallCaptions->setChecked( false );
+ ui->largeGrabBars->setChecked( true );
+ ui->useShadowedText->setChecked( true );
+
+ emit changed();
+}
+
+// vim: set noet ts=4 sw=4:
diff --git a/kwin/clients/keramik/config/config.h b/kwin/clients/keramik/config/config.h
new file mode 100644
index 000000000..71090531d
--- /dev/null
+++ b/kwin/clients/keramik/config/config.h
@@ -0,0 +1,57 @@
+/*
+ * Keramik KWin client configuration module
+ *
+ * Copyright (C) 2002 Fredrik Hglund <fredrik@kde.org>
+ *
+ * Based on the Quartz configuration module,
+ * Copyright (c) 2001 Karol Szwed <gallium@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the license, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __KWIN_KERAMIK_CONFIG_H
+#define __KWIN_KERAMIK_CONFIG_H
+
+#include <kconfig.h>
+
+#include "keramikconfig.h"
+
+class KeramikConfig: public QObject
+{
+ Q_OBJECT
+
+ public:
+ KeramikConfig( KConfig* conf, QWidget* parent );
+ ~KeramikConfig();
+
+ // These public signals/slots work similar to KCM modules
+ signals:
+ void changed();
+
+ public slots:
+ void load( KConfig* conf );
+ void save( KConfig* conf );
+ void defaults();
+
+ private:
+ KeramikConfigUI *ui;
+ KConfig *c;
+};
+
+
+#endif
+
+// vim: set noet ts=4 sw=4:
diff --git a/kwin/clients/keramik/config/keramikconfig.ui b/kwin/clients/keramik/config/keramikconfig.ui
new file mode 100644
index 000000000..f074a00b8
--- /dev/null
+++ b/kwin/clients/keramik/config/keramikconfig.ui
@@ -0,0 +1,76 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>KeramikConfigUI</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KeramikConfigUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>287</width>
+ <height>102</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Keramik</string>
+ </property>
+ <vbox>
+ <property name="margin">
+ <cstring>0</cstring>
+ </property>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>showAppIcons</cstring>
+ </property>
+ <property name="text">
+ <string>Display the window &amp;icon in the caption bubble</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this option if you want the window icon to be displayed in the caption bubble next to the titlebar text.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>smallCaptions</cstring>
+ </property>
+ <property name="text">
+ <string>Draw &amp;small caption bubbles on active windows</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this option if you want the caption bubble to have the same size on active windows that it has on inactive ones. This option is useful for laptops or low resolution displays where you want maximize the amount of space available to the window contents.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>largeGrabBars</cstring>
+ </property>
+ <property name="text">
+ <string>Draw g&amp;rab bars below windows</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this option if you want a grab bar to be drawn below windows. When this option is not selected only a thin border will be drawn in its place.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>useShadowedText</cstring>
+ </property>
+ <property name="text">
+ <string>Use shadowed &amp;text</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this option if you want the titlebar text to have a 3D look with a shadow behind it.</string>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<includes>
+ <include location="global" impldecl="in implementation">kdialog.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/>
+</UI>
diff --git a/kwin/clients/keramik/embedtool.cpp b/kwin/clients/keramik/embedtool.cpp
new file mode 100644
index 000000000..b0e5f1c72
--- /dev/null
+++ b/kwin/clients/keramik/embedtool.cpp
@@ -0,0 +1,230 @@
+/*
+ * Keramik KWin embed tool (version 1.0)
+ *
+ * Copyright (C) 2002 Fredrik Hglund <fredrik@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the license, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <qimage.h>
+#include <qtextstream.h>
+#include <qregexp.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qdatetime.h>
+
+#include <iostream>
+
+static int primes[] = {
+ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
+ 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
+ 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
+ 127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
+ 179, 181, 191, 193, 197, 199, 211, 223, 227, 229
+};
+
+struct EmbedImage {
+ QString string;
+ int width;
+ int height;
+ bool alpha;
+ QString name;
+};
+
+class KeramikEmbedder {
+public:
+ KeramikEmbedder();
+ ~KeramikEmbedder();
+
+ void embed( const char * );
+ void writeIndex();
+
+private:
+ QFile *file;
+ QPtrList<EmbedImage> *index;
+ QTextStream stream;
+};
+
+KeramikEmbedder::KeramikEmbedder()
+{
+ QDateTime date( QDateTime::currentDateTime() );
+ QString datestring( date.toString() );
+
+ file = new QFile( "tiles.h" );
+ file->open( IO_WriteOnly | IO_Truncate );
+
+ stream.setDevice( file );
+
+ stream << "/*\n";
+ stream << " * Generated by embedtool 1.0 on " << datestring << endl;
+ stream << " */\n\n";
+
+ stream << "#ifndef __TILES_H\n";
+ stream << "#define __TILES_H\n\n";
+ stream << "#include <qimage.h>\n";
+ stream << "#include <qdict.h>\n\n";
+ stream << "namespace Keramik {\n\n";
+
+ index = new QPtrList<EmbedImage>;
+ index->setAutoDelete( true );
+}
+
+KeramikEmbedder::~KeramikEmbedder()
+{
+ stream << "} // namespace Keramik\n\n";
+ stream << "#endif // __TILES_H\n\n";
+ stream << "// vim: set noet ts=4 sw=4:\n";
+
+ file->close();
+ delete file;
+ delete index;
+}
+
+void KeramikEmbedder::embed( const char *name )
+{
+ QFileInfo fileinfo( name );
+ QString basename( fileinfo.baseName() );
+ QString codename( basename );
+ QImage image( name );
+
+ codename = codename.replace( QRegExp("[^a-zA-Z0-9]"), "_" );
+
+ stream << "\tstatic const QRgb " << codename << "_data[] = {" << endl << "\t\t";
+ stream.setf( QTextStream::hex | QTextStream::right );
+ stream.fill( '0' );
+
+ int pixels = image.width() * image.height();
+ Q_UINT32 *data = reinterpret_cast<Q_UINT32*>( image.bits() );
+ bool hasAlpha = false;
+
+
+ for ( int i = 0, j = 0; i < pixels; i++ ) {
+ if ( qAlpha( *data ) && qAlpha( *data ) != 0xff )
+ hasAlpha = true;
+
+ stream << "0x" << qSetW(8) << *(data++);
+
+ if ( i != pixels-1 ) {
+ stream << ',';
+
+ if ( j++ > 4 ) {
+ j = 0;
+ stream << endl << "\t\t";
+ } else
+ stream << ' ';
+ }
+ }
+
+ stream.reset();
+
+ stream << endl << "\t}; // " << codename << "_data" << endl << endl;
+
+ EmbedImage *imginfo = new EmbedImage;
+ imginfo->width = image.width();
+ imginfo->height = image.height();
+ imginfo->alpha = hasAlpha;
+ imginfo->name = codename;
+ imginfo->string = basename;
+ index->append( imginfo );
+}
+
+void KeramikEmbedder::writeIndex()
+{
+ stream << "\tstruct EmbedImage {\n";
+ stream << "\t\tconst char *name;\n";
+ stream << "\t\tint width;\n";
+ stream << "\t\tint height;\n";
+ stream << "\t\tbool alpha;\n";
+ stream << "\t\tconst QRgb *data;\n";
+ stream << "\t};\n\n";
+
+ uint i = 0;
+ stream << "\tstatic const EmbedImage image_db[] = {\n";
+ for ( EmbedImage *image = index->first(); image; image = index->next() )
+ {
+ stream << "\t\t{ \"" << image->string << "\", "
+ << image->width << ", " << image->height <<
+ ", " << (image->alpha ? "true" : "false")
+ << ", " << image->name << "_data }";
+ if ( i++ < index->count() - 1 )
+ stream << ',';
+ stream << endl;
+ }
+ stream << "\t};\n\n";
+
+ uint prime = 0;
+
+ for ( i = 0; i < 50; i++ )
+ if ( (prime = primes[i]) >= index->count() )
+ break;
+
+ stream << "\tclass KeramikImageDb {\n";
+ stream << "\tprivate:\n";
+ stream << "\t\tstatic KeramikImageDb *m_inst;\n";
+ stream << "\t\tQDict<QImage> *db;\n\n";
+ stream << "\t\tKeramikImageDb() {\n";
+ stream << "\t\t\tdb = new QDict<QImage>( " << prime << " );\n";
+ stream << "\t\t\tdb->setAutoDelete( true );\n\n";
+ stream << "\t\t\tfor ( int i = 0; i < " << index->count() << "; i++ ) {\n";
+ stream << "\t\t\t\tQImage *img = new QImage( (uchar*)image_db[i].data,\n";
+ stream << "\t\t\t\t\t\timage_db[i].width, image_db[i].height,\n";
+ stream << "\t\t\t\t\t\t32, NULL, 0, QImage::LittleEndian );\n\n";
+ stream << "\t\t\t\tif ( image_db[i].alpha )\n";
+ stream << "\t\t\t\t\timg->setAlphaBuffer( true );\n\n";
+ stream << "\t\t\t\tdb->insert( image_db[i].name, img );\n";
+ stream << "\t\t\t}\n";
+ stream << "\t\t}\n\n";
+ stream << "\t\t~KeramikImageDb() {\n";
+ stream << "\t\t\tdelete db;\n";
+ stream << "\t\t}\n\n";
+ stream << "\tpublic:\n";
+ stream << "\t\tstatic KeramikImageDb* instance() {\n";
+ stream << "\t\t\tif ( ! m_inst ) m_inst = new KeramikImageDb;\n";
+ stream << "\t\t\treturn m_inst;\n";
+ stream << "\t\t}\n\n";
+ stream << "\t\tstatic void release() {\n";
+ stream << "\t\t\tif ( m_inst ) delete m_inst;\n";
+ stream << "\t\t\tm_inst = NULL;\n";
+ stream << "\t\t}\n\n";
+ stream << "\t\tQImage *image( const QString &name ) const {\n";
+ stream << "\t\t\treturn db->find( name );\n";
+ stream << "\t\t}\n\n";
+ stream << "\t}; // class KeramikImageDb\n\n";
+ stream << "\tKeramikImageDb *KeramikImageDb::m_inst = NULL;\n\n";
+}
+
+int main( int argv, char **argc )
+{
+ if ( argv < 2 ) {
+ std::cout << "Insufficient arguments" << std::endl;
+ return 1;
+ }
+
+ KeramikEmbedder embedder;
+
+ for ( int i = 1; i < argv; i++ )
+ {
+ std::cout << argc[i] << std::endl;
+ embedder.embed( argc[i] );
+ }
+
+ embedder.writeIndex();
+
+ return 0;
+}
+
+// vim: set noet ts=4 sw=4:
+
diff --git a/kwin/clients/keramik/keramik.cpp b/kwin/clients/keramik/keramik.cpp
new file mode 100644
index 000000000..57a51bce1
--- /dev/null
+++ b/kwin/clients/keramik/keramik.cpp
@@ -0,0 +1,1834 @@
+/*
+ *
+ * Keramik KWin client (version 0.8)
+ *
+ * Copyright (C) 2002 Fredrik H�lund <fredrik@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the license, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <kconfig.h>
+#include <klocale.h>
+#include <kiconeffect.h>
+
+#include <qpainter.h>
+#include <qlayout.h>
+#include <qbitmap.h>
+#include <qstyle.h>
+#include <qtooltip.h>
+#include <qwidget.h>
+#include <qlabel.h>
+
+#include <X11/Xlib.h>
+
+#include "keramik.h"
+#include "keramik.moc"
+
+
+
+// -------------------------------------------------------------------------------------------
+
+static void flip( QPixmap *&pix )
+{
+ QPixmap *tmp = new QPixmap( pix->xForm( QWMatrix(-1,0,0,1,pix->width(),0) ) );
+ delete pix;
+ pix = tmp;
+}
+
+static void flip( QBitmap *&pix )
+{
+ QBitmap *tmp = new QBitmap( pix->xForm( QWMatrix(-1,0,0,1,pix->width(),0) ) );
+ delete pix;
+ pix = tmp;
+}
+
+namespace Keramik
+{
+
+ const int buttonMargin = 9; // Margin between the window edge and the buttons
+ const int buttonSpacing = 4; // Spacing between the titlebar buttons
+ const int iconSpacing = 5; // Spacing between the icon and the text label
+
+ // Default button layout
+ const char default_left[] = "M";
+ const char default_right[] = "HIAX";
+
+ // Titlebar button bitmaps
+ const unsigned char menu_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0xf0, 0x07, 0x00,
+ 0xe0, 0x03, 0x00, 0xc0, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00};
+
+ const unsigned char on_all_desktops_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x80, 0x01, 0x00, 0x80, 0x01, 0x00, 0xf0, 0x0f, 0x00,
+ 0xf0, 0x0f, 0x00, 0x80, 0x01, 0x00, 0x80, 0x01, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00};
+
+ const unsigned char not_on_all_desktops_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00,
+ 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00};
+
+ const unsigned char help_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00,
+ 0xf0, 0x07, 0x00, 0x30, 0x06, 0x00, 0x00, 0x07, 0x00, 0x80, 0x03, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00};
+
+ const unsigned char minimize_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00};
+
+ const unsigned char maximize_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0xc0, 0x03, 0x00, 0xe0, 0x07, 0x00, 0xf0, 0x0f, 0x00,
+ 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00};
+
+ const unsigned char restore_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00,
+ 0xf0, 0x0f, 0x00, 0xe0, 0x07, 0x00, 0xc0, 0x03, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00};
+
+ const unsigned char close_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x0c, 0x00, 0x70, 0x0e, 0x00, 0xe0, 0x07, 0x00, 0xc0, 0x03, 0x00,
+ 0xc0, 0x03, 0x00, 0xe0, 0x07, 0x00, 0x70, 0x0e, 0x00, 0x30, 0x0c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00};
+
+ const unsigned char above_on_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
+ 0x80, 0x01, 0x00, 0xe0, 0x07, 0x00, 0xc0, 0x03, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00 };
+
+ const unsigned char above_off_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0xc0, 0x03, 0x00,
+ 0xe0, 0x07, 0x00, 0x80, 0x01, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00 };
+
+ const unsigned char below_on_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0xc0, 0x03, 0x00,
+ 0xe0, 0x07, 0x00, 0x80, 0x01, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00 };
+
+ const unsigned char below_off_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
+ 0x80, 0x01, 0x00, 0xe0, 0x07, 0x00, 0xc0, 0x03, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00 };
+
+ const unsigned char shade_on_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
+ 0x10, 0x08, 0x00, 0x10, 0x08, 0x00, 0x10, 0x08, 0x00, 0x10, 0x08, 0x00,
+ 0x10, 0x08, 0x00, 0x10, 0x08, 0x00, 0x10, 0x08, 0x00, 0xf0, 0x0f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00 };
+
+ const unsigned char shade_off_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00 };
+
+ KeramikHandler *clientHandler = NULL;
+ bool keramik_initialized = false;
+
+
+
+// -------------------------------------------------------------------------------------------
+
+
+
+KeramikHandler::KeramikHandler()
+{
+ for ( int i = 0; i < NumTiles; i++ ) {
+ activeTiles[i] = NULL;
+ inactiveTiles[i] = NULL;
+ }
+
+ settings_cache = NULL;
+
+ imageDb = KeramikImageDb::instance();
+
+ // Create the button deco bitmaps
+ buttonDecos[ Menu ] = new QBitmap( 17, 17, menu_bits, true );
+ buttonDecos[ OnAllDesktops ] = new QBitmap( 17, 17, on_all_desktops_bits, true );
+ buttonDecos[ NotOnAllDesktops ] = new QBitmap( 17, 17, not_on_all_desktops_bits, true );
+ buttonDecos[ Help ] = new QBitmap( 17, 17, help_bits, true );
+ buttonDecos[ Minimize ] = new QBitmap( 17, 17, minimize_bits, true );
+ buttonDecos[ Maximize ] = new QBitmap( 17, 17, maximize_bits, true );
+ buttonDecos[ Restore ] = new QBitmap( 17, 17, restore_bits, true );
+ buttonDecos[ Close ] = new QBitmap( 17, 17, close_bits, true );
+ buttonDecos[ AboveOn ] = new QBitmap( 17, 17, above_on_bits, true );
+ buttonDecos[ AboveOff ] = new QBitmap( 17, 17, above_off_bits, true );
+ buttonDecos[ BelowOn ] = new QBitmap( 17, 17, below_on_bits, true );
+ buttonDecos[ BelowOff ] = new QBitmap( 17, 17, below_off_bits, true );
+ buttonDecos[ ShadeOn ] = new QBitmap( 17, 17, shade_on_bits, true );
+ buttonDecos[ ShadeOff ] = new QBitmap( 17, 17, shade_off_bits, true );
+
+ // Selfmask the bitmaps
+ for ( int i = 0; i < NumButtonDecos; i++ )
+ buttonDecos[i]->setMask( *buttonDecos[i] );
+
+ // Flip the bitmaps horizontally in right-to-left mode
+ if ( QApplication::reverseLayout() ) {
+ for ( int i = 0; i < Help; ++i )
+ ::flip( buttonDecos[i] );
+
+ for ( int i = Help + 1; i < NumButtonDecos; ++i )
+ ::flip( buttonDecos[i] );
+ }
+
+ readConfig();
+ createPixmaps();
+
+ keramik_initialized = true;
+}
+
+
+KeramikHandler::~KeramikHandler()
+{
+ keramik_initialized = false;
+ destroyPixmaps();
+
+ for ( int i = 0; i < NumButtonDecos; i++ )
+ delete buttonDecos[i];
+
+ delete settings_cache;
+
+ KeramikImageDb::release();
+ imageDb = NULL;
+ clientHandler = NULL;
+}
+
+
+void KeramikHandler::createPixmaps()
+{
+ int heightOffset;
+ int widthOffset;
+ switch(options()->preferredBorderSize(this)) {
+ case BorderLarge:
+ widthOffset = 4;
+ heightOffset = 0;
+ break;
+ case BorderVeryLarge:
+ widthOffset = 8;
+ heightOffset = 0;
+ break;
+ case BorderHuge:
+ widthOffset = 14;
+ heightOffset = 0;
+ break;
+ case BorderVeryHuge:
+ widthOffset = 23;
+ heightOffset = 10;
+ break;
+ case BorderOversized:
+ widthOffset = 36;
+ heightOffset = 25;
+ break;
+ case BorderTiny:
+ case BorderNormal:
+ default:
+ widthOffset = 0;
+ heightOffset = 0;
+ }
+ int fontHeight = QFontMetrics(options()->font(true)).height();
+ if (fontHeight > heightOffset + 20)
+ heightOffset = fontHeight - 20;
+
+ QString size = (heightOffset < 8) ? "" : (heightOffset < 20) ? "-large" : "-huge";
+
+ QColor titleColor, captionColor, buttonColor;
+ QImage *titleCenter = NULL, *captionLeft = NULL,
+ *captionRight = NULL, *captionCenter = NULL;
+
+
+ // Active tiles
+ // -------------------------------------------------------------------------
+ captionColor = KDecoration::options()->color( ColorTitleBar, true );
+ titleColor = KDecoration::options()->color( ColorTitleBlend, true );
+
+ // Load the titlebar corners.
+ activeTiles[ TitleLeft ] = loadPixmap( "titlebar-left", titleColor );
+ activeTiles[ TitleRight ] = loadPixmap( "titlebar-right", titleColor );
+
+ // Load the titlebar center tile image (this will be used as
+ // the background for the caption bubble tiles).
+ titleCenter = loadImage( "titlebar-center", titleColor );
+
+ // Load the small version of the caption bubble corner & center images.
+ captionLeft = loadImage( "caption-small-left", captionColor );
+ captionRight = loadImage( "caption-small-right", captionColor );
+ captionCenter = loadImage( "caption-small-center", captionColor );
+
+ // Create the caption bubble tiles (by blending the images onto the titlebar)
+ activeTiles[ CaptionSmallLeft ] = composite( captionLeft, titleCenter );
+ activeTiles[ CaptionSmallRight ] = composite( captionRight, titleCenter );
+ activeTiles[ CaptionSmallCenter ] = composite( captionCenter, titleCenter );
+
+ delete captionLeft;
+ delete captionRight;
+ delete captionCenter;
+
+ // Now do the same with the large version
+ captionLeft = loadImage( "caption-large-left", captionColor );
+ captionRight = loadImage( "caption-large-right", captionColor );
+ captionCenter = loadImage( "caption-large-center", captionColor );
+
+ activeTiles[ CaptionLargeLeft ] = composite( captionLeft, titleCenter );
+ activeTiles[ CaptionLargeRight ] = composite( captionRight, titleCenter );
+ activeTiles[ CaptionLargeCenter ] = composite( captionCenter, titleCenter );
+
+ delete captionLeft;
+ delete captionRight;
+ delete captionCenter;
+
+ // Create the titlebar center tile
+ activeTiles[ TitleCenter ] = new QPixmap( *titleCenter );
+
+ delete titleCenter;
+
+ // Load the left & right border pixmaps
+ activeTiles[ BorderLeft ] = loadPixmap( "border-left", titleColor );
+ activeTiles[ BorderRight ] = loadPixmap( "border-right", titleColor );
+
+ // Load the bottom grabbar pixmaps
+ if ( largeGrabBars ) {
+ activeTiles[ GrabBarLeft ] = loadPixmap( "grabbar-left", titleColor );
+ activeTiles[ GrabBarRight ] = loadPixmap( "grabbar-right", titleColor );
+ activeTiles[ GrabBarCenter ] = loadPixmap( "grabbar-center", titleColor );
+ } else {
+ activeTiles[ GrabBarLeft ] = loadPixmap( "bottom-left", titleColor );
+ activeTiles[ GrabBarRight ] = loadPixmap( "bottom-right", titleColor );
+ activeTiles[ GrabBarCenter ] = loadPixmap( "bottom-center", titleColor );
+ }
+
+ // Inactive tiles
+ // -------------------------------------------------------------------------
+ captionColor = KDecoration::options()->color( ColorTitleBar, false );
+ titleColor = KDecoration::options()->color( ColorTitleBlend, false );
+
+ inactiveTiles[ TitleLeft ] = loadPixmap( "titlebar-left", titleColor );
+ inactiveTiles[ TitleRight ] = loadPixmap( "titlebar-right", titleColor );
+
+ titleCenter = loadImage( "titlebar-center", titleColor );
+
+ captionLeft = loadImage( "caption-small-left", captionColor );
+ captionRight = loadImage( "caption-small-right", captionColor );
+ captionCenter = loadImage( "caption-small-center", captionColor );
+
+ inactiveTiles[ CaptionSmallLeft ] = composite( captionLeft, titleCenter );
+ inactiveTiles[ CaptionSmallRight ] = composite( captionRight, titleCenter );
+ inactiveTiles[ CaptionSmallCenter ] = composite( captionCenter, titleCenter );
+
+ delete captionLeft;
+ delete captionRight;
+ delete captionCenter;
+
+ inactiveTiles[ TitleCenter ] = new QPixmap( *titleCenter );
+
+ delete titleCenter;
+
+ inactiveTiles[ BorderLeft ] = loadPixmap( "border-left", titleColor );
+ inactiveTiles[ BorderRight ] = loadPixmap( "border-right", titleColor );
+
+ if ( largeGrabBars ) {
+ inactiveTiles[ GrabBarLeft ] = loadPixmap( "grabbar-left", titleColor );
+ inactiveTiles[ GrabBarRight ] = loadPixmap( "grabbar-right", titleColor );
+ inactiveTiles[ GrabBarCenter ] = loadPixmap( "grabbar-center", titleColor );
+ } else {
+ inactiveTiles[ GrabBarLeft ] = loadPixmap( "bottom-left", titleColor );
+ inactiveTiles[ GrabBarRight ] = loadPixmap( "bottom-right", titleColor );
+ inactiveTiles[ GrabBarCenter ] = loadPixmap( "bottom-center", titleColor );
+ }
+
+ // Buttons
+ // -------------------------------------------------------------------------
+ buttonColor = QColor(); //KDecoration::options()->color( ButtonBg, true );
+
+ titleButtonRound = loadPixmap( "titlebutton-round"+size, buttonColor );
+ titleButtonSquare = loadPixmap( "titlebutton-square"+size, buttonColor );
+
+
+ // Prepare the tiles for use
+ // -------------------------------------------------------------------------
+ if ( QApplication::reverseLayout() ) {
+
+ // Fix lighting
+ flip( activeTiles[CaptionSmallLeft], activeTiles[CaptionSmallRight] );
+ flip( inactiveTiles[CaptionSmallLeft], inactiveTiles[CaptionSmallRight] );
+
+ flip( activeTiles[CaptionLargeLeft], activeTiles[CaptionLargeRight] );
+
+ flip( activeTiles[TitleLeft], activeTiles[TitleRight] );
+ flip( inactiveTiles[TitleLeft], inactiveTiles[TitleRight] );
+
+ flip( activeTiles[BorderLeft], activeTiles[BorderRight] );
+ flip( inactiveTiles[BorderLeft], inactiveTiles[BorderRight] );
+
+ flip( activeTiles[GrabBarLeft], activeTiles[GrabBarRight] );
+ flip( inactiveTiles[GrabBarLeft], inactiveTiles[GrabBarRight] );
+
+ ::flip( titleButtonRound );
+ ::flip( titleButtonSquare );
+ }
+
+ // Pretile the center & border tiles for optimal performance
+ pretile( activeTiles[ CaptionSmallCenter ], 64, Qt::Horizontal );
+ pretile( activeTiles[ CaptionLargeCenter ], 64, Qt::Horizontal );
+ pretile( activeTiles[ TitleCenter ], 64, Qt::Horizontal );
+ pretile( activeTiles[ GrabBarCenter ], 128, Qt::Horizontal );
+ pretile( activeTiles[ BorderLeft ], 128, Qt::Vertical );
+ pretile( activeTiles[ BorderRight ], 128, Qt::Vertical );
+
+ pretile( inactiveTiles[ CaptionSmallCenter ], 64, Qt::Horizontal );
+ pretile( inactiveTiles[ TitleCenter ], 64, Qt::Horizontal );
+ pretile( inactiveTiles[ GrabBarCenter ], 128, Qt::Horizontal );
+ pretile( inactiveTiles[ BorderLeft ], 128, Qt::Vertical );
+ pretile( inactiveTiles[ BorderRight ], 128, Qt::Vertical );
+
+ if (heightOffset > 0) {
+ addHeight (heightOffset, activeTiles[TitleLeft]);
+ addHeight (heightOffset, activeTiles[TitleCenter]);
+ addHeight (heightOffset, activeTiles[TitleRight]);
+ addHeight (heightOffset, activeTiles[CaptionSmallLeft]);
+ addHeight (heightOffset, activeTiles[CaptionSmallCenter]);
+ addHeight (heightOffset, activeTiles[CaptionSmallRight]);
+ addHeight (heightOffset, activeTiles[CaptionLargeLeft]);
+ addHeight (heightOffset, activeTiles[CaptionLargeCenter]);
+ addHeight (heightOffset, activeTiles[CaptionLargeRight]);
+
+ addHeight (heightOffset, inactiveTiles[TitleLeft]);
+ addHeight (heightOffset, inactiveTiles[TitleCenter]);
+ addHeight (heightOffset, inactiveTiles[TitleRight]);
+ addHeight (heightOffset, inactiveTiles[CaptionSmallLeft]);
+ addHeight (heightOffset, inactiveTiles[CaptionSmallCenter]);
+ addHeight (heightOffset, inactiveTiles[CaptionSmallRight]);
+ }
+
+ if (widthOffset > 0) {
+ addWidth (widthOffset, activeTiles[BorderLeft], true, activeTiles[GrabBarCenter]);
+ addWidth (widthOffset, activeTiles[BorderRight], false, activeTiles[GrabBarCenter]);
+ addWidth (widthOffset, inactiveTiles[BorderLeft], true, inactiveTiles[GrabBarCenter]);
+ addWidth (widthOffset, inactiveTiles[BorderRight], false, inactiveTiles[GrabBarCenter]);
+
+ if (largeGrabBars)
+ widthOffset = widthOffset*3/2;
+
+ addHeight (widthOffset, activeTiles[GrabBarLeft]);
+ addHeight (widthOffset, activeTiles[GrabBarCenter]);
+ addHeight (widthOffset, activeTiles[GrabBarRight]);
+ addHeight (widthOffset, inactiveTiles[GrabBarLeft]);
+ addHeight (widthOffset, inactiveTiles[GrabBarCenter]);
+ addHeight (widthOffset, inactiveTiles[GrabBarRight]);
+ }
+}
+
+
+
+void KeramikHandler::destroyPixmaps()
+{
+ for ( int i = 0; i < NumTiles; i++ ) {
+ delete activeTiles[i];
+ delete inactiveTiles[i];
+ activeTiles[i] = NULL;
+ inactiveTiles[i] = NULL;
+ }
+
+ delete titleButtonRound;
+ delete titleButtonSquare;
+}
+
+
+void KeramikHandler::addWidth (int width, QPixmap *&pix, bool left, QPixmap *bottomPix) {
+ int w = pix->width()+width;
+ int h = pix->height();
+
+ QPixmap *tmp = new QPixmap (w, h);
+ tmp->fill ();
+ QPainter p;
+ p.begin (tmp);
+
+ for (int i = 0; i < h; i++)
+ p.drawPixmap (0, i, *bottomPix, i%2, 0, w,1);
+
+ if (left)
+ p.drawPixmap(0, 0, *pix);
+ else
+ p.drawPixmap(width, 0, *pix);
+
+ p.end();
+
+ delete pix;
+ pix = tmp;
+}
+
+
+void KeramikHandler::addHeight (int height, QPixmap *&pix) {
+ int w = pix->width();
+ int h = pix->height()+height;
+
+ QPixmap *tmp = new QPixmap (w, h);
+ QPainter p;
+ p.begin (tmp);
+ if (pix->height() > 10) {
+ p.drawPixmap(0, 0, *pix, 0, 0, w, 11);
+ for (int i = 0; i < height; i+=2)
+ p.drawPixmap(0, 11+i, *pix, 0, 11, w, 2);
+ p.drawPixmap(0, 11+height, *pix, 0, 11, w, -1);
+ }
+ else {
+ int lines = h-3;
+ int factor = pix->height()-3;
+ for (int i = 0; i < lines; i++)
+ p.drawPixmap(0, i, *pix, 0, i*factor/lines, w, 1);
+ p.drawPixmap(0, lines, *pix, 0, factor, w, 3);
+ }
+ p.end();
+
+ delete pix;
+ pix = tmp;
+}
+
+
+void KeramikHandler::flip( QPixmap *&pix1, QPixmap *&pix2 )
+{
+ // Flip the pixmaps horizontally
+ QPixmap *tmp = new QPixmap( pix1->xForm( QWMatrix(-1,0,0,1,pix1->width(),0) ) );
+
+ delete pix1;
+ pix1 = new QPixmap( pix2->xForm( QWMatrix(-1,0,0,1,pix2->width(),0) ) );
+
+ delete pix2;
+ pix2 = tmp;
+}
+
+
+void KeramikHandler::pretile( QPixmap *&pix, int size, Qt::Orientation dir )
+{
+ QPixmap *newpix;
+ QPainter p;
+
+ if ( dir == Qt::Horizontal )
+ newpix = new QPixmap( size, pix->height() );
+ else
+ newpix = new QPixmap( pix->width(), size );
+
+ p.begin( newpix );
+ p.drawTiledPixmap( newpix->rect(), *pix ) ;
+ p.end();
+
+ delete pix;
+ pix = newpix;
+}
+
+
+void KeramikHandler::readConfig()
+{
+ KConfig *c = new KConfig( "kwinkeramikrc" );
+
+ c->setGroup( "General" );
+ showIcons = c->readBoolEntry( "ShowAppIcons", true );
+ shadowedText = c->readBoolEntry( "UseShadowedText", true );
+ smallCaptionBubbles = c->readBoolEntry( "SmallCaptionBubbles", false );
+ largeGrabBars = c->readBoolEntry( "LargeGrabBars", true );
+
+ if ( ! settings_cache ) {
+ settings_cache = new SettingsCache;
+ settings_cache->largeGrabBars = largeGrabBars;
+ settings_cache->smallCaptionBubbles = smallCaptionBubbles;
+ }
+
+ delete c;
+}
+
+
+QPixmap *KeramikHandler::composite( QImage *over, QImage *under )
+{
+ QImage dest( over->width(), over->height(), 32 );
+ int width = over->width(), height = over->height();
+
+ // Clear the destination image
+ Q_UINT32 *data = reinterpret_cast<Q_UINT32*>( dest.bits() );
+ for (int i = 0; i < width * height; i++)
+ *(data++) = 0;
+
+ // Copy the under image (bottom aligned) to the destination image
+ for (int y1 = height - under->height(), y2 = 0; y1 < height; y1++, y2++ )
+ {
+ register Q_UINT32 *dst = reinterpret_cast<Q_UINT32*>( dest.scanLine(y1) );
+ register Q_UINT32 *src = reinterpret_cast<Q_UINT32*>( under->scanLine(y2) );
+
+ for ( int x = 0; x < width; x++ )
+ *(dst++) = *(src++);
+ }
+
+ // Blend the over image onto the destination
+ register Q_UINT32 *dst = reinterpret_cast<Q_UINT32*>( dest.bits() );
+ register Q_UINT32 *src = reinterpret_cast<Q_UINT32*>( over->bits() );
+ for ( int i = 0; i < width * height; i++ )
+ {
+ int r1 = qRed( *dst ), g1 = qGreen( *dst ), b1 = qBlue( *dst );
+ int r2 = qRed( *src ), g2 = qGreen( *src ), b2 = qBlue( *src );
+ int a = qAlpha( *src );
+
+ if ( a == 0xff )
+ *dst = *src;
+
+ else if ( a != 0x00 )
+ *dst = qRgba( Q_UINT8( r1 + (((r2 - r1) * a) >> 8) ),
+ Q_UINT8( g1 + (((g2 - g1) * a) >> 8) ),
+ Q_UINT8( b1 + (((b2 - b1) * a) >> 8) ),
+ 0xff );
+
+ else if ( qAlpha(*dst) == 0x00 )
+ *dst = 0;
+
+ src++; dst++;
+ }
+
+ // Create the final pixmap and return it
+ return new QPixmap( dest );
+}
+
+
+QImage *KeramikHandler::loadImage( const QString &name, const QColor &col )
+{
+ if ( col.isValid() ) {
+ QImage *img = new QImage( imageDb->image(name)->copy() );
+ KIconEffect::colorize( *img, col, 1.0 );
+ return img;
+ } else
+ return new QImage( imageDb->image(name)->copy() );
+}
+
+
+QPixmap *KeramikHandler::loadPixmap( const QString &name, const QColor &col )
+{
+ QImage *img = loadImage( name, col );
+ QPixmap *pix = new QPixmap( *img );
+ delete img;
+
+ return pix;
+}
+
+
+bool KeramikHandler::reset( unsigned long changed )
+{
+ keramik_initialized = false;
+
+ bool needHardReset = false;
+ bool pixmapsInvalid = false;
+
+ // Re-read the config file
+ readConfig();
+
+ if ( changed & SettingBorder )
+ {
+ pixmapsInvalid = true;
+ needHardReset = true;
+ }
+ if ( changed & SettingFont )
+ {
+ pixmapsInvalid = true;
+ needHardReset = true;
+ }
+ // Check if the color scheme has changed
+ if ( changed & SettingColors )
+ {
+ pixmapsInvalid = true;
+ }
+ // Check if button positions have changed
+
+ if ( changed & SettingButtons ) {
+ needHardReset = true;
+ }
+
+ // Check if tooltips options have changed
+ if ( changed & SettingTooltips ) {
+ needHardReset = true;
+ }
+
+ if ( (settings_cache->largeGrabBars != largeGrabBars) ) {
+ pixmapsInvalid = true;
+ needHardReset = true;
+ }
+
+ if ( (settings_cache->smallCaptionBubbles != smallCaptionBubbles) ) {
+ needHardReset = true;
+ }
+
+ // Update our config cache
+ settings_cache->largeGrabBars = largeGrabBars;
+ settings_cache->smallCaptionBubbles = smallCaptionBubbles;
+
+ // Do we need to recreate the pixmaps?
+ if ( pixmapsInvalid ) {
+ destroyPixmaps();
+ createPixmaps();
+ }
+
+ keramik_initialized = true;
+
+ // Do we need to "hit the wooden hammer" ?
+ if ( !needHardReset )
+ resetDecorations( changed );
+ return needHardReset;
+}
+
+
+bool KeramikHandler::supports( Ability ability )
+{
+ switch( ability )
+ {
+ case AbilityAnnounceButtons:
+ case AbilityButtonMenu:
+ case AbilityButtonOnAllDesktops:
+ case AbilityButtonSpacer:
+ case AbilityButtonHelp:
+ case AbilityButtonMinimize:
+ case AbilityButtonMaximize:
+ case AbilityButtonClose:
+ case AbilityButtonAboveOthers:
+ case AbilityButtonBelowOthers:
+ case AbilityButtonShade:
+ return true;
+ default:
+ return false;
+ };
+}
+
+
+const QPixmap *KeramikHandler::tile( TilePixmap tilePix, bool active ) const
+{
+ return ( active ? activeTiles[ tilePix ] : inactiveTiles[ tilePix ] );
+}
+
+KDecoration* KeramikHandler::createDecoration( KDecorationBridge* bridge )
+{
+ return new KeramikClient( bridge, this );
+}
+
+QValueList< KeramikHandler::BorderSize > KeramikHandler::borderSizes() const
+{ // the list must be sorted
+ return QValueList< BorderSize >() << BorderNormal << BorderLarge <<
+ BorderVeryLarge << BorderHuge << BorderVeryHuge << BorderOversized;
+}
+
+
+// -------------------------------------------------------------------------------------------
+
+
+
+KeramikButton::KeramikButton( KeramikClient* c, const char *name, Button btn, const QString &tip, const int realizeBtns )
+ : QButton( c->widget(), name ),
+ client( c ), button( btn ), hover( false ), lastbutton( NoButton )
+{
+ realizeButtons = realizeBtns;
+
+ QToolTip::add( this, tip ); // FRAME
+ setBackgroundMode( NoBackground );
+ setCursor( arrowCursor );
+ int size = clientHandler->roundButton()->height();
+ setFixedSize( size, size );
+
+ setToggleButton( (button == OnAllDesktopsButton) );
+}
+
+
+KeramikButton::~KeramikButton()
+{
+ // Empty.
+}
+
+
+void KeramikButton::enterEvent( QEvent *e )
+{
+ QButton::enterEvent( e );
+
+ hover = true;
+ repaint( false );
+}
+
+
+void KeramikButton::leaveEvent( QEvent *e )
+{
+ QButton::leaveEvent( e );
+
+ hover = false;
+ repaint( false );
+}
+
+
+void KeramikButton::mousePressEvent( QMouseEvent *e )
+{
+ lastbutton = e->button();
+ QMouseEvent me( e->type(), e->pos(), e->globalPos(), (e->button()&realizeButtons)?LeftButton:NoButton, e->state() );
+ QButton::mousePressEvent( &me );
+}
+
+
+void KeramikButton::mouseReleaseEvent( QMouseEvent *e )
+{
+ lastbutton = e->button();
+ QMouseEvent me( e->type(), e->pos(), e->globalPos(), (e->button()&realizeButtons)?LeftButton:NoButton, e->state() );
+ QButton::mouseReleaseEvent( &me );
+}
+
+
+void KeramikButton::drawButton( QPainter *p )
+{
+ const QPixmap *pix;
+ const QBitmap *deco;
+ int size = clientHandler->roundButton()->height();
+
+ // Get the bevel from the client handler
+ if ( button == MenuButton || button == OnAllDesktopsButton || button == HelpButton )
+ pix = clientHandler->roundButton();
+ else
+ pix = clientHandler->squareButton();
+
+ // Draw the button background
+ const QPixmap *background = clientHandler->tile( TitleCenter, client->isActive() );
+ p->drawPixmap( 0, 0, *background,
+ 0, (background->height()-size+1)/2, size, size );
+
+ if ( isDown() ) {
+ // Pressed
+ p->drawPixmap( QPoint(), *pix, QStyle::visualRect( QRect(2*size, 0, size, size), pix->rect() ) );
+ p->translate( QApplication::reverseLayout() ? -1 : 1, 1 );
+ } else if ( hover )
+ // Mouse over
+ p->drawPixmap( QPoint(), *pix, QStyle::visualRect( QRect(size, 0, size, size), pix->rect() ) );
+ else
+ // Normal
+ p->drawPixmap( QPoint(), *pix, QStyle::visualRect( QRect(0, 0, size, size), pix->rect() ) );
+
+
+ // Draw the button deco on the bevel
+ switch ( button ) {
+ case MenuButton:
+ deco = clientHandler->buttonDeco( Menu );
+ break;
+
+ case OnAllDesktopsButton:
+ deco = clientHandler->buttonDeco( client->isOnAllDesktops() ? NotOnAllDesktops : OnAllDesktops );
+ break;
+
+ case HelpButton:
+ deco = clientHandler->buttonDeco( Help );
+ // The '?' won't be flipped around in the ctor, so we need to
+ // shift it to the right to compensate for the button shadow
+ // being on the left side of the button in RTL mode.
+ if ( QApplication::reverseLayout() )
+ p->translate( 2, 0 );
+ break;
+
+ case MinButton:
+ deco = clientHandler->buttonDeco( Minimize );
+ break;
+
+ case MaxButton:
+ deco = clientHandler->buttonDeco( client->maximizeMode() == KeramikClient::MaximizeFull ? Restore : Maximize );
+ break;
+
+ case CloseButton:
+ deco = clientHandler->buttonDeco( Close );
+ break;
+
+ case AboveButton:
+ deco = clientHandler->buttonDeco( client->keepAbove() ? AboveOn : AboveOff );
+ break;
+
+ case BelowButton:
+ deco = clientHandler->buttonDeco( client->keepBelow() ? BelowOn : BelowOff );
+ break;
+
+ case ShadeButton:
+ deco = clientHandler->buttonDeco( client->isSetShade() ? ShadeOn : ShadeOff );
+ break;
+
+ default:
+ deco = NULL;
+ }
+
+ p->setPen( Qt::black ); // ### hardcoded color
+ p->drawPixmap( (size-17)/2, (size-17)/2, *deco );
+}
+
+
+
+// ------------------------------------------------------------------------------------------
+
+
+
+KeramikClient::KeramikClient( KDecorationBridge* bridge, KDecorationFactory* factory )
+ : KDecoration( bridge, factory ),
+ activeIcon( NULL ), inactiveIcon( NULL ), captionBufferDirty( true ), maskDirty( true )
+{
+}
+
+void KeramikClient::init()
+{
+ connect( this, SIGNAL( keepAboveChanged( bool )), SLOT( keepAboveChange( bool )));
+ connect( this, SIGNAL( keepBelowChanged( bool )), SLOT( keepBelowChange( bool )));
+
+ createMainWidget( WStaticContents | WResizeNoErase | WRepaintNoErase );
+ widget()->installEventFilter( this );
+
+ // Minimize flicker
+ widget()->setBackgroundMode( NoBackground );
+
+ for ( int i=0; i < NumButtons; i++ )
+ button[i] = NULL;
+
+ createLayout();
+}
+
+void KeramikClient::createLayout()
+{
+
+ QVBoxLayout *mainLayout = new QVBoxLayout( widget() );
+ QBoxLayout *titleLayout = new QBoxLayout( 0, QBoxLayout::LeftToRight, 0, 0, 0 );
+ QHBoxLayout *windowLayout = new QHBoxLayout();
+
+ largeTitlebar = ( !maximizedVertical() && clientHandler->largeCaptionBubbles() );
+ largeCaption = ( isActive() && largeTitlebar );
+
+ int grabBarHeight = clientHandler->grabBarHeight();
+ int topSpacing = ( largeTitlebar ? 4 : 1 );
+ int leftBorderWidth = clientHandler->tile( BorderLeft, true )->width();
+ int rightBorderWidth = clientHandler->tile( BorderRight, true )->width();
+ topSpacer = new QSpacerItem( 10, topSpacing,
+ QSizePolicy::Expanding, QSizePolicy::Minimum );
+
+ mainLayout->addItem( topSpacer );
+
+ mainLayout->addLayout( titleLayout ); // Titlebar
+ mainLayout->addLayout( windowLayout, 1 ); // Left border + window + right border
+ mainLayout->addSpacing( grabBarHeight ); // Bottom grab bar
+
+ titleLayout->setSpacing( buttonSpacing );
+
+ titleLayout->addSpacing( buttonMargin ); // Left button margin
+ addButtons( titleLayout, options()->customButtonPositions() ?
+ options()->titleButtonsLeft() : QString(default_left) );
+
+ titlebar = new QSpacerItem( 10, clientHandler->titleBarHeight(largeTitlebar)
+ - topSpacing, QSizePolicy::Expanding, QSizePolicy::Minimum );
+ titleLayout->addItem( titlebar );
+
+ titleLayout->addSpacing( buttonSpacing );
+ addButtons( titleLayout, options()->customButtonPositions() ?
+ options()->titleButtonsRight() : QString(default_right) );
+ titleLayout->addSpacing( buttonMargin - 1 ); // Right button margin
+
+ windowLayout->addSpacing( leftBorderWidth ); // Left border
+ if( isPreview())
+ windowLayout->addWidget( new QLabel( i18n( "<center><b>Keramik preview</b></center>" ), widget()));
+ else
+ windowLayout->addItem( new QSpacerItem( 0, 0 )); //no widget in the middle
+ windowLayout->addSpacing( rightBorderWidth ); // Right border
+}
+
+
+KeramikClient::~KeramikClient()
+{
+ delete activeIcon;
+ delete inactiveIcon;
+
+ activeIcon = inactiveIcon = NULL;
+}
+
+
+void KeramikClient::reset( unsigned long )
+{
+ if ( clientHandler->largeCaptionBubbles() && !largeTitlebar )
+ {
+ // We're switching from small caption bubbles to large
+ if ( !maximizedVertical() ) {
+ topSpacer->changeSize( 10, 4, QSizePolicy::Expanding, QSizePolicy::Minimum );
+ largeTitlebar = true;
+ largeCaption = isActive();
+
+ widget()->layout()->activate();
+
+ // Compensate for the titlebar size change
+
+ // TODO This is wrong, this may break size increments (see bug #53784).
+ // FRAME
+ widget()->setGeometry( widget()->x(), widget()->y() - 3, width(), height() + 3 );
+ }
+ }
+ else if ( !clientHandler->largeCaptionBubbles() && largeTitlebar )
+ {
+ // We're switching from large caption bubbles to small
+ topSpacer->changeSize( 10, 1, QSizePolicy::Expanding, QSizePolicy::Minimum );
+ largeTitlebar = largeCaption = false;
+
+ widget()->layout()->activate();
+
+ // Compensate for the titlebar size change
+ // FRAME
+ widget()->setGeometry( widget()->x(), widget()->y() + 3, width(), height() - 3 );
+ }
+
+ calculateCaptionRect();
+
+ captionBufferDirty = maskDirty = true;
+
+ // Only repaint the window if it's visible
+ // (i.e. not minimized and on the current desktop)
+ if ( widget()->isVisible() ) {
+ widget()->repaint( false );
+
+ for ( int i = 0; i < NumButtons; i++ )
+ if ( button[i] ) button[i]->repaint( false );
+ }
+}
+
+
+void KeramikClient::addButtons( QBoxLayout *layout, const QString &s )
+{
+ for ( uint i=0; i < s.length(); i++ )
+ {
+ switch ( s[i].latin1() )
+ {
+ // Menu button
+ case 'M' :
+ if ( !button[MenuButton] ) {
+ button[MenuButton] = new KeramikButton( this, "menu", MenuButton, i18n("Menu"), LeftButton|RightButton );
+ connect( button[MenuButton], SIGNAL( pressed() ), SLOT( menuButtonPressed() ) );
+ layout->addWidget( button[MenuButton] );
+ }
+ break;
+
+ // OnAllDesktops button
+ case 'S' :
+ if ( !button[OnAllDesktopsButton] ) {
+ button[OnAllDesktopsButton] = new KeramikButton( this, "on_all_desktops",
+ OnAllDesktopsButton, isOnAllDesktops()?i18n("Not on all desktops"):i18n("On all desktops") );
+ if(isOnAllDesktops())
+ button[OnAllDesktopsButton]->toggle();
+ connect( button[OnAllDesktopsButton], SIGNAL( clicked() ), SLOT( toggleOnAllDesktops() ) );
+ layout->addWidget( button[OnAllDesktopsButton] );
+ }
+ break;
+
+ // Help button
+ case 'H' :
+ if ( !button[HelpButton] && providesContextHelp() ) {
+ button[HelpButton] = new KeramikButton( this, "help", HelpButton, i18n("Help") );
+ connect( button[HelpButton], SIGNAL( clicked() ), SLOT( showContextHelp() ) );
+ layout->addWidget( button[HelpButton] );
+ }
+ break;
+
+ // Minimize button
+ case 'I' :
+ if ( !button[MinButton] && isMinimizable() ) {
+ button[MinButton] = new KeramikButton( this, "minimize", MinButton, i18n("Minimize") );
+ connect( button[MinButton], SIGNAL( clicked() ), SLOT( minimize() ) );
+ layout->addWidget( button[MinButton] );
+ }
+ break;
+
+ // Maximize button
+ case 'A' :
+ if ( !button[MaxButton] && isMaximizable() ) {
+ button[MaxButton] = new KeramikButton( this, "maximize", MaxButton, i18n("Maximize"), LeftButton|MidButton|RightButton );
+ connect( button[MaxButton], SIGNAL( clicked() ), SLOT( slotMaximize() ) );
+ layout->addWidget( button[MaxButton] );
+ }
+ break;
+
+ // Close button
+ case 'X' :
+ if ( !button[CloseButton] && isCloseable() ) {
+ button[CloseButton] = new KeramikButton( this, "close", CloseButton, i18n("Close") );
+ connect( button[CloseButton], SIGNAL( clicked() ), SLOT( closeWindow() ) );
+ layout->addWidget( button[CloseButton] );
+ }
+ break;
+
+ // Above button
+ case 'F' :
+ if ( !button[AboveButton]) {
+ button[AboveButton] = new KeramikButton( this, "above", AboveButton, i18n("Keep Above Others") );
+ connect( button[AboveButton], SIGNAL( clicked() ), SLOT( slotAbove() ) );
+ layout->addWidget( button[AboveButton] );
+ }
+ break;
+
+ // Below button
+ case 'B' :
+ if ( !button[BelowButton]) {
+ button[BelowButton] = new KeramikButton( this, "below", BelowButton, i18n("Keep Below Others") );
+ connect( button[BelowButton], SIGNAL( clicked() ), SLOT( slotBelow() ) );
+ layout->addWidget( button[BelowButton] );
+ }
+ break;
+
+ // Shade button
+ case 'L' :
+ if ( !button[ShadeButton] && isShadeable() ) {
+ button[ShadeButton] = new KeramikButton( this, "shade", ShadeButton,
+ isSetShade() ? i18n("Unshade") : i18n( "Shade" ));
+ connect( button[ShadeButton], SIGNAL( clicked() ), SLOT( slotShade() ) );
+ layout->addWidget( button[ShadeButton] );
+ }
+ break;
+
+ // Additional spacing
+ case '_' :
+ layout->addSpacing( buttonSpacing );
+ break;
+ }
+ }
+}
+
+
+void KeramikClient::updateMask()
+{
+ if ( !keramik_initialized )
+ return;
+
+ // To maximize performance this code uses precalculated bounding rects
+ // to set the window mask. This saves us from having to allocate a 1bpp
+ // pixmap, paint the mask on it and then have the X server iterate
+ // over the pixels to compute the bounding rects from it.
+
+ QRegion r;
+ register int w, y = 0;
+ int nrects;
+
+ if ( QApplication::reverseLayout() ) {
+
+ // If the caption bubble is visible and extends above the titlebar
+ if ( largeCaption && captionRect.width() >= 25 ) {
+ register int x = captionRect.left();
+ w = captionRect.width();
+ r += QRegion( x + 11, y++, w - 19, 1 );
+ r += QRegion( x + 9, y++, w - 15, 1 );
+ r += QRegion( x + 7, y++, w - 12, 1 );
+ } else {
+ nrects = 8;
+
+ // Do we have a large titlebar with a retracted caption bubble?
+ // (i.e. the style is set to use large caption bubbles, we're
+ // not maximized and not active)
+ if ( largeTitlebar )
+ y = 3;
+ }
+
+ w = width(); // FRAME
+
+ // The rounded titlebar corners
+ r += QRegion( 9, y++, w - 17, 1 );
+ r += QRegion( 7, y++, w - 13, 1 );
+ r += QRegion( 5, y++, w - 9, 1 );
+ r += QRegion( 4, y++, w - 7, 1 );
+ r += QRegion( 3, y++, w - 5, 1 );
+ r += QRegion( 2, y++, w - 4, 1 );
+ r += QRegion( 1, y++, w - 2, 2 );
+ } else {
+
+ // If the caption bubble is visible and extends above the titlebar
+ if ( largeCaption && captionRect.width() >= 25 ) {
+ nrects = 11;
+ register int x = captionRect.left();
+ w = captionRect.width();
+ r += QRegion( x + 8, y++, w - 19, 1 );
+ r += QRegion( x + 6, y++, w - 15, 1 );
+ r += QRegion( x + 5, y++, w - 12, 1 );
+ } else {
+ nrects = 8;
+
+ // Do we have a large titlebar with a retracted caption bubble?
+ // (i.e. the style is set to use large caption bubbles, we're
+ // not maximized and not active)
+ if ( largeTitlebar )
+ y = 3;
+ }
+
+ w = width(); // FRAME
+
+ // The rounded titlebar corners
+ r += QRegion( 8, y++, w - 17, 1 );
+ r += QRegion( 6, y++, w - 13, 1 );
+ r += QRegion( 4, y++, w - 9, 1 );
+ r += QRegion( 3, y++, w - 7, 1 );
+ r += QRegion( 2, y++, w - 5, 1 );
+ r += QRegion( 2, y++, w - 4, 1 );
+ r += QRegion( 1, y++, w - 2, 2 );
+ }
+
+ y++;
+
+ // The part of the window below the titlebar
+ r += QRegion( 0, y, w, height() - y );
+
+ setMask( r, YXBanded );
+
+ maskDirty = false;
+}
+
+
+void KeramikClient::updateCaptionBuffer()
+{
+ if ( !keramik_initialized )
+ return;
+
+ bool active = isActive();
+ QPixmap *icon = NULL;
+
+ if ( captionBuffer.size() != captionRect.size() )
+ captionBuffer.resize( captionRect.size() );
+
+ if ( captionBuffer.isNull() )
+ return;
+
+ QPainter p( &captionBuffer );
+
+ // Draw the caption bubble
+ if ( active && largeCaption ) {
+ p.drawPixmap( 0, 0, *clientHandler->tile( CaptionLargeLeft, true ) );
+ p.drawTiledPixmap( 15, 0, captionRect.width() - 30, captionRect.height(),
+ *clientHandler->tile( CaptionLargeCenter, true ) );
+ p.drawPixmap( captionRect.width() - 15, 0, *clientHandler->tile( CaptionLargeRight, true ) );
+ } else {
+ p.drawPixmap( 0, 0, *clientHandler->tile( CaptionSmallLeft, active ) );
+ p.drawTiledPixmap( 15, 0, captionRect.width() - 30, captionRect.height(),
+ *clientHandler->tile( CaptionSmallCenter, active ) );
+ p.drawPixmap( captionRect.width() - 15, 0, *clientHandler->tile( CaptionSmallRight, active ) );
+ }
+
+ if ( clientHandler->showAppIcons() )
+ {
+ if ( active ) {
+ if ( ! activeIcon )
+ activeIcon = new QPixmap( this->icon().pixmap( QIconSet::Small, QIconSet::Normal )); // FRAME
+ icon = activeIcon;
+ } else {
+ if ( ! inactiveIcon ) {
+ QImage img = this->icon().pixmap( QIconSet::Small, QIconSet::Normal ).convertToImage();
+ KIconEffect::semiTransparent( img );
+ inactiveIcon = new QPixmap( img );
+ }
+ icon = inactiveIcon;
+ }
+ }
+
+ p.setFont( options()->font( active ) );
+ int tw = p.fontMetrics().width( caption() ) +
+ ( clientHandler->showAppIcons() ? 16 + iconSpacing : 0 );
+
+ int xpos = QMAX( (captionRect.width() - tw) / 3, 8 );
+ QRect tr = QStyle::visualRect( QRect(xpos, 1, captionRect.width() - xpos - 10,
+ captionRect.height() - 4), captionBuffer.rect() );
+
+ //p.setPen( Qt::red ); // debug
+ //p.drawRect( tr ); // debug
+
+ // Application icon
+ if ( clientHandler->showAppIcons() )
+ {
+ QRect iconRect = QStyle::visualRect( QRect(tr.x(),
+ 1 + (captionRect.height() - 4 - 16) / 2, 16, 16), tr );
+ QRect r( icon->rect() );
+ r.moveCenter( iconRect.center() );
+
+ if ( tr.width() > 16 ) {
+ p.drawPixmap( r, *icon );
+ } else {
+ QRect sr( 0, 0, icon->width(), icon->height() );
+
+ if ( QApplication::reverseLayout() )
+ sr.addCoords( icon->width() - tr.width(), 0, 0, 0 );
+ else
+ sr.addCoords( 0, 0, -( icon->width() - tr.width() ), 0 );
+
+ p.drawPixmap( r.x() + sr.x(), r.y() + sr.y(), *icon,
+ sr.x(), sr.y(), sr.width(), sr.height() );
+ }
+
+ //p.drawRect( r ); // debug
+
+ if ( QApplication::reverseLayout() )
+ tr.addCoords( 0, 0, -(16 + iconSpacing), 0 );
+ else
+ tr.addCoords( (16 + iconSpacing), 0, 0, 0 );
+ }
+
+ // Draw the titlebar text
+ int flags = AlignVCenter | SingleLine;
+ flags |= ( QApplication::reverseLayout() ? AlignRight : AlignLeft );
+
+ if ( clientHandler->useShadowedText() )
+ {
+ p.translate( QApplication::reverseLayout() ? -1 : 1, 1 );
+ //p.setPen( options()->color(ColorTitleBar, active).dark() );
+ if (qGray(options()->color(ColorFont, active).rgb()) < 100)
+ p.setPen( QColor(200,200,200) );
+ else
+ p.setPen( black );
+ p.drawText( tr, flags, caption() );
+ p.translate( QApplication::reverseLayout() ? 1 : -1, -1 );
+ }
+
+ p.setPen( options()->color( ColorFont, active ) );
+ p.drawText( tr, flags, caption() );
+
+ captionBufferDirty = false;
+}
+
+
+void KeramikClient::calculateCaptionRect()
+{
+ QFontMetrics fm( options()->font(isActive()) );
+ int cw = fm.width( caption() ) + 95;
+ int titleBaseY = ( largeTitlebar ? 3 : 0 );
+
+ if ( clientHandler->showAppIcons() )
+ cw += 16 + 4; // icon width + space
+
+ cw = QMIN( cw, titlebar->geometry().width() );
+ captionRect = QStyle::visualRect( QRect(titlebar->geometry().x(), (largeCaption ? 0 : titleBaseY),
+ cw, clientHandler->titleBarHeight(largeCaption) ),
+ titlebar->geometry() );
+}
+
+
+void KeramikClient::captionChange()
+{
+ QRect r( captionRect );
+ calculateCaptionRect();
+
+ if ( r.size() != captionRect.size() )
+ maskDirty = true;
+
+ captionBufferDirty = true;
+
+ widget()->repaint( r | captionRect, false );
+}
+
+
+void KeramikClient::iconChange()
+{
+ if ( clientHandler->showAppIcons() ) {
+
+ // Force updateCaptionBuffer() to recreate the cached icons
+ delete activeIcon;
+
+ delete inactiveIcon;
+
+ activeIcon = inactiveIcon = NULL;
+
+ captionBufferDirty = true;
+ widget()->repaint( captionRect, false );
+ }
+}
+
+
+void KeramikClient::activeChange()
+{
+ bool active = isActive();
+ // Note: It's assumed that the same font will always be used for both active
+ // and inactive windows, since the fonts kcm hasn't supported setting
+ // different fonts for different window states for some time.
+ if ( largeTitlebar ) {
+ largeCaption = ( active && !maximizedVertical() );
+ calculateCaptionRect();
+ maskDirty = true;
+ }
+
+ captionBufferDirty = true;
+
+ widget()->repaint( false );
+
+ for ( int i=0; i < NumButtons; i++ )
+ if ( button[i] ) button[i]->repaint( false );
+}
+
+
+void KeramikClient::maximizeChange()
+{
+ if ( clientHandler->largeCaptionBubbles() )
+ {
+ if ( maximizeMode() & MaximizeVertical ) {
+ // We've been maximized - shrink the titlebar by 3 pixels
+ topSpacer->changeSize( 10, 1, QSizePolicy::Expanding, QSizePolicy::Minimum );
+ largeCaption = largeTitlebar = false;
+
+ calculateCaptionRect();
+ captionBufferDirty = maskDirty = true;
+
+ widget()->layout()->activate();
+ widget()->repaint( false );
+ } else if (( maximizeMode() & MaximizeVertical ) == 0 && !largeTitlebar ) {
+ // We've been restored - enlarge the titlebar by 3 pixels
+ topSpacer->changeSize( 10, 4, QSizePolicy::Expanding, QSizePolicy::Minimum );
+ largeCaption = largeTitlebar = true;
+
+ calculateCaptionRect();
+ captionBufferDirty = maskDirty = true;
+
+ widget()->layout()->activate();
+ widget()->repaint( false );
+ }
+ }
+
+ if ( button[ MaxButton ] ) {
+ QToolTip::remove( button[ MaxButton ] );
+ QToolTip::add( button[ MaxButton ], maximizeMode() == MaximizeFull ? i18n("Restore") : i18n("Maximize") );
+ button[ MaxButton ]->repaint();
+ }
+}
+
+
+void KeramikClient::desktopChange()
+{
+ if ( button[ OnAllDesktopsButton ] )
+ {
+ button[ OnAllDesktopsButton ]->repaint( true );
+ QToolTip::remove( button[ OnAllDesktopsButton ] );
+ QToolTip::add( button[ OnAllDesktopsButton ], isOnAllDesktops() ? i18n("Not on all desktops") : i18n("On all desktops") );
+ }
+}
+
+
+void KeramikClient::shadeChange()
+{
+ if ( button[ ShadeButton ] )
+ {
+ button[ ShadeButton ]->repaint( true );
+ QToolTip::remove( button[ ShadeButton ] );
+ QToolTip::add( button[ ShadeButton ], isSetShade() ? i18n("Unshade") : i18n("Shade") );
+ }
+}
+
+
+void KeramikClient::keepAboveChange( bool )
+{
+ if ( button[ AboveButton ] )
+ button[ AboveButton ]->repaint( true );
+}
+
+
+void KeramikClient::keepBelowChange( bool )
+{
+ if ( button[ BelowButton ] )
+ button[ BelowButton ]->repaint( true );
+}
+
+
+void KeramikClient::menuButtonPressed()
+{
+ QPoint menuTop ( button[MenuButton]->rect().topLeft() );
+ QPoint menuBottom ( button[MenuButton]->rect().bottomRight() );
+ menuTop += QPoint(-6, -3);
+ menuBottom += QPoint(6, 3);
+ KDecorationFactory* f = factory();
+ showWindowMenu( QRect( button[MenuButton]->mapToGlobal( menuTop ),
+ button[MenuButton]->mapToGlobal( menuBottom )) );
+ if( !f->exists( this )) // 'this' was destroyed
+ return;
+ button[MenuButton]->setDown(false);
+}
+
+
+void KeramikClient::slotMaximize()
+{
+ maximize( button[ MaxButton ]->lastButton() );
+}
+
+
+void KeramikClient::slotAbove()
+{
+ setKeepAbove( !keepAbove());
+ button[ AboveButton ]->repaint( true );
+}
+
+
+void KeramikClient::slotBelow()
+{
+ setKeepBelow( !keepBelow());
+ button[ BelowButton ]->repaint( true );
+}
+
+
+void KeramikClient::slotShade()
+{
+ setShade( !isSetShade());
+ button[ ShadeButton ]->repaint( true );
+}
+
+
+void KeramikClient::paintEvent( QPaintEvent *e )
+{
+ if ( !keramik_initialized )
+ return;
+
+ QPainter p( widget());
+ QRect updateRect( e->rect() );
+ bool active = isActive();
+
+ int titleBaseY = ( largeTitlebar ? 3 : 0 );
+ int titleBarHeight = clientHandler->titleBarHeight( largeTitlebar );
+ int grabBarHeight = clientHandler->grabBarHeight();
+ int leftBorderWidth = clientHandler->tile( BorderLeft, active )->width();
+ int rightBorderWidth = clientHandler->tile( BorderRight, active )->width();
+
+ if ( maskDirty )
+ updateMask();
+
+ // Titlebar
+ // -----------------------------------------------------------------------
+ if ( updateRect.y() < titleBarHeight )
+ {
+ int titleBarBaseHeight = titleBarHeight - titleBaseY;
+
+ if ( captionBufferDirty )
+ updateCaptionBuffer();
+
+ // Top left corner
+ if ( updateRect.x() < 15 )
+ p.drawPixmap( 0, titleBaseY,
+ *clientHandler->tile( TitleLeft, active ) );
+
+ // Space between the top left corner and the caption bubble
+ if ( updateRect.x() < captionRect.left() && updateRect.right() >= 15 ) {
+ int x1 = QMAX( 15, updateRect.x() );
+ int x2 = QMIN( captionRect.left(), updateRect.right() );
+
+ p.drawTiledPixmap( x1, titleBaseY, x2 - x1 + 1, titleBarBaseHeight,
+ *clientHandler->tile( TitleCenter, active ) );
+ }
+
+ // Caption bubble
+ if ( updateRect.x() <= captionRect.right() && updateRect.right() > 15 ) {
+ if ( captionRect.width() >= 25 )
+ p.drawPixmap( captionRect.left(), active ? 0 : titleBaseY, captionBuffer );
+ else
+ p.drawTiledPixmap( captionRect.x(), titleBaseY, captionRect.width(),
+ titleBarBaseHeight, *clientHandler->tile( TitleCenter, active ) );
+ }
+
+ // Space between the caption bubble and the top right corner
+ if ( updateRect.right() > captionRect.right() && updateRect.x() < width() - 15 ) { // FRAME
+ int x1 = QMAX( captionRect.right() + 1, updateRect.x() );
+ int x2 = QMIN( width() - 15, updateRect.right() );
+
+ p.drawTiledPixmap( x1, titleBaseY, x2 - x1 + 1, titleBarBaseHeight,
+ *clientHandler->tile( TitleCenter, active ) );
+ }
+
+ // Top right corner
+ if ( updateRect.right() >= width() - 15 )
+ p.drawPixmap( width() - 15, titleBaseY,
+ *clientHandler->tile( TitleRight, active ) );
+ }
+
+ // Borders
+ // -----------------------------------------------------------------------
+ if ( updateRect.bottom() >= titleBarHeight &&
+ updateRect.top() < height() - grabBarHeight )
+ {
+ int top = QMAX( titleBarHeight, updateRect.top() );
+ int bottom = QMIN( updateRect.bottom(), height() - grabBarHeight );
+
+ // Left border
+ if ( updateRect.x() < leftBorderWidth )
+ p.drawTiledPixmap( 0, top, leftBorderWidth, bottom - top + 1,
+ *clientHandler->tile( BorderLeft, active ) );
+
+ // Right border
+ if ( e->rect().right() > width() - rightBorderWidth - 1 )
+ p.drawTiledPixmap( width() - rightBorderWidth, top, rightBorderWidth,
+ bottom - top + 1, *clientHandler->tile( BorderRight, active ) );
+ }
+
+ // Bottom grab bar
+ // -----------------------------------------------------------------------
+ if ( updateRect.bottom() >= height() - grabBarHeight ) {
+ // Bottom left corner
+ if ( updateRect.x() < 9 )
+ p.drawPixmap( 0, height() - grabBarHeight,
+ *clientHandler->tile( GrabBarLeft, active ) );
+
+ // Space between the left corner and the right corner
+ if ( updateRect.x() < width() - 9 ) {
+ int x1 = QMAX( 9, updateRect.x() );
+ int x2 = QMIN( width() - 9, updateRect.right() );
+
+ p.drawTiledPixmap( x1, height() - grabBarHeight, x2 - x1 + 1,
+ grabBarHeight, *clientHandler->tile( GrabBarCenter, active ) );
+ }
+
+ // Bottom right corner
+ if ( updateRect.right() > width() - 9 )
+ p.drawPixmap( width() - 9, height() - grabBarHeight,
+ *clientHandler->tile( GrabBarRight, active ) );
+ }
+
+ // Extra drawline for the 1 pixel empty space QLayout leaves when a window is shaded.
+ p.setPen( options()->color( ColorTitleBlend, active ) );
+ p.drawLine( leftBorderWidth, height() - grabBarHeight - 1,
+ width() - rightBorderWidth - 1, height() - grabBarHeight - 1 );
+}
+
+
+void KeramikClient::resizeEvent( QResizeEvent *e )
+{
+// FRAME Client::resizeEvent( e );
+
+ QRect r( captionRect );
+ calculateCaptionRect();
+
+ if ( r.size() != captionRect.size() )
+ captionBufferDirty = true;
+
+ maskDirty = true;
+
+ if ( widget()->isVisible() )
+ {
+ widget()->update( widget()->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 )
+ 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( this, new QPaintEvent( titlebar->geometry(), FALSE ) );
+ }
+ }
+}
+
+
+void KeramikClient::mouseDoubleClickEvent( QMouseEvent *e )
+{
+ if ( e->button() == LeftButton
+ && QRect( 0, 0, width(), clientHandler->titleBarHeight( largeTitlebar ) ).contains( e->pos() ) )
+ titlebarDblClickOperation();
+}
+
+void KeramikClient::wheelEvent( QWheelEvent *e )
+{
+ if (isSetShade()
+ || QRect( 0, 0, width(), clientHandler->titleBarHeight( largeTitlebar ) ).contains( e->pos() ) )
+ titlebarMouseWheelOperation( e->delta());
+}
+
+KeramikClient::Position KeramikClient::mousePosition( const QPoint &p ) const
+{
+ int titleBaseY = (largeTitlebar ? 3 : 0);
+
+ int leftBorder = clientHandler->tile( BorderLeft, true )->width();
+ int rightBorder = width() - clientHandler->tile( BorderRight, true )->width() - 1;
+ int bottomBorder = height() - clientHandler->grabBarHeight() - 1;
+ int bottomCornerSize = 3*clientHandler->tile( BorderRight, true )->width()/2 + 24;
+
+ // Test if the mouse is over the titlebar area
+ if ( p.y() < titleBaseY + 11 ) {
+ // Test for the top left corner
+ if ( p.x() < leftBorder + 11 ) {
+ if ( (p.y() < titleBaseY + 3 && p.x() < leftBorder + 11) ||
+ (p.y() < titleBaseY + 6 && p.x() < leftBorder + 6) ||
+ (p.y() < titleBaseY + 11 && p.x() < leftBorder + 3) )
+ return PositionTopLeft;
+ }
+
+ // Test for the top right corner
+ if ( p.x() > rightBorder - 11 ) {
+ if ( (p.y() < titleBaseY + 3 && p.x() > rightBorder - 11) ||
+ (p.y() < titleBaseY + 6 && p.x() > rightBorder - 6) ||
+ (p.y() < titleBaseY + 11 && p.x() > rightBorder - 3) )
+ return PositionTopRight;
+ }
+
+ // Test for the top border
+ if ( p.y() <= 3 || (p.y() <= titleBaseY+3 &&
+ (p.x() < captionRect.left() || p.x() > captionRect.right()) ) )
+ return PositionTop;
+
+ // The cursor must be over the center of the titlebar.
+ return PositionCenter;
+ }
+
+ // Test the sides
+ else if ( p.y() < bottomBorder ) {
+ // Test for the left side
+ if ( p.x() < leftBorder ) {
+ if ( p.y() < height() - bottomCornerSize )
+ return PositionLeft;
+ else
+ return PositionBottomLeft;
+ }
+
+ // Test for the right side
+ else if ( p.x() > rightBorder ) {
+ if ( p.y() < height() - bottomCornerSize )
+ return PositionRight;
+ else
+ return PositionBottomRight;
+ }
+
+ // The cursor must be over the center of the window
+ return PositionCenter;
+ }
+
+ // Test the grab bar / bottom border
+ else {
+ // Test for the bottom left corner
+ if ( p.x() < bottomCornerSize )
+ return PositionBottomLeft;
+
+ // Test for the bottom right corner
+ else if ( p.x() > width() - bottomCornerSize - 1 )
+ return PositionBottomRight;
+
+ // The cursor must be over the bottom border
+ return PositionBottom;
+ }
+
+ // We should never get here
+ return PositionCenter;
+}
+
+
+void KeramikClient::resize( const QSize& s )
+{
+ widget()->resize( s );
+}
+
+
+void KeramikClient::borders( int& left, int& right, int& top, int& bottom ) const
+{
+ int titleBarHeight = clientHandler->titleBarHeight( clientHandler->largeCaptionBubbles() );
+ int grabBarHeight = clientHandler->grabBarHeight();
+ int leftBorderWidth = clientHandler->tile( BorderLeft, isActive() )->width();
+ int rightBorderWidth = clientHandler->tile( BorderRight, isActive() )->width();
+
+ left = leftBorderWidth;
+ right = rightBorderWidth;
+ top = titleBarHeight;
+ bottom = grabBarHeight;
+
+ if ( ( maximizeMode() & MaximizeHorizontal ) && !options()->moveResizeMaximizedWindows())
+ left = right = 0;
+ if( maximizeMode() & MaximizeVertical)
+ {
+ top = clientHandler->titleBarHeight( false );
+ if( !options()->moveResizeMaximizedWindows())
+ bottom = 0;
+ }
+}
+
+
+QSize KeramikClient::minimumSize() const
+{
+ return widget()->minimumSize();
+}
+
+
+bool KeramikClient::eventFilter( QObject* o, QEvent* e )
+{
+ if ( o != widget() )
+ return false;
+
+ switch ( e->type() )
+ {
+ case QEvent::Resize:
+ resizeEvent( static_cast< QResizeEvent* >( e ) );
+ return true;
+
+ case QEvent::Paint:
+ paintEvent( static_cast< QPaintEvent* >( e ) );
+ return true;
+
+ case QEvent::MouseButtonDblClick:
+ mouseDoubleClickEvent( static_cast< QMouseEvent* >( e ) );
+ return true;
+
+ case QEvent::MouseButtonPress:
+ processMousePressEvent( static_cast< QMouseEvent* >( e ) );
+ return true;
+
+ case QEvent::Wheel:
+ wheelEvent( static_cast< QWheelEvent* >( e ));
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+} // namespace Keramik
+
+
+
+// -------------------------------------------------------------------------------------------
+
+
+
+extern "C"
+{
+ KDE_EXPORT KDecorationFactory *create_factory()
+ {
+ Keramik::clientHandler = new Keramik::KeramikHandler();
+ return Keramik::clientHandler;
+ }
+}
+
+
+
+// vim: set noet ts=4 sw=4:
diff --git a/kwin/clients/keramik/keramik.desktop b/kwin/clients/keramik/keramik.desktop
new file mode 100644
index 000000000..c58f8d522
--- /dev/null
+++ b/kwin/clients/keramik/keramik.desktop
@@ -0,0 +1,31 @@
+[Desktop Entry]
+Name=Keramik
+Name[ar]=قرميدي
+Name[be]=Кераміка
+Name[bn]=কেরামিক
+Name[cs]=Keramika
+Name[eo]=Ceramiko
+Name[fa]=کرامیک
+Name[fy]=Keramyk
+Name[hi]=के-रामिक
+Name[it]=Ceramica
+Name[lo]=ເຄຣາມິກ - K
+Name[lv]=Keramika
+Name[mk]=Керамик
+Name[mn]=Ваар
+Name[nb]=Keramikk
+Name[ne]=केरामिक
+Name[nn]=Keramikk
+Name[pa]=ਕੀਰਾਮਿਕ
+Name[se]=Bálseduodji
+Name[sr]=Керамика
+Name[sr@Latn]=Keramika
+Name[ta]=கெராமிக்
+Name[te]=కెరామిక్
+Name[th]=เครามิก
+Name[uk]=Керамік
+Name[uz]=Keramika
+Name[uz@cyrillic]=Керамика
+Name[vi]=Gốm
+X-KDE-Library=kwin3_keramik
+
diff --git a/kwin/clients/keramik/keramik.h b/kwin/clients/keramik/keramik.h
new file mode 100644
index 000000000..40a24a058
--- /dev/null
+++ b/kwin/clients/keramik/keramik.h
@@ -0,0 +1,201 @@
+/*
+ *
+ * Keramik KWin client (version 0.8)
+ *
+ * Copyright (C) 2002 Fredrik Hglund <fredrik@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the license, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __KERAMIK_H
+#define __KERAMIK_H
+
+#include <qbutton.h>
+#include <kdecoration.h>
+#include <kdecorationfactory.h>
+
+#include "tiles.h"
+
+class QSpacerItem;
+
+namespace Keramik {
+
+ enum TilePixmap { TitleLeft=0, TitleCenter, TitleRight,
+ CaptionSmallLeft, CaptionSmallCenter, CaptionSmallRight,
+ CaptionLargeLeft, CaptionLargeCenter, CaptionLargeRight,
+ GrabBarLeft, GrabBarCenter, GrabBarRight,
+ BorderLeft, BorderRight, NumTiles };
+
+ enum Button { MenuButton=0, OnAllDesktopsButton, HelpButton, MinButton,
+ MaxButton, CloseButton, AboveButton, BelowButton, ShadeButton,
+ NumButtons };
+
+ enum ButtonDeco { Menu=0, OnAllDesktops, NotOnAllDesktops, Help, Minimize, Maximize,
+ Restore, Close, AboveOn, AboveOff, BelowOn, BelowOff, ShadeOn, ShadeOff,
+ NumButtonDecos };
+
+ struct SettingsCache
+ {
+ bool largeGrabBars:1;
+ bool smallCaptionBubbles:1;
+ };
+
+ class KeramikHandler : public KDecorationFactory
+ {
+ public:
+ KeramikHandler();
+ ~KeramikHandler();
+
+ virtual QValueList< BorderSize > borderSizes() const;
+ virtual bool reset( unsigned long changed );
+ virtual KDecoration* createDecoration( KDecorationBridge* );
+ virtual bool supports( Ability ability );
+
+ bool showAppIcons() const { return showIcons; }
+ bool useShadowedText() const { return shadowedText; }
+ bool largeCaptionBubbles() const { return !smallCaptionBubbles; }
+
+ int titleBarHeight( bool large ) const {
+ return ( large ? activeTiles[CaptionLargeCenter]->height()
+ : activeTiles[CaptionSmallCenter]->height() );
+ }
+
+ int grabBarHeight() const
+ { return activeTiles[GrabBarCenter]->height(); }
+
+ const QPixmap *roundButton() const { return titleButtonRound; }
+ const QPixmap *squareButton() const { return titleButtonSquare; }
+ const QBitmap *buttonDeco( ButtonDeco deco ) const
+ { return buttonDecos[ deco ]; }
+
+ inline const QPixmap *tile( TilePixmap tilePix, bool active ) const;
+
+ private:
+ void readConfig();
+ void createPixmaps();
+ void destroyPixmaps();
+
+ void addWidth (int width, QPixmap *&pix, bool left, QPixmap *bottomPix);
+ void addHeight (int height, QPixmap *&pix);
+ void flip( QPixmap *&, QPixmap *& );
+ void pretile( QPixmap *&, int, Qt::Orientation );
+ QPixmap *composite( QImage *, QImage * );
+ QImage *loadImage( const QString &, const QColor & );
+ QPixmap *loadPixmap( const QString &, const QColor & );
+
+ bool showIcons:1, shadowedText:1,
+ smallCaptionBubbles:1, largeGrabBars:1;
+ SettingsCache *settings_cache;
+ KeramikImageDb *imageDb;
+
+ QPixmap *activeTiles[ NumTiles ];
+ QPixmap *inactiveTiles[ NumTiles ];
+ QBitmap *buttonDecos[ NumButtonDecos ];
+
+ QPixmap *titleButtonRound, *titleButtonSquare;
+
+ }; // class KeramikHandler
+
+ class KeramikClient;
+ class KeramikButton : public QButton
+ {
+ public:
+ KeramikButton( KeramikClient *, const char *, Button, const QString &, const int realizeBtns = LeftButton );
+ ~KeramikButton();
+
+ ButtonState lastButton() const { return lastbutton; }
+
+ private:
+ void enterEvent( QEvent * );
+ void leaveEvent( QEvent * );
+ void mousePressEvent( QMouseEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+ void drawButton( QPainter * );
+
+ private:
+ KeramikClient *client;
+ Button button;
+ bool hover;
+ ButtonState lastbutton;
+ int realizeButtons;
+ }; // class KeramikButton
+
+
+ class KeramikClient : public KDecoration
+ {
+ Q_OBJECT
+
+ public:
+
+ KeramikClient( KDecorationBridge* bridge, KDecorationFactory* factory );
+ ~KeramikClient();
+ virtual void init();
+ virtual void reset( unsigned long changed );
+ virtual Position mousePosition( const QPoint& p ) const;
+ virtual void borders( int& left, int& right, int& top, int& bottom ) const;
+ virtual void resize( const QSize& s );
+ virtual QSize minimumSize() const;
+ virtual bool eventFilter( QObject* o, QEvent* e );
+ virtual void activeChange();
+ virtual void captionChange();
+ virtual void maximizeChange();
+ virtual void desktopChange();
+ virtual void shadeChange();
+
+ private:
+ void createLayout();
+ void addButtons( QBoxLayout*, const QString & );
+ void updateMask(); // FRAME
+ void updateCaptionBuffer();
+ void iconChange();
+ void resizeEvent( QResizeEvent *); // FRAME
+ void paintEvent( QPaintEvent *); // FRAME
+ void mouseDoubleClickEvent( QMouseEvent * ); // FRAME
+ void wheelEvent( QWheelEvent *); //FRAME
+ int width() const { return widget()->width(); }
+ int height() const { return widget()->height(); }
+
+ void calculateCaptionRect();
+
+ inline bool maximizedVertical() const {
+ return ( maximizeMode() & MaximizeVertical );
+ }
+
+ private slots:
+ void menuButtonPressed();
+ void slotMaximize();
+ void slotAbove();
+ void slotBelow();
+ void slotShade();
+ void keepAboveChange( bool );
+ void keepBelowChange( bool );
+
+ private:
+ QSpacerItem *topSpacer, *titlebar;
+ KeramikButton *button[ NumButtons ];
+ QRect captionRect;
+ QPixmap captionBuffer;
+ QPixmap *activeIcon, *inactiveIcon;
+ bool captionBufferDirty:1, maskDirty:1;
+ bool largeCaption:1, largeTitlebar:1;
+ }; // class KeramikClient
+
+} // namespace Keramik
+
+#endif // ___KERAMIK_H
+
+// vim: set noet ts=4 sw=4:
diff --git a/kwin/clients/keramik/pics/border-left.png b/kwin/clients/keramik/pics/border-left.png
new file mode 100644
index 000000000..298a0aa9a
--- /dev/null
+++ b/kwin/clients/keramik/pics/border-left.png
Binary files differ
diff --git a/kwin/clients/keramik/pics/border-right.png b/kwin/clients/keramik/pics/border-right.png
new file mode 100644
index 000000000..1ca876b0d
--- /dev/null
+++ b/kwin/clients/keramik/pics/border-right.png
Binary files differ
diff --git a/kwin/clients/keramik/pics/bottom-center.png b/kwin/clients/keramik/pics/bottom-center.png
new file mode 100644
index 000000000..d6d002534
--- /dev/null
+++ b/kwin/clients/keramik/pics/bottom-center.png
Binary files differ
diff --git a/kwin/clients/keramik/pics/bottom-left.png b/kwin/clients/keramik/pics/bottom-left.png
new file mode 100644
index 000000000..16a2ab982
--- /dev/null
+++ b/kwin/clients/keramik/pics/bottom-left.png
Binary files differ
diff --git a/kwin/clients/keramik/pics/bottom-right.png b/kwin/clients/keramik/pics/bottom-right.png
new file mode 100644
index 000000000..2d4045432
--- /dev/null
+++ b/kwin/clients/keramik/pics/bottom-right.png
Binary files differ
diff --git a/kwin/clients/keramik/pics/caption-large-center.png b/kwin/clients/keramik/pics/caption-large-center.png
new file mode 100644
index 000000000..786276b55
--- /dev/null
+++ b/kwin/clients/keramik/pics/caption-large-center.png
Binary files differ
diff --git a/kwin/clients/keramik/pics/caption-large-left.png b/kwin/clients/keramik/pics/caption-large-left.png
new file mode 100644
index 000000000..7d96bdcea
--- /dev/null
+++ b/kwin/clients/keramik/pics/caption-large-left.png
Binary files differ
diff --git a/kwin/clients/keramik/pics/caption-large-right.png b/kwin/clients/keramik/pics/caption-large-right.png
new file mode 100644
index 000000000..3055d13a7
--- /dev/null
+++ b/kwin/clients/keramik/pics/caption-large-right.png
Binary files differ
diff --git a/kwin/clients/keramik/pics/caption-small-center.png b/kwin/clients/keramik/pics/caption-small-center.png
new file mode 100644
index 000000000..78636dfd1
--- /dev/null
+++ b/kwin/clients/keramik/pics/caption-small-center.png
Binary files differ
diff --git a/kwin/clients/keramik/pics/caption-small-left.png b/kwin/clients/keramik/pics/caption-small-left.png
new file mode 100644
index 000000000..cb7e69d73
--- /dev/null
+++ b/kwin/clients/keramik/pics/caption-small-left.png
Binary files differ
diff --git a/kwin/clients/keramik/pics/caption-small-right.png b/kwin/clients/keramik/pics/caption-small-right.png
new file mode 100644
index 000000000..9fc74640e
--- /dev/null
+++ b/kwin/clients/keramik/pics/caption-small-right.png
Binary files differ
diff --git a/kwin/clients/keramik/pics/grabbar-center.png b/kwin/clients/keramik/pics/grabbar-center.png
new file mode 100644
index 000000000..b623b5df2
--- /dev/null
+++ b/kwin/clients/keramik/pics/grabbar-center.png
Binary files differ
diff --git a/kwin/clients/keramik/pics/grabbar-left.png b/kwin/clients/keramik/pics/grabbar-left.png
new file mode 100644
index 000000000..653f5ccfb
--- /dev/null
+++ b/kwin/clients/keramik/pics/grabbar-left.png
Binary files differ
diff --git a/kwin/clients/keramik/pics/grabbar-right.png b/kwin/clients/keramik/pics/grabbar-right.png
new file mode 100644
index 000000000..248d55410
--- /dev/null
+++ b/kwin/clients/keramik/pics/grabbar-right.png
Binary files differ
diff --git a/kwin/clients/keramik/pics/titlebar-center.png b/kwin/clients/keramik/pics/titlebar-center.png
new file mode 100644
index 000000000..bac31dc55
--- /dev/null
+++ b/kwin/clients/keramik/pics/titlebar-center.png
Binary files differ
diff --git a/kwin/clients/keramik/pics/titlebar-left.png b/kwin/clients/keramik/pics/titlebar-left.png
new file mode 100644
index 000000000..bc8ee5ca3
--- /dev/null
+++ b/kwin/clients/keramik/pics/titlebar-left.png
Binary files differ
diff --git a/kwin/clients/keramik/pics/titlebar-right.png b/kwin/clients/keramik/pics/titlebar-right.png
new file mode 100644
index 000000000..d34a465f5
--- /dev/null
+++ b/kwin/clients/keramik/pics/titlebar-right.png
Binary files differ
diff --git a/kwin/clients/keramik/pics/titlebutton-round-huge.png b/kwin/clients/keramik/pics/titlebutton-round-huge.png
new file mode 100644
index 000000000..c5ca19342
--- /dev/null
+++ b/kwin/clients/keramik/pics/titlebutton-round-huge.png
Binary files differ
diff --git a/kwin/clients/keramik/pics/titlebutton-round-large.png b/kwin/clients/keramik/pics/titlebutton-round-large.png
new file mode 100644
index 000000000..9c3267bf9
--- /dev/null
+++ b/kwin/clients/keramik/pics/titlebutton-round-large.png
Binary files differ
diff --git a/kwin/clients/keramik/pics/titlebutton-round.png b/kwin/clients/keramik/pics/titlebutton-round.png
new file mode 100644
index 000000000..dd2369af3
--- /dev/null
+++ b/kwin/clients/keramik/pics/titlebutton-round.png
Binary files differ
diff --git a/kwin/clients/keramik/pics/titlebutton-square-huge.png b/kwin/clients/keramik/pics/titlebutton-square-huge.png
new file mode 100644
index 000000000..a908a9f27
--- /dev/null
+++ b/kwin/clients/keramik/pics/titlebutton-square-huge.png
Binary files differ
diff --git a/kwin/clients/keramik/pics/titlebutton-square-large.png b/kwin/clients/keramik/pics/titlebutton-square-large.png
new file mode 100644
index 000000000..6e3ada47b
--- /dev/null
+++ b/kwin/clients/keramik/pics/titlebutton-square-large.png
Binary files differ
diff --git a/kwin/clients/keramik/pics/titlebutton-square.png b/kwin/clients/keramik/pics/titlebutton-square.png
new file mode 100644
index 000000000..871cf751a
--- /dev/null
+++ b/kwin/clients/keramik/pics/titlebutton-square.png
Binary files differ