diff --git a/clients/oxygen/CMakeLists.txt b/clients/oxygen/CMakeLists.txt new file mode 100644 index 0000000000..4950af0b3c --- /dev/null +++ b/clients/oxygen/CMakeLists.txt @@ -0,0 +1,27 @@ +include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/workspace/kwin/lib ) + + +########### next target ############### + +set(kwin_oxy_SRCS + oxygenclient.cpp + oxygenbutton.cpp + oxygen.cpp + definitions.cpp + ) + +kde4_automoc(${kwin_oxy_SRCS}) + +kde4_add_plugin(kwin3_oxy ${kwin_oxy_SRCS}) + + +target_link_libraries(kwin3_oxy ${KDE4_KDEFX_LIBS} ${KDE4_KDEUI_LIBS} ${X11_Xrender_LIB} kdecorations) + +install(TARGETS kwin3_oxy DESTINATION ${PLUGIN_INSTALL_DIR} ) + + +########### install files ############### + +install( FILES oxygenclient.desktop DESTINATION ${DATA_INSTALL_DIR}/kwin/ ) + + diff --git a/clients/oxygen/definitions.cpp b/clients/oxygen/definitions.cpp new file mode 100644 index 0000000000..a0ff711f7a --- /dev/null +++ b/clients/oxygen/definitions.cpp @@ -0,0 +1,35 @@ +////////////////////////////////////////////////////////////////////////////// +// oxygenbutton.h +// ------------------- +// Oxygen window decoration for KDE. Definitions of some global constants using +// preprocessor directives. +// ------------------- +// Copyright (c) 2006, 2007 Riccardo Iaconelli +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#define BUTTONSIZE 18 +#define DECOSIZE 8 +#define TITLESIZE 18 +#define TFRAMESIZE 5 +#define BFRAMESIZE 4 +#define LFRAMESIZE 4 +#define RFRAMESIZE 4 +#define FRAMEBUTTONSPACE 67 diff --git a/clients/oxygen/oxygen.cpp b/clients/oxygen/oxygen.cpp new file mode 100644 index 0000000000..b461fe9d83 --- /dev/null +++ b/clients/oxygen/oxygen.cpp @@ -0,0 +1,123 @@ +////////////////////////////////////////////////////////////////////////////// +// oxygenbutton.h +// ------------------- +// Oxygen window decoration for KDE. +// ------------------- +// Copyright (c) 2006, 2007 Riccardo Iaconelli +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "oxygenclient.h" +#include "oxygen.h" +extern "C" +{ +KDE_EXPORT KDecorationFactory* create_factory() +{ + return new Oxygen::OxygenFactory(); +} +} +namespace Oxygen +{ + + +////////////////////////////////////////////////////////////////////////////// +// OxygenFactory Class // +////////////////////////////////////////////////////////////////////////////// + +bool OxygenFactory::initialized_ = false; +Qt::Alignment OxygenFactory::titlealign_ = Qt::AlignHCenter; + +////////////////////////////////////////////////////////////////////////////// +// OxygenFactory() +// ---------------- +// Constructor + +OxygenFactory::OxygenFactory() +{ + readConfig(); + initialized_ = true; +} + +////////////////////////////////////////////////////////////////////////////// +// ~OxygenFactory() +// ----------------- +// Destructor + +OxygenFactory::~OxygenFactory() { initialized_ = false; } + +////////////////////////////////////////////////////////////////////////////// +// createDecoration() +// ----------------- +// Create the decoration + +KDecoration* OxygenFactory::createDecoration(KDecorationBridge* b) +{ + return new OxygenClient(b, this); +} + +////////////////////////////////////////////////////////////////////////////// +// reset() +// ------- +// Reset the handler. Returns true if decorations need to be remade, false if +// only a repaint is necessary + +bool OxygenFactory::reset(unsigned long changed) +{ + // read in the configuration + initialized_ = false; + bool confchange = readConfig(); + initialized_ = true; + + if (confchange || + (changed & (SettingDecoration | SettingButtons | SettingBorder))) { + return true; + } else { + resetDecorations(changed); + return false; + } +} + +////////////////////////////////////////////////////////////////////////////// +// readConfig() +// ------------ +// Read in the configuration file + +bool OxygenFactory::readConfig() +{ + // create a config object + KConfig config("kwinexamplerc"); + config.setGroup("General"); + + // grab settings + Qt::Alignment oldalign = titlealign_; + QString value = config.readEntry("TitleAlignment", "AlignHCenter"); + if (value == "AlignLeft") titlealign_ = Qt::AlignLeft; + else if (value == "AlignHCenter") titlealign_ = Qt::AlignHCenter; + else if (value == "AlignRight") titlealign_ = Qt::AlignRight; + + if (oldalign == titlealign_) + return false; + else + return true; +} + + + +} //namespace Oxygen diff --git a/clients/oxygen/oxygen.h b/clients/oxygen/oxygen.h new file mode 100644 index 0000000000..cfec02e054 --- /dev/null +++ b/clients/oxygen/oxygen.h @@ -0,0 +1,75 @@ +////////////////////////////////////////////////////////////////////////////// +// oxygenbutton.h +// ------------------- +// Oxygen window decoration for KDE. +// ------------------- +// Copyright (c) 2006, 2007 Riccardo Iaconelli +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// +#ifndef OXYGEN_H +#define OXYGEN_H + +#include +#include + +namespace Oxygen +{ +class OxygenClient; +// OxygenFactory ///////////////////////////////////////////////////////////// + +enum ButtonType { + ButtonHelp=0, + ButtonMax, + ButtonMin, + ButtonClose, + ButtonMenu, + ButtonSticky, + ButtonTypeCount +}; +Q_DECLARE_FLAGS(ButtonTypes, ButtonType); + +class OxygenFactory: public KDecorationFactory +{ +public: + OxygenFactory(); + virtual ~OxygenFactory(); + virtual KDecoration *createDecoration(KDecorationBridge *b); + virtual bool reset(unsigned long changed); + + static bool initialized(); + static Qt::Alignment titleAlign(); + +private: + bool readConfig(); + +private: + static bool initialized_; + static Qt::Alignment titlealign_; +}; + +inline bool OxygenFactory::initialized() + { return initialized_; } + +inline Qt::Alignment OxygenFactory::titleAlign() + { return titlealign_; } + +} //namespace Oxygen + +#endif diff --git a/clients/oxygen/oxygenbutton.cpp b/clients/oxygen/oxygenbutton.cpp new file mode 100644 index 0000000000..d07ad5a16b --- /dev/null +++ b/clients/oxygen/oxygenbutton.cpp @@ -0,0 +1,388 @@ +////////////////////////////////////////////////////////////////////////////// +// oxygenbutton.cpp +// ------------------- +// Oxygen window decoration for KDE. Buttons. +// ------------------- +// Copyright (c) 2006, 2007 Riccardo Iaconelli +// Copyright (c) 2006, 2007 Casper Boemann +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include + +#include + +#include "oxygenclient.h" +#include "oxygenbutton.h" +#include "oxygen.h" +#include "definitions.cpp" + +namespace Oxygen +{ + +// class OxygenClient; +/* +extern int BUTTONSIZE; +extern int DECOSIZE;*/ + +// static const int BUTTONSIZE = 18; +// static const int DECOSIZE = 8; +////////////////////////////////////////////////////////////////////////////// +// OxygenButton Class // +////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +// OxygenButton() +// --------------- +// Constructor + +OxygenButton::OxygenButton(OxygenClient *parent, + const QString& tip, ButtonType type, + const unsigned char *bitmap) + : QAbstractButton(parent->widget()), client_(parent), type_(type), + deco_(0), lastmouse_(0) +{ + //setBackgroundMode(Qt::NoBackground); PORT to qt4 + setFixedSize(BUTTONSIZE, BUTTONSIZE); + setCursor(Qt::ArrowCursor); + if (bitmap) setBitmap(bitmap); + setToolTip(tip); + connect(this, SIGNAL(pressed()), this, SLOT(pressSlot())); +} + +OxygenButton::~OxygenButton() +{ + if (deco_) delete deco_; +} + +////////////////////////////////////////////////////////////////////////////// +// setBitmap() +// ----------- +// Set the button decoration + +void OxygenButton::setBitmap(const unsigned char *bitmap) +{ + if (!bitmap) return; // no bitmap, probably the menu button + + if (deco_) delete deco_; + deco_ = new QBitmap(DECOSIZE, DECOSIZE); + //PORT to qt4 set actual pixels , bitmap, true); + deco_->setMask(*deco_); + update(); +} + +////////////////////////////////////////////////////////////////////////////// +// sizeHint() +// ---------- +// Return size hint + +QSize OxygenButton::sizeHint() const +{ + return QSize(BUTTONSIZE, BUTTONSIZE); +} + +////////////////////////////////////////////////////////////////////////////// +// enterEvent() +// ------------ +// Mouse has entered the button + +void OxygenButton::enterEvent(QEvent *e) +{ + // if we wanted to do mouseovers, we would keep track of it here + if (status_ != Oxygen::Pressed) { + status_ = Oxygen::Hovered; + } + QAbstractButton::enterEvent(e); +} + +////////////////////////////////////////////////////////////////////////////// +// leaveEvent() +// ------------ +// Mouse has left the button + +void OxygenButton::leaveEvent(QEvent *e) +{ + // if we wanted to do mouseovers, we would keep track of it here + status_ = Oxygen::Normal; + QAbstractButton::leaveEvent(e); +} + +////////////////////////////////////////////////////////////////////////////// +// pressSlot() +// ------------ +// Mouse has pressed the button + +void OxygenButton::pressSlot() +{ + kDebug() << "Pressed " << endl; + status_ = Oxygen::Pressed; + update(); +} +////////////////////////////////////////////////////////////////////////////// +// drawButton() +// ------------ +// Draw the button + +void OxygenButton::paintEvent(QPaintEvent *) +{ + QPainter painter(this); + + if (type_ == ButtonMenu) { + // we paint the mini icon (which is 16 pixels high) + int dx = (width() - 16) / 2; + int dy = (height() - 16) / 2; + painter.drawPixmap(dx, dy, client_->icon().pixmap(16)); + return; + } + + QRadialGradient grad1(QPointF(5.0, 5.0),5.0, QPointF(5.0, 7.5)); + grad1.setColorAt(0.0, QColor(0,0,0,255)); + grad1.setColorAt(1.0, QColor(0,0,0,0)); + QRadialGradient grad2(QPointF(5.0, 5.0),5.0, QPointF(5.0, 8.0)); + grad2.setColorAt(0.0, QColor(240,240,240)); + grad2.setColorAt(1.0, QColor(220,220,220)); + QRadialGradient grad3(QPointF(5.0, 3.75), 3.5,QPointF(5.0, 2.5)); + grad3.setColorAt(0, QColor(255,255,255,211)); + grad3.setColorAt(1, QColor(255,255,255,25)); + QBrush brush1(grad1); + QBrush brush2(grad2); + QBrush brush3(grad3); + + painter.scale(width()/10.0, height()/10.0); + painter.setRenderHint(QPainter::Antialiasing,true); + + QPainterPath path1; + path1.addEllipse(0.0, 0.0, 10.0, 10.0); + painter.fillPath(path1, brush1); + + QPainterPath path2; + path2.addEllipse(0.5, 0.5, 9.0, 9.0); + painter.fillPath(path2, brush2); + + + QLinearGradient grad8; + QLinearGradient grad7; + + if (type_ == Oxygen::ButtonClose){ + //Draw the red 'x' + painter.save(); + grad7.setStart(0,0); + grad7.setFinalStop(3, 7); + if (status_ == Oxygen::Hovered) { + grad7.setColorAt(0, Qt::red); + grad7.setColorAt(1, Qt::black); + } else if (status_ == Oxygen::Normal) { + grad7.setColorAt(0, QColor(91, 0, 0, 144)); + grad7.setColorAt(1, QColor(91, 0, 0, 144)); + } + painter.setBrush(grad7); + painter.translate(3.3, 2.5); + painter.rotate(45); + painter.setPen(Qt::NoPen); + painter.drawRoundRect(0, 0, 6, 1, 0, 0); + painter.translate(3.5, -2.5); + painter.rotate(90); + painter.drawRoundRect(0, 0, 6, 1, 0, 0); + painter.restore(); + } else if (type_ == Oxygen::ButtonMax){ + //Draw the green '+' + painter.save(); + grad7.setStart(0,0); + grad7.setFinalStop(3, 7); + grad8.setStart(0,0); + grad8.setFinalStop(7, 3); + if (status_ == Oxygen::Hovered) { + grad7.setColorAt(0, QColor(0, 80, 0, 50)); + grad7.setColorAt(1, QColor(0, 80, 0, 50)); + grad8.setColorAt(0, QColor(0, 80, 0, 50)); + grad8.setColorAt(1, QColor(0, 80, 0, 50)); + } else if (status_ == Oxygen::Normal) { + grad7.setColorAt(0, QColor(0, 0, 0, 15)); + grad7.setColorAt(1, QColor(0, 0, 0, 15)); + grad8.setColorAt(0, QColor(0, 0, 0, 15)); + grad8.setColorAt(1, QColor(0, 0, 0, 15)); + } else { //Pressed + grad7.setColorAt(0, Qt::green); + grad7.setColorAt(1, Qt::green); + grad8.setColorAt(0, Qt::green); + grad8.setColorAt(1, Qt::green); + } + painter.setBrush(grad8); + painter.translate(2.0, 4.5); + painter.setPen(Qt::NoPen); + painter.drawRoundRect(0, 0, 6, 1, 0, 0); + painter.translate(3.5, -2.5); + painter.setBrush(grad7); + painter.rotate(90); + painter.drawRoundRect(0, 0, 6, 1, 0, 0); + painter.restore(); + } else if (type_ == Oxygen::ButtonMin){ + //Draw the yellow '-' + painter.save(); +// QLinearGradient grad7; +// grad7.setStart(0,0); +// grad7.setFinalStop(3, 7); + grad8.setStart(0,0); + grad8.setFinalStop(7, 3); + if (status_ == Oxygen::Hovered) { +// grad7.setColorAt(0, QColor(0, 91, 0, 144)); +// grad7.setColorAt(1, QColor(0, 91, 0, 144)); + grad8.setColorAt(0, QColor(155, 121, 0, 155)); + grad8.setColorAt(1, QColor(155, 121, 0, 155)); + } else if (status_ == Oxygen::Normal) { +// grad7.setColorAt(0, QColor(0, 0, 0, 144)); +// grad7.setColorAt(1, QColor(0, 0, 0, 144)); + grad8.setColorAt(0, QColor(0, 0, 0, 30)); + grad8.setColorAt(1, QColor(0, 0, 0, 30)); + } else if (status_ == Oxygen::Pressed){ //Pressed +// grad7.setColorAt(0, Qt::yellow); +// grad7.setColorAt(1, Qt::yellow); + grad8.setColorAt(0, Qt::yellow); + grad8.setColorAt(1, Qt::yellow); + } + painter.setBrush(grad8); + painter.translate(2.0, 4.5); + painter.setPen(Qt::NoPen); + painter.drawRoundRect(0, 0, 6, 1, 0, 0); +// painter.translate(3.5, -2.5); +// painter.setBrush(grad7); +// painter.rotate(90); +// painter.drawRoundRect(0, 0, 6, 1, 0, 0); + painter.restore(); + } else if (type_ == Oxygen::ButtonHelp){ + //Draw the red 'x' + painter.save(); +// QLinearGradient grad7; +// grad7.setStart(0,0); +// grad7.setFinalStop(3, 7); + grad8.setStart(0,0); + grad8.setFinalStop(7, 3); + if (status_ == Oxygen::Hovered) { +// grad7.setColorAt(0, QColor(0, 91, 0, 144)); +// grad7.setColorAt(1, QColor(0, 91, 0, 144)); + grad8.setColorAt(0, QColor(155, 121, 0, 155)); + grad8.setColorAt(1, QColor(155, 121, 0, 155)); + } else if (status_ == Oxygen::Normal) { +// grad7.setColorAt(0, QColor(0, 0, 0, 144)); +// grad7.setColorAt(1, QColor(0, 0, 0, 144)); + grad8.setColorAt(0, QColor(0, 0, 0, 30)); + grad8.setColorAt(1, QColor(0, 0, 0, 30)); + } else if (status_ == Oxygen::Pressed){ //Pressed +// grad7.setColorAt(0, Qt::yellow); +// grad7.setColorAt(1, Qt::yellow); + grad8.setColorAt(0, Qt::yellow); + grad8.setColorAt(1, Qt::yellow); + } + //This code has been picked up by a drawing made with inkscape + QPolygonF questionMark; + questionMark << QPointF(37.918475,94.451027) << QPointF(36.026474,85.486156) + << QPointF(36.772553,75.80096) << QPointF(41.423128,66.688939) + << QPointF(49.497475,61.402536) << QPointF(58.596523,56.663413) + << QPointF(68.690373,56.194458) << QPointF(78.505617,59.46141) + << QPointF(86.699378,68.158973) << QPointF(90.881465,78.404561) + << QPointF(90.345804,89.078756) << QPointF(88.320755,95.66811) + << QPointF(81.408421,102.0783) << QPointF(69.198471,108.7171) + << QPointF(64.91,116.86) << QPointF(63.067541,120.47646) + << QPointF(62.467671,131.84155) << QPointF(62.6367,146.0); + + QMatrix inkscapeMatrix(0.09245,0,0,0.0916,-3.2868,-5.1); + + painter.translate(2.0, 4.5); + painter.setWorldMatrix(inkscapeMatrix); +// painter.setBrush(grad8); + QPen oxyPen; // creates a default pen + oxyPen.setStyle(Qt::DashDotLine); + oxyPen.setWidth(5); + oxyPen.setBrush(grad8); + oxyPen.setCapStyle(Qt::RoundCap); + oxyPen.setJoinStyle(Qt::RoundJoin); + + painter.setPen(oxyPen); +// painter.setPen(grad8); + painter.drawPolygon(questionMark); +// painter.drawRoundRect(0, 0, 6, 1, 0, 0); +// painter.translate(3.5, -2.5); +// painter.setBrush(grad7); +// painter.rotate(90); +// painter.drawRoundRect(0, 0, 6, 1, 0, 0); + painter.restore(); + } + + //light + QPainterPath path3; + path3.addEllipse(1.5, 0.5, 7.0, 6.0); + painter.fillPath(path3, brush3); + + if (type_ == Oxygen::ButtonMax) { + painter.save(); + painter.setBrush(grad8); + painter.translate(2.0, 4.5); + painter.setPen(Qt::NoPen); + painter.drawRoundRect(0, 0, 6, 1, 0, 0); + painter.translate(3.5, -2.5); + painter.setBrush(grad7); + painter.rotate(90); + painter.drawRoundRect(0, 0, 6, 1, 0, 0); + painter.restore(); + } + +// QPainter painter(this); +// +// if (!OxygenFactory::initialized()) return; +// +// QPalette palette; +// int dx, dy; +// +// // paint a plain box with border +// palette = KDecoration::options()->palette(KDecoration::ColorFrame, client_->isActive()); +// painter.fillRect(rect(), palette.button()); +// +// if (type_ == ButtonMenu) { +// // we paint the mini icon (which is 16 pixels high) +// dx = (width() - 16) / 2; +// dy = (height() - 16) / 2; +// //PORT qt4 painter.drawPixmap(dx, dy, client_->icon().pixmap(QIcon::Small, QIcon::Normal)); +// } else { +// // painter->fillRect(rect(), palette.button()); +// int x,y,w,h; +// rect().getRect(&x, &y, &w, &h); +// painter.setBrush(palette.dark()); +// painter.drawEllipse(x, y, w, h); +// +// if (deco_) { +// // otherwise we paint the deco +// dx = (width() - DECOSIZE) / 2; +// dy = (height() - DECOSIZE) / 2; +// painter.setBrush(palette.dark()); +// painter.drawPixmap(dx, dy, *deco_); +// } +// } +} + + + + + + + + +} //namespace Oxygen diff --git a/clients/oxygen/oxygenbutton.h b/clients/oxygen/oxygenbutton.h new file mode 100644 index 0000000000..d9cd467222 --- /dev/null +++ b/clients/oxygen/oxygenbutton.h @@ -0,0 +1,77 @@ +////////////////////////////////////////////////////////////////////////////// +// oxygenbutton.h +// ------------------- +// Oxygen window decoration for KDE. Buttons. +// ------------------- +// Copyright (c) 2006, 2007 Riccardo Iaconelli +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// +// class QAbstractButton; +#ifndef OXYGENBUTTON_H +#define OXYGENBUTTON_H + +#include +class QPainterPath; + +#include "oxygen.h" + +namespace Oxygen +{ +class OxygenClient; + +enum ButtonStatus { + Normal, + Hovered, + Pressed }; + +Q_DECLARE_FLAGS(ButtonState, ButtonStatus); + +class OxygenButton : public QAbstractButton +{ +public: + OxygenButton(OxygenClient *parent=0, + const QString &tip=NULL, + ButtonType type=ButtonHelp, + const unsigned char *bitmap=0); + ~OxygenButton(); + + void setBitmap(const unsigned char *bitmap); + QSize sizeHint() const; + const int lastMousePress(){return lastmouse_;}; + void reset(){repaint();}; + +private: + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + void paintEvent(QPaintEvent *e); + +private Q_SLOTS: + void pressSlot(); + +private: + OxygenClient *client_; + ButtonType type_; + ButtonState status_; + QBitmap *deco_; + int lastmouse_; +}; + +} //namespace Oxygen +#endif diff --git a/clients/oxygen/oxygenclient.cpp b/clients/oxygen/oxygenclient.cpp new file mode 100644 index 0000000000..3552e2885b --- /dev/null +++ b/clients/oxygen/oxygenclient.cpp @@ -0,0 +1,794 @@ +////////////////////////////////////////////////////////////////////////////// +// oxygenclient.cpp +// ------------------- +// Oxygen window decoration for KDE +// ------------------- +// Copyright (c) 2003, 2004 David Johnson +// Copyright (c) 2006, 2007 Casper Boemann +// Copyright (c) 2006, 2007 Riccardo Iaconelli +// +// Please see the header file for copyright and license information. +////////////////////////////////////////////////////////////////////////////// +// #ifndef OXYGENCLIENT_H +// #define OXYGENCLIENT_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "oxygenclient.h" +#include "oxygenclient.moc" +#include "oxygenbutton.h" +#include "oxygen.h" + +#include "definitions.cpp" + +namespace Oxygen +{ + +// global constants + +// static const int BUTTONSIZE = 18; +// static const int DECOSIZE = 8; +// static const int TITLESIZE = 18; +// static const int TFRAMESIZE = 8; +// static const int BFRAMESIZE = 7; +// static const int LFRAMESIZE = 8; +// static const int RFRAMESIZE = 7;BUTTONSIZE +// static const int FRAMEBUTTONSPACE = 67; + + + +void renderDot(QPainter *p, const QPointF &point, qreal diameter) +{ + p->drawEllipse(QRectF(point.x()-diameter/2, point.y()-diameter/2, diameter, diameter)); +} + +// window button decorations +static const unsigned char close_bits[] = { + 0xc3, 0x66, 0x7e, 0x3c, 0x3c, 0x7e, 0x66, 0xc3}; + +static const unsigned char help_bits[] = { + 0x7e, 0x7e, 0x60, 0x78, 0x78, 0x00, 0x18, 0x18}; + +static const unsigned char max_bits[] = { + 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00}; + +static const unsigned char min_bits[] = { +// 0x00, 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00}; + 0x00, 0x00, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00}; + +static const unsigned char minmax_bits[] = { + 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e, 0x00}; + +static const unsigned char stickydown_bits[] = { + 0x00, 0x18, 0x18, 0x7e, 0x7e, 0x18, 0x18, 0x00}; + +static const unsigned char sticky_bits[] = { + 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x00, 0x00, 0x00}; + +////////////////////////////////////////////////////////////////////////////// +// OxygenClient Class // +////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +// OxygenClient() +// --------------- +// Constructor + +OxygenClient::OxygenClient(KDecorationBridge *b, KDecorationFactory *f) + : KDecoration(b, f) { ; } + +OxygenClient::~OxygenClient() +{ + for (int n=0; nsetAutoFillBackground(true); + widget()->installEventFilter(this); + + // setup layout + QGridLayout *mainlayout = new QGridLayout(widget()); + QHBoxLayout *titlelayout = new QHBoxLayout(); + titlebar_ = new QSpacerItem(1, TITLESIZE, QSizePolicy::Expanding, + QSizePolicy::Fixed); + + mainlayout->addItem(new QSpacerItem(LFRAMESIZE, TFRAMESIZE), 0, 0); +// mainlayout->addItem(new QSpacerItem(RFRAMESIZE, BFRAMESIZE), 2, 2); + mainlayout->addItem(new QSpacerItem(0, TFRAMESIZE), 3, 0); + mainlayout->addItem(new QSpacerItem(RFRAMESIZE, 0), 0, 2); + + mainlayout->addLayout(titlelayout, 1, 1); + if (isPreview()) { + mainlayout->addWidget( + new QLabel(i18n("
Oxygen preview! =)
"), + widget()), 2, 1); + } else { + mainlayout->addItem(new QSpacerItem(0, 0), 2, 1); + } + + mainlayout->setRowStretch(2, 10); + mainlayout->setColumnStretch(1, 10); + + // setup titlebar buttons + for (int n=0; naddSpacing(5); + addButtons(titlelayout, options()->titleButtonsLeft()); + titlelayout->addSpacing(15); + titlelayout->addItem(titlebar_); + titlelayout->addSpacing(15); + addButtons(titlelayout, options()->titleButtonsRight()); + titlelayout->addSpacing(5); + + titlelayout->setSpacing(0); + titlelayout->setMargin(0); + mainlayout->setSpacing(0); + mainlayout->setMargin(0); + + setDecoDim(TITLESIZE + TFRAMESIZE, BFRAMESIZE, LFRAMESIZE, RFRAMESIZE); + fallbackDeco = false; + xPic[0] = xPic[1] = xPic[2] = xPic[3] = 0L; + connect (&updateTimer, SIGNAL(timeout()), this, SLOT(updateDecoPics())); + if (!updateTimer.isActive()) + updateTimer.start(250); + +} + +////////////////////////////////////////////////////////////////////////////// +// addButtons() +// ------------ +// Add buttons to title layout + +void OxygenClient::addButtons(QHBoxLayout *layout, const QString& s) +{ + const unsigned char *bitmap; + QString tip; + + if (s.length() > 0) { + for (int n=0; n < s.length(); n++) { + if(n>0) + layout->addSpacing(3); + switch (s[n].toLatin1()) { + case 'M': // Menu button + if (!button[ButtonMenu]) { + button[ButtonMenu] = + new OxygenButton(this, i18n("Menu"), ButtonMenu, 0); + connect(button[ButtonMenu], SIGNAL(pressed()), + this, SLOT(menuButtonPressed())); + layout->addWidget(button[ButtonMenu]); + } + break; + + case 'S': // Sticky button + if (!button[ButtonSticky]) { + if (isOnAllDesktops()) { + bitmap = stickydown_bits; + tip = i18n("Un-Sticky"); + } else { + bitmap = sticky_bits; + tip = i18n("Sticky"); + } + button[ButtonSticky] = + new OxygenButton(this, tip, ButtonSticky, bitmap); + connect(button[ButtonSticky], SIGNAL(clicked()), + this, SLOT(toggleOnAllDesktops())); + layout->addWidget(button[ButtonSticky]); + } + break; + + case 'H': // Help button + if ((!button[ButtonHelp]) && providesContextHelp()) { + button[ButtonHelp] = + new OxygenButton(this, i18n("Help"), ButtonHelp, help_bits); + connect(button[ButtonHelp], SIGNAL(clicked()), + this, SLOT(showContextHelp())); + layout->addWidget(button[ButtonHelp]); + } + break; + + case 'I': // Minimize button + if ((!button[ButtonMin]) && isMinimizable()) { + button[ButtonMin] = + new OxygenButton(this, i18n("Minimize"), ButtonMin, min_bits); + connect(button[ButtonMin], SIGNAL(clicked()), + this, SLOT(minimize())); + layout->addWidget(button[ButtonMin]); + } + break; + + case 'A': // Maximize button + if ((!button[ButtonMax]) && isMaximizable()) { + if (maximizeMode() == MaximizeFull) { + bitmap = minmax_bits; + tip = i18n("Restore"); + } else { + bitmap = max_bits; + tip = i18n("Maximize"); + } + button[ButtonMax] = + new OxygenButton(this, tip, ButtonMax, bitmap); + connect(button[ButtonMax], SIGNAL(clicked()), + this, SLOT(maxButtonPressed())); + layout->addWidget(button[ButtonMax]); + } + break; + + case 'X': // Close button + if ((!button[ButtonClose]) && isCloseable()) { + button[ButtonClose] = + new OxygenButton(this, i18n("Close"), ButtonClose, close_bits); + connect(button[ButtonClose], SIGNAL(clicked()), + this, SLOT(closeWindow())); + layout->addWidget(button[ButtonClose]); + } + break; + + case '_': // Spacer item + layout->addSpacing(FRAMEBUTTONSPACE); + } + } + } +} + +////////////////////////////////////////////////////////////////////////////// +// activeChange() +// -------------- +// window active state has changed + +void OxygenClient::activeChange() +{ + for (int n=0; nreset(); + widget()->repaint(); +} + +////////////////////////////////////////////////////////////////////////////// +// captionChange() +// --------------- +// The title has changed + +void OxygenClient::captionChange() +{ + widget()->repaint(titlebar_->geometry()); +} + +////////////////////////////////////////////////////////////////////////////// +// desktopChange() +// --------------- +// Called when desktop/sticky changes + +void OxygenClient::desktopChange() +{ + bool d = isOnAllDesktops(); + if (button[ButtonSticky]) { + button[ButtonSticky]->setBitmap(d ? stickydown_bits : sticky_bits); + button[ButtonSticky]->setToolTip( d ? i18n("Un-Sticky") : i18n("Sticky")); + } +} + +////////////////////////////////////////////////////////////////////////////// +// iconChange() +// ------------ +// The title has changed + +void OxygenClient::iconChange() +{ + if (button[ButtonMenu]) { + button[ButtonMenu]->setBitmap(0); + button[ButtonMenu]->repaint(); + } +} + +////////////////////////////////////////////////////////////////////////////// +// maximizeChange() +// ---------------- +// Maximized state has changed + +void OxygenClient::maximizeChange() +{ + bool m = (maximizeMode() == MaximizeFull); + if (button[ButtonMax]) { + button[ButtonMax]->setBitmap(m ? minmax_bits : max_bits); + button[ButtonMax]->setToolTip(m ? i18n("Restore") : i18n("Maximize")); + } +} + +////////////////////////////////////////////////////////////////////////////// +// shadeChange() +// ------------- +// Called when window shading changes + +void OxygenClient::shadeChange() +{ ; } + +////////////////////////////////////////////////////////////////////////////// +// borders() +// ---------- +// Get the size of the borders + +void OxygenClient::borders(int &l, int &r, int &t, int &b) const +{ + l = LFRAMESIZE; + r = RFRAMESIZE; + t = TITLESIZE + TFRAMESIZE; + b = BFRAMESIZE; +} + +////////////////////////////////////////////////////////////////////////////// +// resize() +// -------- +// Called to resize the window + +void OxygenClient::resize(const QSize &size) +{ + widget()->resize(size); +} + +////////////////////////////////////////////////////////////////////////////// +// minimumSize() +// ------------- +// Return the minimum allowable size for this window + +QSize OxygenClient::minimumSize() const +{ + return widget()->minimumSize(); +} + +////////////////////////////////////////////////////////////////////////////// +// mousePosition() +// --------------- +// Return logical mouse position + +KDecoration::Position OxygenClient::mousePosition(const QPoint &point) const +{ + const int corner = 24; + Position pos; + + if (point.y() <= TFRAMESIZE) { + // inside top frame + if (point.x() <= corner) pos = PositionTopLeft; + else if (point.x() >= (width()-corner)) pos = PositionTopRight; + else pos = PositionTop; + } else if (point.y() >= (height()-BFRAMESIZE)) { + // inside handle + if (point.x() <= corner) pos = PositionBottomLeft; + else if (point.x() >= (width()-corner)) pos = PositionBottomRight; + else pos = PositionBottom; + } else if (point.x() <= LFRAMESIZE) { + // on left frame + if (point.y() <= corner) pos = PositionTopLeft; + else if (point.y() >= (height()-corner)) pos = PositionBottomLeft; + else pos = PositionLeft; + } else if (point.x() >= width()-RFRAMESIZE) { + // on right frame + if (point.y() <= corner) pos = PositionTopRight; + else if (point.y() >= (height()-corner)) pos = PositionBottomRight; + else pos = PositionRight; + } else { + // inside the frame + pos = PositionCenter; + } + return pos; +} + +////////////////////////////////////////////////////////////////////////////// +// eventFilter() +// ------------- +// Event filter + +bool OxygenClient::eventFilter(QObject *obj, QEvent *e) +{ + if (obj != widget()) return false; + + switch (e->type()) { + case QEvent::MouseButtonDblClick: { + mouseDoubleClickEvent(static_cast(e)); + return true; + } + case QEvent::MouseButtonPress: { + processMousePressEvent(static_cast(e)); + return true; + } + case QEvent::Paint: { + paintEvent(static_cast(e)); + return true; + } + case QEvent::Resize: { + resizeEvent(static_cast(e)); + return true; + } + case QEvent::Show: { + showEvent(static_cast(e)); + return true; + } + default: { + return false; + } + } + + return false; +} + +////////////////////////////////////////////////////////////////////////////// +// mouseDoubleClickEvent() +// ----------------------- +// Doubleclick on title + +void OxygenClient::mouseDoubleClickEvent(QMouseEvent *e) +{ + if (titlebar_->geometry().contains(e->pos())) titlebarDblClickOperation(); +} + +////////////////////////////////////////////////////////////////////////////// +// paintEvent() +// ------------ +// Repaint the window + +void OxygenClient::paintEvent(QPaintEvent *e) +{ + if (!OxygenFactory::initialized()) return; + + doShape(); + + QPalette palette = widget()->palette(); + QPainter painter(widget()); + painter.setRenderHint(QPainter::Antialiasing,true); + + QRect title(titlebar_->geometry()); + + // the background + + updateDecoPics(); + + int x,y,w,h; + + if (fallbackDeco) + painter.fillRect(widget()->rect(), Qt::red); + else { + // explanation if you don't know render syntax: + //------------------------------------------------ + // XRenderComposite (dpy, op, + // src.x11PictureHandle(), mask, dst.x11PictureHandle(), + // sx, sy, mx, my, dx, dy, w, h); + //===================================================== + QRect winRect = widget()->rect(); + winRect.getRect(&x,&y,&w,&h); + x = e->rect().x(); + y = e->rect().y(); + int updW = e->rect().width(); + int updH = e->rect().height(); + + Picture window = widget()->x11PictureHandle(); + // left + if (x < LFRAMESIZE) + XRenderComposite (QX11Info::display(), PictOpSrc, xPic[2], 0, window, + x, y, 0, 0, x, y, qMin(LFRAMESIZE - x, updW), qMin(h - y, updH)); + // right + if (x+updW >= w - RFRAMESIZE - 1) { + int paintW = updW; + if(x < w-RFRAMESIZE-1) + paintW = updW - (w - RFRAMESIZE - 1) + x; + XRenderComposite (QX11Info::display(), PictOpSrc, xPic[3], 0, window, + qMax(x-(w-RFRAMESIZE),0), y, 0, 0, + qMax(x, w-RFRAMESIZE-1), y, paintW, qMin(h - y, updH)); + } + + if (x < LFRAMESIZE) { // don't paint left frame again + updW -= (LFRAMESIZE - x); + x = LFRAMESIZE; + } + if (x + updW > w - RFRAMESIZE) // dont paint right frame again + updW = w - RFRAMESIZE - x; + + // top + if (y < TITLESIZE + TFRAMESIZE) + XRenderComposite (QX11Info::display(), PictOpSrc, xPic[0], 0, window, + x-LFRAMESIZE, y, 0, 0, x, y, updW, qMin(TITLESIZE + TFRAMESIZE - y, updH)); + // bottom + if (y + updH >= h - BFRAMESIZE - 1) { + int paintH = updH; + if(y < h-BFRAMESIZE-1) + paintH = updH - (h - BFRAMESIZE - 1) + y; + XRenderComposite (QX11Info::display(), PictOpSrc, xPic[1], 0, window, + x-LFRAMESIZE, qMax(y-(h-BFRAMESIZE),0), 0, 0, + x, qMax(y, h-BFRAMESIZE-1), updW, paintH); + } + + XFlush(QX11Info::display()); // must be?! - the pictures will change soon + } + + // draw title text + painter.setFont(options()->font(isActive(), false)); + painter.setBrush(palette.windowText()); + painter.drawText(title.x(), title.y(), title.width(), title.height(), + OxygenFactory::titleAlign() | Qt::AlignVCenter, caption()); +#if 0 + // draw frame + QRect frame(0, 0, width(), TFRAMESIZE); + painter.fillRect(frame, palette.window()); + frame.setRect(0, 0, LFRAMESIZE, height()); + painter.fillRect(frame, palette.window()); + frame.setRect(0, height() - BFRAMESIZE, width(), BFRAMESIZE); + painter.fillRect(frame, palette.window()); + frame.setRect(width()-RFRAMESIZE, 0, RFRAMESIZE, height()); + painter.fillRect(frame, palette.window()); +#endif + + // Draw depression lines where the buttons are + QLinearGradient grad1(LFRAMESIZE, TFRAMESIZE + title.height()/2, title.x(), TFRAMESIZE + title.height()/2); + grad1.setColorAt(0.0, QColor(0,0,0,64)); + grad1.setColorAt(1.0, QColor(0,0,0,5)); + QBrush brush1(grad1); + painter.fillRect(LFRAMESIZE, TFRAMESIZE + title.height()/2-1, title.x(), 1, brush1); + QLinearGradient grad2(LFRAMESIZE, TFRAMESIZE + title.height()/2, title.x(), TFRAMESIZE + title.height()/2); + grad2.setColorAt(0.0, QColor(255,255,255,128)); + grad2.setColorAt(1.0, QColor(255,255,255,5)); + QBrush brush2(grad2); + painter.fillRect(LFRAMESIZE, TFRAMESIZE + title.height()/2, title.x(), 1, brush2); + QLinearGradient grad3(width()-RFRAMESIZE, TFRAMESIZE + title.height()/2, title.right(), TFRAMESIZE + title.height()/2); + grad3.setColorAt(0.0, QColor(0,0,0,64)); + grad3.setColorAt(1.0, QColor(0,0,0,5)); + QBrush brush3(grad3); + painter.fillRect(title.right(), TFRAMESIZE + title.height()/2-1, width() - title.right()-RFRAMESIZE, 1, brush3); + QLinearGradient grad4(width()-RFRAMESIZE, TFRAMESIZE + title.height()/2, title.right(), TFRAMESIZE + title.height()/2); + grad4.setColorAt(0.0, QColor(255,255,255,128)); + grad4.setColorAt(1.0, QColor(255,255,255,5)); + QBrush brush4(grad4); + painter.fillRect(title.right(), TFRAMESIZE + title.height()/2, width() -title.right()-RFRAMESIZE, 1, brush4); + + painter.setRenderHint(QPainter::Antialiasing); + + // shadows of the frame + QRect frame = widget()->rect(); + frame.getRect(&x, &y, &w, &h); + + painter.setBrush(Qt::NoBrush); + QLinearGradient lg(0, 0, 0, 10); + QGradientStops stops; + stops << QGradientStop( 0, QColor(255,255,255, 110) ) + << QGradientStop( 1, QColor(128,128,128, 60) ); + lg.setStops(stops); + painter.setPen(QPen(QBrush(lg),1)); + painter.drawLine(QPointF(6.3, 0.5), QPointF(w-6.3, 0.5)); + painter.drawArc(QRectF(0.5, 0.5, 9.5, 9.5),90*16, 90*16); + painter.drawArc(QRectF(w-9.5-0.5, 0.5, 9.5, 9.5), 0, 90*16); + + painter.setPen(QColor(128,128,128, 60)); + painter.drawLine(QPointF(0.5, 6.3), QPointF(0.5, h-6.3)); + painter.drawLine(QPointF(w-0.5, 6.3), QPointF(w-0.5, h-6.3)); + + lg = QLinearGradient(0, h-10, 0, h); + stops.clear(); + stops << QGradientStop( 0, QColor(128,128,128, 60) ) + << QGradientStop( 1, QColor(0,0,0, 50) ); + lg.setStops(stops); + painter.setPen(QPen(QBrush(lg),1)); + painter.drawArc(QRectF(0.5, h-9.5-0.5, 9.5, 9.5),180*16, 90*16); + painter.drawArc(QRectF(w-9.5-0.5, h-9.5-0.5, 9.5, 9.5), 270*16, 90*16); + painter.drawLine(QPointF(6.3, h-0.5), QPointF(w-6.3, h-0.5)); + + qreal cenX = frame.width() / 2 + 0.5; + + painter.setPen(Qt::NoPen); + painter.setBrush(QColor(0, 0, 0, 66)); + renderDot(&painter, QPointF(cenX-10, 2.5), 1); + renderDot(&painter, QPointF(cenX-5, 2.5), 1.5); + renderDot(&painter, QPointF(cenX, 2.5), 2); + renderDot(&painter, QPointF(cenX+5, 2.5), 1.5); + renderDot(&painter, QPointF(cenX+10, 2.5), 1); + + painter.translate(frame.width()-9, frame.height()-9); + renderDot(&painter, QPointF(0.5, 6.5), 2.5); + renderDot(&painter, QPointF(5.5, 5.5), 2.5); + renderDot(&painter, QPointF(6.5, 0.5), 2.5); +} + +void OxygenClient::doShape() +{ + int r=widget()->width(); + int b=widget()->height(); +QRegion mask(0,0,r,b); + // Remove top-left corner. + mask -= QRegion(0, 0, 3, 1); + mask -= QRegion(0, 1, 2, 1); + mask -= QRegion(0, 2, 1, 1); + + // Remove top-right corner. + mask -= QRegion(r - 3, 0, 3, 1); + mask -= QRegion(r - 2, 1, 2, 1); + mask -= QRegion(r - 1, 2, 1, 1); + + // Remove bottom-left corner. + mask -= QRegion(0, b-1-0, 3, b-1-1); + mask -= QRegion(0, b-1-1, 2, b-1-1); + mask -= QRegion(0, b-1-2, 1, b-1-1); + + // Remove bottom-right corner. + mask -= QRegion(r - 3, b-1-0, 3, b-1-1); + mask -= QRegion(r - 2, b-1-1, 2, b-1-1); + mask -= QRegion(r - 1, b-1-2, 1, b-1-1); + + setMask(mask); +} + +////////////////////////////////////////////////////////////////////////////// +// resizeEvent() +// ------------- +// Window is being resized + +void OxygenClient::resizeEvent(QResizeEvent *) +{ + if (widget()->isVisible()) { + QRegion region = widget()->rect(); + region = region.subtract(titlebar_->geometry()); + widget()->update(); + } +} + +////////////////////////////////////////////////////////////////////////////// +// showEvent() +// ----------- +// Window is being shown + +void OxygenClient::showEvent(QShowEvent *) +{ + widget()->repaint(); +} + +////////////////////////////////////////////////////////////////////////////// +// maxButtonPressed() +// ----------------- +// Max button was pressed + +void OxygenClient::maxButtonPressed() +{ + if (button[ButtonMax]) { + switch (button[ButtonMax]->lastMousePress()) { + case Qt::MidButton: + maximize(maximizeMode() ^ MaximizeVertical); + break; + case Qt::RightButton: + maximize(maximizeMode() ^ MaximizeHorizontal); + break; + default: + (maximizeMode() == MaximizeFull) ? maximize(MaximizeRestore) + : maximize(MaximizeFull); + } + } +} + +////////////////////////////////////////////////////////////////////////////// +// menuButtonPressed() +// ------------------- +// Menu button was pressed (popup the menu) + +void OxygenClient::menuButtonPressed() +{ + if (button[ButtonMenu]) { + QPoint p(button[ButtonMenu]->rect().bottomLeft().x(), + button[ButtonMenu]->rect().bottomLeft().y()); + KDecorationFactory* f = factory(); + showWindowMenu(button[ButtonMenu]->mapToGlobal(p)); + if (!f->exists(this)) return; // decoration was destroyed + button[ButtonMenu]->setDown(false); + } +} + +////////////////////////////////////////////////////////////////////////////// +// updateDecoPics() +// ----------------- +// The function queries the X server for the location of the bg pixmaps +// (XRender pictures), provided by the style +// as these pictures can get lost or updated anytime (e.g. if the user +// deselects the oxygen style), it's a slot and bound to a 250ms timer, i.e. +// every quarter second we check if we're still using the proper and if not, +// trigger a repaint + +void OxygenClient::updateDecoPics() +{ + if (readDecoPics()) + widget()->update(); +} + +static const Atom oxygen_deco_top = +XInternAtom(QX11Info::display(), "OXYGEN_DECO_TOP", False); +static const Atom oxygen_deco_bottom = +XInternAtom(QX11Info::display(), "OXYGEN_DECO_BOTTOM", False); +static const Atom oxygen_deco_left = +XInternAtom(QX11Info::display(), "OXYGEN_DECO_LEFT", False); +static const Atom oxygen_deco_right = +XInternAtom(QX11Info::display(), "OXYGEN_DECO_RIGHT", False); + +#define READ_PIC(_ATOM_, _CARD_)\ + result = XGetWindowProperty(QX11Info::display(), windowId(), \ + _ATOM_, 0L, 1L, False, XA_CARDINAL, \ + &actual, &format, &n, &left, &data); \ + if (result == Success && data != None) \ + memcpy (&_CARD_, data, sizeof (unsigned int)); \ + else {\ + _CARD_ = 0; \ + fallbackDeco = true;\ + }// + +// this function reads out the Render Pictures the style should have stacked +// onto the server +//notice that on any read failure, we'll fall back to a simple deco + +bool OxygenClient::readDecoPics() +{ + fallbackDeco = false; + + unsigned char *data = 0; + Atom actual; + int format, result; + unsigned long n, left; + +// DON'T change the order atom -> pixmap + Picture oldPic = xPic[0]; + READ_PIC(oxygen_deco_top, xPic[0]); + if (xPic[0] == oldPic) // there has been NO update + return false; + READ_PIC(oxygen_deco_bottom, xPic[1]); + READ_PIC(oxygen_deco_left, xPic[2]); + READ_PIC(oxygen_deco_right, xPic[3]); + + return true; // has been an update +} + +static const Atom oxygen_decoDim = +XInternAtom(QX11Info::display(), "OXYGEN_DECO_DIM", False); + +// this function tells the deco about how much oversize it should create for +// the bg pixmap (each dim must be < 256) +// it's called in init() and should be recalled whenever the sizes get changed +// for some reason +void OxygenClient::setDecoDim(int top, int bottom, int left, int right) { +// DON'T change the order + int tmp = (top & 0xff) | + ((bottom & 0xff) << 8) | + ((left & 0xff) << 16) | + ((right & 0xff) <<24 ); + XChangeProperty(QX11Info::display(), windowId(), oxygen_decoDim, XA_CARDINAL, + 32, PropModeReplace, (unsigned char *) &(tmp), 1L); +} + +} //namespace Oxygen + +//#include "oxygenclient.moc" + +// #endif diff --git a/clients/oxygen/oxygenclient.desktop b/clients/oxygen/oxygenclient.desktop new file mode 100644 index 0000000000..492d4434a6 --- /dev/null +++ b/clients/oxygen/oxygenclient.desktop @@ -0,0 +1,7 @@ +# KDE Desktop Entry +[Desktop Entry] +Encoding=UTF-8 +Name=Oxygen +Name[vi]=Oxy +Name[xx]=xxOxygenxx +X-KDE-Library=kwin3_oxy diff --git a/clients/oxygen/oxygenclient.h b/clients/oxygen/oxygenclient.h new file mode 100644 index 0000000000..71ad8d7bf6 --- /dev/null +++ b/clients/oxygen/oxygenclient.h @@ -0,0 +1,115 @@ +////////////////////////////////////////////////////////////////////////////// +// oxygenclient.h +// ------------------- +// Oxygen window decoration for KDE +// ------------------- +// Copyright (c) 2003, 2004 David Johnson +// Copyright (c) 2006, 2007 Riccardo Iaconelli +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#ifndef OXYGENCLIENT_H +#define OXYGENCLIENT_H + +// #include +#include +//Added by qt3to4: +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "oxygenbutton.h" +// #include "oxygen.h" + +class QSpacerItem; +class QPoint; + +namespace Oxygen { + +// class OxygenClient; +class OxygenButton; +// OxygenButton ////////////////////////////////////////////////////////////// + + + +// inline int OxygenButton::lastMousePress() const +// { return lastmouse_; } +// +// inline void OxygenButton::reset() +// { repaint(); } + +// OxygenClient ////////////////////////////////////////////////////////////// + +class OxygenClient : public KDecoration +{ + Q_OBJECT +public: + OxygenClient(KDecorationBridge *b, KDecorationFactory *f); + virtual ~OxygenClient(); + + virtual void init(); + + virtual void activeChange(); + virtual void desktopChange(); + virtual void captionChange(); + virtual void iconChange(); + virtual void maximizeChange(); + virtual void shadeChange(); + + virtual void borders(int &l, int &r, int &t, int &b) const; + virtual void resize(const QSize &size); + virtual QSize minimumSize() const; + virtual Position mousePosition(const QPoint &point) const; + +private: + void addButtons(QHBoxLayout* layout, const QString& buttons); + + bool eventFilter(QObject *obj, QEvent *e); + void mouseDoubleClickEvent(QMouseEvent *e); + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *); + void showEvent(QShowEvent *); + void doShape(); + bool readDecoPics(); + void setDecoDim(int top, int bottom, int left, int right); +private slots: + void maxButtonPressed(); + void menuButtonPressed(); + void updateDecoPics(); + +private: + OxygenButton *button[ButtonTypeCount]; + QSpacerItem *titlebar_; + Picture xPic[4]; + bool fallbackDeco; +}; + + +} // namespace Oxygen + +#endif // EXAMPLECLIENT_H diff --git a/clients/oxygen/snippet.cpp b/clients/oxygen/snippet.cpp new file mode 100644 index 0000000000..0e10f5ca69 --- /dev/null +++ b/clients/oxygen/snippet.cpp @@ -0,0 +1,46 @@ +class OxygenWidget : public QWidget +{ +protected: + virtual void paintEvent ( QPaintEvent * event ); +}; + +void OxygenWidget::paintEvent ( QPaintEvent * ) +{ + QPainter painter(this); + + QRadialGradient grad1(QPointF(5.0, 5.0),5.0); + grad1.setColorAt(0.9, QColor(0,0,0,100)); + grad1.setColorAt(1.0, QColor(0,0,0,0)); + QRadialGradient grad2(QPointF(5.0, 5.0),5.0); + grad2.setColorAt(0.0, QColor(235,235,235)); + grad2.setColorAt(1.0, QColor(220,220,220)); + QRadialGradient grad3(QPointF(5.0, 3.75), 3.5,QPointF(5.0, 2.5)); + grad3.setColorAt(0, QColor(255,255,255,50)); + grad3.setColorAt(1, QColor(255,255,255,0)); + QRadialGradient grad4(QPointF(5.0, 3.3), 3.5, QPointF(5.0, 2.1)); + grad4.setColorAt(0, QColor(255,255,255,50)); + grad4.setColorAt(1, QColor(255,255,255,0)); + QBrush brush1(grad1); + QBrush brush2(grad2); + QBrush brush3(grad3); + QBrush brush4(grad4); + + painter.scale(1.6, 1.6); + painter.setRenderHint(QPainter::Antialiasing,true); + + QPainterPath path1; + path1.addEllipse(0.0, 0.0, 10.0, 10.0); + painter.fillPath(path1, brush1); + + QPainterPath path2; + path2.addEllipse(0.5, 0.5, 9.0, 9.0); + painter.fillPath(path2, brush2); + + QPainterPath path3; + path3.addEllipse(1.5, 0.5, 7.0, 6.0); + painter.fillPath(path3, brush3); + + QPainterPath path4; + path4.addEllipse(1.5, 0.5, 7.0, 6.0); + painter.fillPath(path4, brush4); +}