TWin: Active borders and snap tiling

This commit is a squash of the commits of TDE/tdebase#331.

In short, this backports some improvements to existing electric border
functionality from KDE, adds the snap tiling (or aerosnap) feature and
brings rudimentary support for active corners, which will be fully
implemented in a later PR.

The options dialog and the documentation has been updated to reflect
these changes.

Additionally, a new relevant option is introduced: an option for
restoring the original size of maximized/tiled windows when the user
starts dragging them. The option is set to be off by default,
preserving the traditional behaviour of KDE 3.x/TDE.

Last but not least, the term "electric" in relation to borders and
corners is replaced by "active" for clarity to the users.

Signed-off-by: Mavridis Philippe <mavridisf@gmail.com>
pull/331/head
Mavridis Philippe 1 year ago
parent 3285a47d5d
commit 31335a04ed
No known key found for this signature in database
GPG Key ID: 93F66F98F906147D

@ -615,6 +615,13 @@ to allow moving or resizing maximized windows.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Restore size of maximized/tiled windows when moving</guilabel></term>
<listitem>
<para>When enabled, this feature restores the original size of a maximized or <link linkend="active-borders">tiled</link> window when the window is dragged.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Placement</guilabel></term>
<listitem>
@ -739,36 +746,46 @@ Use the slider widget to configure the delay.
</variablelist>
<variablelist>
<title>Active Desktop Borders</title>
<variablelist id="active-borders">
<title>Active Borders</title>
<para>Active Borders is a feature which allows you to quickly perform window management actions by moving your mouse into a desktop border.</para>
<para>The corresponding section allows you to configure the function that will be performed when pushing your mouse cursor against a border or moving a window into it:</para>
<varlistentry>
<term><guilabel>Disabled</guilabel></term>
<listitem>
<para>When this option is enabled, moving the mouse pointer to a screen
border will change your desktop. This is useful when you want to drag
windows from one desktop to another.</para>
<para>This option disables the Active Borders feature.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Only when moving windows</guilabel></term>
<term><guilabel>Switch desktop</guilabel></term>
<listitem>
<para>Moving your mouse pointer against the side of the screen will
switch to a new desktop only while moving a window.</para>
<para>Moving your mouse pointer against the side of the screen will switch to another desktop.</para>
<para>By default the switch occurs both when moving your mouse pointer into a border and dragging a window into it. The <guilabel>Switch desktop only when moving a window</guilabel> checkbox disables the former behaviour and only switches to another desktop when a window is being dragged into a desktop border.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Always enabled</guilabel></term>
<term><guilabel>Tile window</guilabel></term>
<listitem>
<para>Moving your mouse pointer against the side of the screen will
always switch to a new desktop.</para>
<para>Dragging a window into a desktop border will tile that window at that side of the screen. This feature is also known as <quote>Aerosnap</quote> or <quote>Quick Tile</quote>.</para>
<para><guilabel>Maximize windows by dragging them to the top of the screen</guilabel> changes the behaviour of the top border of the desktop. If this option is enabled, dragging a window into the top border will not result in tiling, but the window will become maximized instead.</para>
<para>By default dragging a tiled window does not reset its original size. This behaviour is controlled by an option in the <link linkend="moving">Moving</link> tab of this control module.</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<guilabel>Border activation delay</guilabel>.
This option controls the delay before the designated active border function is performed. A higher value can prevent accidental activations of this feature.
</para>
<sect3>
<title>Other</title>
<para>
<guilabel>Hide utility windows for inactive applications</guilabel>. When
enabled, utility windows (tool windows, torn-off menus) of
@ -776,6 +793,7 @@ inactive applications will be hidden and will be shown only when the
application becomes active. Note that applications have to mark the windows
with the proper window type for this feature to work.
</para>
</sect3>
</sect2>

@ -120,7 +120,9 @@ Client::Client( Workspace *ws )
border_top( 0 ),
border_bottom( 0 ),
opacity_( 0 ),
demandAttentionKNotifyTimer( NULL )
demandAttentionKNotifyTimer( NULL ),
activeMaximizing(false),
activeTiled(false)
// SELI do all as initialization
{
autoRaiseTimer = 0;

@ -232,6 +232,11 @@ class Client : public TQObject, public KDecorationDefines
void resizeWithChecks( int w, int h, ForceGeometry_t force = NormalGeometrySet );
void resizeWithChecks( const TQSize& s, ForceGeometry_t force = NormalGeometrySet );
void keepInArea( TQRect area, bool partial = false );
void setActiveBorderMode( ActiveMaximizingMode mode );
ActiveMaximizingMode activeBorderMode() const;
void setActiveBorderMaximizing(bool maximizing);
bool isActiveBorderMaximizing() const;
TQRect activeBorderMaximizeGeometry();
void growHorizontal();
void shrinkHorizontal();
@ -600,6 +605,11 @@ class Client : public TQObject, public KDecorationDefines
bool isBMP_;
TQTimer* demandAttentionKNotifyTimer;
bool activeMaximizing;
bool activeTiled;
TQRect activeTiledOrigGeom;
ActiveMaximizingMode activeMode;
friend bool performTransiencyCheck();
bool minimized_before_suspend;
};

@ -389,7 +389,7 @@ bool Workspace::workspaceEvent( XEvent * e )
if ( w )
TQWhatsThis::leaveWhatsThisMode();
}
if( electricBorder(e))
if (activeBorderEvent(e))
return true;
break;
}
@ -454,7 +454,7 @@ bool Workspace::workspaceEvent( XEvent * e )
case FocusOut:
return true; // always eat these, they would tell Qt that KWin is the active app
case ClientMessage:
if( electricBorder( e ))
if (activeBorderEvent(e))
return true;
break;
default:

