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 else
new_areas[ (*it)->desktop() ] = new_areas[ (*it)->desktop() ].intersect( r ); 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; bool changed = force;
for( int i = 1; for( int i = 1;
@ -104,6 +113,7 @@ void Workspace::updateClientArea( bool force )
rootInfo->setWorkArea( i, r ); rootInfo->setWorkArea( i, r );
} }
updateTopMenuSpaceGeometry();
for( ClientList::ConstIterator it = clients.begin(); for( ClientList::ConstIterator it = clients.begin();
it != clients.end(); it != clients.end();
++it) ++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 // Client
//******************************************** //********************************************
@ -351,11 +371,9 @@ void Workspace::unclutterDesktop()
QRect Client::adjustedClientArea( const QRect& area ) const QRect Client::adjustedClientArea( const QRect& area ) const
{ {
QRect r = area; QRect r = area;
if( isTopMenu() && workspace()->managingTopMenus()) // topmenu area is reserved in updateClientArea()
{ if( isTopMenu())
r.setTop( r.top() + workspace()->topMenuHeight());
return r; return r;
}
NETStrut strut = info->strut(); NETStrut strut = info->strut();
if ( strut.left > 0 ) if ( strut.left > 0 )
r.setLeft( r.left() + (int) strut.left ); r.setLeft( r.left() + (int) strut.left );

View File

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

View File

@ -146,6 +146,13 @@ unsigned long Options::updateSettings()
globalConfig.setGroup("KDE"); globalConfig.setGroup("KDE");
fade_tooltips = globalConfig.readBoolEntry("EffectFadeTooltip", false); fade_tooltips = globalConfig.readBoolEntry("EffectFadeTooltip", false);
animate_tooltips = globalConfig.readBoolEntry("EffectAnimateTooltip", 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; return changed;
} }

View File

@ -253,6 +253,9 @@ class Options : public KDecorationOptions
*/ */
int electricBorderDelay(); int electricBorderDelay();
bool topMenuEnabled() const { return topmenus; }
bool desktopTopMenu() const { return desktop_topmenu; }
private: private:
WindowOperation OpTitlebarDblClick; WindowOperation OpTitlebarDblClick;
@ -276,6 +279,8 @@ class Options : public KDecorationOptions
int electric_borders; int electric_borders;
int electric_border_delay; int electric_border_delay;
bool show_geometry_tip; bool show_geometry_tip;
bool topmenus;
bool desktop_topmenu;
}; };
extern Options* options; extern Options* options;

View File

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

View File

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