Back to index

kdeartwork  4.3.2
icewm.cpp
Go to the documentation of this file.
00001 /*
00002   $Id: icewm.cpp 922431 2009-02-07 01:12:28Z schwarzer $
00003 
00004   Gallium-IceWM themeable KWin client
00005 
00006   Copyright 2001
00007        Karol Szwed <gallium@kde.org>
00008        http://gallium.n3.net/
00009 
00010   This program is free software; you can redistribute it and/or
00011   modify it under the terms of the GNU General Public
00012   License as published by the Free Software Foundation; either
00013   version 2 of the License, or (at your option) any later version.
00014 
00015   This program is distributed in the hope that it will be useful,
00016   but WITHOUT ANY WARRANTY; without even the implied warranty of
00017   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018   General Public License for more details.
00019 
00020   You should have received a copy of the GNU General Public License
00021   along with this program; see the file COPYING.  If not, write to
00022   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00023   Boston, MA 02110-1301, USA.
00024 
00025   -----------------------------------------------------------------------------
00026   This client loads most icewm 1.0.X pixmap themes, without taking into account
00027   specific font settings for clients, or coloured mouse cursors. Titlebar
00028   fonts can be changed via the kde control center. Bi-colour mouse cursors
00029   may be added in future if requested by users, as well as theme font support.
00030   Any styles using inbuilt icewm titlebar drawing without using pixmaps (e.g.
00031   Warp4, win95 etc.) are not fully supported, and may cause drawing errors,
00032   as these themes use in-built icewm drawing mechanisms.
00033 
00034   When a pixmap theme is not present (or a corrupt one is present) then very
00035   plain title decorations are painted instead, so that users don't see
00036   non-painted window areas where possible ;)
00037 
00038   At a later date, frame shaping may be added if really requested, and an
00039   update to support the latest icewm 1.1.X theme format may be made.
00040 
00041 */
00042 
00043 #include <kconfig.h>
00044 #include <kstandarddirs.h>
00045 #include <kglobal.h>
00046 #include <klocale.h>
00047 #include <kdrawutil.h>
00048 #include <qapplication.h>
00049 #include <qlabel.h>
00050 #include <qdrawutil.h>
00051 #include <qdatetime.h>
00052 #include <qbitmap.h>
00053 #include <qcursor.h>
00054 #include <qstring.h>
00055 #include <qtooltip.h>
00056 #include <qregexp.h>
00057 //Added by qt3to4:
00058 #include <QPixmap>
00059 #include <QPaintEvent>
00060 #include <QGridLayout>
00061 #include <QEvent>
00062 #include <QBoxLayout>
00063 #include <QShowEvent>
00064 #include <QResizeEvent>
00065 #include <QMouseEvent>
00066 #include "icewm.h"
00067 
00068 namespace IceWM {
00069 
00071 // Here's the global pixmap stuff - as memory efficient as it can be :)
00073 
00074 // IceWM frame pixmaps
00075 QPixmap* frameTL[] = {NULL, NULL};
00076 QPixmap* frameT [] = {NULL, NULL};
00077 QPixmap* frameTR[] = {NULL, NULL};
00078 QPixmap* frameL [] = {NULL, NULL};
00079 QPixmap* frameR [] = {NULL, NULL};
00080 QPixmap* frameBL[] = {NULL, NULL};
00081 QPixmap* frameB [] = {NULL, NULL};
00082 QPixmap* frameBR[] = {NULL, NULL};
00083 
00084 // Button pixmaps
00085 QPixmap* closePix[]      = {NULL, NULL};
00086 QPixmap* depthPix[]      = {NULL, NULL};
00087 QPixmap* maximizePix[]   = {NULL, NULL};
00088 QPixmap* minimizePix[]   = {NULL, NULL};
00089 QPixmap* restorePix[]    = {NULL, NULL};
00090 QPixmap* hidePix[]       = {NULL, NULL};
00091 QPixmap* rollupPix[]     = {NULL, NULL};
00092 QPixmap* rolldownPix[]   = {NULL, NULL};
00093 QPixmap* menuButtonPix[] = {NULL, NULL};
00094 
00095 // Titlebar pixmaps
00096 QPixmap* titleJ[] = {NULL, NULL};
00097 QPixmap* titleL[] = {NULL, NULL};
00098 QPixmap* titleS[] = {NULL, NULL};
00099 QPixmap* titleP[] = {NULL, NULL};
00100 QPixmap* titleT[] = {NULL, NULL};
00101 QPixmap* titleM[] = {NULL, NULL};
00102 QPixmap* titleB[] = {NULL, NULL};
00103 QPixmap* titleR[] = {NULL, NULL};
00104 QPixmap* titleQ[] = {NULL, NULL};
00105 
00106 ThemeHandler* clientHandler;
00107 
00108 QString* titleButtonsLeft;
00109 QString* titleButtonsRight;
00110 
00111 QColor* colorActiveBorder;
00112 QColor* colorInActiveBorder;
00113 QColor* colorActiveButton;
00114 QColor* colorInActiveButton;
00115 QColor* colorActiveTitleBarText;
00116 QColor* colorInActiveTitleBarText;
00117 QColor* colorActiveTitleBar;
00118 QColor* colorInActiveTitleBar;
00119 QColor* colorActiveTitleTextShadow;
00120 QColor* colorInActiveTitleTextShadow;
00121 
00122 int  cornerSizeX;
00123 int  cornerSizeY;
00124 int  titleBarHeight;
00125 int  borderSizeX;
00126 int  borderSizeY;
00127 
00128 bool validframe                    = false;
00129 bool useActiveShadow               = false;
00130 bool useInActiveShadow             = false;
00131 
00132 // KControl Settings - Read from kwinicewmrc config file or icewm theme
00133 bool themeTitleTextColors   = true;              // Allow theme to set colors.
00134                                                                       // kcontrol will have no effect
00135 
00136 bool titleBarOnTop                 = true;              // Titlebars can be below windows too :)
00137 bool showMenuButtonIcon     = false;      // Draw a mini icon over the menu pixmap.
00138 bool customButtonPositions  = false;      // Let the theme dictate the btn pos.
00139 bool titleBarCentered              = true;
00140 
00141 enum styles {OTHER, WARP3, WARP4, MOTIF, WIN95, NICE} themeLook;
00142 
00144 // General utility functions
00146 
00147 // Returns true if both active and inactive pixmaps are valid, and not null
00148 bool validPixmaps( QPixmap* p[] )
00149 {
00150        return ( p[Active]   && ( !p[Active]->isNull()   ) &&
00151                       p[InActive] && ( !p[InActive]->isNull() ) );
00152 }
00153 
00154 
00156 // ThemeHandler class
00157 //
00158 // This class allows us to free dynamic memory upon being reset, or unloaded
00159 // from kwin, so we don't leak big images everywhere, and handles the theme
00160 // initialisation / destruction in general.
00162 
00163 ThemeHandler::ThemeHandler()
00164 {
00165        initialized = false;
00166 
00167        // Prevent having globals objects (use pointers to objects)
00168        titleButtonsLeft     = new QString();
00169        titleButtonsRight    = new QString();
00170 
00171        colorActiveBorder                  = new QColor();
00172        colorInActiveBorder         = new QColor();
00173        colorActiveButton            = new QColor();
00174        colorInActiveButton         = new QColor();
00175        colorActiveTitleBarText     = new QColor();
00176        colorInActiveTitleBarText   = new QColor();
00177        colorActiveTitleBar         = new QColor();
00178        colorInActiveTitleBar              = new QColor();
00179        colorActiveTitleTextShadow  = new QColor();
00180        colorInActiveTitleTextShadow = new QColor();
00181 
00182        // Initialize
00183        readConfig();
00184        initTheme();
00185        validframe = isFrameValid();
00186        initialized = true;
00187 }
00188 
00189 
00190 ThemeHandler::~ThemeHandler()
00191 {
00192        if (initialized)
00193               freePixmaps();
00194 
00195        delete colorInActiveTitleTextShadow;
00196        delete colorActiveTitleTextShadow;
00197        delete colorInActiveBorder;
00198        delete colorActiveTitleBarText;
00199        delete colorInActiveTitleBarText;
00200        delete colorActiveTitleBar;
00201        delete colorInActiveTitleBar;
00202        delete colorActiveBorder;
00203        delete colorActiveButton;
00204        delete colorInActiveButton;
00205 
00206        delete titleButtonsRight;
00207        delete titleButtonsLeft;
00208 }
00209 
00210 
00211 KDecoration* ThemeHandler::createDecoration( KDecorationBridge* bridge )
00212 {
00213        return new IceWMClient( bridge, this );
00214 }
00215 
00216 
00217 // Converts KDE style button strings to icewm style button strings
00218 void ThemeHandler::convertButtons( QString& s )
00219 {
00220        s.replace( QRegExp("_"), "");      // Spacer     (ignored)
00221        s.replace( QRegExp("H"), "");      // Help              (ignored)
00222        s.replace( QRegExp("M"), "s");     // Sysmenu
00223        s.replace( QRegExp("S"), "d");     // Sticky/OnAllDesktops
00224        s.replace( QRegExp("I"), "i");     // Minimize
00225        s.replace( QRegExp("A"), "m");     // Maximize
00226        s.replace( QRegExp("X"), "x");     // Close
00227 }
00228 
00229 
00230 // Reverses all characters in a QString
00231 QString ThemeHandler::reverseString( QString s )
00232 {
00233        if (s.length() <= 1)
00234               return s;
00235 
00236        QString tmpStr;
00237        for(int i = s.length()-1; i >= 0; i--)
00238        {
00239               tmpStr += s[(unsigned int)i];
00240        }
00241 
00242        return tmpStr;
00243 }
00244 
00245 
00246 // This function reads the kwinicewmrc config file
00247 void ThemeHandler::readConfig()
00248 {
00249        KConfig conf("kwinicewmrc");
00250        conf.setGroup("General");
00251        themeName = conf.readEntry("CurrentTheme");
00252        themeTitleTextColors = conf.readEntry("ThemeTitleTextColors", true);
00253        showMenuButtonIcon = conf.readEntry("ShowMenuButtonIcon", false);
00254        titleBarOnTop = conf.readEntry("TitleBarOnTop", true);
00255 
00256        customButtonPositions = KDecoration::options()->customButtonPositions();
00257        if (customButtonPositions)
00258        {
00259               *titleButtonsLeft  = KDecoration::options()->titleButtonsLeft();
00260               *titleButtonsRight = KDecoration::options()->titleButtonsRight();
00261 
00262               // Convert KDE to icewm style buttons
00263               convertButtons( *titleButtonsLeft );
00264               convertButtons( *titleButtonsRight );
00265        }
00266 
00267        // Provide a default theme alias
00268        if (themeName == "default")
00269               themeName = "";
00270 }
00271 
00272 
00273 // This creates the dynamic pixmaps upon loading the style
00274 // into the pixmap buffers above, and configures the dimensioning stuff.
00275 void ThemeHandler::initTheme()
00276 {
00277        // Add a slash if required
00278        if ( !themeName.isEmpty() )
00279               themeName += "/";
00280 
00281        // We use kconfig to read icewm config files...
00282        // this is easy since icewm uses key=value pairs!
00283        KConfig config( locate("data", QString("kwin/icewm-themes/") +
00284                                    themeName + QString("default.theme")) );
00285 
00286        // Load specifics, or use IceWM defaults instead.
00287        borderSizeX = config.readNumEntry("BorderSizeX", 6);
00288        borderSizeY = config.readNumEntry("BorderSizeY", 6);
00289        cornerSizeX = config.readNumEntry("CornerSizeX", 24);
00290        cornerSizeY = config.readNumEntry("CornerSizeY", 24);
00291        titleBarCentered = (bool) config.readNumEntry("TitleBarCentered", 0);
00292 
00293        // Check if readConfig() hasn't overridden this value...
00294        if (!showMenuButtonIcon)
00295               showMenuButtonIcon = (bool) config.readNumEntry("ShowMenuButtonIcon", 0);
00296        titleBarHeight = config.readNumEntry("TitleBarHeight", 20);
00297 
00298        if (!customButtonPositions)
00299        {
00300               // Read in the button configuration, stripping any quotes
00301               // Ignore on all desktops 'd' on the left buttons
00302               // (some themes look bad with it on by default)
00303               *titleButtonsLeft = config.readEntry("TitleButtonsLeft", "s");
00304               *titleButtonsLeft = titleButtonsLeft->replace( QRegExp(QString("\"")), "");
00305               *titleButtonsRight = config.readEntry("TitleButtonsRight", "xmir");
00306               *titleButtonsRight = titleButtonsRight->replace( QRegExp(QString("\"")), "");
00307 
00308               // I have no idea why the right side buttons in icewm are reversed
00309               *titleButtonsRight = reverseString( *titleButtonsRight );
00310        }
00311 
00312        // Read the default border and text colours from the config file
00313        // And use IceWM defaults if not found
00314        QString s;
00315 
00316        s = config.readEntry("Look", "other");
00317        if (s=="motif") themeLook = MOTIF;
00318        else if (s=="warp3") themeLook = WARP3;
00319        else if (s=="warp4") themeLook = WARP4;
00320        else if (s=="win95") themeLook = WIN95;
00321        else if (s=="nice") themeLook = NICE;
00322        else themeLook = OTHER;
00323 
00324        s = config.readEntry("ColorActiveBorder", "#C0C0C0");
00325        *colorActiveBorder = decodeColor( s );
00326        s = config.readEntry("ColorNormalBorder", "#C0C0C0");
00327        *colorInActiveBorder = decodeColor( s );
00328        s = config.readEntry("ColorActiveButton", "#C0C0C0");
00329        *colorActiveButton = decodeColor( s );
00330        s = config.readEntry("ColorNormalButton", "#C0C0C0");
00331        *colorInActiveButton = decodeColor( s );
00332 
00333        // Use these as a last resort
00334        s = config.readEntry("ColorActiveTitleBar", "#0000A0");
00335        *colorActiveTitleBar = decodeColor( s );
00336        s = config.readEntry("ColorNormalTitleBar", "#808080");
00337        *colorInActiveTitleBar = decodeColor( s );
00338 
00339        // Read titlebar text colours
00340        s = config.readEntry("ColorActiveTitleBarText", "#FFFFFF");
00341        *colorActiveTitleBarText = decodeColor( s );
00342        s = config.readEntry("ColorNormalTitleBarText", "#000000");
00343        *colorInActiveTitleBarText = decodeColor( s );
00344 
00345        // Use title text shadows only with theme title text colors
00346        if ( themeTitleTextColors )
00347        {
00348               s = config.readEntry("ColorActiveTitleBarShadow");
00349               if (!s.isEmpty())
00350               {
00351                      *colorActiveTitleTextShadow = decodeColor( s );
00352                      useActiveShadow = true;
00353               } else
00354                      useActiveShadow = false;
00355 
00356               s = config.readEntry("ColorNormalTitleBarShadow");
00357               if (!s.isEmpty())
00358               {
00359                      *colorInActiveTitleTextShadow = decodeColor( s );
00360                      useInActiveShadow = true;
00361               } else
00362                      useInActiveShadow = false;
00363        } else
00364               {
00365                      useActiveShadow = false;
00366                      useInActiveShadow = false;
00367               }
00368 
00369        // Stretch pixmaps for speed, where required
00370        setPixmap( titleJ, "title", "J.xpm" );
00371        setPixmap( titleL, "title", "L.xpm" );
00372        setPixmap( titleS, "title", "S.xpm", true );
00373 
00374        setPixmap( titleP, "title", "P.xpm" );
00375        setPixmap( titleT, "title", "T.xpm", true );
00376        setPixmap( titleM, "title", "M.xpm" );
00377        setPixmap( titleB, "title", "B.xpm", true );
00378        setPixmap( titleR, "title", "R.xpm" );
00379        setPixmap( titleQ, "title", "Q.xpm" );
00380 
00381        setPixmapButton( closePix,     "close",     ".xpm" );
00382        setPixmapButton( depthPix,     "depth",     ".xpm" );
00383        setPixmapButton( maximizePix,  "maximize",  ".xpm" );
00384        setPixmapButton( minimizePix,  "minimize",  ".xpm" );
00385        setPixmapButton( restorePix,   "restore",   ".xpm" );
00386        setPixmapButton( hidePix,      "hide",      ".xpm" );
00387        setPixmapButton( rollupPix,    "rollup",    ".xpm" );
00388        setPixmapButton( rolldownPix,  "rolldown",  ".xpm" );
00389        setPixmapButton( menuButtonPix,"menuButton",".xpm" );
00390 
00391        // Top
00392        setPixmap( frameTL, "frame", "TL.xpm" );
00393        setPixmap( frameT,  "frame", "T.xpm", true );
00394        setPixmap( frameTR, "frame", "TR.xpm" );
00395 
00396        // Sides
00397        setPixmap( frameL, "frame", "L.xpm", true, Vertical );
00398        setPixmap( frameR, "frame", "R.xpm", true, Vertical );
00399 
00400        // Bottom
00401        setPixmap( frameBL, "frame", "BL.xpm" );
00402        setPixmap( frameB,  "frame", "B.xpm", true );
00403        setPixmap( frameBR, "frame", "BR.xpm" );
00404 
00405     // Make sure border sizes are at least reasonable...
00406        if (borderSizeX < 0)
00407               borderSizeX = 0;
00408        if (borderSizeY < 0)
00409               borderSizeY = 0;
00410        // ...and titleBarHeight as well
00411        if (titleBarHeight < 0)
00412               titleBarHeight = 0;
00413 
00414        // This is a work-around for some themes
00415        if (!titleT[Active])
00416               titleT[Active] = duplicateValidPixmap( Active );
00417 
00418        if (!titleB[Active])
00419               titleB[Active] = duplicateValidPixmap( Active );
00420 
00421 
00422        if (titleL[Active] && !titleL[InActive])
00423               titleL[InActive] = duplicateValidPixmap( InActive, titleL[Active]->width() );
00424 
00425        if (titleS[Active] && !titleS[InActive])
00426               titleS[InActive] = duplicateValidPixmap( InActive, titleS[Active]->width() );
00427 
00428        if (titleP[Active] && !titleP[InActive])
00429               titleP[InActive] = duplicateValidPixmap( InActive, titleP[Active]->width() );
00430 
00431        if (titleT[Active] && !titleT[InActive])
00432               titleT[InActive] = duplicateValidPixmap( InActive, titleT[Active]->width() );
00433 
00434        if (titleM[Active] && !titleM[InActive])
00435               titleM[InActive] = duplicateValidPixmap( InActive, titleM[Active]->width() );
00436 
00437        if (titleB[Active] && !titleB[InActive])
00438               titleB[InActive] = duplicateValidPixmap( InActive, titleB[Active]->width() );
00439 
00440        if (titleR[Active] && !titleR[InActive])
00441               titleR[InActive] = duplicateValidPixmap( InActive, titleR[Active]->width() );
00442 }
00443 
00444 
00445 QPixmap* ThemeHandler::duplicateValidPixmap( bool act, int size )
00446 {
00447        QPixmap* p1 = NULL;
00448        // Use the stretch or title pixmaps instead
00449        if ( titleS[act] )
00450               p1 = new QPixmap( *titleS[act] );
00451        else if ( titleB[act] )
00452               p1 = new QPixmap( *titleB[act] );
00453        else if ( titleT[act] )
00454               p1 = new QPixmap( *titleT[act] );
00455 
00456        // Stretch if required
00457        if ( (size != -1) && p1 && (!p1->isNull()) )
00458               p1 = stretchPixmap( p1, true, size );
00459 
00460        return p1;
00461 }
00462 
00463 
00464 // Frees all memory used by pixmaps.
00465 void ThemeHandler::freePixmaps()
00466 {
00467        freePixmapGroup( frameTL );
00468        freePixmapGroup( frameT );
00469        freePixmapGroup( frameTR );
00470        freePixmapGroup( frameL );
00471        freePixmapGroup( frameR );
00472        freePixmapGroup( frameBL );
00473        freePixmapGroup( frameB );
00474        freePixmapGroup( frameBR );
00475 
00476        freePixmapGroup( closePix );
00477        freePixmapGroup( depthPix );
00478        freePixmapGroup( maximizePix );
00479        freePixmapGroup( minimizePix );
00480        freePixmapGroup( restorePix );
00481        freePixmapGroup( hidePix );
00482        freePixmapGroup( rollupPix );
00483        freePixmapGroup( rolldownPix );
00484        freePixmapGroup( menuButtonPix );
00485 
00486        freePixmapGroup( titleJ );
00487        freePixmapGroup( titleL );
00488        freePixmapGroup( titleS );
00489        freePixmapGroup( titleP );
00490        freePixmapGroup( titleT );
00491        freePixmapGroup( titleM );
00492        freePixmapGroup( titleB );
00493        freePixmapGroup( titleR );
00494        freePixmapGroup( titleQ );
00495 }
00496 
00497 
00498 // Frees a dynamic pixmap group from the heap.
00499 void ThemeHandler::freePixmapGroup( QPixmap* p[] )
00500 {
00501        if (p)
00502        {
00503               if (p[Active])   delete p[Active];
00504               if (p[InActive]) delete p[InActive];
00505               p[Active] = NULL;
00506               p[InActive] = NULL;
00507        } else
00508               qWarning("kwin-icewm: freePixmapGroup - invalid QPixmap** 'p'\n");
00509 }
00510 
00511 
00512 // Converts icewm colors #C0C0C0 or rgb:C0/C0/C0 to QColors
00513 QColor ThemeHandler::decodeColor( QString& s )
00514 {
00515        // Make rgb:C0/C0/C0, or #C0/C0/C0  -> C0C0C0
00516        s.replace( QRegExp("r"), "");
00517        s.replace( QRegExp("g"), "");
00518        s.replace( QRegExp("b"), "");
00519        s.replace( QRegExp("#"), "");
00520        s.replace( QRegExp("/"), "");
00521        s.replace( QRegExp(":"), "");
00522        s.replace( QRegExp("\\"), "");
00523        s.replace( QRegExp("\""), "");
00524 
00525        // Wierd error - return grey
00526        if (s.length() != 6)
00527               return QColor( 0xC0, 0xC0, 0xC0 );
00528 
00529        // Qt makes this conversion very easy
00530        return QColor( QString("#") + s );
00531 }
00532 
00533 
00534 // Stretches tiny pixmaps vertically or horizontally, taking into account
00535 // repetition in patterns, so as not to make them mismatched
00536 QPixmap* ThemeHandler::stretchPixmap( QPixmap* src, bool stretchHoriz, int stretchSize )
00537 {
00538        if (!src) return NULL;
00539        if (src->isNull()) return NULL;
00540 
00541        int s_inc, size;
00542 
00543        // If it is the right size already, just return
00544        if (stretchSize == -1)
00545        {
00546               if (stretchHoriz)
00547                      s_inc = src->width();
00548               else
00549                      s_inc = src->height();
00550 
00551               size = s_inc;
00552               if (size >= 100)
00553                      return src;
00554 
00555               // Stretch an appropriate amount - taking care of pattern repetition
00556               while( size < 100 )
00557                      size += s_inc;
00558        } else
00559               size = stretchSize;
00560 
00561        QPixmap* p = new QPixmap();
00562        if ( stretchHoriz )
00563               p->resize( size, src->height() );
00564        else
00565               p->resize( src->width(), size );
00566 
00567        QPainter pnt( p );
00568        if ( stretchHoriz )
00569               pnt.drawTiledPixmap( 0, 0, size, src->height(), *src);
00570        else
00571               pnt.drawTiledPixmap( 0, 0, src->width(), size, *src);
00572        pnt.end();
00573 
00574        delete src;
00575        return p;
00576 }
00577 
00578 static void draw3DRect(QPainter &pnt, QColor &col, int x, int y, int w, int h, bool up) {
00579        QColor light = col.light(135);
00580        QColor dark = col.dark(140);
00581        pnt.setPen(up ? light : dark);
00582        pnt.drawLine(x, y, x+w, y);
00583        pnt.drawLine(x, y, x, y+h);
00584        pnt.setPen(up ? dark : light);
00585        pnt.drawLine(x, y+h, x+w, y+h);
00586        pnt.drawLine(x+w, y, x+w, y+h);
00587        pnt.setPen(col);
00588        pnt.drawPoint(x+w, y);
00589        pnt.drawPoint(x, y+h);
00590 }
00591 
00592 void ThemeHandler::setPixmapButton( QPixmap* p[], QString s1, QString s2)
00593 {
00594        if ( p[Active] )
00595               qWarning("kwin-icewm: setPixmap - should be null (1)\n");
00596        if ( p[InActive] )
00597               qWarning("kwin-icewm: setPixmap - should be null (2)\n");
00598 
00599        QString str = locate("appdata", QString("icewm-themes/")
00600                             + themeName + s1 + "A" + s2);
00601        if (str.isEmpty())
00602               str = locate("appdata", QString("icewm-themes/")
00603                             + themeName + s1 + s2);
00604 
00605         QPixmap *qp = new QPixmap(str);
00606        QColor cActive = themeLook == WIN95 ? *colorActiveTitleBar : *colorActiveButton;
00607        QColor cInActive = themeLook == WIN95 ? *colorInActiveTitleBar : *colorInActiveButton;
00608 
00609        if (!qp->isNull() && themeLook > 0) {
00610               int w = qp->width();
00611               if (themeLook > 0 && titleBarHeight > w) w = titleBarHeight;
00612               p[Active] = new QPixmap(w, 2*titleBarHeight );
00613               p[Active] -> fill(cActive);
00614 
00615               QPainter pnt( p[Active] );
00616 
00617               int offX = (w - qp->width())/2;
00618               int offY = (titleBarHeight - qp->height())/2;
00619               if (offY < 0) offY = 0;
00620 
00621               if (themeLook == WIN95) {
00622                      draw3DRect(pnt, *colorActiveButton, offX-1, offY-1,
00623                                qp->width()+1, qp->height()+1, true);
00624                      draw3DRect(pnt, *colorActiveButton, offX-1, offY-1 + titleBarHeight,
00625                                qp->width()+1, qp->height()+1, false);
00626               } else if (themeLook != WARP4) {
00627                      draw3DRect(pnt, *colorActiveButton, 0, 0,
00628                                w-1, titleBarHeight-1, true);
00629                      draw3DRect(pnt, *colorActiveButton, 0, titleBarHeight,
00630                                w-1, 2*titleBarHeight-1, false);
00631               }
00632 
00633               pnt.drawPixmap(offX, offY, *qp);
00634               if (qp->height() <= titleBarHeight) {
00635                      pnt.drawPixmap(offX, titleBarHeight+offY, *qp);
00636               }
00637               pnt.end();
00638               delete qp;
00639        } else {
00640               p[Active] = qp;
00641        }
00642 
00643        str = locate("appdata", QString("icewm-themes/")
00644                    + themeName + s1 + "I" + s2);
00645        if (str.isEmpty())
00646               str = locate("appdata", QString("icewm-themes/")
00647                           + themeName + s1 + s2);
00648 
00649         qp = new QPixmap(str);
00650        if (!qp->isNull() && themeLook > 0) {
00651               int w = qp->width();
00652               if (titleBarHeight > w) w = titleBarHeight;
00653               p[InActive] = new QPixmap(w, 2*titleBarHeight );
00654               p[InActive] -> fill(cInActive);
00655 
00656               QPainter pnt( p[InActive] );
00657 
00658               int offX = (w - qp->width())/2;
00659               int offY = (titleBarHeight - qp->height())/2;
00660               if (offY < 0) offY = 0;
00661 
00662               if (themeLook == WIN95) {
00663                      draw3DRect(pnt, *colorInActiveButton, offX-1, offY-1,
00664                                qp->width()+1, qp->height()+1, true);
00665                      draw3DRect(pnt, *colorInActiveButton, offX-1, offY-1 + titleBarHeight,
00666                                qp->width()+1, qp->height()+1, false);
00667               } else if (themeLook != WARP4) {
00668                      draw3DRect(pnt, *colorInActiveButton, 0, 0,
00669                                w-1, titleBarHeight-1, true);
00670                      draw3DRect(pnt, *colorActiveButton, 0, titleBarHeight,
00671                                w-1, 2*titleBarHeight-1, false);
00672               }
00673               pnt.drawPixmap(offX, offY, *qp);
00674               if (qp->height() <= titleBarHeight) {
00675                      pnt.drawPixmap(offX, titleBarHeight+offY, *qp);
00676               }
00677               pnt.end();
00678               delete qp;
00679        } else {
00680               p[InActive] = qp;
00681        }
00682 }
00683 
00684 
00685 
00686 
00687 // Loads the specified Active/InActive files into the specific pixmaps, and
00688 // can perform horizontal / vertical stretching if required for speed.
00689 // Tries to implement some icewm specific pixmap handling for some dodgy themes
00690 void ThemeHandler::setPixmap( QPixmap* p[], QString s1, QString s2,
00691                                                    bool stretch, bool stretchHoriz )
00692 {
00693        if ( p[Active] )
00694               qWarning("kwin-icewm: setPixmap - should be null (1)\n");
00695        if ( p[InActive] )
00696               qWarning("kwin-icewm: setPixmap - should be null (2)\n");
00697 
00698        p[Active]   = new QPixmap( locate("data", QString("kwin/icewm-themes/")
00699                                                         + themeName + s1 + "A" + s2) );
00700        p[InActive] = new QPixmap( locate("data", QString("kwin/icewm-themes/")
00701                                                         + themeName + s1 + "I" + s2) );
00702 
00703        // Stretch the pixmap if requested.
00704        if ( stretch )
00705        {
00706               if (p[Active])
00707                      p[Active] = stretchPixmap( p[Active], stretchHoriz );
00708               if (p[InActive])
00709                      p[InActive] = stretchPixmap( p[InActive], stretchHoriz );
00710        }
00711 
00712        if ( p[Active] && p[InActive] )
00713        {
00714               // Make sure active and inactive pixmaps are the same width for proper painting
00715               if (p[Active]->width() > p[InActive]->width())
00716                      p[InActive] = stretchPixmap( p[InActive], true, p[Active]->width() );
00717        }
00718 
00719 }
00720 
00721 
00722 // returns true if there were enough pixmaps loaded to
00723 // draw the pixmap frame properly.
00724 bool ThemeHandler::isFrameValid()
00725 {
00726        return
00727          ( validPixmaps( frameTL ) &&
00728               validPixmaps( frameT )  &&
00729               validPixmaps( frameTR ) &&
00730               validPixmaps( frameL )  &&
00731               validPixmaps( frameR )  &&
00732               validPixmaps( frameBL ) &&
00733               validPixmaps( frameB )  &&
00734               validPixmaps( frameBR ) );
00735 }
00736 
00737 
00738 // Resets the theme, and re-clients all kwin's wrapped windows.
00739 bool ThemeHandler::reset( unsigned long)
00740 {
00741        initialized = false;
00742        freePixmaps();
00743        readConfig();
00744        initTheme();
00745        validframe = isFrameValid();
00746        initialized = true;
00747 
00748        // recreate all clients
00749        return true;
00750 }
00751 
00752 bool ThemeHandler::supports( Ability ability )
00753 {
00754     switch( ability )
00755     {
00756         case AbilityAnnounceButtons:
00757         case AbilityButtonMenu:
00758         case AbilityButtonOnAllDesktops:
00759         case AbilityButtonMinimize:
00760         case AbilityButtonMaximize:
00761         case AbilityButtonClose:
00762             return true;
00763         default:
00764             return false;
00765     };
00766 }
00767 
00768 
00770 // IceWM button class
00772 
00773 IceWMButton::IceWMButton(IceWMClient *parent, const char *name, QPixmap* (*p)[2],
00774          bool isToggle, const QString& tip, const int realizeBtns )
00775     : Q3Button(parent->widget(), name)
00776 {
00777        m_realizeButtons = realizeBtns;
00778        setTipText(tip);
00779        setCursor(ArrowCursor);
00780        // Eliminate any possible background flicker
00781        setBackgroundMode( QWidget::NoBackground );
00782        client = parent;
00783        usePixmap( p );
00784        setFixedSize( sizeHint() );
00785        setToggleButton( isToggle );
00786 }
00787 
00788 
00789 void IceWMButton::setTipText(const QString &tip) {
00790        if(KDecoration::options()->showTooltips()) {
00791               QToolTip::remove(this );
00792               this->setToolTip( tip );
00793        }
00794 }
00795 
00796 
00797 QSize IceWMButton::sizeHint() const
00798 {
00799        // Check for invalid data
00800        if ( validPixmaps( (QPixmap**) (*pix) ) )  // Cast to avoid dumb warning
00801        {
00802               QPixmap* p = (*pix)[ client->isActive() ? Active : InActive ];
00803               return( QSize(p->width(), titleBarHeight) );
00804        } else
00805               return( QSize(0, 0) );
00806 }
00807 
00808 
00809 void IceWMButton::usePixmap( QPixmap* (*p)[2] )
00810 {
00811        if (validPixmaps( *p )) {
00812               pix = p;
00813               setFixedSize( (*pix)[Active]->width(), titleBarHeight );
00814               repaint( false );
00815        } else
00816               pix = NULL;
00817 }
00818 
00819 
00820 void IceWMButton::drawButton(QPainter *pnt)
00821 {
00822        if ( pix && validPixmaps(*pix) )
00823        {
00824               QPixmap* p = (*pix)[ client->isActive() ? Active : InActive ];
00825 
00826               if( p && (!p->isNull()) )
00827               {
00828                      int width = p->width();
00829 
00830                      // Only draw the lower pixmap 1/2 for down, and upper 1/2 for up state
00831                      if( isDown() || isOn() )
00832                             pnt->drawPixmap(0, 0, *p, 0, titleBarHeight, width, titleBarHeight);
00833                      else
00834                             pnt->drawPixmap(0, 0, *p, 0, 0, width, titleBarHeight);
00835               }
00836        } else
00837               qWarning("kwin-icewm: Can't paint a null pixmap button");
00838 }
00839 
00840 
00841 void IceWMButton::turnOn( bool isOn )
00842 {
00843        if ( isToggleButton() )
00844               setOn( isOn );
00845 }
00846 
00847 
00848 void IceWMButton::mousePressEvent( QMouseEvent* e )
00849 {
00850        last_button = e->button();
00851        QMouseEvent me ( e->type(), e->pos(), e->globalPos(),
00852                                     (e->button()&m_realizeButtons)?Qt::LeftButton:Qt::NoButton, e->state() );
00853        Q3Button::mousePressEvent( &me );
00854 }
00855 
00856 
00857 void IceWMButton::mouseReleaseEvent( QMouseEvent* e )
00858 {
00859        last_button = e->button();
00860        QMouseEvent me ( e->type(), e->pos(), e->globalPos(),
00861                                     (e->button()&m_realizeButtons)?Qt::LeftButton:Qt::NoButton, e->state() );
00862        Q3Button::mouseReleaseEvent( &me );
00863 }
00864 
00865 
00866 
00868 // IceWMClient class
00870 
00871 IceWMClient::IceWMClient( KDecorationBridge* bridge, KDecorationFactory* factory )
00872     : KDecoration (bridge, factory),
00873       m_closing(false)
00874 {
00875 }
00876 
00877 
00878 IceWMClient::~IceWMClient()
00879 {
00880        // Free the menu pixmaps if previously allocated
00881        if ( menuButtonWithIconPix[Active] )
00882               delete menuButtonWithIconPix[Active];
00883        if ( menuButtonWithIconPix[InActive] )
00884               delete menuButtonWithIconPix[InActive];
00885 }
00886 
00887 
00888 void IceWMClient::init()
00889 {
00890        createMainWidget( WNoAutoErase | WStaticContents );
00891        widget()->installEventFilter( this );
00892 
00893        // Set button pointers to null so we can track things
00894        for(int i= IceWMClient::BtnSysMenu; i < IceWMClient::BtnCount; i++)
00895               button[i] = NULL;
00896 
00897        // Make sure we can track the menu pixmaps too.
00898        menuButtonWithIconPix[Active] = NULL;
00899        menuButtonWithIconPix[InActive] = NULL;
00900 
00901        // No flicker thanks
00902        widget()->setBackgroundMode( NoBackground );
00903 
00904        // Pack the windowWrapper() window within a grid layout
00905        grid = new QGridLayout(widget(), 0, 0, 0);
00906        grid->setResizeMode(QLayout::FreeResize);
00907        grid->addRowSpacing(0, borderSizeY);      // Top grab bar
00908 
00909        // Do something IceWM can't do :)
00910        if (titleBarOnTop) {
00911               if( isPreview())
00912                      grid->addWidget( new QLabel( i18n( "<center><b>IceWM preview</b></center>" ), widget() ), 2, 1);
00913                 else
00914                      grid->addItem( new QSpacerItem( 0, 0 ), 2, 1);
00915               // no shade flicker
00916        grid->addItem( new QSpacerItem( 0, 0, QSizePolicy::Fixed,                                                                 QSizePolicy::Expanding ) );
00917     }
00918        else {
00919               // no shade flicker
00920        grid->addItem( new QSpacerItem( 0, 0, QSizePolicy::Fixed,                                                                 QSizePolicy::Expanding ) );
00921               if( isPreview())
00922                      grid->addWidget( new QLabel( i18n( "<center><b>IceWM preview</b></center>" ), widget() ), 1, 1);
00923                 else
00924                      grid->addItem( new QSpacerItem( 0, 0 ), 1, 1);
00925     }
00926 
00927        grid->setRowStretch(1, 10);
00928        grid->setRowStretch(2, 10);
00929        grid->setColStretch(1, 10);
00930        grid->addRowSpacing(3, borderSizeY);
00931        grid->addColSpacing(0, borderSizeX);
00932        grid->addColSpacing(2, borderSizeX);
00933 
00934        // Pack the titlebar with spacers and buttons
00935        hb = new QBoxLayout(0, QBoxLayout::LeftToRight, 0, 0, 0);
00936        hb->setResizeMode( QLayout::FreeResize );
00937 
00938        titleSpacerJ = addPixmapSpacer( titleJ );
00939 
00940        addClientButtons( *titleButtonsLeft );
00941        titleSpacerL = addPixmapSpacer( titleL );
00942 
00943        // Centre titlebar if required.
00944        QSizePolicy::SizeType spTitleBar;
00945        spTitleBar = titleBarCentered ? QSizePolicy::Expanding : QSizePolicy::Maximum;
00946        titleSpacerS = addPixmapSpacer( titleS, spTitleBar, 1 );
00947        titleSpacerP = addPixmapSpacer( titleP );
00948 
00949        titlebar = new QSpacerItem( titleTextWidth(caption()), titleBarHeight,
00950                                                         QSizePolicy::Preferred, QSizePolicy::Fixed );
00951        hb->addItem(titlebar);
00952 
00953        titleSpacerM = addPixmapSpacer( titleM );
00954        titleSpacerB = addPixmapSpacer( titleB, QSizePolicy::Expanding, 1 );
00955        titleSpacerR = addPixmapSpacer( titleR );
00956 
00957        addClientButtons( *titleButtonsRight );
00958 
00959        titleSpacerQ = addPixmapSpacer( titleQ );
00960 
00961        if (titleBarOnTop)
00962               grid->addLayout ( hb, 1, 1 );
00963        else
00964               grid->addLayout ( hb, 2, 1 );
00965 }
00966 
00967 
00968 // Adds the buttons to the hbox layout as per the buttons specified
00969 // in the button string 's'
00970 void IceWMClient::addClientButtons( const QString& s )
00971 {
00972        if (!s.isEmpty())
00973               for(unsigned int i = 0; i < s.length(); i++)
00974               {
00975                      switch ( s[i].latin1() )
00976                      {
00977                             case 's':
00978                                    // Create the menu icons, and render with the current mini-icon
00979                                    // if explicitly requested by the theme.
00980                                    if ( (validPixmaps(menuButtonPix) || showMenuButtonIcon) && !button[BtnSysMenu])
00981                                    {
00982                                           if (showMenuButtonIcon) {
00983                                                  renderMenuIcons();
00984                                                  button[BtnSysMenu] = new IceWMButton(this, "menu",
00985                                                         &menuButtonWithIconPix, false, i18n("Menu"), Qt::LeftButton|Qt::RightButton);
00986                                           }
00987                                           else
00988                                                  button[BtnSysMenu] = new IceWMButton(this, "menu",
00989                                                         &menuButtonPix, false, i18n("Menu"));
00990 
00991                                           connect( button[BtnSysMenu], SIGNAL(pressed()),
00992                                                          this, SLOT(menuButtonPressed()));
00993                                           connect( button[BtnSysMenu], SIGNAL(released()),
00994                                                          this, SLOT(menuButtonReleased()));
00995                                           hb->addWidget( button[BtnSysMenu] );
00996                                    }
00997                                    break;
00998 
00999                             case 'x':
01000                                    if ( validPixmaps(closePix) && !button[BtnClose] && isCloseable())
01001                                    {
01002                                           button[BtnClose] = new IceWMButton(this, "close",
01003                                                         &closePix, false, i18n("Close"));
01004                                           hb->addWidget( button[BtnClose] );
01005                                           connect( button[BtnClose], SIGNAL(clicked()),
01006                                                          this, SLOT(closeWindow()));
01007                                    }
01008                                    break;
01009 
01010                             case 'm':
01011                                    if ( validPixmaps(maximizePix) && !button[BtnMaximize] && isMaximizable() )
01012                                    {
01013                                           button[BtnMaximize] = new IceWMButton(this, "maximize",
01014                                                         &maximizePix, false, i18n("Maximize"), Qt::LeftButton|Qt::MidButton|Qt::RightButton);
01015                                           hb->addWidget( button[BtnMaximize] );
01016                                           connect( button[BtnMaximize], SIGNAL(clicked()),
01017                                                          this, SLOT(slotMaximize()));
01018                                    }
01019                                    break;
01020 
01021                             case 'i':
01022                                    if ( validPixmaps(minimizePix) && !button[BtnMinimize] &&
01023                                            isMinimizable() )
01024                                    {
01025                                           button[BtnMinimize] = new IceWMButton(this, "minimize",
01026                                                         &minimizePix, false, i18n("Minimize"));
01027                                           hb->addWidget( button[BtnMinimize] );
01028                                           connect( button[BtnMinimize], SIGNAL(clicked()),
01029                                                          this, SLOT(minimize()));
01030                                    }
01031                                    break;
01032 
01033                             /* Not yet implemented - how's hide useful anyway?
01034                             case 'h':
01035                                    if ( button[BtnHide]  && !button[BtnHide] )
01036                                           hb->addWidget( button[BtnHide] );
01037                                    break; */
01038 
01039                             case 'r':
01040                                    // NOTE: kwin doesn't have toggleShade() in clients.h !
01041                                 if ( validPixmaps(rollupPix) && !button[BtnRollup] )
01042                                 {
01043                                           button[BtnRollup] = new IceWMButton(this, "shade",
01044                                                  isSetShade() ? &rolldownPix : &rollupPix,
01045                                                                           false, i18n("Rollup"));
01046                                           hb->addWidget( button[BtnRollup] );
01047                                           connect( button[BtnRollup], SIGNAL(clicked()),
01048                                                          this, SLOT(toggleShade()));
01049                                    }
01050                                    break;
01051 
01052                             case 'd':
01053                                    // Make depth == on all desktops
01054                                    if ( validPixmaps(depthPix) && !button[BtnDepth] )
01055                                    {
01056                                           button[BtnDepth] = new IceWMButton(this, "on_all_desktops",
01057                                                         &depthPix, true, isOnAllDesktops()?i18n("Not on all desktops"):i18n("On all desktops"));
01058                                           button[BtnDepth]->turnOn( isOnAllDesktops() );
01059                                           hb->addWidget( button[BtnDepth] );
01060                                           connect( button[BtnDepth], SIGNAL(clicked()),
01061                                                          this, SLOT(toggleOnAllDesktops()));
01062                                    }
01063                                    break;
01064                      }
01065               }
01066 }
01067 
01068 
01069 // Adds a pixmap to the titlebar layout via the use of a nice QSpacerItem
01070 QSpacerItem* IceWMClient::addPixmapSpacer( QPixmap* p[], QSizePolicy::SizeType s, int hsize )
01071 {
01072        QSpacerItem* sp;
01073 
01074        // Add a null spacer for zero image
01075        if ( p && p[Active] )
01076        {
01077               int w = (hsize == -1) ? p[Active]->width(): hsize;
01078               sp = new QSpacerItem( w, titleBarHeight, s, QSizePolicy::Fixed );
01079        }
01080        else
01081               sp = new QSpacerItem(0, 0, QSizePolicy::Maximum, QSizePolicy::Fixed );
01082 
01083        hb->addItem( sp );
01084        return sp;
01085 }
01086 
01087 
01088 void IceWMClient::renderMenuIcons()
01089 {
01090        QPixmap miniIcon( icon().pixmap( QIcon::Small, QIcon::Normal) );
01091 
01092        if (!miniIcon.isNull())
01093                 for(int i = 0; i < 2; i++) {
01094                        if ( menuButtonWithIconPix[i] )
01095                               delete menuButtonWithIconPix[i];
01096 
01097                        // Try to be more friendly to dodgy themes - icewm assumes a square menu button
01098                        // but some pixmap themes don't provide a square menu button.
01099                        int w = titleBarHeight;
01100                        if (validPixmaps(menuButtonPix) && menuButtonPix[i]->width() > w)
01101                                w = menuButtonPix[i]->width();
01102                        menuButtonWithIconPix[i] = new QPixmap(w, 2*titleBarHeight );
01103                        if (themeLook != WIN95)
01104                                menuButtonWithIconPix[i] -> fill((i==0) ? *colorInActiveButton : *colorActiveButton);
01105                        else
01106                                menuButtonWithIconPix[i] -> fill((i==0) ? *colorInActiveTitleBar : *colorActiveTitleBar);
01107                        QPainter pnt( menuButtonWithIconPix[i] );
01108 
01109                        if (themeLook > 0 && themeLook != WIN95 && themeLook != WARP4) {
01110                                draw3DRect(pnt, *colorActiveButton, 0, 0,
01111                                           w-1, titleBarHeight-1, true);
01112                                draw3DRect(pnt, *colorActiveButton, 0, titleBarHeight,
01113                                           w-1, 2*titleBarHeight-1, false);
01114                        }
01115                        if (validPixmaps(menuButtonPix)) {
01116                                pnt.drawPixmap(0, 0, *menuButtonPix[i]);
01117                        }
01118                        int offset = (titleBarHeight - miniIcon.width())/2;
01119                        if (offset<0) offset = 0;
01120                        // Paint the mini icon over the menu pixmap in the centre
01121                        pnt.drawPixmap( offset, offset, miniIcon );
01122                        pnt.drawPixmap( offset, titleBarHeight+offset, miniIcon );
01123                        pnt.end();
01124                 }
01125 
01126 }
01127 
01128 
01129 void IceWMClient::slotMaximize()
01130 {
01131        maximize(button[BtnMaximize]->last_button);
01132 }
01133 
01134 void IceWMClient::toggleShade()
01135 {
01136         setShade(!isSetShade());
01137 }
01138 
01139 int IceWMClient::titleTextWidth( const QString& s )
01140 {
01141        // Obtains the actual width of the text, using the titlebar font
01142        QSize size;
01143        QFontMetrics fm( options()->font(true) );
01144        size = fm.size( 0, s );
01145        return size.width();
01146 }
01147 
01148 
01149 void IceWMClient::borders(int& left, int& right, int& top, int& bottom) const
01150 {
01151        left = borderSizeX;
01152        right = borderSizeX;
01153        if( titleBarOnTop ) {
01154               top = titleBarHeight + borderSizeY;
01155               bottom = borderSizeY;
01156        } else {
01157               top = borderSizeY;
01158               bottom = titleBarHeight + borderSizeY;
01159        }
01160 }
01161 
01162 
01163 void IceWMClient::resize( const QSize& s )
01164 {
01165        widget()->resize( s );
01166 }
01167 
01168 
01169 QSize IceWMClient::minimumSize() const
01170 {
01171        return widget()->minimumSize();
01172 }
01173 
01174 
01175 // Repaint nicely upon resize to minimise flicker.
01176 void IceWMClient::resizeEvent( QResizeEvent* e )
01177 {
01178        calcHiddenButtons();
01179 
01180        if (widget()->isVisibleToTLW())
01181        {
01182                widget()->update(widget()->rect());
01183               int dx = 0;
01184               int dy = 0;
01185 
01186               if ( e->oldSize().width() != widget()->width() )
01187                      dx = 32 + qAbs( e->oldSize().width() -  width() );
01188 
01189               if ( e->oldSize().height() != height() )
01190                      dy = 8 + qAbs( e->oldSize().height() -  height() );
01191 
01192               if ( dy )
01193                      widget()->update( 0, height() - dy + 1, width(), dy );
01194 
01195               if ( dx )
01196               {
01197                      widget()->update( width() - dx + 1, 0, dx, height() );
01198                      widget()->update( QRect( QPoint(4,4), titlebar->geometry().bottomLeft() - QPoint(1,0) ) );
01199                      widget()->update( QRect( titlebar->geometry().topRight(), QPoint( width() - 4, titlebar->geometry().bottom() ) ) );
01200                      widget()->repaint(titlebar->geometry(), false);
01201               }
01202        }
01203 }
01204 
01205 
01206 // IceWM Paint magic goes here.
01207 void IceWMClient::paintEvent( QPaintEvent* )
01208 {
01209        QColor colorTitleShadow;
01210        QColor colorTitle;
01211        QColor c1;
01212        int rx, rw;
01213 
01214        QPainter p( widget() );
01215        int act = isActive() ? Active: InActive;
01216 
01217        // Determine titlebar shadow colors
01218        bool useShadow = isActive() ? useActiveShadow : useInActiveShadow;
01219        if ( useShadow )
01220               colorTitleShadow = isActive() ? *colorActiveTitleTextShadow : *colorInActiveTitleTextShadow;
01221 
01222        if ( themeTitleTextColors )
01223               colorTitle = isActive()? *colorActiveTitleBarText : *colorInActiveTitleBarText;
01224        else
01225               colorTitle = options()->color(ColorFont, isActive());
01226 
01227        // Obtain widget bounds.
01228        QRect r;
01229        r = widget()->rect();
01230        int fillWidth  = r.width()  - 2*borderSizeX;
01231        int y = r.y();
01232        int x = r.x();
01233        int w = r.width();
01234        int h = r.height();
01235 
01236        // Do we have pixmaps for the frame?
01237        if (validframe)
01238        {
01239               // Top corner
01240               p.drawPixmap(0, 0, *frameTL[ act ], 0, 0, cornerSizeX, borderSizeY);
01241               p.drawPixmap(0, 0, *frameTL[ act ], 0, 0, borderSizeX, cornerSizeY);
01242 
01243               // Top right corner
01244               p.drawPixmap(w-cornerSizeX, 0, *frameTR[ act ],
01245                                     frameTR[act]->width()-cornerSizeX, 0, cornerSizeX, borderSizeY);
01246               p.drawPixmap(w-borderSizeX, 0, *frameTR[ act ],
01247                                     frameTR[act]->width()-borderSizeX, 0, borderSizeX, cornerSizeY);
01248 
01249               // Top bar
01250               p.drawTiledPixmap( cornerSizeX, 0, w-(2*cornerSizeX), borderSizeY, *frameT[ act ] );
01251 
01252               // Left bar
01253               p.drawTiledPixmap( 0, cornerSizeY, borderSizeX, h-(2*cornerSizeY), *frameL[ act ] );
01254 
01255               // Right bar
01256               p.drawTiledPixmap( w-borderSizeX, cornerSizeY, borderSizeX, h-(2*cornerSizeY),
01257                                              *frameR[ act ],frameR[act]->width()-borderSizeX );
01258 
01259               // Bottom left corner
01260               p.drawPixmap(0, h-borderSizeY, *frameBL[ act ],
01261                                     0, frameBL[act]->height()-borderSizeY, cornerSizeX, borderSizeY);
01262               p.drawPixmap(0, h-cornerSizeY, *frameBL[ act ],
01263                                     0, frameBL[act]->height()-cornerSizeY, borderSizeX, cornerSizeY);
01264 
01265               // Bottom right corner
01266               p.drawPixmap(w-cornerSizeX, h-borderSizeY, *frameBR[ act ],
01267                                     frameBR[act]->width()-cornerSizeX, frameBR[act]->height()-borderSizeY,
01268                                     cornerSizeX, borderSizeY);
01269 
01270               p.drawPixmap(w-borderSizeX, h-cornerSizeY, *frameBR[ act ],
01271                                     frameBR[act]->width()-borderSizeX, frameBR[act]->height()-cornerSizeY,
01272                                     borderSizeX, cornerSizeY);
01273 
01274               // Bottom bar
01275               p.drawTiledPixmap(cornerSizeX, h-borderSizeY, w-(2*cornerSizeX), borderSizeY,
01276                                             *frameB[ act ], 0, frameB[ act ]->height()-borderSizeY );
01277 
01278               // Ensure uncovered areas during shading are painted with something
01279               p.setPen( *colorInActiveBorder );
01280               if (titleBarOnTop)
01281                p.drawLine( x+borderSizeX, y+h-borderSizeY-1,
01282                                           x+w-borderSizeX-1, y+h-borderSizeY-1);
01283               else
01284                p.drawLine( x+borderSizeX, y+borderSizeY,
01285                                           x+w-borderSizeX-1, y+borderSizeY);
01286 
01287        } else
01288        {
01289               // Draw a stock IceWM frame instead of a pixmap frame
01290               c1 = isActive() ? *colorActiveBorder : *colorInActiveBorder;
01291 
01292               if (themeLook == WARP3 || themeLook == MOTIF) {
01293                      draw3DRect(p, c1, x, y, w-1, h-1, true);
01294                      p.setPen(c1);
01295                      p.drawRect(x+1, y+1, w-2, h-2);
01296               } else {
01297                      p.setPen( c1.light(135) );
01298                      p.drawLine(0, 0, w-2, 0);
01299                      p.drawLine(0, 0, 0, h-2);
01300 
01301                      p.setPen(c1);
01302                      p.drawLine(1, 1, w-3, 1);
01303                      p.drawLine(1, 1, 1, h-3);
01304 
01305                      p.setPen( c1.dark(140) );
01306                      p.drawLine(1, h-2, w-2, h-2);
01307                      p.drawLine(w-2, 1, w-2, h-2);
01308 
01309                      p.setPen( Qt::black );
01310                      p.drawLine(w-1, 0, w-1, h-1);
01311                      p.drawLine(0, h-1, w-1, h-1);
01312               }
01313 
01314 
01315               // Fill frame border if required
01316               if (borderSizeX > 2)
01317               {
01318                      // Fill Vertical sizes
01319                      p.fillRect( x+2, y+2, borderSizeX-2, h-4, c1);
01320                      p.fillRect( w-borderSizeX, y+2, borderSizeX-2, h-4, c1);
01321               }
01322 
01323               if (borderSizeY > 2)
01324               {
01325                      // Fill horizontal frame parts
01326                      p.fillRect( x+borderSizeX, y+2, fillWidth, borderSizeY-2, c1);
01327                      p.fillRect( x+borderSizeX, h-borderSizeY, fillWidth, borderSizeY-2, c1);
01328               }
01329 
01330               if (themeLook == WARP3 || themeLook == MOTIF) {
01331                      draw3DRect(p, c1, x+borderSizeX-1, y+borderSizeY-1,
01332                                 w+1-2*borderSizeX, h+1-2*borderSizeY, false);
01333               }
01334               if (themeLook == MOTIF && !isShade()) {
01335                      int xext = titleBarHeight + borderSizeX - 1;
01336                      int yext = titleBarHeight + borderSizeY - 1;
01337 
01338                      int xext2 = w-xext-2;
01339                      int yext2 = h-yext-2;
01340 
01341                      int bX = w - borderSizeX-1;
01342                      int bY = h - borderSizeY-1;
01343 
01344                      p.setPen( c1.dark(140) );
01345                      p.drawLine(xext, 0, xext, borderSizeY);
01346                      p.drawLine(xext2, 0, xext2, borderSizeY);
01347                      p.drawLine(xext, bY, xext, h-1);
01348                      p.drawLine(xext2, bY, xext2, h-1);
01349 
01350                      p.drawLine(0, yext, borderSizeX, yext);
01351                      p.drawLine(0, yext2, borderSizeX, yext2);
01352                      p.drawLine(bX, yext, w-1, yext);
01353                      p.drawLine(bX, yext2, w-1, yext2);
01354 
01355                      p.setPen( c1.light(135) );
01356 
01357                      ++xext; ++yext; ++xext2; ++yext2;
01358 
01359                      p.drawLine(xext, 0, xext, borderSizeY);
01360                      p.drawLine(xext2, 0, xext2, borderSizeY);
01361                      p.drawLine(xext, bY, xext, h-1);
01362                      p.drawLine(xext2, bY, xext2, h-1);
01363 
01364                      p.drawLine(0, yext, borderSizeX, yext);
01365                      p.drawLine(0, yext2, borderSizeX, yext2);
01366                      p.drawLine(bX, yext, w-1, yext);
01367                      p.drawLine(bX, yext2, w-1, yext2);
01368 
01369 
01370               }
01371 
01372               // Ensure uncovered areas during shading are painted with something
01373               p.setPen( *colorInActiveBorder );
01374               if (titleBarOnTop)
01375                p.drawLine( x+borderSizeX, y+h-borderSizeY-1,
01376                                           x+w-borderSizeX-1, y+h-borderSizeY-1);
01377               else
01378                p.drawLine( x+borderSizeX, y+borderSizeY,
01379                                           x+w-borderSizeX-1, y+borderSizeY);
01380        }
01381 
01382        // Draw the title elements, if we need to draw a titlebar.
01383        if (titleBarHeight > 0)
01384        {
01385               QPixmap* titleBuffer = new QPixmap( width()-(2*borderSizeX), titleBarHeight );
01386               QPainter p2( titleBuffer, this );
01387               titleBuffer->fill( act ? *colorActiveTitleBar : *colorInActiveTitleBar );
01388 
01389               r = titleSpacerJ->geometry();
01390               if (!r.isEmpty() && titleJ[ act ])
01391                      p2.drawPixmap( r.x()-borderSizeX, 0, *titleJ[ act ]);
01392 
01393               r = titleSpacerL->geometry();
01394               if (!r.isEmpty() && titleL[ act ])
01395                      p2.drawPixmap( r.x()-borderSizeX, 0, *titleL[ act ]);
01396 
01397               r = titleSpacerS->geometry();
01398               if (!r.isEmpty() && titleS[ act ])
01399                      p2.drawTiledPixmap( r.x()-borderSizeX, 0, r.width(), titleBarHeight, *titleS[ act ]);
01400 
01401               r = titleSpacerP->geometry();
01402               if (!r.isEmpty() && titleP[ act ])
01403                      p2.drawPixmap( r.x()-borderSizeX, 0, *titleP[ act ]);
01404 
01405               r = titlebar->geometry();
01406               if (!r.isEmpty() && titleT[ act ] )
01407                      p2.drawTiledPixmap( r.x()-borderSizeX, 0, r.width(), titleBarHeight, *titleT[ act ]);
01408 
01409               r = titleSpacerM->geometry();
01410               if (!r.isEmpty() && titleM[ act ])
01411                      p2.drawPixmap( r.x()-borderSizeX, 0, *titleM[ act ], 0, 0, r.width(), r.height());
01412 
01413               r = titleSpacerB->geometry();
01414               if (!r.isEmpty() && titleB[ act ])
01415                      p2.drawTiledPixmap( r.x()-borderSizeX, 0, r.width(), titleBarHeight, *titleB[ act ]);
01416 
01417               r = titleSpacerR->geometry();
01418               if (!r.isEmpty() && titleR[ act ])
01419                      p2.drawPixmap( r.x()-borderSizeX, 0, *titleR[ act ], 0, 0, r.width(), r.height());
01420 
01421               r = titleSpacerQ->geometry();
01422               if (!r.isEmpty() && titleQ[ act ])
01423                      p2.drawPixmap( r.x()-borderSizeX, 0, *titleQ[ act ], 0, 0, r.width(), r.height());
01424 
01425               p2.setFont( options()->font(true) );
01426 
01427               // Pre-compute as much as possible
01428               r = titlebar->geometry();
01429               rx = r.x() - borderSizeX;
01430               rw = width()-(2*borderSizeX)-r.x();
01431 
01432               // Paint a title text shadow if requested
01433               if ( useShadow )
01434               {
01435                      p2.setPen( colorTitleShadow );
01436                      p2.drawText(rx+1, 1, rw, titleBarHeight, AlignLeft|AlignVCenter, caption());
01437               }
01438 
01439               // Draw the title text
01440               p2.setPen( colorTitle );
01441               p2.drawText(rx, 0, rw, titleBarHeight, AlignLeft|AlignVCenter, caption());
01442               p2.end();
01443 
01444               bitBlt( widget(), borderSizeX, hb->geometry().y(), titleBuffer );
01445 
01446               delete titleBuffer;
01447        }
01448 }
01449 
01450 
01451 void IceWMClient::showEvent(QShowEvent *ev)
01452 {
01453        calcHiddenButtons();
01454 
01455        titlebar->changeSize( titleTextWidth(caption()), titleBarHeight,
01456                                             QSizePolicy::Preferred, QSizePolicy::Fixed );
01457        grid->activate();
01458        widget()->show();
01459        IceWMClient::showEvent(ev);
01460 }
01461 
01462 
01463 void IceWMClient::mouseDoubleClickEvent( QMouseEvent * e )
01464 {
01465        if( e->button() != Qt::LeftButton )
01466               return;
01467 
01468        QRect r;
01469        if (titleBarOnTop)
01470               r.setRect( borderSizeX, borderSizeY, width()-(2*borderSizeX), titleBarHeight);
01471        else
01472               r.setRect( borderSizeX, height()-borderSizeY-titleBarHeight,
01473                                width()-(2*borderSizeX), titleBarHeight);
01474 
01475        if (r.contains( e->pos() ) )
01476               titlebarDblClickOperation();
01477 
01478 }
01479 
01480 
01481 // Called via Client class when the miniIcon() changes
01482 void IceWMClient::iconChange()
01483 {
01484        if (validPixmaps(menuButtonPix) && showMenuButtonIcon)
01485        {
01486               if (button[BtnSysMenu])
01487               {
01488                      renderMenuIcons();
01489                      button[BtnSysMenu]->usePixmap( &menuButtonWithIconPix );
01490                      if (button[BtnSysMenu]->isVisible())
01491                             button[BtnSysMenu]->repaint(false);
01492               }
01493        }
01494 }
01495 
01496 
01497 void IceWMClient::desktopChange()
01498 {
01499        if (button[BtnDepth])
01500        {
01501               button[BtnDepth]->turnOn( isOnAllDesktops() );
01502               button[BtnDepth]->repaint(false);
01503               button[BtnDepth]->setTipText(isOnAllDesktops() ? i18n("Not on all desktops") : i18n("On all desktops"));
01504        }
01505 }
01506 
01507 
01508 // Please don't modify the following unless you want layout problems
01509 void IceWMClient::captionChange()
01510 {
01511        QRect r( 0, borderSizeY, geometry().width(), titleBarHeight);
01512 
01513        titlebar->changeSize( titleTextWidth( caption() ), titleBarHeight,
01514                                             QSizePolicy::Preferred, QSizePolicy::Fixed );
01515        titlebar->invalidate();
01516     grid->activate();
01517     widget()->repaint( r, false );
01518 }
01519 
01520 
01521 void IceWMClient::maximizeChange()
01522 {
01523        // Change the button pixmap to restore if required
01524        if (button[BtnMaximize] && validPixmaps(restorePix))
01525        {
01526               button[BtnMaximize]->usePixmap( (maximizeMode()==MaximizeFull) ? &restorePix : &maximizePix );
01527               button[BtnMaximize]->setTipText( (maximizeMode()==MaximizeFull) ? i18n("Restore") : i18n("Maximize"));
01528        }
01529 }
01530 
01531 
01532 void IceWMClient::shadeChange()
01533 {
01534        // Change the button pixmap to rolldown if required
01535        if (button[BtnRollup] && validPixmaps(rolldownPix))
01536        {
01537               button[BtnRollup]->usePixmap( isSetShade() ? &rolldownPix : &rollupPix );
01538               button[BtnRollup]->setTipText( isSetShade() ? i18n("Rolldown") : i18n("Rollup"));
01539        }
01540 
01541 }
01542 
01543 
01544 void IceWMClient::activeChange()
01545 {
01546        widget()->repaint(false);
01547 
01548     // Reset the button pixmaps.
01549        for(int i= IceWMClient::BtnSysMenu; i < IceWMClient::BtnCount; i++)
01550               if(button[i])
01551                      button[i]->repaint( false );
01552 }
01553 
01554 
01555 // This does the showing / hiding button magic
01556 // for variable positioned buttons.
01557 void IceWMClient::calcHiddenButtons()
01558 {
01559        const int minwidth = 220; // Minimum width where all buttons are shown
01560        const int btn_width = 20; // Average width
01561 
01562        // Show/Hide buttons in this order - OnAllDesktops, Maximize, Menu, Rollup, Minimize, Close.
01563        IceWMButton* btnArray[] = { button[BtnDepth], button[BtnMaximize], button[BtnSysMenu],
01564                                                         button[BtnRollup], button[BtnMinimize], button[BtnClose] };
01565 
01566        int current_width = width();
01567        int count = 0;
01568        int i;
01569 
01570        // Find out how many buttons we have to hide.
01571        while (current_width < minwidth)
01572        {
01573               current_width += btn_width;
01574               count++;
01575        }
01576 
01577        // Bound the number of buttons to hide
01578        if (count > 6) count = 6;
01579 
01580        // Hide the required buttons...
01581        for(i = 0; i < count; i++)
01582        {
01583               if (btnArray[i] && btnArray[i]->isVisible() )
01584                      btnArray[i]->hide();
01585        }
01586 
01587        // Show the rest of the buttons...
01588        for(i = count; i < 6; i++)
01589        {
01590               if (btnArray[i] && (!btnArray[i]->isVisible()) )
01591                      btnArray[i]->show();
01592        }
01593 }
01594 
01595 
01596 // Mouse position code modified from that in workspace.cpp
01597 IceWMClient::Position IceWMClient::mousePosition( const QPoint& p ) const
01598 {
01599     int rangeX = cornerSizeX;
01600     int rangeY = cornerSizeY;
01601     int borderX = borderSizeX;
01602     int borderY = borderSizeY;
01603 
01604     Position m = PositionCenter;
01605 
01606     if ((p.x()  > borderX && p.x() < width()  - borderX) &&
01607            ( p.y() > borderY && p.y() < height() - borderY))
01608        return PositionCenter;
01609 
01610     if ( p.y() <= rangeY && p.x() <= rangeX)
01611               m = PositionTopLeft;
01612     else if ( p.y() >= height()-rangeY && p.x() >= width()-rangeX)
01613               m = PositionBottomRight;
01614     else if ( p.y() >= height()-rangeX && p.x() <= rangeX)
01615               m = PositionBottomLeft;
01616     else if ( p.y() <= rangeY && p.x() >= width()-rangeX)
01617               m = PositionTopRight;
01618     else if ( p.y() <= borderY )
01619               m = PositionTop;
01620     else if ( p.y() >= height()-borderY )
01621               m = PositionBottom;
01622     else if ( p.x() <= borderX )
01623               m = PositionLeft;
01624     else if ( p.x() >= width()-borderX )
01625        m = PositionRight;
01626     else
01627               m = PositionCenter;
01628        return m;
01629 }
01630 
01631 
01632 void IceWMClient::menuButtonPressed()
01633 {
01634        static QTime t;
01635        static IceWMClient* lastClient = NULL;
01636        bool dbl = ( lastClient == this && t.elapsed() <= QApplication::doubleClickInterval());
01637        lastClient = this;
01638        t.start();
01639 
01640        if (dbl)
01641        {
01642               m_closing = true;
01643               return;
01644     }
01645 
01646        QPoint menuPoint ( button[BtnSysMenu]->rect().bottomLeft() );
01647 
01648        // Move to right if menu on rhs, otherwise on left
01649        // and make this depend on windowWrapper(), not button.
01650 
01651         KDecorationFactory* f = factory();
01652        showWindowMenu( button[BtnSysMenu]->mapToGlobal(menuPoint) );
01653         if( !f->exists( this )) // 'this' was deleted
01654             return;
01655        button[BtnSysMenu]->setDown(false);
01656 }
01657 
01658 void IceWMClient::menuButtonReleased()
01659 {
01660        if (m_closing)
01661               closeWindow();
01662 }
01663 
01664 bool IceWMClient::eventFilter( QObject* o, QEvent* e )
01665 {
01666        if( o != widget())
01667        return false;
01668        switch( e->type())
01669        {
01670        case QEvent::Resize:
01671               resizeEvent(static_cast< QResizeEvent* >( e ) );
01672               return true;
01673        case QEvent::Paint:
01674               paintEvent(static_cast< QPaintEvent* >( e ) );
01675               return true;
01676        case QEvent::MouseButtonDblClick:
01677               mouseDoubleClickEvent(static_cast< QMouseEvent* >( e ) );
01678               return true;
01679        case QEvent::MouseButtonPress:
01680               processMousePressEvent(static_cast< QMouseEvent* >( e ) );
01681               return true;
01682        default:
01683               break;
01684        }
01685        return false;
01686 }
01687 
01688 }
01689 
01690 extern "C"
01691 {
01692        KDE_EXPORT KDecorationFactory *create_factory()
01693        {
01694               IceWM::clientHandler = new IceWM::ThemeHandler;
01695               return IceWM::clientHandler;
01696        }
01697 }
01698 
01699 
01700 #include "icewm.moc"
01701 
01702 // vim: ts=4