@ -40,7 +40,7 @@ namespace KWinInternal
Resizes the workspace after an XRANDR screen size change
*/
void Workspace::desktopResized()
{
{
//printf("Workspace::desktopResized()\n");
TQRect geom = TDEApplication::desktop()->geometry();
NETSize desktop_geometry;
@ -49,24 +49,17 @@ void Workspace::desktopResized()
rootInfo->setDesktopGeometry( -1, desktop_geometry );
updateClientArea( true );
checkElectricBorders( true );
}
destroyActiveBorders();
updateActiveBorders();
}
/*!
Resizes the workspace after kdesktop signals a desktop resize
*/
void Workspace::kDestopResized()
{
//printf("Workspace::kDesktopResized()\n");
TQRect geom = TDEApplication::desktop()->geometry();
NETSize desktop_geometry;
desktop_geometry.width = geom.width();
desktop_geometry.height = geom.height();
rootInfo->setDesktopGeometry( -1, desktop_geometry );
updateClientArea( true );
checkElectricBorders( true );
}
{
desktopResized();
}
/*!
Updates the current client areas according to the current clients.
@ -2302,7 +2295,7 @@ class EatAllPaintEvents
static EatAllPaintEvents* eater = 0;
bool Client::startMoveResize()
{
{
assert( !moveResizeMode );
assert( TQWidget::keyboardGrabber() == NULL );
assert( TQWidget::mouseGrabber() == NULL );
@ -2324,28 +2317,55 @@ bool Client::startMoveResize()
if( XGrabKeyboard( tqt_xdisplay(), frameId(), False, GrabModeAsync, GrabModeAsync, GET_QT_X_TIME() ) == Success )
has_grab = true;
if( !has_grab ) // at least one grab is necessary in order to be able to finish move/resize
{
{
XDestroyWindow( tqt_xdisplay(), move_resize_grab_window );
move_resize_grab_window = None;
return false;
}
if ( maximizeMode() != MaximizeRestore )
resetMaximize();
}
removeShadow();
moveResizeMode = true;
initialMoveResizeGeom = geometry();
if (activeTiled)
{
// Restore original geometry
activeTiled = false;
if (options->resetMaximizedWindowGeometry() && isMove()) {
setGeometry(activeTiledOrigGeom);
}
}
if ( maximizeMode() != MaximizeRestore )
{
if (options->resetMaximizedWindowGeometry() && isMove()) {
maximize(MaximizeRestore);
}
else {
resetMaximize();
}
activeTiled = false;
}
moveResizeGeom = geometry();
workspace()->setClientIsMoving(this);
initialMoveResizeGeom = moveResizeGeom = geometry();
checkUnrestrictedMoveResize();
// rule out non opaque windows from useless translucency settings, maybe resizes?
if ((isResize() && options->removeShadowsOnResize) || (isMove() && options->removeShadowsOnMove))
{
setShadowSize(0);
if (rules()->checkMoveResizeMode( options->moveMode ) == Options::Opaque){
}
if (rules()->checkMoveResizeMode( options->moveMode ) == Options::Opaque)
{
savedOpacity_ = opacity_;
setOpacity(options->translucentMovingWindows, options->movingWindowOpacity);
}
if ( ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque )
|| ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque ) )
{
{
grabXServer();
kapp->sendPostedEvents();
// we have server grab -> nothing should cause paint events
@ -2355,25 +2375,57 @@ bool Client::startMoveResize()
// paint events for the geometrytip need to be allowed, though
eater = new EatAllPaintEvents;
// not needed anymore? kapp->installEventFilter( eater );
}
}
Notify::raise( isResize() ? Notify::ResizeStart : Notify::MoveStart );
return true;
if (options->activeBorders() == Options::ActiveSwitchOnMove ||
options->activeBorders() == Options::ActiveTileMaximize ||
options->activeBorders() == Options::ActiveTileOnly)
{
workspace()->reserveActiveBorderSwitching(true);
}
return true;
}
void Client::finishMoveResize( bool cancel )
{
{
leaveMoveResize();
if( cancel )
setGeometry( initialMoveResizeGeom );
if (!isActiveBorderMaximizing()) {
setGeometry(cancel ? initialMoveResizeGeom : moveResizeGeom);
}
else
setGeometry( moveResizeGeom );
{
kdDebug() <<"finishing moveresize in active mode, cancel is " << cancel << endl;
activeMaximizing = false;
activeTiled = true;
activeTiledOrigGeom = initialMoveResizeGeom;
switch(activeMode)
{
case ActiveMaximizeMode:
{
if (!cancel) {
bool full = (maximizeMode() == MaximizeFull);
setMaximize(!full, !full);
}
break;
}
default:
setGeometry(cancel ? initialMoveResizeGeom
: activeBorderMaximizeGeometry());
}
}
checkMaximizeGeometry();
// FRAME update();
Notify::raise( isResize() ? Notify::ResizeEnd : Notify::MoveEnd );
}
}
void Client::leaveMoveResize()
{
{
// rule out non opaque windows from useless translucency settings, maybe resizes?
if (rules()->checkMoveResizeMode( options->moveMode ) == Options::Opaque)
setOpacity(true, savedOpacity_);
@ -2401,12 +2453,19 @@ void Client::leaveMoveResize()
delete eater;
eater = 0;
if (options->shadowEnabled(isActive()))
{
{
drawIntersectingShadows();
updateOpacityCache();
}
}
if (options->activeBorders() == Options::ActiveSwitchOnMove ||
options->activeBorders() == Options::ActiveTileMaximize ||
options->activeBorders() == Options::ActiveTileOnly)
{
workspace()->reserveActiveBorderSwitching(false);
}
}
// This function checks if it actually makes sense to perform a restricted move/resize.
// If e.g. the titlebar is already outside of the workarea, there's no point in performing
// a restricted move resize, because then e.g. resize would also move the window (#74555).
@ -2454,25 +2513,25 @@ void Client::checkUnrestrictedMoveResize()
void Client::handleMoveResize( int x, int y, int x_root, int y_root )
{
if(( mode == PositionCenter && !isMovable())
|| ( mode != PositionCenter && ( isShade() || !isResizable())))
if ( (mode == PositionCenter && !isMovable())
|| (mode != PositionCenter && (isShade() || !isResizable())) )
return;
if ( !moveResizeMode )
{
TQPoint p( TQPoint( x, y ) - moveOffset );
if (!moveResizeMode)
{
TQPoint p(TQPoint( x, y ) - moveOffset);
if (p.manhattanLength() >= 6)
{
if(!startMoveResize())
{
if( !startMoveResize())
{
buttonDown = false;
setCursor( mode );
return;
}
}
}
else
return;
}
}
// ShadeHover or ShadeActive, ShadeNormal was already avoided above
if ( mode != PositionCenter && shade_mode != ShadeNone )
@ -2494,7 +2553,7 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root )
if( unrestrictedMoveResize ) // unrestricted, just don't let it go out completely
left_marge = right_marge = top_marge = bottom_marge = titlebar_marge = 5;
else // restricted move/resize - keep at least part of the titlebar always visible
{
{
// how much must remain visible when moved away in that direction
left_marge = KMIN( 100 + border_right, moveResizeGeom.width());
right_marge = KMIN( 100 + border_left, moveResizeGeom.width());
@ -2502,16 +2561,16 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root )
titlebar_marge = initialMoveResizeGeom.height();
top_marge = border_bottom;
bottom_marge = border_top;
}
}
bool update = false;
if( isResize())
{
if (isResize())
{
// first resize (without checking constraints), then snap, then check bounds, then check constraints
TQRect orig = initialMoveResizeGeom;
Sizemode sizemode = SizemodeAny;
switch ( mode )
{
{
case PositionTopLeft:
moveResizeGeom = TQRect( topleft, orig.bottomRight() ) ;
break;
@ -2544,7 +2603,7 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root )
default:
assert( false );
break;
}
}
// adjust new size to snap to other windows/borders
moveResizeGeom = workspace()->adjustClientSize( this, moveResizeGeom, mode );
@ -2567,7 +2626,7 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root )
bottomright = TQPoint( moveResizeGeom.left() + size.width() - 1, moveResizeGeom.top() + size.height() - 1 );
orig = moveResizeGeom;
switch ( mode )
{ // these 4 corners ones are copied from above
{ // these 4 corners ones are copied from above
case PositionTopLeft:
moveResizeGeom = TQRect( topleft, orig.bottomRight() ) ;
break;
@ -2599,12 +2658,12 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root )
default:
assert( false );
break;
}
if( moveResizeGeom.size() != previousMoveResizeGeom.size())
update = true;
}
else if( isMove())
{
if (moveResizeGeom.size() != previousMoveResizeGeom.size())
update = true;
}
else if (isMove())
{
assert( mode == PositionCenter );
// first move, then snap, then check bounds
moveResizeGeom.moveTopLeft( topleft );
@ -2621,29 +2680,98 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root )
moveResizeGeom.moveLeft(desktopArea.right() - right_marge );
if( moveResizeGeom.topLeft() != previousMoveResizeGeom.topLeft())
update = true;
}
}
else
assert( false );
assert(false);
if( update )
if (update)
{
if (rules()->checkMoveResizeMode(isResize() ? options->resizeMode : options->moveMode) == Options::Opaque
&& !isActiveBorderMaximizing())
{
if( rules()->checkMoveResizeMode
( isResize() ? options->resizeMode : options->moveMode ) == Options::Opaque )
{
setGeometry( moveResizeGeom );
positionGeometryTip();
}
else if( rules()->checkMoveResizeMode
( isResize() ? options->resizeMode : options->moveMode ) == Options::Transparent )
{
clearbound(); // it's necessary to move the geometry tip when there's no outline
positionGeometryTip(); // shown, otherwise it would cause repaint problems in case
drawbound( moveResizeGeom ); // they overlap; the paint event will come after this,
} // so the geometry tip will be painted above the outline
}
if ( isMove() )
workspace()->clientMoved(globalPos, GET_QT_X_TIME());
else if (rules()->checkMoveResizeMode(isResize() ? options->resizeMode : options->moveMode) == Options::Transparent )
{
/* It's necessary to move the geometry tip when there's no outline
* shown, otherwise it would cause repaint problems in case
* they overlap; the paint event will come after this,
* so the geometry tip will be painted above the outline
*/
clearbound();
positionGeometryTip();
drawbound(isActiveBorderMaximizing() ? activeBorderMaximizeGeometry() : moveResizeGeom);
}
}
if (isMove())
workspace()->checkActiveBorder(globalPos, GET_QT_X_TIME());
}
void Client::setActiveBorderMode( ActiveMaximizingMode mode )
{
activeMode = mode;
}
ActiveMaximizingMode Client::activeBorderMode() const
{
return activeMode;
}
bool Client::isActiveBorderMaximizing() const
{
return activeMaximizing;
}
void Client::setActiveBorderMaximizing( bool maximizing )
{
activeMaximizing = maximizing;
if (maximizing || rules()->checkMoveResizeMode(isResize() ? options->resizeMode : options->moveMode) == Options::Opaque) {
clearbound();
}
if (maximizing) {
drawbound(activeBorderMaximizeGeometry());
}
}
TQRect Client::activeBorderMaximizeGeometry()
{
TQRect ret;
TQRect max = workspace()->clientArea(MaximizeArea, TQCursor::pos(), workspace()->currentDesktop());
switch (activeMode)
{
case ActiveMaximizeMode:
{
if (maximizeMode() == MaximizeFull)
ret = geometryRestore();
else
ret = max;
break;
}
case ActiveLeftMode:
{
ret = TQRect( max.x(), max.y(), max.width()/2, max.height() );
break;
}
case ActiveRightMode:
{
ret = TQRect( max.x() + max.width()/2, max.y(), max.width()/2, max.height() );
break;
}
case ActiveTopMode:
{
ret = TQRect( max.x(), max.y(), max.width(), max.height()/2 );
break;
}
case ActiveBottomMode:
{
ret = TQRect( max.x(), max.y() + max.height()/2, max.width(), max.height()/2 );
break;
}
}
return ret;
}
} // namespace

