~ubuntu-branches/ubuntu/wily/unity-2d/wily

« back to all changes in this revision

Viewing changes to libunity-2d-private/src/indicatorsmanager.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2011-08-25 18:16:57 UTC
  • mfrom: (1.1.19 upstream)
  • Revision ID: james.westby@ubuntu.com-20110825181657-opb29rqsxae3i98f
Tags: 4.2.0-0ubuntu1
* New upstream release:
  - [panel] application menus do not appear on first hover after dismissal
    (lp: #825262)
  - [dash] Lens icons badly scaled (lp: #825368)
  - [panel] indicators are shifted offscreen to the right (lp: #827673)
  - [panel] scrubbing from system indicators to menubar should be possible
    (lp: #706903)
  - [launcher] Closed applications don't get their launcher counts cleared
    (lp: #767367)
  - [dash] selected item should not be underlined but use the same 
    treatment as unity (lp: #817456)
  - [dash] categories should be collapsed by default (lp: #827214)
  - [dash] Ratings filter (lp: #831855)
  - [dash] Multirange filter (lp: #831856)
  - [dash] ToggleButton filter (lp: #831857)
  - [dash] Icon size must be bigger to match the mockups (lp: #831858)
  - [dash] "Refine search" right margin should be 15 pixels (lp: #832058)
  - [dash] "Refine search" should be "Filter results" (lp: #832060)
  - [dash] Font sizes should match new design (lp: #832114)
  - [panel] Glitch: application menu appearing when pressing the BFB 
    (lp: #825060)
  - [panel] Glitch: application menus are quickly opened after a drag gesture
    (lp: #825267)
  - [dash] File thumbnails aspect ratio is not respected (lp: #832204)
* debian/control: require current the current versions of nux and unity

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * This file is part of unity-2d
 
3
 *
 
4
 * Copyright 2011 Canonical Ltd.
 
5
 *
 
6
 * Authors:
 
7
 * - Aurélien Gâteau <aurelien.gateau@canonical.com>
 
8
 *
 
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.
 
12
 *
 
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.
 
17
 *
 
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/>.
 
20
 */
 
21
// Self
 
22
#include "indicatorsmanager.h"
 
23
 
 
24
// Local
 
25
#include <debug_p.h>
 
26
#include <indicatorentrywidget.h>
 
27
 
 
28
// Qt
 
29
#include <QApplication>
 
30
#include <QTimer>
 
31
#include <QX11Info>
 
32
 
 
33
// X11
 
34
#include <X11/Xlib.h>
 
35
 
 
36
using namespace unity::indicator;
 
37
 
 
38
IndicatorsManager::IndicatorsManager(QObject* parent)
 
39
: QObject(parent)
 
40
, m_indicators(new DBusIndicators)
 
41
, m_geometrySyncTimer(new QTimer(this))
 
42
, m_mouseTrackerTimer(new QTimer(this))
 
43
{
 
44
    m_geometrySyncTimer->setInterval(0);
 
45
    m_geometrySyncTimer->setSingleShot(true);
 
46
    connect(m_geometrySyncTimer, SIGNAL(timeout()), SLOT(syncGeometries()));
 
47
 
 
48
    // m_mouseTrackerTimer is inspired from
 
49
    // plugins/unityshell/src/PanelView.cpp in OnEntryActivated()
 
50
    //
 
51
    // Rationale copied from Unity source code:
 
52
    // """
 
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.
 
61
    // """
 
62
    m_mouseTrackerTimer->setInterval(16);
 
63
    m_mouseTrackerTimer->setSingleShot(false);
 
64
    connect(m_mouseTrackerTimer, SIGNAL(timeout()), SLOT(checkMousePosition()));
 
65
 
 
66
    m_indicators->on_entry_show_menu.connect(
 
67
        sigc::mem_fun(this, &IndicatorsManager::onEntryShowMenu)
 
68
        );
 
69
 
 
70
    m_indicators->on_entry_activate_request.connect(
 
71
        sigc::mem_fun(this, &IndicatorsManager::onEntryActivateRequest)
 
72
        );
 
73
 
 
74
    m_indicators->on_entry_activated.connect(
 
75
        sigc::mem_fun(this, &IndicatorsManager::onEntryActivated)
 
76
        );
 
77
 
 
78
    m_indicators->on_synced.connect(
 
79
        sigc::mem_fun(this, &IndicatorsManager::onSynced)
 
80
        );
 
81
}
 
82
 
 
83
unity::indicator::DBusIndicators::Ptr IndicatorsManager::indicators() const
 
84
{
 
85
    return m_indicators;
 
86
}
 
87
 
 
88
void IndicatorsManager::onEntryShowMenu(const std::string& /*entryId*/, int posX, int posY, int /*timestamp*/, int /*button*/)
 
89
{
 
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())
 
93
    /*
 
94
    Neil explanation:
 
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.
 
100
    */
 
101
    Display* display = QX11Info::display();
 
102
    XUngrabPointer(display, CurrentTime);
 
103
    XFlush(display);
 
104
 
 
105
    XButtonEvent event = {
 
106
        ButtonRelease,
 
107
        0,
 
108
        False,
 
109
        display,
 
110
        0,
 
111
        0,
 
112
        0,
 
113
        CurrentTime,
 
114
        posX, posY,
 
115
        posX, posY,
 
116
        0,
 
117
        Button1,
 
118
        True
 
119
    };
 
120
    qApp->x11ProcessEvent(reinterpret_cast<XEvent*>(&event));
 
121
}
 
122
 
 
123
void IndicatorsManager::checkMousePosition()
 
124
{
 
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
    // Also, delivers motion events to Qt, which will generate correct
 
128
    // enter/leave events for IndicatorEntry widgets.
 
129
    QPoint pos = QCursor::pos();
 
130
    QWidget* widget = QApplication::widgetAt(pos);
 
131
    Display* display = QX11Info::display();
 
132
 
 
133
    QPoint relPos = widget != 0 ? widget->mapFromGlobal(pos) : pos;
 
134
    XMotionEvent event = {
 
135
        MotionNotify,
 
136
        0,
 
137
        False,
 
138
        display,
 
139
        widget != 0 ? widget->effectiveWinId() : 0,
 
140
        widget != 0 ? RootWindow(display, widget->x11Info().screen()) : 0,
 
141
        0,
 
142
        CurrentTime,
 
143
        pos.x(), pos.y(),
 
144
        relPos.x(), relPos.y(),
 
145
        0,
 
146
        False,
 
147
        True
 
148
    };
 
149
    qApp->x11ProcessEvent(reinterpret_cast<XEvent*>(&event));
 
150
 
 
151
    IndicatorEntryWidget* entryWidget = qobject_cast<IndicatorEntryWidget*>(widget);
 
152
    if (!entryWidget) {
 
153
        return;
 
154
    }
 
155
    entryWidget->showMenu(Qt::NoButton);
 
156
}
 
157
 
 
158
void IndicatorsManager::onEntryActivateRequest(const std::string& entryId)
 
159
{
 
160
    if (entryId.empty()) {
 
161
        return;
 
162
    }
 
163
    IndicatorEntryWidget* widget = 0;
 
164
    Q_FOREACH(widget, m_widgetList) {
 
165
        if (widget->entry()->id() == entryId) {
 
166
            break;
 
167
        }
 
168
    }
 
169
    if (!widget) {
 
170
        UQ_WARNING << "Could not find a widget for IndicatorEntry with id" << QString::fromStdString(entryId);
 
171
        return;
 
172
    }
 
173
    widget->showMenu(Qt::NoButton);
 
174
}
 
175
 
 
176
void IndicatorsManager::onEntryActivated(const std::string& entryId)
 
177
{
 
178
    if (entryId.empty()) {
 
179
        m_mouseTrackerTimer->stop();
 
180
    } else {
 
181
        m_mouseTrackerTimer->start();
 
182
    }
 
183
}
 
184
 
 
185
void IndicatorsManager::onSynced()
 
186
{
 
187
    QMetaObject::invokeMethod(m_geometrySyncTimer, "start", Qt::QueuedConnection);
 
188
}
 
189
 
 
190
void IndicatorsManager::addIndicatorEntryWidget(IndicatorEntryWidget* widget)
 
191
{
 
192
    m_widgetList.append(widget);
 
193
    widget->installEventFilter(this);
 
194
}
 
195
 
 
196
bool IndicatorsManager::eventFilter(QObject*, QEvent* event)
 
197
{
 
198
    switch (event->type()) {
 
199
    case QEvent::Show:
 
200
    case QEvent::Hide:
 
201
    case QEvent::Move:
 
202
    case QEvent::Resize:
 
203
        m_geometrySyncTimer->start();
 
204
        break;
 
205
    default:
 
206
        break;
 
207
    }
 
208
    return false;
 
209
}
 
210
 
 
211
void IndicatorsManager::syncGeometries()
 
212
{
 
213
    EntryLocationMap locations;
 
214
    Q_FOREACH(IndicatorEntryWidget* widget, m_widgetList) {
 
215
        if (!widget->isVisible()) {
 
216
            continue;
 
217
        }
 
218
        Entry::Ptr entry = widget->entry();
 
219
        if (entry->IsUnused()) {
 
220
            continue;
 
221
        }
 
222
        QPoint topLeft = widget->mapToGlobal(QPoint(0, 0));
 
223
        nux::Rect rect(topLeft.x(), topLeft.y(), widget->width(), widget->height());
 
224
        locations[widget->entry()->id()] = rect;
 
225
    }
 
226
    m_indicators->SyncGeometries("Panel", locations);
 
227
}
 
228
 
 
229
#include "indicatorsmanager.moc"