diff --git a/Makefile.am b/Makefile.am index 95ec9724c5..a475f6e8e0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,8 +4,8 @@ LDFLAGS = $(all_libraries) $(KDE_RPATH) bin_PROGRAMS = kwin -kwin_SOURCES = atoms.cpp beclient.cpp client.cpp main.cpp stdclient.cpp workspace.cpp tabbox.cpp +kwin_SOURCES = atoms.cpp beclient.cpp client.cpp main.cpp stdclient.cpp workspace.cpp tabbox.cpp options.cpp kwin_LDADD = $(LIB_KDECORE) -METASOURCES = AUTO \ No newline at end of file +METASOURCES = AUTO diff --git a/client.cpp b/client.cpp index 52a5a67303..33d517f5b8 100644 --- a/client.cpp +++ b/client.cpp @@ -1,8 +1,10 @@ #include #include #include +#include #include #include +#include #include "workspace.h" #include "client.h" #include "atoms.h" @@ -14,6 +16,32 @@ extern Atom qt_wm_state; +static QImage* imgClient = 0; +static QPixmap* pmBackground = 0; +static QImage* imgBackground = 0; + +static QRect* visible_bound = 0; + +void Client::drawbound( const QRect& geom ) +{ + if ( visible_bound ) + *visible_bound = geom; + else + visible_bound = new QRect( geom ); + QPainter p ( workspace()->desktopWidget() ); + p.setPen( QPen( Qt::white, 5 ) ); + p.setRasterOp( Qt::XorROP ); + p.drawRect( geom ); +} +void Client::clearbound() +{ + if ( !visible_bound ) + return; + drawbound( *visible_bound ); + delete visible_bound; + visible_bound = 0; +} + static void sendClientMessage(Window w, Atom a, long x){ XEvent ev; @@ -361,6 +389,7 @@ bool WindowWrapper::x11Event( XEvent * e) } + /*! \class Client client.h @@ -392,6 +421,7 @@ Client::Client( Workspace *ws, WId w, QWidget *parent, const char *name, WFlags mode = Nowhere; buttonDown = FALSE; + moveResizeMode = FALSE; setMouseTracking( TRUE ); active = FALSE; @@ -400,7 +430,7 @@ Client::Client( Workspace *ws, WId w, QWidget *parent, const char *name, WFlags is_sticky = FALSE; ignore_unmap = 0; - + getIcons(); getWindowProtocols(); getWmNormalHints(); // get xSizeHint @@ -824,6 +854,30 @@ void Client::mouseReleaseEvent( QMouseEvent * e) { if ( e->button() == LeftButton ) { buttonDown = FALSE; + if ( moveResizeMode ) { + clearbound(); + if ( isMove() && options->moveMode == Options::HalfTransparent ) { + QPainter p ( workspace()->desktopWidget() ); + if ( !mask.isNull() ) { + QRegion r( mask ); + r.translate( x(), y() ); + p.setClipRegion( r ); + } + p.drawImage( x(), y(), *imgClient); + } + delete imgClient; + imgClient = 0; + delete imgBackground; + imgBackground = 0; + delete pmBackground; + pmBackground = 0; + if ( ( isMove() && options->moveMode != Options::Opaque ) + || ( isResize() && options->resizeMode != Options::Opaque ) ) + XUngrabServer( qt_xdisplay() ); + setGeometry( geom ); + moveResizeMode = FALSE; + releaseMouse(); + } } } @@ -838,6 +892,39 @@ void Client::mouseMoveEvent( QMouseEvent * e) return; } + QRect oldGeom( geom ); + + if ( !moveResizeMode ) + { + QPoint p( e->pos() - moveOffset ); + if ( QABS( p.x() >= 4) || QABS( p.y() ) >= 4 ) { + moveResizeMode = TRUE; + grabMouse( cursor() ); // to keep the right cursor + if ( ( isMove() && options->moveMode != Options::Opaque ) + || ( isResize() && options->resizeMode != Options::Opaque ) ) + XGrabServer( qt_xdisplay() ); + + if ( isMove() && options->moveMode == Options::HalfTransparent ) { + imgClient = new QImage( QPixmap::grabWidget( this ).convertToImage() ); + // TODO SLOW!!! + pmBackground = new QPixmap( QPixmap::grabWindow( qt_xrootwin() )); + imgBackground = new QImage( pmBackground->convertToImage() ); + QRect ww( windowWrapper()->geometry() ); + ww.moveBy( x(), y() ); + ww = ww.intersect( workspace()->geometry() ); + ww.moveBy( -x(), -y() ); + bitBlt( imgClient, + ww.x(), + ww.y(), + imgBackground, + x()+ww.x(), y()+ww.y(), ww.width(), ww.height() ); + oldGeom.setRect(0,0,0,0); + } + } + else + return; + } + if ( mode != Center && shaded ) { wwrap->show(); workspace()->requestFocus( this ); @@ -846,22 +933,6 @@ void Client::mouseMoveEvent( QMouseEvent * e) QPoint globalPos = e->pos() + geometry().topLeft(); - // TODO for MDI this has to be based on the parent window! -// QPoint p = parentWidget()->mapFromGlobal( e->globalPos() ); - -// if ( !parentWidget()->rect().contains(p) ) { -// if ( p.x() < 0 ) -// p.rx() = 0; -// if ( p.y() < 0 ) -// p.ry() = 0; -// if ( p.x() > parentWidget()->width() ) -// p.rx() = parentWidget()->width(); -// if ( p.y() > parentWidget()->height() ) -// p.ry() = parentWidget()->height(); -// } - -// if ( testWState(WState_ConfigPending) ) -// return; QPoint p = globalPos + invertedMoveOffset; @@ -872,7 +943,7 @@ void Client::mouseMoveEvent( QMouseEvent * e) QPoint mp( geometry().right() - mpsize.width() + 1, geometry().bottom() - mpsize.height() + 1 ); - QRect geom = geometry(); + geom = geometry(); switch ( mode ) { case TopLeft: geom = QRect( mp, geometry().bottomRight() ) ; @@ -905,12 +976,74 @@ void Client::mouseMoveEvent( QMouseEvent * e) break; } - if ( geom.size() != size() ) { - geom.setSize( adjustedSize( geom.size() ) ); - setGeometry( geom ); + if ( isResize() && geom.size() != size() ) { + if (options->resizeMode == Options::Opaque ) { + geom.setSize( adjustedSize( geom.size() ) ); + setGeometry( geom ); + } else if ( options->resizeMode == Options::Transparent ) { + clearbound(); + drawbound( geom ); + } + } + else if ( isMove() && geom.topLeft() != geometry().topLeft() ) { + switch ( options->moveMode ) { + case Options::Opaque: + move( geom.topLeft() ); + break; + case Options::Transparent: + clearbound(); + drawbound( geom ); + break; + case Options::HalfTransparent: + { + QPainter p ( workspace()->desktopWidget() ); + QRegion now( geom ); + if ( !mask.isNull() ) { + QRegion r( mask ); + r.translate( geom.x(), geom.y() ); + now = r; + } + if ( !oldGeom.isEmpty() ) { + QRegion r( oldGeom ); + r = r.subtract( now ); + p.setClipRegion( r ); + p.drawPixmap( oldGeom.x(), oldGeom.y(), + *pmBackground, + oldGeom.x(), oldGeom.y(), + oldGeom.width(), oldGeom.height() ); + } + p.setClipRegion( now ); + QImage img ( *imgClient ); + img.detach(); + QRect visibleRect = QRect( 0, 0, + workspace()->geometry().width(), + workspace()->geometry().height() ).intersect( geom ); + for ( int i=visibleRect.top(); i<=visibleRect.bottom(); i++ ) { + uint *p = (uint *)imgBackground->scanLine(i); + uint *end = p + visibleRect.right(); + p += visibleRect.left(); + uint *pimg = (uint *)img.scanLine(i - geom.top() ); + pimg += visibleRect.left() - geom.left(); + while ( p <= end ) { + int r = (*p&0x00ff0000) >> 16; + int r2 = (*pimg&0x00ff0000) >> 16; + int g = (*p&0x0000ff00) >> 8; + int g2 = (*pimg&0x0000ff00) >> 8; + int b = (*p&0x000000ff ); + int b2 = (*pimg&0x000000ff ); + *pimg = ( ( (r+2*r2)/3 ) << 16 ) + + ( ( (g+2*g2)/3 ) << 8 ) + + ( (b+2*b2)/3 ); + p++; + pimg++; + } + } + + p.drawImage( geom.x(), geom.y(), img ); + } + break; + } } - else if ( geom.topLeft() != geometry().topLeft() ) - move( geom.topLeft() ); } @@ -1451,6 +1584,15 @@ void Client::takeFocus() } +/*!\reimp + */ +void Client::setMask( const QRegion & reg) +{ + mask = reg; + QWidget::setMask( reg ); +} + + NoBorderClient::NoBorderClient( Workspace *ws, WId w, QWidget *parent=0, const char *name=0 ) : Client( ws, w, parent, name ) { diff --git a/client.h b/client.h index 1571cc0789..8dc87b1d60 100644 --- a/client.h +++ b/client.h @@ -119,6 +119,12 @@ public: void takeFocus(); + void setMask( const QRegion & ); + + // transparent stuff + virtual void drawbound( const QRect& geom ); + virtual void clearbound(); + public slots: void iconify(); void closeWindow(); @@ -175,6 +181,13 @@ private: Workspace* wspace; int desk; bool buttonDown; + bool moveResizeMode; + bool isMove() const { + return moveResizeMode && mode == Center; + } + bool isResize() const { + return !isMove(); + } MousePosition mode; QPoint moveOffset; QPoint invertedMoveOffset; @@ -185,6 +198,7 @@ private: bool active; int ignore_unmap; QRect original_geometry; + QRect geom; //### TODO bool shaded; WId transient_for; bool is_sticky; @@ -195,6 +209,7 @@ private: QPixmap icon_pix; QPixmap miniicon_pix; QRect geom_restore; + QRegion mask; }; inline WId Client::window() const diff --git a/kwin b/kwin new file mode 100755 index 0000000000..a6c1c7b0d7 Binary files /dev/null and b/kwin differ diff --git a/kwin.pro b/kwin.pro index 8895e7e2c7..65657649db 100644 --- a/kwin.pro +++ b/kwin.pro @@ -12,6 +12,7 @@ SOURCES = atoms.cpp \ beclient.cpp \ client.cpp \ main.cpp \ + options.cpp \ stdclient.cpp \ tabbox.cpp \ workspace.cpp diff --git a/options.h b/options.h index 764f23fe06..bb509ef1eb 100644 --- a/options.h +++ b/options.h @@ -8,38 +8,40 @@ public: /*! Different focus policies:
    - +
  • ClickToFocus - Clicking into a window activates it. This is also the default. - +
  • FocusFollowsMouse - Moving the mouse pointer actively onto a window activates it. - +
  • FocusUnderMouse - The window that happens to be under the mouse pointer becomes active. - +
  • FocusStricklyUnderMouse - Only the window under the mouse pointer is active. If the mouse points nowhere, nothing has the focus. In practice, this is the same as FocusUnderMouse, since kdesktop can take the focus. - + Note that FocusUnderMouse and FocusStricklyUnderMouse are not particulary useful. They are only provided for old-fashined die-hard UNIX people ;-) - +