@ -29,6 +29,7 @@
#include <tqslider.h>
#include <tqwhatsthis.h>
#include <tqvbuttongroup.h>
#include <tqhbox.h>
#include <tqcheckbox.h>
#include <tqradiobutton.h>
#include <tqlabel.h>
@ -69,6 +70,7 @@
#define KWIN_CLICKRAISE "ClickRaise"
#define KWIN_ANIMSHADE "AnimateShade"
#define KWIN_MOVE_RESIZE_MAXIMIZED "MoveResizeMaximizedWindows"
#define KWIN_RESET_MAX_WIN_GEOM "ResetMaximizedWindowGeometry"
#define KWIN_ALTTABMODE "AltTabStyle"
#define KWIN_TRAVERSE_ALL "TraverseAll"
#define KWIN_SHOW_POPUP "ShowPopup"
@ -79,10 +81,12 @@
#define KWIN_HIDE_UTILITY "HideUtilityWindowsForInactive"
#define KWIN_SEPARATE_SCREEN_FOCUS "SeparateScreenFocus"
#define KWIN_ACTIVE_MOUSE_SCREEN "ActiveMouseScreen"
#define KWIN_ACTIVE_BORDERS "ActiveBorders"
#define KWIN_ACTIVE_BORDER_DELAY "ActiveBorderDelay"
// kwm config keywords
#define KWM_ELECTRIC_BORDER "ElectricBorders"
#define KWM_ELECTRIC_BORDER_DELAY "ElectricBorderDelay"
// legacy options
#define KWIN_OLD_ACTIVE_BORDERS "ElectricBorders"
#define KWIN_OLD_ACTIVE_BORDER_DELAY "ElectricBorderDelay"
//CT 15mar 98 - magics
#define KWM_BRDR_SNAP_ZONE "BorderSnapZone"
@ -662,31 +666,59 @@ KAdvancedConfig::KAdvancedConfig (bool _standAlone, TDEConfig *_config, TQWidget
connect(shadeHoverOn, TQT_SIGNAL(toggled(bool)), TQT_SLOT(changed()));
connect(shadeHover, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(changed()));
electricBox = new TQVButtonGroup(i18n("Active Desktop Borders"), this);
electricBox->setMargin(15);
TQWhatsThis::add( electricBox, i18n("If this option is enabled, moving the mouse to a screen border"
" will change your desktop. This is e.g. useful if you want to drag windows from one desktop"
" to the other.") );
active_disable = new TQRadioButton(i18n("D&isabled"), electricBox);
active_move = new TQRadioButton(i18n("Only &when moving windows"), electricBox);
active_always = new TQRadioButton(i18n("A&lways enabled"), electricBox);
delays = new KIntNumInput(10, electricBox);
active_box = new TQButtonGroup(i18n("Active Desktop Borders"), this);
TQVBoxLayout *active_vbox = new TQVBoxLayout(active_box);
active_vbox->setSpacing(5);
active_vbox->setMargin(15);
TQWhatsThis::add( active_box, i18n("If this option is enabled, moving the mouse to a screen border"
" will perform an action. It will either change your desktop or tile the window that is currently"
" dragged.") );
TQLabel *active_func_label = new TQLabel(i18n("Function:"), active_box);
active_disable = new TQRadioButton(i18n("D&isabled"), active_box);
active_desktop = new TQRadioButton(i18n("Switch &desktop"), active_box);
active_desktop_conf = new TQWidget(active_box);
TQHBoxLayout *active_desktop_conf_hbox = new TQHBoxLayout(active_desktop_conf);
active_desktop_conf_hbox->addSpacing(20);
active_desktop_conf_hbox->setAutoAdd(true);
active_move = new TQCheckBox(i18n("Switch desktop only when &moving a window"), active_desktop_conf);
active_tile = new TQRadioButton(i18n("Tile &window"), active_box);
active_tile_conf = new TQWidget(active_box);
TQHBoxLayout *active_tile_conf_hbox = new TQHBoxLayout(active_tile_conf);
active_tile_conf_hbox->addSpacing(20);
active_tile_conf_hbox->setAutoAdd(true);
active_maximize = new TQCheckBox(i18n("Maximize windows by dragging them to the &top of the screen"), active_tile_conf);
delays = new KIntNumInput(10, active_box);
delays->setRange(0, MAX_EDGE_RES, 50, true);
delays->setSuffix(i18n(" msec"));
delays->setLabel(i18n("Desktop &switch delay:"));
TQWhatsThis::add( delays, i18n("Here you can set a delay for switching desktops using the active"
" borders feature. Desktops will be switched after the mouse has been pushed against a screen border"
" for the specified number of milliseconds.") );
connect( electricBox, TQT_SIGNAL(clicked(int)), this, TQT_SLOT(setEBorders()));
delays->setLabel(i18n("Border &activation delay:"));
TQWhatsThis::add( delays, i18n("Here you can set a delay for the activation of"
" active borders feature. The selected action will be performed after the mouse "
" has been pushed against a screen border for the specified number of milliseconds.") );
active_vbox->addSpacing(10);
active_vbox->addWidget(active_func_label);
active_vbox->addWidget(active_disable);
active_vbox->addWidget(active_desktop);
active_vbox->addWidget(active_desktop_conf);
active_vbox->addWidget(active_tile);
active_vbox->addWidget(active_tile_conf);
active_vbox->addSpacing(15);
active_vbox->addWidget(delays);
connect(active_box, TQT_SIGNAL(clicked(int)), this, TQT_SLOT(setEBorders()));
// Any changes goes to slotChanged()
connect(electricBox, TQT_SIGNAL(clicked(int)), TQT_SLOT(changed()));
connect(delays, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(changed()));
connect(active_box, TQT_SIGNAL(clicked(int)), this, TQT_SLOT(changed()));
connect(active_move, TQT_SIGNAL(clicked()), this, TQT_SLOT(changed()));
connect(active_maximize, TQT_SIGNAL(clicked()), this, TQT_SLOT(changed()));
connect(delays, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(changed()));
lay->addWidget(electricBox);
lay->addWidget(active_box);
hideUtilityWindowsForInactive = new TQCheckBox( i18n( "Hide utility windows for inactive applications" ), this );
TQWhatsThis::add( hideUtilityWindowsForInactive,
@ -736,8 +768,19 @@ void KAdvancedConfig::load( void )
setShadeHover(config->readBoolEntry(KWIN_SHADEHOVER, false));
setShadeHoverInterval(config->readNumEntry(KWIN_SHADEHOVER_INTERVAL, 250));
setElectricBorders(config->readNumEntry(KWM_ELECTRIC_BORDER, 0));
setElectricBorderDelay(config->readNumEntry(KWM_ELECTRIC_BORDER_DELAY, 150));
// compatibility with old option names
int active_borders = config->readNumEntry(KWIN_ACTIVE_BORDERS, -1);
if (active_borders == -1) {
active_borders = config->readNumEntry(KWIN_OLD_ACTIVE_BORDERS, 0);
}
int active_borders_delay = config->readNumEntry(KWIN_ACTIVE_BORDER_DELAY, -1);
if (active_borders_delay == -1) {
active_borders_delay = config->readNumEntry(KWIN_OLD_ACTIVE_BORDER_DELAY, 150);
}
setActiveBorders(active_borders);
setActiveBorderDelay(active_borders_delay);
setHideUtilityWindowsForInactive( config->readBoolEntry( KWIN_HIDE_UTILITY, true ));
@ -759,11 +802,15 @@ void KAdvancedConfig::save( void )
if (v<0) v = 0;
config->writeEntry(KWIN_SHADEHOVER_INTERVAL, v);
config->writeEntry(KWM_ELECTRIC_BORDER, getElectricBorders());
config->writeEntry(KWM_ELECTRIC_BORDER_DELAY,getElectricBorderDelay());
config->writeEntry(KWIN_ACTIVE_BORDERS, getActiveBorders());
config->writeEntry(KWIN_ACTIVE_BORDER_DELAY, getActiveBorderDelay());
config->writeEntry(KWIN_HIDE_UTILITY, hideUtilityWindowsForInactive->isChecked());
// remove replaced legacy entries
config->deleteEntry(KWIN_OLD_ACTIVE_BORDERS);
config->deleteEntry(KWIN_OLD_ACTIVE_BORDER_DELAY);
if (standAlone)
{
config->sync();
@ -779,42 +826,59 @@ void KAdvancedConfig::defaults()
setAnimateShade(true);
setShadeHover(false);
setShadeHoverInterval(250);
setElectricBorders(0);
setElectricBorderDelay(150);
setActiveBorders(0);
setActiveBorderDelay(150);
setHideUtilityWindowsForInactive( true );
emit TDECModule::changed(true);
}
void KAdvancedConfig::setEBorders()
{
delays->setEnabled(!active_disable->isChecked());
active_desktop_conf->setEnabled(active_desktop->isChecked());
active_tile_conf->setEnabled(active_tile->isChecked());
}
int KAdvancedConfig::getElectricBorders()
int KAdvancedConfig::getActiveBorders()
{
if (active_move->isChecked())
return 1;
if (active_always->isChecked())
return 2;
if (active_desktop->isChecked())
{
return active_move->isChecked() ? 1 : 2;
}
if (active_tile->isChecked())
{
return active_maximize->isChecked() ? 4 : 3;
}
return 0;
}
int KAdvancedConfig::getElectricBorderDelay()
int KAdvancedConfig::getActiveBorderDelay()
{
return delays->value();
}
void KAdvancedConfig::setElectricBorders(int i){
void KAdvancedConfig::setActiveBorders(int i){
switch(i)
{
case 1: active_move->setChecked(true); break;
case 2: active_always->setChecked(true); break;
default: active_disable->setChecked(true); break;
case 1:
active_move->setChecked(true);
case 2:
active_desktop->setChecked(true);
break;
case 4:
active_maximize->setChecked(true);
case 3:
active_tile->setChecked(true);
break;
default:
active_disable->setChecked(true);
break;
}
setEBorders();
}
void KAdvancedConfig::setElectricBorderDelay(int delay)
void KAdvancedConfig::setActiveBorderDelay(int delay)
{
delays->setValue(delay);
}
@ -900,6 +964,11 @@ KMovingConfig::KMovingConfig (bool _standAlone, TDEConfig *_config, TQWidget *pa
" and allows you to move or resize them,"
" just like for normal windows"));
resetMaximizedWindowGeometry = new TQCheckBox( i18n("Restore size of maximized/tiled windows when moving"), windowsBox);
bLay->addWidget(resetMaximizedWindowGeometry);
TQWhatsThis::add(resetMaximizedWindowGeometry, i18n("If this feature is enabled, dragging a maximized or tiled window"
" will restore the window to its original size."));
TQBoxLayout *vLay = new TQHBoxLayout(bLay);
TQLabel *plcLabel = new TQLabel(i18n("&Placement:"),windowsBox);
@ -994,6 +1063,7 @@ KMovingConfig::KMovingConfig (bool _standAlone, TDEConfig *_config, TQWidget *pa
connect( minimizeAnimOn, TQT_SIGNAL(clicked() ), TQT_SLOT(changed()));
connect( minimizeAnimSlider, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(changed()));
connect( moveResizeMaximized, TQT_SIGNAL(toggled(bool)), TQT_SLOT(changed()));
connect( resetMaximizedWindowGeometry, TQT_SIGNAL(toggled(bool)), TQT_SLOT(changed()));
connect( placementCombo, TQT_SIGNAL(activated(int)), TQT_SLOT(changed()));
connect( BrdrSnap, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(changed()));
connect( BrdrSnap, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(slotBrdrSnapChanged(int)));
@ -1074,6 +1144,10 @@ void KMovingConfig::setMoveResizeMaximized(bool a) {
moveResizeMaximized->setChecked(a);
}
void KMovingConfig::setResetMaximizedWindowGeometry(bool a) {
resetMaximizedWindowGeometry->setChecked(a);
}
void KMovingConfig::slotBrdrSnapChanged(int value) {
BrdrSnap->setSuffix(i18n(" pixel", " pixels", value));
}
@ -1149,6 +1223,7 @@ void KMovingConfig::load( void )
// }
setMoveResizeMaximized(config->readBoolEntry(KWIN_MOVE_RESIZE_MAXIMIZED, false));
setResetMaximizedWindowGeometry(config->readBoolEntry(KWIN_RESET_MAX_WIN_GEOM, false));
int v;
@ -1212,6 +1287,7 @@ void KMovingConfig::save( void )
config->writeEntry(KWIN_RESIZE_OPAQUE, "Transparent");
config->writeEntry(KWIN_MOVE_RESIZE_MAXIMIZED, moveResizeMaximized->isChecked());
config->writeEntry(KWIN_RESET_MAX_WIN_GEOM, resetMaximizedWindowGeometry->isChecked());
config->writeEntry(KWM_BRDR_SNAP_ZONE,getBorderSnapZone());
@ -1235,6 +1311,7 @@ void KMovingConfig::defaults()
setGeometryTip(false);
setPlacement(SMART_PLACEMENT);
setMoveResizeMaximized(false);
setResetMaximizedWindowGeometry(false);
//copied from kcontrol/konq/twindesktop, aleXXX
setWindowSnapZone(KWM_WNDW_SNAP_ZONE_DEFAULT);

@ -68,6 +68,7 @@ class KIntNumInput;
#define FOCUS_STRICTLY_UNDER_MOUSE 3
class TQSpinBox;
class TQHBox;
class KFocusConfig : public TDECModule
{
@ -88,7 +89,7 @@ private slots:
void clickRaiseOnTog(bool);
void updateAltTabMode();
void updateActiveMouseScreen();
void changed() { emit TDECModule::changed(true); }
void changed() { emit TDECModule::changed(true); }
private:
@ -163,6 +164,7 @@ private:
void setGeometryTip(bool); //KS
void setPlacement(int); //CT
void setMoveResizeMaximized(bool);
void setResetMaximizedWindowGeometry(bool);
TQButtonGroup *windowsBox;
TQCheckBox *opaque;
@ -172,6 +174,7 @@ private:
TQSlider *minimizeAnimSlider;
TQLabel *minimizeAnimSlowLabel, *minimizeAnimFastLabel;
TQCheckBox *moveResizeMaximized;
TQCheckBox *resetMaximizedWindowGeometry;
TQComboBox *placementCombo;
@ -223,17 +226,21 @@ private:
TDEConfig *config;
bool standAlone;
int getElectricBorders( void );
int getElectricBorderDelay();
void setElectricBorders( int );
void setElectricBorderDelay( int );
int getActiveBorders( void );
int getActiveBorderDelay();
void setActiveBorders( int );
void setActiveBorderDelay( int );
TQVButtonGroup *electricBox;
TQButtonGroup *active_box;
TQRadioButton *active_disable;
TQRadioButton *active_move;
TQRadioButton *active_always;
TQRadioButton *active_desktop;
TQCheckBox *active_move;
TQRadioButton *active_tile;
TQCheckBox *active_maximize;
KIntNumInput *delays;
TQWidget *active_desktop_conf;
TQWidget *active_tile_conf;
void setHideUtilityWindowsForInactive( bool );
TQCheckBox* hideUtilityWindowsForInactive;

@ -129,43 +129,50 @@ void Workspace::updateStackingOrder( bool propagate_new_clients )
void Workspace::propagateClients( bool propagate_new_clients )
{
Window *cl; // MW we should not assume WId and Window to be compatible
// when passig pointers around.
// when passing pointers around.
// restack the windows according to the stacking order
#if 0
Window* new_stack = new Window[ stacking_order.count() + 2 ];
int pos = 0;
#endif
NET::WindowType t;
Window shadow;
Window *dock_shadow_stack, *window_stack;
int i, numDocks, pos, topmenu_space_pos;
// Dock Stack size magic number explanation:
// -> (count * 2) because we might need to also store the shadow window
// for each dock window (Chakra shadow patch, introduced in 9cc1e2c1aa)
dock_shadow_stack = new Window[ stacking_order.count() * 2 ];
window_stack = new Window[ stacking_order.count() * 2 + 2 ];
// Window Stack size magic number explanation:
// -> (count * 2) because we might need to store shadow windows (see above)
// -> + 1 for supportWindow
// -> + 1 for topmenu_space
// -> + 8 for active borders
window_stack = new Window[ stacking_order.count() * 2 + 1 + 1 + 8 ];
i = 0;
pos = 0;
topmenu_space_pos = 1; // not 0, that's supportWindow !!!
// Stack all windows under the support window. The support window is
// not used for anything (besides the NETWM property), and it's not shown,
// but it was lowered after twin startup. Stacking all clients below
// it ensures that no client will be ever shown above override-redirect
// windows (e.g. popups).
#if 0
new_stack[ pos++ ] = supportWindow->winId();
int topmenu_space_pos = 1; // not 0, that's supportWindow !!!
#endif
// Stack active windows under the support window.
/* The support window is not used for anything (besides the NETWM property),
* and it's not shown, but it was lowered after TWin startup.
* Stacking all clients below it ensures that no client will be ever shown
* above override-redirect windows (e.g. popups).
*/
for (int i = 0; i < ACTIVE_BORDER_COUNT; ++i)
{
if (active_windows[i] != None)
{
window_stack[pos++] = active_windows[i];
}
}
// Stack all windows under the support and active borders windows.
window_stack[pos++] = supportWindow->winId();
for( ClientList::ConstIterator it = stacking_order.fromLast();
it != stacking_order.end();
--it )
{
#if 0
new_stack[ pos++ ] = (*it)->frameId();
if( (*it)->belongsToLayer() >= DockLayer )
topmenu_space_pos = pos;
#endif
t = (*it)->windowType();
switch (t)
{
@ -202,15 +209,14 @@ void Workspace::propagateClients( bool propagate_new_clients )
new_stack[ topmenu_space_pos ] = topmenu_space->winId();
#endif
window_stack[ i ] = window_stack[ i - 1 ];
window_stack[ topmenu_space_pos ] = topmenu_space->winId();
++pos;
window_stack[ topmenu_space_pos ] = topmenu_space->winId();
++pos;
}
#if 0
// TODO isn't it too inefficient to restart always all clients?
// TODO don't restack not visible windows?
assert( new_stack[ 0 ] = supportWindow->winId());
#endif
#if 0
XRestackWindows(tqt_xdisplay(), new_stack, pos);
delete [] new_stack;
#endif

@ -31,8 +31,8 @@ namespace KWinInternal
#ifndef KCMRULES
Options::Options()
: electric_borders( 0 ),
electric_border_delay(0)
: active_borders( 0 ),
active_border_delay(0)
{
d = new KDecorationOptionsPrivate;
d->defaultKWinSettings();
@ -54,6 +54,7 @@ unsigned long Options::updateSettings()
moveMode = stringToMoveResizeMode( config->readEntry("MoveMode", "Opaque" ));
resizeMode = stringToMoveResizeMode( config->readEntry("ResizeMode", "Opaque" ));
show_geometry_tip = config->readBoolEntry("GeometryTip", false);
reset_maximized_window_geometry = config->readBoolEntry("ResetMaximizedWindowGeometry", false);
tabboxOutline = config->readBoolEntry("TabboxOutline", true);
TQString val;
@ -125,8 +126,16 @@ unsigned long Options::updateSettings()
borderSnapZone = config->readNumEntry("BorderSnapZone", 10);
windowSnapZone = config->readNumEntry("WindowSnapZone", 10);
snapOnlyWhenOverlapping=config->readBoolEntry("SnapOnlyWhenOverlapping",FALSE);
electric_borders = config->readNumEntry("ElectricBorders", 0);
electric_border_delay = config->readNumEntry("ElectricBorderDelay", 150);
// active borders: compatibility with old option names (Electric*)
active_borders = config->readNumEntry("ActiveBorders", -1);
if (active_borders == -1) {
active_borders = config->readNumEntry("ElectricBorders", 0);
}
active_border_delay = config->readNumEntry("ActiveBorderDelay", -1);
if (active_border_delay == -1) {
active_border_delay = config->readNumEntry("ElectricBorderDelay", 150);
}
OpTitlebarDblClick = windowOperation( config->readEntry("TitlebarDoubleClickCommand", "Shade"), true );
d->OpMaxButtonLeftClick = windowOperation( config->readEntry("MaximizeButtonLeftClickCommand", "Maximize"), true );
@ -308,6 +317,11 @@ bool Options::showGeometryTip()
return show_geometry_tip;
}
bool Options::resetMaximizedWindowGeometry()
{
return reset_maximized_window_geometry;
}
TQColor &Options::shadowColour(bool active)
{
return active ? shadow_colour : shadow_inactive_colour;
@ -373,14 +387,14 @@ int Options::shadowYOffset(bool active)
return active ? shadow_y_offset : shadow_inactive_y_offset;
}
int Options::electricBorders()
int Options::activeBorders()
{
return electric_borders;
return active_borders;
}
int Options::electricBorderDelay()
int Options::activeBorderDelay()
{
return electric_border_delay;
return active_border_delay;
}
bool Options::checkIgnoreFocusStealing( const Client* c )

@ -268,6 +268,13 @@ class Options : public KDecorationOptions
*/
bool showGeometryTip();
/**
* @returns true if a maximized or tiled window should be reset to its original
* size when dragging it.
* @since R14.1.1
*/
bool resetMaximizedWindowGeometry();
/**
* @returns A TQColor representing the colour that window drop shadows should
* be.
@ -307,18 +314,22 @@ class Options : public KDecorationOptions
*/
int shadowYOffset(bool active=true);
enum { ElectricDisabled = 0, ElectricMoveOnly = 1, ElectricAlways = 2 };
enum { ActiveDisabled = 0,
ActiveSwitchOnMove = 1,
ActiveSwitchAlways = 2,
ActiveTileOnly = 3,
ActiveTileMaximize = 4 };
/**
* @returns true if electric borders are enabled. With electric borders
* @returns true if active borders are enabled. With active borders
* you can change desktop by moving the mouse pointer towards the edge
* of the screen
*/
int electricBorders();
int activeBorders();
/**
* @returns the activation delay for electric borders in milliseconds.
* @returns the activation delay for active borders in milliseconds.
*/
int electricBorderDelay();
int activeBorderDelay();
bool topMenuEnabled() const { return topmenus; }
bool desktopTopMenu() const { return desktop_topmenu; }
@ -373,9 +384,10 @@ class Options : public KDecorationOptions
bool CmdAllRevWheel;
uint CmdAllModKey;
int electric_borders;
int electric_border_delay;
int active_borders;
int active_border_delay;
bool show_geometry_tip;
bool reset_maximized_window_geometry;
bool topmenus;
bool desktop_topmenu;
TQColor shadow_colour;

@ -108,6 +108,29 @@ enum ShadeMode
ShadeActivated // "shaded", but visible due to alt+tab to the window
};
enum ActiveBorder
{
ActiveTop,
ActiveTopRight,
ActiveRight,
ActiveBottomRight,
ActiveBottom,
ActiveBottomLeft,
ActiveLeft,
ActiveTopLeft,
ACTIVE_BORDER_COUNT,
ActiveNone
};
enum ActiveMaximizingMode
{
ActiveMaximizeMode,
ActiveLeftMode,
ActiveRightMode,
ActiveTopMode,
ActiveBottomMode
};
class Shape
{
public:

@ -167,12 +167,7 @@ Workspace::Workspace( bool restore )
global_shortcuts_disabled_for_client( false ),
root (0),
workspaceInit (true),
startup(0), electric_have_borders(false),
electric_current_border(0),
electric_top_border(None),
electric_bottom_border(None),
electric_left_border(None),
electric_right_border(None),
startup(0),
layoutOrientation(Qt::Vertical),
layoutX(-1),
layoutY(2),
@ -194,6 +189,12 @@ Workspace::Workspace( bool restore )
installed_colormap = default_colormap;
session.setAutoDelete( TRUE );
for (int i = 0; i < ACTIVE_BORDER_COUNT; ++i)
{
active_reserved[i] = 0;
active_windows[i] = None;
}
connect( &temporaryRulesMessages, TQT_SIGNAL( gotMessage( const TQString& )),
this, TQT_SLOT( gotTemporaryRulesMessage( const TQString& )));
connect( &rulesUpdatedTimer, TQT_SIGNAL( timeout()), this, TQT_SLOT( writeWindowRules()));
@ -202,8 +203,8 @@ Workspace::Workspace( bool restore )
delayFocusTimer = 0;
electric_time_first = GET_QT_X_TIME();
electric_time_last = GET_QT_X_TIME();
active_time_first = GET_QT_X_TIME();
active_time_last = GET_QT_X_TIME();
if ( restore )
loadSessionInfo();
@ -304,8 +305,12 @@ Workspace::Workspace( bool restore )
void Workspace::init()
{
if (options->activeBorders() == Options::ActiveSwitchAlways)
{
checkElectricBorders();
reserveActiveBorderSwitching(true);
}
updateActiveBorders();
// not used yet
// topDock = 0L;
@ -483,7 +488,6 @@ void Workspace::init()
updateStackingOrder( true );
updateClientArea();
raiseElectricBorders();
// NETWM spec says we have to set it to (0,0) if we don't support it
NETPoint* viewports = new NETPoint[ number_of_desktops ];
@ -514,12 +518,27 @@ void Workspace::init()
}
if( new_active_client != NULL )
activateClient( new_active_client );
// outline windows for active border maximize window mode
outline_left = XCreateWindow(tqt_xdisplay(), rootWin(), 0, 0, 1, 1, 0,
CopyFromParent, CopyFromParent, CopyFromParent,
CWOverrideRedirect, &attr);
outline_right = XCreateWindow(tqt_xdisplay(), rootWin(), 0, 0, 1, 1, 0,
CopyFromParent, CopyFromParent, CopyFromParent,
CWOverrideRedirect, &attr);
outline_top = XCreateWindow(tqt_xdisplay(), rootWin(), 0, 0, 1, 1, 0,
CopyFromParent, CopyFromParent, CopyFromParent,
CWOverrideRedirect, &attr);
outline_bottom = XCreateWindow(tqt_xdisplay(), rootWin(), 0, 0, 1, 1, 0,
CopyFromParent, CopyFromParent, CopyFromParent,
CWOverrideRedirect, &attr);
// SELI TODO this won't work with unreasonable focus policies,
// and maybe in rare cases also if the selected client doesn't
// want focus
workspaceInit = false;
// TODO ungrabXServer()
}
}
Workspace::~Workspace()
{
@ -550,6 +569,12 @@ Workspace::~Workspace()
writeWindowRules();
TDEGlobal::config()->sync();
// destroy outline windows for active border maximize window mode
XDestroyWindow(tqt_xdisplay(), outline_left);
XDestroyWindow(tqt_xdisplay(), outline_right);
XDestroyWindow(tqt_xdisplay(), outline_top);
XDestroyWindow(tqt_xdisplay(), outline_bottom);
delete rootInfo;
delete supportWindow;
delete mgr;
@ -1038,6 +1063,11 @@ void Workspace::slotReconfigure()
kdDebug(1212) << "Workspace::slotReconfigure()" << endl;
reconfigureTimer.stop();
if (options->activeBorders() == Options::ActiveSwitchAlways)
{
reserveActiveBorderSwitching(false);
}
TDEGlobal::config()->reparseConfiguration();
unsigned long changed = options->updateSettings();
tab_box->reconfigure();
@ -1068,7 +1098,10 @@ void Workspace::slotReconfigure()
forEachClient( CheckBorderSizesProcedure());
}
checkElectricBorders();
if (options->activeBorders() == Options::ActiveSwitchAlways)
{
reserveActiveBorderSwitching(true);
}
if( options->topMenuEnabled() && !managingTopMenus())
{
@ -2357,7 +2390,7 @@ void Workspace::delayFocus()
requestFocus( delayfocus_client );
cancelDelayFocus();
}
void Workspace::requestDelayFocus( Client* c )
{
delayfocus_client = c;
@ -2366,283 +2399,353 @@ void Workspace::requestDelayFocus( Client* c )
connect( delayFocusTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( delayFocus() ) );
delayFocusTimer->start( options->delayFocusInterval, TRUE );
}
void Workspace::cancelDelayFocus()
{
delete delayFocusTimer;
delayFocusTimer = 0;
}
// Electric Borders
//========================================================================//
// Electric Border Window management. Electric borders allow a user
// to change the virtual desktop by moving the mouse pointer to the
// borders. Technically this is done with input only windows. Since
// electric borders can be switched on and off, we have these two
// functions to create and destroy them.
void Workspace::checkElectricBorders( bool force )
/* Active (Electric) Borders
* ========================================================================
* Active Border Window management. Active borders allow a user to switch
* to another virtual desktop or activate other features by moving
* the mouse pointer to the borders or corners of the workspace.
* Technically this is done with input only windows.
*/
void Workspace::updateActiveBorders()
{
if( force )
destroyBorderWindows();
electric_current_border = 0;
active_time_first = GET_QT_X_TIME();
active_time_last = GET_QT_X_TIME();
active_time_last_trigger = GET_QT_X_TIME();
active_current_border = ActiveNone;
TQRect r = TQApplication::desktop()->geometry();
electricTop = r.top();
electricBottom = r.bottom();
electricLeft = r.left();
electricRight = r.right();
activeTop = r.top();
activeBottom = r.bottom();
activeLeft = r.left();
activeRight = r.right();
if (options->electricBorders() == Options::ElectricAlways)
createBorderWindows();
else
destroyBorderWindows();
for (int pos = 0; pos < ACTIVE_BORDER_COUNT; ++pos)
{
if (active_reserved[pos] == 0)
{
if (active_windows[pos] != None)
{
XDestroyWindow( tqt_xdisplay(), active_windows[pos] );
}
active_windows[pos] = None;
continue;
}
if (active_windows[pos] != None)
{
continue;
}
XSetWindowAttributes attributes;
attributes.override_redirect = True;
attributes.event_mask = EnterWindowMask;
unsigned long valuemask = CWOverrideRedirect | CWEventMask;
int xywh[ ACTIVE_BORDER_COUNT ][ 4 ] =
{
{ r.left() + 1, r.top(), r.width() - 2, 1 }, // top
{ r.right(), r.top(), 1, 1 }, // topright
{ r.right(), r.top() + 1, 1, r.height() - 2 }, // etc.
{ r.right(), r.bottom(), 1, 1 },
{ r.left() + 1, r.bottom(), r.width() - 2, 1 },
{ r.left(), r.bottom(), 1, 1 },
{ r.left(), r.top() + 1, 1, r.height() - 2 },
{ r.left(), r.top(), 1, 1 }
};
active_windows[pos] = XCreateWindow(tqt_xdisplay(), tqt_xrootwin(),
xywh[pos][0], xywh[pos][1],
xywh[pos][2], xywh[pos][3],
0, CopyFromParent, InputOnly,
CopyFromParent, valuemask,
&attributes);
XMapWindow(tqt_xdisplay(), active_windows[pos]);
// Set XdndAware on the windows, so that DND enter events are received (#86998)
Atom version = 4; // XDND version
XChangeProperty(tqt_xdisplay(), active_windows[pos],
atoms->xdnd_aware, XA_ATOM, 32, PropModeReplace,
(unsigned char*)&version, 1);
}
}
void Workspace::createBorderWindows()
void Workspace::destroyActiveBorders()
{
for (int pos = 0; pos < ACTIVE_BORDER_COUNT; ++pos)
{
if ( electric_have_borders )
if (active_windows[ pos ] != None)
{
XDestroyWindow( tqt_xdisplay(), active_windows[ pos ] );
}
active_windows[ pos ] = None;
}
}
void Workspace::reserveActiveBorderSwitching( bool reserve )
{
for (int pos = 0; pos < ACTIVE_BORDER_COUNT; ++pos)
{
if (reserve)
{
reserveActiveBorder(static_cast<ActiveBorder>(pos));
}
else
{
unreserveActiveBorder(static_cast<ActiveBorder>(pos));
}
}
}
void Workspace::reserveActiveBorder( ActiveBorder border )
{
if (border == ActiveNone)
return;
electric_have_borders = true;
if (active_reserved[border]++ == 0)
TQTimer::singleShot(0, this, TQT_SLOT(updateActiveBorders()));
}
TQRect r = TQApplication::desktop()->geometry();
XSetWindowAttributes attributes;
unsigned long valuemask;
attributes.override_redirect = True;
attributes.event_mask = ( EnterWindowMask | LeaveWindowMask );
valuemask= (CWOverrideRedirect | CWEventMask | CWCursor );
attributes.cursor = XCreateFontCursor(tqt_xdisplay(),
XC_sb_up_arrow);
electric_top_border = XCreateWindow (tqt_xdisplay(), tqt_xrootwin(),
0,0,
r.width(),1,
0,
CopyFromParent, InputOnly,
CopyFromParent,
valuemask, &attributes);
XMapWindow(tqt_xdisplay(), electric_top_border);
attributes.cursor = XCreateFontCursor(tqt_xdisplay(),
XC_sb_down_arrow);
electric_bottom_border = XCreateWindow (tqt_xdisplay(), tqt_xrootwin(),
0,r.height()-1,
r.width(),1,
0,
CopyFromParent, InputOnly,
CopyFromParent,
valuemask, &attributes);
XMapWindow(tqt_xdisplay(), electric_bottom_border);
attributes.cursor = XCreateFontCursor(tqt_xdisplay(),
XC_sb_left_arrow);
electric_left_border = XCreateWindow (tqt_xdisplay(), tqt_xrootwin(),
0,0,
1,r.height(),
0,
CopyFromParent, InputOnly,
CopyFromParent,
valuemask, &attributes);
XMapWindow(tqt_xdisplay(), electric_left_border);
attributes.cursor = XCreateFontCursor(tqt_xdisplay(),
XC_sb_right_arrow);
electric_right_border = XCreateWindow (tqt_xdisplay(), tqt_xrootwin(),
r.width()-1,0,
1,r.height(),
0,
CopyFromParent, InputOnly,
CopyFromParent,
valuemask, &attributes);
XMapWindow(tqt_xdisplay(), electric_right_border);
// Set XdndAware on the windows, so that DND enter events are received (#86998)
Atom version = 4; // XDND version
XChangeProperty( tqt_xdisplay(), electric_top_border, atoms->xdnd_aware, XA_ATOM,
32, PropModeReplace, ( unsigned char* )&version, 1 );
XChangeProperty( tqt_xdisplay(), electric_bottom_border, atoms->xdnd_aware, XA_ATOM,
32, PropModeReplace, ( unsigned char* )&version, 1 );
XChangeProperty( tqt_xdisplay(), electric_left_border, atoms->xdnd_aware, XA_ATOM,
32, PropModeReplace, ( unsigned char* )&version, 1 );
XChangeProperty( tqt_xdisplay(), electric_right_border, atoms->xdnd_aware, XA_ATOM,
32, PropModeReplace, ( unsigned char* )&version, 1 );
}
// Electric Border Window management. Electric borders allow a user
// to change the virtual desktop by moving the mouse pointer to the
// borders. Technically this is done with input only windows. Since
// electric borders can be switched on and off, we have these two
// functions to create and destroy them.
void Workspace::destroyBorderWindows()
{
if( !electric_have_borders)
return;
electric_have_borders = false;
if(electric_top_border)
XDestroyWindow(tqt_xdisplay(),electric_top_border);
if(electric_bottom_border)
XDestroyWindow(tqt_xdisplay(),electric_bottom_border);
if(electric_left_border)
XDestroyWindow(tqt_xdisplay(),electric_left_border);
if(electric_right_border)
XDestroyWindow(tqt_xdisplay(),electric_right_border);
electric_top_border = None;
electric_bottom_border = None;
electric_left_border = None;
electric_right_border = None;
}
void Workspace::clientMoved(const TQPoint &pos, Time now)
{
if (options->electricBorders() == Options::ElectricDisabled)
return;
void Workspace::unreserveActiveBorder( ActiveBorder border )
{
if (border == ActiveNone)
return;
if ((pos.x() != electricLeft) &&
(pos.x() != electricRight) &&
(pos.y() != electricTop) &&
(pos.y() != electricBottom))
return;
assert(active_reserved[ border ] > 0);
if (--active_reserved[ border ] == 0)
TQTimer::singleShot(0, this, TQT_SLOT(updateActiveBorders()));
}
Time treshold_set = options->electricBorderDelay(); // set timeout
void Workspace::checkActiveBorder(const TQPoint &pos, Time now)
{
Time treshold_set = options->activeBorderDelay(); // set timeout
Time treshold_trigger = 250; // Minimum time between triggers
Time treshold_reset = 250; // reset timeout
int distance_reset = 30; // Mouse should not move more than this many pixels
int border = 0;
if (pos.x() == electricLeft)
border = 1;
else if (pos.x() == electricRight)
border = 2;
else if (pos.y() == electricTop)
border = 3;
else if (pos.y() == electricBottom)
border = 4;
if ((pos.x() > activeLeft + distance_reset) &&
(pos.x() < activeRight - distance_reset) &&
(pos.y() > activeTop + distance_reset) &&
(pos.y() < activeBottom - distance_reset))
{
if (movingClient &&
(options->activeBorders() == Options::ActiveTileMaximize ||
options->activeBorders() == Options::ActiveTileOnly))
{
movingClient->setActiveBorderMaximizing(false);
}
}
if ((electric_current_border == border) &&
(timestampDiff(electric_time_last, now) < treshold_reset) &&
((pos-electric_push_point).manhattanLength() < distance_reset))
if ((pos.x() != activeLeft) &&
(pos.x() != activeRight) &&
(pos.y() != activeTop) &&
(pos.y() != activeBottom))
return;
bool have_borders = false;
for (int i = 0; i < ACTIVE_BORDER_COUNT; ++i)
{
if (active_windows[ i ] != None)
{
electric_time_last = now;
have_borders = true;
}
}
if( !have_borders )
return;
ActiveBorder border;
if( pos.x() == activeLeft && pos.y() == activeTop )
border = ActiveTopLeft;
else if( pos.x() == activeRight && pos.y() == activeTop )
border = ActiveTopRight;
else if( pos.x() == activeLeft && pos.y() == activeBottom )
border = ActiveBottomLeft;
else if( pos.x() == activeRight && pos.y() == activeBottom )
border = ActiveBottomRight;
else if( pos.x() == activeLeft )
border = ActiveLeft;
else if( pos.x() == activeRight )
border = ActiveRight;
else if( pos.y() == activeTop )
border = ActiveTop;
else if( pos.y() == activeBottom )
border = ActiveBottom;
else
abort();
if (timestampDiff(electric_time_first, now) > treshold_set)
if( active_windows[border] == None )
return;
if ((active_current_border == border) &&
(timestampDiff(active_time_last, now) < treshold_reset) &&
(timestampDiff(active_time_last_trigger, now) > treshold_trigger) &&
((pos-active_push_point).manhattanLength() < distance_reset))
{
active_time_last = now;
if (timestampDiff(active_time_first, now) > treshold_set)
{
active_time_last_trigger = now;
active_current_border = ActiveNone;
bool isSide = (border == ActiveTop || border == ActiveRight ||
border == ActiveBottom || border == ActiveLeft);
if (movingClient)
{
electric_current_border = 0;
// Desktop switching
if (options->activeBorders() == Options::ActiveSwitchAlways ||
options->activeBorders() == Options::ActiveSwitchOnMove)
{
activeBorderSwitchDesktop(border, pos);
return; // Don't reset cursor position
}
TQRect r = TQApplication::desktop()->geometry();
int offset;
// Tiling maximize
else if (options->activeBorders() == Options::ActiveTileMaximize &&
border == ActiveTop && movingClient->isMaximizable())
{
if (!movingClient->isResizable()) return;
bool enable = !movingClient->isActiveBorderMaximizing();
movingClient->setActiveBorderMode(ActiveMaximizeMode);
movingClient->setActiveBorderMaximizing(enable);
}
int desk_before = currentDesktop();
switch(border)
// Tiling
else if ((options->activeBorders() == Options::ActiveTileMaximize ||
options->activeBorders() == Options::ActiveTileOnly) && isSide)
{
case 1:
slotSwitchDesktopLeft();
if (currentDesktop() != desk_before)
if (!movingClient->isResizable()) return;
bool enable = !movingClient->isActiveBorderMaximizing();
bool activate = false;
if (border == ActiveLeft)
{
offset = r.width() / 5;
TQCursor::setPos(r.width() - offset, pos.y());
movingClient->setActiveBorderMode( ActiveLeftMode );
activate = true;
}
break;
case 2:
slotSwitchDesktopRight();
if (currentDesktop() != desk_before)
else if (border == ActiveRight)
{
offset = r.width() / 5;
TQCursor::setPos(offset, pos.y());
movingClient->setActiveBorderMode( ActiveRightMode );
activate = true;
}
break;
case 3:
slotSwitchDesktopUp();
if (currentDesktop() != desk_before)
else if (border == ActiveTop)
{
offset = r.height() / 5;
TQCursor::setPos(pos.x(), r.height() - offset);
movingClient->setActiveBorderMode( ActiveTopMode );
activate = true;
}
else if (border == ActiveBottom)
{
movingClient->setActiveBorderMode( ActiveBottomMode );
activate = true;
}
break;
case 4:
slotSwitchDesktopDown();
if (currentDesktop() != desk_before)
if (activate)
{
offset = r.height() / 5;
TQCursor::setPos(pos.x(), offset);
movingClient->setActiveBorderMaximizing(enable);
}
break;
}
return;
else
{
return; // Don't reset cursor position
}
}
else
{
// Desktop switching
if (options->activeBorders() == Options::ActiveSwitchAlways && isSide)
{
activeBorderSwitchDesktop(border, pos);
return; // Don't reset cursor position
}
}
}
else
{
electric_current_border = border;
electric_time_first = now;
electric_time_last = now;
electric_push_point = pos;
}
}
else
{
active_current_border = border;
active_time_first = now;
active_time_last = now;
active_push_point = pos;
}
int mouse_warp = 1;
// reset the pointer to find out wether the user is really pushing
// (the direction back from which it came, starting from top clockwise)
const int xdiff[ ACTIVE_BORDER_COUNT ] = { 0, -1, -1, -1, 0, 1, 1, 1 };
const int ydiff[ ACTIVE_BORDER_COUNT ] = { 1, 1, 0, -1, -1, -1, 0, 1 };
TQCursor::setPos(pos.x() + xdiff[border], pos.y() + ydiff[border]);
// reset the pointer to find out wether the user is really pushing
switch( border)
{
case 1: TQCursor::setPos(pos.x()+mouse_warp, pos.y()); break;
case 2: TQCursor::setPos(pos.x()-mouse_warp, pos.y()); break;
case 3: TQCursor::setPos(pos.x(), pos.y()+mouse_warp); break;
case 4: TQCursor::setPos(pos.x(), pos.y()-mouse_warp); break;
}
}
// this function is called when the user entered an electric border
void Workspace::activeBorderSwitchDesktop(ActiveBorder border, const TQPoint& _pos)
{
TQPoint pos = _pos;
TQRect r = TQApplication::desktop()->geometry();
const int offset = 5;
int desk_before = currentDesktop();
if (border == ActiveLeft || border == ActiveTopLeft || border == ActiveBottomLeft)
{
slotSwitchDesktopLeft();
pos.setX(r.width() - offset);
}
if (border == ActiveRight || border == ActiveTopRight || border == ActiveBottomRight)
{
slotSwitchDesktopRight();
pos.setX(offset);
}
if (border == ActiveTop || border == ActiveTopLeft || border == ActiveTopRight)
{
slotSwitchDesktopUp();
pos.setY(r.height() - offset);
}
if (border == ActiveBottom || border == ActiveBottomLeft || border == ActiveBottomRight)
{
slotSwitchDesktopDown();
pos.setY(offset);
}
if (currentDesktop() != desk_before)
{
TQCursor::setPos(pos);
}
}
// this function is called when the user entered an active border
// with the mouse. It may switch to another virtual desktop
bool Workspace::electricBorder(XEvent *e)
bool Workspace::activeBorderEvent(XEvent *e)
{
if (e->type == EnterNotify)
{
if( !electric_have_borders )
return false;
if( e->type == EnterNotify )
for (int i = 0; i < ACTIVE_BORDER_COUNT; ++i)
{
if( e->xcrossing.window == electric_top_border ||
e->xcrossing.window == electric_left_border ||
e->xcrossing.window == electric_bottom_border ||
e->xcrossing.window == electric_right_border)
// the user entered an electric border
{
clientMoved( TQPoint( e->xcrossing.x_root, e->xcrossing.y_root ), e->xcrossing.time );
return true;
if (active_windows[i] != None && e->xcrossing.window == active_windows[i])
{ // the user entered an active border
checkActiveBorder(TQPoint(e->xcrossing.x_root, e->xcrossing.y_root), e->xcrossing.time);
return true;
}
}
if( e->type == ClientMessage )
{
if( e->xclient.message_type == atoms->xdnd_position
&& ( e->xclient.window == electric_top_border
|| e->xclient.window == electric_bottom_border
|| e->xclient.window == electric_left_border
|| e->xclient.window == electric_right_border ))
{
updateXTime();
clientMoved( TQPoint( e->xclient.data.l[2]>>16, e->xclient.data.l[2]&0xffff), GET_QT_X_TIME() );
return true;
}
}
return false;
}
// electric borders (input only windows) have to be always on the
// top. For that reason kwm calls this function always after some
// windows have been raised.
void Workspace::raiseElectricBorders()
if (e->type == ClientMessage)
{
if(electric_have_borders)
if (e->xclient.message_type == atoms->xdnd_position)
{
XRaiseWindow(tqt_xdisplay(), electric_top_border);
XRaiseWindow(tqt_xdisplay(), electric_left_border);
XRaiseWindow(tqt_xdisplay(), electric_bottom_border);
XRaiseWindow(tqt_xdisplay(), electric_right_border);
for (int i = 0; i < ACTIVE_BORDER_COUNT; ++i)
{
if (active_windows[i] != None && e->xclient.window == active_windows[i])
{
updateXTime();
checkActiveBorder(TQPoint(e->xclient.data.l[2]>>16, e->xclient.data.l[2]&0xffff), GET_QT_X_TIME());
return true;
}
}
}
}
return false;
}
void Workspace::addTopMenu( Client* c )
{

@ -156,7 +156,10 @@ class Workspace : public TQObject, public KWinInterface, public KDecorationDefin
void clientHidden( Client* );
void clientAttentionChanged( Client* c, bool set );
void clientMoved(const TQPoint &pos, Time time);
void checkActiveBorder(const TQPoint &pos, Time time);
void reserveActiveBorder(ActiveBorder border);
void unreserveActiveBorder(ActiveBorder border);
void reserveActiveBorderSwitching(bool reserve);
/**
* Returns the current virtual desktop of this workspace
@ -302,7 +305,7 @@ class Workspace : public TQObject, public KWinInterface, public KDecorationDefin
void requestDelayFocus( Client* );
void updateFocusMousePosition( const TQPoint& pos );
TQPoint focusMousePosition() const;
void toggleTopDockShadows(bool on);
public slots:
@ -406,6 +409,7 @@ class Workspace : public TQObject, public KWinInterface, public KDecorationDefin
void cleanupTemporaryRules();
void writeWindowRules();
void kipcMessage( int id, int data );
void updateActiveBorders();
// kompmgr
void setPopupClientOpacity(int v);
void resetClientOpacity();
@ -486,12 +490,10 @@ class Workspace : public TQObject, public KWinInterface, public KDecorationDefin
void tabBoxKeyPress( const KKeyNative& keyX );
void tabBoxKeyRelease( const XKeyEvent& ev );
// electric borders
void checkElectricBorders( bool force = false );
void createBorderWindows();
void destroyBorderWindows();
bool electricBorder(XEvent * e);
void raiseElectricBorders();
// active borders
void destroyActiveBorders();
bool activeBorderEvent(XEvent *e);
void activeBorderSwitchDesktop(ActiveBorder border, const TQPoint& pos);
// ------------------
@ -617,19 +619,17 @@ class Workspace : public TQObject, public KWinInterface, public KDecorationDefin
TDEStartupInfo* startup;
bool electric_have_borders;
int electric_current_border;
WId electric_top_border;
WId electric_bottom_border;
WId electric_left_border;
WId electric_right_border;
int electricLeft;
int electricRight;
int electricTop;
int electricBottom;
Time electric_time_first;
Time electric_time_last;
TQPoint electric_push_point;
ActiveBorder active_current_border;
Window active_windows[ ACTIVE_BORDER_COUNT ];
int activeLeft;
int activeRight;
int activeTop;
int activeBottom;
Time active_time_first;
Time active_time_last;
Time active_time_last_trigger;
TQPoint active_push_point;
int active_reserved[ ACTIVE_BORDER_COUNT ]; // corners/edges used by something
Qt::Orientation layoutOrientation;
int layoutX;
@ -663,7 +663,11 @@ class Workspace : public TQObject, public KWinInterface, public KDecorationDefin
int maximizedWindowCounter;
int topDockShadowSize;*/
//end
Window outline_left;
Window outline_right;
Window outline_top;
Window outline_bottom;
signals:
void kompmgrStarted();
void kompmgrStopped();

Loading…
Cancel
Save