GUI: Alt/Tab shows list of icon+window title; Ctrl/Tab shows

list of desktop number+name+icon of apps

svn path=/trunk/kdebase/kwin/; revision=285419
icc-effect-5.14.5
Martin Koller 2004-02-05 21:58:22 +00:00
parent 42e26ff608
commit 3c26c240fe
2 changed files with 285 additions and 172 deletions

View File

@ -43,11 +43,16 @@ namespace KWinInternal
extern QPixmap* kwin_get_menu_pix_hack(); extern QPixmap* kwin_get_menu_pix_hack();
TabBox::TabBox( Workspace *ws, const char *name ) TabBox::TabBox( Workspace *ws, const char *name )
: QWidget( 0, name ) : QFrame( 0, name, Qt::WNoAutoErase ), client(0), wspace(ws)
{ {
setFrameStyle(QFrame::StyledPanel | QFrame::Plain);
setLineWidth(2);
setMargin(2);
showMiniIcon = false;
no_tasks = i18n("*** No Tasks ***"); no_tasks = i18n("*** No Tasks ***");
m = DesktopMode; // init variables m = DesktopMode; // init variables
wspace = ws;
reconfigure(); reconfigure();
reset(); reset();
connect(&delayedShowTimer, SIGNAL(timeout()), this, SLOT(show())); connect(&delayedShowTimer, SIGNAL(timeout()), this, SLOT(show()));
@ -70,69 +75,146 @@ void TabBox::setMode( Mode mode )
/*! /*!
Resets the tab box to display the active client in WindowsMode, or the Create list of clients on specified desktop, starting with client c
current desktop in DesktopListMode */
*/ void TabBox::createClientList(ClientList &list, int desktop /*-1 = all*/, Client *c, bool chain)
void TabBox::reset()
{ {
QFont f = font(); ClientList::size_type idx = 0;
f.setBold( TRUE );
f.setPointSize( 14 );
setFont( f );
wmax = 0; list.clear();
Client* start = c;
if ( chain )
c = workspace()->nextFocusChainClient(c);
else
c = workspace()->stackingOrder().first();
if ( mode() == WindowsMode )
{
client = workspace()->activeClient();
clients.clear();
Client* c = workspace()->nextFocusChainClient( client );
Client* stop = c; Client* stop = c;
QFontMetrics fm( fontMetrics() );
int cw = fm.width(no_tasks)+20;
while ( c ) while ( c )
{ {
if ( (options_traverse_all ||c->isOnDesktop(workspace()->currentDesktop())) if ( ((desktop == -1) || c->isOnDesktop(desktop))
&& (!c->isMinimized() || !c->isTransient() || c->isUtility()) ) && (!c->isMinimized() || !c->isTransient() || c->isUtility()) && c->wantsTabFocus() )
{ {
if ( client == c ) if ( start == c )
{ {
clients.remove( c ); list.remove( c );
clients.prepend( c ); list.prepend( c );
} }
else else
{ // don't add windows that have modal dialogs { // don't add windows that have modal dialogs
Client* modal = c->findModal(); Client* modal = c->findModal();
if( modal == NULL || modal == c ) if( modal == NULL || modal == c )
clients += c; list += c;
else if( !clients.contains( modal )) else if( !list.contains( modal ))
clients += modal; list += modal;
else else
; // nothing ; // nothing
} }
cw = fm.width( c->caption() ) + 40;
if ( cw > wmax )
wmax = cw;
} }
if ( chain )
c = workspace()->nextFocusChainClient( c ); c = workspace()->nextFocusChainClient( c );
else
{
if ( idx >= (workspace()->stackingOrder().size()-1) )
c = 0;
else
c = workspace()->stackingOrder()[++idx];
}
if ( c == stop ) if ( c == stop )
break; break;
} }
wmax = QMAX( wmax, int(clients.count())*20 );
}
else
{ // DesktopListMode
desk = workspace()->currentDesktop();
} }
/*!
Resets the tab box to display the active client in WindowsMode, or the
current desktop in DesktopListMode
*/
void TabBox::reset()
{
int w, h, cw = 0, wmax = 0;
QRect r = KGlobalSettings::desktopGeometry(QCursor::pos()); QRect r = KGlobalSettings::desktopGeometry(QCursor::pos());
int w = QMIN( QMAX( wmax + 20, r.width()/3 ), r.width() ); // calculate height of 1 line
setGeometry( (r.width()-w)/2 + r.x(), // fontheight + 1 pixel above + 1 pixel below, or 32x32 icon + 2 pixel above + below
r.height()/2-fontMetrics().height()*2-10 + r.y(), lineHeight = QMAX(fontMetrics().height() + 2, 32 + 4);
w, fontMetrics().height()*4 + 20 );
wmax = QMIN( wmax, width() - 12 ); if ( mode() == WindowsMode )
{
client = workspace()->activeClient();
// get all clients to show
createClientList(clients, options_traverse_all ? -1 : workspace()->currentDesktop(), client, true);
// calculate maximum caption width
cw = fontMetrics().width(no_tasks)+20;
for (ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it)
{
cw = fontMetrics().width( (*it)->caption() );
if ( cw > wmax ) wmax = cw;
}
// calculate height for the popup
if ( clients.count() == 0 ) // height for the "not tasks" text
{
QFont f = font();
f.setBold( TRUE );
f.setPointSize( 14 );
h = QFontMetrics(f).height()*4;
}
else
{
showMiniIcon = false;
h = clients.count() * lineHeight;
if ( h > (r.height()-(2*frameWidth())) ) // if too high, use mini icons
{
showMiniIcon = true;
// fontheight + 1 pixel above + 1 pixel below, or 16x16 icon + 1 pixel above + below
lineHeight = QMAX(fontMetrics().height() + 2, 16 + 2);
h = clients.count() * lineHeight;
if ( h > (r.height()-(2*frameWidth())) ) // if still too high, remove some clients
{
// how many clients to remove
int howMany = (h - (r.height()-(2*frameWidth())))/lineHeight;
for (; howMany; howMany--)
clients.remove(clients.last());
h = clients.count() * lineHeight;
}
}
}
}
else
{ // DesktopListMode
showMiniIcon = false;
desk = workspace()->currentDesktop();
for ( int i = 1; i <= workspace()->numberOfDesktops(); i++ )
{
cw = fontMetrics().width( workspace()->desktopName(i) );
if ( cw > wmax ) wmax = cw;
}
// calculate height for the popup (max. 16 desktops always fit in a 800x600 screen)
h = workspace()->numberOfDesktops() * lineHeight;
}
// height, width for the popup
h += 2 * frameWidth();
w = QMIN( QMAX( 5 + (showMiniIcon ? 16 : 32) + 8 +wmax, r.width()/3 ), r.width() ); // 5=space, ()=icon, 8=space between icon+text
setGeometry( (r.width()-w)/2 + r.x(),
(r.height()-h)/2+ r.y(),
w, h );
} }
@ -187,7 +269,7 @@ void TabBox::nextPrev( bool next)
} }
} }
paintContents(); update();
} }
@ -235,125 +317,159 @@ void TabBox::hideEvent( QHideEvent* )
{ {
} }
/*! /*!
Paints the tab box Paints the tab box
*/ */
void TabBox::paintEvent( QPaintEvent* ) void TabBox::drawContents( QPainter * )
{ {
{ QRect r(contentsRect());
QPainter p( this ); QPixmap pix(r.size()); // do double buffering to avoid flickers
style().drawPrimitive( QStyle::PE_Panel, &p, QRect( 0, 0, width(), height() ), pix.fill(this, 0, 0);
colorGroup(), QStyle::Style_Default );
style().drawPrimitive( QStyle::PE_Panel, &p, QRect( 4, 4, width()-8, height()-8 ),
colorGroup(), QStyle::Style_Sunken );
}
paintContents();
}
QPainter p;
p.begin(&pix, this);
/*!
Paints the contents of the tab box. Used in paintEvent() and
whenever the contents changes.
*/
void TabBox::paintContents()
{
QPixmap* menu_pix = kwin_get_menu_pix_hack(); QPixmap* menu_pix = kwin_get_menu_pix_hack();
QPainter p( this );
QRect r( 6, 6, width()-12, height()-32 ); int iconWidth = showMiniIcon ? 16 : 32;
p.fillRect( r, colorGroup().brush( QColorGroup::Background ) ); int x = 0;
int y = 0;
if ( mode () == WindowsMode ) if ( mode () == WindowsMode )
{ {
if ( currentClient() ) if ( !currentClient() )
{ {
int textw, maxlen = client->caption().length(); QFont f = font();
int icon = client->icon().isNull() ? 0 : 42; f.setBold( TRUE );
QString s; f.setPointSize( 14 );
do
{
s = QString();
if (!client->isOnDesktop(workspace()->currentDesktop()))
{
s.append(": ");
}
if (client->isMinimized()) p.setFont(f);
s += QString("(")+KStringHandler::csqueeze(client->caption(), maxlen)+")";
else
s += KStringHandler::csqueeze(client->caption(), maxlen);
textw = fontMetrics().width( s );
maxlen--;
} while (textw > r.width() - icon);
r.setLeft( r.left() + (r.width() - textw)/2);
if ( icon )
{
int py = r.center().y() - 16;
r.setLeft( r.left() + 20 );
if( client->icon().mask() != NULL )
p.fillRect( r.left()-42, py, client->icon().width(), client->icon().height(),
colorGroup().brush( QColorGroup::Background ));
p.drawPixmap( r.left()-42, py, client->icon() );
}
p.drawText( r, AlignVCenter, s );
}
else
{
r.setBottom( r.bottom() + 20 );
p.drawText( r, AlignCenter, no_tasks); p.drawText( r, AlignCenter, no_tasks);
} }
else
{
for (ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it)
{
if ( workspace()->hasClient( *it ) ) // safety
{
// draw highlight background
if ( (*it) == currentClient() )
p.fillRect(x, y, r.width(), lineHeight, colorGroup().highlight());
int x = (width() - clients.count() * 20 )/2; // draw icon
int y = height() - 26; if ( showMiniIcon )
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it)
{ {
if ( workspace()->hasClient( *it ) )
{ // safety
if ( !(*it)->miniIcon().isNull() ) if ( !(*it)->miniIcon().isNull() )
{ p.drawPixmap( x+5, y + (lineHeight - iconWidth)/2, (*it)->miniIcon() );
if( (*it)->miniIcon().mask() != NULL )
p.fillRect( x, y, 16, 16, colorGroup().brush( QColorGroup::Background ));
p.drawPixmap( x, y, (*it)->miniIcon() );
} }
else
if ( !(*it)->icon().isNull() )
p.drawPixmap( x+5, y + (lineHeight - iconWidth)/2, (*it)->icon() );
else if ( menu_pix ) else if ( menu_pix )
{ p.drawPixmap( x, y + (lineHeight - iconWidth)/2, *menu_pix );
if( menu_pix->mask() != NULL )
p.fillRect( x, y, 16, 16, colorGroup().brush( QColorGroup::Background )); // generate text to display
p.drawPixmap( x, y, *menu_pix ); QString s;
if ( !(*it)->isOnDesktop(workspace()->currentDesktop()) )
s = workspace()->desktopName((*it)->desktop()) + ": ";
if ( (*it)->isMinimized() )
s += QString("(") + (*it)->caption() + ")";
else
s += (*it)->caption();
s = KStringHandler::cPixelSqueeze(s, fontMetrics(), r.width() - 5 - iconWidth - 8);
// draw text
if ( (*it) == currentClient() )
p.setPen(colorGroup().highlightedText());
else
p.setPen(colorGroup().text());
p.drawText(x+5 + iconWidth + 8, y, r.width() - 5 - iconWidth - 8, lineHeight,
Qt::AlignLeft | Qt::AlignVCenter | Qt::SingleLine, s);
y += lineHeight;
} }
p.setPen( (*it)==currentClient()? if ( y >= r.height() ) break;
colorGroup().highlight():colorGroup().background() );
p.drawRect( x-2, y-2, 20, 20 );
p.setPen( colorGroup().foreground() );
x += 20;
} }
} }
} }
else else
{ // DesktopMode || DesktopListMode { // DesktopMode || DesktopListMode
p.drawText( r, AlignCenter, workspace()->desktopName(desk) ); int iconHeight = iconWidth;
int x = (width() - workspace()->numberOfDesktops() * 20 )/2;
int y = height() - 26; // get widest desktop name/number
QFont f( font() ); QFont f(font());
f.setPointSize( 12 ); f.setBold(true);
f.setBold( FALSE ); f.setPixelSize(iconHeight - 4); // pixel, not point because I need to know the pixels
p.setFont(f ); QFontMetrics fm(f);
int wmax = 0;
for ( int i = 1; i <= workspace()->numberOfDesktops(); i++ )
{
wmax = QMAX(wmax, fontMetrics().width(workspace()->desktopName(i)));
// calculate max width of desktop-number text
QString num = QString::number(i);
iconWidth = QMAX(iconWidth - 4, fm.boundingRect(num).width()) + 4;
}
// In DesktopMode, start at the current desktop // In DesktopMode, start at the current desktop
// In DesktopListMode, start at desktop #1 // In DesktopListMode, start at desktop #1
int iDesktop = (mode() == DesktopMode) ? workspace()->currentDesktop() : 1; int iDesktop = (mode() == DesktopMode) ? workspace()->currentDesktop() : 1;
for ( int i = 1; i <= workspace()->numberOfDesktops(); i++ ) for ( int i = 1; i <= workspace()->numberOfDesktops(); i++ )
{ {
p.setPen( iDesktop == desk? // draw highlight background
colorGroup().highlight():colorGroup().background() ); if ( iDesktop == desk ) // current desktop
p.drawRect( x-2, y-2, 20, 20 ); p.fillRect(x, y, r.width(), lineHeight, colorGroup().highlight());
qDrawWinPanel( &p, QRect( x, y, 16, 16), colorGroup(), FALSE,
&colorGroup().brush(QColorGroup::Base ) ); p.save();
p.setPen( colorGroup().text() );
p.drawText( x, y, 16, 16, AlignCenter, QString::number(iDesktop) ); // draw "icon" (here: number of desktop)
x += 20; p.fillRect(x+5, y+2, iconWidth, iconHeight, colorGroup().base());
p.setPen(colorGroup().text());
p.drawRect(x+5, y+2, iconWidth, iconHeight);
// draw desktop-number
p.setFont(f);
QString num = QString::number(iDesktop);
p.drawText(x+5, y+2, iconWidth, iconHeight, Qt::AlignCenter, num);
p.restore();
// draw desktop name text
if ( iDesktop == desk )
p.setPen(colorGroup().highlightedText());
else
p.setPen(colorGroup().text());
p.drawText(x+5 + iconWidth + 8, y, r.width() - 5 - iconWidth - 8, lineHeight,
Qt::AlignLeft | Qt::AlignVCenter | Qt::SingleLine,
workspace()->desktopName(iDesktop));
// show mini icons from that desktop aligned to each other
int x1 = x + 5 + iconWidth + 8 + wmax + 5;
ClientList list;
createClientList(list, iDesktop, 0, false);
// clients are in reversed stacking order
for (ClientList::ConstIterator it = list.fromLast(); it != list.end(); --it)
{
if ( !(*it)->miniIcon().isNull() )
{
if ( x1+18 >= x+r.width() ) // only show full icons
break;
p.drawPixmap( x1, y + (lineHeight - 16)/2, (*it)->miniIcon() );
x1 += 18;
}
}
// next desktop
y += lineHeight;
if ( y >= r.height() ) break;
if( mode() == DesktopMode ) if( mode() == DesktopMode )
iDesktop = workspace()->nextDesktopFocusChain( iDesktop ); iDesktop = workspace()->nextDesktopFocusChain( iDesktop );
@ -361,6 +477,8 @@ void TabBox::paintContents()
iDesktop++; iDesktop++;
} }
} }
p.end();
bitBlt(this, r.x(), r.y(), &pix);
} }
void TabBox::hide() void TabBox::hide()
@ -426,49 +544,42 @@ void TabBox::handleMouseEvent( XEvent* e )
return; return;
pos.rx() -= x(); // pos is now inside tabbox pos.rx() -= x(); // pos is now inside tabbox
pos.ry() -= y(); pos.ry() -= y();
int num = (pos.y()-frameWidth()) / lineHeight;
if( mode() == WindowsMode ) if( mode() == WindowsMode )
{ {
int x = (width() - clients.count() * 20 )/2;
int y = height() - 26;
if( pos.x() < x || pos.y() < y - 2 || pos.y() > y - 2 + 20 )
return;
for( ClientList::ConstIterator it = clients.begin(); for( ClientList::ConstIterator it = clients.begin();
it != clients.end(); it != clients.end();
++it) ++it)
{ {
if( workspace()->hasClient( *it ) // safety if( workspace()->hasClient( *it ) && (num == 0) ) // safety
&& pos.x() < x + 20 )
{ {
client = *it; client = *it;
break; break;
} }
x += 20; num--;
} }
} }
else else
{ {
int x = (width() - workspace()->numberOfDesktops() * 20 )/2;
int y = height() - 26;
if( pos.x() < x || pos.y() < y - 2 || pos.y() > y - 2 + 20 )
return;
int iDesktop = (mode() == DesktopMode) ? workspace()->currentDesktop() : 1; int iDesktop = (mode() == DesktopMode) ? workspace()->currentDesktop() : 1;
for( int i = 1; for( int i = 1;
i <= workspace()->numberOfDesktops(); i <= workspace()->numberOfDesktops();
++i ) ++i )
{ {
if( pos.x() < x + 20 ) if( num == 0 )
{ {
desk = iDesktop; desk = iDesktop;
break; break;
} }
x += 20; num--;
if( mode() == DesktopMode ) if( mode() == DesktopMode )
iDesktop = workspace()->nextDesktopFocusChain( iDesktop ); iDesktop = workspace()->nextDesktopFocusChain( iDesktop );
else else
iDesktop++; iDesktop++;
} }
} }
paintContents(); update();
} }
//******************************* //*******************************

