You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1667 lines
43 KiB
1667 lines
43 KiB
/*****************************************************************
|
|
|
|
Copyright (c) 2001 Matthias Elter <elter@kde.org>
|
|
Copyright (c) 2002 John Firebaugh <jfirebaugh@kde.org>
|
|
Copyright (c) 2005 Aaron Seigo <aseigo@kde.org>
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.#
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
******************************************************************/
|
|
|
|
#include <assert.h>
|
|
|
|
#include <tqbitmap.h>
|
|
#include <tqcolor.h>
|
|
#include <tqcursor.h>
|
|
#include <tqimage.h>
|
|
#include <tqpainter.h>
|
|
#include <tqpixmap.h>
|
|
#include <tqstyle.h>
|
|
#include <tqstylesheet.h>
|
|
#include <tqtooltip.h>
|
|
|
|
#include <kapplication.h>
|
|
#include <kdebug.h>
|
|
#include <kglobalsettings.h>
|
|
#include <klocale.h>
|
|
#include <kiconeffect.h>
|
|
#include <kiconloader.h>
|
|
#include <kimageeffect.h>
|
|
|
|
#include "global.h"
|
|
#include "kickerSettings.h"
|
|
#include "paneldrag.h"
|
|
#include "taskbar.h"
|
|
#include "taskbarsettings.h"
|
|
#include "tasklmbmenu.h"
|
|
#include "taskrmbmenu.h"
|
|
|
|
#include "taskcontainer.h"
|
|
#include "taskcontainer.moc"
|
|
|
|
TaskContainer::TaskContainer(Task::Ptr task, TaskBar* bar,
|
|
TQWidget *parent, const char *name)
|
|
: TQToolButton(parent, name),
|
|
animationTimer(0, "TaskContainer::animationTimer"),
|
|
dragSwitchTimer(0, "TaskContainer::dragSwitchTimer"),
|
|
attentionTimer(0, "TaskContainer::attentionTimer"),
|
|
m_paintEventCompressionTimer(0, "TaskContainer::paintEventCompressionTimer"),
|
|
currentFrame(0),
|
|
attentionState(-1),
|
|
lastActivated(0),
|
|
m_menu(0),
|
|
m_startup(0),
|
|
arrowType(TQt::UpArrow),
|
|
taskBar(bar),
|
|
discardNextMouseEvent(false),
|
|
aboutToActivate(false),
|
|
m_mouseOver(false),
|
|
m_paintEventCompression(false)
|
|
{
|
|
init();
|
|
setAcceptDrops(true); // Always enabled to activate task during drag&drop.
|
|
|
|
add(task);
|
|
|
|
// we abuse this timer once to get shown
|
|
// no point in having another timer just for this, and
|
|
// a single shot won't do because we need to stop the timer
|
|
// in case our task is deleted out from under us
|
|
dragSwitchTimer.start(0, true);
|
|
}
|
|
|
|
TaskContainer::TaskContainer(Startup::Ptr startup, PixmapList& startupFrames,
|
|
TaskBar* bar, TQWidget *parent, const char *name)
|
|
: TQToolButton(parent, name),
|
|
animationTimer(0, "TaskContainer::animationTimer"),
|
|
dragSwitchTimer(0, "TaskContainer::dragSwitchTimer"),
|
|
attentionTimer(0, "TaskContainer::attentionTimer"),
|
|
m_paintEventCompressionTimer(0, "TaskContainer::paintEventCompressionTimer"),
|
|
currentFrame(0),
|
|
frames(startupFrames),
|
|
attentionState(-1),
|
|
lastActivated(0),
|
|
m_menu(0),
|
|
m_startup(startup),
|
|
arrowType(TQt::LeftArrow),
|
|
taskBar(bar),
|
|
discardNextMouseEvent(false),
|
|
aboutToActivate(false),
|
|
m_mouseOver(false),
|
|
m_paintEventCompression(false)
|
|
{
|
|
init();
|
|
setEnabled(false);
|
|
|
|
sid = m_startup->bin();
|
|
|
|
connect(m_startup, TQT_SIGNAL(changed()), TQT_SLOT(update()));
|
|
|
|
dragSwitchTimer.start(333, true);
|
|
}
|
|
|
|
void TaskContainer::init()
|
|
{
|
|
setWFlags(TQt::WNoAutoErase);
|
|
setBackgroundMode(NoBackground);
|
|
animBg = TQPixmap(16, 16);
|
|
|
|
installEventFilter(KickerTip::the());
|
|
|
|
connect(&animationTimer, TQT_SIGNAL(timeout()), TQT_SLOT(animationTimerFired()));
|
|
connect(&dragSwitchTimer, TQT_SIGNAL(timeout()), TQT_SLOT(showMe()));
|
|
connect(&attentionTimer, TQT_SIGNAL(timeout()), TQT_SLOT(attentionTimerFired()));
|
|
connect(&m_paintEventCompressionTimer, TQT_SIGNAL(timeout()), TQT_SLOT(updateNow()));
|
|
}
|
|
|
|
TaskContainer::~TaskContainer()
|
|
{
|
|
if (m_menu)
|
|
{
|
|
delete m_menu;
|
|
m_menu = 0;
|
|
}
|
|
|
|
stopTimers();
|
|
}
|
|
|
|
void TaskContainer::showMe()
|
|
{
|
|
if(!frames.isEmpty() && taskBar->showIcon())
|
|
animationTimer.start(100);
|
|
|
|
emit showMe(this);
|
|
disconnect(&dragSwitchTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(showMe()));
|
|
connect(&dragSwitchTimer, TQT_SIGNAL(timeout()), TQT_SLOT(dragSwitch()));
|
|
}
|
|
|
|
void TaskContainer::stopTimers()
|
|
{
|
|
animationTimer.stop();
|
|
dragSwitchTimer.stop();
|
|
attentionTimer.stop();
|
|
}
|
|
|
|
void TaskContainer::taskChanged(bool geometryOnlyChange)
|
|
{
|
|
if (geometryOnlyChange)
|
|
{
|
|
// we really don't care about those changes, which we may be getting
|
|
// thanks to the pager, for instance, turning it on in taskmanager.
|
|
// // let's ignore them so we don't end up with tons of processing going on
|
|
return;
|
|
}
|
|
|
|
const TQObject* source = TQT_TQOBJECT_CONST(sender());
|
|
Task::Ptr task = 0;
|
|
Task::List::const_iterator itEnd = tasks.constEnd();
|
|
for (Task::List::const_iterator it = tasks.constBegin(); it != itEnd; ++it)
|
|
{
|
|
if (*it == source)
|
|
{
|
|
task = *it;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (task)
|
|
{
|
|
checkAttention(task);
|
|
}
|
|
|
|
KickerTip::Client::updateKickerTip();
|
|
update();
|
|
}
|
|
|
|
void TaskContainer::iconChanged()
|
|
{
|
|
const TQObject* source = TQT_TQOBJECT_CONST(sender());
|
|
Task::Ptr task = 0;
|
|
Task::List::const_iterator itEnd = tasks.constEnd();
|
|
for (Task::List::const_iterator it = tasks.constBegin(); it != itEnd; ++it)
|
|
{
|
|
if (*it == source)
|
|
{
|
|
task = *it;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (task && !m_filteredTasks.empty() && task != m_filteredTasks.first())
|
|
{
|
|
if (m_menu)
|
|
{
|
|
m_menu->update();
|
|
}
|
|
return;
|
|
}
|
|
|
|
KickerTip::Client::updateKickerTip();
|
|
TQToolButton::update();
|
|
}
|
|
|
|
void TaskContainer::setLastActivated()
|
|
{
|
|
Task::List::const_iterator itEnd = m_filteredTasks.constEnd();
|
|
for (Task::List::const_iterator it = m_filteredTasks.constBegin(); it != itEnd; ++it)
|
|
{
|
|
Task::Ptr t = *it;
|
|
if ( t->isActive() )
|
|
{
|
|
lastActivated = t;
|
|
return;
|
|
}
|
|
}
|
|
lastActivated = 0L;
|
|
}
|
|
|
|
|
|
void TaskContainer::animationTimerFired()
|
|
{
|
|
if (!frames.isEmpty() && taskBar->showIcon() && frames.at(currentFrame) != frames.end())
|
|
{
|
|
TQPixmap *pm = *frames.at(currentFrame);
|
|
|
|
// draw pixmap
|
|
if ( pm && !pm->isNull() ) {
|
|
// we only have to redraw the background for frames 0, 8 and 9
|
|
if ( currentFrame == 0 || currentFrame > 7 ) {
|
|
// double buffered painting
|
|
TQPixmap composite( animBg );
|
|
bitBlt( &composite, 0, 0, pm );
|
|
bitBlt( this, iconRect.x(), iconRect.y(), &composite );
|
|
}
|
|
else
|
|
bitBlt( this, iconRect.x(), iconRect.y(), pm );
|
|
}
|
|
|
|
// increment frame counter
|
|
if ( currentFrame >= 9)
|
|
currentFrame = 0;
|
|
else
|
|
currentFrame++;
|
|
}
|
|
}
|
|
|
|
void TaskContainer::checkAttention(const Task::Ptr t)
|
|
{
|
|
bool attention = t ? t->demandsAttention() : false;
|
|
if (attention && attentionState == -1) // was activated
|
|
{
|
|
attentionState = 0;
|
|
attentionTimer.start(500);
|
|
}
|
|
else if(!attention && attentionState >= 0)
|
|
{ // need to check all
|
|
Task::List::iterator itEnd = tasks.end();
|
|
for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
|
|
{
|
|
if ((*it)->demandsAttention())
|
|
{
|
|
attention = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!attention)
|
|
{
|
|
attentionTimer.stop();
|
|
attentionState = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
void TaskContainer::attentionTimerFired()
|
|
{
|
|
assert( attentionState != -1 );
|
|
if (attentionState < TaskBarSettings::attentionBlinkIterations()*2)
|
|
{
|
|
++attentionState;
|
|
}
|
|
else if (TaskBarSettings::attentionBlinkIterations() < 1000)
|
|
{
|
|
attentionTimer.stop();
|
|
}
|
|
else
|
|
{
|
|
// we have a "forever" blinker (attentionBlinkIterations > 999) and have reached
|
|
// the upper limit. so we need to decrement the attentionState to make it blink
|
|
--attentionState;
|
|
}
|
|
update();
|
|
}
|
|
|
|
TQSizePolicy TaskContainer::sizePolicy() const
|
|
{
|
|
return TQSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Expanding );
|
|
}
|
|
|
|
void TaskContainer::resizeEvent( TQResizeEvent * )
|
|
{
|
|
// calculate the icon rect
|
|
TQRect br( tqstyle().subRect( TQStyle::SR_PushButtonContents, this ) );
|
|
iconRect = TQStyle::visualRect( TQRect(br.x() + 2, (height() - 16) / 2, 16, 16), this );
|
|
}
|
|
|
|
void TaskContainer::add(Task::Ptr task)
|
|
{
|
|
if (!task)
|
|
{
|
|
return;
|
|
}
|
|
|
|
tasks.append(task);
|
|
|
|
if (sid.isEmpty())
|
|
{
|
|
sid = task->classClass();
|
|
}
|
|
|
|
updateFilteredTaskList();
|
|
checkAttention(task);
|
|
|
|
KickerTip::Client::updateKickerTip();
|
|
update();
|
|
|
|
connect(task, TQT_SIGNAL(changed(bool)), TQT_SLOT(taskChanged(bool)));
|
|
connect(task, TQT_SIGNAL(iconChanged()), TQT_SLOT(iconChanged()));
|
|
connect(task, TQT_SIGNAL(activated()), TQT_SLOT(setLastActivated()));
|
|
}
|
|
|
|
void TaskContainer::remove(Task::Ptr task)
|
|
{
|
|
if (!task)
|
|
{
|
|
return;
|
|
}
|
|
|
|
task->publishIconGeometry(TQRect());
|
|
for (Task::List::Iterator it = tasks.begin(); it != tasks.end(); ++it)
|
|
{
|
|
if ((*it) == task)
|
|
{
|
|
tasks.erase(it);
|
|
break;
|
|
}
|
|
}
|
|
|
|
updateFilteredTaskList();
|
|
|
|
if (isEmpty())
|
|
{
|
|
stopTimers();
|
|
return;
|
|
}
|
|
|
|
checkAttention();
|
|
KickerTip::Client::updateKickerTip();
|
|
update();
|
|
}
|
|
|
|
void TaskContainer::remove(Startup::Ptr startup)
|
|
{
|
|
if (!startup || startup != m_startup)
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_startup = 0;
|
|
animationTimer.stop();
|
|
frames.clear();
|
|
|
|
if (!tasks.isEmpty())
|
|
{
|
|
setEnabled(true);
|
|
}
|
|
}
|
|
|
|
bool TaskContainer::contains(Task::Ptr task)
|
|
{
|
|
if (!task)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (Task::List::Iterator it = tasks.begin(); it != tasks.end(); ++it)
|
|
{
|
|
if ((*it) == task)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool TaskContainer::contains(Startup::Ptr startup)
|
|
{
|
|
return startup && (m_startup == startup);
|
|
}
|
|
|
|
bool TaskContainer::contains(WId win)
|
|
{
|
|
Task::List::iterator itEnd = tasks.end();
|
|
for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
|
|
{
|
|
if ((*it)->window() == win)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool TaskContainer::isEmpty()
|
|
{
|
|
return (tasks.isEmpty() && !m_startup);
|
|
}
|
|
|
|
TQString TaskContainer::id()
|
|
{
|
|
return sid;
|
|
}
|
|
|
|
void TaskContainer::updateNow()
|
|
{
|
|
m_paintEventCompression = true;
|
|
update();
|
|
}
|
|
|
|
void TaskContainer::setBackground()
|
|
{
|
|
updateNow();
|
|
}
|
|
|
|
void TaskContainer::paintEvent( TQPaintEvent* )
|
|
{
|
|
if (!m_paintEventCompression)
|
|
{
|
|
if (!m_paintEventCompressionTimer.isActive())
|
|
{
|
|
m_paintEventCompressionTimer.start(30, true);
|
|
}
|
|
return;
|
|
}
|
|
|
|
m_paintEventCompression = false;
|
|
TQPixmap* pm = new TQPixmap(size());
|
|
|
|
const TQPixmap* background = taskBar->backgroundPixmap();
|
|
|
|
if (background)
|
|
{
|
|
TQPoint pt = mapTo(taskBar, TQPoint(0, 0)) + taskBar->backgroundOffset();
|
|
TQPainter p(pm);
|
|
p.drawTiledPixmap(0, 0, width(), height(), *background, pt.x(), pt.y());
|
|
p.end();
|
|
}
|
|
else
|
|
{
|
|
pm->fill(taskBar->paletteBackgroundColor());
|
|
}
|
|
|
|
TQPainter p;
|
|
p.begin(pm ,this);
|
|
drawButton(&p);
|
|
p.end();
|
|
|
|
TQPixmap iconPixmapToSet = *pm;
|
|
if (TQPaintDevice::x11AppDepth() == 32) iconPixmapToSet.convertFromImage(KImageEffect::convertToPremultipliedAlpha( iconPixmapToSet.convertToImage() ));
|
|
|
|
bitBlt(this, 0, 0, &iconPixmapToSet);
|
|
delete pm;
|
|
}
|
|
|
|
void TaskContainer::drawButton(TQPainter *p)
|
|
{
|
|
if (isEmpty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// get a pointer to the pixmap we're drawing on
|
|
TQPixmap *pm((TQPixmap*)p->device());
|
|
TQPixmap pixmap; // icon
|
|
Task::Ptr task = 0;
|
|
bool iconified = !TaskBarSettings::showOnlyIconified();
|
|
bool halo = TaskBarSettings::haloText();
|
|
bool alwaysDrawButtons = TaskBarSettings::drawButtons();
|
|
bool drawButton = alwaysDrawButtons ||
|
|
(m_mouseOver && !halo && isEnabled() &&
|
|
TaskBarSettings::showButtonOnHover());
|
|
TQFont font(KGlobalSettings::taskbarFont());
|
|
|
|
// draw sunken if we contain the active task
|
|
bool active = false;
|
|
bool demandsAttention = false;
|
|
Task::List::iterator itEnd = m_filteredTasks.end();
|
|
for (Task::List::iterator it = m_filteredTasks.begin(); it != itEnd; ++it)
|
|
{
|
|
task = *it;
|
|
if (iconified && !task->isIconified())
|
|
{
|
|
iconified = false;
|
|
}
|
|
|
|
if (task->isActive())
|
|
{
|
|
active = true;
|
|
}
|
|
|
|
if (task->demandsAttention())
|
|
{
|
|
demandsAttention = attentionState == TaskBarSettings::attentionBlinkIterations() ||
|
|
attentionState % 2 == 0;
|
|
}
|
|
}
|
|
|
|
font.setBold(active);
|
|
|
|
TQColorGroup colors = tqpalette().active();
|
|
|
|
if (TaskBarSettings::useCustomColors())
|
|
{
|
|
colors.setColor( TQColorGroup::Button, TaskBarSettings::taskBackgroundColor());
|
|
colors.setColor( TQColorGroup::Background, TaskBarSettings::taskBackgroundColor() );
|
|
colors.setColor( TQColorGroup::ButtonText, TaskBarSettings::inactiveTaskTextColor() );
|
|
colors.setColor( TQColorGroup::Text, TaskBarSettings::inactiveTaskTextColor() );
|
|
}
|
|
|
|
if (demandsAttention)
|
|
{
|
|
if (!drawButton)
|
|
{
|
|
halo = true;
|
|
|
|
TQRect r = rect();
|
|
TQColor line = colors.highlight();
|
|
r.addCoords(2, 2, -2, -2);
|
|
p->fillRect(r, line);
|
|
for (int i = 0; i < 2; ++i)
|
|
{
|
|
line = KickerLib::blendColors(line, colors.background());
|
|
p->setPen(TQPen(line, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
|
|
r.addCoords(-1, -1, 1, 1);
|
|
p->drawRect(r);
|
|
}
|
|
}
|
|
|
|
// blink until blink timeout, then display differently without blinking
|
|
colors.setColor( TQColorGroup::Button, colors.highlight() );
|
|
colors.setColor( TQColorGroup::Background, colors.highlight() );
|
|
colors.setColor( TQColorGroup::ButtonText, colors.highlightedText() );
|
|
colors.setColor( TQColorGroup::Text, colors.highlightedText() );
|
|
}
|
|
|
|
if (active || aboutToActivate)
|
|
{
|
|
colors.setColor(TQColorGroup::Button, colors.button().dark(110));
|
|
}
|
|
|
|
// get the task icon
|
|
if (task)
|
|
{
|
|
pixmap = task->pixmap();
|
|
}
|
|
|
|
bool sunken = isDown() || (alwaysDrawButtons && (active || aboutToActivate));
|
|
bool reverse = TQApplication::reverseLayout();
|
|
TQRect br(tqstyle().subRect(TQStyle::SR_PushButtonContents, this));
|
|
TQPoint shift = TQPoint(tqstyle().pixelMetric(TQStyle::PM_ButtonShiftHorizontal),
|
|
tqstyle().pixelMetric(TQStyle::PM_ButtonShiftVertical));
|
|
|
|
// draw button background
|
|
if (drawButton)
|
|
{
|
|
if (KickerSettings::showDeepButtons()) {
|
|
tqstyle().tqdrawPrimitive(TQStyle::PE_ButtonBevel, p,
|
|
TQRect(1, 1, width()-3, height()-2),
|
|
colors, sunken ? TQStyle::Style_On : TQStyle::Style_Raised);
|
|
}
|
|
else {
|
|
tqstyle().tqdrawPrimitive(TQStyle::PE_ButtonTool, p,
|
|
TQRect(1, 1, width()-2, height()-2),
|
|
colors, sunken ? TQStyle::Style_Down : TQStyle::Style_Raised);
|
|
}
|
|
}
|
|
|
|
// shift button label on sunken buttons
|
|
if (sunken)
|
|
{
|
|
p->translate(shift.x(), shift.y());
|
|
}
|
|
|
|
if (taskBar->showIcon())
|
|
{
|
|
if (pixmap.isNull() && m_startup)
|
|
{
|
|
pixmap = SmallIcon(m_startup->icon());
|
|
}
|
|
|
|
if ( !pixmap.isNull() )
|
|
{
|
|
// make sure it is no larger than 16x16
|
|
if ( pixmap.width() > 16 || pixmap.height() > 16 )
|
|
{
|
|
TQImage tmp = pixmap.convertToImage();
|
|
pixmap.convertFromImage( tmp.smoothScale( 16, 16 ) );
|
|
}
|
|
|
|
// fade out the icon when minimized
|
|
if (iconified)
|
|
{
|
|
KIconEffect::semiTransparent( pixmap );
|
|
}
|
|
|
|
// draw icon
|
|
TQRect pmr(0, 0, pixmap.width(), pixmap.height());
|
|
pmr.moveCenter(iconRect.center());
|
|
p->drawPixmap(pmr, pixmap);
|
|
}
|
|
}
|
|
|
|
// find text
|
|
TQString text = name();
|
|
|
|
// modified overlay
|
|
static TQString modStr = "[" + i18n( "modified" ) + "]";
|
|
int modStrPos = text.find( modStr );
|
|
int textPos = ( taskBar->showIcon() && (!pixmap.isNull() || m_startup)) ? 2 + 16 + 2 : 0;
|
|
|
|
if (modStrPos >= 0)
|
|
{
|
|
// +1 because we include a space after the closing brace.
|
|
text.remove(modStrPos, modStr.length() + 1);
|
|
TQPixmap modPixmap = SmallIcon("modified");
|
|
|
|
// draw modified overlay
|
|
if (!modPixmap.isNull())
|
|
{
|
|
TQRect r = TQStyle::visualRect(TQRect(br.x() + textPos,
|
|
(height() - 16) / 2, 16, 16),
|
|
this);
|
|
|
|
if (iconified)
|
|
{
|
|
KIconEffect::semiTransparent(modPixmap);
|
|
}
|
|
|
|
p->drawPixmap(r, modPixmap);
|
|
textPos += 16 + 2;
|
|
}
|
|
}
|
|
|
|
// draw text
|
|
if (!text.isEmpty())
|
|
{
|
|
TQRect tr = TQStyle::visualRect(TQRect(br.x() + textPos + 1, 0,
|
|
width() - textPos, height()),
|
|
this);
|
|
int textFlags = AlignVCenter | SingleLine;
|
|
textFlags |= reverse ? AlignRight : AlignLeft;
|
|
TQPen textPen;
|
|
|
|
// get the color for the text label
|
|
if (iconified)
|
|
{
|
|
textPen = TQPen(KickerLib::blendColors(colors.button(), colors.buttonText()));
|
|
}
|
|
else if (!active)
|
|
{
|
|
textPen = TQPen(colors.buttonText());
|
|
}
|
|
else // hack for the dotNET style and others
|
|
{
|
|
if (TaskBarSettings::useCustomColors())
|
|
{
|
|
textPen = TQPen(TaskBarSettings::activeTaskTextColor());
|
|
}
|
|
else
|
|
{
|
|
textPen = TQPen(colors.buttonText()); // textPen = p->pen();
|
|
}
|
|
}
|
|
|
|
int availableWidth = width() - (br.x() * 2) - textPos - 2 - KickerSettings::showDeepButtons()?2:0;
|
|
if (m_filteredTasks.count() > 1)
|
|
{
|
|
availableWidth -= 8;
|
|
}
|
|
|
|
if (TQFontMetrics(font).width(text) > availableWidth)
|
|
{
|
|
// draw text into overlay pixmap
|
|
TQPixmap tpm(*pm);
|
|
TQPainter tp(&tpm);
|
|
|
|
if (sunken)
|
|
{
|
|
tp.translate(shift.x(), shift.y());
|
|
}
|
|
|
|
tp.setFont(font);
|
|
tp.setPen(textPen);
|
|
|
|
if (halo)
|
|
{
|
|
taskBar->textShadowEngine()->drawText(tp, tr, textFlags, text, size());
|
|
}
|
|
else
|
|
{
|
|
tp.drawText(tr, textFlags, text);
|
|
}
|
|
|
|
// blend text into background image
|
|
TQImage img = pm->convertToImage();
|
|
TQImage timg = tpm.convertToImage();
|
|
KImageEffect::blend(img, timg, *taskBar->blendGradient(size()), KImageEffect::Red);
|
|
|
|
// End painting before assigning the pixmap
|
|
TQPaintDevice* opd = p->device();
|
|
p->end();
|
|
pm->convertFromImage(img);
|
|
p->begin(opd ,this);
|
|
}
|
|
else
|
|
{
|
|
p->setFont(font);
|
|
p->setPen(textPen);
|
|
|
|
if (halo)
|
|
{
|
|
taskBar->textShadowEngine()->drawText(*p, tr, textFlags, text, size());
|
|
}
|
|
else
|
|
{
|
|
p->drawText(tr, textFlags, text);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!frames.isEmpty() && m_startup && frames.at(currentFrame) != frames.end())
|
|
{
|
|
TQPixmap *anim = *frames.at(currentFrame);
|
|
|
|
if (anim && !anim->isNull())
|
|
{
|
|
// save the background for the other frames
|
|
bitBlt(&animBg, TQPoint(0,0), pm, iconRect);
|
|
// draw the animation frame
|
|
bitBlt(pm, iconRect.x(), iconRect.y(), anim);
|
|
}
|
|
}
|
|
|
|
if (sunken)
|
|
{
|
|
// Change the painter back so the arrow, etc gets drawn in the right location
|
|
p->translate(-shift.x(), -shift.y());
|
|
}
|
|
|
|
// draw popup arrow
|
|
if ((m_filteredTasks.count() > 1) && (!KickerSettings::showDeepButtons()))
|
|
{
|
|
TQStyle::PrimitiveElement e = TQStyle::PE_ArrowLeft;
|
|
|
|
switch (arrowType)
|
|
{
|
|
case Qt::LeftArrow: e = TQStyle::PE_ArrowLeft; break;
|
|
case Qt::RightArrow: e = TQStyle::PE_ArrowRight; break;
|
|
case Qt::UpArrow: e = TQStyle::PE_ArrowUp; break;
|
|
case Qt::DownArrow: e = TQStyle::PE_ArrowDown; break;
|
|
}
|
|
|
|
int flags = TQStyle::Style_Enabled;
|
|
TQRect ar = TQStyle::visualRect(TQRect(br.x() + br.width() - 8 - 2,
|
|
br.y(), 8, br.height()), this);
|
|
if (sunken)
|
|
{
|
|
flags |= TQStyle::Style_Down;
|
|
}
|
|
|
|
tqstyle().tqdrawPrimitive(e, p, ar, colors, flags);
|
|
}
|
|
|
|
// draw mouse over frame in transparent mode
|
|
if (m_mouseOver && halo)
|
|
KickerLib::drawBlendedRect(p, TQRect(0, 0, width(), height()), colorGroup().foreground());
|
|
|
|
if (aboutToActivate)
|
|
{
|
|
aboutToActivate = false;
|
|
}
|
|
}
|
|
|
|
TQString TaskContainer::name()
|
|
{
|
|
// default to container id
|
|
TQString text;
|
|
|
|
// single task -> use mainwindow caption
|
|
if (m_filteredTasks.count() == 1)
|
|
{
|
|
text = m_filteredTasks.first()->visibleName();
|
|
}
|
|
else if (m_filteredTasks.count() > 1)
|
|
{
|
|
// multiple tasks -> use the common part of all captions
|
|
// if it is more descriptive than the class name
|
|
const TQString match = m_filteredTasks.first()->visibleName();
|
|
unsigned int maxLength = match.length();
|
|
unsigned int i = 0;
|
|
bool stop = false;
|
|
|
|
// what we do is find the right-most letter than the names do NOT have
|
|
// in common, and then use everything UP TO that as the name in the button
|
|
while (i < maxLength)
|
|
{
|
|
TQChar check = match.at(i).lower();
|
|
Task::List::iterator itEnd = m_filteredTasks.end();
|
|
for (Task::List::iterator it = m_filteredTasks.begin(); it != itEnd; ++it)
|
|
{
|
|
// we're doing a lot of Utf8 -> TQString conversions here
|
|
// by repeatedly calling visibleIconicName() =/
|
|
if (check != (*it)->visibleName().at(i).lower())
|
|
{
|
|
if (i > 0)
|
|
{
|
|
--i;
|
|
}
|
|
stop = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (stop)
|
|
{
|
|
break;
|
|
}
|
|
|
|
++i;
|
|
}
|
|
|
|
// strip trailing crap
|
|
while (i > 0 && !match.at(i).isLetterOrNumber())
|
|
{
|
|
--i;
|
|
}
|
|
|
|
// more descriptive than id()?
|
|
if (i > 0 && (i + 1) >= id().length())
|
|
{
|
|
text = match.left(i + 1);
|
|
}
|
|
}
|
|
else if (m_startup && !m_startup->text().isEmpty())
|
|
{
|
|
// fall back to startup name
|
|
text = m_startup->text();
|
|
}
|
|
|
|
if (text.isEmpty())
|
|
{
|
|
text = id();
|
|
|
|
// Upper case first letter: seems to be the right thing to do for most cases
|
|
text[0] = text[0].upper();
|
|
}
|
|
|
|
if (m_filteredTasks.count() > 1)
|
|
{
|
|
// this is faster than (" [%1]").arg() or +
|
|
// and it's as fast as using append, but cleaner looking
|
|
text += " [";
|
|
text += TQString::number(m_filteredTasks.count());
|
|
text += "]";
|
|
}
|
|
|
|
return text;
|
|
}
|
|
|
|
void TaskContainer::mousePressEvent( TQMouseEvent* e )
|
|
{
|
|
if (discardNextMouseEvent)
|
|
{
|
|
discardNextMouseEvent = false;
|
|
return;
|
|
}
|
|
|
|
if (e->button() == Qt::LeftButton)
|
|
{
|
|
m_dragStartPos = e->pos();
|
|
}
|
|
else
|
|
{
|
|
m_dragStartPos = TQPoint();
|
|
}
|
|
|
|
int buttonAction = 0;
|
|
|
|
// On left button, only do actions that invoke a menu.
|
|
// Other actions will be handled in mouseReleaseEvent
|
|
switch (e->button())
|
|
{
|
|
case Qt::LeftButton:
|
|
buttonAction = TaskBarSettings::action(TaskBarSettings::LeftButton);
|
|
break;
|
|
case Qt::MidButton:
|
|
buttonAction = TaskBarSettings::action(TaskBarSettings::MiddleButton);
|
|
break;
|
|
case Qt::RightButton:
|
|
default:
|
|
buttonAction = TaskBarSettings::action(TaskBarSettings::RightButton);
|
|
break;
|
|
}
|
|
|
|
if ((buttonAction == TaskBarSettings::ShowTaskList &&
|
|
m_filteredTasks.count() > 1) ||
|
|
buttonAction == TaskBarSettings::ShowOperationsMenu)
|
|
{
|
|
performAction(buttonAction);
|
|
}
|
|
}
|
|
|
|
void TaskContainer::mouseReleaseEvent(TQMouseEvent *e)
|
|
{
|
|
m_dragStartPos = TQPoint();
|
|
|
|
if (!TaskBarSettings::drawButtons())
|
|
{
|
|
setDown(false);
|
|
}
|
|
|
|
// This is to avoid the flicker caused by redrawing the
|
|
// button as unpressed just before it's activated.
|
|
if (!TQT_TQRECT_OBJECT(rect()).contains(e->pos()))
|
|
{
|
|
TQToolButton::mouseReleaseEvent(e);
|
|
return;
|
|
}
|
|
|
|
int buttonAction = 0;
|
|
|
|
switch (e->button())
|
|
{
|
|
case Qt::LeftButton:
|
|
buttonAction = TaskBarSettings::action(TaskBarSettings::LeftButton);
|
|
break;
|
|
case Qt::MidButton:
|
|
buttonAction = TaskBarSettings::action(TaskBarSettings::MiddleButton);
|
|
break;
|
|
case Qt::RightButton:
|
|
default:
|
|
buttonAction = TaskBarSettings::action(TaskBarSettings::RightButton);
|
|
break;
|
|
}
|
|
|
|
if ((buttonAction == TaskBarSettings::ShowTaskList &&
|
|
m_filteredTasks.count() > 1) ||
|
|
buttonAction == TaskBarSettings::ShowOperationsMenu)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (buttonAction == TaskBarSettings::ActivateRaiseOrMinimize ||
|
|
buttonAction == TaskBarSettings::Activate)
|
|
{
|
|
aboutToActivate = true;
|
|
}
|
|
|
|
performAction( buttonAction );
|
|
TQTimer::singleShot(0, this, TQT_SLOT(update()));
|
|
}
|
|
|
|
void TaskContainer::performAction(int action)
|
|
{
|
|
if (m_filteredTasks.isEmpty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch( action ) {
|
|
case TaskBarSettings::ShowTaskList:
|
|
// If there is only one task, the correct behavior is
|
|
// to activate, raise, or iconify it, not show the task menu.
|
|
if( m_filteredTasks.count() > 1 ) {
|
|
popupMenu( TaskBarSettings::ShowTaskList );
|
|
} else {
|
|
performAction( TaskBarSettings::ActivateRaiseOrMinimize );
|
|
}
|
|
break;
|
|
case TaskBarSettings::ShowOperationsMenu:
|
|
popupMenu( TaskBarSettings::ShowOperationsMenu );
|
|
break;
|
|
case TaskBarSettings::ActivateRaiseOrMinimize:
|
|
if (m_filteredTasks.isEmpty())
|
|
{
|
|
break;
|
|
}
|
|
if (m_filteredTasks.count() == 1)
|
|
{
|
|
m_filteredTasks.first()->activateRaiseOrIconify();
|
|
}
|
|
else
|
|
{
|
|
// multiple tasks -> cycle list
|
|
bool hasLastActivated = false;
|
|
Task::List::iterator itEnd = m_filteredTasks.end();
|
|
for (Task::List::iterator it = m_filteredTasks.begin(); it != itEnd; ++it)
|
|
{
|
|
if ((*it) == lastActivated)
|
|
{
|
|
hasLastActivated = true;
|
|
}
|
|
|
|
if ((*it)->isActive())
|
|
{
|
|
// activate next
|
|
++it;
|
|
if (it == itEnd)
|
|
{
|
|
it = m_filteredTasks.begin();
|
|
}
|
|
(*it)->activateRaiseOrIconify();
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (hasLastActivated)
|
|
{
|
|
lastActivated->activateRaiseOrIconify();
|
|
}
|
|
else
|
|
{
|
|
m_filteredTasks[0]->activateRaiseOrIconify();
|
|
}
|
|
}
|
|
break;
|
|
case TaskBarSettings::Activate:
|
|
m_filteredTasks.first()->activate();
|
|
break;
|
|
case TaskBarSettings::Raise:
|
|
m_filteredTasks.first()->raise();
|
|
break;
|
|
case TaskBarSettings::Lower:
|
|
m_filteredTasks.first()->lower();
|
|
break;
|
|
case TaskBarSettings::Minimize:
|
|
m_filteredTasks.first()->toggleIconified();
|
|
break;
|
|
case TaskBarSettings::Close:
|
|
m_filteredTasks.first()->close();
|
|
break;
|
|
case TaskBarSettings::ToCurrentDesktop:
|
|
m_filteredTasks.first()->toCurrentDesktop();
|
|
break;
|
|
default:
|
|
kdWarning(1210) << "Unknown taskbar action!" << endl;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// forcenext == true means the last entry in the previous
|
|
// taskcontainer was active -> activate first
|
|
bool TaskContainer::activateNextTask(bool forward, bool& forcenext)
|
|
{
|
|
if (forcenext)
|
|
{
|
|
if (m_filteredTasks.isEmpty())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (forward)
|
|
{
|
|
m_filteredTasks.first()->activate();
|
|
}
|
|
else
|
|
{
|
|
m_filteredTasks.last()->activate();
|
|
}
|
|
|
|
forcenext = false;
|
|
return true;
|
|
}
|
|
|
|
Task::List::iterator itEnd = m_filteredTasks.end();
|
|
for (Task::List::iterator it = m_filteredTasks.begin();
|
|
it != itEnd;
|
|
++it)
|
|
{
|
|
if ((*it)->isActive())
|
|
{
|
|
if (forward)
|
|
{
|
|
++it;
|
|
if (it == itEnd)
|
|
{
|
|
forcenext = true;
|
|
return false;
|
|
}
|
|
|
|
(*it)->activate();
|
|
return true;
|
|
}
|
|
else if (it == m_filteredTasks.begin())
|
|
{
|
|
forcenext = true;
|
|
return false;
|
|
}
|
|
|
|
--it;
|
|
(*it)->activate();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void TaskContainer::popupMenu(int action)
|
|
{
|
|
if (action == TaskBarSettings::ShowTaskList )
|
|
{
|
|
m_menu = new TaskLMBMenu(m_filteredTasks);
|
|
}
|
|
else if (action == TaskBarSettings::ShowOperationsMenu)
|
|
{
|
|
if (!kapp->authorizeKAction("kwin_rmb"))
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_menu = new TaskRMBMenu(m_filteredTasks, taskBar->showAllWindows());
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
|
|
// calc popup menu position
|
|
TQPoint pos(mapToGlobal(TQPoint(0, 0)));
|
|
|
|
switch( arrowType )
|
|
{
|
|
case RightArrow:
|
|
pos.setX(pos.x() + width());
|
|
break;
|
|
case LeftArrow:
|
|
pos.setX(pos.x() - m_menu->sizeHint().width());
|
|
break;
|
|
case DownArrow:
|
|
if ( TQApplication::reverseLayout() )
|
|
pos.setX( pos.x() + width() - m_menu->sizeHint().width() );
|
|
pos.setY( pos.y() + height() );
|
|
break;
|
|
case UpArrow:
|
|
if ( TQApplication::reverseLayout() )
|
|
pos.setX( pos.x() + width() - m_menu->sizeHint().width() );
|
|
pos.setY(pos.y() - m_menu->sizeHint().height());
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
m_menu->installEventFilter( this );
|
|
m_menu->exec( pos );
|
|
|
|
delete m_menu;
|
|
m_menu = 0;
|
|
}
|
|
|
|
void TaskContainer::mouseMoveEvent( TQMouseEvent* e )
|
|
{
|
|
kdDebug() << "regular move" << endl;
|
|
if (!m_dragStartPos.isNull())
|
|
{
|
|
startDrag(e->pos());
|
|
}
|
|
|
|
TQToolButton::mouseMoveEvent(e);
|
|
}
|
|
|
|
bool TaskContainer::startDrag(const TQPoint& pos)
|
|
{
|
|
if (m_filteredTasks.count() != 1)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int delay = KGlobalSettings::dndEventDelay();
|
|
|
|
if ((m_dragStartPos - pos).manhattanLength() > delay)
|
|
{
|
|
if (!m_filteredTasks.first()->isActive())
|
|
{
|
|
setDown(false);
|
|
}
|
|
|
|
TaskDrag* drag = new TaskDrag(m_filteredTasks, this);
|
|
|
|
if (!m_filteredTasks.isEmpty())
|
|
{
|
|
kdDebug() << m_filteredTasks.first()->name() << endl;
|
|
drag->setPixmap(m_filteredTasks.first()->pixmap());
|
|
}
|
|
|
|
drag->dragMove();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// This is the code that gives us the proper behavior
|
|
// when a popup menu is displayed and we are clicked:
|
|
// close the menu, and don't reopen it immediately.
|
|
// It's copied from TQToolButton. Unfortunately Qt is lame
|
|
// as usual and makes interesting stuff private or
|
|
// non-virtual, so we have to copy code.
|
|
bool TaskContainer::eventFilter(TQObject *o, TQEvent *e)
|
|
{
|
|
switch ( e->type() )
|
|
{
|
|
case TQEvent::MouseButtonPress:
|
|
case TQEvent::MouseButtonDblClick:
|
|
{
|
|
TQMouseEvent *me = (TQMouseEvent*)e;
|
|
TQPoint p = me->globalPos();
|
|
if ( TQApplication::widgetAt( p, true ) == this )
|
|
{
|
|
if (me->type() == TQEvent::MouseButtonPress &&
|
|
me->button() == Qt::LeftButton)
|
|
{
|
|
m_dragStartPos = mapFromGlobal(p);
|
|
}
|
|
|
|
discardNextMouseEvent = true;
|
|
}
|
|
break;
|
|
}
|
|
case TQEvent::MouseButtonRelease:
|
|
{
|
|
m_dragStartPos = TQPoint();
|
|
break;
|
|
}
|
|
case TQEvent::MouseMove:
|
|
{
|
|
if (!m_dragStartPos.isNull())
|
|
{
|
|
TQMouseEvent* me = TQT_TQMOUSEEVENT(e);
|
|
TQPoint p(me->globalPos());
|
|
|
|
if (me->state() & Qt::LeftButton &&
|
|
TQApplication::widgetAt(p, true) == this)
|
|
{
|
|
kdDebug() << "event move" << endl;
|
|
if (startDrag(mapFromGlobal(p)))
|
|
{
|
|
TQPopupMenu* menu = dynamic_cast<TQPopupMenu*>(o);
|
|
|
|
if (menu)
|
|
{
|
|
menu->hide();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return TQToolButton::eventFilter( o, e );
|
|
}
|
|
|
|
void TaskContainer::setArrowType( TQt::ArrowType at )
|
|
{
|
|
if (arrowType == at)
|
|
{
|
|
return;
|
|
}
|
|
|
|
arrowType = at;
|
|
update();
|
|
}
|
|
|
|
void TaskContainer::publishIconGeometry( TQPoint global )
|
|
{
|
|
TQPoint p = global + geometry().topLeft();
|
|
|
|
Task::List::const_iterator itEnd = tasks.constEnd();
|
|
for (Task::List::const_iterator it = tasks.constBegin(); it != itEnd; ++it)
|
|
{
|
|
Task::Ptr t = *it;
|
|
t->publishIconGeometry(TQRect(p.x(), p.y(), width(), height()));
|
|
}
|
|
}
|
|
|
|
void TaskContainer::dragEnterEvent( TQDragEnterEvent* e )
|
|
{
|
|
// ignore task drags and applet drags
|
|
if (TaskDrag::canDecode(e) || PanelDrag::canDecode(e))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// if a dragitem is held for over a taskbutton for two seconds,
|
|
// activate corresponding window
|
|
if (m_filteredTasks.isEmpty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!m_filteredTasks.first()->isActive() ||
|
|
m_filteredTasks.count() > 1)
|
|
{
|
|
dragSwitchTimer.start(1000, true);
|
|
}
|
|
|
|
TQToolButton::dragEnterEvent( e );
|
|
}
|
|
|
|
void TaskContainer::dragLeaveEvent( TQDragLeaveEvent* e )
|
|
{
|
|
dragSwitchTimer.stop();
|
|
|
|
TQToolButton::dragLeaveEvent( e );
|
|
}
|
|
|
|
void TaskContainer::enterEvent(TQEvent* e)
|
|
{
|
|
TQToolTip::remove(this);
|
|
m_mouseOver = true;
|
|
updateNow();
|
|
|
|
if (tasks.isEmpty())
|
|
{
|
|
TQToolButton::enterEvent(e);
|
|
return;
|
|
}
|
|
|
|
if (!KickerSettings::showMouseOverEffects())
|
|
{
|
|
TQString tooltip = "<qt>" + TQStyleSheet::escape(name()) + "</qt>";
|
|
TQToolTip::add(this, tooltip);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void TaskContainer::leaveEvent(TQEvent*)
|
|
{
|
|
m_mouseOver = false;
|
|
updateNow();
|
|
}
|
|
|
|
void TaskContainer::dragSwitch()
|
|
{
|
|
if (m_filteredTasks.isEmpty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (m_filteredTasks.count() == 1)
|
|
{
|
|
m_filteredTasks.first()->activate();
|
|
}
|
|
else
|
|
{
|
|
popupMenu(TaskBarSettings::ShowTaskList);
|
|
}
|
|
}
|
|
|
|
int TaskContainer::desktop()
|
|
{
|
|
if ( tasks.isEmpty() )
|
|
return TaskManager::the()->currentDesktop();
|
|
|
|
if ( tasks.count() > 1 )
|
|
return TaskManager::the()->numberOfDesktops();
|
|
|
|
return tasks.first()->desktop();
|
|
}
|
|
|
|
bool TaskContainer::onCurrentDesktop()
|
|
{
|
|
if (m_startup)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
Task::List::const_iterator itEnd = tasks.constEnd();
|
|
for (Task::List::const_iterator it = tasks.constBegin(); it != itEnd; ++it)
|
|
{
|
|
Task::Ptr t = *it;
|
|
if (t->isOnCurrentDesktop())
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool TaskContainer::isOnScreen()
|
|
{
|
|
if (isEmpty())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int screen = taskBar->showScreen();
|
|
if ((tasks.isEmpty() && m_startup) || screen == -1)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
Task::List::iterator itEnd = tasks.end();
|
|
for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
|
|
{
|
|
if ((*it)->isOnScreen( screen ))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool TaskContainer::isIconified()
|
|
{
|
|
if (isEmpty())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (tasks.isEmpty() && m_startup)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
Task::List::const_iterator itEnd = tasks.constEnd();
|
|
for (Task::List::const_iterator it = tasks.constBegin(); it != itEnd; ++it)
|
|
{
|
|
if ((*it)->isIconified())
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void TaskContainer::updateFilteredTaskList()
|
|
{
|
|
m_filteredTasks.clear();
|
|
|
|
Task::List::const_iterator itEnd = tasks.constEnd();
|
|
for (Task::List::const_iterator it = tasks.constBegin(); it != itEnd; ++it)
|
|
{
|
|
Task::Ptr t = *it;
|
|
if ((taskBar->showAllWindows() || t->isOnCurrentDesktop()) &&
|
|
(!TaskBarSettings::showOnlyIconified() || t->isIconified()))
|
|
{
|
|
m_filteredTasks.append(t);
|
|
}
|
|
else
|
|
{
|
|
t->publishIconGeometry( TQRect());
|
|
}
|
|
}
|
|
|
|
// sort container list by desktop
|
|
if (taskBar->sortByDesktop() && m_filteredTasks.count() > 1)
|
|
{
|
|
TQValueVector<QPair<int, Task::Ptr> > sorted;
|
|
sorted.resize(m_filteredTasks.count());
|
|
int i = 0;
|
|
|
|
Task::List::const_iterator itEnd = m_filteredTasks.constEnd();
|
|
for (Task::List::const_iterator it = m_filteredTasks.constBegin(); it != itEnd; ++it)
|
|
{
|
|
Task::Ptr t = *it;
|
|
sorted[i] = (qMakePair(t->desktop(), t));
|
|
++i;
|
|
}
|
|
|
|
qHeapSort(sorted);
|
|
|
|
m_filteredTasks.clear();
|
|
for (TQValueVector<QPair<int, Task::Ptr> >::iterator it = sorted.begin();
|
|
it != sorted.end();
|
|
++it)
|
|
{
|
|
m_filteredTasks.append((*it).second);
|
|
}
|
|
}
|
|
}
|
|
|
|
void TaskContainer::desktopChanged(int)
|
|
{
|
|
updateFilteredTaskList();
|
|
KickerTip::Client::updateKickerTip();
|
|
update();
|
|
}
|
|
|
|
void TaskContainer::windowChanged(Task::Ptr)
|
|
{
|
|
updateFilteredTaskList();
|
|
KickerTip::Client::updateKickerTip();
|
|
update();
|
|
}
|
|
|
|
void TaskContainer::settingsChanged()
|
|
{
|
|
updateFilteredTaskList();
|
|
KickerTip::Client::updateKickerTip();
|
|
update();
|
|
}
|
|
|
|
void TaskContainer::updateKickerTip(KickerTip::Data& data)
|
|
{
|
|
if (m_startup)
|
|
{
|
|
data.message = m_startup->text();
|
|
data.duration = 4000;
|
|
data.subtext = i18n("Loading application ...");
|
|
data.icon = KGlobal::iconLoader()->loadIcon(m_startup->icon(),
|
|
KIcon::Small,
|
|
KIcon::SizeMedium,
|
|
KIcon::DefaultState,
|
|
0, true);
|
|
return;
|
|
}
|
|
|
|
TQPixmap pixmap;
|
|
TQString name;
|
|
TQString details;
|
|
|
|
if (m_filteredTasks.count() > 0)
|
|
{
|
|
if (TaskBarSettings::showThumbnails() &&
|
|
m_filteredTasks.count() == 1)
|
|
{
|
|
Task::Ptr t = m_filteredTasks.first();
|
|
|
|
pixmap = t->thumbnail(TaskBarSettings::thumbnailMaxDimension());
|
|
}
|
|
|
|
if (pixmap.isNull() && tasks.count())
|
|
{
|
|
// try to load icon via net_wm
|
|
pixmap = KWin::icon(tasks.last()->window(),
|
|
KIcon::SizeMedium,
|
|
KIcon::SizeMedium,
|
|
true);
|
|
}
|
|
|
|
// Collect all desktops the tasks are on. Sort naturally.
|
|
TQMap<int, TQString> desktopMap;
|
|
bool demandsAttention = false;
|
|
bool modified = false;
|
|
bool allDesktops = false;
|
|
Task::List::const_iterator itEnd = m_filteredTasks.constEnd();
|
|
for (Task::List::const_iterator it = m_filteredTasks.constBegin(); it != itEnd; ++it)
|
|
{
|
|
Task::Ptr t = *it;
|
|
if (t->demandsAttention())
|
|
{
|
|
demandsAttention = true;
|
|
}
|
|
|
|
if (t->isModified())
|
|
{
|
|
modified = true;
|
|
}
|
|
|
|
if (t->isOnAllDesktops())
|
|
{
|
|
allDesktops = true;
|
|
desktopMap.clear();
|
|
}
|
|
else if (!allDesktops)
|
|
{
|
|
desktopMap.insert(t->desktop(),
|
|
TaskManager::the()->desktopName(t->desktop()));
|
|
}
|
|
}
|
|
|
|
if (TaskBarSettings::showAllWindows() && KWin::numberOfDesktops() > 1)
|
|
{
|
|
if (desktopMap.isEmpty())
|
|
{
|
|
details.append(i18n("On all desktops"));
|
|
}
|
|
else
|
|
{
|
|
TQStringList desktopNames = desktopMap.values();
|
|
details.append(i18n("On %1").arg(TQStyleSheet::escape(desktopNames.join(", "))) + "<br>");
|
|
}
|
|
}
|
|
|
|
if (demandsAttention)
|
|
{
|
|
details.append(i18n("Requesting attention") + "<br>");
|
|
}
|
|
|
|
name = this->name();
|
|
if (modified)
|
|
{
|
|
details.append(i18n("Has unsaved changes"));
|
|
|
|
static TQString modStr = "[" + i18n( "modified" ) + "]";
|
|
int modStrPos = name.find(modStr);
|
|
|
|
if (modStrPos >= 0)
|
|
{
|
|
// +1 because we include a space after the closing brace.
|
|
name.remove(modStrPos, modStr.length() + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
data.message = TQStyleSheet::escape(name);
|
|
data.subtext = details;
|
|
data.icon = pixmap;
|
|
data.direction = KickerLib::arrowToDirection(arrowType);
|
|
}
|
|
|
|
void TaskContainer::finish()
|
|
{
|
|
// Disconnect all signal/slot connections to avoid triggering a popupMenu() call,
|
|
// whose event loop is the root of all (or at least much) evil.
|
|
// Unfortunately, we can't just do "disconnect()", because that gets us a bunch
|
|
// of dangling TQGuardedPtr objects (most notably in QTipManager.) (kling)
|
|
|
|
animationTimer.disconnect();
|
|
dragSwitchTimer.disconnect();
|
|
attentionTimer.disconnect();
|
|
|
|
if (m_startup)
|
|
m_startup->disconnect(this);
|
|
|
|
for (Task::List::Iterator it = tasks.begin(); it != tasks.end(); ++it)
|
|
{
|
|
(*it)->disconnect(this);
|
|
}
|
|
|
|
if (m_menu)
|
|
m_menu->close();
|
|
}
|