Reserve space for topmenus, so there's no flicker, and the space is taken

even with no topmenu shown. Support topmenus only when enabled in kdeglobals.

svn path=/trunk/kdebase/kwin/; revision=266531
icc-effect-5.14.5
Luboš Luňák 2003-11-12 09:47:13 +00:00
parent 6c3176c74c
commit 1d71c9839b
6 changed files with 125 additions and 48 deletions

View File

@ -82,6 +82,15 @@ void Workspace::updateClientArea( bool force )
else
new_areas[ (*it)->desktop() ] = new_areas[ (*it)->desktop() ].intersect( r );
}
if( topmenu_space != NULL )
{
QRect topmenu_area = all;
topmenu_area.setTop( topMenuHeight());
for( int i = 1;
i <= numberOfDesktops();
++i )
new_areas[ i ] = new_areas[ i ].intersect( topmenu_area );
}
bool changed = force;
for( int i = 1;
@ -104,6 +113,7 @@ void Workspace::updateClientArea( bool force )
rootInfo->setWorkArea( i, r );
}
updateTopMenuSpaceGeometry();
for( ClientList::ConstIterator it = clients.begin();
it != clients.end();
++it)
@ -337,6 +347,16 @@ void Workspace::unclutterDesktop()
}
void Workspace::updateTopMenuSpaceGeometry()
{
if( !managingTopMenus())
return;
QRect area;
area = clientArea( MaximizeFullArea, QPoint( 0, 0 ), 1 ); // HACK desktop ?
area.setHeight( topMenuHeight());
topmenu_space->setGeometry( area );
}
//********************************************
// Client
//********************************************
@ -351,11 +371,9 @@ void Workspace::unclutterDesktop()
QRect Client::adjustedClientArea( const QRect& area ) const
{
QRect r = area;
if( isTopMenu() && workspace()->managingTopMenus())
{
r.setTop( r.top() + workspace()->topMenuHeight());
// topmenu area is reserved in updateClientArea()
if( isTopMenu())
return r;
}
NETStrut strut = info->strut();
if ( strut.left > 0 )
r.setLeft( r.left() + (int) strut.left );

View File

@ -131,39 +131,55 @@ void Workspace::propagateClients( bool propagate_new_clients )
// when passig pointers around.
// restack the windows according to the stacking order
Window* new_stack = new Window[ stacking_order.count() + 1 ];
int i = 0;
Window* new_stack = new Window[ stacking_order.count() + 2 ];
int pos = 0;
// 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 kwin startup. Stacking all clients below
// it ensures that no client will be ever shown above override-redirect
// windows (e.g. popups).
new_stack[ i++ ] = supportWindow->winId();
for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it)
new_stack[i++] = (*it)->frameId();
new_stack[ pos++ ] = supportWindow->winId();
int topmenu_space_pos = 0;
for( ClientList::ConstIterator it = stacking_order.fromLast();
it != stacking_order.end();
--it )
{
new_stack[ pos++ ] = (*it)->frameId();
if( (*it)->isTopMenu())
topmenu_space_pos = pos;
}
if( topmenu_space != NULL )
{ // make sure the topmenu space is below all topmenus, if there are any
for( int i = pos;
i > topmenu_space_pos;
--i )
new_stack[ i ] = new_stack[ i - 1 ];
new_stack[ topmenu_space_pos ] = topmenu_space->winId();
++pos;
}
// TODO isn't it too inefficient to restart always all clients?
// TODO don't restack not visible windows?
XRestackWindows(qt_xdisplay(), new_stack, i);
XRestackWindows(qt_xdisplay(), new_stack, pos);
delete [] new_stack;
if ( propagate_new_clients )
{
cl = new Window[ desktops.count() + clients.count()];
i = 0;
pos = 0;
// TODO this is still not completely in the map order
for ( ClientList::ConstIterator it = desktops.begin(); it != desktops.end(); ++it )
cl[i++] = (*it)->window();
cl[pos++] = (*it)->window();
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it )
cl[i++] = (*it)->window();
rootInfo->setClientList( cl, i );
cl[pos++] = (*it)->window();
rootInfo->setClientList( cl, pos );
delete [] cl;
}
cl = new Window[ stacking_order.count()];
i = 0;
pos = 0;
for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
cl[i++] = (*it)->window();
rootInfo->setClientListStacking( cl, i );
cl[pos++] = (*it)->window();
rootInfo->setClientListStacking( cl, pos );
delete [] cl;
#if 0 // not necessary anymore?

