Contents of /branches/KDE/3.5/kdebase/kicker/taskbar/taskbar.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 604546 - (show annotations) (download) (as text)
Mon Nov 13 07:35:56 2006 UTC (11 years, 2 months ago) by aseigo
File MIME type: text/x-c++src
File size: 32605 byte(s)
backport fix for potential modulo|div-by-zero bug by  
Rafael Fernández López

1 /*****************************************************************
2
3 Copyright (c) 2001 Matthias Elter <elter@kde.org>
4 Copyright (c) 2004 Sebastian Wolff
5 Copyright (c) 2005 Aaron Seigo <aseigo@kde.org>
6
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24 ******************************************************************/
25
26 #include <math.h>
27
28 #include <qapplication.h>
29 #include <qbitmap.h>
30 #include <qdesktopwidget.h>
31 #include <qlayout.h>
32 #include <qpainter.h>
33 #include <qstringlist.h>
34
35 #include <dcopclient.h>
36 #include <kapplication.h>
37 #include <kdebug.h>
38 #include <kglobal.h>
39 #include <kglobalaccel.h>
40 #include <kimageeffect.h>
41 #include <klocale.h>
42 #include <kstandarddirs.h>
43
44 #include "kshadowengine.h"
45 #include "kshadowsettings.h"
46 #include "kickerSettings.h"
47 #include "taskbarsettings.h"
48 #include "taskcontainer.h"
49 #include "taskmanager.h"
50
51 #include "taskbar.h"
52 #include "taskbar.moc"
53
54
55 TaskBar::TaskBar( QWidget *parent, const char *name )
56 : Panner( parent, name ),
57 m_showAllWindows(false),
58 m_currentScreen(-1),
59 m_showOnlyCurrentScreen(false),
60 m_sortByDesktop(false),
61 m_showIcon(false),
62 m_showOnlyIconified(false),
63 m_textShadowEngine(0),
64 m_ignoreUpdates(false)
65 {
66 setBackgroundOrigin( AncestorOrigin );
67
68 setFrameStyle( NoFrame );
69
70 arrowType = LeftArrow;
71 blocklayout = true;
72
73 // init
74 setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) );
75
76 // setup animation frames
77 for (int i = 1; i < 11; i++)
78 {
79 frames.append(new QPixmap(locate("data", "kicker/pics/disk" + QString::number(i) + ".png")));
80 }
81
82 // configure
83 configure();
84
85 connect(&m_relayoutTimer, SIGNAL(timeout()),
86 this, SLOT(reLayout()));
87
88 // connect manager
89 connect(TaskManager::the(), SIGNAL(taskAdded(Task::Ptr)),
90 this, SLOT(add(Task::Ptr)));
91 connect(TaskManager::the(), SIGNAL(taskRemoved(Task::Ptr)),
92 this, SLOT(remove(Task::Ptr)));
93 connect(TaskManager::the(), SIGNAL(startupAdded(Startup::Ptr)),
94 this, SLOT(add(Startup::Ptr)));
95 connect(TaskManager::the(), SIGNAL(startupRemoved(Startup::Ptr)),
96 this, SLOT(remove(Startup::Ptr)));
97 connect(TaskManager::the(), SIGNAL(desktopChanged(int)),
98 this, SLOT(desktopChanged(int)));
99 connect(TaskManager::the(), SIGNAL(windowChanged(Task::Ptr)),
100 this, SLOT(windowChanged(Task::Ptr)));
101
102 isGrouping = shouldGroup();
103
104 // register existant tasks
105 Task::Dict tasks = TaskManager::the()->tasks();
106 Task::Dict::iterator taskEnd = tasks.end();
107 for (Task::Dict::iterator it = tasks.begin(); it != taskEnd; ++it)
108 {
109 add(it.data());
110 }
111
112 // register existant startups
113 Startup::List startups = TaskManager::the()->startups();
114 Startup::List::iterator startupEnd = startups.end();
115 for (Startup::List::iterator sIt = startups.begin(); sIt != startupEnd; ++sIt)
116 {
117 add((*sIt));
118 }
119
120 blocklayout = false;
121
122 connect(kapp, SIGNAL(settingsChanged(int)), SLOT(slotSettingsChanged(int)));
123 keys = new KGlobalAccel( this );
124 #include "taskbarbindings.cpp"
125 keys->readSettings();
126 keys->updateConnections();
127
128 reLayout();
129 }
130
131 TaskBar::~TaskBar()
132 {
133 for (TaskContainer::Iterator it = m_hiddenContainers.begin();
134 it != m_hiddenContainers.end();
135 ++it)
136 {
137 (*it)->deleteLater();
138 }
139
140 for (TaskContainer::List::const_iterator it = containers.constBegin();
141 it != containers.constEnd();
142 ++it)
143 {
144 (*it)->deleteLater();
145 }
146
147 for (PixmapList::const_iterator it = frames.constBegin();
148 it != frames.constEnd();
149 ++it)
150 {
151 delete *it;
152 }
153
154 delete m_textShadowEngine;
155 m_textShadowEngine = 0;
156 }
157
158 QSize TaskBar::sizeHint() const
159 {
160 // get our minimum height based on the minimum button height or the
161 // height of the font in use, which is largest
162 QFontMetrics fm(KGlobalSettings::taskbarFont());
163 int minButtonHeight = fm.height() > TaskBarSettings::minimumButtonHeight() ?
164 fm.height() : TaskBarSettings::minimumButtonHeight();
165
166 return QSize(BUTTON_MIN_WIDTH, minButtonHeight);
167 }
168
169 QSize TaskBar::sizeHint( KPanelExtension::Position p, QSize maxSize) const
170 {
171 // get our minimum height based on the minimum button height or the
172 // height of the font in use, which is largest
173 QFontMetrics fm(KGlobalSettings::taskbarFont());
174 int minButtonHeight = fm.height() > TaskBarSettings::minimumButtonHeight() ?
175 fm.height() : TaskBarSettings::minimumButtonHeight();
176
177 if ( p == KPanelExtension::Left || p == KPanelExtension::Right )
178 {
179 int actualMax = minButtonHeight * containerCount();
180
181 if (containerCount() == 0)
182 {
183 actualMax = minButtonHeight;
184 }
185
186 if (actualMax > maxSize.height())
187 {
188 return maxSize;
189 }
190 return QSize( maxSize.width(), actualMax );
191 }
192 else
193 {
194 int rows = KickerSettings::conserveSpace() ?
195 contentsRect().height() / minButtonHeight :
196 1;
197 if ( rows < 1 )
198 {
199 rows = 1;
200 }
201
202 int maxWidth = TaskBarSettings::maximumButtonWidth();
203 if (maxWidth == 0)
204 {
205 maxWidth = BUTTON_MAX_WIDTH;
206 }
207
208 int actualMax = maxWidth * (containerCount() / rows);
209
210 if (containerCount() % rows > 0)
211 {
212 actualMax += maxWidth;
213 }
214 if (containerCount() == 0)
215 {
216 actualMax = maxWidth;
217 }
218
219 if (actualMax > maxSize.width())
220 {
221 return maxSize;
222 }
223 return QSize( actualMax, maxSize.height() );
224 }
225 }
226
227 void TaskBar::configure()
228 {
229 bool wasShowWindows = m_showAllWindows;
230 bool wasSortByDesktop = m_sortByDesktop;
231 bool wasShowIcon = m_showIcon;
232 bool wasShowOnlyIconified = m_showOnlyIconified;
233
234 m_showAllWindows = TaskBarSettings::showAllWindows();
235 m_sortByDesktop = m_showAllWindows && TaskBarSettings::sortByDesktop();
236 m_showIcon = TaskBarSettings::showIcon();
237 m_showOnlyIconified = TaskBarSettings::showOnlyIconified();
238
239 m_currentScreen = -1; // Show all screens or re-get our screen
240 m_showOnlyCurrentScreen = TaskBarSettings::showCurrentScreenOnly() &&
241 QApplication::desktop()->isVirtualDesktop() &&
242 QApplication::desktop()->numScreens() > 1;
243
244 // we need to watch geometry issues if we aren't showing windows when we
245 // are paying attention to the current Xinerama screen
246 if (m_showOnlyCurrentScreen)
247 {
248 // disconnect first in case we've been here before
249 // to avoid multiple connections
250 disconnect(TaskManager::the(), SIGNAL(windowChangedGeometry(Task::Ptr)),
251 this, SLOT(windowChangedGeometry(Task::Ptr)));
252 connect(TaskManager::the(), SIGNAL(windowChangedGeometry(Task::Ptr)),
253 this, SLOT(windowChangedGeometry(Task::Ptr)));
254 }
255 TaskManager::the()->trackGeometry(m_showOnlyCurrentScreen);
256
257 if (wasShowWindows != m_showAllWindows ||
258 wasSortByDesktop != m_sortByDesktop ||
259 wasShowIcon != m_showIcon ||
260 wasShowOnlyIconified != m_showOnlyIconified)
261 {
262 // relevant settings changed, update our task containers
263 for (TaskContainer::Iterator it = containers.begin();
264 it != containers.end();
265 ++it)
266 {
267 (*it)->settingsChanged();
268 }
269 }
270
271 TaskManager::the()->setXCompositeEnabled(TaskBarSettings::showThumbnails());
272
273 reLayoutEventually();
274 }
275
276 void TaskBar::setOrientation( Orientation o )
277 {
278 Panner::setOrientation( o );
279 reLayoutEventually();
280 }
281
282 void TaskBar::resizeEvent( QResizeEvent* e )
283 {
284 if (m_showOnlyCurrentScreen)
285 {
286 QPoint topLeft = mapToGlobal(this->geometry().topLeft());
287 if (m_currentScreen != QApplication::desktop()->screenNumber(topLeft))
288 {
289 // we have been moved to another screen!
290 m_currentScreen = -1;
291 reGroup();
292 }
293 }
294
295 Panner::resizeEvent(e);
296 reLayoutEventually();
297 }
298
299 void TaskBar::add(Task::Ptr task)
300 {
301 if (!task ||
302 (m_showOnlyCurrentScreen &&
303 !TaskManager::isOnScreen(showScreen(), task->window())))
304 {
305 return;
306 }
307
308 // try to group
309 if (isGrouping)
310 {
311 for (TaskContainer::Iterator it = containers.begin();
312 it != containers.end();
313 ++it)
314 {
315 TaskContainer* c = *it;
316
317 if (idMatch(task->classClass(), c->id()))
318 {
319 c->add(task);
320 reLayoutEventually();
321 return;
322 }
323 }
324 }
325
326 // create new container
327 TaskContainer *container = new TaskContainer(task, this, viewport());
328 m_hiddenContainers.append(container);
329
330 // even though there is a signal to listen to, we have to add this
331 // immediately to ensure grouping doesn't break (primarily on startup)
332 // we still add the container to m_hiddenContainers in case the event
333 // loop gets re-entered here and something bizarre happens. call it
334 // insurance =)
335 showTaskContainer(container);
336 }
337
338 void TaskBar::add(Startup::Ptr startup)
339 {
340 if (!startup)
341 {
342 return;
343 }
344
345 for (TaskContainer::Iterator it = containers.begin();
346 it != containers.end();
347 ++it)
348 {
349 if ((*it)->contains(startup))
350 {
351 return;
352 }
353 }
354
355 // create new container
356 TaskContainer *container = new TaskContainer(startup, frames, this, viewport());
357 m_hiddenContainers.append(container);
358 connect(container, SIGNAL(showMe(TaskContainer*)), this, SLOT(showTaskContainer(TaskContainer*)));
359 }
360
361 void TaskBar::showTaskContainer(TaskContainer* container)
362 {
363 TaskContainer::List::iterator it = m_hiddenContainers.find(container);
364 if (it != m_hiddenContainers.end())
365 {
366 m_hiddenContainers.erase(it);
367 }
368
369 if (container->isEmpty())
370 {
371 return;
372 }
373
374 // try to place the container after one of the same app
375 if (TaskBarSettings::sortByApp())
376 {
377 TaskContainer::Iterator it = containers.begin();
378 for (; it != containers.end(); ++it)
379 {
380 TaskContainer* c = *it;
381
382 if (container->id().lower() == c->id().lower())
383 {
384 // search for the last occurrence of this app
385 for (; it != containers.end(); ++it)
386 {
387 c = *it;
388
389 if (container->id().lower() != c->id().lower())
390 {
391 break;
392 }
393 }
394 break;
395 }
396 }
397
398 if (it != containers.end())
399 {
400 containers.insert(it, container);
401 }
402 else
403 {
404 containers.append(container);
405 }
406 }
407 else
408 {
409 containers.append(container);
410 }
411
412 addChild(container);
413 reLayoutEventually();
414 emit containerCountChanged();
415 }
416
417 void TaskBar::remove(Task::Ptr task, TaskContainer* container)
418 {
419 for (TaskContainer::Iterator it = m_hiddenContainers.begin();
420 it != m_hiddenContainers.end();
421 ++it)
422 {
423 if ((*it)->contains(task))
424 {
425 (*it)->finish();
426 m_deletableContainers.append(*it);
427 m_hiddenContainers.erase(it);
428 break;
429 }
430 }
431
432 if (!container)
433 {
434 for (TaskContainer::Iterator it = containers.begin();
435 it != containers.end();
436 ++it)
437 {
438 if ((*it)->contains(task))
439 {
440 container = *it;
441 break;
442 }
443 }
444
445 if (!container)
446 {
447 return;
448 }
449 }
450
451 container->remove(task);
452
453 if (container->isEmpty())
454 {
455 TaskContainer::List::iterator it = containers.find(container);
456 if (it != containers.end())
457 {
458 containers.erase(it);
459 }
460
461 removeChild(container);
462 container->finish();
463 m_deletableContainers.append(container);
464
465 reLayoutEventually();
466 emit containerCountChanged();
467 }
468 else if (container->filteredTaskCount() < 1)
469 {
470 reLayoutEventually();
471 emit containerCountChanged();
472 }
473 }
474
475 void TaskBar::remove(Startup::Ptr startup, TaskContainer* container)
476 {
477 for (TaskContainer::Iterator it = m_hiddenContainers.begin();
478 it != m_hiddenContainers.end();
479 ++it)
480 {
481 if ((*it)->contains(startup))
482 {
483 (*it)->remove(startup);
484
485 if ((*it)->isEmpty())
486 {
487 (*it)->finish();
488 m_deletableContainers.append(*it);
489 m_hiddenContainers.erase(it);
490 }
491
492 break;
493 }
494 }
495
496 if (!container)
497 {
498 for (TaskContainer::Iterator it = containers.begin();
499 it != containers.end();
500 ++it)
501 {
502 if ((*it)->contains(startup))
503 {
504 container = *it;
505 break;
506 }
507 }
508
509 if (!container)
510 {
511 return;
512 }
513 }
514
515 container->remove(startup);
516 if (!container->isEmpty())
517 {
518 return;
519 }
520
521 TaskContainer::List::iterator it = containers.find(container);
522 if (it != containers.end())
523 {
524 containers.erase(it);
525 }
526
527 // startup containers only ever contain that one item. so
528 // just delete the poor bastard.
529 container->finish();
530 m_deletableContainers.append(container);
531 reLayoutEventually();
532 emit containerCountChanged();
533 }
534
535 void TaskBar::desktopChanged(int desktop)
536 {
537 if (m_showAllWindows)
538 {
539 return;
540 }
541
542 m_relayoutTimer.stop();
543 m_ignoreUpdates = true;
544 for (TaskContainer::Iterator it = containers.begin();
545 it != containers.end();
546 ++it)
547 {
548 (*it)->desktopChanged(desktop);
549 }
550
551 m_ignoreUpdates = false;
552 reLayout();
553 emit containerCountChanged();
554 }
555
556 void TaskBar::windowChanged(Task::Ptr task)
557 {
558 if (m_showOnlyCurrentScreen &&
559 !TaskManager::isOnScreen(showScreen(), task->window()))
560 {
561 return; // we don't care about this window
562 }
563
564 TaskContainer* container = 0;
565 for (TaskContainer::List::const_iterator it = containers.constBegin();
566 it != containers.constEnd();
567 ++it)
568 {
569 TaskContainer* c = *it;
570
571 if (c->contains(task))
572 {
573 container = c;
574 break;
575 }
576 }
577
578 // if we don't have a container or we're showing only windows on this
579 // desktop and the container is neither on the desktop nor currently visible
580 // just skip it
581 if (!container ||
582 (!m_showAllWindows &&
583 !container->onCurrentDesktop() &&
584 !container->isVisibleTo(this)))
585 {
586 return;
587 }
588
589 container->windowChanged(task);
590
591 if (!m_showAllWindows || m_showOnlyIconified)
592 {
593 emit containerCountChanged();
594 }
595
596 reLayoutEventually();
597 }
598
599 void TaskBar::windowChangedGeometry(Task::Ptr task)
600 {
601 //TODO: this gets called every time a window's geom changes
602 // when we are in "show only on the same Xinerama screen"
603 // mode it would be Good(tm) to compress these events so this
604 // gets run less often, but always when needed
605 TaskContainer* container = 0;
606 for (TaskContainer::Iterator it = containers.begin();
607 it != containers.end();
608 ++it)
609 {
610 TaskContainer* c = *it;
611 if (c->contains(task))
612 {
613 container = c;
614 break;
615 }
616 }
617
618 if ((!!container) == TaskManager::isOnScreen(showScreen(), task->window()))
619 {
620 // we have this window covered, so we don't need to do anything
621 return;
622 }
623
624 if (container)
625 {
626 remove(task, container);
627 }
628 else
629 {
630 add(task);
631 }
632 }
633
634 void TaskBar::reLayoutEventually()
635 {
636 m_relayoutTimer.stop();
637
638 if (!blocklayout && !m_ignoreUpdates)
639 {
640 m_relayoutTimer.start(100, true);
641 }
642 }
643
644 void TaskBar::reLayout()
645 {
646 // Because QPopupMenu::exec() creates its own event loop, deferred deletes
647 // via QObject::deleteLater() may be prematurely executed when a container's
648 // popup menu is visible.
649 //
650 // To get around this, we collect the containers and delete them manually
651 // when doing a relayout. (kling)
652 if (!m_deletableContainers.isEmpty()) {
653 TaskContainer::List::iterator it = m_deletableContainers.begin();
654 for (; it != m_deletableContainers.end(); ++it)
655 delete *it;
656 m_deletableContainers.clear();
657 }
658
659 // filter task container list
660 TaskContainer::List list = filteredContainers();
661
662 if (list.count() < 1)
663 {
664 resizeContents(contentsRect().width(), contentsRect().height());
665 return;
666 }
667
668 if (isGrouping != shouldGroup())
669 {
670 reGroup();
671 return;
672 }
673
674 // sort container list by desktop
675 if (m_sortByDesktop)
676 {
677 sortContainersByDesktop(list);
678 }
679
680 // needed because Panner doesn't know how big it's contents are so it's
681 // up to use to initialize it. =(
682 resizeContents(contentsRect().width(), contentsRect().height());
683
684 // number of rows simply depends on our height which is either the
685 // minimum button height or the height of the font in use, whichever is
686 // largest
687 QFontMetrics fm(KGlobalSettings::taskbarFont());
688 int minButtonHeight = fm.height() > TaskBarSettings::minimumButtonHeight() ?
689 fm.height() : TaskBarSettings::minimumButtonHeight();
690
691 // horizontal layout
692 if (orientation() == Horizontal)
693 {
694 int bwidth = BUTTON_MIN_WIDTH;
695 int rows = contentsRect().height() / minButtonHeight;
696
697 if ( rows < 1 )
698 {
699 rows = 1;
700 }
701
702 // actual button height
703 int bheight = contentsRect().height() / rows;
704
705 // avoid zero devision later
706 if (bheight < 1)
707 {
708 bheight = 1;
709 }
710
711 // buttons per row
712 int bpr = (int)ceil( (double)list.count() / rows);
713
714 // adjust content size
715 if ( contentsRect().width() < bpr * BUTTON_MIN_WIDTH )
716 {
717 resizeContents( bpr * BUTTON_MIN_WIDTH, contentsRect().height() );
718 }
719
720 // maximum number of buttons per row
721 int mbpr = contentsRect().width() / BUTTON_MIN_WIDTH;
722
723 // expand button width if space permits
724 if (mbpr > bpr)
725 {
726 bwidth = contentsRect().width() / bpr;
727 int maxWidth = TaskBarSettings::maximumButtonWidth();
728 if (maxWidth > 0 && bwidth > maxWidth)
729 {
730 bwidth = maxWidth;
731 }
732 }
733
734 // layout containers
735
736 // for taskbars at the bottom, we need to ensure that the bottom
737 // buttons touch the bottom of the screen. since we layout from
738 // top to bottom this means seeing if we have any padding and
739 // popping it on the top. this preserves Fitt's Law behaviour
740 // for taskbars on the bottom
741 int topPadding = 0;
742 if (arrowType == UpArrow)
743 {
744 topPadding = contentsRect().height() % (rows * bheight);
745 }
746
747 int i = 0;
748 bool reverseLayout = QApplication::reverseLayout();
749 for (TaskContainer::Iterator it = list.begin();
750 it != list.end();
751 ++it, i++)
752 {
753 TaskContainer* c = *it;
754
755 int row = i % rows;
756
757 c->setArrowType(arrowType);
758 c->resize( bwidth, bheight );
759 c->show();
760
761 int x = ( i / rows ) * bwidth;
762 if (reverseLayout)
763 {
764 x = contentsRect().width() - x - bwidth;
765 }
766
767 moveChild(c, x, (row * bheight) + topPadding);
768 c->update();
769 }
770 }
771 else // vertical layout
772 {
773 // adjust content size
774 if (contentsRect().height() < (int)list.count() * minButtonHeight)
775 {
776 resizeContents(contentsRect().width(), list.count() * minButtonHeight);
777 }
778
779 // layout containers
780 int i = 0;
781 for (TaskContainer::Iterator it = list.begin();
782 it != list.end();
783 ++it)
784 {
785 TaskContainer* c = *it;
786
787 c->setArrowType(arrowType);
788 c->resize(contentsRect().width(), minButtonHeight);
789 c->show();
790
791 moveChild(c, 0, i * minButtonHeight);
792 i++;
793 c->update();
794 }
795 }
796
797 QTimer::singleShot(100, this, SLOT(publishIconGeometry()));
798 }
799
800 void TaskBar::setArrowType(Qt::ArrowType at)
801 {
802 if (arrowType == at)
803 {
804 return;
805 }
806
807 arrowType = at;
808 for (TaskContainer::Iterator it = containers.begin();
809 it != containers.end();
810 ++it)
811 {
812 (*it)->setArrowType(arrowType);
813 }
814 }
815
816 void TaskBar::publishIconGeometry()
817 {
818 QPoint p = mapToGlobal(QPoint(0,0)); // roundtrip, don't do that too often
819
820 for (TaskContainer::Iterator it = containers.begin();
821 it != containers.end();
822 ++it)
823 {
824 (*it)->publishIconGeometry(p);
825 }
826 }
827
828 void TaskBar::viewportMousePressEvent( QMouseEvent* e )
829 {
830 propagateMouseEvent( e );
831 }
832
833 void TaskBar::viewportMouseReleaseEvent( QMouseEvent* e )
834 {
835 propagateMouseEvent( e );
836 }
837
838 void TaskBar::viewportMouseDoubleClickEvent( QMouseEvent* e )
839 {
840 propagateMouseEvent( e );
841 }
842
843 void TaskBar::viewportMouseMoveEvent( QMouseEvent* e )
844 {
845 propagateMouseEvent( e );
846 }
847
848 void TaskBar::propagateMouseEvent( QMouseEvent* e )
849 {
850 if ( !isTopLevel() )
851 {
852 QMouseEvent me( e->type(), mapTo( topLevelWidget(), e->pos() ),
853 e->globalPos(), e->button(), e->state() );
854 QApplication::sendEvent( topLevelWidget(), &me );
855 }
856 }
857
858 bool TaskBar::idMatch( const QString& id1, const QString& id2 )
859 {
860 if ( id1.isEmpty() || id2.isEmpty() )
861 return false;
862
863 return id1.lower() == id2.lower();
864 }
865
866 int TaskBar::containerCount() const
867 {
868 int i = 0;
869
870 for (TaskContainer::List::const_iterator it = containers.constBegin();
871 it != containers.constEnd();
872 ++it)
873 {
874 if ((m_showAllWindows || (*it)->onCurrentDesktop()) &&
875 ((showScreen() == -1) || ((*it)->isOnScreen())))
876 {
877 i++;
878 }
879 }
880
881 return i;
882 }
883
884 int TaskBar::taskCount() const
885 {
886 int i = 0;
887
888 for (TaskContainer::List::const_iterator it = containers.constBegin();
889 it != containers.constEnd();
890 ++it)
891 {
892 if ((m_showAllWindows || (*it)->onCurrentDesktop()) &&
893 ((showScreen() == -1) || ((*it)->isOnScreen())))
894 {
895 i += (*it)->filteredTaskCount();
896 }
897 }
898
899 return i;
900 }
901
902 int TaskBar::maximumButtonsWithoutShrinking() const
903 {
904 QFontMetrics fm(KGlobalSettings::taskbarFont());
905 int minButtonHeight = fm.height() > TaskBarSettings::minimumButtonHeight() ?
906 fm.height() : TaskBarSettings::minimumButtonHeight();
907 int rows = contentsRect().height() / minButtonHeight;
908
909 if (rows < 1)
910 {
911 rows = 1;
912 }
913
914 if ( orientation() == Horizontal ) {
915 // maxWidth of 0 means no max width, drop back to default
916 int maxWidth = TaskBarSettings::maximumButtonWidth();
917 if (maxWidth == 0)
918 {
919 maxWidth = BUTTON_MAX_WIDTH;
920 }
921
922 // They squash a bit before they pop, hence the 2
923 return rows * (contentsRect().width() / maxWidth) + 2;
924 }
925 else
926 {
927 // Overlap slightly and ugly arrows appear, hence -1
928 return rows - 1;
929 }
930 }
931
932 bool TaskBar::shouldGroup() const
933 {
934 return TaskBarSettings::groupTasks() == TaskBarSettings::GroupAlways ||
935 (TaskBarSettings::groupTasks() == TaskBarSettings::GroupWhenFull &&
936 taskCount() > maximumButtonsWithoutShrinking());
937 }
938
939 void TaskBar::reGroup()
940 {
941 isGrouping = shouldGroup();
942 blocklayout = true;
943
944 TaskContainer::Iterator lastContainer = m_hiddenContainers.end();
945 for (TaskContainer::Iterator it = m_hiddenContainers.begin();
946 it != lastContainer;
947 ++it)
948 {
949 (*it)->finish();
950 m_deletableContainers.append(*it);
951 }
952 m_hiddenContainers.clear();
953
954 for (TaskContainer::List::const_iterator it = containers.constBegin();
955 it != containers.constEnd();
956 ++it)
957 {
958 (*it)->finish();
959 m_deletableContainers.append(*it);
960 }
961 containers.clear();
962
963 Task::Dict tasks = TaskManager::the()->tasks();
964 Task::Dict::iterator lastTask = tasks.end();
965 for (Task::Dict::iterator it = tasks.begin(); it != lastTask; ++it)
966 {
967 Task::Ptr task = it.data();
968 if (showScreen() == -1 || task->isOnScreen(showScreen()))
969 {
970 add(task);
971 }
972 }
973
974 Startup::List startups = TaskManager::the()->startups();
975 Startup::List::iterator itEnd = startups.end();
976 for (Startup::List::iterator sIt = startups.begin(); sIt != itEnd; ++sIt)
977 {
978 add(*sIt);
979 }
980
981 blocklayout = false;
982 reLayoutEventually();
983 }
984
985 TaskContainer::List TaskBar::filteredContainers()
986 {
987 // filter task container list
988 TaskContainer::List list;
989
990 for (TaskContainer::List::const_iterator it = containers.constBegin();
991 it != containers.constEnd();
992 ++it)
993 {
994 TaskContainer* c = *it;
995 if ((m_showAllWindows || c->onCurrentDesktop()) &&
996 (!m_showOnlyIconified || c->isIconified()) &&
997 ((showScreen() == -1) || c->isOnScreen()))
998 {
999 list.append(c);
1000 c->show();
1001 }
1002 else
1003 {
1004 c->hide();
1005 }
1006 }
1007
1008 return list;
1009 }
1010
1011 void TaskBar::activateNextTask(bool forward)
1012 {
1013 bool forcenext = false;
1014 TaskContainer::List list = filteredContainers();
1015
1016 // this is necessary here, because 'containers' is unsorted and
1017 // we want to iterate over the _shown_ task containers in a linear way
1018 if (m_sortByDesktop)
1019 {
1020 sortContainersByDesktop(list);
1021 }
1022
1023 int numContainers = list.count();
1024 TaskContainer::List::iterator it;
1025 for (int i = 0; i < numContainers; ++i)
1026 {
1027 it = forward ? list.at(i) : list.at(numContainers - i - 1);
1028
1029 if (it != list.end() && (*it)->activateNextTask(forward, forcenext))
1030 {
1031 return;
1032 }
1033 }
1034
1035 if (forcenext)
1036 {
1037 // moving forward from the last, or backward from the first, loop around
1038 for (int i = 0; i < numContainers; ++i)
1039 {
1040 it = forward ? list.at(i) : list.at(numContainers - i - 1);
1041
1042 if (it != list.end() && (*it)->activateNextTask(forward, forcenext))
1043 {
1044 return;
1045 }
1046 }
1047
1048 return;
1049 }
1050
1051 forcenext = true; // select first
1052 for (int i = 0; i < numContainers; ++i)
1053 {
1054 it = forward ? list.at(i) : list.at(numContainers - i - 1);
1055
1056 if (it == list.end())
1057 {
1058 break;
1059 }
1060
1061 TaskContainer* c = *it;
1062 if (m_sortByDesktop)
1063 {
1064 if (forward ? c->desktop() < TaskManager::the()->currentDesktop()
1065 : c->desktop() > TaskManager::the()->currentDesktop())
1066 {
1067 continue;
1068 }
1069 }
1070
1071 if (c->activateNextTask(forward, forcenext))
1072 {
1073 return;
1074 }
1075 }
1076 }
1077
1078 void TaskBar::wheelEvent(QWheelEvent* e)
1079 {
1080 if (e->delta() > 0)
1081 {
1082 // scroll away from user, previous task
1083 activateNextTask(false);
1084 }
1085 else
1086 {
1087 // scroll towards user, next task
1088 activateNextTask(true);
1089 }
1090 }
1091
1092 void TaskBar::slotActivateNextTask()
1093 {
1094 activateNextTask( true );
1095 }
1096
1097 void TaskBar::slotActivatePreviousTask()
1098 {
1099 activateNextTask( false );
1100 }
1101
1102 void TaskBar::slotSettingsChanged( int category )
1103 {
1104 if( category == (int) KApplication::SETTINGS_SHORTCUTS )
1105 {
1106 keys->readSettings();
1107 keys->updateConnections();
1108 }
1109 }
1110
1111 int TaskBar::showScreen() const
1112 {
1113 if (m_showOnlyCurrentScreen && m_currentScreen == -1)
1114 {
1115 const_cast<TaskBar*>(this)->m_currentScreen =
1116 QApplication::desktop()->screenNumber(mapToGlobal(this->geometry().topLeft()));
1117 }
1118
1119 return m_currentScreen;
1120 }
1121
1122 // taken from mtaskbar, by Sebastian Wolff
1123 void TaskBar::drawShadowText(QPainter &p, const QRect &tr, int tf, const QString &str, const QSize &size)
1124 {
1125 // get the color of the shadow: white for dark text, black for bright text
1126 QPen textPen = p.pen();
1127 QColor shadCol = textPen.color();
1128
1129 if (shadCol.red() +
1130 shadCol.green() +
1131 shadCol.blue() <= 3*256/2-1)
1132 {
1133 shadCol = QColor(255,255,255);
1134 }
1135 else
1136 {
1137 shadCol = QColor(0,0,0);
1138 }
1139
1140 // get a transparent pixmap
1141 QPainter pixPainter;
1142 QPixmap textPixmap(size);
1143
1144 textPixmap.fill(QColor(0,0,0));
1145 textPixmap.setMask(textPixmap.createHeuristicMask(true));
1146
1147 // draw text
1148 pixPainter.begin(&textPixmap);
1149 pixPainter.setPen(white);
1150 pixPainter.setFont(p.font()); // get the font from the root painter
1151 pixPainter.drawText(tr, tf, str);
1152 pixPainter.end();
1153
1154 if (!m_textShadowEngine)
1155 {
1156 KShadowSettings * shadset = new KShadowSettings();
1157 shadset->setOffsetX(0);
1158 shadset->setOffsetY(0);
1159 shadset->setThickness(1);
1160 shadset->setMaxOpacity(96);
1161 m_textShadowEngine = new KShadowEngine(shadset);
1162 }
1163
1164 // draw shadow
1165 QImage img = m_textShadowEngine->makeShadow(textPixmap, shadCol);
1166
1167 // return
1168 p.drawImage(0, 0, img);
1169 p.drawText(tr, tf, str);
1170 }
1171
1172 QImage* TaskBar::blendGradient(const QSize& size)
1173 {
1174 if (m_blendGradient.isNull() || m_blendGradient.size() != size)
1175 {
1176 QPixmap bgpm(size);
1177 QPainter bgp(&bgpm);
1178 bgpm.fill(black);
1179
1180 if (QApplication::reverseLayout())
1181 {
1182 QImage gradient = KImageEffect::gradient(
1183 QSize(30, size.height()),
1184 QColor(255,255,255),
1185 QColor(0,0,0),
1186 KImageEffect::HorizontalGradient);
1187 bgp.drawImage(0, 0, gradient);
1188 }
1189 else
1190 {
1191 QImage gradient = KImageEffect::gradient(
1192 QSize(30, size.height()),
1193 QColor(0,0,0),
1194 QColor(255,255,255),
1195 KImageEffect::HorizontalGradient);
1196 bgp.drawImage(size.width() - 30, 0, gradient);
1197 }
1198
1199 m_blendGradient = bgpm.convertToImage();
1200 }
1201
1202 return &m_blendGradient;
1203 }
1204
1205 void TaskBar::sortContainersByDesktop(TaskContainer::List& list)
1206 {
1207 typedef QValueVector<QPair<int, QPair<int, TaskContainer*> > > SortVector;
1208 SortVector sorted;
1209 sorted.resize(list.count());
1210 int i = 0;
1211
1212 TaskContainer::List::ConstIterator lastUnsorted(list.constEnd());
1213 for (TaskContainer::List::ConstIterator it = list.constBegin();
1214 it != lastUnsorted;
1215 ++it)
1216 {
1217 sorted[i] = qMakePair((*it)->desktop(), qMakePair(i, *it));
1218 ++i;
1219 }
1220
1221 qHeapSort(sorted);
1222
1223 list.clear();
1224 SortVector::const_iterator lastSorted(sorted.constEnd());
1225 for (SortVector::const_iterator it = sorted.constBegin();
1226 it != lastSorted;
1227 ++it)
1228 {
1229 list.append((*it).second.second);
1230 }
1231 }
1232

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision
svn:mime-type text/x-c++src