diff options
Diffstat (limited to 'twin-styles/icewm/icewm.cpp')
-rw-r--r-- | twin-styles/icewm/icewm.cpp | 1703 |
1 files changed, 1703 insertions, 0 deletions
diff --git a/twin-styles/icewm/icewm.cpp b/twin-styles/icewm/icewm.cpp new file mode 100644 index 00000000..4b9a064b --- /dev/null +++ b/twin-styles/icewm/icewm.cpp @@ -0,0 +1,1703 @@ +/* + $Id$ + + Gallium-IceWM themeable KWin client + + Copyright 2001 + Karol Szwed <[email protected]> + http://gallium.n3.net/ + + 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. + + ----------------------------------------------------------------------------- + This client loads most icewm 1.0.X pixmap themes, without taking into account + specific font settings for clients, or coloured mouse cursors. Titlebar + fonts can be changed via the kde control center. Bi-colour mouse cursors + may be added in future if requested by users, as well as theme font support. + Any styles using inbuilt icewm titlebar drawing without using pixmaps (e.g. + Warp4, win95 etc.) are not fully supported, and may cause drawing errors, + as these themes use in-built icewm drawing mechanisms. + + When a pixmap theme is not present (or a corrupt one is present) then very + plain title decorations are painted instead, so that users don't see + non-painted window areas where possible ;) + + At a later date, frame shaping may be added if really requested, and an + update to support the latest icewm 1.1.X theme format may be made. + +*/ + +#include <kconfig.h> +#include <kstandarddirs.h> +#include <kglobal.h> +#include <klocale.h> +#include <kdrawutil.h> +#include <tqapplication.h> +#include <tqlabel.h> +#include <tqdrawutil.h> +#include <tqdatetime.h> +#include <tqbitmap.h> +#include <tqcursor.h> +#include <tqstring.h> +#include <tqtooltip.h> +#include <tqregexp.h> +#include "icewm.h" + +namespace IceWM { + +//////////////////////////////////////////////////////////////////////////////////////////// +// Here's the global pixmap stuff - as memory efficient as it can be :) +//////////////////////////////////////////////////////////////////////////////////////////// + +// IceWM frame pixmaps +TQPixmap* frameTL[] = {NULL, NULL}; +TQPixmap* frameT [] = {NULL, NULL}; +TQPixmap* frameTR[] = {NULL, NULL}; +TQPixmap* frameL [] = {NULL, NULL}; +TQPixmap* frameR [] = {NULL, NULL}; +TQPixmap* frameBL[] = {NULL, NULL}; +TQPixmap* frameB [] = {NULL, NULL}; +TQPixmap* frameBR[] = {NULL, NULL}; + +// Button pixmaps +TQPixmap* closePix[] = {NULL, NULL}; +TQPixmap* depthPix[] = {NULL, NULL}; +TQPixmap* maximizePix[] = {NULL, NULL}; +TQPixmap* minimizePix[] = {NULL, NULL}; +TQPixmap* restorePix[] = {NULL, NULL}; +TQPixmap* hidePix[] = {NULL, NULL}; +TQPixmap* rollupPix[] = {NULL, NULL}; +TQPixmap* rolldownPix[] = {NULL, NULL}; +TQPixmap* menuButtonPix[] = {NULL, NULL}; + +// Titlebar pixmaps +TQPixmap* titleJ[] = {NULL, NULL}; +TQPixmap* titleL[] = {NULL, NULL}; +TQPixmap* titleS[] = {NULL, NULL}; +TQPixmap* titleP[] = {NULL, NULL}; +TQPixmap* titleT[] = {NULL, NULL}; +TQPixmap* titleM[] = {NULL, NULL}; +TQPixmap* titleB[] = {NULL, NULL}; +TQPixmap* titleR[] = {NULL, NULL}; +TQPixmap* titleQ[] = {NULL, NULL}; + +ThemeHandler* clientHandler; + +TQString* titleButtonsLeft; +TQString* titleButtonsRight; + +TQColor* colorActiveBorder; +TQColor* colorInActiveBorder; +TQColor* colorActiveButton; +TQColor* colorInActiveButton; +TQColor* colorActiveTitleBarText; +TQColor* colorInActiveTitleBarText; +TQColor* colorActiveTitleBar; +TQColor* colorInActiveTitleBar; +TQColor* colorActiveTitleTextShadow; +TQColor* colorInActiveTitleTextShadow; + +int cornerSizeX; +int cornerSizeY; +int titleBarHeight; +int borderSizeX; +int borderSizeY; + +bool validframe = false; +bool useActiveShadow = false; +bool useInActiveShadow = false; + +// KControl Settings - Read from twinicewmrc config file or icewm theme +bool themeTitleTextColors = true; // Allow theme to set colors. + // kcontrol will have no effect + +bool titleBarOnTop = true; // Titlebars can be below windows too :) +bool showMenuButtonIcon = false; // Draw a mini icon over the menu pixmap. +bool customButtonPositions = false; // Let the theme dictate the btn pos. +bool titleBarCentered = true; + +enum styles {OTHER, WARP3, WARP4, MOTIF, WIN95, NICE} themeLook; + +//////////////////////////////////////////////////////////////////////////////////////////// +// General utility functions +//////////////////////////////////////////////////////////////////////////////////////////// + +// Returns true if both active and inactive pixmaps are valid, and not null +bool validPixmaps( TQPixmap* p[] ) +{ + return ( p[Active] && ( !p[Active]->isNull() ) && + p[InActive] && ( !p[InActive]->isNull() ) ); +} + + +//////////////////////////////////////////////////////////////////////////////////////////// +// ThemeHandler class +// +// This class allows us to free dynamic memory upon being reset, or unloaded +// from twin, so we don't leak big images everywhere, and handles the theme +// initialisation / destruction in general. +//////////////////////////////////////////////////////////////////////////////////////////// + +ThemeHandler::ThemeHandler() +{ + initialized = false; + + // Prevent having globals objects (use pointers to objects) + titleButtonsLeft = new TQString(); + titleButtonsRight = new TQString(); + + colorActiveBorder = new TQColor(); + colorInActiveBorder = new TQColor(); + colorActiveButton = new TQColor(); + colorInActiveButton = new TQColor(); + colorActiveTitleBarText = new TQColor(); + colorInActiveTitleBarText = new TQColor(); + colorActiveTitleBar = new TQColor(); + colorInActiveTitleBar = new TQColor(); + colorActiveTitleTextShadow = new TQColor(); + colorInActiveTitleTextShadow = new TQColor(); + + // Initialize + readConfig(); + initTheme(); + validframe = isFrameValid(); + initialized = true; +} + + +ThemeHandler::~ThemeHandler() +{ + if (initialized) + freePixmaps(); + + delete colorInActiveTitleTextShadow; + delete colorActiveTitleTextShadow; + delete colorInActiveBorder; + delete colorActiveTitleBarText; + delete colorInActiveTitleBarText; + delete colorActiveTitleBar; + delete colorInActiveTitleBar; + delete colorActiveBorder; + delete colorActiveButton; + delete colorInActiveButton; + + delete titleButtonsRight; + delete titleButtonsLeft; +} + + +KDecoration* ThemeHandler::createDecoration( KDecorationBridge* bridge ) +{ + return new IceWMClient( bridge, this ); +} + + +// Converts KDE style button strings to icewm style button strings +void ThemeHandler::convertButtons( TQString& s ) +{ + s.replace( TQRegExp("_"), ""); // Spacer (ignored) + s.replace( TQRegExp("H"), ""); // Help (ignored) + s.replace( TQRegExp("M"), "s"); // Sysmenu + s.replace( TQRegExp("S"), "d"); // Sticky/OnAllDesktops + s.replace( TQRegExp("I"), "i"); // Minimize + s.replace( TQRegExp("A"), "m"); // Maximize + s.replace( TQRegExp("X"), "x"); // Close +} + + +// Reverses all characters in a TQString +TQString ThemeHandler::reverseString( TQString s ) +{ + if (s.length() <= 1) + return s; + + TQString tmpStr; + for(int i = s.length()-1; i >= 0; i--) + { + tmpStr += s[(unsigned int)i]; + } + + return tmpStr; +} + + +// This function reads the twinicewmrc config file +void ThemeHandler::readConfig() +{ + KConfig conf("twinicewmrc"); + conf.setGroup("General"); + themeName = conf.readEntry("CurrentTheme"); + themeTitleTextColors = conf.readBoolEntry("ThemeTitleTextColors", true); + showMenuButtonIcon = conf.readBoolEntry("ShowMenuButtonIcon", false); + titleBarOnTop = conf.readBoolEntry("TitleBarOnTop", true); + + customButtonPositions = KDecoration::options()->customButtonPositions(); + if (customButtonPositions) + { + *titleButtonsLeft = KDecoration::options()->titleButtonsLeft(); + *titleButtonsRight = KDecoration::options()->titleButtonsRight(); + + // Convert KDE to icewm style buttons + convertButtons( *titleButtonsLeft ); + convertButtons( *titleButtonsRight ); + } + + // Provide a default theme alias + if (themeName == "default") + themeName = ""; +} + + +// This creates the dynamic pixmaps upon loading the style +// into the pixmap buffers above, and configures the dimensioning stuff. +void ThemeHandler::initTheme() +{ + // Add a slash if required + if ( !themeName.isEmpty() ) + themeName += "/"; + + // We use kconfig to read icewm config files... + // this is easy since icewm uses key=value pairs! + KConfig config( locate("data", TQString("twin/icewm-themes/") + + themeName + TQString("default.theme")) ); + + // Load specifics, or use IceWM defaults instead. + borderSizeX = config.readNumEntry("BorderSizeX", 6); + borderSizeY = config.readNumEntry("BorderSizeY", 6); + cornerSizeX = config.readNumEntry("CornerSizeX", 24); + cornerSizeY = config.readNumEntry("CornerSizeY", 24); + titleBarCentered = (bool) config.readNumEntry("TitleBarCentered", 0); + + // Check if readConfig() hasn't overridden this value... + if (!showMenuButtonIcon) + showMenuButtonIcon = (bool) config.readNumEntry("ShowMenuButtonIcon", 0); + titleBarHeight = config.readNumEntry("TitleBarHeight", 20); + + if (!customButtonPositions) + { + // Read in the button configuration, stripping any quotes + // Ignore on all desktops 'd' on the left buttons + // (some themes look bad with it on by default) + *titleButtonsLeft = config.readEntry("TitleButtonsLeft", "s"); + *titleButtonsLeft = titleButtonsLeft->replace( TQRegExp(TQString("\"")), ""); + *titleButtonsRight = config.readEntry("TitleButtonsRight", "xmir"); + *titleButtonsRight = titleButtonsRight->replace( TQRegExp(TQString("\"")), ""); + + // I have no idea why the right side buttons in icewm are reversed + *titleButtonsRight = reverseString( *titleButtonsRight ); + } + + // Read the default border and text colours from the config file + // And use IceWM defaults if not found + TQString s; + + s = config.readEntry("Look", "other"); + if (s=="motif") themeLook = MOTIF; + else if (s=="warp3") themeLook = WARP3; + else if (s=="warp4") themeLook = WARP4; + else if (s=="win95") themeLook = WIN95; + else if (s=="nice") themeLook = NICE; + else themeLook = OTHER; + + s = config.readEntry("ColorActiveBorder", "#C0C0C0"); + *colorActiveBorder = decodeColor( s ); + s = config.readEntry("ColorNormalBorder", "#C0C0C0"); + *colorInActiveBorder = decodeColor( s ); + s = config.readEntry("ColorActiveButton", "#C0C0C0"); + *colorActiveButton = decodeColor( s ); + s = config.readEntry("ColorNormalButton", "#C0C0C0"); + *colorInActiveButton = decodeColor( s ); + + // Use these as a last resort + s = config.readEntry("ColorActiveTitleBar", "#0000A0"); + *colorActiveTitleBar = decodeColor( s ); + s = config.readEntry("ColorNormalTitleBar", "#808080"); + *colorInActiveTitleBar = decodeColor( s ); + + // Read titlebar text colours + s = config.readEntry("ColorActiveTitleBarText", "#FFFFFF"); + *colorActiveTitleBarText = decodeColor( s ); + s = config.readEntry("ColorNormalTitleBarText", "#000000"); + *colorInActiveTitleBarText = decodeColor( s ); + + // Use title text shadows only with theme title text colors + if ( themeTitleTextColors ) + { + s = config.readEntry("ColorActiveTitleBarShadow"); + if (!s.isEmpty()) + { + *colorActiveTitleTextShadow = decodeColor( s ); + useActiveShadow = true; + } else + useActiveShadow = false; + + s = config.readEntry("ColorNormalTitleBarShadow"); + if (!s.isEmpty()) + { + *colorInActiveTitleTextShadow = decodeColor( s ); + useInActiveShadow = true; + } else + useInActiveShadow = false; + } else + { + useActiveShadow = false; + useInActiveShadow = false; + } + + // Stretch pixmaps for speed, where required + setPixmap( titleJ, "title", "J.xpm" ); + setPixmap( titleL, "title", "L.xpm" ); + setPixmap( titleS, "title", "S.xpm", true ); + + setPixmap( titleP, "title", "P.xpm" ); + setPixmap( titleT, "title", "T.xpm", true ); + setPixmap( titleM, "title", "M.xpm" ); + setPixmap( titleB, "title", "B.xpm", true ); + setPixmap( titleR, "title", "R.xpm" ); + setPixmap( titleQ, "title", "Q.xpm" ); + + setPixmapButton( closePix, "close", ".xpm" ); + setPixmapButton( depthPix, "depth", ".xpm" ); + setPixmapButton( maximizePix, "maximize", ".xpm" ); + setPixmapButton( minimizePix, "minimize", ".xpm" ); + setPixmapButton( restorePix, "restore", ".xpm" ); + setPixmapButton( hidePix, "hide", ".xpm" ); + setPixmapButton( rollupPix, "rollup", ".xpm" ); + setPixmapButton( rolldownPix, "rolldown", ".xpm" ); + setPixmapButton( menuButtonPix,"menuButton",".xpm" ); + + // Top + setPixmap( frameTL, "frame", "TL.xpm" ); + setPixmap( frameT, "frame", "T.xpm", true ); + setPixmap( frameTR, "frame", "TR.xpm" ); + + // Sides + setPixmap( frameL, "frame", "L.xpm", true,Qt::Vertical ); + setPixmap( frameR, "frame", "R.xpm", true,Qt::Vertical ); + + // Bottom + setPixmap( frameBL, "frame", "BL.xpm" ); + setPixmap( frameB, "frame", "B.xpm", true ); + setPixmap( frameBR, "frame", "BR.xpm" ); + + // Make sure border sizes are at least reasonable... + if (borderSizeX < 0) + borderSizeX = 0; + if (borderSizeY < 0) + borderSizeY = 0; + // ...and titleBarHeight as well + if (titleBarHeight < 0) + titleBarHeight = 0; + + // This is a work-around for some themes + if (!titleT[Active]) + titleT[Active] = duplicateValidPixmap( Active ); + + if (!titleB[Active]) + titleB[Active] = duplicateValidPixmap( Active ); + + + if (titleL[Active] && !titleL[InActive]) + titleL[InActive] = duplicateValidPixmap( InActive, titleL[Active]->width() ); + + if (titleS[Active] && !titleS[InActive]) + titleS[InActive] = duplicateValidPixmap( InActive, titleS[Active]->width() ); + + if (titleP[Active] && !titleP[InActive]) + titleP[InActive] = duplicateValidPixmap( InActive, titleP[Active]->width() ); + + if (titleT[Active] && !titleT[InActive]) + titleT[InActive] = duplicateValidPixmap( InActive, titleT[Active]->width() ); + + if (titleM[Active] && !titleM[InActive]) + titleM[InActive] = duplicateValidPixmap( InActive, titleM[Active]->width() ); + + if (titleB[Active] && !titleB[InActive]) + titleB[InActive] = duplicateValidPixmap( InActive, titleB[Active]->width() ); + + if (titleR[Active] && !titleR[InActive]) + titleR[InActive] = duplicateValidPixmap( InActive, titleR[Active]->width() ); +} + + +TQPixmap* ThemeHandler::duplicateValidPixmap( bool act, int size ) +{ + TQPixmap* p1 = NULL; + // Use the stretch or title pixmaps instead + if ( titleS[act] ) + p1 = new TQPixmap( *titleS[act] ); + else if ( titleB[act] ) + p1 = new TQPixmap( *titleB[act] ); + else if ( titleT[act] ) + p1 = new TQPixmap( *titleT[act] ); + + // Stretch if required + if ( (size != -1) && p1 && (!p1->isNull()) ) + p1 = stretchPixmap( p1, true, size ); + + return p1; +} + + +// Frees all memory used by pixmaps. +void ThemeHandler::freePixmaps() +{ + freePixmapGroup( frameTL ); + freePixmapGroup( frameT ); + freePixmapGroup( frameTR ); + freePixmapGroup( frameL ); + freePixmapGroup( frameR ); + freePixmapGroup( frameBL ); + freePixmapGroup( frameB ); + freePixmapGroup( frameBR ); + + freePixmapGroup( closePix ); + freePixmapGroup( depthPix ); + freePixmapGroup( maximizePix ); + freePixmapGroup( minimizePix ); + freePixmapGroup( restorePix ); + freePixmapGroup( hidePix ); + freePixmapGroup( rollupPix ); + freePixmapGroup( rolldownPix ); + freePixmapGroup( menuButtonPix ); + + freePixmapGroup( titleJ ); + freePixmapGroup( titleL ); + freePixmapGroup( titleS ); + freePixmapGroup( titleP ); + freePixmapGroup( titleT ); + freePixmapGroup( titleM ); + freePixmapGroup( titleB ); + freePixmapGroup( titleR ); + freePixmapGroup( titleQ ); +} + + +// Frees a dynamic pixmap group from the heap. +void ThemeHandler::freePixmapGroup( TQPixmap* p[] ) +{ + if (p) + { + if (p[Active]) delete p[Active]; + if (p[InActive]) delete p[InActive]; + p[Active] = NULL; + p[InActive] = NULL; + } else + qWarning("twin-icewm: freePixmapGroup - invalid TQPixmap** 'p'\n"); +} + + +// Converts icewm colors #C0C0C0 or rgb:C0/C0/C0 to TQColors +TQColor ThemeHandler::decodeColor( TQString& s ) +{ + // Make rgb:C0/C0/C0, or #C0/C0/C0 -> C0C0C0 + s.replace( TQRegExp("r"), ""); + s.replace( TQRegExp("g"), ""); + s.replace( TQRegExp("b"), ""); + s.replace( TQRegExp("#"), ""); + s.replace( TQRegExp("/"), ""); + s.replace( TQRegExp(":"), ""); + s.replace( TQRegExp("\\"), ""); + s.replace( TQRegExp("\""), ""); + + // Wierd error - return grey + if (s.length() != 6) + return TQColor( 0xC0, 0xC0, 0xC0 ); + + // TQt makes this conversion very easy + return TQColor( TQString("#") + s ); +} + + +// Stretches tiny pixmaps vertically or horizontally, taking into account +// repetition in patterns, so as not to make them mismatched +TQPixmap* ThemeHandler::stretchPixmap( TQPixmap* src, bool stretchHoriz, int stretchSize ) +{ + if (!src) return NULL; + if (src->isNull()) return NULL; + + int s_inc, size; + + // If its the right size already, just return + if (stretchSize == -1) + { + if (stretchHoriz) + s_inc = src->width(); + else + s_inc = src->height(); + + size = s_inc; + if (size >= 100) + return src; + + // Stretch an appropriate amount - taking care of pattern repetition + while( size < 100 ) + size += s_inc; + } else + size = stretchSize; + + TQPixmap* p = new TQPixmap(); + if ( stretchHoriz ) + p->resize( size, src->height() ); + else + p->resize( src->width(), size ); + + TQPainter pnt( p ); + if ( stretchHoriz ) + pnt.drawTiledPixmap( 0, 0, size, src->height(), *src); + else + pnt.drawTiledPixmap( 0, 0, src->width(), size, *src); + pnt.end(); + + delete src; + return p; +} + +static void draw3DRect(TQPainter &pnt, TQColor &col, int x, int y, int w, int h, bool up) { + TQColor light = col.light(135); + TQColor dark = col.dark(140); + pnt.setPen(up ? light : dark); + pnt.drawLine(x, y, x+w, y); + pnt.drawLine(x, y, x, y+h); + pnt.setPen(up ? dark : light); + pnt.drawLine(x, y+h, x+w, y+h); + pnt.drawLine(x+w, y, x+w, y+h); + pnt.setPen(col); + pnt.drawPoint(x+w, y); + pnt.drawPoint(x, y+h); +} + +void ThemeHandler::setPixmapButton( TQPixmap* p[], TQString s1, TQString s2) +{ + if ( p[Active] ) + qWarning("twin-icewm: setPixmap - should be null (1)\n"); + if ( p[InActive] ) + qWarning("twin-icewm: setPixmap - should be null (2)\n"); + + TQString str = locate("appdata", TQString("icewm-themes/") + + themeName + s1 + "A" + s2); + if (str.isEmpty()) + str = locate("appdata", TQString("icewm-themes/") + + themeName + s1 + s2); + + TQPixmap *qp = new TQPixmap(str); + TQColor cActive = themeLook == WIN95 ? *colorActiveTitleBar : *colorActiveButton; + TQColor cInActive = themeLook == WIN95 ? *colorInActiveTitleBar : *colorInActiveButton; + + if (!qp->isNull() && themeLook > 0) { + int w = qp->width(); + if (themeLook > 0 && titleBarHeight > w) w = titleBarHeight; + p[Active] = new TQPixmap(w, 2*titleBarHeight ); + p[Active] -> fill(cActive); + + TQPainter pnt( p[Active] ); + + int offX = (w - qp->width())/2; + int offY = (titleBarHeight - qp->height())/2; + if (offY < 0) offY = 0; + + if (themeLook == WIN95) { + draw3DRect(pnt, *colorActiveButton, offX-1, offY-1, + qp->width()+1, qp->height()+1, true); + draw3DRect(pnt, *colorActiveButton, offX-1, offY-1 + titleBarHeight, + qp->width()+1, qp->height()+1, false); + } else if (themeLook != WARP4) { + draw3DRect(pnt, *colorActiveButton, 0, 0, + w-1, titleBarHeight-1, true); + draw3DRect(pnt, *colorActiveButton, 0, titleBarHeight, + w-1, 2*titleBarHeight-1, false); + } + + pnt.drawPixmap(offX, offY, *qp); + if (qp->height() <= titleBarHeight) { + pnt.drawPixmap(offX, titleBarHeight+offY, *qp); + } + pnt.end(); + delete qp; + } else { + p[Active] = qp; + } + + str = locate("appdata", TQString("icewm-themes/") + + themeName + s1 + "I" + s2); + if (str.isEmpty()) + str = locate("appdata", TQString("icewm-themes/") + + themeName + s1 + s2); + + qp = new TQPixmap(str); + if (!qp->isNull() && themeLook > 0) { + int w = qp->width(); + if (titleBarHeight > w) w = titleBarHeight; + p[InActive] = new TQPixmap(w, 2*titleBarHeight ); + p[InActive] -> fill(cInActive); + + TQPainter pnt( p[InActive] ); + + int offX = (w - qp->width())/2; + int offY = (titleBarHeight - qp->height())/2; + if (offY < 0) offY = 0; + + if (themeLook == WIN95) { + draw3DRect(pnt, *colorInActiveButton, offX-1, offY-1, + qp->width()+1, qp->height()+1, true); + draw3DRect(pnt, *colorInActiveButton, offX-1, offY-1 + titleBarHeight, + qp->width()+1, qp->height()+1, false); + } else if (themeLook != WARP4) { + draw3DRect(pnt, *colorInActiveButton, 0, 0, + w-1, titleBarHeight-1, true); + draw3DRect(pnt, *colorActiveButton, 0, titleBarHeight, + w-1, 2*titleBarHeight-1, false); + } + pnt.drawPixmap(offX, offY, *qp); + if (qp->height() <= titleBarHeight) { + pnt.drawPixmap(offX, titleBarHeight+offY, *qp); + } + pnt.end(); + delete qp; + } else { + p[InActive] = qp; + } +} + + + + +// Loads the specified Active/InActive files into the specific pixmaps, and +// can perform horizontal / vertical stretching if required for speed. +// Tries to implement some icewm specific pixmap handling for some dodgy themes +void ThemeHandler::setPixmap( TQPixmap* p[], TQString s1, TQString s2, + bool stretch, bool stretchHoriz ) +{ + if ( p[Active] ) + qWarning("twin-icewm: setPixmap - should be null (1)\n"); + if ( p[InActive] ) + qWarning("twin-icewm: setPixmap - should be null (2)\n"); + + p[Active] = new TQPixmap( locate("data", TQString("twin/icewm-themes/") + + themeName + s1 + "A" + s2) ); + p[InActive] = new TQPixmap( locate("data", TQString("twin/icewm-themes/") + + themeName + s1 + "I" + s2) ); + + // Stretch the pixmap if requested. + if ( stretch ) + { + if (p[Active]) + p[Active] = stretchPixmap( p[Active], stretchHoriz ); + if (p[InActive]) + p[InActive] = stretchPixmap( p[InActive], stretchHoriz ); + } + + if ( p[Active] && p[InActive] ) + { + // Make sure active and inactive pixmaps are the same width for proper painting + if (p[Active]->width() > p[InActive]->width()) + p[InActive] = stretchPixmap( p[InActive], true, p[Active]->width() ); + } + +} + + +// returns true if there were enough pixmaps loaded to +// draw the pixmap frame properly. +bool ThemeHandler::isFrameValid() +{ + return + ( validPixmaps( frameTL ) && + validPixmaps( frameT ) && + validPixmaps( frameTR ) && + validPixmaps( frameL ) && + validPixmaps( frameR ) && + validPixmaps( frameBL ) && + validPixmaps( frameB ) && + validPixmaps( frameBR ) ); +} + + +// Resets the theme, and re-clients all twin's wrapped windows. +bool ThemeHandler::reset( unsigned long) +{ + initialized = false; + freePixmaps(); + readConfig(); + initTheme(); + validframe = isFrameValid(); + initialized = true; + + // recreate all clients + return true; +} + +bool ThemeHandler::supports( Ability ability ) +{ + switch( ability ) + { + case AbilityAnnounceButtons: + case AbilityButtonMenu: + case AbilityButtonOnAllDesktops: + case AbilityButtonMinimize: + case AbilityButtonMaximize: + case AbilityButtonClose: + return true; + default: + return false; + }; +} + + +//////////////////////////////////////////////////////////////////////////////////////////// +// IceWM button class +//////////////////////////////////////////////////////////////////////////////////////////// + +IceWMButton::IceWMButton(IceWMClient *parent, const char *name, TQPixmap* (*p)[2], + bool isToggle, const TQString& tip, const int realizeBtns ) + : TQButton(parent->widget(), name) +{ + m_realizeButtons = realizeBtns; + setTipText(tip); + setCursor(ArrowCursor); + // Eliminate any possible background flicker + setBackgroundMode( TQWidget::NoBackground ); + client = parent; + usePixmap( p ); + setFixedSize( tqsizeHint() ); + setToggleButton( isToggle ); +} + + +void IceWMButton::setTipText(const TQString &tip) { + if(KDecoration::options()->showTooltips()) { + TQToolTip::remove(this ); + TQToolTip::add(this, tip ); + } +} + + +TQSize IceWMButton::tqsizeHint() const +{ + // Check for invalid data + if ( validPixmaps( (TQPixmap**) (*pix) ) ) // Cast to avoid dumb warning + { + TQPixmap* p = (*pix)[ client->isActive() ? Active : InActive ]; + return( TQSize(p->width(), titleBarHeight) ); + } else + return( TQSize(0, 0) ); +} + + +void IceWMButton::usePixmap( TQPixmap* (*p)[2] ) +{ + if (validPixmaps( *p )) { + pix = p; + setFixedSize( (*pix)[Active]->width(), titleBarHeight ); + tqrepaint( false ); + } else + pix = NULL; +} + + +void IceWMButton::drawButton(TQPainter *pnt) +{ + if ( pix && validPixmaps(*pix) ) + { + TQPixmap* p = (*pix)[ client->isActive() ? Active : InActive ]; + + if( p && (!p->isNull()) ) + { + int width = p->width(); + + // Only draw the lower pixmap 1/2 for down, and upper 1/2 for up state + if( isDown() || isOn() ) + pnt->drawPixmap(0, 0, *p, 0, titleBarHeight, width, titleBarHeight); + else + pnt->drawPixmap(0, 0, *p, 0, 0, width, titleBarHeight); + } + } else + qWarning("twin-icewm: Can't paint a null pixmap button"); +} + + +void IceWMButton::turnOn( bool isOn ) +{ + if ( isToggleButton() ) + setOn( isOn ); +} + + +void IceWMButton::mousePressEvent( TQMouseEvent* e ) +{ + last_button = e->button(); + TQMouseEvent me ( e->type(), e->pos(), e->globalPos(), + (e->button()&m_realizeButtons)?Qt::LeftButton:Qt::NoButton, e->state() ); + TQButton::mousePressEvent( &me ); +} + + +void IceWMButton::mouseReleaseEvent( TQMouseEvent* e ) +{ + last_button = e->button(); + TQMouseEvent me ( e->type(), e->pos(), e->globalPos(), + (e->button()&m_realizeButtons)?Qt::LeftButton:Qt::NoButton, e->state() ); + TQButton::mouseReleaseEvent( &me ); +} + + + +//////////////////////////////////////////////////////////////////////////////////////////// +// IceWMClient class +//////////////////////////////////////////////////////////////////////////////////////////// + +IceWMClient::IceWMClient( KDecorationBridge* bridge, KDecorationFactory* factory ) + : KDecoration (bridge, factory), + m_closing(false) +{ +} + + +IceWMClient::~IceWMClient() +{ + // Free the menu pixmaps if previously allocated + if ( menuButtonWithIconPix[Active] ) + delete menuButtonWithIconPix[Active]; + if ( menuButtonWithIconPix[InActive] ) + delete menuButtonWithIconPix[InActive]; +} + + +void IceWMClient::init() +{ + createMainWidget( WNoAutoErase | WStaticContents ); + widget()->installEventFilter( this ); + + // Set button pointers to null so we can track things + for(int i= IceWMClient::BtnSysMenu; i < IceWMClient::BtnCount; i++) + button[i] = NULL; + + // Make sure we can track the menu pixmaps too. + menuButtonWithIconPix[Active] = NULL; + menuButtonWithIconPix[InActive] = NULL; + + // No flicker thanks + widget()->setBackgroundMode( NoBackground ); + + // Pack the windowWrapper() window within a grid tqlayout + grid = new TQGridLayout(widget(), 0, 0, 0); + grid->setResizeMode(TQLayout::FreeResize); + grid->addRowSpacing(0, borderSizeY); // Top grab bar + + // Do something IceWM can't do :) + if (titleBarOnTop) { + if( isPreview()) + grid->addWidget( new TQLabel( i18n( "<center><b>IceWM preview</b></center>" ), widget() ), 2, 1); + else + grid->addItem( new TQSpacerItem( 0, 0 ), 2, 1); + // no shade flicker + grid->addItem( new TQSpacerItem( 0, 0, TQSizePolicy::Fixed, TQSizePolicy::Expanding ) ); + } + else { + // no shade flicker + grid->addItem( new TQSpacerItem( 0, 0, TQSizePolicy::Fixed, TQSizePolicy::Expanding ) ); + if( isPreview()) + grid->addWidget( new TQLabel( i18n( "<center><b>IceWM preview</b></center>" ), widget() ), 1, 1); + else + grid->addItem( new TQSpacerItem( 0, 0 ), 1, 1); + } + + grid->setRowStretch(1, 10); + grid->setRowStretch(2, 10); + grid->setColStretch(1, 10); + grid->addRowSpacing(3, borderSizeY); + grid->addColSpacing(0, borderSizeX); + grid->addColSpacing(2, borderSizeX); + + // Pack the titlebar with spacers and buttons + hb = new TQBoxLayout(0, TQBoxLayout::LeftToRight, 0, 0, 0); + hb->setResizeMode( TQLayout::FreeResize ); + + titleSpacerJ = addPixmapSpacer( titleJ ); + + addClientButtons( *titleButtonsLeft ); + titleSpacerL = addPixmapSpacer( titleL ); + + // Centre titlebar if required. + TQSizePolicy::SizeType spTitleBar; + spTitleBar = titleBarCentered ? TQSizePolicy::Expanding : TQSizePolicy::Maximum; + titleSpacerS = addPixmapSpacer( titleS, spTitleBar, 1 ); + titleSpacerP = addPixmapSpacer( titleP ); + + titlebar = new TQSpacerItem( titleTextWidth(caption()), titleBarHeight, + TQSizePolicy::Preferred, TQSizePolicy::Fixed ); + hb->addItem(titlebar); + + titleSpacerM = addPixmapSpacer( titleM ); + titleSpacerB = addPixmapSpacer( titleB, TQSizePolicy::Expanding, 1 ); + titleSpacerR = addPixmapSpacer( titleR ); + + addClientButtons( *titleButtonsRight ); + + titleSpacerQ = addPixmapSpacer( titleQ ); + + if (titleBarOnTop) + grid->addLayout ( hb, 1, 1 ); + else + grid->addLayout ( hb, 2, 1 ); +} + + +// Adds the buttons to the hbox tqlayout as per the buttons specified +// in the button string 's' +void IceWMClient::addClientButtons( const TQString& s ) +{ + if (!s.isEmpty()) + for(unsigned int i = 0; i < s.length(); i++) + { + switch ( s[i].latin1() ) + { + case 's': + // Create the menu icons, and render with the current mini-icon + // if explicitly requested by the theme. + if ( (validPixmaps(menuButtonPix) || showMenuButtonIcon) && !button[BtnSysMenu]) + { + if (showMenuButtonIcon) { + renderMenuIcons(); + button[BtnSysMenu] = new IceWMButton(this, "menu", + &menuButtonWithIconPix, false, i18n("Menu"), Qt::LeftButton|Qt::RightButton); + } + else + button[BtnSysMenu] = new IceWMButton(this, "menu", + &menuButtonPix, false, i18n("Menu")); + + connect( button[BtnSysMenu], TQT_SIGNAL(pressed()), + this, TQT_SLOT(menuButtonPressed())); + connect( button[BtnSysMenu], TQT_SIGNAL(released()), + this, TQT_SLOT(menuButtonReleased())); + hb->addWidget( button[BtnSysMenu] ); + } + break; + + case 'x': + if ( validPixmaps(closePix) && !button[BtnClose] && isCloseable()) + { + button[BtnClose] = new IceWMButton(this, "close", + &closePix, false, i18n("Close")); + hb->addWidget( button[BtnClose] ); + connect( button[BtnClose], TQT_SIGNAL(clicked()), + this, TQT_SLOT(closeWindow())); + } + break; + + case 'm': + if ( validPixmaps(maximizePix) && !button[BtnMaximize] && isMaximizable() ) + { + button[BtnMaximize] = new IceWMButton(this, "maximize", + &maximizePix, false, i18n("Maximize"), Qt::LeftButton|Qt::MidButton|Qt::RightButton); + hb->addWidget( button[BtnMaximize] ); + connect( button[BtnMaximize], TQT_SIGNAL(clicked()), + this, TQT_SLOT(slotMaximize())); + } + break; + + case 'i': + if ( validPixmaps(minimizePix) && !button[BtnMinimize] && + isMinimizable() ) + { + button[BtnMinimize] = new IceWMButton(this, "minimize", + &minimizePix, false, i18n("Minimize")); + hb->addWidget( button[BtnMinimize] ); + connect( button[BtnMinimize], TQT_SIGNAL(clicked()), + this, TQT_SLOT(minimize())); + } + break; + + /* Not yet implemented - how's hide useful anyway? + case 'h': + if ( button[BtnHide] && !button[BtnHide] ) + hb->addWidget( button[BtnHide] ); + break; */ + + case 'r': + // NOTE: twin doesn't have toggleShade() in clients.h ! + if ( validPixmaps(rollupPix) && !button[BtnRollup] ) + { + button[BtnRollup] = new IceWMButton(this, "shade", + isSetShade() ? &rolldownPix : &rollupPix, + false, i18n("Rollup")); + hb->addWidget( button[BtnRollup] ); + connect( button[BtnRollup], TQT_SIGNAL(clicked()), + this, TQT_SLOT(toggleShade())); + } + break; + + case 'd': + // Make depth == on all desktops + if ( validPixmaps(depthPix) && !button[BtnDepth] ) + { + button[BtnDepth] = new IceWMButton(this, "on_all_desktops", + &depthPix, true, isOnAllDesktops()?i18n("Not on all desktops"):i18n("On all desktops")); + button[BtnDepth]->turnOn( isOnAllDesktops() ); + hb->addWidget( button[BtnDepth] ); + connect( button[BtnDepth], TQT_SIGNAL(clicked()), + this, TQT_SLOT(toggleOnAllDesktops())); + } + break; + } + } +} + + +// Adds a pixmap to the titlebar tqlayout via the use of a nice TQSpacerItem +TQSpacerItem* IceWMClient::addPixmapSpacer( TQPixmap* p[], TQSizePolicy::SizeType s, int hsize ) +{ + TQSpacerItem* sp; + + // Add a null spacer for zero image + if ( p && p[Active] ) + { + int w = (hsize == -1) ? p[Active]->width(): hsize; + sp = new TQSpacerItem( w, titleBarHeight, s, TQSizePolicy::Fixed ); + } + else + sp = new TQSpacerItem(0, 0, TQSizePolicy::Maximum, TQSizePolicy::Fixed ); + + hb->addItem( sp ); + return sp; +} + + +void IceWMClient::renderMenuIcons() +{ + TQPixmap miniIcon( icon().pixmap( TQIconSet::Small, TQIconSet::Normal) ); + + if (!miniIcon.isNull()) + for(int i = 0; i < 2; i++) { + if ( menuButtonWithIconPix[i] ) + delete menuButtonWithIconPix[i]; + + // Try to be more friendly to dodgy themes - icewm assumes a square menu button + // but some pixmap themes don't provide a square menu button. + int w = titleBarHeight; + if (validPixmaps(menuButtonPix) && menuButtonPix[i]->width() > w) + w = menuButtonPix[i]->width(); + menuButtonWithIconPix[i] = new TQPixmap(w, 2*titleBarHeight ); + if (themeLook != WIN95) + menuButtonWithIconPix[i] -> fill((i==0) ? *colorInActiveButton : *colorActiveButton); + else + menuButtonWithIconPix[i] -> fill((i==0) ? *colorInActiveTitleBar : *colorActiveTitleBar); + TQPainter pnt( menuButtonWithIconPix[i] ); + + if (themeLook > 0 && themeLook != WIN95 && themeLook != WARP4) { + draw3DRect(pnt, *colorActiveButton, 0, 0, + w-1, titleBarHeight-1, true); + draw3DRect(pnt, *colorActiveButton, 0, titleBarHeight, + w-1, 2*titleBarHeight-1, false); + } + if (validPixmaps(menuButtonPix)) { + pnt.drawPixmap(0, 0, *menuButtonPix[i]); + } + int offset = (titleBarHeight - miniIcon.width())/2; + if (offset<0) offset = 0; + // Paint the mini icon over the menu pixmap in the centre + pnt.drawPixmap( offset, offset, miniIcon ); + pnt.drawPixmap( offset, titleBarHeight+offset, miniIcon ); + pnt.end(); + } + +} + + +void IceWMClient::slotMaximize() +{ + maximize(button[BtnMaximize]->last_button); +} + +void IceWMClient::toggleShade() +{ + setShade(!isSetShade()); +} + +int IceWMClient::titleTextWidth( const TQString& s ) +{ + // Obtains the actual width of the text, using the titlebar font + TQSize size; + TQFontMetrics fm( options()->font(true) ); + size = fm.size( 0, s ); + return size.width(); +} + + +void IceWMClient::borders(int& left, int& right, int& top, int& bottom) const +{ + left = borderSizeX; + right = borderSizeX; + if( titleBarOnTop ) { + top = titleBarHeight + borderSizeY; + bottom = borderSizeY; + } else { + top = borderSizeY; + bottom = titleBarHeight + borderSizeY; + } +} + + +void IceWMClient::resize( const TQSize& s ) +{ + widget()->resize( s ); +} + + +TQSize IceWMClient::tqminimumSize() const +{ + return widget()->tqminimumSize(); +} + + +// Repaint nicely upon resize to minimise flicker. +void IceWMClient::resizeEvent( TQResizeEvent* e ) +{ + calcHiddenButtons(); + + if (widget()->isVisibleToTLW()) + { + widget()->update(widget()->rect()); + int dx = 0; + int dy = 0; + + if ( e->oldSize().width() != widget()->width() ) + dx = 32 + TQABS( e->oldSize().width() - width() ); + + if ( e->oldSize().height() != height() ) + dy = 8 + TQABS( 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( TQRect( TQPoint(4,4), titlebar->tqgeometry().bottomLeft() - TQPoint(1,0) ) ); + widget()->update( TQRect( titlebar->tqgeometry().topRight(), TQPoint( width() - 4, titlebar->tqgeometry().bottom() ) ) ); + widget()->tqrepaint(titlebar->tqgeometry(), false); + } + } +} + + +// IceWM Paint magic goes here. +void IceWMClient::paintEvent( TQPaintEvent* ) +{ + TQColor colorTitleShadow; + TQColor colorTitle; + TQColor c1; + int rx, rw; + + TQPainter p( widget() ); + int act = isActive() ? Active: InActive; + + // Determine titlebar shadow colors + bool useShadow = isActive() ? useActiveShadow : useInActiveShadow; + if ( useShadow ) + colorTitleShadow = isActive() ? *colorActiveTitleTextShadow : *colorInActiveTitleTextShadow; + + if ( themeTitleTextColors ) + colorTitle = isActive()? *colorActiveTitleBarText : *colorInActiveTitleBarText; + else + colorTitle = options()->color(ColorFont, isActive()); + + // Obtain widget bounds. + TQRect r; + r = widget()->rect(); + int fillWidth = r.width() - 2*borderSizeX; + int y = r.y(); + int x = r.x(); + int w = r.width(); + int h = r.height(); + + // Do we have pixmaps for the frame? + if (validframe) + { + // Top corner + p.drawPixmap(0, 0, *frameTL[ act ], 0, 0, cornerSizeX, borderSizeY); + p.drawPixmap(0, 0, *frameTL[ act ], 0, 0, borderSizeX, cornerSizeY); + + // Top right corner + p.drawPixmap(w-cornerSizeX, 0, *frameTR[ act ], + frameTR[act]->width()-cornerSizeX, 0, cornerSizeX, borderSizeY); + p.drawPixmap(w-borderSizeX, 0, *frameTR[ act ], + frameTR[act]->width()-borderSizeX, 0, borderSizeX, cornerSizeY); + + // Top bar + p.drawTiledPixmap( cornerSizeX, 0, w-(2*cornerSizeX), borderSizeY, *frameT[ act ] ); + + // Left bar + p.drawTiledPixmap( 0, cornerSizeY, borderSizeX, h-(2*cornerSizeY), *frameL[ act ] ); + + // Right bar + p.drawTiledPixmap( w-borderSizeX, cornerSizeY, borderSizeX, h-(2*cornerSizeY), + *frameR[ act ],frameR[act]->width()-borderSizeX ); + + // Bottom left corner + p.drawPixmap(0, h-borderSizeY, *frameBL[ act ], + 0, frameBL[act]->height()-borderSizeY, cornerSizeX, borderSizeY); + p.drawPixmap(0, h-cornerSizeY, *frameBL[ act ], + 0, frameBL[act]->height()-cornerSizeY, borderSizeX, cornerSizeY); + + // Bottom right corner + p.drawPixmap(w-cornerSizeX, h-borderSizeY, *frameBR[ act ], + frameBR[act]->width()-cornerSizeX, frameBR[act]->height()-borderSizeY, + cornerSizeX, borderSizeY); + + p.drawPixmap(w-borderSizeX, h-cornerSizeY, *frameBR[ act ], + frameBR[act]->width()-borderSizeX, frameBR[act]->height()-cornerSizeY, + borderSizeX, cornerSizeY); + + // Bottom bar + p.drawTiledPixmap(cornerSizeX, h-borderSizeY, w-(2*cornerSizeX), borderSizeY, + *frameB[ act ], 0, frameB[ act ]->height()-borderSizeY ); + + // Ensure uncovered areas during shading are painted with something + p.setPen( *colorInActiveBorder ); + if (titleBarOnTop) + p.drawLine( x+borderSizeX, y+h-borderSizeY-1, + x+w-borderSizeX-1, y+h-borderSizeY-1); + else + p.drawLine( x+borderSizeX, y+borderSizeY, + x+w-borderSizeX-1, y+borderSizeY); + + } else + { + // Draw a stock IceWM frame instead of a pixmap frame + c1 = isActive() ? *colorActiveBorder : *colorInActiveBorder; + + if (themeLook == WARP3 || themeLook == MOTIF) { + draw3DRect(p, c1, x, y, w-1, h-1, true); + p.setPen(c1); + p.drawRect(x+1, y+1, w-2, h-2); + } else { + p.setPen( c1.light(135) ); + p.drawLine(0, 0, w-2, 0); + p.drawLine(0, 0, 0, h-2); + + p.setPen(c1); + p.drawLine(1, 1, w-3, 1); + p.drawLine(1, 1, 1, h-3); + + p.setPen( c1.dark(140) ); + p.drawLine(1, h-2, w-2, h-2); + p.drawLine(w-2, 1, w-2, h-2); + + p.setPen( TQt::black ); + p.drawLine(w-1, 0, w-1, h-1); + p.drawLine(0, h-1, w-1, h-1); + } + + + // Fill frame border if required + if (borderSizeX > 2) + { + // FillQt::Vertical sizes + p.fillRect( x+2, y+2, borderSizeX-2, h-4, c1); + p.fillRect( w-borderSizeX, y+2, borderSizeX-2, h-4, c1); + } + + if (borderSizeY > 2) + { + // Fill horizontal frame parts + p.fillRect( x+borderSizeX, y+2, fillWidth, borderSizeY-2, c1); + p.fillRect( x+borderSizeX, h-borderSizeY, fillWidth, borderSizeY-2, c1); + } + + if (themeLook == WARP3 || themeLook == MOTIF) { + draw3DRect(p, c1, x+borderSizeX-1, y+borderSizeY-1, + w+1-2*borderSizeX, h+1-2*borderSizeY, false); + } + if (themeLook == MOTIF && !isShade()) { + int xext = titleBarHeight + borderSizeX - 1; + int yext = titleBarHeight + borderSizeY - 1; + + int xext2 = w-xext-2; + int yext2 = h-yext-2; + + int bX = w - borderSizeX-1; + int bY = h - borderSizeY-1; + + p.setPen( c1.dark(140) ); + p.drawLine(xext, 0, xext, borderSizeY); + p.drawLine(xext2, 0, xext2, borderSizeY); + p.drawLine(xext, bY, xext, h-1); + p.drawLine(xext2, bY, xext2, h-1); + + p.drawLine(0, yext, borderSizeX, yext); + p.drawLine(0, yext2, borderSizeX, yext2); + p.drawLine(bX, yext, w-1, yext); + p.drawLine(bX, yext2, w-1, yext2); + + p.setPen( c1.light(135) ); + + ++xext; ++yext; ++xext2; ++yext2; + + p.drawLine(xext, 0, xext, borderSizeY); + p.drawLine(xext2, 0, xext2, borderSizeY); + p.drawLine(xext, bY, xext, h-1); + p.drawLine(xext2, bY, xext2, h-1); + + p.drawLine(0, yext, borderSizeX, yext); + p.drawLine(0, yext2, borderSizeX, yext2); + p.drawLine(bX, yext, w-1, yext); + p.drawLine(bX, yext2, w-1, yext2); + + + } + + // Ensure uncovered areas during shading are painted with something + p.setPen( *colorInActiveBorder ); + if (titleBarOnTop) + p.drawLine( x+borderSizeX, y+h-borderSizeY-1, + x+w-borderSizeX-1, y+h-borderSizeY-1); + else + p.drawLine( x+borderSizeX, y+borderSizeY, + x+w-borderSizeX-1, y+borderSizeY); + } + + // Draw the title elements, if we need to draw a titlebar. + if (titleBarHeight > 0) + { + TQPixmap* titleBuffer = new TQPixmap( width()-(2*borderSizeX), titleBarHeight ); + TQPainter p2( titleBuffer, this ); + titleBuffer->fill( act ? *colorActiveTitleBar : *colorInActiveTitleBar ); + + r = titleSpacerJ->tqgeometry(); + if (!r.isEmpty() && titleJ[ act ]) + p2.drawPixmap( r.x()-borderSizeX, 0, *titleJ[ act ]); + + r = titleSpacerL->tqgeometry(); + if (!r.isEmpty() && titleL[ act ]) + p2.drawPixmap( r.x()-borderSizeX, 0, *titleL[ act ]); + + r = titleSpacerS->tqgeometry(); + if (!r.isEmpty() && titleS[ act ]) + p2.drawTiledPixmap( r.x()-borderSizeX, 0, r.width(), titleBarHeight, *titleS[ act ]); + + r = titleSpacerP->tqgeometry(); + if (!r.isEmpty() && titleP[ act ]) + p2.drawPixmap( r.x()-borderSizeX, 0, *titleP[ act ]); + + r = titlebar->tqgeometry(); + if (!r.isEmpty() && titleT[ act ] ) + p2.drawTiledPixmap( r.x()-borderSizeX, 0, r.width(), titleBarHeight, *titleT[ act ]); + + r = titleSpacerM->tqgeometry(); + if (!r.isEmpty() && titleM[ act ]) + p2.drawPixmap( r.x()-borderSizeX, 0, *titleM[ act ], 0, 0, r.width(), r.height()); + + r = titleSpacerB->tqgeometry(); + if (!r.isEmpty() && titleB[ act ]) + p2.drawTiledPixmap( r.x()-borderSizeX, 0, r.width(), titleBarHeight, *titleB[ act ]); + + r = titleSpacerR->tqgeometry(); + if (!r.isEmpty() && titleR[ act ]) + p2.drawPixmap( r.x()-borderSizeX, 0, *titleR[ act ], 0, 0, r.width(), r.height()); + + r = titleSpacerQ->tqgeometry(); + if (!r.isEmpty() && titleQ[ act ]) + p2.drawPixmap( r.x()-borderSizeX, 0, *titleQ[ act ], 0, 0, r.width(), r.height()); + + p2.setFont( options()->font(true) ); + + // Pre-compute as much as possible + r = titlebar->tqgeometry(); + rx = r.x() - borderSizeX; + rw = width()-(2*borderSizeX)-r.x(); + + // Paint a title text shadow if requested + if ( useShadow ) + { + p2.setPen( colorTitleShadow ); + p2.drawText(rx+1, 1, rw, titleBarHeight, AlignLeft|AlignVCenter, caption()); + } + + // Draw the title text + p2.setPen( colorTitle ); + p2.drawText(rx, 0, rw, titleBarHeight, AlignLeft|AlignVCenter, caption()); + p2.end(); + + bitBlt( widget(), borderSizeX, hb->tqgeometry().y(), titleBuffer ); + + delete titleBuffer; + } +} + + +void IceWMClient::showEvent(TQShowEvent *ev) +{ + calcHiddenButtons(); + + titlebar->changeSize( titleTextWidth(caption()), titleBarHeight, + TQSizePolicy::Preferred, TQSizePolicy::Fixed ); + grid->activate(); + widget()->show(); + IceWMClient::showEvent(ev); +} + + +void IceWMClient::mouseDoubleClickEvent( TQMouseEvent * e ) +{ + if( e->button() != Qt::LeftButton ) + return; + + TQRect r; + if (titleBarOnTop) + r.setRect( borderSizeX, borderSizeY, width()-(2*borderSizeX), titleBarHeight); + else + r.setRect( borderSizeX, height()-borderSizeY-titleBarHeight, + width()-(2*borderSizeX), titleBarHeight); + + if (r.contains( e->pos() ) ) + titlebarDblClickOperation(); + +} + + +void IceWMClient::wheelEvent(TQWheelEvent *e) +{ + if (isSetShade() || TQRect( 0, 0, width(), titleBarHeight ).contains( e->pos() ) ) + titlebarMouseWheelOperation( e->delta()); +} + + +// Called via Client class when the miniIcon() changes +void IceWMClient::iconChange() +{ + if (validPixmaps(menuButtonPix) && showMenuButtonIcon) + { + if (button[BtnSysMenu]) + { + renderMenuIcons(); + button[BtnSysMenu]->usePixmap( &menuButtonWithIconPix ); + if (button[BtnSysMenu]->isVisible()) + button[BtnSysMenu]->tqrepaint(false); + } + } +} + + +void IceWMClient::desktopChange() +{ + if (button[BtnDepth]) + { + button[BtnDepth]->turnOn( isOnAllDesktops() ); + button[BtnDepth]->tqrepaint(false); + button[BtnDepth]->setTipText(isOnAllDesktops() ? i18n("Not on all desktops") : i18n("On all desktops")); + } +} + + +// Please don't modify the following unless you want tqlayout problems +void IceWMClient::captionChange() +{ + TQRect r( 0, borderSizeY, geometry().width(), titleBarHeight); + + titlebar->changeSize( titleTextWidth( caption() ), titleBarHeight, + TQSizePolicy::Preferred, TQSizePolicy::Fixed ); + titlebar->invalidate(); + grid->activate(); + widget()->tqrepaint( r, false ); +} + + +void IceWMClient::maximizeChange() +{ + // Change the button pixmap to restore if required + if (button[BtnMaximize] && validPixmaps(restorePix)) + { + button[BtnMaximize]->usePixmap( (maximizeMode()==MaximizeFull) ? &restorePix : &maximizePix ); + button[BtnMaximize]->setTipText( (maximizeMode()==MaximizeFull) ? i18n("Restore") : i18n("Maximize")); + } +} + + +void IceWMClient::shadeChange() +{ + // Change the button pixmap to rolldown if required + if (button[BtnRollup] && validPixmaps(rolldownPix)) + { + button[BtnRollup]->usePixmap( isSetShade() ? &rolldownPix : &rollupPix ); + button[BtnRollup]->setTipText( isSetShade() ? i18n("Rolldown") : i18n("Rollup")); + } + +} + + +void IceWMClient::activeChange() +{ + widget()->tqrepaint(false); + + // Reset the button pixmaps. + for(int i= IceWMClient::BtnSysMenu; i < IceWMClient::BtnCount; i++) + if(button[i]) + button[i]->tqrepaint( false ); +} + + +// This does the showing / hiding button magic +// for variable positioned buttons. +void IceWMClient::calcHiddenButtons() +{ + const int minwidth = 220; // Minimum width where all buttons are shown + const int btn_width = 20; // Average width + + // Show/Hide buttons in this order - OnAllDesktops, Maximize, Menu, Rollup, Minimize, Close. + IceWMButton* btnArray[] = { button[BtnDepth], button[BtnMaximize], button[BtnSysMenu], + button[BtnRollup], button[BtnMinimize], button[BtnClose] }; + + int current_width = width(); + int count = 0; + int i; + + // Find out how many buttons we have to hide. + while (current_width < minwidth) + { + current_width += btn_width; + count++; + } + + // Bound the number of buttons to hide + if (count > 6) count = 6; + + // Hide the required buttons... + for(i = 0; i < count; i++) + { + if (btnArray[i] && btnArray[i]->isVisible() ) + btnArray[i]->hide(); + } + + // Show the rest of the buttons... + for(i = count; i < 6; i++) + { + if (btnArray[i] && (!btnArray[i]->isVisible()) ) + btnArray[i]->show(); + } +} + + +// Mouse position code modified from that in workspace.cpp +IceWMClient::Position IceWMClient::mousePosition( const TQPoint& p ) const +{ + int rangeX = cornerSizeX; + int rangeY = cornerSizeY; + int borderX = borderSizeX; + int borderY = borderSizeY; + + Position m = PositionCenter; + + if ((p.x() > borderX && p.x() < width() - borderX) && + ( p.y() > borderY && p.y() < height() - borderY)) + return PositionCenter; + + if ( p.y() <= rangeY && p.x() <= rangeX) + m = PositionTopLeft; + else if ( p.y() >= height()-rangeY && p.x() >= width()-rangeX) + m = PositionBottomRight; + else if ( p.y() >= height()-rangeX && p.x() <= rangeX) + m = PositionBottomLeft; + else if ( p.y() <= rangeY && p.x() >= width()-rangeX) + m = PositionTopRight; + else if ( p.y() <= borderY ) + m = PositionTop; + else if ( p.y() >= height()-borderY ) + m = PositionBottom; + else if ( p.x() <= borderX ) + m = PositionLeft; + else if ( p.x() >= width()-borderX ) + m = PositionRight; + else + m = PositionCenter; + return m; +} + + +void IceWMClient::menuButtonPressed() +{ + static TQTime t; + static IceWMClient* lastClient = NULL; + bool dbl = ( lastClient == this && t.elapsed() <= TQApplication::doubleClickInterval()); + lastClient = this; + t.start(); + + if (dbl) + { + m_closing = true; + return; + } + + TQPoint menuPoint ( button[BtnSysMenu]->rect().bottomLeft() ); + + // Move to right if menu on rhs, otherwise on left + // and make this depend on windowWrapper(), not button. + + KDecorationFactory* f = factory(); + showWindowMenu( button[BtnSysMenu]->mapToGlobal(menuPoint) ); + if( !f->exists( this )) // 'this' was deleted + return; + button[BtnSysMenu]->setDown(false); +} + +void IceWMClient::menuButtonReleased() +{ + if (m_closing) + closeWindow(); +} + +bool IceWMClient::eventFilter( TQObject* o, TQEvent* e ) +{ + if( TQT_BASE_OBJECT(o) != TQT_BASE_OBJECT(widget())) + return false; + switch( e->type()) + { + case TQEvent::Resize: + resizeEvent(TQT_TQRESIZEEVENT( e ) ); + return true; + case TQEvent::Paint: + paintEvent(TQT_TQPAINTEVENT( e ) ); + return true; + case TQEvent::MouseButtonDblClick: + mouseDoubleClickEvent(TQT_TQMOUSEEVENT( e ) ); + return true; + case TQEvent::MouseButtonPress: + processMousePressEvent(TQT_TQMOUSEEVENT( e ) ); + return true; + case TQEvent::Wheel: + wheelEvent( TQT_TQWHEELEVENT( e )); + return true; + default: + break; + } + return false; +} + +} + +extern "C" +{ + KDE_EXPORT KDecorationFactory *create_factory() + { + IceWM::clientHandler = new IceWM::ThemeHandler; + return IceWM::clientHandler; + } +} + + +#include "icewm.moc" + +// vim: ts=4 |