More keyboard commands such as "Window move" and "Window resize".

"Mouse emulation" (defaults to F12 currently) provides mouse emulation with
[Ctrl|Alt]-ArrowKeys.  Unfortunatly, dragging isn't (technically) possible with
X, but at least normal clicks work with Space or Return.

svn path=/trunk/kdebase/kwin/; revision=35919
This commit is contained in:
Matthias Ettrich 1999-12-06 00:43:55 +00:00
parent 6d59623f8f
commit 935c0a4478
5 changed files with 339 additions and 20 deletions

View file

@ -20,6 +20,8 @@
extern Atom qt_wm_state;
extern Time kwin_time;
static bool resizeHorizontalDirectionFixed = FALSE;
static bool resizeVerticalDirectionFixed = FALSE;
static QRect* visible_bound = 0;
@ -82,7 +84,7 @@ static void sendClientMessage(Window w, Atom a, long x){
There's not much to know about this class, it's completley handled by
the abstract class Client. You get access to the window wrapper with
Client:.windowWrapper(). The big advantage of WindowWrapper is,
Client::windowWrapper(). The big advantage of WindowWrapper is,
that you can use just like a normal QWidget, although it encapsulates
an X window that belongs to another application.
@ -823,6 +825,7 @@ void Client::mouseReleaseEvent( QMouseEvent * e)
setGeometry( geom );
moveResizeMode = FALSE;
releaseMouse();
releaseKeyboard();
}
}
}
@ -1402,12 +1405,12 @@ void Client::setShade( bool s )
*/
void Client::setActive( bool act)
{
if ( act )
workspace()->setActiveClient( this );
if ( active == act )
return;
active = act;
if ( active )
workspace()->setActiveClient( this );
activeChange( active );
}
@ -1517,7 +1520,7 @@ Client* Client::mainClient()
Returns whether the window provides context help or not. If it does,
you should show a help menu item or a help button lie '?' and call
contextHelp() if this is invoked.
\sa contextHelp()
*/
bool Client::providesContextHelp() const
@ -1529,7 +1532,7 @@ bool Client::providesContextHelp() const
/*!
Invokes context help on the window. Only works if the window
actually provides context help.
\sa providesContextHelp()
*/
void Client::contextHelp()
@ -1541,6 +1544,9 @@ void Client::contextHelp()
}
/*!
Performs a mouse command on this client (see options.h)
*/
bool Client::performMouseCommand( Options::MouseCommand command, QPoint globalPos)
{
bool replay = FALSE;
@ -1581,6 +1587,7 @@ bool Client::performMouseCommand( Options::MouseCommand command, QPoint globalPo
moveOffset = mapFromGlobal( globalPos );
invertedMoveOffset = rect().bottomRight() - moveOffset;
grabMouse( arrowCursor );
grabKeyboard();
if ( options->moveMode != Options::Opaque )
XGrabServer( qt_xdisplay() );
break;
@ -1602,6 +1609,9 @@ bool Client::performMouseCommand( Options::MouseCommand command, QPoint globalPo
invertedMoveOffset = rect().bottomRight() - moveOffset;
setMouseCursor( mode );
grabMouse( cursor() );
grabKeyboard();
resizeHorizontalDirectionFixed = FALSE;
resizeVerticalDirectionFixed = FALSE;
if ( options->resizeMode != Options::Opaque )
XGrabServer( qt_xdisplay() );
break;
@ -1615,6 +1625,98 @@ bool Client::performMouseCommand( Options::MouseCommand command, QPoint globalPo
}
void Client::keyPressEvent( QKeyEvent * e )
{
if ( !isMove() && !isResize() )
return;
bool is_control = e->state() & ControlButton;
int delta = is_control?1:8;
QPoint pos = QCursor::pos();
switch ( e->key() ) {
case Key_Left:
pos.rx() -= delta;
if ( pos.x() <= workspace()->geometry().left() ) {
moveOffset.rx() += delta;
invertedMoveOffset.rx() += delta;
}
if ( isResize() && !resizeHorizontalDirectionFixed ) {
resizeHorizontalDirectionFixed = TRUE;
if ( mode == BottomRight )
mode = BottomLeft;
else if ( mode == TopRight )
mode = TopLeft;
setMouseCursor( mode );
grabMouse( cursor() );
}
break;
case Key_Right:
pos.rx() += delta;
if ( pos.x() >= workspace()->geometry().right() ) {
moveOffset.rx() -= delta;
invertedMoveOffset.rx() -= delta;
}
if ( isResize() && !resizeHorizontalDirectionFixed ) {
resizeHorizontalDirectionFixed = TRUE;
if ( mode == BottomLeft )
mode = BottomRight;
else if ( mode == TopLeft )
mode = TopRight;
setMouseCursor( mode );
grabMouse( cursor() );
}
break;
case Key_Up:
pos.ry() -= delta;
if ( pos.y() <= workspace()->geometry().top() ) {
moveOffset.ry() += delta;
invertedMoveOffset.ry() += delta;
}
if ( isResize() && !resizeVerticalDirectionFixed ) {
resizeVerticalDirectionFixed = TRUE;
if ( mode == BottomLeft )
mode = TopLeft;
else if ( mode == BottomRight )
mode = TopRight;
setMouseCursor( mode );
grabMouse( cursor() );
}
break;
case Key_Down:
pos.ry() += delta;
if ( pos.y() >= workspace()->geometry().bottom() ) {
moveOffset.ry() -= delta;
invertedMoveOffset.ry() -= delta;
}
if ( isResize() && !resizeVerticalDirectionFixed ) {
resizeVerticalDirectionFixed = TRUE;
if ( mode == TopLeft )
mode = BottomLeft;
else if ( mode == TopRight )
mode = BottomRight;
setMouseCursor( mode );
grabMouse( cursor() );
}
break;
case Key_Space:
case Key_Return:
case Key_Enter:
clearbound();
if ( ( isMove() && options->moveMode != Options::Opaque )
|| ( isResize() && options->resizeMode != Options::Opaque ) )
XUngrabServer( qt_xdisplay() );
setGeometry( geom );
moveResizeMode = FALSE;
releaseMouse();
releaseKeyboard();
buttonDown = FALSE;
break;
default:
return;
}
QCursor::setPos( pos );
}
NoBorderClient::NoBorderClient( Workspace *ws, WId w, QWidget *parent, const char *name )
: Client( ws, w, parent, name )
{

View file

@ -129,7 +129,7 @@ public:
virtual bool wantsTabFocus() const { return TRUE;} //### just for now
bool providesContextHelp() const;
bool performMouseCommand( Options::MouseCommand, QPoint globalPos );
@ -147,6 +147,7 @@ protected:
void mousePressEvent( QMouseEvent * );
void mouseReleaseEvent( QMouseEvent * );
void mouseMoveEvent( QMouseEvent * );
void keyPressEvent( QKeyEvent * );
void resizeEvent( QResizeEvent * );
virtual void windowWrapperShowEvent( QShowEvent* ){}
virtual void windowWrapperHideEvent( QHideEvent* ){}

View file

@ -15,3 +15,7 @@
keys->insertItem(i18n("Window maximize horizontal"),"Window maximize horizontal", "");
keys->insertItem(i18n("Window iconify"),"Window iconify", "");
keys->insertItem(i18n("Window shade"),"Window shade", "");
keys->insertItem(i18n("Window move"),"Window move", "");
keys->insertItem(i18n("Window resize"),"Window resize", "");
keys->insertItem(i18n("Mouse emulation"),"Mouse emulation", "F12");

View file

@ -18,6 +18,7 @@
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
#include <X11/keysymdef.h>
#include <X11/extensions/shape.h>
extern Time kwin_time;
@ -120,6 +121,7 @@ Workspace::Workspace()
control_grab = FALSE;
tab_grab = FALSE;
mouse_emulation = FALSE;
tab_box = new TabBox( this );
}
@ -235,6 +237,11 @@ Workspace::~Workspace()
*/
bool Workspace::workspaceEvent( XEvent * e )
{
if ( mouse_emulation && e->type == ButtonPress || e->type == ButtonRelease ) {
mouse_emulation = FALSE;
XUngrabKeyboard( qt_xdisplay(), kwin_time );
}
Client * c = findClient( e->xany.window );
if ( c )
return c->windowEvent( e );
@ -349,9 +356,20 @@ bool Workspace::workspaceEvent( XEvent * e )
}
break;
case KeyPress:
if ( QWidget::keyboardGrabber() ) {
freeKeyboard( FALSE );
break;
}
if ( mouse_emulation )
return keyPressMouseEmulation( e->xkey );
return keyPress(e->xkey);
break;
case KeyRelease:
if ( QWidget::keyboardGrabber() ) {
freeKeyboard( FALSE );
break;
}
if ( mouse_emulation )
return FALSE;
return keyRelease(e->xkey);
break;
case FocusIn:
@ -831,6 +849,8 @@ void Workspace::requestFocus( Client* c)
if ( !popup || !popup->isVisible() )
popup_client = c;
active_client = c;
if ( c->isVisible() && !c->isShade() ) {
c->takeFocus();
@ -916,6 +936,12 @@ void Workspace::performWindowOperation( Client* c, Options::WindowOperation op )
return;
switch ( op ) {
case Options::MoveOp:
c->performMouseCommand( Options::MouseMove, QCursor::pos() );
break;
case Options::ResizeOp:
c->performMouseCommand( Options::MouseResize, QCursor::pos() );
break;
case Options::CloseOp:
c->closeWindow();
break;
@ -935,8 +961,7 @@ void Workspace::performWindowOperation( Client* c, Options::WindowOperation op )
void Workspace::clientPopupActivated( int id )
{
if ( popup_client )
performWindowOperation( popup_client, (Options::WindowOperation) id );
performWindowOperation( popup_client, (Options::WindowOperation) id );
}
/*!
@ -1499,6 +1524,11 @@ void Workspace::propagateClients( bool onlyStacking )
}
/*!
Check whether \a w is a dock window. If so, add it to the respective
datastructures and propagate it to the world.
*/
bool Workspace::addDockwin( WId w )
{
WId dockFor = 0;
@ -1512,6 +1542,10 @@ bool Workspace::addDockwin( WId w )
return TRUE;
}
/*!
Check whether \a w is a dock window. If so, remove it from the
respective datastructures and propagate this to the world.
*/
bool Workspace::removeDockwin( WId w )
{
if ( !dockwins.contains( w ) )
@ -1521,6 +1555,12 @@ bool Workspace::removeDockwin( WId w )
return TRUE;
}
/*!
Returns whether iconify means actually withdraw for client \a. This
is TRUE for clients that have a docking window. In that case the
docking window will serve as icon replacement.
*/
bool Workspace::iconifyMeansWithdraw( Client* c)
{
for ( DockWindowList::ConstIterator it = dockwins.begin(); it != dockwins.end(); ++it ) {
@ -1547,6 +1587,9 @@ void Workspace::propagateDockwins()
}
/*!
Create the global accel object \c keys.
*/
void Workspace::createKeybindings(){
keys = new KGlobalAccel();
@ -1568,7 +1611,10 @@ void Workspace::createKeybindings(){
keys->connectItem( "Window maximize vertical", this, SLOT( slotWindowMaximizeVertical() ) );
keys->connectItem( "Window iconify", this, SLOT( slotWindowIconify() ) );
keys->connectItem( "Window shade", this, SLOT( slotWindowShade() ) );
keys->connectItem( "Window move", this, SLOT( slotWindowMove() ) );
keys->connectItem( "Window resize", this, SLOT( slotWindowResize() ) );
keys->connectItem( "Mouse emulation", this, SLOT( slotMouseEmulation() ) );
keys->readSettings();
}
@ -1598,33 +1644,70 @@ void Workspace::slotSwitchDesktop8(){
}
/*!
Maximizes the popup client
*/
void Workspace::slotWindowMaximize()
{
if ( popup_client )
popup_client->maximize( Client::MaximizeFull );
}
/*!
Maximizes the popup client vertically
*/
void Workspace::slotWindowMaximizeVertical()
{
if ( popup_client )
popup_client->maximize( Client::MaximizeVertical );
}
/*!
Maximizes the popup client horiozontally
*/
void Workspace::slotWindowMaximizeHorizontal()
{
if ( popup_client )
popup_client->maximize( Client::MaximizeHorizontal );
}
/*!
Iconifies the popup client
*/
void Workspace::slotWindowIconify()
{
if ( popup_client )
popup_client->iconify();
performWindowOperation( popup_client, Options::IconifyOp );
}
/*!
Shades/unshades the popup client respectively
*/
void Workspace::slotWindowShade()
{
if ( popup_client )
popup_client->setShade( !popup_client->isShade() );
performWindowOperation( popup_client, Options::ShadeOp );
}
/*!
Invokes keyboard mouse emulation
*/
void Workspace::slotMouseEmulation()
{
if ( XGrabKeyboard(qt_xdisplay(),
root, FALSE,
GrabModeAsync, GrabModeAsync,
kwin_time) == GrabSuccess ) {
mouse_emulation = TRUE;
}
}
/*!
Adjusts the desktop popup to the current values and the location of
the popup client.
*/
void Workspace::desktopPopupAboutToShow()
{
if ( !desk_popup )
@ -1641,6 +1724,12 @@ void Workspace::desktopPopupAboutToShow()
}
}
/*!
The client popup menu will become visible soon.
Adjust the items according to the respective popup client.
*/
void Workspace::clientPopupAboutToShow()
{
if ( !popup_client || !popup )
@ -1649,6 +1738,10 @@ void Workspace::clientPopupAboutToShow()
popup->setItemChecked( Options::ShadeOp, popup_client->isShade() );
}
/*!
Sends the activeClient() to desktop \a desk
*/
void Workspace::sendToDesktop( int desk )
{
if ( !popup_client )
@ -1677,6 +1770,10 @@ void Workspace::sendToDesktop( int desk )
}
}
/*!
Shows the window operations popup menu for the activeClient()
*/
void Workspace::slotWindowOperations()
{
if ( !active_client )
@ -1685,14 +1782,34 @@ void Workspace::slotWindowOperations()
p->popup( active_client->mapToGlobal( active_client->windowWrapper()->geometry().topLeft() ) );
}
/*!
Closes the popup client
*/
void Workspace::slotWindowClose()
{
if ( popup_client )
popup_client->closeWindow();
performWindowOperation( popup_client, Options::CloseOp );
}
/*
/*!
Starts keyboard move mode for the popup client
*/
void Workspace::slotWindowMove()
{
performWindowOperation( popup_client, Options::MoveOp );
}
/*!
Starts keyboard resize mode for the popup client
*/
void Workspace::slotWindowResize()
{
performWindowOperation( popup_client, Options::ResizeOp );
}
/*!
Client \a c is moved around to position \a pos. This gives the
workspace the opportunity to interveniate and to implement
snap-to-windows functionality.
@ -1793,3 +1910,93 @@ QPoint Workspace::adjustClientPosition( Client* c, QPoint pos )
}
return pos;
}
/*!
Handles keypress event during mouse emulation
*/
bool Workspace::keyPressMouseEmulation( XKeyEvent key )
{
if ( root != qt_xrootwin() )
return FALSE;
int kc = XKeycodeToKeysym(qt_xdisplay(), key.keycode, 0);
int km = key.state & (ControlMask | Mod1Mask | ShiftMask);
bool is_control = km & ControlMask;
bool is_alt = km & Mod1Mask;
int delta = is_control?1:is_alt?32:8;
QPoint pos = QCursor::pos();
switch ( kc ) {
case XK_Left:
case XK_KP_Left:
pos.rx() -= delta;
break;
case XK_Right:
case XK_KP_Right:
pos.rx() += delta;
break;
case XK_Up:
case XK_KP_Up:
pos.ry() -= delta;
break;
case XK_Down:
case XK_KP_Down:
pos.ry() += delta;
break;
case XK_Return:
case XK_space:
case XK_KP_Enter:
case XK_KP_Space:
{
Window root;
Window child = qt_xrootwin();
int root_x, root_y, lx, ly;
uint state;
Window w;
Client * c = 0;
do {
w = child;
if (!c)
c = findClientWidthId( w );
XQueryPointer( qt_xdisplay(), w, &root, &child,
&root_x, &root_y, &lx, &ly, &state );
} while ( child != None && child != w );
if ( c && !c->isActive() )
activateClient( c );
QWidget* widget = QWidget::find( w );
if ( (!widget || widget->inherits("QToolButton") ) && !findClient( w ) ) {
XButtonEvent e;
e.type = ButtonPress;
e.window = w;
e.root = qt_xrootwin();
e.subwindow = w;
e.time = kwin_time;
e.x = lx;
e.y = ly;
e.x_root = root_x;
e.y_root = root_y;
e.state = key.state;
e.button = Button1;
XSendEvent( qt_xdisplay(), w, TRUE, ButtonPressMask, (XEvent*)&e );
e.type = ButtonRelease;
e.state = key.state & Button1Mask;
XSendEvent( qt_xdisplay(), w, TRUE, ButtonReleaseMask, (XEvent*)&e );
}
}
// fall through
case XK_Escape:
XUngrabKeyboard(qt_xdisplay(), kwin_time);
mouse_emulation = FALSE;
return TRUE;
default:
return FALSE;
}
QCursor::setPos( pos );
return TRUE;
}

View file

@ -97,7 +97,7 @@ public:
bool iconifyMeansWithdraw( Client* );
void iconifyOrDeiconifyTransientsOf( Client* );
bool hasCaption( const QString& caption );
void performWindowOperation( Client* c, Options::WindowOperation op );
@ -123,7 +123,10 @@ public slots:
void slotWindowOperations();
void slotWindowClose();
void slotWindowMove();
void slotWindowResize();
void slotMouseEmulation();
private slots:
void setDecorationStyle( int );
@ -135,6 +138,7 @@ private slots:
protected:
bool keyPress( XKeyEvent key );
bool keyRelease( XKeyEvent key );
bool keyPressMouseEmulation( XKeyEvent key );
bool clientMessage( XClientMessageEvent msg );
private:
@ -148,6 +152,7 @@ private:
Client* active_client;
bool control_grab;
bool tab_grab;
bool mouse_emulation;
TabBox* tab_box;
void freeKeyboard(bool pass);
QGuardedPtr<Client> popup_client;
@ -181,7 +186,7 @@ private:
bool removeDockwin( WId w );
void propagateDockwins();
DockWindow findDockwin( WId w );
//CT needed for cascading+
struct CascadingInfo {
QPoint pos;