*/ enum FocusPolicy { ClickToFocus, FocusFollowsMouse, FocusUnderMouse, FocusStricklyUnderMouse }; FocusPolicy focusPolicy; + + enum MoveResizeMode { Transparent, Opaque, HalfTransparent }; + + MoveResizeMode resizeMode; + MoveResizeMode moveMode; bool focusPolicyIsReasonable() { return focusPolicy == ClickToFocus || focusPolicy == FocusFollowsMouse; } - Options(){ - focusPolicy = ClickToFocus; - } - + Options(); }; extern Options* options; diff --git a/workspace.cpp b/workspace.cpp index 15eae53c56..c68915decf 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -36,6 +36,7 @@ Workspace::Workspace() root = qt_xrootwin(); // no MDI for now (void) QApplication::desktop(); // trigger creation of desktop widget + desktop_widget = new QWidget(0, "desktop_widget", Qt::WType_Desktop | Qt::WPaintUnclipped ); // select windowmanager privileges XSelectInput(qt_xdisplay(), root, @@ -162,9 +163,12 @@ bool Workspace::workspaceEvent( XEvent * e ) case DestroyNotify: return destroyClient( findClient( e->xdestroywindow.window ) ); case MapRequest: + qDebug("map request"); if ( e->xmaprequest.parent == root ) { + qDebug("map request on root window"); c = findClient( e->xmaprequest.window ); if ( !c ) { + qDebug("didn't find a client, make a new one"); c = clientFactory( this, e->xmaprequest.window ); if ( root != qt_xrootwin() ) { // TODO may use QWidget:.create @@ -640,33 +644,33 @@ void Workspace::clientHidden( Client* c ) void Workspace::showPopup( const QPoint& pos, Client* c) { - // experimental!!! - + // experimental!!! + if ( !popup ) { popup = new QPopupMenu; - // I wish I could use qt-2.1 features here..... grmblll + // I wish I could use qt-2.1 features here..... grmblll QPopupMenu* deco = new QPopupMenu( popup ); deco->insertItem("KDE Classic", 100 ); deco->insertItem("Be-like style", 101 ); - + popup->insertItem("Decoration", deco ); } popup_client = c; // TODO customize popup for the client int ret = popup->exec( pos ); - + switch( ret ) { case 100: setDecoration( 0 ); break; case 101: setDecoration( 1 ); - break; + break; default: break; } - + popup_client = 0; ret = 0; } @@ -803,7 +807,7 @@ void Workspace::switchDesktop( int new_desktop ){ if (new_desktop == current_desktop ) return; - /* + /* optimized Desktop switching: unmapping done from back to front mapping done from front to back => less exposure events */ @@ -857,3 +861,8 @@ void Workspace::setDecoration( int deco ) activateClient( c ); } + +QWidget* Workspace::desktopWidget() +{ + return desktop_widget; +} diff --git a/workspace.h b/workspace.h index 8091d7a8a9..0c08047fa3 100644 --- a/workspace.h +++ b/workspace.h @@ -42,6 +42,8 @@ public: int currentDesktop() const; int numberOfDesktops() const; + + QWidget* desktopWidget(); void grabKey(KeySym keysym, unsigned int mod); @@ -87,7 +89,8 @@ private: int current_desktop; Client* popup_client; - + QWidget* desktop_widget; + //experimental void setDecoration( int deco ); };