diff options
Diffstat (limited to 'twin')
-rw-r--r-- | twin/client.cpp | 4 | ||||
-rw-r--r-- | twin/client.h | 10 | ||||
-rw-r--r-- | twin/events.cpp | 4 | ||||
-rw-r--r-- | twin/geometry.cpp | 266 | ||||
-rw-r--r-- | twin/kcmtwin/twinoptions/windows.cpp | 159 | ||||
-rw-r--r-- | twin/kcmtwin/twinoptions/windows.h | 25 | ||||
-rw-r--r-- | twin/layers.cpp | 56 | ||||
-rw-r--r-- | twin/options.cpp | 30 | ||||
-rw-r--r-- | twin/options.h | 26 | ||||
-rw-r--r-- | twin/utils.h | 23 | ||||
-rw-r--r-- | twin/workspace.cpp | 577 | ||||
-rw-r--r-- | twin/workspace.h | 48 |
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(); |