2
* This file is part of unity-2d
4
* Copyright 2011 Canonical Ltd.
7
* - Aurélien Gâteau <aurelien.gateau@canonical.com>
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; version 3.
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with this program. If not, see <http://www.gnu.org/licenses/>.
22
#include "indicatorsmanager.h"
26
#include <indicatorentrywidget.h>
29
#include <QApplication>
36
using namespace unity::indicator;
38
IndicatorsManager::IndicatorsManager(QObject* parent)
40
, m_indicators(new DBusIndicators)
41
, m_geometrySyncTimer(new QTimer(this))
42
, m_mouseTrackerTimer(new QTimer(this))
44
m_geometrySyncTimer->setInterval(0);
45
m_geometrySyncTimer->setSingleShot(true);
46
connect(m_geometrySyncTimer, SIGNAL(timeout()), SLOT(syncGeometries()));
48
// m_mouseTrackerTimer is inspired from
49
// plugins/unityshell/src/PanelView.cpp in OnEntryActivated()
51
// Rationale copied from Unity source code:
53
// Track menus being scrubbed at 60Hz (about every 16 millisec)
54
// It might sound ugly, but it's far nicer (and more responsive) than the
55
// code it replaces which used to capture motion events in another process
56
// (unity-panel-service) and send them to us over dbus.
57
// NOTE: The reason why we have to use a timer instead of tracking motion
58
// events is because the motion events will never be delivered to this
59
// process. All the motion events will go to unity-panel-service while
60
// scrubbing because the active panel menu has (needs) the pointer grab.
62
m_mouseTrackerTimer->setInterval(16);
63
m_mouseTrackerTimer->setSingleShot(false);
64
connect(m_mouseTrackerTimer, SIGNAL(timeout()), SLOT(checkMousePosition()));
66
m_indicators->on_entry_show_menu.connect(
67
sigc::mem_fun(this, &IndicatorsManager::onEntryShowMenu)
70
m_indicators->on_entry_activate_request.connect(
71
sigc::mem_fun(this, &IndicatorsManager::onEntryActivateRequest)
74
m_indicators->on_entry_activated.connect(
75
sigc::mem_fun(this, &IndicatorsManager::onEntryActivated)
78
m_indicators->on_synced.connect(
79
sigc::mem_fun(this, &IndicatorsManager::onSynced)
83
unity::indicator::DBusIndicators::Ptr IndicatorsManager::indicators() const
88
void IndicatorsManager::onEntryShowMenu(const std::string& /*entryId*/, int posX, int posY, int /*timestamp*/, int /*button*/)
90
// Copied from plugins/unityshell/src/PanelView.cpp, in OnEntryShowMenu()
91
// Without this code, menus cannot be shown from mousePressEvent() (but can
92
// be shown from mouseReleaseEvent())
95
On button down, X automatically gives Qt a passive grab on the mouse this
96
means that, if the panel service tries to grab the pointer to show the menu
97
(gtk does this automatically), it fails and the menu can't show.
98
We connect to the on_entry_show_menu signal, which is emitted before
99
DBusIndicators does anything else, and just break the grab.
101
Display* display = QX11Info::display();
102
XUngrabPointer(display, CurrentTime);
105
XButtonEvent event = {
120
qApp->x11ProcessEvent(reinterpret_cast<XEvent*>(&event));
123
void IndicatorsManager::checkMousePosition()
125
// Called by m_mouseTrackerTimer to implement mouse scrubbing
126
// (Assuming item A menu is opened, move mouse over item B => item B menu opens)
127
QWidget* widget = QApplication::widgetAt(QCursor::pos());
128
IndicatorEntryWidget* entryWidget = qobject_cast<IndicatorEntryWidget*>(widget);
132
entryWidget->showMenu(Qt::NoButton);
135
void IndicatorsManager::onEntryActivateRequest(const std::string& entryId)
137
if (entryId.empty()) {
140
IndicatorEntryWidget* widget = 0;
141
Q_FOREACH(widget, m_widgetList) {
142
if (widget->entry()->id() == entryId) {
147
UQ_WARNING << "Could not find a widget for IndicatorEntry with id" << QString::fromStdString(entryId);
150
widget->showMenu(Qt::NoButton);
153
void IndicatorsManager::onEntryActivated(const std::string& entryId)
155
if (entryId.empty()) {
156
m_mouseTrackerTimer->stop();
158
m_mouseTrackerTimer->start();
162
void IndicatorsManager::onSynced()
164
QMetaObject::invokeMethod(m_geometrySyncTimer, "start", Qt::QueuedConnection);
167
void IndicatorsManager::addIndicatorEntryWidget(IndicatorEntryWidget* widget)
169
m_widgetList.append(widget);
170
widget->installEventFilter(this);
173
bool IndicatorsManager::eventFilter(QObject*, QEvent* event)
175
switch (event->type()) {
180
m_geometrySyncTimer->start();
188
void IndicatorsManager::syncGeometries()
190
EntryLocationMap locations;
191
Q_FOREACH(IndicatorEntryWidget* widget, m_widgetList) {
192
if (!widget->isVisible()) {
195
Entry::Ptr entry = widget->entry();
196
if (entry->IsUnused()) {
199
QPoint topLeft = widget->mapToGlobal(QPoint(0, 0));
200
nux::Rect rect(topLeft.x(), topLeft.y(), widget->width(), widget->height());
201
locations[widget->entry()->id()] = rect;
203
m_indicators->SyncGeometries("Panel", locations);
206
#include "indicatorsmanager.moc"