View File

@ -12,7 +12,7 @@ License. See the file "COPYING" for the exact licensing terms.
#ifndef KWIN_TABBOX_H #ifndef KWIN_TABBOX_H
#define KWIN_TABBOX_H #define KWIN_TABBOX_H
#include <qwidget.h> #include <qframe.h>
#include <qtimer.h> #include <qtimer.h>
#include <qvaluelist.h> #include <qvaluelist.h>
#include "utils.h" #include "utils.h"
@ -25,7 +25,7 @@ namespace KWinInternal
class Workspace; class Workspace;
class Client; class Client;
class TabBox : public QWidget class TabBox : public QFrame
{ {
Q_OBJECT Q_OBJECT
public: public:
@ -55,10 +55,12 @@ class TabBox : public QWidget
void reconfigure(); void reconfigure();
protected: protected:
void paintEvent( QPaintEvent* );
void showEvent( QShowEvent* ); void showEvent( QShowEvent* );
void hideEvent( QHideEvent* ); void hideEvent( QHideEvent* );
void paintContents(); void drawContents( QPainter * );
private:
void createClientList(ClientList &list, int desktop /*-1 = all*/, Client *start, bool chain);
private: private:
Client* client; Client* client;
@ -66,8 +68,8 @@ class TabBox : public QWidget
Workspace* wspace; Workspace* wspace;
ClientList clients; ClientList clients;
int desk; int desk;
QLabel* icon; int lineHeight;
int wmax; bool showMiniIcon;
QTimer delayedShowTimer; QTimer delayedShowTimer;
QString no_tasks; QString no_tasks;
bool options_traverse_all; bool options_traverse_all;