22 #include "private/popupapplet_p.h"
23 #include "private/dialog_p.h"
25 #include <QApplication>
26 #include <QGraphicsProxyWidget>
27 #include <QGraphicsLinearLayout>
29 #include <QVBoxLayout>
36 #include <kiconloader.h>
37 #include <kwindowsystem.h>
38 #include <kglobalsettings.h>
41 #include "plasma/private/applet_p.h"
42 #include "plasma/private/extenderitemmimedata_p.h"
45 #include "plasma/private/containment_p.h"
59 : Plasma::
Applet(parent, args),
60 d(new PopupAppletPrivate(this))
65 : Plasma::
Applet(packagePath, appletId, args),
66 d(new PopupAppletPrivate(this))
90 d->createIconWidget();
91 d->icon->setIcon(icon);
99 if (!file.isEmpty()) {
106 QString
name = QString(
"icons/") + iconName.split(
"-").first();
108 d->createIconWidget();
109 d->icon->setSvg(name, iconName);
110 if (d->icon->svg().isEmpty()) {
123 return d->icon ? d->icon->icon() : QIcon();
137 QVBoxLayout *lay = 0;
139 QLayout *existingLayout = dialog->layout();
140 if (existingLayout) {
141 lay =
dynamic_cast<QVBoxLayout *
>(existingLayout);
143 delete existingLayout;
148 lay =
new QVBoxLayout;
149 dialog->setLayout(lay);
152 lay->removeWidget(d->widget);
153 lay->addWidget(widget);
154 }
else if (d->proxy) {
155 d->proxy.data()->setWidget(widget);
164 if (d->graphicsWidget) {
165 return d->graphicsWidget.data();
167 return static_cast<Applet*
>(
this)->d->extender.data();
173 if (d->graphicsWidget) {
175 d->dialogPtr.data()->setGraphicsWidget(graphicsWidget);
176 }
else if (layout()) {
177 QGraphicsLinearLayout *lay =
static_cast<QGraphicsLinearLayout *
>(layout());
179 if (graphicsWidget) {
180 lay->addItem(graphicsWidget);
194 }
else if (q->location() ==
TopEdge) {
201 dialogPtr.data()->setGraphicsWidget(extender);
206 void PopupAppletPrivate::popupConstraintsEvent(Plasma::Constraints constraints)
211 checkExtenderAppearance(f);
218 QGraphicsLinearLayout *lay =
dynamic_cast<QGraphicsLinearLayout *
>(q->layout());
220 if (icon && lay && lay->count() > 0) {
229 QWidget *qWidget = q->widget();
232 minimum = gWidget->minimumSize();
234 lay =
dynamic_cast<QGraphicsLinearLayout *
>(q->layout());
237 checkExtenderAppearance(f);
239 }
else if (qWidget) {
240 minimum = qWidget->minimumSizeHint();
245 if (q->parentLayoutItem()) {
246 parentSize = q->parentLayoutItem()->geometry().size();
247 }
else if (q->parentWidget()) {
248 parentSize = q->parentWidget()->size();
255 while (candidateParentApplet) {
256 candidateParentApplet = candidateParentApplet->parentWidget();
257 parentApplet = qobject_cast<
Plasma::Applet *>(candidateParentApplet);
281 Dialog *dialog = dialogPtr.data();
283 if (dialog->layout() && qWidget) {
285 dialog->layout()->removeWidget(qWidget);
289 qWidget->setParent(0);
296 lay =
new QGraphicsLinearLayout();
297 lay->setContentsMargins(0, 0, 0, 0);
307 proxy.data()->setWidget(0);
311 Corona *corona = qobject_cast<Corona *>(gWidget->scene());
314 corona->removeOffscreenWidget(gWidget);
317 lay->addItem(gWidget);
318 prefSize = gWidget->preferredSize().toSize();
319 }
else if (qWidget) {
322 proxy.data()->setWidget(qWidget);
323 proxy.data()->show();
326 lay->addItem(proxy.data());
327 prefSize = qWidget->sizeHint();
333 minimum.setHeight(0);
338 qreal left, top, right, bottom;
339 q->getContentsMargins(&left, &top, &right, &bottom);
340 QSizeF oldSize(q->size());
343 if (oldSize.width() < q->minimumSize().width() || oldSize.height() < q->minimumSize().height()) {
345 emit q->appletTransformedItself();
354 if (!qWidget && !gWidget) {
355 delete dialogPtr.data();
365 proxy.data()->setWidget(0);
370 savedAspectRatio = q->aspectRatioMode();
377 Dialog *dialog =
new Dialog();
378 dialog->d->appletPtr = q;
382 dialog->setAspectRatioMode(savedAspectRatio);
391 Corona *corona = qobject_cast<Corona *>(gWidget->scene());
393 corona = qobject_cast<Corona *>(q->scene());
397 corona->addOffscreenWidget(gWidget);
401 dialog->setGraphicsWidget(gWidget);
402 dialog->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | (gWidget->windowFlags() & Qt::X11BypassWindowManagerHint));
403 }
else if (qWidget) {
404 QVBoxLayout *l_layout =
new QVBoxLayout(dialog);
405 l_layout->setSpacing(0);
406 l_layout->setMargin(0);
407 l_layout->addWidget(qWidget);
408 dialog->adjustSize();
409 dialog->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | (qWidget->windowFlags() & Qt::X11BypassWindowManagerHint));
411 dialog->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
415 KWindowSystem::setState(dialog->winId(), NET::SkipTaskbar | NET::SkipPager);
416 dialog->installEventFilter(q);
418 QObject::connect(dialog, SIGNAL(dialogResized()), q, SLOT(dialogSizeChanged()));
419 QObject::connect(dialog, SIGNAL(dialogVisible(
bool)), q, SLOT(dialogStatusChanged(
bool)));
424 updateDialogPosition();
430 emit q->sizeHintChanged(Qt::PreferredSize);
434 void PopupAppletPrivate::appletActivated()
436 internalTogglePopup(
true);
441 if (!d->dialogPtr || which != Qt::PreferredSize) {
448 const int size = IconSize(KIconLoader::Panel);
449 return QSizeF(size, size);
456 return QSizeF(size, size);
461 if (!d->icon && !d->popupLostFocus && event->buttons() == Qt::LeftButton) {
462 d->clicked = scenePos().toPoint();
463 event->setAccepted(
true);
466 d->popupLostFocus =
false;
474 (d->clicked - scenePos().toPoint()).manhattanLength() < KGlobalSettings::dndEventDelay()) {
475 d->internalTogglePopup();
483 if (!d->passive && watched == d->dialogPtr.data() && (
event->type() == QEvent::WindowDeactivate)) {
484 d->popupLostFocus =
true;
485 QTimer::singleShot(100,
this, SLOT(clearPopupLostFocus()));
488 if (watched == d->dialogPtr.data() &&
event->type() == QEvent::ContextMenu) {
495 Dialog *dialog = d->dialogPtr.data();
497 int left, top, right, bottom;
498 dialog->getContentsMargins(&left, &top, &right, &bottom);
499 const QPoint eventPos =
static_cast<QContextMenuEvent*
>(event)->pos() - QPoint(left, top);
502 if (
Applet *actual = c->d->appletAt(pos)) {
508 c->d->addAppletActions(desktopMenu, applet, event);
510 if (!desktopMenu.isEmpty()) {
511 desktopMenu.exec(static_cast<QContextMenuEvent*>(event)->globalPos());
525 if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
526 const ExtenderItemMimeData *mimeData =
527 qobject_cast<
const ExtenderItemMimeData*>(
event->mimeData());
537 if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
538 const ExtenderItemMimeData *mimeData =
539 qobject_cast<
const ExtenderItemMimeData*>(
event->mimeData());
543 if (d->dialogPtr && !d->dialogPtr.data()->geometry().contains(event->screenPos()) &&
556 if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
557 const ExtenderItemMimeData *mimeData =
558 qobject_cast<
const ExtenderItemMimeData*>(
event->mimeData());
560 mimeData->extenderItem()->setExtender(
extender());
561 QApplication::restoreOverrideCursor();
569 if (popupDuration > 0 || d->autohideTimer) {
570 if (!d->autohideTimer) {
571 d->autohideTimer =
new QTimer(
this);
572 d->autohideTimer->setSingleShot(
true);
573 connect(d->autohideTimer, SIGNAL(timeout()),
this, SLOT(hideTimedPopup()));
576 d->autohideTimer->stop();
577 d->autohideTimer->setInterval(popupDuration);
581 d->delayedShowTimer.start(0,
this);
586 if (event->timerId() == d->delayedShowTimer.timerId()) {
587 d->delayedShowTimer.stop();
588 Dialog *dialog = d->dialogPtr.data();
592 if (!dialog->isVisible()) {
593 d->internalTogglePopup();
596 const int popupDuration = d->autohideTimer ? d->autohideTimer->interval() : 0;
598 if (popupDuration > 0) {
599 d->autohideTimer->start();
600 }
else if (d->autohideTimer) {
601 d->autohideTimer->stop();
604 }
else if (event->timerId() == d->showDialogTimer.timerId()) {
605 d->showDialogTimer.stop();
614 d->showDialogTimer.stop();
615 d->delayedShowTimer.stop();
617 Dialog *dialog = d->dialogPtr.data();
618 if (dialog && dialog->isVisible()) {
629 d->internalTogglePopup();
634 return d->popupPlacement;
639 d->popupAlignment = alignment;
644 return d->popupAlignment;
649 if (Applet::d->script) {
650 emit Applet::d->script->popupEvent(popped);
656 d->passive = passive;
666 return d->dialogPtr && d->dialogPtr.data()->isVisible();
674 PopupAppletPrivate::PopupAppletPrivate(
PopupApplet *applet)
679 popupAlignment(Qt::AlignLeft),
683 popupLostFocus(false),
687 q->resize(iconSize, iconSize);
688 q->setAcceptDrops(
true);
689 QObject::disconnect(q, SIGNAL(
activate()), static_cast<Applet*>(q), SLOT(setFocus()));
690 QObject::connect(q, SIGNAL(
activate()), q, SLOT(appletActivated()));
691 QObject::connect(KGlobalSettings::self(), SIGNAL(iconChanged(
int)), q, SLOT(iconSizeChanged(
int)));
694 PopupAppletPrivate::~PopupAppletPrivate()
697 proxy.data()->setWidget(0);
700 delete dialogPtr.data();
704 void PopupAppletPrivate::iconSizeChanged(
int group)
711 void PopupAppletPrivate::internalTogglePopup(
bool fromActivatedSignal)
714 autohideTimer->stop();
717 delayedShowTimer.stop();
721 q->setFocus(Qt::ShortcutFocusReason);
722 if (!fromActivatedSignal) {
723 QObject::disconnect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
725 QObject::connect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
734 if (dialog->isVisible()) {
741 dialog->clearFocus();
743 if (q->graphicsWidget() &&
744 q->graphicsWidget() ==
static_cast<Applet*
>(q)->d->extender.data() &&
745 static_cast<Applet*
>(q)->d->extender.data()->isEmpty()) {
747 if (!fromActivatedSignal) {
748 QObject::disconnect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
750 QObject::connect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
756 showDialogTimer.start(0, q);
760 void PopupAppletPrivate::showDialog()
767 updateDialogPosition();
769 KWindowSystem::setOnAllDesktops(dialog->winId(),
true);
770 KWindowSystem::setState(dialog->winId(), NET::SkipTaskbar | NET::SkipPager);
782 if (!(dialog->windowFlags() & Qt::X11BypassWindowManagerHint)) {
783 KWindowSystem::activateWindow(dialog->winId());
787 void PopupAppletPrivate::hideTimedPopup()
789 autohideTimer->stop();
793 void PopupAppletPrivate::clearPopupLostFocus()
795 if (!icon || !icon->isDown()) {
799 popupLostFocus =
false;
802 KConfigGroup PopupAppletPrivate::popupConfigGroup()
804 KConfigGroup *mainGroup =
static_cast<Applet*
>(q)->d->mainConfigGroup();
805 return KConfigGroup(mainGroup,
"PopupApplet");
808 void PopupAppletPrivate::dialogSizeChanged()
813 KConfigGroup sizeGroup = popupConfigGroup();
814 sizeGroup.writeEntry(
"DialogHeight", dialog->height());
815 sizeGroup.writeEntry(
"DialogWidth", dialog->width());
819 emit q->configNeedsSaving();
820 emit q->appletTransformedByUser();
824 void PopupAppletPrivate::dialogStatusChanged(
bool shown)
827 preShowStatus = q->status();
831 Qt::UniqueConnection);
835 q->setStatus(preShowStatus);
838 q->popupEvent(shown);
843 preShowStatus = status;
846 void PopupAppletPrivate::createIconWidget()
853 QObject::connect(icon, SIGNAL(clicked()), q, SLOT(internalTogglePopup()));
855 QGraphicsLinearLayout *layout =
new QGraphicsLinearLayout();
856 layout->setContentsMargins(0, 0, 0, 0);
857 layout->setSpacing(0);
859 layout->addItem(icon);
860 layout->setAlignment(icon, Qt::AlignCenter);
861 q->setLayout(layout);
864 void PopupAppletPrivate::restoreDialogSize()
871 Corona *corona = qobject_cast<Corona *>(q->scene());
876 KConfigGroup sizeGroup = popupConfigGroup();
878 int preferredWidth = 0;
879 int preferredHeight = 0;
882 preferredWidth = gWidget->preferredSize().width();
883 preferredHeight = gWidget->preferredSize().height();
886 const int width = qMin(sizeGroup.readEntry(
"DialogWidth", preferredWidth),
887 corona->screenGeometry(-1).width() - 50);
888 const int height = qMin(sizeGroup.readEntry(
"DialogHeight", preferredHeight),
889 corona->screenGeometry(-1).height() - 50);
891 QSize saved(width, height);
893 if (saved.isNull()) {
894 saved = dialog->sizeHint();
896 saved = saved.expandedTo(dialog->minimumSizeHint());
899 if (saved.width() != dialog->width() || saved.height() != dialog->height()) {
900 dialog->resize(saved);
907 void PopupAppletPrivate::updateDialogPosition(
bool move)
914 Corona *corona = qobject_cast<Corona *>(q->scene());
924 const QPoint appletPos = view->mapToGlobal(view->mapFromScene(q->scenePos()));
926 QPoint dialogPos = dialog->pos();
928 if (!q->containment() || view == q->containment()->view()) {
929 dialogPos = corona->popupPosition(q, dialog->size(), popupAlignment);
931 dialogPos = corona->popupPosition(q->parentItem(), dialog->size(), popupAlignment);
935 bool reverse =
false;
937 reverse = (appletPos.y() + (q->size().height() / 2)) < (dialogPos.y() + (dialog->size().height() / 2));
940 reverse = (appletPos.x() + (q->size().width() / 2)) < (dialogPos.x() + (dialog->size().width() / 2));
945 switch (q->location()) {
972 dialog->move(dialogPos);
978 #include "popupapplet.moc"