From 4681129e4b560841a363d008be5445289c37f42e Mon Sep 17 00:00:00 2001 From: Lucas Murray Date: Sat, 14 Feb 2009 09:46:12 +0000 Subject: [PATCH] Move desktop layout code into a separate file and class. This will allow adding more complex desktop layout features (Such as desktop rearranging, and non-rectangular layouts) easier in the future. Workspace::calcDesktopLayout() has been deprecated. svn path=/trunk/KDE/kdebase/workspace/; revision=925812 --- CMakeLists.txt | 1 + desktoplayout.cpp | 192 +++++++++++++++++++++++++++++++++++++++++++ desktoplayout.h | 198 ++++++++++++++++++++++++++++++++++++++++++++ workspace.cpp | 205 +++++++++------------------------------------- workspace.h | 32 ++++++-- 5 files changed, 454 insertions(+), 174 deletions(-) create mode 100644 desktoplayout.cpp create mode 100644 desktoplayout.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d9233ce12..68ca2b2a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,6 +89,7 @@ set(kwin_KDEINIT_SRCS deleted.cpp effects.cpp compositingprefs.cpp + desktoplayout.cpp ) qt4_add_dbus_adaptor( kwin_KDEINIT_SRCS org.kde.KWin.xml workspace.h KWin::Workspace ) diff --git a/desktoplayout.cpp b/desktoplayout.cpp new file mode 100644 index 000000000..e74873cd4 --- /dev/null +++ b/desktoplayout.cpp @@ -0,0 +1,192 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2009 Lucas Murray + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ + +#include "desktoplayout.h" + +namespace KWin +{ + +DesktopLayout::DesktopLayout() + : m_count( 0 ) // This is an invalid state + , m_gridSize( 1, 2 ) // Default to two rows + , m_grid( new int[2] ) + , m_current( 0 ) + , m_dynamic( false ) + { + m_grid[0] = 0; + m_grid[1] = 0; + } + +DesktopLayout::~DesktopLayout() + { + delete[] m_grid; + } + +void DesktopLayout::setNumberOfDesktops( int count ) + { + m_count = count; + // Make sure our grid is valid. TODO: Is there a sane way to avoid overriding the existing grid? + setNETDesktopLayout( Qt::Horizontal, m_count / m_gridSize.height() + 1, m_gridSize.height(), 0 ); + } + +void DesktopLayout::setNETDesktopLayout( Qt::Orientation orientation, int width, int height, + int startingCorner ) + { + Q_UNUSED( startingCorner ); // Not really worth implementing right now. + + // Calculate valid grid size + assert( width > 0 && height > 0 ); + if(( width <= 0 ) && ( height > 0 )) + width = ( m_count + height - 1 ) / height; + else if(( height <= 0 ) && ( width > 0 )) + height = ( m_count + width - 1 ) / width; + + // Set private variables + m_gridSize = QSize( width, height ); + delete[] m_grid; + m_grid = new int[width * height]; + + // Populate grid + int desktop = 1; + if( orientation == Qt::Horizontal ) + for( int y = 0; y < height; y++ ) + for( int x = 0; x < width; x++ ) + m_grid[y * height + x] = (desktop <= m_count ? desktop++ : 0); + else + for( int x = 0; x < width; x++ ) + for( int y = 0; y < height; y++ ) + m_grid[y * height + x] = (desktop <= m_count ? desktop++ : 0); + } + +QPoint DesktopLayout::desktopGridCoords( int id ) const + { + for( int y = 0; y < m_gridSize.height(); y++ ) + for( int x = 0; x < m_gridSize.width(); x++ ) + if( m_grid[y * m_gridSize.height() + x] == id ) + return QPoint( x, y ); + return QPoint( -1, -1 ); + } + +QPoint DesktopLayout::desktopCoords( int id ) const + { + QPoint coords = desktopGridCoords( id ); + if( coords.x() == -1 ) + return QPoint( -1, -1 ); + return QPoint( coords.x() * displayWidth(), coords.y() * displayHeight() ); + } + +int DesktopLayout::desktopAbove( int id, bool wrap ) const + { + if( id == 0 ) + id = currentDesktop(); + QPoint coords = desktopGridCoords( id ); + assert( coords.x() >= 0 ); + for(;;) + { + coords.ry()--; + if( coords.y() < 0 ) + { + if( wrap ) + coords.setY( m_gridSize.height() - 1 ); + else + return id; // Already at the top-most desktop + } + int desktop = desktopAtCoords( coords ); + if( desktop > 0 ) + return desktop; + } + } + +int DesktopLayout::desktopToRight( int id, bool wrap ) const + { + if( id == 0 ) + id = currentDesktop(); + QPoint coords = desktopGridCoords( id ); + assert( coords.x() >= 0 ); + for(;;) + { + coords.rx()++; + if( coords.x() >= m_gridSize.width() ) + { + if( wrap ) + coords.setX( 0 ); + else + return id; // Already at the right-most desktop + } + int desktop = desktopAtCoords( coords ); + if( desktop > 0 ) + return desktop; + } + } + +int DesktopLayout::desktopBelow( int id, bool wrap ) const + { + if( id == 0 ) + id = currentDesktop(); + QPoint coords = desktopGridCoords( id ); + assert( coords.x() >= 0 ); + for(;;) + { + coords.ry()++; + if( coords.y() >= m_gridSize.height() ) + { + if( wrap ) + coords.setY( 0 ); + else + return id; // Already at the bottom-most desktop + } + int desktop = desktopAtCoords( coords ); + if( desktop > 0 ) + return desktop; + } + } + +int DesktopLayout::desktopToLeft( int id, bool wrap ) const + { + if( id == 0 ) + id = currentDesktop(); + QPoint coords = desktopGridCoords( id ); + assert( coords.x() >= 0 ); + for(;;) + { + coords.rx()--; + if( coords.x() < 0 ) + { + if( wrap ) + coords.setX( m_gridSize.width() - 1 ); + else + return id; // Already at the left-most desktop + } + int desktop = desktopAtCoords( coords ); + if( desktop > 0 ) + return desktop; + } + } + +int DesktopLayout::addDesktop( QPoint coords ) + { // TODO + return 0; + } + +void DesktopLayout::deleteDesktop( int id ) + { // TODO + } + +} // namespace diff --git a/desktoplayout.h b/desktoplayout.h new file mode 100644 index 000000000..0121bed65 --- /dev/null +++ b/desktoplayout.h @@ -0,0 +1,198 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2009 Lucas Murray + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ + +#ifndef KWIN_DESKTOPLAYOUT_H +#define KWIN_DESKTOPLAYOUT_H + +#include +#include +#include + +#include "utils.h" + +namespace KWin +{ + +class DesktopLayout + { + public: + DesktopLayout(); + ~DesktopLayout(); + + /** + * @returns Total number of desktops currently in existance. + */ + int numberOfDesktops() const; + /** + * Set the number of available desktops to @a count. It is not recommended to use this + * function as it overrides any previous grid layout. + */ + void setNumberOfDesktops( int count ); + + /** + * @returns The width of desktop layout in grid units. + */ + int gridWidth() const; + /** + * @returns The height of desktop layout in grid units. + */ + int gridHeight() const; + /** + * @returns The width of desktop layout in pixels. Equivalent to gridWidth() * + * ::displayWidth(). + */ + int width() const; + /** + * @returns The height of desktop layout in pixels. Equivalent to gridHeight() * + * ::displayHeight(). + */ + int height() const; + + /** + * @returns The ID of the current desktop. + */ + int currentDesktop() const; + /** + * Set the current desktop to @a current. + */ + void setCurrentDesktop( int current ); + + /** + * Generate a desktop layout from EWMH _NET_DESKTOP_LAYOUT property parameters. + */ + void setNETDesktopLayout( Qt::Orientation orientation, int width, int height, int startingCorner ); + + /** + * @returns The ID of the desktop at the point @a coords or 0 if no desktop exists at that + * point. @a coords is to be in grid units. + */ + int desktopAtCoords( QPoint coords ) const; + /** + * @returns The coords of desktop @a id in grid units. + */ + QPoint desktopGridCoords( int id ) const; + /** + * @returns The coords of the top-left corner of desktop @a id in pixels. + */ + QPoint desktopCoords( int id ) const; + + /** + * @returns The ID of the desktop above desktop @a id. Wraps around to the bottom of + * the layout if @a wrap is set. If @a id is not set use the current one. + */ + int desktopAbove( int id = 0, bool wrap = true ) const; + /** + * @returns The ID of the desktop to the right of desktop @a id. Wraps around to the + * left of the layout if @a wrap is set. If @a id is not set use the current one. + */ + int desktopToRight( int id = 0, bool wrap = true ) const; + /** + * @returns The ID of the desktop below desktop @a id. Wraps around to the top of the + * layout if @a wrap is set. If @a id is not set use the current one. + */ + int desktopBelow( int id = 0, bool wrap = true ) const; + /** + * @returns The ID of the desktop to the left of desktop @a id. Wraps around to the + * right of the layout if @a wrap is set. If @a id is not set use the current one. + */ + int desktopToLeft( int id = 0, bool wrap = true ) const; + + /** + * @returns Whether or not the layout is allowed to be modified by the user. + */ + bool isDynamic() const; + /** + * Sets whether or not this layout can be modified by the user. + */ + void setDynamic( bool dynamic ); + /** + * Create new desktop at the point @a coords + * @returns The ID of the created desktop + */ + int addDesktop( QPoint coords ); + /** + * Deletes the desktop with the ID @a id. All desktops with an ID greater than the one that + * was deleted will have their IDs' decremented. + */ + void deleteDesktop( int id ); + + private: + int m_count; + QSize m_gridSize; + int* m_grid; + int m_current; + bool m_dynamic; + }; + +inline int DesktopLayout::numberOfDesktops() const + { + return m_count; + } + +inline int DesktopLayout::gridWidth() const + { + return m_gridSize.width(); + } + +inline int DesktopLayout::gridHeight() const + { + return m_gridSize.height(); + } + +inline int DesktopLayout::width() const + { + return m_gridSize.width() * displayWidth(); + } + +inline int DesktopLayout::height() const + { + return m_gridSize.height() * displayHeight(); + } + +inline int DesktopLayout::currentDesktop() const + { + return m_current; + } + +inline void DesktopLayout::setCurrentDesktop( int current ) + { + assert( current >= 1 ); + assert( current <= m_count ); + m_current = current; + } + +inline int DesktopLayout::desktopAtCoords( QPoint coords ) const + { + return m_grid[coords.y() * m_gridSize.height() + coords.x()]; + } + +inline bool DesktopLayout::isDynamic() const + { + return m_dynamic; + } + +inline void DesktopLayout::setDynamic( bool dynamic ) + { + m_dynamic = dynamic; + } + +} // namespace + +#endif diff --git a/workspace.cpp b/workspace.cpp index ec3066a43..344e52a96 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -88,8 +88,6 @@ Workspace* Workspace::_self = 0; Workspace::Workspace( bool restore ) : QObject( 0 ) - , current_desktop( 0 ) - , number_of_desktops( 0 ) , active_popup( NULL ) , active_popup_client( NULL ) , temporaryRulesMessages( "_KDE_NET_WM_TEMPORARY_RULES", NULL, false ) @@ -127,8 +125,6 @@ Workspace::Workspace( bool restore ) , workspaceInit( true ) , startup( 0 ) , layoutOrientation( Qt::Vertical ) - , layoutX( -1 ) - , layoutY( 2 ) , managing_topmenus( false ) , topmenu_selection( NULL ) , topmenu_watcher( NULL ) @@ -417,8 +413,8 @@ void Workspace::init() updateClientArea(); // NETWM spec says we have to set it to (0,0) if we don't support it - NETPoint* viewports = new NETPoint[number_of_desktops]; - rootInfo->setDesktopViewport( number_of_desktops, *viewports ); + NETPoint* viewports = new NETPoint[numberOfDesktops()]; + rootInfo->setDesktopViewport( numberOfDesktops(), *viewports ); delete[] viewports; QRect geom = Kephal::ScreenUtils::desktopGeometry(); NETSize desktop_geometry; @@ -1121,11 +1117,11 @@ void Workspace::loadDesktopSettings() KConfigGroup group( c, groupname ); int n = group.readEntry( "Number", 4 ); - number_of_desktops = n; + desktopLayout.setNumberOfDesktops( n ); workarea.clear(); workarea.resize( n + 1 ); screenarea.clear(); - rootInfo->setNumberOfDesktops( number_of_desktops ); + rootInfo->setNumberOfDesktops( n ); desktop_focus_chain.resize( n ); // Make it +1, so that it can be accessed as [1..numberofdesktops] focus_chain.resize( n + 1 ); @@ -1147,8 +1143,8 @@ void Workspace::saveDesktopSettings() groupname.sprintf( "Desktops-screen-%d", screen_number ); KConfigGroup group( c, groupname ); - group.writeEntry( "Number", number_of_desktops ); - for( int i = 1; i <= number_of_desktops; i++ ) + group.writeEntry( "Number", numberOfDesktops() ); + for( int i = 1; i <= numberOfDesktops(); i++ ) { QString s = desktopName( i ); QString defaultvalue = i18n( "Desktop %1", i ); @@ -1308,7 +1304,7 @@ ObscuringWindows::~ObscuringWindows() */ bool Workspace::setCurrentDesktop( int new_desktop ) { - if( new_desktop < 1 || new_desktop > number_of_desktops ) + if( new_desktop < 1 || new_desktop > numberOfDesktops() ) return false; closeActivePopup(); @@ -1316,8 +1312,8 @@ bool Workspace::setCurrentDesktop( int new_desktop ) // TODO: Q_ASSERT( block_stacking_updates == 0 ); // Make sure stacking_order is up to date StackingUpdatesBlocker blocker( this ); - int old_desktop = current_desktop; - if (new_desktop != current_desktop ) + int old_desktop = currentDesktop(); + if (new_desktop != currentDesktop() ) { ++block_showing_desktop; // Optimized Desktop switching: unmapping done from back to front @@ -1326,7 +1322,7 @@ bool Workspace::setCurrentDesktop( int new_desktop ) ObscuringWindows obs_wins; - current_desktop = new_desktop; // Change the desktop (so that Client::updateVisibility() works) + desktopLayout.setCurrentDesktop( new_desktop ); // Change the desktop (so that Client::updateVisibility() works) for( ClientList::ConstIterator it = stacking_order.constBegin(); it != stacking_order.constEnd(); @@ -1339,7 +1335,7 @@ bool Workspace::setCurrentDesktop( int new_desktop ) } // Now propagate the change, after hiding, before showing - rootInfo->setCurrentDesktop( current_desktop ); + rootInfo->setCurrentDesktop( currentDesktop() ); if( movingClient && !movingClient->isOnDesktop( new_desktop )) movingClient->setDesktop( new_desktop ); @@ -1440,162 +1436,34 @@ void Workspace::previousDesktop() setCurrentDesktop( desktop > 0 ? desktop : numberOfDesktops() ); } -int Workspace::desktopToRight( int desktop, bool wrap ) const - { - int x,y; - Qt::Orientation orientation; - calcDesktopLayout( &x, &y, &orientation ); - int dt = desktop - 1; - if( orientation == Qt::Vertical ) - { - dt += y; - if( dt >= numberOfDesktops() ) - { - if( wrap ) - dt -= numberOfDesktops(); - else - return desktop; - } - } - else - { - int d = ( dt % x ) + 1; - if( d >= x ) - { - if( wrap ) - d -= x; - else - return desktop; - } - dt = dt - ( dt % x ) + d; - } - return dt + 1; - } - -int Workspace::desktopToLeft( int desktop, bool wrap ) const - { - int x,y; - Qt::Orientation orientation; - calcDesktopLayout( &x, &y, &orientation ); - int dt = desktop - 1; - if( orientation == Qt::Vertical ) - { - dt -= y; - if( dt < 0 ) - { - if( wrap ) - dt += numberOfDesktops(); - else - return desktop; - } - } - else - { - int d = ( dt % x ) - 1; - if( d < 0 ) - { - if( wrap ) - d += x; - else - return desktop; - } - dt = dt - ( dt % x ) + d; - } - return dt + 1; - } - -int Workspace::desktopUp( int desktop, bool wrap ) const - { - int x,y; - Qt::Orientation orientation; - calcDesktopLayout( &x, &y, &orientation); - int dt = desktop - 1; - if( orientation == Qt::Horizontal ) - { - dt -= x; - if( dt < 0 ) - { - if( wrap ) - dt += numberOfDesktops(); - else - return desktop; - } - } - else - { - int d = ( dt % y ) - 1; - if( d < 0 ) - { - if( wrap ) - d += y; - else - return desktop; - } - dt = dt - ( dt % y ) + d; - } - return dt + 1; - } - -int Workspace::desktopDown( int desktop, bool wrap ) const - { - int x,y; - Qt::Orientation orientation; - calcDesktopLayout( &x, &y, &orientation); - int dt = desktop - 1; - if( orientation == Qt::Horizontal ) - { - dt += x; - if( dt >= numberOfDesktops() ) - { - if( wrap ) - dt -= numberOfDesktops(); - else - return desktop; - } - } - else - { - int d = ( dt % y ) + 1; - if( d >= y ) - { - if( wrap ) - d -= y; - else - return desktop; - } - dt = dt - ( dt % y ) + d; - } - return dt + 1; - } - /** * Sets the number of virtual desktops to \a n */ void Workspace::setNumberOfDesktops( int n ) { - if( n == number_of_desktops ) + if( n == numberOfDesktops() ) return; - int old_number_of_desktops = number_of_desktops; - number_of_desktops = n; + int old_number_of_desktops = numberOfDesktops(); + desktopLayout.setNumberOfDesktops( n ); if( currentDesktop() > numberOfDesktops() ) setCurrentDesktop( numberOfDesktops() ); // If increasing the number, do the resizing now, otherwise // after the moving of windows to still existing desktops - if( old_number_of_desktops < number_of_desktops ) + if( old_number_of_desktops < numberOfDesktops() ) { - rootInfo->setNumberOfDesktops( number_of_desktops ); - NETPoint* viewports = new NETPoint[number_of_desktops]; - rootInfo->setDesktopViewport( number_of_desktops, *viewports ); + rootInfo->setNumberOfDesktops( numberOfDesktops() ); + NETPoint* viewports = new NETPoint[numberOfDesktops()]; + rootInfo->setDesktopViewport( numberOfDesktops(), *viewports ); delete[] viewports; updateClientArea( true ); - focus_chain.resize( number_of_desktops + 1 ); + focus_chain.resize( numberOfDesktops() + 1 ); } // If the number of desktops decreased, move all windows // that would be hidden to the last visible desktop - if( old_number_of_desktops > number_of_desktops ) + if( old_number_of_desktops > numberOfDesktops() ) { for( ClientList::ConstIterator it = clients.constBegin(); it != clients.constEnd(); @@ -1603,14 +1471,14 @@ void Workspace::setNumberOfDesktops( int n ) if( !(*it)->isOnAllDesktops() && (*it)->desktop() > numberOfDesktops() ) sendClientToDesktop( *it, numberOfDesktops(), true ); } - if( old_number_of_desktops > number_of_desktops ) + if( old_number_of_desktops > numberOfDesktops() ) { - rootInfo->setNumberOfDesktops( number_of_desktops ); - NETPoint* viewports = new NETPoint[number_of_desktops]; - rootInfo->setDesktopViewport( number_of_desktops, *viewports ); + rootInfo->setNumberOfDesktops( numberOfDesktops() ); + NETPoint* viewports = new NETPoint[numberOfDesktops()]; + rootInfo->setDesktopViewport( numberOfDesktops(), *viewports ); delete[] viewports; updateClientArea( true ); - focus_chain.resize( number_of_desktops + 1 ); + focus_chain.resize( numberOfDesktops() + 1 ); } saveDesktopSettings(); @@ -1735,19 +1603,22 @@ void Workspace::sendClientToScreen( Client* c, int screen ) void Workspace::updateDesktopLayout() { - //rootInfo->desktopLayoutCorner(); // I don't find this worth bothering, feel free to - layoutOrientation = ( rootInfo->desktopLayoutOrientation() == NET::OrientationHorizontal - ? Qt::Horizontal : Qt::Vertical ); - layoutX = rootInfo->desktopLayoutColumnsRows().width(); - layoutY = rootInfo->desktopLayoutColumnsRows().height(); - if( layoutX == 0 && layoutY == 0 ) // Not given, set default layout - layoutY = 2; + int width = rootInfo->desktopLayoutColumnsRows().width(); + int height = rootInfo->desktopLayoutColumnsRows().height(); + if( width == 0 && height == 0 ) // Not given, set default layout + height = 2; + layoutOrientation = rootInfo->desktopLayoutOrientation() == NET::OrientationHorizontal ? + Qt::Horizontal : Qt::Vertical; + desktopLayout.setNETDesktopLayout( + layoutOrientation, width, height, + 0 //rootInfo->desktopLayoutCorner() // Not really worth implementing right now. + ); } void Workspace::calcDesktopLayout( int* xp, int* yp, Qt::Orientation* orientation ) const - { - int x = layoutX; // <= 0 means compute it from the other and total number of desktops - int y = layoutY; + { // TODO: Deprecated, use desktopLayout instead + int x = desktopLayout.gridWidth(); // <= 0 means compute it from the other and total number of desktops + int y = desktopLayout.gridHeight(); if(( x <= 0 ) && ( y > 0 )) x = ( numberOfDesktops() + y - 1 ) / y; else if(( y <= 0) && ( x > 0 )) diff --git a/workspace.h b/workspace.h index 4125100df..a97dd0789 100644 --- a/workspace.h +++ b/workspace.h @@ -31,6 +31,7 @@ along with this program. If not, see . #include #include +#include "desktoplayout.h" #include "plugins.h" #include "utils.h" #include "kdecoration.h" @@ -613,8 +614,6 @@ class Workspace : public QObject, public KDecorationDefines void setCompositeTimer(); void checkCompositePaintTime( int msec ); - int current_desktop; - int number_of_desktops; QVector desktop_focus_chain; QWidget* active_popup; @@ -747,9 +746,8 @@ class Workspace : public QObject, public KDecorationDefines QPoint electric_push_point; int electric_reserved[ELECTRIC_COUNT]; // Corners/edges used by something - Qt::Orientation layoutOrientation; - int layoutX; - int layoutY; + DesktopLayout desktopLayout; + Qt::Orientation layoutOrientation; // TODO: Deprecated, remove when calcDesktopLayout() is. Placement* initPositioning; @@ -855,12 +853,32 @@ inline Client* Workspace::mostRecentlyActivatedClient() const inline int Workspace::currentDesktop() const { - return current_desktop; + return desktopLayout.currentDesktop(); } inline int Workspace::numberOfDesktops() const { - return number_of_desktops; + return desktopLayout.numberOfDesktops(); + } + +inline int Workspace::desktopToRight( int desktop, bool wrap ) const + { + return desktopLayout.desktopToRight( desktop, wrap ); + } + +inline int Workspace::desktopToLeft( int desktop, bool wrap ) const + { + return desktopLayout.desktopToLeft( desktop, wrap ); + } + +inline int Workspace::desktopUp( int desktop, bool wrap ) const + { + return desktopLayout.desktopAbove( desktop, wrap ); + } + +inline int Workspace::desktopDown( int desktop, bool wrap ) const + { + return desktopLayout.desktopBelow( desktop, wrap ); } inline void Workspace::addGroup( Group* group, allowed_t )