View File

@ -146,6 +146,13 @@ unsigned long Options::updateSettings()
globalConfig.setGroup("KDE");
fade_tooltips = globalConfig.readBoolEntry("EffectFadeTooltip", false);
animate_tooltips = globalConfig.readBoolEntry("EffectAnimateTooltip", false);
topmenus = globalConfig.readBoolEntry( "macStyle", false );
KConfig kdesktopcfg( "kdesktoprc", true );
kdesktopcfg.setGroup( "Menubar" );
desktop_topmenu = kdesktopcfg.readBoolEntry( "ShowMenubar", false );
if( desktop_topmenu )
topmenus = true;
return changed;
}

View File

@ -252,6 +252,9 @@ class Options : public KDecorationOptions
* @returns the activation delay for electric borders in milliseconds.
*/
int electricBorderDelay();
bool topMenuEnabled() const { return topmenus; }
bool desktopTopMenu() const { return desktop_topmenu; }
private:
WindowOperation OpTitlebarDblClick;
@ -276,6 +279,8 @@ class Options : public KDecorationOptions
int electric_borders;
int electric_border_delay;
bool show_geometry_tip;
bool topmenus;
bool desktop_topmenu;
};
extern Options* options;

View File

@ -296,26 +296,25 @@ void Workspace::init()
topmenu_selection = new KSelectionOwner( topmenu_atom );
topmenu_watcher = new KSelectionWatcher( topmenu_atom );
topmenu_height = 0;
if( topmenu_selection->claim( false ))
{
managing_topmenus = true;
connect( topmenu_selection, SIGNAL( lostOwnership()), this, SLOT( lostTopMenuSelection()));
}
else
{
managing_topmenus = false;
connect( topmenu_watcher, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
}
// kdDebug() << "TOPMENU INIT:" << managing_topmenus << endl;
managing_topmenus = false;
topmenu_space = NULL;
{ // begin updates blocker block
StackingUpdatesBlocker blocker( this );
if( options->topMenuEnabled() && topmenu_selection->claim( false ))
setupTopMenuHandling(); // this can call updateStackingOrder()
else
lostTopMenuSelection();
XQueryTree(qt_xdisplay(), root, &root_return, &parent_return, &wins, &nwins);
for (i = 0; i < nwins; i++)
{
XGetWindowAttributes(qt_xdisplay(), wins[i], &attr);
if (attr.override_redirect )
continue;
if( topmenu_space && topmenu_space->winId() == wins[ i ] )
continue;
if (attr.map_state != IsUnmapped)
{
if ( addSystemTrayWin( wins[i] ) )
@ -400,6 +399,7 @@ Workspace::~Workspace()
delete initPositioning;
delete topmenu_watcher;
delete topmenu_selection;
delete topmenu_space;
_self = 0;
}
@ -505,14 +505,15 @@ void Workspace::updateCurrentTopMenu()
{
// toplevel menubar handling
Client* menubar = 0;
bool block_desktop_menubar = false;
if( active_client )
{
// show the new menu bar first...
Client* menu_client = active_client;
// SELI TODO make this also depend on kdesktop's setting, like in menuapplet
bool block_desktop_menubar = active_client->isFullScreen();
for(;;)
{
if( menu_client->isFullScreen())
block_desktop_menubar = true;
for( ClientList::ConstIterator it = menu_client->transients().begin();
it != menu_client->transients().end();
++it )
@ -524,30 +525,26 @@ void Workspace::updateCurrentTopMenu()
if( menubar != NULL || !menu_client->isTransient())
break;
if( menu_client->isModal() || menu_client->transientFor() == NULL )
{ // don't use mainwindow's menu if this is modal or group transient
if( menu_client->isModal() || menu_client->groupTransient())
block_desktop_menubar = true;
break;
}
break; // don't use mainwindow's menu if this is modal or group transient
menu_client = menu_client->transientFor();
}
if( !menubar && active_client->keepAbove())
block_desktop_menubar = true;
if( !menubar && !block_desktop_menubar )
}
if( !options->desktopTopMenu())
block_desktop_menubar = true;
if( !menubar && !block_desktop_menubar )
{
// Find the menubar of the desktop
Client* desktop = findDesktop( true, currentDesktop());
if( desktop != NULL )
{
// Find the menubar of the desktop
Client* desktop = findDesktop( true, currentDesktop());
if( desktop != NULL )
{
for( ClientList::ConstIterator it = desktop->transients().begin();
it != desktop->transients().end();
++it )
if( (*it)->isTopMenu())
for( ClientList::ConstIterator it = desktop->transients().begin();
it != desktop->transients().end();
++it )
if( (*it)->isTopMenu())
{
menubar = *it;
break;
}
}
}
}
@ -569,7 +566,7 @@ void Workspace::updateCurrentTopMenu()
(*it)->hideClient( true );
}
#else
// TODO there should be a blank area where topmenus are placed, no need to keep
// There's a blank area where topmenus are placed, no need to keep
// the desktop one always visible
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it)
{
@ -729,13 +726,28 @@ void Workspace::slotReconfigure()
else
destroyBorderWindows();
if( options->topMenuEnabled())
{
if( !managingTopMenus() && topmenu_selection->claim( false ))
setupTopMenuHandling();
}
else
{
if( managingTopMenus())
{
topmenu_selection->release();
lostTopMenuSelection();
}
}
topmenu_height = 0; // invalidate used menu height
if( managingTopMenus())
{
updateTopMenuSpaceGeometry();
for( ClientList::ConstIterator it = topmenus.begin();
it != topmenus.end();
++it )
(*it)->checkWorkspacePosition();
updateCurrentTopMenu();
}
}
@ -1815,6 +1827,7 @@ void Workspace::addTopMenu( Client* c )
if( minsize > topMenuHeight())
{
topmenu_height = minsize;
updateTopMenuSpaceGeometry();
for( ClientList::ConstIterator it = topmenus.begin();
it != topmenus.end();
++it )
@ -1837,9 +1850,13 @@ void Workspace::removeTopMenu( Client* c )
void Workspace::lostTopMenuSelection()
{
// kdDebug() << "lost TopMenu selection" << endl;
if( !managing_topmenus )
return;
connect( topmenu_watcher, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
disconnect( topmenu_selection, SIGNAL( lostOwnership()), this, SLOT( lostTopMenuSelection()));
managing_topmenus = false;
delete topmenu_space;
updateClientArea();
for( ClientList::ConstIterator it = topmenus.begin();
it != topmenus.end();
++it )
@ -1855,9 +1872,20 @@ void Workspace::lostTopMenuOwner()
return;
}
// kdDebug() << "claimed TopMenu selection" << endl;
setupTopMenuHandling();
}
void Workspace::setupTopMenuHandling()
{
if( managing_topmenus )
return;
connect( topmenu_selection, SIGNAL( lostOwnership()), this, SLOT( lostTopMenuSelection()));
disconnect( topmenu_watcher, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
managing_topmenus = true;
topmenu_space = new QWidget;
updateTopMenuSpaceGeometry();
topmenu_space->show();
updateClientArea();
for( ClientList::ConstIterator it = topmenus.begin();
it != topmenus.end();
++it )

View File

@ -341,6 +341,8 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine
void updateCurrentTopMenu();
void addTopMenu( Client* c );
void removeTopMenu( Client* c );
void setupTopMenuHandling();
void updateTopMenuSpaceGeometry();
void updateToolWindows( bool also_hide );
// this is the right way to create a new client
@ -502,6 +504,7 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine
KSelectionWatcher* topmenu_watcher;
ClientList topmenus; // doesn't own them
mutable int topmenu_height;
QWidget* topmenu_space;
int set_active_client_recursion;
int block_stacking_updates; // when >0, stacking updates are temporarily disabled