iconify/deiconify animation.
Don't forget to update libkdecore and kicker svn path=/trunk/kdebase/kwin/; revision=54131
This commit is contained in:
parent
2322242681
commit
72abf668d2
4 changed files with 184 additions and 64 deletions
165
client.cpp
165
client.cpp
|
@ -16,6 +16,7 @@ Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
|
|||
#include <qlayout.h>
|
||||
#include <qpainter.h>
|
||||
#include <qwhatsthis.h>
|
||||
#include <qdatetime.h>
|
||||
#include <qtimer.h>
|
||||
#include <kwin.h>
|
||||
#include <netwm.h>
|
||||
|
@ -50,27 +51,25 @@ public:
|
|||
virtual void changeDesktop(Q_UINT32 desktop) {
|
||||
m_client->setDesktop( desktop );
|
||||
}
|
||||
virtual void changeState(Q_UINT32 state, Q_UINT32 /* mask */) {
|
||||
// What's the mask ?
|
||||
// Warning: this code was written by David who has no clue about window managers :/
|
||||
virtual void changeState(Q_UINT32 state, Q_UINT32 mask ) {
|
||||
// state : kwin.h says: possible values are or'ed combinations of NET::Modal,
|
||||
// NET::Sticky, NET::MaxVert, NET::MaxHoriz, NET::Shaded, NET::SkipTaskbar
|
||||
|
||||
// state : kwin.h says: possible values are or'ed combinations of NET::Modal,
|
||||
// NET::Sticky, NET::MaxVert, NET::MaxHoriz, NET::Shaded, NET::SkipTaskbar
|
||||
|
||||
m_client->setSticky( state & NET::Sticky );
|
||||
m_client->setShade( state & NET::Shaded );
|
||||
|
||||
if ( state & NET::MaxVert )
|
||||
if ( state & NET::MaxHoriz )
|
||||
m_client->maximize( Client::MaximizeFull );
|
||||
else
|
||||
m_client->maximize( Client::MaximizeVertical );
|
||||
else if ( state & NET::MaxHoriz )
|
||||
m_client->maximize( Client::MaximizeHorizontal );
|
||||
|
||||
// if ( state & NET::Modal ) ???
|
||||
// if ( state & NET::SkipTaskbar ) ???
|
||||
state &= mask; // for safety, clear all other bits
|
||||
|
||||
if ( mask & NET::Sticky )
|
||||
m_client->setSticky( state & NET::Sticky );
|
||||
if ( mask & NET::Shaded )
|
||||
m_client->setShade( state & NET::Shaded );
|
||||
|
||||
if ( mask & NET::Max ) {
|
||||
if ( state & NET::Max == NET::Max )
|
||||
m_client->maximize( Client::MaximizeFull );
|
||||
else if ( state & NET::MaxVert )
|
||||
m_client->maximize( Client::MaximizeVertical );
|
||||
else if ( state & NET::MaxHoriz )
|
||||
m_client->maximize( Client::MaximizeHorizontal );
|
||||
}
|
||||
}
|
||||
private:
|
||||
::Client * m_client;
|
||||
|
@ -376,7 +375,8 @@ Client::Client( Workspace *ws, WId w, QWidget *parent, const char *name, WFlags
|
|||
NET::WMState |
|
||||
NET::WMWindowType |
|
||||
NET::WMStrut |
|
||||
NET::WMName
|
||||
NET::WMName |
|
||||
NET::WMIconGeometry
|
||||
;
|
||||
|
||||
info = new WinInfo( this, qt_xdisplay(), win, qt_xrootwin(), properties );
|
||||
|
@ -1209,6 +1209,8 @@ void Client::move( int x, int y )
|
|||
*/
|
||||
void Client::showEvent( QShowEvent* )
|
||||
{
|
||||
if ( isIconified() && !isTransient() )
|
||||
animateIconifyOrDeiconify( FALSE );
|
||||
setMappingState( NormalState );
|
||||
}
|
||||
|
||||
|
@ -1324,6 +1326,10 @@ void Client::invalidateWindow()
|
|||
}
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
Iconifies this client plus its transients
|
||||
*/
|
||||
void Client::iconify()
|
||||
{
|
||||
if (!isMovable())
|
||||
|
@ -1339,11 +1345,19 @@ void Client::iconify()
|
|||
}
|
||||
Events::raise( Events::Iconify );
|
||||
setMappingState( IconicState );
|
||||
|
||||
if ( !isTransient() )
|
||||
animateIconifyOrDeiconify( TRUE );
|
||||
hide();
|
||||
// TODO animation (virtual function)
|
||||
|
||||
workspace()->iconifyOrDeiconifyTransientsOf( this );
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Closes the window by either sending a delete_window message or
|
||||
using XKill.
|
||||
*/
|
||||
void Client::closeWindow()
|
||||
{
|
||||
Events::raise( Events::Close );
|
||||
|
@ -1358,6 +1372,10 @@ void Client::closeWindow()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Kills the window via XKill
|
||||
*/
|
||||
void Client::killWindow()
|
||||
{
|
||||
// not sure if we need an Events::Kill or not.. until then, use
|
||||
|
@ -1511,14 +1529,14 @@ void Client::gravitate( bool invert )
|
|||
|
||||
/*!
|
||||
Reimplement to handle crossing events (qt should provide xroot, yroot)
|
||||
|
||||
|
||||
Crossing events are necessary for the focus-follows-mouse focus
|
||||
policies, to do proper activation and deactivation.
|
||||
*/
|
||||
bool Client::x11Event( XEvent * e)
|
||||
{
|
||||
if ( e->type == EnterNotify && e->xcrossing.mode == NotifyNormal ) {
|
||||
if ( options->focusPolicy == Options::ClickToFocus )
|
||||
if ( options->focusPolicy == Options::ClickToFocus )
|
||||
return TRUE;
|
||||
|
||||
if ( options->focusPolicy != Options::FocusStrictlyUnderMouse && ( isDesktop() || isDock() ) )
|
||||
|
@ -2107,9 +2125,9 @@ bool Client::isDock() const
|
|||
}
|
||||
|
||||
|
||||
/*!
|
||||
/*!
|
||||
Returns \a area with the client's strut taken into account.
|
||||
|
||||
|
||||
Used from Workspace in updateClientArea.
|
||||
*/
|
||||
QRect Client::adjustedClientArea( const QRect& area ) const
|
||||
|
@ -2128,6 +2146,103 @@ QRect Client::adjustedClientArea( const QRect& area ) const
|
|||
}
|
||||
|
||||
|
||||
void Client::animateIconifyOrDeiconify( bool iconify)
|
||||
{
|
||||
// the function is a bit tricky since it will ensure that an
|
||||
// animation action needs always the same time regardless of the
|
||||
// performance of the machine or the X-Server.
|
||||
|
||||
float lf,rf,tf,bf,step;
|
||||
|
||||
int options_dot_ResizeAnimation = 1;
|
||||
|
||||
step = 40. * (11 - options_dot_ResizeAnimation);
|
||||
|
||||
NETRect r = info->iconGeometry();
|
||||
QRect icongeom( r.pos.x, r.pos.y, r.size.width, r.size.height );
|
||||
if ( !icongeom.isValid() )
|
||||
return;
|
||||
|
||||
QPixmap pm = animationPixmap( iconify ? width() : icongeom.width() );
|
||||
|
||||
QRect before, after;
|
||||
if ( iconify ) {
|
||||
before = QRect( x(), y(), width(), pm.height() );
|
||||
after = QRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
|
||||
} else {
|
||||
before = QRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
|
||||
after = QRect( x(), y(), width(), pm.height() );
|
||||
}
|
||||
|
||||
lf = (after.left() - before.left())/step;
|
||||
rf = (after.right() - before.right())/step;
|
||||
tf = (after.top() - before.top())/step;
|
||||
bf = (after.bottom() - before.bottom())/step;
|
||||
|
||||
|
||||
XGrabServer( qt_xdisplay() );
|
||||
|
||||
QRect area = before;
|
||||
QRect area2;
|
||||
QPixmap pm2;
|
||||
|
||||
QTime t;
|
||||
t.start();
|
||||
float diff;
|
||||
|
||||
QPainter p ( workspace()->desktopWidget() );
|
||||
bool need_to_clear = FALSE;
|
||||
QPixmap pm3;
|
||||
do {
|
||||
if (area2 != area){
|
||||
pm = animationPixmap( area.width() );
|
||||
pm2 = QPixmap::grabWindow( qt_xrootwin(), area.x(), area.y(), area.width(), area.height() );
|
||||
p.drawPixmap( area.x(), area.y(), pm );
|
||||
if ( need_to_clear ) {
|
||||
p.drawPixmap( area2.x(), area2.y(), pm3 );
|
||||
need_to_clear = FALSE;
|
||||
}
|
||||
area2 = area;
|
||||
}
|
||||
XFlush(qt_xdisplay());
|
||||
XSync( qt_xdisplay(), FALSE );
|
||||
diff = t.elapsed();
|
||||
if (diff > step)
|
||||
diff = step;
|
||||
area.setLeft(before.left() + int(diff*lf));
|
||||
area.setRight(before.right() + int(diff*rf));
|
||||
area.setTop(before.top() + int(diff*tf));
|
||||
area.setBottom(before.bottom() + int(diff*bf));
|
||||
if (area2 != area ) {
|
||||
if ( area2.intersects( area ) )
|
||||
p.drawPixmap( area2.x(), area2.y(), pm2 );
|
||||
else { // no overlap, we can clear later to avoid flicker
|
||||
pm3 = pm2;
|
||||
need_to_clear = TRUE;
|
||||
}
|
||||
}
|
||||
} while ( t.elapsed() < step);
|
||||
if (area2 == area || need_to_clear )
|
||||
p.drawPixmap( area2.x(), area2.y(), pm2 );
|
||||
|
||||
p.end();
|
||||
XUngrabServer( qt_xdisplay() );
|
||||
}
|
||||
|
||||
QPixmap Client::animationPixmap( int w )
|
||||
{
|
||||
QFont font = options->font(isActive());
|
||||
QFontMetrics fm( font );
|
||||
QPixmap pm( w, fm.lineSpacing() );
|
||||
pm.fill( options->color(Options::TitleBar, isActive() || isIconified() ) );
|
||||
QPainter p( &pm );
|
||||
p.setPen(options->color(Options::Font, isActive() || isIconified() ));
|
||||
p.setFont(options->font(isActive()));
|
||||
p.drawText( pm.rect(), AlignLeft|AlignVCenter|SingleLine, caption() );
|
||||
return pm;
|
||||
}
|
||||
|
||||
|
||||
NoBorderClient::NoBorderClient( Workspace *ws, WId w, QWidget *parent, const char *name )
|
||||
: Client( ws, w, parent, name )
|
||||
{
|
||||
|
|
11
client.h
11
client.h
|
@ -117,7 +117,7 @@ public:
|
|||
bool isSticky() const;
|
||||
void setSticky( bool );
|
||||
|
||||
|
||||
|
||||
// auxiliary functions, depend on the windowType
|
||||
bool wantsTabFocus() const;
|
||||
bool isMovable() const;
|
||||
|
@ -145,8 +145,6 @@ public:
|
|||
void move( const QPoint & p )
|
||||
{ move( p.x(), p.y() ); }
|
||||
|
||||
|
||||
|
||||
bool providesContextHelp() const;
|
||||
|
||||
bool performMouseCommand( Options::MouseCommand, QPoint globalPos );
|
||||
|
@ -155,7 +153,7 @@ public:
|
|||
QCString sessionId();
|
||||
|
||||
QRect adjustedClientArea( const QRect& area ) const;
|
||||
|
||||
|
||||
public slots:
|
||||
void iconify();
|
||||
void closeWindow();
|
||||
|
@ -200,6 +198,11 @@ protected:
|
|||
virtual MousePosition mousePosition( const QPoint& ) const;
|
||||
virtual void setMouseCursor( MousePosition m );
|
||||
|
||||
|
||||
virtual void animateIconifyOrDeiconify( bool iconify );
|
||||
virtual QPixmap animationPixmap( int w );
|
||||
|
||||
|
||||
// handlers for X11 events
|
||||
bool mapRequest( XMapRequestEvent& e );
|
||||
bool unmapNotify( XUnmapEvent& e );
|
||||
|
|
20
main.cpp
20
main.cpp
|
@ -79,6 +79,26 @@ int x11ErrorHandler(Display *d, XErrorEvent *e){
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Updates kwin_time by receiving a current timestamp from the server.
|
||||
|
||||
Use this function only when really necessary. Keep in mind that it's
|
||||
a roundtrip to the X-Server.
|
||||
*/
|
||||
void kwin_updateTime()
|
||||
{
|
||||
static QWidget* w = 0;
|
||||
if ( !w )
|
||||
w = new QWidget;
|
||||
long data = 1;
|
||||
XChangeProperty(qt_xdisplay(), w->winId(), atoms->kwin_running, atoms->kwin_running, 32,
|
||||
PropModeAppend, (unsigned char*) &data, 1);
|
||||
XEvent ev;
|
||||
XWindowEvent( qt_xdisplay(), w->winId(), PropertyChangeMask, &ev );
|
||||
kwin_time = ev.xproperty.time;
|
||||
}
|
||||
|
||||
|
||||
Application::Application( )
|
||||
: KApplication( )
|
||||
{
|
||||
|
|
|
@ -78,6 +78,7 @@ private:
|
|||
|
||||
|
||||
extern Time kwin_time;
|
||||
extern void kwin_updateTime();
|
||||
|
||||
// used to store the return values of
|
||||
// XShapeQueryExtension.
|
||||
|
@ -136,31 +137,12 @@ bool Motif::noBorder( WId w )
|
|||
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
Updates kwin_time by receiving a current timestamp from the server.
|
||||
|
||||
Use this function only when really necessary. Keep in mind that it's
|
||||
a roundtrip to the X-Server.
|
||||
*/
|
||||
static void updateTime()
|
||||
{
|
||||
static QWidget* w = 0;
|
||||
if ( !w )
|
||||
w = new QWidget;
|
||||
long data = 1;
|
||||
XChangeProperty(qt_xdisplay(), w->winId(), atoms->kwin_running, atoms->kwin_running, 32,
|
||||
PropModeAppend, (unsigned char*) &data, 1);
|
||||
XEvent ev;
|
||||
XWindowEvent( qt_xdisplay(), w->winId(), PropertyChangeMask, &ev );
|
||||
kwin_time = ev.xproperty.time;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Creates a new client for window \a w, depending on certain hints
|
||||
(like Motif hints and the NET_WM_TYPE.
|
||||
|
||||
Shaped windows always get a NoBorderClient.
|
||||
|
||||
Shaped windows always get a NoBorderClient.
|
||||
*/
|
||||
Client* Workspace::clientFactory( WId w )
|
||||
{
|
||||
|
@ -454,7 +436,7 @@ bool Workspace::workspaceEvent( XEvent * e )
|
|||
return TRUE;
|
||||
return destroyClient( findClient( e->xdestroywindow.window ) );
|
||||
case MapRequest:
|
||||
updateTime();
|
||||
kwin_updateTime();
|
||||
c = findClient( e->xmaprequest.window );
|
||||
if ( !c ) {
|
||||
if ( e->xmaprequest.parent == root ) {
|
||||
|
@ -859,7 +841,7 @@ Client* Workspace::previousStaticClient( Client* c ) const
|
|||
}
|
||||
|
||||
|
||||
/*!
|
||||
/*!
|
||||
Returns topmost visible client. Windows on the dock and the
|
||||
desktop are excluded.
|
||||
*/
|
||||
|
@ -1434,7 +1416,7 @@ void Workspace::cascadeDesktop()
|
|||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
/*!
|
||||
Unclutters the current desktop by smart-placing all clients
|
||||
again.
|
||||
*/
|
||||
|
@ -1711,7 +1693,7 @@ void Workspace::setCurrentDesktop( int new_desktop ){
|
|||
|
||||
|
||||
|
||||
/*!
|
||||
/*!
|
||||
Returns the workspace's desktop widget. The desktop widget is
|
||||
sometimes required by clients to draw on it, for example outlines on
|
||||
moving or resizing.
|
||||
|
@ -2424,7 +2406,7 @@ void Workspace::slotResetAllClients()
|
|||
|
||||
/*!
|
||||
Stores the current session in the config file
|
||||
|
||||
|
||||
\sa loadSessionInfo()
|
||||
*/
|
||||
void Workspace::storeSession( KConfig* config )
|
||||
|
@ -2455,7 +2437,7 @@ void Workspace::storeSession( KConfig* config )
|
|||
|
||||
/*!
|
||||
Loads the session information from the config file.
|
||||
|
||||
|
||||
\sa storeSession()
|
||||
*/
|
||||
void Workspace::loadSessionInfo()
|
||||
|
@ -2481,10 +2463,10 @@ void Workspace::loadSessionInfo()
|
|||
}
|
||||
|
||||
|
||||
/*!
|
||||
/*!
|
||||
Returns the SessionInfo for client \a c. The returned session
|
||||
info is removed from the storage. It's up to the caller to delete it.
|
||||
|
||||
|
||||
May return 0 if there's no session info for the client.
|
||||
*/
|
||||
SessionInfo* Workspace::takeSessionInfo( Client* c )
|
||||
|
@ -2508,13 +2490,13 @@ SessionInfo* Workspace::takeSessionInfo( Client* c )
|
|||
|
||||
/*!
|
||||
Updates the current client area according to the current clients.
|
||||
|
||||
|
||||
If the area changes, the new area is propagate to the world.
|
||||
|
||||
The client area is the area that is available for clients (that
|
||||
which is not taken by windows like panels, the top-of-screen menu
|
||||
etc).
|
||||
|
||||
|
||||
\sa clientArea()
|
||||
*/
|
||||
void Workspace::updateClientArea()
|
||||
|
@ -2539,11 +2521,11 @@ void Workspace::updateClientArea()
|
|||
}
|
||||
|
||||
|
||||
/*!
|
||||
/*!
|
||||
returns the area available for clients. This is the desktop
|
||||
geometry minus windows on the dock. Placement algorithms should
|
||||
refer to this rather than geometry().
|
||||
|
||||
refer to this rather than geometry().
|
||||
|
||||
\sa geometry()
|
||||
*/
|
||||
QRect Workspace::clientArea()
|
||||
|
|
Loading…
Reference in a new issue