Say hello to kwin. WARNING: NOT USABLE YET. See README.
svn path=/trunk/kdebase/kwin/; revision=27871
This commit is contained in:
commit
311db796c6
18 changed files with 3848 additions and 0 deletions
20
README
Normal file
20
README
Normal file
|
@ -0,0 +1,20 @@
|
|||
Fri Aug 20 01:30:50 CEST 1999
|
||||
|
||||
This is the beginning of kwin, kwm next generation.
|
||||
|
||||
WARNING: this thing is hardly usable now, neither ICCCM nor KDE
|
||||
compliant yet!
|
||||
|
||||
All it has is a context menu that allows you to switch between two
|
||||
decoration styles, KDE classic and an experimental style.
|
||||
|
||||
Please don't work on the code, I'll finish it during my summer
|
||||
vacations (four weeks from now on).
|
||||
|
||||
kwin was only commited to allow people like Mosfet to have a look at
|
||||
the Client API (and StdClient) to write nifty new themable decorations.
|
||||
|
||||
Have fun,
|
||||
|
||||
Matthias
|
||||
<ettrich@kde.org>
|
15
atoms.cpp
Normal file
15
atoms.cpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include <qapplication.h>
|
||||
#include "atoms.h"
|
||||
|
||||
Atoms::Atoms()
|
||||
{
|
||||
|
||||
//TODO use XInternAtoms instead to avoid roundtrips
|
||||
wm_protocols = XInternAtom(qt_xdisplay(), "WM_PROTOCOLS", FALSE);
|
||||
wm_delete_window = XInternAtom(qt_xdisplay(), "WM_DELETE_WINDOW", FALSE);
|
||||
wm_take_focus = XInternAtom(qt_xdisplay(), "WM_TAKE_FOCUS", FALSE);
|
||||
|
||||
// compatibility
|
||||
kwm_win_icon = XInternAtom(qt_xdisplay(), "KWM_WIN_ICON", FALSE);
|
||||
|
||||
}
|
19
atoms.h
Normal file
19
atoms.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef ATOMS_H
|
||||
#define ATOMS_H
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
class Atoms {
|
||||
public:
|
||||
Atoms();
|
||||
|
||||
Atom wm_protocols;
|
||||
Atom wm_delete_window;
|
||||
Atom wm_take_focus;
|
||||
Atom kwm_win_icon; // compatibility
|
||||
|
||||
};
|
||||
|
||||
|
||||
extern Atoms* atoms;
|
||||
|
||||
#endif
|
213
beclient.cpp
Normal file
213
beclient.cpp
Normal file
|
@ -0,0 +1,213 @@
|
|||
#include "beclient.h"
|
||||
#include <qapplication.h>
|
||||
#include <qcursor.h>
|
||||
#include <qabstractlayout.h>
|
||||
#include <qlayout.h>
|
||||
#include <qtoolbutton.h>
|
||||
#include <qlabel.h>
|
||||
#include <qdrawutil.h>
|
||||
#include "workspace.h"
|
||||
|
||||
|
||||
|
||||
static const char * size_xpm[] = {
|
||||
/* width height num_colors chars_per_pixel */
|
||||
"16 16 3 1",
|
||||
/* colors */
|
||||
" s None c None",
|
||||
". c #707070",
|
||||
"X c white",
|
||||
/* pixels */
|
||||
" ",
|
||||
" ....... ",
|
||||
" .XXXXXX ",
|
||||
" .X .X ",
|
||||
" .X .X....... ",
|
||||
" .X .XXXXXXXX ",
|
||||
" .X .X .X ",
|
||||
" .X....X .X ",
|
||||
" .XXXXXX .X ",
|
||||
" .X .X ",
|
||||
" .X .X ",
|
||||
" .X .X ",
|
||||
" .X........X ",
|
||||
" .XXXXXXXXXX ",
|
||||
" ",
|
||||
" "};
|
||||
|
||||
static QPixmap* size_pix = 0;
|
||||
static bool pixmaps_created = FALSE;
|
||||
|
||||
static void create_pixmaps()
|
||||
{
|
||||
if ( pixmaps_created )
|
||||
return;
|
||||
size_pix = new QPixmap( size_xpm );
|
||||
}
|
||||
|
||||
|
||||
|
||||
BeClient::BeClient( Workspace *ws, WId w, QWidget *parent, const char *name )
|
||||
: Client( ws, w, parent, name, WResizeNoErase )
|
||||
{
|
||||
create_pixmaps();
|
||||
|
||||
QFont f = font();
|
||||
f.setBold( TRUE );
|
||||
setFont( f );
|
||||
|
||||
QGridLayout* g = new QGridLayout( this, 0, 0, 2 );
|
||||
g->addRowSpacing(1, 2);
|
||||
g->setRowStretch( 2, 10 );
|
||||
g->addWidget( windowWrapper(), 2, 1 );
|
||||
g->addColSpacing(0, 2);
|
||||
g->addColSpacing(2, 2);
|
||||
g->addRowSpacing(3, 2);
|
||||
|
||||
|
||||
|
||||
QHBoxLayout* hb = new QHBoxLayout;
|
||||
g->addLayout( hb, 0, 1 );
|
||||
int fh = QMAX( 16, fontMetrics().lineSpacing());
|
||||
titlebar = new QSpacerItem(40, fh, QSizePolicy::Preferred,
|
||||
QSizePolicy::Minimum );
|
||||
hb->addItem( titlebar );
|
||||
|
||||
hb->addStretch();
|
||||
|
||||
}
|
||||
|
||||
|
||||
BeClient::~BeClient()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void BeClient::resizeEvent( QResizeEvent* e)
|
||||
{
|
||||
Client::resizeEvent( e );
|
||||
doShape();
|
||||
if ( isVisibleToTLW() ) {
|
||||
// manual clearing without the titlebar (we selected WResizeNoErase )
|
||||
QPainter p( this );
|
||||
QRect t = titlebar->geometry();
|
||||
t.setTop( 0 );
|
||||
t.setLeft( 0 );
|
||||
QRegion r = rect();
|
||||
r = r.subtract( t );
|
||||
p.setClipRegion( r );
|
||||
p.eraseRect( rect() );
|
||||
}
|
||||
}
|
||||
|
||||
/*!\reimp
|
||||
*/
|
||||
void BeClient::captionChange( const QString& )
|
||||
{
|
||||
doShape();
|
||||
repaint();
|
||||
}
|
||||
|
||||
void BeClient::paintEvent( QPaintEvent* )
|
||||
{
|
||||
QPainter p( this );
|
||||
QRect bar ( 0, 0, titlebar->geometry().right()+1, titlebar->geometry().bottom() );
|
||||
qDrawWinPanel( &p, 0, bar.bottom()+2, width(), height() - bar.bottom()-2, colorGroup(), FALSE );
|
||||
qDrawWinPanel( &p, 2, bar.bottom()+4, width()-4, height() - bar.bottom()-6, colorGroup(), TRUE );
|
||||
QRect t = titlebar->geometry();
|
||||
|
||||
bar.setBottom( bar.bottom() + 3 );
|
||||
p.setClipRect( bar );
|
||||
bar.setBottom( bar.bottom() + 2 );
|
||||
if ( isActive() ) {
|
||||
QPalette pal( QColor(248,204,0) );
|
||||
qDrawWinPanel( &p, bar, pal.normal(), FALSE, &pal.brush(QPalette::Normal, QColorGroup::Background ) );
|
||||
}
|
||||
else
|
||||
qDrawWinPanel( &p, bar, colorGroup(), FALSE, &colorGroup().brush( QColorGroup::Background ) );
|
||||
p.setClipping( FALSE );
|
||||
|
||||
p.drawPixmap( t.right() - 20, t.center().y()-8, *size_pix );
|
||||
p.drawPixmap( t.left() +4, t.center().y()-miniIcon().height()/2, miniIcon() );
|
||||
t.setLeft( t.left() + 20 +10);
|
||||
p.drawText( t, AlignLeft|AlignVCenter, caption() );
|
||||
}
|
||||
|
||||
|
||||
void BeClient::showEvent( QShowEvent* e)
|
||||
{
|
||||
Client::showEvent( e );
|
||||
doShape();
|
||||
repaint();
|
||||
}
|
||||
|
||||
void BeClient::doShape()
|
||||
{
|
||||
QFontMetrics fm = fontMetrics();
|
||||
int cap = 20+20+10+10+fm.boundingRect(caption() ).width();
|
||||
titlebar->changeSize( QMIN( width(), cap), QMAX( 16, fm.lineSpacing()),
|
||||
QSizePolicy::Preferred, QSizePolicy::Minimum );
|
||||
layout()->activate(); //#### this is broken!!!!! PAUL!!!!!
|
||||
|
||||
// // // do it manually: #######remove this for Qt-2.01
|
||||
titlebar->setGeometry( QRect( titlebar->geometry().x(), titlebar->geometry().y(),
|
||||
titlebar->sizeHint().width(), titlebar->sizeHint().height() ) );
|
||||
QRegion r( rect() );
|
||||
r = r.subtract( QRect( QPoint( titlebar->geometry().right()+1, 0), QPoint( width(), titlebar->geometry().bottom()) ) );
|
||||
setMask( r );
|
||||
}
|
||||
|
||||
/*!\reimp
|
||||
*/
|
||||
void BeClient::activeChange( bool /* act */ )
|
||||
{
|
||||
repaint( 0, 0, width(), titlebar->geometry().bottom()+3, FALSE );
|
||||
}
|
||||
|
||||
/*!\reimp
|
||||
*/
|
||||
Client::MousePosition BeClient::mousePosition( const QPoint& p ) const
|
||||
{
|
||||
const int range = 16;
|
||||
const int border = 4;
|
||||
|
||||
int ly = titlebar->geometry().bottom();
|
||||
int lx = titlebar->geometry().right();
|
||||
if ( p.x() > titlebar->geometry().right() ) {
|
||||
|
||||
if ( p.y() <= ly + range && p.x() >= width()-range)
|
||||
return TopRight;
|
||||
else if ( p.y() <= ly + border )
|
||||
return Top;
|
||||
} else if ( p.y() < ly ) {
|
||||
if ( p.y() > border && p.x() < lx - border )
|
||||
return Client::mousePosition( p );
|
||||
if ( p.y() < range && p.x() > lx - range )
|
||||
return TopRight;
|
||||
else if ( p.x() > lx-border )
|
||||
return Right;
|
||||
}
|
||||
|
||||
return Client::mousePosition( p );
|
||||
}
|
||||
|
||||
|
||||
void BeClient::mousePressEvent( QMouseEvent * e )
|
||||
{
|
||||
|
||||
Client::mousePressEvent( e );
|
||||
}
|
||||
|
||||
void BeClient::mouseReleaseEvent( QMouseEvent * e )
|
||||
{
|
||||
workspace()->makeFullScreen( this );
|
||||
Client::mouseReleaseEvent( e );
|
||||
}
|
||||
|
||||
|
||||
void BeClient::mouseDoubleClickEvent( QMouseEvent * e )
|
||||
{
|
||||
if ( titlebar->geometry().contains( e->pos() ) )
|
||||
setShade( !isShade() );
|
||||
workspace()->requestFocus( this );
|
||||
}
|
37
beclient.h
Normal file
37
beclient.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef BECLIENT_H
|
||||
#define BECLIENT_H
|
||||
#include "client.h"
|
||||
class QToolButton;
|
||||
class QLabel;
|
||||
class QSpacerItem;
|
||||
|
||||
|
||||
class BeClient : public Client
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
BeClient( Workspace *ws, WId w, QWidget *parent=0, const char *name=0 );
|
||||
~BeClient();
|
||||
|
||||
protected:
|
||||
void resizeEvent( QResizeEvent* );
|
||||
void paintEvent( QPaintEvent* );
|
||||
void mousePressEvent( QMouseEvent * );
|
||||
void mouseReleaseEvent( QMouseEvent * );
|
||||
void mouseDoubleClickEvent( QMouseEvent * e );
|
||||
|
||||
void captionChange( const QString& name );
|
||||
|
||||
void showEvent( QShowEvent* );
|
||||
void activeChange( bool );
|
||||
|
||||
MousePosition mousePosition( const QPoint& p ) const;
|
||||
|
||||
private:
|
||||
QSpacerItem* titlebar;
|
||||
void doShape();
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
1464
client.cpp
Normal file
1464
client.cpp
Normal file
File diff suppressed because it is too large
Load diff
285
client.h
Normal file
285
client.h
Normal file
|
@ -0,0 +1,285 @@
|
|||
#ifndef CLIENT_H
|
||||
#define CLIENT_H
|
||||
|
||||
#include "options.h"
|
||||
#include <qframe.h>
|
||||
#include <qvbox.h>
|
||||
#include <qpixmap.h>
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
class Workspace;
|
||||
class Client;
|
||||
|
||||
class KWM
|
||||
{
|
||||
public:
|
||||
static QPixmap miniIcon(Window w, int width=0, int height=0);
|
||||
static QPixmap icon(Window w, int width=0, int height=0);
|
||||
};
|
||||
|
||||
class WindowWrapper : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
WindowWrapper( WId w, Client *parent=0, const char* name=0);
|
||||
~WindowWrapper();
|
||||
|
||||
inline WId window() const;
|
||||
void releaseWindow();
|
||||
void invalidateWindow();
|
||||
QSize sizeHint() const;
|
||||
QSizePolicy sizePolicy() const;
|
||||
|
||||
protected:
|
||||
void resizeEvent( QResizeEvent * );
|
||||
void showEvent( QShowEvent* );
|
||||
void hideEvent( QHideEvent* );
|
||||
void mousePressEvent( QMouseEvent* );
|
||||
void mouseReleaseEvent( QMouseEvent* );
|
||||
void mouseMoveEvent( QMouseEvent* );
|
||||
bool x11Event( XEvent * ); // X11 event
|
||||
|
||||
private:
|
||||
WId win;
|
||||
Time lastMouseEventTime;
|
||||
};
|
||||
|
||||
inline WId WindowWrapper::window() const
|
||||
{
|
||||
return win;
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Client : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Client( Workspace *ws, WId w, QWidget *parent=0, const char *name=0, WFlags f = 0);
|
||||
~Client();
|
||||
|
||||
inline WId window() const;
|
||||
inline WindowWrapper* windowWrapper() const;
|
||||
inline Workspace* workspace() const;
|
||||
void releaseWindow();
|
||||
void invalidateWindow();
|
||||
inline WId transientFor() const;
|
||||
|
||||
virtual bool windowEvent( XEvent * );
|
||||
|
||||
void manage( bool isMapped = FALSE );
|
||||
|
||||
void setMappingState( int s );
|
||||
int mappingState() const;
|
||||
|
||||
void requestActivation();
|
||||
void withdraw();
|
||||
|
||||
QSize adjustedSize( const QSize& ) const;
|
||||
QSize minimumSize() const;
|
||||
int minimumWidth() const;
|
||||
int minimumHeight() const;
|
||||
QSize maximumSize() const;
|
||||
int maximumWidth() const;
|
||||
int maximumHeight() const;
|
||||
|
||||
inline QPixmap icon() const;
|
||||
inline QPixmap miniIcon() const;
|
||||
|
||||
|
||||
// is the window in withdrawn state?
|
||||
bool isWithdrawn(){
|
||||
return state == WithdrawnState;
|
||||
}
|
||||
// is the window in iconic state?
|
||||
bool isIconified(){
|
||||
return state == IconicState;
|
||||
}
|
||||
// is the window in normal state?
|
||||
bool isNormal(){
|
||||
return state == NormalState;
|
||||
}
|
||||
|
||||
inline bool isActive() const;
|
||||
void setActive( bool );
|
||||
|
||||
int desktop() const;
|
||||
bool isOnDesktop( int d ) const;
|
||||
|
||||
bool isShade() const;
|
||||
virtual void setShade( bool );
|
||||
|
||||
inline bool isMaximized() const;
|
||||
enum MaximizeMode { MaximizeVertical, MaximizeHorizontal, MaximizeFull };
|
||||
|
||||
inline bool isSticky() const;
|
||||
void setSticky( bool );
|
||||
|
||||
void takeFocus();
|
||||
|
||||
public slots:
|
||||
void iconify();
|
||||
void closeWindow();
|
||||
void maximize( MaximizeMode );
|
||||
void maximize();
|
||||
void fullScreen();
|
||||
void toggleSticky();
|
||||
|
||||
protected:
|
||||
void paintEvent( QPaintEvent * );
|
||||
void mousePressEvent( QMouseEvent * );
|
||||
void mouseReleaseEvent( QMouseEvent * );
|
||||
void mouseMoveEvent( QMouseEvent * );
|
||||
void enterEvent( QEvent * );
|
||||
void leaveEvent( QEvent * );
|
||||
void moveEvent( QMoveEvent * );
|
||||
void showEvent( QShowEvent* );
|
||||
void hideEvent( QHideEvent* );
|
||||
bool x11Event( XEvent * ); // X11 event
|
||||
|
||||
bool eventFilter( QObject *, QEvent * );
|
||||
|
||||
|
||||
virtual void init();
|
||||
virtual void captionChange( const QString& name );
|
||||
virtual void iconChange();
|
||||
virtual void activeChange( bool );
|
||||
virtual void maximizeChange( bool );
|
||||
virtual void stickyChange( bool );
|
||||
|
||||
|
||||
enum MousePosition {
|
||||
Nowhere, TopLeft , BottomRight, BottomLeft, TopRight, Top, Bottom, Left, Right, Center
|
||||
};
|
||||
|
||||
virtual MousePosition mousePosition( const QPoint& ) const;
|
||||
virtual void setMouseCursor( MousePosition m );
|
||||
|
||||
// handlers for X11 events
|
||||
bool mapRequest( XMapRequestEvent& e );
|
||||
bool unmapNotify( XUnmapEvent& e );
|
||||
bool configureRequest( XConfigureRequestEvent& e );
|
||||
bool propertyNotify( XPropertyEvent& e );
|
||||
|
||||
private:
|
||||
QSize sizeForWindowSize( const QSize&, bool ignore_height = FALSE ) const;
|
||||
void getWmNormalHints();
|
||||
void fetchName();
|
||||
void gravitate( bool invert );
|
||||
|
||||
|
||||
WId win;
|
||||
WindowWrapper* wwrap;
|
||||
Workspace* wspace;
|
||||
int desk;
|
||||
bool buttonDown;
|
||||
MousePosition mode;
|
||||
QPoint moveOffset;
|
||||
QPoint invertedMoveOffset;
|
||||
QSize clientSize;
|
||||
XSizeHints xSizeHint;
|
||||
void sendSynteticConfigureNotify();
|
||||
int state;
|
||||
bool active;
|
||||
int ignore_unmap;
|
||||
QRect original_geometry;
|
||||
bool shaded;
|
||||
WId transient_for;
|
||||
bool is_sticky;
|
||||
void getIcons();
|
||||
void getWindowProtocols();
|
||||
uint Pdeletewindow :1; // does the window understand the DeleteWindow protocol?
|
||||
uint Ptakefocus :1;// does the window understand the TakeFocus protocol?
|
||||
QPixmap icon_pix;
|
||||
QPixmap miniicon_pix;
|
||||
QRect geom_restore;
|
||||
};
|
||||
|
||||
inline WId Client::window() const
|
||||
{
|
||||
return win;
|
||||
}
|
||||
|
||||
inline WindowWrapper* Client::windowWrapper() const
|
||||
{
|
||||
return wwrap;
|
||||
}
|
||||
|
||||
inline Workspace* Client::workspace() const
|
||||
{
|
||||
return wspace;
|
||||
}
|
||||
|
||||
inline WId Client::transientFor() const
|
||||
{
|
||||
return transient_for;
|
||||
}
|
||||
|
||||
inline int Client::mappingState() const
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
inline bool Client::isActive() const
|
||||
{
|
||||
return active;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the virtual desktop within the workspace() the client window
|
||||
is located in, -1 if it isn't located on any special desktop. This may be
|
||||
if the window wasn't mapped yet or if the window is sticky. Do not use
|
||||
desktop() directly, use isOnDesktop() instead.
|
||||
*/
|
||||
inline int Client::desktop() const
|
||||
{
|
||||
return desk;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns whether the client is on visible or iconified on the virtual
|
||||
desktop \a d. This is always TRUE for sticky clients.
|
||||
*/
|
||||
inline bool Client::isOnDesktop( int d ) const
|
||||
{
|
||||
return desk == d || desk == -1 || isSticky();
|
||||
}
|
||||
|
||||
|
||||
inline QPixmap Client::icon() const
|
||||
{
|
||||
return icon_pix;
|
||||
}
|
||||
|
||||
inline QPixmap Client::miniIcon() const
|
||||
{
|
||||
return miniicon_pix;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Is the client maximized?
|
||||
*/
|
||||
inline bool Client::isMaximized() const
|
||||
{
|
||||
return !geom_restore.isNull();
|
||||
}
|
||||
|
||||
inline bool Client::isSticky() const
|
||||
{
|
||||
return is_sticky;
|
||||
}
|
||||
|
||||
|
||||
class NoBorderClient : public Client
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NoBorderClient( Workspace *ws, WId w, QWidget *parent=0, const char *name=0 );
|
||||
~NoBorderClient();
|
||||
};
|
||||
|
||||
#endif
|
BIN
kwin
Executable file
BIN
kwin
Executable file
Binary file not shown.
18
kwin.pro
Normal file
18
kwin.pro
Normal file
|
@ -0,0 +1,18 @@
|
|||
TEMPLATE = app
|
||||
CONFIG = qt warn_on release
|
||||
HEADERS = atoms.h \
|
||||
beclient.h \
|
||||
client.h \
|
||||
main.h \
|
||||
options.h \
|
||||
stdclient.h \
|
||||
tabbox.h \
|
||||
workspace.h
|
||||
SOURCES = atoms.cpp \
|
||||
beclient.cpp \
|
||||
client.cpp \
|
||||
main.cpp \
|
||||
stdclient.cpp \
|
||||
tabbox.cpp \
|
||||
workspace.cpp
|
||||
TARGET = kwin
|
113
main.cpp
Normal file
113
main.cpp
Normal file
|
@ -0,0 +1,113 @@
|
|||
#include "main.h"
|
||||
#include "options.h"
|
||||
#include "atoms.h"
|
||||
#include "workspace.h"
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xos.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#define INT8 _X11INT8
|
||||
#define INT32 _X11INT32
|
||||
#include <X11/Xproto.h>
|
||||
#undef INT8
|
||||
#undef INT32
|
||||
|
||||
#define i18n(x) (x)
|
||||
|
||||
Options* options;
|
||||
Atoms* atoms;
|
||||
|
||||
static bool initting = FALSE;
|
||||
int x11ErrorHandler(Display *d, XErrorEvent *e){
|
||||
char msg[80], req[80], number[80];
|
||||
bool ignore_badwindow = FALSE; //maybe temporary
|
||||
|
||||
if (initting &&
|
||||
(
|
||||
e->request_code == X_ChangeWindowAttributes
|
||||
|| e->request_code == X_GrabKey
|
||||
)
|
||||
&& (e->error_code == BadAccess)) {
|
||||
fprintf(stderr, i18n("kwin: it looks like there's already a window manager running. kwin not started\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (ignore_badwindow && (e->error_code == BadWindow || e->error_code == BadColor))
|
||||
return 0;
|
||||
|
||||
XGetErrorText(d, e->error_code, msg, sizeof(msg));
|
||||
sprintf(number, "%d", e->request_code);
|
||||
XGetErrorDatabaseText(d, "XRequest", number, "<unknown>", req, sizeof(req));
|
||||
|
||||
fprintf(stderr, "kwin: %s(0x%lx): %s\n", req, e->resourceid, msg);
|
||||
|
||||
if (initting) {
|
||||
fprintf(stderr, i18n("kwin: failure during initialisation; aborting\n"));
|
||||
exit(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Application::Application( int &argc, char *argv[] )
|
||||
: QApplication( argc, argv )
|
||||
{
|
||||
initting = TRUE;
|
||||
options = new Options;
|
||||
atoms = new Atoms;
|
||||
|
||||
// install X11 error handler
|
||||
XSetErrorHandler( x11ErrorHandler );
|
||||
|
||||
// create a workspace.
|
||||
workspaces += new Workspace();
|
||||
initting = FALSE;
|
||||
if ( argc > 1 ) {
|
||||
QString s = argv[1];
|
||||
int i = s.toInt();
|
||||
workspaces += new Workspace( (WId ) i );
|
||||
}
|
||||
|
||||
syncX();
|
||||
initting = FALSE;
|
||||
}
|
||||
|
||||
|
||||
Application::~Application()
|
||||
{
|
||||
for ( WorkspaceList::Iterator it = workspaces.begin(); it != workspaces.end(); ++it) {
|
||||
delete (*it);
|
||||
}
|
||||
}
|
||||
|
||||
bool Application::x11EventFilter( XEvent *e )
|
||||
{
|
||||
for ( WorkspaceList::Iterator it = workspaces.begin(); it != workspaces.end(); ++it) {
|
||||
if ( (*it)->workspaceEvent( e ) )
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void sighandler(int) {
|
||||
QApplication::exit();
|
||||
}
|
||||
|
||||
int main( int argc, char * argv[] ) {
|
||||
|
||||
if (signal(SIGTERM, sighandler) == SIG_IGN)
|
||||
signal(SIGTERM, SIG_IGN);
|
||||
if (signal(SIGINT, sighandler) == SIG_IGN)
|
||||
signal(SIGINT, SIG_IGN);
|
||||
if (signal(SIGHUP, sighandler) == SIG_IGN)
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
|
||||
Application a( argc, argv );
|
||||
fcntl(ConnectionNumber(qt_xdisplay()), F_SETFD, 1);
|
||||
|
||||
return a.exec();
|
||||
}
|
23
main.h
Normal file
23
main.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef MAIN_H
|
||||
#define MAIN_H
|
||||
|
||||
#include <qapplication.h>
|
||||
#include "workspace.h"
|
||||
|
||||
typedef QValueList<Workspace*> WorkspaceList;
|
||||
class Application : public QApplication
|
||||
{
|
||||
public:
|
||||
Application( int &argc, char **argv );
|
||||
~Application();
|
||||
|
||||
protected:
|
||||
bool x11EventFilter( XEvent * );
|
||||
|
||||
private:
|
||||
WorkspaceList workspaces;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
47
options.h
Normal file
47
options.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#ifndef OPTIONS_H
|
||||
#define OPTIONS_H
|
||||
|
||||
|
||||
class Options {
|
||||
public:
|
||||
|
||||
/*!
|
||||
Different focus policies:
|
||||
<ul>
|
||||
|
||||
<li>ClickToFocus - Clicking into a window activates it. This is
|
||||
also the default.
|
||||
|
||||
<li>FocusFollowsMouse - Moving the mouse pointer actively onto a
|
||||
window activates it.
|
||||
|
||||
<li>FocusUnderMouse - The window that happens to be under the
|
||||
mouse pointer becomes active.
|
||||
|
||||
<li>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 ;-)
|
||||
|
||||
</ul>
|
||||
*/
|
||||
enum FocusPolicy { ClickToFocus, FocusFollowsMouse, FocusUnderMouse, FocusStricklyUnderMouse };
|
||||
FocusPolicy focusPolicy;
|
||||
|
||||
bool focusPolicyIsReasonable() {
|
||||
return focusPolicy == ClickToFocus || focusPolicy == FocusFollowsMouse;
|
||||
}
|
||||
|
||||
Options(){
|
||||
focusPolicy = ClickToFocus;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
extern Options* options;
|
||||
|
||||
#endif
|
334
stdclient.cpp
Normal file
334
stdclient.cpp
Normal file
|
@ -0,0 +1,334 @@
|
|||
#include "stdclient.h"
|
||||
#include <qapplication.h>
|
||||
#include <qcursor.h>
|
||||
#include <qabstractlayout.h>
|
||||
#include <qlayout.h>
|
||||
#include <qtoolbutton.h>
|
||||
#include <qlabel.h>
|
||||
#include <qdrawutil.h>
|
||||
#include "workspace.h"
|
||||
|
||||
|
||||
static const char * close_xpm[] = {
|
||||
/* width height num_colors chars_per_pixel */
|
||||
"16 16 3 1",
|
||||
/* colors */
|
||||
" s None c None",
|
||||
". c white",
|
||||
"X c #707070",
|
||||
/* pixels */
|
||||
" ",
|
||||
" ",
|
||||
" .X .X ",
|
||||
" .XX .XX ",
|
||||
" .XX .XX ",
|
||||
" .XX .XX ",
|
||||
" .XX.XX ",
|
||||
" .XXX ",
|
||||
" .XXX ",
|
||||
" .XX.XX ",
|
||||
" .XX .XX ",
|
||||
" .XX .XX ",
|
||||
" .XX .XX ",
|
||||
" .X .X ",
|
||||
" ",
|
||||
" "};
|
||||
|
||||
|
||||
static const char * maximize_xpm[] = {
|
||||
/* width height num_colors chars_per_pixel */
|
||||
"16 16 3 1",
|
||||
/* colors */
|
||||
" s None c None",
|
||||
". c white",
|
||||
"X c #707070",
|
||||
/* pixels */
|
||||
" ",
|
||||
" ",
|
||||
" ........... ",
|
||||
" .XXXXXXXXXX ",
|
||||
" .X .X ",
|
||||
" .X .X ",
|
||||
" .X .X ",
|
||||
" .X .X ",
|
||||
" .X .X ",
|
||||
" .X .X ",
|
||||
" .X .X ",
|
||||
" .X........X ",
|
||||
" .XXXXXXXXXX ",
|
||||
" ",
|
||||
" ",
|
||||
" "};
|
||||
|
||||
|
||||
static const char * minimize_xpm[] = {
|
||||
/* width height num_colors chars_per_pixel */
|
||||
"16 16 3 1",
|
||||
/* colors */
|
||||
" s None c None",
|
||||
". c white",
|
||||
"X c #707070",
|
||||
/* pixels */
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ... ",
|
||||
" . X ",
|
||||
" .XX ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" "};
|
||||
|
||||
static const char * normalize_xpm[] = {
|
||||
/* width height num_colors chars_per_pixel */
|
||||
"16 16 3 1",
|
||||
/* colors */
|
||||
" s None c None",
|
||||
". c #707070",
|
||||
"X c white",
|
||||
/* pixels */
|
||||
" ",
|
||||
" ",
|
||||
" ........... ",
|
||||
" .XXXXXXXXXX ",
|
||||
" .X .X ",
|
||||
" .X .X ",
|
||||
" .X .X ",
|
||||
" .X .X ",
|
||||
" .X .X ",
|
||||
" .X .X ",
|
||||
" .X .X ",
|
||||
" .X........X ",
|
||||
" .XXXXXXXXXX ",
|
||||
" ",
|
||||
" ",
|
||||
" "};
|
||||
|
||||
static const char * pinup_xpm[] = {
|
||||
/* width height num_colors chars_per_pixel */
|
||||
"16 16 4 1",
|
||||
/* colors */
|
||||
" s None c None",
|
||||
". c #707070",
|
||||
"X c white",
|
||||
"o c #a0a0a0",
|
||||
/* pixels */
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" .. . ",
|
||||
" .X. .. ",
|
||||
" .XX...X. ",
|
||||
"XXXXXX.oXoXoX. ",
|
||||
"oooooo.oXoXoX. ",
|
||||
".......oo.o.o. ",
|
||||
" .o...... ",
|
||||
" ... .. ",
|
||||
" .. . ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" "};
|
||||
|
||||
static const char * pindown_xpm[] = {
|
||||
/* width height num_colors chars_per_pixel */
|
||||
"16 16 4 1",
|
||||
/* colors */
|
||||
" s None c None",
|
||||
". c #707070",
|
||||
"X c white",
|
||||
"o c #a0a0a0",
|
||||
/* pixels */
|
||||
" ",
|
||||
" ",
|
||||
" .... ",
|
||||
" ..XXXX. ",
|
||||
" ...XXXXXX. ",
|
||||
" .X.XXXooo. ",
|
||||
" .XX.XXooo.. ",
|
||||
" .XX..Xoo... ",
|
||||
" .XXXX..... ",
|
||||
" .XXXoooo.. ",
|
||||
" .Xoooo... ",
|
||||
" .oooo... ",
|
||||
" ...... ",
|
||||
" ",
|
||||
" ",
|
||||
" "};
|
||||
|
||||
static QPixmap* close_pix = 0;
|
||||
static QPixmap* maximize_pix = 0;
|
||||
static QPixmap* minimize_pix = 0;
|
||||
static QPixmap* normalize_pix = 0;
|
||||
static QPixmap* pinup_pix = 0;
|
||||
static QPixmap* pindown_pix = 0;
|
||||
static bool pixmaps_created = FALSE;
|
||||
|
||||
static void create_pixmaps()
|
||||
{
|
||||
if ( pixmaps_created )
|
||||
return;
|
||||
close_pix = new QPixmap( close_xpm );
|
||||
maximize_pix = new QPixmap( maximize_xpm );
|
||||
minimize_pix = new QPixmap( minimize_xpm );
|
||||
normalize_pix = new QPixmap( normalize_xpm );
|
||||
pinup_pix = new QPixmap( pinup_xpm );
|
||||
pindown_pix = new QPixmap( pindown_xpm );
|
||||
|
||||
}
|
||||
|
||||
|
||||
StdClient::StdClient( Workspace *ws, WId w, QWidget *parent, const char *name )
|
||||
: Client( ws, w, parent, name, WResizeNoErase )
|
||||
{
|
||||
create_pixmaps();
|
||||
|
||||
QFont f = font();
|
||||
f.setBold( TRUE );
|
||||
setFont( f );
|
||||
|
||||
QGridLayout* g = new QGridLayout( this, 0, 0, 2 );
|
||||
g->setRowStretch( 1, 10 );
|
||||
g->addWidget( windowWrapper(), 1, 1 );
|
||||
g->addColSpacing(0, 2);
|
||||
g->addColSpacing(2, 2);
|
||||
g->addRowSpacing(2, 2);
|
||||
|
||||
|
||||
button[0] = new QToolButton( this );
|
||||
button[1] = new QToolButton( this );
|
||||
button[2] = new QToolButton( this );
|
||||
button[3] = new QToolButton( this );
|
||||
button[4] = new QToolButton( this );
|
||||
button[5] = new QToolButton( this );
|
||||
|
||||
QHBoxLayout* hb = new QHBoxLayout;
|
||||
g->addLayout( hb, 0, 1 );
|
||||
hb->addWidget( button[0] );
|
||||
hb->addWidget( button[1] );
|
||||
hb->addWidget( button[2] );
|
||||
|
||||
int fh = fontMetrics().lineSpacing();
|
||||
|
||||
titlebar = new QSpacerItem(10, fh, QSizePolicy::Expanding,
|
||||
QSizePolicy::Minimum );
|
||||
hb->addItem( titlebar );
|
||||
|
||||
hb->addWidget( button[3] );
|
||||
hb->addWidget( button[4] );
|
||||
hb->addWidget( button[5] );
|
||||
|
||||
for ( int i = 0; i < 6; i++) {
|
||||
button[i]->setMouseTracking( TRUE );
|
||||
button[i]->setFixedSize( 20, 20 );
|
||||
}
|
||||
|
||||
button[0]->setIconSet( miniIcon() );
|
||||
button[1]->setIconSet( isSticky()?*pindown_pix:*pinup_pix );
|
||||
connect( button[1], SIGNAL( clicked() ), this, ( SLOT( toggleSticky() ) ) );
|
||||
button[2]->hide();
|
||||
|
||||
button[3]->setIconSet( *minimize_pix );
|
||||
connect( button[3], SIGNAL( clicked() ), this, ( SLOT( iconify() ) ) );
|
||||
button[4]->setIconSet( *maximize_pix );
|
||||
connect( button[4], SIGNAL( clicked() ), this, ( SLOT( maximize() ) ) );
|
||||
button[5]->setIconSet( *close_pix );
|
||||
connect( button[5], SIGNAL( clicked() ), this, ( SLOT( closeWindow() ) ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
StdClient::~StdClient()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void StdClient::resizeEvent( QResizeEvent* e)
|
||||
{
|
||||
Client::resizeEvent( e );
|
||||
|
||||
if ( isVisibleToTLW() ) {
|
||||
// manual clearing without the titlebar (we selected WResizeNoErase )
|
||||
QPainter p( this );
|
||||
QRect t = titlebar->geometry();
|
||||
t.setTop( 0 );
|
||||
QRegion r = rect();
|
||||
r = r.subtract( t );
|
||||
p.setClipRegion( r );
|
||||
p.eraseRect( rect() );
|
||||
}
|
||||
}
|
||||
|
||||
/*!\reimp
|
||||
*/
|
||||
void StdClient::captionChange( const QString& )
|
||||
{
|
||||
repaint( titlebar->geometry(), FALSE );
|
||||
}
|
||||
|
||||
|
||||
/*!\reimp
|
||||
*/
|
||||
void StdClient::maximizeChange( bool m )
|
||||
{
|
||||
button[4]->setIconSet( m?*normalize_pix:*maximize_pix );
|
||||
}
|
||||
|
||||
|
||||
/*!\reimp
|
||||
*/
|
||||
void StdClient::stickyChange( bool s)
|
||||
{
|
||||
button[1]->setIconSet( s?*pindown_pix:*pinup_pix );
|
||||
}
|
||||
|
||||
void StdClient::paintEvent( QPaintEvent* )
|
||||
{
|
||||
QPainter p( this );
|
||||
QRect t = titlebar->geometry();
|
||||
t.setTop( 0 );
|
||||
QRegion r = rect();
|
||||
r = r.subtract( t );
|
||||
p.setClipRegion( r );
|
||||
qDrawWinPanel( &p, rect(), colorGroup() );
|
||||
p.setClipping( FALSE );
|
||||
p.fillRect( t, isActive()?darkBlue:gray );
|
||||
qDrawShadePanel( &p, t.x(), t.y(), t.width(), t.height(),
|
||||
colorGroup(), TRUE );
|
||||
|
||||
t.setTop( 2 );
|
||||
t.setLeft( t.left() + 4 );
|
||||
t.setRight( t.right() - 2 );
|
||||
|
||||
p.setPen( colorGroup().light() );
|
||||
p.drawText( t, AlignLeft|AlignVCenter, caption() );
|
||||
}
|
||||
|
||||
|
||||
void StdClient::mouseDoubleClickEvent( QMouseEvent * e )
|
||||
{
|
||||
if ( titlebar->geometry().contains( e->pos() ) )
|
||||
setShade( !isShade() );
|
||||
workspace()->requestFocus( this );
|
||||
}
|
||||
|
||||
|
||||
void StdClient::init()
|
||||
{
|
||||
button[0]->setIconSet( miniIcon() );
|
||||
|
||||
// ### TODO transient etc.
|
||||
}
|
||||
|
||||
void StdClient::iconChange()
|
||||
{
|
||||
button[0]->setIconSet( miniIcon() );
|
||||
button[0]->repaint( FALSE );
|
||||
}
|
33
stdclient.h
Normal file
33
stdclient.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#ifndef STDCLIENT_H
|
||||
#define STDCLIENT_H
|
||||
#include "client.h"
|
||||
class QToolButton;
|
||||
class QLabel;
|
||||
class QSpacerItem;
|
||||
|
||||
class StdClient : public Client
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
StdClient( Workspace *ws, WId w, QWidget *parent=0, const char *name=0 );
|
||||
~StdClient();
|
||||
|
||||
protected:
|
||||
void resizeEvent( QResizeEvent* );
|
||||
void paintEvent( QPaintEvent* );
|
||||
|
||||
void mouseDoubleClickEvent( QMouseEvent * );
|
||||
|
||||
void init();
|
||||
void captionChange( const QString& name );
|
||||
void iconChange();
|
||||
void maximizeChange( bool );
|
||||
void stickyChange( bool );
|
||||
|
||||
private:
|
||||
QToolButton* button[6];
|
||||
QSpacerItem* titlebar;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
179
tabbox.cpp
Normal file
179
tabbox.cpp
Normal file
|
@ -0,0 +1,179 @@
|
|||
#include "tabbox.h"
|
||||
#include "workspace.h"
|
||||
#include "client.h"
|
||||
#include <qpainter.h>
|
||||
|
||||
const bool options_traverse_all = FALSE; // TODO
|
||||
|
||||
TabBox::TabBox( Workspace *ws, const char *name=0 )
|
||||
: QWidget( 0, name, WStyle_Customize | WStyle_NoBorder )
|
||||
{
|
||||
wspace = ws;
|
||||
reset();
|
||||
}
|
||||
|
||||
TabBox::~TabBox()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Sets the current mode to \a mode, either DesktopMode or WindowsMode
|
||||
|
||||
\sa mode()
|
||||
*/
|
||||
void TabBox::setMode( Mode mode )
|
||||
{
|
||||
m = mode;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Resets the tab box to display the active client in WindowsMode, or the
|
||||
current desktop in DesktopMode
|
||||
*/
|
||||
void TabBox::reset()
|
||||
{
|
||||
QFont f = font();
|
||||
f.setBold( TRUE );
|
||||
f.setPointSize( 14 );
|
||||
setFont( f );
|
||||
|
||||
|
||||
// TODO icons etc.
|
||||
setGeometry( qApp->desktop()->width()/4,
|
||||
qApp->desktop()->height()/2-fontMetrics().height()*2,
|
||||
qApp->desktop()->width()/2, fontMetrics().height()*4 );
|
||||
|
||||
if ( mode() == WindowsMode ) {
|
||||
client = workspace()->activeClient();
|
||||
// todo build window list, consider options_traverse_all
|
||||
}
|
||||
else { // DesktopMode
|
||||
desk = wspace->currentDesktop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Shows the next or previous item, depending on \a next
|
||||
*/
|
||||
void TabBox::nextPrev( bool next)
|
||||
{
|
||||
if ( mode() == WindowsMode ) {
|
||||
Client* sign = client;
|
||||
do {
|
||||
if (client != sign && !sign)
|
||||
sign = client;
|
||||
if ( next )
|
||||
client = workspace()->nextClient(client);
|
||||
else
|
||||
client = workspace()->previousClient(client);
|
||||
} while (client != sign && client &&
|
||||
!options_traverse_all &&
|
||||
!client->isOnDesktop(workspace()->currentDesktop()));
|
||||
|
||||
if (!options_traverse_all && client
|
||||
&& !client->isOnDesktop(workspace()->currentDesktop()))
|
||||
client = 0;
|
||||
}
|
||||
else { // DesktopMode
|
||||
if ( next ) {
|
||||
desk++;
|
||||
if ( desk > wspace->numberOfDesktops() )
|
||||
desk = 1;
|
||||
} else {
|
||||
desk--;
|
||||
if ( desk < 1 )
|
||||
desk = wspace->numberOfDesktops();
|
||||
}
|
||||
}
|
||||
|
||||
paintContents();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
Returns the currently displayed client ( only works in WindowsMode ).
|
||||
Returns 0 if no client is displayed.
|
||||
*/
|
||||
Client* TabBox::currentClient()
|
||||
{
|
||||
if ( mode() != WindowsMode )
|
||||
return 0;
|
||||
return client;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the currently displayed virtual desktop ( only works in
|
||||
DesktopMode )
|
||||
Returns -1 if no desktop is displayed.
|
||||
*/
|
||||
int TabBox::currentDesktop()
|
||||
{
|
||||
if ( mode() != DesktopMode )
|
||||
return -1;
|
||||
return desk;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Reimplemented to raise the tab box as well
|
||||
*/
|
||||
void TabBox::showEvent( QShowEvent* )
|
||||
{
|
||||
raise();
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Paints the tab box
|
||||
*/
|
||||
void TabBox::paintEvent( QPaintEvent* )
|
||||
{
|
||||
{
|
||||
QPainter p( this );
|
||||
style().drawPanel( &p, 0, 0, width(), height(), colorGroup(), FALSE );
|
||||
style().drawPanel( &p, 4, 4, width()-8, height()-8, colorGroup(), TRUE );
|
||||
}
|
||||
paintContents();
|
||||
}
|
||||
|
||||
/*!
|
||||
Paints the contents of the tab box. Used in paintEvent() and
|
||||
whenever the contents changes.
|
||||
*/
|
||||
void TabBox::paintContents()
|
||||
{
|
||||
QPainter p( this );
|
||||
QRect r(6, 6, width()-12, height()-12 );
|
||||
p.fillRect( r, colorGroup().brush( QColorGroup::Background ) );
|
||||
if ( mode () == WindowsMode ) {
|
||||
if ( currentClient() ) {
|
||||
QString s;
|
||||
if (!client->isOnDesktop(workspace()->currentDesktop())){
|
||||
//TODO s = KWM::getDesktopName(client->desktop);
|
||||
s.append(": ");
|
||||
}
|
||||
|
||||
if (client->isIconified())
|
||||
s += QString("(")+client->caption()+")";
|
||||
else
|
||||
s += client->caption();
|
||||
if ( p.fontMetrics().width( s ) > r.width() )
|
||||
p.drawText( r, AlignLeft, s );
|
||||
else
|
||||
p.drawText( r, AlignCenter, s );
|
||||
|
||||
}
|
||||
else {
|
||||
p.drawText( r, AlignCenter, "*** No Tasks ***" );
|
||||
}
|
||||
} else { // DesktopMode
|
||||
QString s;
|
||||
s.setNum( desk );
|
||||
p.drawText( r, AlignCenter, s );
|
||||
}
|
||||
}
|
63
tabbox.h
Normal file
63
tabbox.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
#ifndef TABBOX_H
|
||||
#define TABBOX_H
|
||||
#include <qwidget.h>
|
||||
|
||||
class Workspace;
|
||||
class Client;
|
||||
|
||||
typedef QValueList<Client*> ClientList;
|
||||
|
||||
class TabBox : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TabBox( Workspace *ws, const char *name=0 );
|
||||
~TabBox();
|
||||
|
||||
Client* currentClient();
|
||||
int currentDesktop();
|
||||
|
||||
enum Mode { DesktopMode, WindowsMode };
|
||||
void setMode( Mode mode );
|
||||
Mode mode() const;
|
||||
|
||||
void reset();
|
||||
void nextPrev( bool next = TRUE);
|
||||
|
||||
Workspace* workspace() const;
|
||||
|
||||
protected:
|
||||
void paintEvent( QPaintEvent* );
|
||||
void showEvent( QShowEvent* );
|
||||
void paintContents();
|
||||
|
||||
private:
|
||||
Client* client;
|
||||
Mode m;
|
||||
Workspace* wspace;
|
||||
ClientList clients;
|
||||
int desk;
|
||||
// QValueList <QLabel*> labels;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
Returns the tab box' workspace
|
||||
*/
|
||||
inline Workspace* TabBox::workspace() const
|
||||
{
|
||||
return wspace;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the current mode, either DesktopMode or WindowsMode
|
||||
|
||||
\sa setMode()
|
||||
*/
|
||||
inline TabBox::Mode TabBox::mode() const
|
||||
{
|
||||
return m;
|
||||
}
|
||||
|
||||
#endif
|
859
workspace.cpp
Normal file
859
workspace.cpp
Normal file
|
@ -0,0 +1,859 @@
|
|||
#include "workspace.h"
|
||||
#include "client.h"
|
||||
#include "stdclient.h"
|
||||
#include "beclient.h"
|
||||
#include "tabbox.h"
|
||||
#include "atoms.h"
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xos.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/keysym.h>
|
||||
|
||||
|
||||
|
||||
static Client* clientFactory( Workspace *ws, WId w )
|
||||
{
|
||||
// hack TODO hints
|
||||
char* name = 0;
|
||||
QString s;
|
||||
if ( XFetchName( qt_xdisplay(), (Window) w, &name ) && name ) {
|
||||
s = QString::fromLatin1( name );
|
||||
XFree( name );
|
||||
}
|
||||
if ( s == "desktop") {
|
||||
Client * c = new NoBorderClient( ws, w);
|
||||
ws->setDesktopClient( c );
|
||||
return c;
|
||||
}
|
||||
|
||||
return new StdClient( ws, w );
|
||||
}
|
||||
|
||||
Workspace::Workspace()
|
||||
{
|
||||
root = qt_xrootwin(); // no MDI for now
|
||||
|
||||
(void) QApplication::desktop(); // trigger creation of desktop widget
|
||||
|
||||
// select windowmanager privileges
|
||||
XSelectInput(qt_xdisplay(), root,
|
||||
KeyPressMask |
|
||||
PropertyChangeMask |
|
||||
ColormapChangeMask |
|
||||
SubstructureRedirectMask |
|
||||
SubstructureNotifyMask
|
||||
);
|
||||
|
||||
init();
|
||||
control_grab = FALSE;
|
||||
tab_grab = FALSE;
|
||||
tab_box = new TabBox( this );
|
||||
grabKey(XK_Tab, Mod1Mask);
|
||||
grabKey(XK_Tab, Mod1Mask | ShiftMask);
|
||||
grabKey(XK_Tab, ControlMask);
|
||||
grabKey(XK_Tab, ControlMask | ShiftMask);
|
||||
|
||||
}
|
||||
|
||||
Workspace::Workspace( WId rootwin )
|
||||
{
|
||||
qDebug("create MDI workspace for %d", rootwin );
|
||||
root = rootwin;
|
||||
|
||||
// select windowmanager privileges
|
||||
XSelectInput(qt_xdisplay(), root,
|
||||
KeyPressMask |
|
||||
PropertyChangeMask |
|
||||
ColormapChangeMask |
|
||||
SubstructureRedirectMask |
|
||||
SubstructureNotifyMask
|
||||
);
|
||||
|
||||
init();
|
||||
control_grab = FALSE;
|
||||
tab_grab = FALSE;
|
||||
tab_box = new TabBox( this );
|
||||
grabKey(XK_Tab, Mod1Mask);
|
||||
grabKey(XK_Tab, Mod1Mask | ShiftMask);
|
||||
grabKey(XK_Tab, ControlMask);
|
||||
grabKey(XK_Tab, ControlMask | ShiftMask);
|
||||
|
||||
}
|
||||
|
||||
void Workspace::init()
|
||||
{
|
||||
tab_box = 0;
|
||||
active_client = 0;
|
||||
should_get_focus = 0;
|
||||
desktop_client = 0;
|
||||
current_desktop = 1;
|
||||
|
||||
unsigned int i, nwins;
|
||||
Window dw1, dw2, *wins;
|
||||
XWindowAttributes attr;
|
||||
|
||||
XGrabServer( qt_xdisplay() );
|
||||
XQueryTree(qt_xdisplay(), root, &dw1, &dw2, &wins, &nwins);
|
||||
for (i = 0; i < nwins; i++) {
|
||||
XGetWindowAttributes(qt_xdisplay(), wins[i], &attr);
|
||||
if (attr.override_redirect )
|
||||
continue;
|
||||
if (attr.map_state != IsUnmapped) {
|
||||
Client* c = clientFactory( this, wins[i] );
|
||||
clients.append( c );
|
||||
if ( c != desktop_client )
|
||||
stacking_order.append( c );
|
||||
focus_chain.append( c );
|
||||
c->manage( TRUE );
|
||||
if ( c == desktop_client )
|
||||
setDesktopClient( c );
|
||||
if ( root != qt_xrootwin() ) {
|
||||
// TODO may use QWidget:.create
|
||||
qDebug(" create a mdi client");
|
||||
XReparentWindow( qt_xdisplay(), c->winId(), root, 0, 0 );
|
||||
c->move(0,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
XFree((void *) wins);
|
||||
XUngrabServer( qt_xdisplay() );
|
||||
popup = 0;
|
||||
}
|
||||
|
||||
Workspace::~Workspace()
|
||||
{
|
||||
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) {
|
||||
delete (*it);
|
||||
}
|
||||
delete tab_box;
|
||||
delete popup;
|
||||
}
|
||||
|
||||
/*!
|
||||
Handles workspace specific XEvents
|
||||
*/
|
||||
bool Workspace::workspaceEvent( XEvent * e )
|
||||
{
|
||||
Client * c = findClient( e->xany.window );
|
||||
if ( c )
|
||||
return c->windowEvent( e );
|
||||
|
||||
switch (e->type) {
|
||||
case ButtonPress:
|
||||
case ButtonRelease:
|
||||
break;
|
||||
case UnmapNotify:
|
||||
// this is special due to
|
||||
// SubstructureRedirectMask. e->xany.window is the window the
|
||||
// event is reported to. Take care not to confuse Qt.
|
||||
c = findClient( e->xunmap.window );
|
||||
|
||||
if ( c )
|
||||
return c->windowEvent( e );
|
||||
|
||||
if ( e->xunmap.event != e->xunmap.window ) // hide wm typical event from Qt
|
||||
return TRUE;
|
||||
case ReparentNotify:
|
||||
//do not confuse Qt with these events. After all, _we_ are the
|
||||
//window manager who does the reparenting.
|
||||
return true;
|
||||
case DestroyNotify:
|
||||
return destroyClient( findClient( e->xdestroywindow.window ) );
|
||||
case MapRequest:
|
||||
if ( e->xmaprequest.parent == root ) {
|
||||
c = findClient( e->xmaprequest.window );
|
||||
if ( !c ) {
|
||||
c = clientFactory( this, e->xmaprequest.window );
|
||||
if ( root != qt_xrootwin() ) {
|
||||
// TODO may use QWidget:.create
|
||||
XReparentWindow( qt_xdisplay(), c->winId(), root, 0, 0 );
|
||||
}
|
||||
clients.append( c );
|
||||
if ( c != desktop_client )
|
||||
stacking_order.append( c );
|
||||
}
|
||||
bool result = c->windowEvent( e );
|
||||
if ( c == desktop_client )
|
||||
setDesktopClient( c );
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case ConfigureRequest:
|
||||
if ( e->xconfigurerequest.parent == root ) {
|
||||
XWindowChanges wc;
|
||||
unsigned int value_mask = 0;
|
||||
wc.border_width = 0;
|
||||
wc.x = e->xconfigurerequest.x;
|
||||
wc.y = e->xconfigurerequest.y;
|
||||
wc.width = e->xconfigurerequest.width;
|
||||
wc.height = e->xconfigurerequest.height;
|
||||
wc.sibling = None;
|
||||
wc.stack_mode = Above;
|
||||
value_mask = e->xconfigurerequest.value_mask | CWBorderWidth;
|
||||
XConfigureWindow( qt_xdisplay(), e->xconfigurerequest.window, value_mask, & wc );
|
||||
|
||||
XWindowAttributes attr;
|
||||
if (XGetWindowAttributes(qt_xdisplay(), e->xconfigurerequest.window, &attr)){
|
||||
// send a synthetic configure notify in any case (even if we didn't change anything)
|
||||
XConfigureEvent c;
|
||||
c.type = ConfigureNotify;
|
||||
c.event = e->xconfigurerequest.window;
|
||||
c.window = e->xconfigurerequest.window;
|
||||
c.x = attr.x;
|
||||
c.y = attr.y;
|
||||
c.width = attr.width;
|
||||
c.height = attr.height;
|
||||
c.border_width = 0;
|
||||
XSendEvent( qt_xdisplay(), c.event, TRUE, NoEventMask, (XEvent*)&c );
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
c = findClient( e->xconfigurerequest.window );
|
||||
if ( c )
|
||||
return c->windowEvent( e );
|
||||
}
|
||||
|
||||
break;
|
||||
case KeyPress:
|
||||
return keyPress(e->xkey);
|
||||
break;
|
||||
case KeyRelease:
|
||||
return keyRelease(e->xkey);
|
||||
break;
|
||||
case FocusIn:
|
||||
break;
|
||||
case FocusOut:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*!
|
||||
Finds the client that embedds the window \a w
|
||||
*/
|
||||
Client* Workspace::findClient( WId w ) const
|
||||
{
|
||||
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) {
|
||||
if ( (*it)->window() == w )
|
||||
return *it;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the workspace's geometry
|
||||
*/
|
||||
QRect Workspace::geometry() const
|
||||
{
|
||||
if ( root == qt_xrootwin() )
|
||||
return QRect( QPoint(0, 0), QApplication::desktop()->size() );
|
||||
else {
|
||||
// todo caching, keep track of configure notify etc.
|
||||
QRect r;
|
||||
XWindowAttributes attr;
|
||||
if (XGetWindowAttributes(qt_xdisplay(), root, &attr)){
|
||||
r.setRect(0, 0, attr.width, attr.height );
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Destroys the client \a c
|
||||
*/
|
||||
bool Workspace::destroyClient( Client* c)
|
||||
{
|
||||
if ( !c )
|
||||
return FALSE;
|
||||
clients.remove( c );
|
||||
stacking_order.remove( c );
|
||||
focus_chain.remove( c );
|
||||
c->invalidateWindow();
|
||||
delete c;
|
||||
clientHidden( c );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
Auxiliary function to release a passive keyboard grab
|
||||
*/
|
||||
void Workspace::freeKeyboard(bool pass){
|
||||
if (!pass)
|
||||
XAllowEvents(qt_xdisplay(), AsyncKeyboard, CurrentTime);
|
||||
else
|
||||
XAllowEvents(qt_xdisplay(), ReplayKeyboard, CurrentTime);
|
||||
QApplication::syncX();
|
||||
}
|
||||
|
||||
/*!
|
||||
Handles alt-tab / control-tab
|
||||
*/
|
||||
bool Workspace::keyPress(XKeyEvent key)
|
||||
{
|
||||
if ( root != qt_xrootwin() )
|
||||
return FALSE;
|
||||
int kc = XKeycodeToKeysym(qt_xdisplay(), key.keycode, 0);
|
||||
int km = key.state & (ControlMask | Mod1Mask | ShiftMask);
|
||||
|
||||
const bool options_alt_tab_mode_is_CDE_style = FALSE; // TODO
|
||||
|
||||
if (!control_grab){
|
||||
|
||||
if( (kc == XK_Tab) &&
|
||||
( km == (Mod1Mask | ShiftMask)
|
||||
|| km == (Mod1Mask)
|
||||
)){
|
||||
if (!tab_grab){
|
||||
if (options_alt_tab_mode_is_CDE_style ){
|
||||
// CDE style raise / lower
|
||||
Client* c = topClientOnDesktop();
|
||||
Client* nc = c;
|
||||
if (km & ShiftMask){
|
||||
do {
|
||||
nc = previousStaticClient(nc);
|
||||
} while (nc && nc != c &&
|
||||
(!nc->isOnDesktop(currentDesktop()) ||
|
||||
nc->isIconified()));
|
||||
|
||||
}
|
||||
else
|
||||
do {
|
||||
nc = nextStaticClient(nc);
|
||||
} while (nc && nc != c &&
|
||||
(!nc->isOnDesktop(currentDesktop()) ||
|
||||
nc->isIconified()));
|
||||
if (c && c != nc)
|
||||
;//TODO lowerClient(c);
|
||||
if (nc)
|
||||
activateClient( nc );
|
||||
freeKeyboard(FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
XGrabKeyboard(qt_xdisplay(),
|
||||
root, FALSE,
|
||||
GrabModeAsync, GrabModeAsync,
|
||||
CurrentTime);
|
||||
tab_grab = TRUE;
|
||||
tab_box->setMode( TabBox::WindowsMode );
|
||||
tab_box->reset();
|
||||
}
|
||||
tab_box->nextPrev( (km & ShiftMask) == 0 );
|
||||
tab_box->show();
|
||||
}
|
||||
}
|
||||
|
||||
if (!tab_grab){
|
||||
|
||||
|
||||
if( (kc == XK_Tab) &&
|
||||
( km == (ControlMask | ShiftMask)
|
||||
|| km == (ControlMask)
|
||||
)){
|
||||
//TODO if (!options.ControlTab){
|
||||
// freeKeyboard(TRUE);
|
||||
// return TRUE;
|
||||
// }
|
||||
if (!control_grab){
|
||||
XGrabKeyboard(qt_xdisplay(),
|
||||
root, FALSE,
|
||||
GrabModeAsync, GrabModeAsync,
|
||||
CurrentTime);
|
||||
control_grab = TRUE;
|
||||
tab_box->setMode( TabBox::DesktopMode );
|
||||
tab_box->reset();
|
||||
}
|
||||
tab_box->nextPrev( (km & ShiftMask) == 0 );
|
||||
tab_box->show();
|
||||
}
|
||||
}
|
||||
|
||||
if (control_grab || tab_grab){
|
||||
if (kc == XK_Escape){
|
||||
XUngrabKeyboard(qt_xdisplay(), CurrentTime);
|
||||
tab_box->hide();
|
||||
tab_grab = FALSE;
|
||||
control_grab = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
freeKeyboard(FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*!
|
||||
Handles alt-tab / control-tab
|
||||
*/
|
||||
bool Workspace::keyRelease(XKeyEvent key)
|
||||
{
|
||||
if ( root != qt_xrootwin() )
|
||||
return FALSE;
|
||||
int i;
|
||||
if (tab_grab){
|
||||
XModifierKeymap* xmk = XGetModifierMapping(qt_xdisplay());
|
||||
for (i=0; i<xmk->max_keypermod; i++)
|
||||
if (xmk->modifiermap[xmk->max_keypermod * Mod1MapIndex + i]
|
||||
== key.keycode){
|
||||
XUngrabKeyboard(qt_xdisplay(), CurrentTime);
|
||||
tab_box->hide();
|
||||
tab_grab = false;
|
||||
if ( tab_box->currentClient() ){
|
||||
|
||||
activateClient( tab_box->currentClient() );
|
||||
}
|
||||
}
|
||||
}
|
||||
if (control_grab){
|
||||
XModifierKeymap* xmk = XGetModifierMapping(qt_xdisplay());
|
||||
for (i=0; i<xmk->max_keypermod; i++)
|
||||
if (xmk->modifiermap[xmk->max_keypermod * ControlMapIndex + i]
|
||||
== key.keycode){
|
||||
XUngrabKeyboard(qt_xdisplay(), CurrentTime);
|
||||
tab_box->hide();
|
||||
control_grab = False;
|
||||
if ( tab_box->currentDesktop() != -1 )
|
||||
switchDesktop( tab_box->currentDesktop() );
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*!
|
||||
auxiliary functions to travers all clients according the focus
|
||||
order. Useful for kwm´s Alt-tab feature.
|
||||
*/
|
||||
Client* Workspace::nextClient( Client* c ) const
|
||||
{
|
||||
if ( focus_chain.isEmpty() )
|
||||
return 0;
|
||||
ClientList::ConstIterator it = focus_chain.find( c );
|
||||
if ( it == focus_chain.end() )
|
||||
return focus_chain.last();
|
||||
if ( it == focus_chain.begin() )
|
||||
return focus_chain.last();
|
||||
--it;
|
||||
return *it;
|
||||
}
|
||||
|
||||
/*!
|
||||
auxiliary functions to travers all clients according the focus
|
||||
order. Useful for kwm´s Alt-tab feature.
|
||||
*/
|
||||
Client* Workspace::previousClient( Client* c ) const
|
||||
{
|
||||
if ( focus_chain.isEmpty() )
|
||||
return 0;
|
||||
ClientList::ConstIterator it = focus_chain.find( c );
|
||||
if ( it == focus_chain.end() )
|
||||
return focus_chain.first();
|
||||
++it;
|
||||
if ( it == focus_chain.end() )
|
||||
return focus_chain.first();
|
||||
return *it;
|
||||
}
|
||||
|
||||
/*!
|
||||
auxiliary functions to travers all clients according the static
|
||||
order. Useful for the CDE-style Alt-tab feature.
|
||||
*/
|
||||
Client* Workspace::nextStaticClient( Client* c ) const
|
||||
{
|
||||
if ( clients.isEmpty() )
|
||||
return 0;
|
||||
ClientList::ConstIterator it = clients.find( c );
|
||||
if ( it == clients.end() )
|
||||
return clients.first();
|
||||
++it;
|
||||
if ( it == clients.end() )
|
||||
return clients.first();
|
||||
return *it;
|
||||
}
|
||||
/*!
|
||||
auxiliary functions to travers all clients according the static
|
||||
order. Useful for the CDE-style Alt-tab feature.
|
||||
*/
|
||||
Client* Workspace::previousStaticClient( Client* c ) const
|
||||
{
|
||||
if ( clients.isEmpty() )
|
||||
return 0;
|
||||
ClientList::ConstIterator it = clients.find( c );
|
||||
if ( it == clients.end() )
|
||||
return clients.last();
|
||||
if ( it == clients.begin() )
|
||||
return clients.last();
|
||||
--it;
|
||||
return *it;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Returns topmost visible client within the specified layer range on
|
||||
the current desktop, or 0 if no clients are visible. \a fromLayer has to
|
||||
be smaller than \a toLayer.
|
||||
*/
|
||||
Client* Workspace::topClientOnDesktop( int fromLayer, int toLayer) const
|
||||
{
|
||||
fromLayer = toLayer = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Grabs the keysymbol \a keysym with the given modifiers \a mod
|
||||
plus all possibile combinations of Lock and NumLock
|
||||
*/
|
||||
void Workspace::grabKey(KeySym keysym, unsigned int mod){
|
||||
static int NumLockMask = 0;
|
||||
if (!keysym||!XKeysymToKeycode(qt_xdisplay(), keysym)) return;
|
||||
if (!NumLockMask){
|
||||
XModifierKeymap* xmk = XGetModifierMapping(qt_xdisplay());
|
||||
int i;
|
||||
for (i=0; i<8; i++){
|
||||
if (xmk->modifiermap[xmk->max_keypermod * i] ==
|
||||
XKeysymToKeycode(qt_xdisplay(), XK_Num_Lock))
|
||||
NumLockMask = (1<<i);
|
||||
}
|
||||
}
|
||||
XGrabKey(qt_xdisplay(),
|
||||
XKeysymToKeycode(qt_xdisplay(), keysym), mod,
|
||||
qt_xrootwin(), TRUE,
|
||||
GrabModeSync, GrabModeSync);
|
||||
XGrabKey(qt_xdisplay(),
|
||||
XKeysymToKeycode(qt_xdisplay(), keysym), mod | LockMask,
|
||||
qt_xrootwin(), TRUE,
|
||||
GrabModeSync, GrabModeSync);
|
||||
XGrabKey(qt_xdisplay(),
|
||||
XKeysymToKeycode(qt_xdisplay(), keysym), mod | NumLockMask,
|
||||
qt_xrootwin(), TRUE,
|
||||
GrabModeSync, GrabModeSync);
|
||||
XGrabKey(qt_xdisplay(),
|
||||
XKeysymToKeycode(qt_xdisplay(), keysym), mod | LockMask | NumLockMask,
|
||||
qt_xrootwin(), TRUE,
|
||||
GrabModeSync, GrabModeSync);
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
Informs the workspace about the active client, i.e. the client that
|
||||
has the focus (or None if no client has the focus). This functions
|
||||
is called by the client itself that gets focus. It has no other
|
||||
effect than fixing the focus chain and the return value of activeClient()
|
||||
*/
|
||||
void Workspace::setActiveClient( Client* c )
|
||||
{
|
||||
if ( active_client == c )
|
||||
return;
|
||||
if ( active_client )
|
||||
active_client->setActive( FALSE );
|
||||
active_client = c;
|
||||
if ( active_client ) {
|
||||
focus_chain.remove( c );
|
||||
focus_chain.append( c );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Tries to activate the client \a c. This function performs what you
|
||||
expect when clicking the respective entry in a taskbar: showing and
|
||||
raising the client (this may imply switching to the another virtual
|
||||
desktop) and putting the focus onto it. Once X really gave focus to
|
||||
the client window as requested, the client itself will call
|
||||
setActiveClient() and the operation is complete. This may not happen
|
||||
with certain focus policies, though.
|
||||
|
||||
\sa setActiveClient(), requestFocus()
|
||||
*/
|
||||
void Workspace::activateClient( Client* c)
|
||||
{
|
||||
if (!c->isOnDesktop(currentDesktop()) ) {
|
||||
// TODO switch desktop
|
||||
}
|
||||
raiseClient( c );
|
||||
c->show();
|
||||
if ( options->focusPolicyIsReasonable() )
|
||||
requestFocus( c );
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Tries to activate the client by asking X for the input focus. This
|
||||
function does not perform any show, raise or desktop switching. See
|
||||
Workspace::activateClient() instead.
|
||||
|
||||
\sa Workspace::activateClient()
|
||||
*/
|
||||
void Workspace::requestFocus( Client* c)
|
||||
{
|
||||
|
||||
//TODO will be different for non-root clients. (subclassing?)
|
||||
if ( !c ) {
|
||||
focusToNull();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( c->isVisible() && !c->isShade() ) {
|
||||
c->takeFocus();
|
||||
should_get_focus = c;
|
||||
} else if ( c->isShade() ) {
|
||||
// client cannot accept focus, but at least the window should be active (window menu, et. al. )
|
||||
focusToNull();
|
||||
c->setActive( TRUE );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Informs the workspace that the client \a c has been hidden. If it
|
||||
was the active client, the workspace activates another one.
|
||||
|
||||
\a c may already be destroyed
|
||||
*/
|
||||
void Workspace::clientHidden( Client* c )
|
||||
{
|
||||
if ( c == active_client || ( !active_client && c == should_get_focus ) ) {
|
||||
active_client = 0;
|
||||
should_get_focus = 0;
|
||||
if ( clients.contains( c ) ) {
|
||||
focus_chain.remove( c );
|
||||
focus_chain.prepend( c );
|
||||
}
|
||||
if ( options->focusPolicyIsReasonable() ) {
|
||||
for ( ClientList::ConstIterator it = focus_chain.fromLast(); it != focus_chain.begin(); --it) {
|
||||
if ( (*it)->isVisible() ) {
|
||||
requestFocus( *it );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Workspace::showPopup( const QPoint& pos, Client* c)
|
||||
{
|
||||
// experimental!!!
|
||||
|
||||
if ( !popup ) {
|
||||
popup = new QPopupMenu;
|
||||
|
||||
// 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;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
popup_client = 0;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Places the client \a c according to the workspace's layout policy
|
||||
*/
|
||||
void Workspace::doPlacement( Client* c )
|
||||
{
|
||||
randomPlacement( c );
|
||||
}
|
||||
|
||||
/*!
|
||||
Place the client \a c according to a simply "random" placement algorithm.
|
||||
*/
|
||||
void Workspace::randomPlacement(Client* c){
|
||||
const int step = 24;
|
||||
static int px = step;
|
||||
static int py = 2 * step;
|
||||
int tx,ty;
|
||||
|
||||
QRect maxRect = geometry(); // TODO
|
||||
|
||||
if (px < maxRect.x())
|
||||
px = maxRect.x();
|
||||
if (py < maxRect.y())
|
||||
py = maxRect.y();
|
||||
|
||||
px += step;
|
||||
py += 2*step;
|
||||
|
||||
if (px > maxRect.width()/2)
|
||||
px = maxRect.x() + step;
|
||||
if (py > maxRect.height()/2)
|
||||
py = maxRect.y() + step;
|
||||
tx = px;
|
||||
ty = py;
|
||||
if (tx + c->width() > maxRect.right()){
|
||||
tx = maxRect.right() - c->width();
|
||||
if (tx < 0)
|
||||
tx = 0;
|
||||
px = maxRect.x();
|
||||
}
|
||||
if (ty + c->height() > maxRect.bottom()){
|
||||
ty = maxRect.bottom() - c->height();
|
||||
if (ty < 0)
|
||||
ty = 0;
|
||||
py = maxRect.y();
|
||||
}
|
||||
c->move( tx, ty );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
Raises the client \a c taking layers, transient windows and window
|
||||
groups into account.
|
||||
*/
|
||||
void Workspace::raiseClient( Client* c )
|
||||
{
|
||||
if ( !c )
|
||||
return;
|
||||
if ( c == desktop_client )
|
||||
return; // deny
|
||||
|
||||
Window* new_stack = new Window[ stacking_order.count()+1];
|
||||
|
||||
stacking_order.remove( c );
|
||||
stacking_order.append( c );
|
||||
|
||||
ClientList saveset;
|
||||
saveset.append( c );
|
||||
raiseTransientsOf(saveset, c );
|
||||
|
||||
int i = 0;
|
||||
for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
|
||||
new_stack[i++] = (*it)->winId();
|
||||
}
|
||||
XRaiseWindow(qt_xdisplay(), new_stack[0]);
|
||||
XRestackWindows(qt_xdisplay(), new_stack, i);
|
||||
delete [] new_stack;
|
||||
|
||||
if ( c->transientFor() )
|
||||
raiseClient( findClient( c->transientFor() ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
Private auxiliary function used in raiseClient()
|
||||
*/
|
||||
void Workspace::raiseTransientsOf( ClientList& safeset, Client* c )
|
||||
{
|
||||
ClientList local = stacking_order;
|
||||
for ( ClientList::ConstIterator it = local.begin(); it != local.end(); ++it) {
|
||||
if ( (*it)->transientFor() == c->window() && !safeset.contains( *it ) ) {
|
||||
safeset.append( *it );
|
||||
stacking_order.remove( *it );
|
||||
stacking_order.append( *it );
|
||||
raiseTransientsOf( safeset, *it );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Puts the focus on a dummy winodw
|
||||
*/
|
||||
void Workspace::focusToNull(){
|
||||
static Window w = 0;
|
||||
int mask;
|
||||
XSetWindowAttributes attr;
|
||||
if (w == 0) {
|
||||
mask = CWOverrideRedirect;
|
||||
attr.override_redirect = 1;
|
||||
w = XCreateWindow(qt_xdisplay(), qt_xrootwin(), 0, 0, 1, 1, 0, CopyFromParent,
|
||||
InputOnly, CopyFromParent, mask, &attr);
|
||||
XMapWindow(qt_xdisplay(), w);
|
||||
}
|
||||
XSetInputFocus(qt_xdisplay(), w, RevertToPointerRoot, CurrentTime );
|
||||
//colormapFocus(0); TODO
|
||||
}
|
||||
|
||||
void Workspace::setDesktopClient( Client* c)
|
||||
{
|
||||
desktop_client = c;
|
||||
if ( desktop_client ) {
|
||||
desktop_client->lower();
|
||||
desktop_client->setGeometry( geometry() );
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
|
||||
if ( (*it)->isVisible() && !(*it)->isOnDesktop( new_desktop ) ) {
|
||||
(*it)->hide();
|
||||
}
|
||||
}
|
||||
|
||||
for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it) {
|
||||
if ( (*it)->isOnDesktop( new_desktop ) ) {
|
||||
(*it)->show();
|
||||
//XMapWindow( qt_xdisplay(), (*it)->winId() );
|
||||
}
|
||||
}
|
||||
|
||||
current_desktop = new_desktop;
|
||||
}
|
||||
|
||||
|
||||
void Workspace::makeFullScreen( Client* )
|
||||
{
|
||||
// not yet implemented
|
||||
}
|
||||
|
||||
|
||||
// experimental
|
||||
void Workspace::setDecoration( int deco )
|
||||
{
|
||||
if ( !popup_client )
|
||||
return;
|
||||
Client* c = popup_client;
|
||||
WId w = c->window();
|
||||
clients.remove( c );
|
||||
stacking_order.remove( c );
|
||||
focus_chain.remove( c );
|
||||
bool mapped = c->isVisible();
|
||||
c->hide();
|
||||
c->releaseWindow();
|
||||
switch ( deco ) {
|
||||
case 1:
|
||||
c = new BeClient( this, w);
|
||||
break;
|
||||
default:
|
||||
c = new StdClient( this, w );
|
||||
}
|
||||
clients.append( c );
|
||||
stacking_order.append( c );
|
||||
c->manage( mapped );
|
||||
activateClient( c );
|
||||
}
|
||||
|
126
workspace.h
Normal file
126
workspace.h
Normal file
|
@ -0,0 +1,126 @@
|
|||
#ifndef WORKSPACE_H
|
||||
#define WORKSPACE_H
|
||||
|
||||
#include <qwidget.h>
|
||||
#include <qapplication.h>
|
||||
#include <qpopupmenu.h>
|
||||
#include <qvaluelist.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
class Client;
|
||||
class TabBox;
|
||||
|
||||
typedef QValueList<Client*> ClientList;
|
||||
|
||||
class Workspace : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Workspace();
|
||||
Workspace( WId rootwin );
|
||||
virtual ~Workspace();
|
||||
|
||||
virtual bool workspaceEvent( XEvent * );
|
||||
|
||||
Client* findClient( WId w ) const;
|
||||
|
||||
QRect geometry() const;
|
||||
|
||||
bool destroyClient( Client* );
|
||||
|
||||
WId rootWin() const;
|
||||
|
||||
Client* activeClient() const;
|
||||
void setActiveClient( Client* );
|
||||
void activateClient( Client* );
|
||||
void requestFocus( Client* c);
|
||||
|
||||
void doPlacement( Client* c );
|
||||
void raiseClient( Client* c );
|
||||
|
||||
void clientHidden( Client* );
|
||||
|
||||
int currentDesktop() const;
|
||||
int numberOfDesktops() const;
|
||||
|
||||
void grabKey(KeySym keysym, unsigned int mod);
|
||||
|
||||
Client* nextClient(Client*) const;
|
||||
Client* previousClient(Client*) const;
|
||||
Client* nextStaticClient(Client*) const;
|
||||
Client* previousStaticClient(Client*) const;
|
||||
|
||||
//#### TODO right layers as default
|
||||
Client* topClientOnDesktop( int fromLayer = 0, int toLayer = 0) const;
|
||||
|
||||
|
||||
void showPopup( const QPoint&, Client* );
|
||||
|
||||
void setDesktopClient( Client* );
|
||||
void switchDesktop( int new_desktop );
|
||||
|
||||
void makeFullScreen( Client* );
|
||||
|
||||
protected:
|
||||
bool keyPress( XKeyEvent key );
|
||||
bool keyRelease( XKeyEvent key );
|
||||
|
||||
private:
|
||||
void init();
|
||||
WId root;
|
||||
ClientList clients;
|
||||
ClientList stacking_order;
|
||||
ClientList focus_chain;
|
||||
Client* active_client;
|
||||
bool control_grab;
|
||||
bool tab_grab;
|
||||
TabBox* tab_box;
|
||||
void freeKeyboard(bool pass);
|
||||
QPopupMenu *popup;
|
||||
Client* should_get_focus;
|
||||
|
||||
void raiseTransientsOf( ClientList& safeset, Client* c );
|
||||
void randomPlacement(Client* c);
|
||||
|
||||
void focusToNull();
|
||||
Client* desktop_client;
|
||||
int current_desktop;
|
||||
|
||||
Client* popup_client;
|
||||
|
||||
//experimental
|
||||
void setDecoration( int deco );
|
||||
};
|
||||
|
||||
inline WId Workspace::rootWin() const
|
||||
{
|
||||
return root;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the active client, i.e. the client that has the focus (or None if no
|
||||
client has the focus)
|
||||
*/
|
||||
inline Client* Workspace::activeClient() const
|
||||
{
|
||||
return active_client;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Returns the current virtual desktop of this workspace
|
||||
*/
|
||||
inline int Workspace::currentDesktop() const
|
||||
{
|
||||
return current_desktop;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the number of virtual desktops of this workspace
|
||||
*/
|
||||
inline int Workspace::numberOfDesktops() const
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue