summaryrefslogtreecommitdiffstats
path: root/twin
diff options
context:
space:
mode:
Diffstat (limited to 'twin')
-rw-r--r--twin/client.cpp4
-rw-r--r--twin/client.h10
-rw-r--r--twin/events.cpp4
-rw-r--r--twin/geometry.cpp266
-rw-r--r--twin/kcmtwin/twinoptions/windows.cpp159
-rw-r--r--twin/kcmtwin/twinoptions/windows.h25
-rw-r--r--twin/layers.cpp56
-rw-r--r--twin/options.cpp30
-rw-r--r--twin/options.h26
-rw-r--r--twin/utils.h23
-rw-r--r--twin/workspace.cpp577
-rw-r--r--twin/workspace.h48
12 files changed, 807 insertions, 421 deletions
diff --git a/twin/client.cpp b/twin/client.cpp
index a58fd22f2..484290e45 100644
--- a/twin/client.cpp
+++ b/twin/client.cpp
@@ -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;
diff --git a/twin/client.h b/twin/client.h
index d3c7e7b13..332501f88 100644
--- a/twin/client.h
+++ b/twin/client.h
@@ -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;
};
diff --git a/twin/events.cpp b/twin/events.cpp
index e9f8fd484..8430ad93a 100644
--- a/twin/events.cpp
+++ b/twin/events.cpp
@@ -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:
diff --git a/twin/geometry.cpp b/twin/geometry.cpp
index 5c71e7c1f..7dd38bee2 100644
--- a/twin/geometry.cpp
+++ b/twin/geometry.cpp
@@ -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
diff --git a/twin/kcmtwin/twinoptions/windows.cpp b/twin/kcmtwin/twinoptions/windows.cpp
index 66249d474..3610eb443 100644
--- a/twin/kcmtwin/twinoptions/windows.cpp
+++ b/twin/kcmtwin/twinoptions/windows.cpp
@@ -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);
diff --git a/twin/kcmtwin/twinoptions/windows.h b/twin/kcmtwin/twinoptions/windows.h
index d4d358e9a..435bd0521 100644
--- a/twin/kcmtwin/twinoptions/windows.h
+++ b/twin/kcmtwin/twinoptions/windows.h
@@ -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;
diff --git a/twin/layers.cpp b/twin/layers.cpp
index 143d826d5..17068a675 100644
--- a/twin/layers.cpp
+++ b/twin/layers.cpp
@@ -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
diff --git a/twin/options.cpp b/twin/options.cpp
index ce35f6d06..3d237255b 100644
--- a/twin/options.cpp
+++ b/twin/options.cpp
@@ -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 )
diff --git a/twin/options.h b/twin/options.h
index 113e6b9e6..55183e6bd 100644
--- a/twin/options.h
+++ b/twin/options.h
@@ -269,6 +269,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;
diff --git a/twin/utils.h b/twin/utils.h
index e8bc09a46..65c766690 100644
--- a/twin/utils.h
+++ b/twin/utils.h
@@ -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:
diff --git a/twin/workspace.cpp b/twin/workspace.cpp
index 8cddbb72e..03a2e4e50 100644
--- a/twin/workspace.cpp
+++ b/twin/workspace.cpp
@@ -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 )
{
diff --git a/twin/workspace.h b/twin/workspace.h
index e88e68c85..3a724a4a2 100644
--- a/twin/workspace.h
+++ b/twin/workspace.h
@@ -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();