Back to index

kdeartwork  4.3.2
Manager.cpp
Go to the documentation of this file.
00001 /*
00002   RISC OS KWin client
00003 
00004   Copyright 2000
00005     Rik Hemsley <rik@kde.org>
00006 
00007   This program is free software; you can redistribute it and/or
00008   modify it under the terms of the GNU General Public
00009   License as published by the Free Software Foundation; either
00010   version 2 of the License, or (at your option) any later version.
00011 
00012   This program is distributed in the hope that it will be useful,
00013   but WITHOUT ANY WARRANTY; without even the implied warranty of
00014   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015   General Public License for more details.
00016 
00017   You should have received a copy of the GNU General Public License
00018   along with this program; see the file COPYING.  If not, write to
00019   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020   Boston, MA 02110-1301, USA.
00021 */
00022 
00023 #include <unistd.h> // for usleep
00024 #include <config.h> // for usleep on non-linux platforms
00025 #include <math.h> // for sin and cos
00026 
00027 #include <qapplication.h>
00028 #include <qimage.h>
00029 #include <qlabel.h>
00030 #include <qlayout.h>
00031 #include <qpainter.h>
00032 //Added by qt3to4:
00033 #include <QPaintEvent>
00034 #include <Q3PtrList>
00035 #include <QEvent>
00036 #include <QBoxLayout>
00037 #include <QResizeEvent>
00038 #include <QVBoxLayout>
00039 #include <QMouseEvent>
00040 
00041 #include <netwm.h>
00042 
00043 #include "Manager.h"
00044 #include "Static.h"
00045 #include "AboveButton.h"
00046 #include "CloseButton.h"
00047 #include "HelpButton.h"
00048 #include "IconifyButton.h"
00049 #include "LowerButton.h"
00050 #include "MaximiseButton.h"
00051 #include "StickyButton.h"
00052 
00053 extern "C"
00054 {
00055    KDE_EXPORT KDecorationFactory* create_factory()
00056    {
00057       return new RiscOS::Factory();
00058    }
00059 }
00060 
00061 
00062 namespace RiscOS
00063 {
00064 
00065 Manager::Manager(KDecorationBridge *bridge,
00066                  KDecorationFactory *factory)
00067   : KDecoration(bridge, factory),
00068     topLayout_    (NULL),
00069     titleLayout_  (NULL),
00070     titleSpacer_  (NULL)
00071 {
00072 }
00073 
00074 Manager::~Manager()
00075 {
00076 }
00077 
00078 void Manager::init()
00079 {
00080    createMainWidget(WNoAutoErase);
00081 
00082    widget()->installEventFilter(this);
00083    widget()->setBackgroundMode(NoBackground);
00084 
00085    leftButtonList_.setAutoDelete(true);
00086    rightButtonList_.setAutoDelete(true);
00087 
00088    resetLayout();
00089 }
00090 
00091 bool Manager::eventFilter(QObject *o, QEvent *e)
00092 {
00093    if (o != widget()) return false;
00094    switch (e->type())
00095    {
00096       case QEvent::Resize:
00097          resizeEvent(static_cast<QResizeEvent*>(e));
00098          return true;
00099       case QEvent::Paint:
00100          paintEvent(static_cast<QPaintEvent*>(e));
00101          return true;
00102       case QEvent::MouseButtonDblClick:
00103          mouseDoubleClickEvent(static_cast<QMouseEvent*>(e));
00104          return true;
00105       case QEvent::MouseButtonPress:
00106          processMousePressEvent(static_cast<QMouseEvent*>(e));
00107          return true;
00108       case QEvent::MouseButtonRelease:
00109          return false;
00110       case QEvent::Show:
00111          return false;
00112       case QEvent::MouseMove:
00113          return false;
00114       case QEvent::Enter:
00115          return false;
00116       case QEvent::Leave:
00117          return false;
00118       case QEvent::Move:
00119          return false;
00120       default:
00121          return false;
00122    }
00123 }
00124 
00125 void Manager::reset(unsigned long /*changed*/)
00126 {
00127    resetLayout();
00128 }
00129 
00130 void Manager::borders(int &left, int &right, int &top, int &bottom) const
00131 {
00132    left = right = 1;
00133    top = Static::instance()->titleHeight();
00134    bottom = isResizable() ? Static::instance()->resizeHeight() : 1;
00135 }
00136 
00137 void Manager::resize(const QSize &s)
00138 {
00139    widget()->resize(s);
00140 }
00141 
00142 QSize Manager::minimumSize() const
00143 {
00144    return widget()->minimumSize();
00145 }
00146 
00147 void Manager::activeChange()
00148 {
00149    updateTitleBuffer();
00150    widget()->repaint();
00151    emit(activeChanged(isActive()));
00152 }
00153 
00154 void Manager::captionChange()
00155 {
00156    updateTitleBuffer();
00157    widget()->repaint();
00158 }
00159 
00160 void Manager::iconChange()
00161 {
00162 }
00163 
00164 void Manager::maximizeChange()
00165 {
00166    emit(maximizeChanged(maximizeMode() == MaximizeFull));
00167 }
00168 
00169 void Manager::desktopChange()
00170 {
00171 }
00172 
00173 void Manager::shadeChange()
00174 {
00175 }
00176 
00177 void Manager::paintEvent(QPaintEvent *e)
00178 {
00179    QPainter p(widget());
00180 
00181    QRect r(e->rect());
00182 
00183    bool intersectsLeft = r.intersects(QRect(0, 0, 1, height()));
00184 
00185    bool intersectsRight =
00186       r.intersects(QRect(width() - 1, 0, width(), height()));
00187 
00188    if (intersectsLeft || intersectsRight)
00189    {
00190       p.setPen(Qt::black);
00191 
00192       if (intersectsLeft)
00193          p.drawLine(0, r.top(), 0, r.bottom());
00194 
00195       if (intersectsRight)
00196          p.drawLine(width() - 1, r.top(), width() - 1, r.bottom());
00197    }
00198 
00199    Static * s = Static::instance();
00200 
00201    bool active = isActive();
00202 
00203    // Title bar.
00204 
00205    QRect tr = titleSpacer_->geometry();
00206    bitBlt(widget(), tr.topLeft(), &titleBuf_);
00207 
00208    // Resize bar.
00209 
00210    if (isResizable())
00211    {
00212       int rbt = height() - Static::instance()->resizeHeight(); // Resize bar top
00213 
00214       bitBlt(widget(), 0, rbt, &(s->resize(active)));
00215       bitBlt(widget(), 30, rbt, &(s->resizeMidLeft(active)));
00216 
00217       p.drawTiledPixmap(32, rbt, width() - 34,
00218                         Static::instance()->resizeHeight(),
00219                         s->resizeMidMid(active));
00220 
00221       bitBlt(widget(), width() - 32, rbt, &(s->resizeMidRight(active)));
00222       bitBlt(widget(), width() - 30, rbt, &(s->resize(active)));
00223    }
00224    else
00225       p.drawLine(1, height() - 1, width() - 2, height() - 1);
00226 }
00227 
00228 void Manager::resizeEvent(QResizeEvent*)
00229 {
00230    updateButtonVisibility();
00231    updateTitleBuffer();
00232    widget()->repaint();
00233 }
00234 
00235 void Manager::updateButtonVisibility()
00236 {
00237 #if 0
00238    enum SizeProblem = { None, Small, Medium, Big };
00239    SizeProblem sizeProblem = None;
00240 
00241    if (width() < 80) sizeProblem = Big;
00242    else if (width() < 100) sizeProblem = Medium;
00243    else if (width() < 180) sizeProblem = Small;
00244 
00245    switch (sizeProblem) {
00246 
00247       case Small:
00248          above_    ->hide();
00249          lower_    ->hide();
00250          sticky_   ->hide();
00251          help_     ->hide();
00252          iconify_  ->show();
00253          maximise_ ->hide();
00254          close_    ->show();
00255          break;
00256 
00257       case Medium:
00258          above_    ->hide();
00259          lower_    ->hide();
00260          sticky_   ->hide();
00261          help_     ->hide();
00262          iconify_  ->hide();
00263          maximise_ ->hide();
00264          close_    ->show();
00265          break;
00266 
00267       case Big:
00268          above_    ->hide();
00269          lower_    ->hide();
00270          sticky_   ->hide();
00271          help_     ->hide();
00272          iconify_  ->hide();
00273          maximise_ ->hide();
00274          close_    ->hide();
00275          break;
00276 
00277       case None:
00278       default:
00279          above_    ->show();
00280          lower_    ->show();
00281          sticky_   ->show();
00282          if (providesContextHelp())
00283            help_->show();
00284          iconify_  ->show();
00285          maximise_ ->show();
00286          close_    ->show();
00287          break;
00288    }
00289 
00290    layout()->activate();
00291 #endif
00292 }
00293 
00294 void Manager::updateTitleBuffer()
00295 {
00296    bool active = isActive();
00297 
00298    Static * s = Static::instance();
00299 
00300    QRect tr = titleSpacer_->geometry();
00301 
00302    if (tr.width() == 0 || tr.height() == 0)
00303       titleBuf_.resize(8, 8);
00304    else
00305       titleBuf_.resize(tr.size());
00306 
00307    QPainter p(&titleBuf_);
00308 
00309    p.drawPixmap(0, 0, s->titleTextLeft(active));
00310 
00311    p.drawTiledPixmap(3, 0, tr.width() - 6, Static::instance()->titleHeight(),
00312                      s->titleTextMid(active));
00313 
00314    p.setPen(options()->color(KDecorationOptions::ColorFont, active));
00315 
00316    p.setFont(options()->font(active));
00317 
00318    p.drawText(4, 2, tr.width() - 8, Static::instance()->titleHeight() - 4,
00319               Qt::AlignCenter, caption());
00320 
00321    p.drawPixmap(tr.width() - 3, 0, s->titleTextRight(active));
00322 }
00323 
00324 KDecoration::Position Manager::mousePosition(const QPoint& p) const
00325 {
00326    Position m = PositionCenter;
00327 
00328    // Look out for off-by-one errors here.
00329 
00330    if (isResizable())
00331    {
00332       if (p.y() > (height() - (Static::instance()->resizeHeight() + 1)))
00333       {
00334         // Keep order !
00335 
00336          if (p.x() >= (width() - 30))
00337             m = PositionBottomRight;
00338          else if (p.x() <= 30)
00339             m = PositionBottomLeft;
00340          else
00341             m = PositionBottom;
00342       }
00343       else
00344       {
00345          m = PositionCenter;
00346          // Client::mousePosition(p);
00347       }
00348    }
00349    else
00350    {
00351       m = PositionCenter;
00352       // Client::mousePosition(p);
00353    }
00354 
00355    return m;
00356 }
00357 
00358 void Manager::mouseDoubleClickEvent(QMouseEvent *e)
00359 {
00360    if (e->button() == Qt::LeftButton && titleSpacer_->geometry().contains(e->pos()))
00361       titlebarDblClickOperation();
00362 }
00363 
00364 void Manager::paletteChange(const QPalette &)
00365 {
00366    resetLayout();
00367 }
00368 
00369 void Manager::stickyChange(bool b)
00370 {
00371    emit(stickyChanged(b));
00372 }
00373 
00374 void Manager::slotToggleSticky()
00375 {
00376    toggleOnAllDesktops();
00377    emit(stickyChanged(isOnAllDesktops()));
00378 }
00379 
00380 void Manager::slotAbove()
00381 {
00382    setKeepAbove(!keepAbove());
00383 }
00384 
00385 void Manager::slotLower()
00386 {
00387    setKeepBelow(!keepBelow());
00388 }
00389 
00390 void Manager::slotMaximizeClicked(Qt::MouseButton state)
00391 {
00392    maximize(state);
00393    emit(maximizeChanged(maximizeMode() == MaximizeFull));
00394 }
00395 
00396 bool Manager::animateMinimize(bool iconify)
00397 {
00398    int style = Static::instance()->animationStyle();
00399 
00400    switch (style)
00401    {
00402       case 1:
00403       {
00404          // Double twisting double back, with pike ;)
00405 
00406          if (!iconify) // No animation for restore.
00407             return true;
00408 
00409          // Go away quick.
00410          helperShowHide(false);
00411          qApp->syncX();
00412 
00413          QRect r = iconGeometry();
00414 
00415          if (!r.isValid())
00416             return true;
00417 
00418          // Algorithm taken from Window Maker (http://www.windowmaker.org)
00419 
00420          int sx = geometry().x();
00421          int sy = geometry().y();
00422          int sw = width();
00423          int sh = height();
00424          int dx = r.x();
00425          int dy = r.y();
00426          int dw = r.width();
00427          int dh = r.height();
00428 
00429          double steps = 12;
00430 
00431          double xstep = double((dx-sx)/steps);
00432          double ystep = double((dy-sy)/steps);
00433          double wstep = double((dw-sw)/steps);
00434          double hstep = double((dh-sh)/steps);
00435 
00436          double cx = sx;
00437          double cy = sy;
00438          double cw = sw;
00439          double ch = sh;
00440 
00441          double finalAngle = 3.14159265358979323846;
00442 
00443          double delta  = finalAngle / steps;
00444 
00445          QPainter p(workspaceWidget());
00446          p.setRasterOp(Qt::NotROP);
00447 
00448          for (double angle = 0; ; angle += delta)
00449          {
00450             if (angle > finalAngle)
00451                angle = finalAngle;
00452 
00453             double dx = (cw / 10) - ((cw / 5) * sin(angle));
00454             double dch = (ch / 2) * cos(angle);
00455             double midy = cy + (ch / 2);
00456 
00457             QPoint p1(int(cx + dx), int(midy - dch));
00458             QPoint p2(int(cx + cw - dx), p1.y());
00459             QPoint p3(int(cx + dw + dx), int(midy + dch));
00460             QPoint p4(int(cx - dx), p3.y());
00461 
00462             grabXServer();
00463 
00464             p.drawLine(p1, p2);
00465             p.drawLine(p2, p3);
00466             p.drawLine(p3, p4);
00467             p.drawLine(p4, p1);
00468 
00469             p.flush();
00470 
00471             usleep(500);
00472 
00473             p.drawLine(p1, p2);
00474             p.drawLine(p2, p3);
00475             p.drawLine(p3, p4);
00476             p.drawLine(p4, p1);
00477 
00478             ungrabXServer();
00479 
00480             cx += xstep;
00481             cy += ystep;
00482             cw += wstep;
00483             ch += hstep;
00484 
00485             if (angle >= finalAngle)
00486                break;
00487          }
00488       }
00489       break;
00490 
00491       case 2:
00492       {
00493          // KVirc style ? Maybe. For qwertz.
00494 
00495          if (!iconify) // No animation for restore.
00496             return true;
00497 
00498          // Go away quick.
00499          helperShowHide(false);
00500          qApp->syncX();
00501 
00502          int stepCount = 12;
00503 
00504          QRect r(geometry());
00505 
00506          int dx = r.width() / (stepCount * 2);
00507          int dy = r.height() / (stepCount * 2);
00508 
00509          QPainter p(workspaceWidget());
00510          p.setRasterOp(Qt::NotROP);
00511 
00512          for (int step = 0; step < stepCount; step++)
00513          {
00514             r.moveBy(dx, dy);
00515             r.setWidth(r.width() - 2 * dx);
00516             r.setHeight(r.height() - 2 * dy);
00517 
00518             grabXServer();
00519 
00520             p.drawRect(r);
00521             p.flush();
00522             usleep(200);
00523             p.drawRect(r);
00524 
00525             ungrabXServer();
00526          }
00527       }
00528       break;
00529 
00530 
00531       default:
00532       {
00533          QRect icongeom = iconGeometry();
00534 
00535          if (!icongeom.isValid())
00536             return true;
00537 
00538          QRect wingeom = geometry();
00539 
00540          QPainter p(workspaceWidget());
00541 
00542          p.setRasterOp(Qt::NotROP);
00543 #if 0
00544          if (iconify)
00545             p.setClipRegion(QRegion(workspaceWidget()->rect()) - wingeom);
00546 #endif
00547          grabXServer();
00548 
00549          p.drawLine(wingeom.bottomRight(), icongeom.bottomRight());
00550          p.drawLine(wingeom.bottomLeft(), icongeom.bottomLeft());
00551          p.drawLine(wingeom.topLeft(), icongeom.topLeft());
00552          p.drawLine(wingeom.topRight(), icongeom.topRight());
00553 
00554          p.flush();
00555 
00556          qApp->syncX();
00557 
00558          usleep(30000);
00559 
00560          p.drawLine(wingeom.bottomRight(), icongeom.bottomRight());
00561          p.drawLine(wingeom.bottomLeft(), icongeom.bottomLeft());
00562          p.drawLine(wingeom.topLeft(), icongeom.topLeft());
00563          p.drawLine(wingeom.topRight(), icongeom.topRight());
00564 
00565          ungrabXServer();
00566       }
00567       break;
00568    }
00569    return true;
00570 }
00571 
00572 void Manager::createTitle()
00573 {
00574    leftButtonList_.clear();
00575    rightButtonList_.clear();
00576 
00577    QString buttons;
00578 
00579    if (options()->customButtonPositions())
00580       buttons = options()->titleButtonsLeft() + "|" +
00581                 options()->titleButtonsRight();
00582    else
00583       buttons = "XSH|IA";
00584 
00585    Q3PtrList<Button> *buttonList = &leftButtonList_;
00586 
00587    for (unsigned int i = 0; i < buttons.length(); ++i)
00588    {
00589       Button * tb = NULL;
00590 
00591       switch (buttons[i].latin1())
00592       {
00593          case 'S': // Sticky
00594             tb = new StickyButton(widget());
00595             connect(this, SIGNAL(stickyChanged(bool)),
00596                     tb, SLOT(setOn(bool)));
00597             connect(tb, SIGNAL(toggleSticky()), this, SLOT(slotToggleSticky()));
00598             emit(stickyChanged(isOnAllDesktops()));
00599             break;
00600 
00601          case 'H': // Help
00602             if (providesContextHelp())
00603             {
00604                tb = new HelpButton(widget());
00605                connect(tb, SIGNAL(help()), this, SLOT(showContextHelp()));
00606             }
00607             break;
00608 
00609          case 'I': // Minimize
00610             if (isMinimizable())
00611             {
00612                tb = new IconifyButton(widget());
00613                connect(tb, SIGNAL(iconify()), this, SLOT(minimize()));
00614             }
00615             break;
00616 
00617          case 'A': // Maximize
00618             if (isMaximizable())
00619             {
00620                tb = new MaximiseButton(widget());
00621                connect(tb, SIGNAL(maximizeClicked(MouseButton)),
00622                        this, SLOT(slotMaximizeClicked(MouseButton)));
00623                connect(this, SIGNAL(maximizeChanged(bool)),
00624                        tb, SLOT(setOn(bool)));
00625                emit(maximizeChanged(maximizeMode() == MaximizeFull));
00626             }
00627             break;
00628 
00629          case 'F': // Above
00630             tb = new AboveButton(widget());
00631             connect(tb, SIGNAL(above()), this, SLOT(slotAbove()));
00632             break;
00633 
00634          case 'B': // Lower
00635             tb = new LowerButton(widget());
00636             connect(tb, SIGNAL(lower()), this, SLOT(slotLower()));
00637             break;
00638 
00639          case 'X': // Close
00640             if (isCloseable())
00641             {
00642                tb = new CloseButton(widget());
00643                connect(tb, SIGNAL(closeWindow()), this, SLOT(closeWindow()));
00644             }
00645             break;
00646 
00647          case '|':
00648             buttonList = &rightButtonList_;
00649             break;
00650       }
00651 
00652       if (tb != NULL)
00653       {
00654          connect(this, SIGNAL(activeChanged(bool)), tb, SLOT(setActive(bool)));
00655          buttonList->append(tb);
00656       }
00657    }
00658 
00659    for (Q3PtrListIterator<Button> it(leftButtonList_); it.current(); ++it)
00660    {
00661       it.current()->setAlignment(Button::Left);
00662       titleLayout_->addWidget(it.current());
00663    }
00664 
00665    titleSpacer_ = new QSpacerItem(0, Static::instance()->titleHeight(),
00666                                   QSizePolicy::Expanding, QSizePolicy::Fixed);
00667 
00668    titleLayout_->addItem(titleSpacer_);
00669 
00670    for (Q3PtrListIterator<Button> it(rightButtonList_); it.current(); ++it)
00671    {
00672       it.current()->setAlignment(Button::Right);
00673       titleLayout_->addWidget(it.current());
00674    }
00675 }
00676 
00677 void Manager::resetLayout()
00678 {
00679    delete topLayout_;
00680    topLayout_ = new QVBoxLayout(widget(), 0, 0);
00681    topLayout_->setResizeMode(QLayout::FreeResize);
00682 
00683    titleLayout_ = new QBoxLayout(topLayout_, QBoxLayout::LeftToRight, 0, 0);
00684    titleLayout_->setResizeMode(QLayout::FreeResize);
00685 
00686    createTitle();
00687 
00688    QBoxLayout *midLayout = new QBoxLayout(topLayout_, QBoxLayout::LeftToRight,
00689                                           0, 0);
00690    midLayout->setResizeMode(QLayout::FreeResize);
00691    midLayout->addSpacing(1);
00692    if (isPreview())
00693       midLayout->addWidget(
00694          new QLabel(i18n("<center><b>RiscOS preview</b></center>"), widget()));
00695    midLayout->addSpacing(1);
00696 
00697    if (isResizable())
00698       topLayout_->addSpacing(Static::instance()->resizeHeight());
00699    else
00700       topLayout_->addSpacing(1);
00701 }
00702 
00703 // --------------------
00704 
00705 Factory::Factory()
00706 {
00707    (void) RiscOS::Static::instance();
00708 }
00709 
00710 Factory::~Factory()
00711 {
00712    delete RiscOS::Static::instance();
00713 }
00714 
00715 bool Factory::reset(unsigned long /*changed*/)
00716 {
00717    RiscOS::Static::instance()->reset();
00718    return true;
00719 }
00720 
00721 bool Factory::supports( Ability ability )
00722 {
00723     switch( ability )
00724     {
00725         case AbilityAnnounceButtons:
00726         case AbilityButtonOnAllDesktops:
00727         case AbilityButtonHelp:
00728         case AbilityButtonMinimize:
00729         case AbilityButtonMaximize:
00730         case AbilityButtonClose:
00731         case AbilityButtonAboveOthers:
00732         case AbilityButtonBelowOthers:
00733             return true;
00734         default:
00735             return false;
00736     };
00737 }
00738 
00739 KDecoration* Factory::createDecoration(KDecorationBridge *bridge)
00740 {
00741    return new Manager(bridge, this);
00742 }
00743 
00744 } // End namespace
00745 
00746 // vim:ts=2:sw=2:tw=78
00747 #include "Manager.moc"