kwin Library API Documentation

Web.cpp

00001 /*
00002   'Web' kwin client
00003 
00004   Copyright (C) 2001 Rik Hemsley (rikkus) <rik@kde.org>
00005 
00006   This program is free software; you can redistribute it and/or
00007   modify it under the terms of the GNU General Public
00008   License as published by the Free Software Foundation; either
00009   version 2 of the License, or (at your option) any later version.
00010 
00011   This program is distributed in the hope that it will be useful,
00012   but WITHOUT ANY WARRANTY; without even the implied warranty of
00013   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014   General Public License for more details.
00015 
00016   You should have received a copy of the GNU General Public License
00017   along with this program; see the file COPYING.  If not, write to
00018   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00019   Boston, MA 02111-1307, USA.
00020 */
00021 
00022 #include <qlabel.h>
00023 #include <qlayout.h>
00024 #include <qpainter.h>
00025 
00026 #include <kconfig.h>
00027 
00028 #include "Web.h"
00029 #include "WebButton.h"
00030 #include "WebButtonHelp.h"
00031 #include "WebButtonIconify.h" // minimize button
00032 #include "WebButtonClose.h"
00033 #include "WebButtonSticky.h" // onAllDesktops button
00034 #include "WebButtonMaximize.h"
00035 #include "WebButtonLower.h"
00036 
00037 extern "C"
00038 {
00039   KDE_EXPORT KDecorationFactory *create_factory()
00040   {
00041     return new Web::WebFactory();
00042   }
00043 }
00044 
00045 namespace Web {
00046 
00047 WebClient::WebClient(KDecorationBridge* bridge, KDecorationFactory* factory)
00048   : KDecoration(bridge, factory),
00049     mainLayout_   (0),
00050     titleSpacer_  (0)
00051 {
00052   // Empty.
00053 }
00054 
00055 WebClient::~WebClient()
00056 {
00057   // Empty.
00058 }
00059 
00060   void
00061 WebClient::init()
00062 {
00063   createMainWidget(WNoAutoErase);
00064   widget()->installEventFilter( this );
00065   widget()->setBackgroundMode(NoBackground);
00066 
00067   // title height
00068   const int textVMargin   = 2;
00069   QFontMetrics fm(options()->font(isActive(), isTool()));
00070 
00071   // border size
00072   switch(options()->preferredBorderSize( factory())) {
00073     case BorderLarge:
00074       borderSize_ = 8;
00075       break;
00076     case BorderVeryLarge:
00077       borderSize_ = 12;
00078       break;
00079     case BorderHuge:
00080       borderSize_ = 18;
00081       break;
00082     case BorderVeryHuge:
00083       borderSize_ = 27;
00084       break;
00085     case BorderOversized:
00086       borderSize_ = 40;
00087       break;
00088     case BorderNormal:
00089     default:
00090       borderSize_ = 4;
00091   }
00092   titleHeight_ = QMAX(QMAX(14, fm.height() + textVMargin * 2), borderSize_);
00093 
00094   _resetLayout();
00095 
00096   leftButtonList_   .setAutoDelete(true);
00097   rightButtonList_  .setAutoDelete(true);
00098 }
00099 
00100   void
00101 WebClient::reset( unsigned long changed )
00102 {
00103   if (changed & SettingColors)
00104   {
00105     // repaint the whole thing
00106     widget()->repaint(false);
00107   } else if (changed & SettingFont) {
00108     // font has changed -- update title height
00109     // title height
00110     const uint textVMargin   = 2;
00111     QFontMetrics fm(options()->font(isActive(), isTool()));
00112     titleHeight_ = QMAX(14, fm.height() + textVMargin * 2);
00113     // update buttons
00114     for (QPtrListIterator<WebButton> it(leftButtonList_); it.current(); ++it)
00115     {
00116       it.current()->setFixedSize(titleHeight_, titleHeight_);
00117     }
00118     for (QPtrListIterator<WebButton> it(rightButtonList_); it.current(); ++it)
00119     {
00120       it.current()->setFixedSize(titleHeight_, titleHeight_);
00121     }
00122 //     for (int n=0; n<NumButtons; n++) {
00123 //         if (m_button[n]) m_button[n]->setSize(s_titleHeight-1);
00124 //     }
00125     // update the spacer
00126     titleSpacer_->changeSize(0, titleHeight_, QSizePolicy::Expanding,
00127                              QSizePolicy::Fixed);
00128     widget()->repaint(false);
00129   }
00130 }
00131 
00132   void
00133 WebClient::resizeEvent(QResizeEvent *)
00134 {
00135   doShape();
00136   widget()->repaint();
00137 }
00138 
00139   void
00140 WebClient::captionChange()
00141 {
00142   widget()->repaint();
00143 }
00144 
00145 void WebClient::iconChange()
00146 {
00147 // Empty.
00148 }
00149 
00150   void
00151 WebClient::paintEvent(QPaintEvent * pe)
00152 {
00153   QRect titleRect(titleSpacer_->geometry());
00154   titleRect.setTop(1);
00155 
00156   QPainter p(widget());
00157 
00158   p.setPen(Qt::black);
00159   p.setBrush(options()->colorGroup(ColorFrame, isActive()).background());
00160 
00161   p.setClipRegion(pe->region() - titleRect);
00162 
00163   p.drawRect(widget()->rect());
00164 
00165   p.setClipRegion(pe->region());
00166 
00167   p.fillRect(titleRect, options()->color(ColorTitleBar, isActive()));
00168 
00169   if (shape_)
00170   {
00171     int r(width());
00172     int b(height());
00173 
00174     // Draw edge of top-left corner inside the area removed by the mask.
00175 
00176     p.drawPoint(3, 1);
00177     p.drawPoint(4, 1);
00178     p.drawPoint(2, 2);
00179     p.drawPoint(1, 3);
00180     p.drawPoint(1, 4);
00181 
00182     // Draw edge of top-right corner inside the area removed by the mask.
00183 
00184     p.drawPoint(r - 5, 1);
00185     p.drawPoint(r - 4, 1);
00186     p.drawPoint(r - 3, 2);
00187     p.drawPoint(r - 2, 3);
00188     p.drawPoint(r - 2, 4);
00189 
00190     // Draw edge of bottom-left corner inside the area removed by the mask.
00191 
00192     p.drawPoint(1, b - 5);
00193     p.drawPoint(1, b - 4);
00194     p.drawPoint(2, b - 3);
00195     p.drawPoint(3, b - 2);
00196     p.drawPoint(4, b - 2);
00197 
00198     // Draw edge of bottom-right corner inside the area removed by the mask.
00199 
00200     p.drawPoint(r - 2, b - 5);
00201     p.drawPoint(r - 2, b - 4);
00202     p.drawPoint(r - 3, b - 3);
00203     p.drawPoint(r - 4, b - 2);
00204     p.drawPoint(r - 5, b - 2);
00205   }
00206 
00207   p.setFont(options()->font(isActive(), isTool()));
00208 
00209   p.setPen(options()->color(ColorFont, isActive()));
00210 
00211   p.drawText(titleSpacer_->geometry(), AlignCenter, caption());
00212 }
00213 
00214   void
00215 WebClient::doShape()
00216 {
00217   if (!shape_)
00218     return;
00219 
00220   QRegion mask(0, 0, width(), height());
00221 
00222   int r(width());
00223   int b(height());
00224 
00225   // Remove top-left corner.
00226 
00227   mask -= QRegion(0, 0, 5, 1);
00228   mask -= QRegion(0, 1, 3, 1);
00229   mask -= QRegion(0, 2, 2, 1);
00230   mask -= QRegion(0, 3, 1, 2);
00231 
00232   // Remove top-right corner.
00233 
00234   mask -= QRegion(r - 5, 0, 5, 1);
00235   mask -= QRegion(r - 3, 1, 3, 1);
00236   mask -= QRegion(r - 2, 2, 2, 1);
00237   mask -= QRegion(r - 1, 3, 1, 2);
00238 
00239   // Remove bottom-left corner.
00240 
00241   mask -= QRegion(0, b - 5, 1, 3);
00242   mask -= QRegion(0, b - 3, 2, 1);
00243   mask -= QRegion(0, b - 2, 3, 1);
00244   mask -= QRegion(0, b - 1, 5, 1);
00245 
00246   // Remove bottom-right corner.
00247 
00248   mask -= QRegion(r - 5, b - 1, 5, 1);
00249   mask -= QRegion(r - 3, b - 2, 3, 1);
00250   mask -= QRegion(r - 2, b - 3, 2, 1);
00251   mask -= QRegion(r - 1, b - 5, 1, 2);
00252 
00253   setMask(mask);
00254 }
00255 
00256   void
00257 WebClient::showEvent(QShowEvent *)
00258 {
00259   doShape();
00260   widget()->repaint();
00261 }
00262 
00263   void
00264 WebClient::windowWrapperShowEvent(QShowEvent *)
00265 {
00266   doShape();
00267   widget()->repaint();
00268 }
00269 
00270   void
00271 WebClient::mouseDoubleClickEvent(QMouseEvent * e)
00272 {
00273   if (titleSpacer_->geometry().contains(e->pos()))
00274   {
00275     titlebarDblClickOperation();
00276   }
00277 }
00278 
00279   void
00280 WebClient::desktopChange()
00281 {
00282   emit(oadChange(isOnAllDesktops()));
00283 }
00284 
00285   void
00286 WebClient::maximizeChange()
00287 {
00288   emit(maxChange(maximizeMode()==MaximizeFull));
00289 }
00290 
00291   void
00292 WebClient::activeChange()
00293 {
00294   widget()->repaint();
00295 }
00296 
00297   WebClient::Position
00298 WebClient::mousePosition(const QPoint & p) const
00299 {
00300   int x = p.x();
00301   int y = p.y();
00302   int corner = 14 + 3*borderSize_/2;
00303 
00304   if (y < titleSpacer_->geometry().height())
00305   {
00306     // rikkus: this style is not designed to be resizable at the top edge.
00307 
00308 #if 0
00309     if ((y < 4 && x < corner) || x < 4)
00310       return Client::TopLeft;
00311     else if ((y < 4 && x > width() - corner) || x > width() - 4)
00312       return Client::TopRight;
00313     else if (y < 4)
00314       return Client::Top;
00315     else
00316 #endif
00317       return KDecoration::PositionCenter;
00318   }
00319   else if (y < height() - borderSize_)
00320   {
00321     if (x < borderSize_)
00322       return KDecoration::PositionLeft;
00323     else
00324       if (x > width() - borderSize_)
00325         return KDecoration::PositionRight;
00326       else
00327         return KDecoration::PositionCenter;
00328   }
00329   else
00330   {
00331     if (x < 12 + corner)
00332       return KDecoration::PositionBottomLeft;
00333     else
00334       if (x > width() - corner)
00335         return KDecoration::PositionBottomRight;
00336       else
00337         return KDecoration::PositionBottom;
00338   }
00339 
00340   return KDecoration::mousePosition(p);
00341 }
00342 
00343   void
00344 WebClient::slotMaximize(int button)
00345 {
00346   maximize( static_cast<ButtonState>(button) );
00347 }
00348 
00349   WebButton *
00350 WebClient::_createButton(const QString & s, QWidget * parent)
00351 {
00352   WebButton * b = 0;
00353 
00354   if (("Help" == s) && providesContextHelp())
00355   {
00356     b = new WebButtonHelp(parent, this);
00357     connect(b, SIGNAL(help()), this, SLOT(showContextHelp()));
00358   }
00359 
00360   else if ("OnAllDesktops" == s)
00361   {
00362     b = new WebButtonSticky(isOnAllDesktops(), parent, this);
00363     connect(b, SIGNAL(toggleSticky()), this, SLOT(toggleOnAllDesktops()));
00364     connect(this, SIGNAL(oadChange(bool)), b, SLOT(slotOnAllDesktopsChange(bool)));
00365   }
00366 
00367   else if ("Minimize" == s && isMinimizable())
00368   {
00369     b = new WebButtonIconify(parent, this);
00370     connect(b, SIGNAL(minimize()), this, SLOT(minimize()));
00371   }
00372 
00373   else if ("Maximize" == s && isMaximizable())
00374   {
00375     b = new WebButtonMaximize((maximizeMode()==MaximizeFull), parent, this);
00376     connect(b, SIGNAL(maximize(int)), this, SLOT(slotMaximize(int)));
00377     connect(this, SIGNAL(maxChange(bool)), b, SLOT(slotMaximizeChange(bool)));
00378   }
00379 
00380   else if ("Close" == s && isCloseable())
00381   {
00382     b = new WebButtonClose(parent, this);
00383     connect(b, SIGNAL(closeWindow()), this, SLOT(closeWindow()));
00384   }
00385 
00386   else if ("Lower" == s)
00387   {
00388     b = new WebButtonLower(parent, this);
00389     connect(b, SIGNAL(lowerWindow()), this, SLOT(slotLowerWindow()));
00390   }
00391 
00392   if (0 != b)
00393   {
00394     b->setShape(shape_);
00395   }
00396 
00397   return b;
00398 }
00399 
00400   void
00401 WebClient::_createButtons()
00402 {
00403   leftButtonList_   .clear();
00404   rightButtonList_  .clear();
00405 
00406   QString buttons = options()->titleButtonsLeft() + "|" + options()->titleButtonsRight();
00407   QPtrList<WebButton> *buttonList = &leftButtonList_;
00408   for (unsigned int i = 0; i < buttons.length(); ++i)
00409   {
00410     WebButton * tb = 0;
00411     switch (buttons[i].latin1())
00412     {
00413       case 'S': // OnAllDesktops
00414         tb = _createButton("OnAllDesktops", widget());
00415         break;
00416 
00417       case 'H': // Help
00418         tb = _createButton("Help", widget());
00419         break;
00420 
00421       case 'I': // Minimize
00422         tb = _createButton("Minimize", widget());
00423         break;
00424 
00425       case 'A': // Maximize
00426         tb = _createButton("Maximize", widget());
00427         break;
00428 
00429       case 'X': // Close
00430         tb = _createButton("Close", widget());
00431         break;
00432 
00433       case '|':
00434         buttonList = &rightButtonList_;
00435         break;
00436     }
00437     if (0 != tb)
00438       buttonList->append(tb);
00439   }
00440 
00441   if (!leftButtonList_.isEmpty())
00442     leftButtonList_.first()->setPosition(WebButton::Left);
00443 
00444   if (!rightButtonList_.isEmpty())
00445     rightButtonList_.last()->setPosition(WebButton::Right);
00446 }
00447 
00448   void
00449 WebClient::_resetLayout()
00450 {
00451   KConfig c("kwinwebrc");
00452   c.setGroup("General");
00453   shape_ = c.readBoolEntry("Shape", true);
00454 
00455   //  ____________________________________
00456   // |  |                              |  |
00457   // |Xo|     titleSpacer              |v^| <--- topLayout
00458   // |__|______________________________|__|
00459   // | |                                | |
00460   // | |                                | |
00461   // | |     fake window                | |
00462   // | |                                | | <--- midLayout
00463   // | |                                | |
00464   // | |                                | |
00465   // | |________________________________| |
00466   // |____________________________________|
00467 
00468   const uint sideMargin    = borderSize_;
00469   const uint bottomMargin  = borderSize_;
00470 
00471   if (0 != titleHeight_ % 2)
00472     titleHeight_ += 1;
00473 
00474   delete mainLayout_;
00475 
00476   mainLayout_  = new QVBoxLayout(widget(), 0, 0);
00477 
00478   titleSpacer_ = new QSpacerItem ( 0, titleHeight_, QSizePolicy::Expanding,
00479       QSizePolicy::Fixed);
00480 
00481   QBoxLayout * topLayout = new QBoxLayout(mainLayout_, QBoxLayout::LeftToRight, 0, 0);
00482 
00483   _createButtons();
00484 
00485   // Add left-side buttons.
00486 
00487   for (QPtrListIterator<WebButton> it(leftButtonList_); it.current(); ++it)
00488   {
00489     topLayout->addWidget(it.current(), Qt::AlignVCenter);
00490     topLayout->setStretchFactor(it.current(), 0);
00491     it.current()->setFixedSize(titleHeight_, titleHeight_);
00492   }
00493 
00494   topLayout->addItem(titleSpacer_);
00495 
00496   // Add right-side buttons.
00497 
00498   for (QPtrListIterator<WebButton> it(rightButtonList_); it.current(); ++it)
00499   {
00500     topLayout->addWidget(it.current(), Qt::AlignVCenter);
00501     it.current()->setFixedSize(titleHeight_, titleHeight_);
00502   }
00503 
00504   // -------------------------------------------------------------------
00505 
00506   QHBoxLayout * midLayout   = new QHBoxLayout(mainLayout_, 0, 0);
00507 
00508   midLayout->addSpacing(sideMargin);
00509   if( isPreview())
00510     midLayout->addWidget(new QLabel( i18n( "<center><b>Web</b></center>" ), widget()));
00511   else
00512     midLayout->addItem( new QSpacerItem( 0, 0 )); // no widget in the middle
00513   midLayout->addSpacing(sideMargin);
00514 
00515   // -------------------------------------------------------------------
00516 
00517   mainLayout_->addSpacing(bottomMargin);
00518 
00519   // Make sure that topLayout doesn't stretch - midLayout should take
00520   // all spare space.
00521 
00522   mainLayout_->setStretchFactor(topLayout, 0);
00523   mainLayout_->setStretchFactor(midLayout, 1);
00524 }
00525 
00526 void WebClient::borders(int& left, int& right, int& top, int& bottom) const
00527 {
00528     left = borderSize_;
00529     right = borderSize_;
00530     top =  titleHeight_;
00531     bottom = borderSize_;
00532 }
00533 
00534 void WebClient::resize( const QSize& s )
00535 {
00536     widget()->resize( s );
00537 }
00538 
00539 QSize WebClient::minimumSize() const
00540 {
00541     return QSize( 200, 50 );
00542 }
00543 
00544 const int SUPPORTED_WINDOW_TYPES_MASK = NET::NormalMask | NET::DesktopMask | NET::DockMask
00545     | NET::ToolbarMask | NET::MenuMask | NET::DialogMask | NET::OverrideMask | NET::TopMenuMask
00546     | NET::UtilityMask | NET::SplashMask;
00547 
00548 bool WebClient::isTool()
00549 {
00550   NET::WindowType type = windowType( SUPPORTED_WINDOW_TYPES_MASK );
00551   return ((type==NET::Toolbar)||(type==NET::Utility)||(type==NET::Menu));
00552 }
00553 
00554 bool WebClient::eventFilter( QObject* o, QEvent* e )
00555 {
00556     if( o != widget())
00557     return false;
00558     switch( e->type())
00559     {
00560     case QEvent::Resize:
00561         resizeEvent(static_cast< QResizeEvent* >( e ) );
00562         return true;
00563     case QEvent::Paint:
00564         paintEvent(static_cast< QPaintEvent* >( e ) );
00565         return true;
00566     case QEvent::MouseButtonDblClick:
00567         mouseDoubleClickEvent(static_cast< QMouseEvent* >( e ) );
00568         return true;
00569     case QEvent::MouseButtonPress:
00570         processMousePressEvent(static_cast< QMouseEvent* >( e ) );
00571         return true;
00572     default:
00573         break;
00574     }
00575     return false;
00576 }
00577 
00578 
00579 KDecoration* WebFactory::createDecoration( KDecorationBridge* b )
00580 {
00581   return(new WebClient(b, this));
00582 }
00583 
00584 bool WebFactory::reset(unsigned long changed)
00585 {
00586   // Do we need to "hit the wooden hammer" ?
00587   bool needHardReset = true;
00588   if (changed & SettingColors || changed & SettingFont)
00589   {
00590     needHardReset = false;
00591   }
00592 
00593   if (needHardReset) {
00594     return true;
00595   } else {
00596     resetDecorations(changed);
00597     return false;
00598   }
00599 }
00600 
00601 QValueList< WebFactory::BorderSize > WebFactory::borderSizes() const
00602 { // the list must be sorted
00603   return QValueList< BorderSize >() << BorderNormal << BorderLarge <<
00604       BorderVeryLarge <<  BorderHuge << BorderVeryHuge << BorderOversized;
00605 }
00606 
00607 }
00608 
00609 #include "Web.moc"
00610 // vim:ts=2:sw=2:tw=78:set et:
KDE Logo
This file is part of the documentation for kwin Library Version 3.3.90.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Apr 5 03:59:40 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003