~charlesk/indicator-datetime/lp-1001595

« back to all changes in this revision

Viewing changes to src/timezone-geoclue.cpp

  • Committer: CI bot
  • Author(s): Charles Kerr
  • Date: 2014-01-31 11:46:08 UTC
  • mfrom: (290.2.86 cpp)
  • Revision ID: ps-jenkins@lists.canonical.com-20140131114608-8sfzhimcfdywmk46
Finally land this. Other, still open bugs will be fixed in subsequent commits. Fixes: 793450, 1271484, 1274046

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2013 Canonical Ltd.
 
3
 *
 
4
 * Authors:
 
5
 *   Charles Kerr <charles.kerr@canonical.com>
 
6
 *
 
7
 * This program is free software: you can redistribute it and/or modify it
 
8
 * under the terms of the GNU General Public License version 3, as published
 
9
 * by the Free Software Foundation.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful, but
 
12
 * WITHOUT ANY WARRANTY; without even the implied warranties of
 
13
 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
 
14
 * PURPOSE.  See the GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License along
 
17
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 
18
 */
 
19
 
 
20
#include <datetime/timezone-geoclue.h>
 
21
 
 
22
#define GEOCLUE_BUS_NAME "org.freedesktop.Geoclue.Master"
 
23
 
 
24
namespace unity {
 
25
namespace indicator {
 
26
namespace datetime {
 
27
 
 
28
 
 
29
GeoclueTimezone::GeoclueTimezone():
 
30
    m_cancellable(g_cancellable_new())
 
31
{
 
32
    g_bus_get(G_BUS_TYPE_SESSION, m_cancellable, on_bus_got, this);
 
33
}
 
34
 
 
35
GeoclueTimezone::~GeoclueTimezone()
 
36
{
 
37
    g_cancellable_cancel(m_cancellable);
 
38
    g_object_unref(m_cancellable);
 
39
 
 
40
    if (m_signal_subscription)
 
41
        g_dbus_connection_signal_unsubscribe(m_connection, m_signal_subscription);
 
42
 
 
43
    g_object_unref(m_connection);
 
44
}
 
45
 
 
46
/***
 
47
****
 
48
***/
 
49
 
 
50
void
 
51
GeoclueTimezone::on_bus_got(GObject*      /*source*/,
 
52
                            GAsyncResult*   res,
 
53
                            gpointer        gself)
 
54
{
 
55
    GError * error;
 
56
    GDBusConnection * connection;
 
57
 
 
58
    error = nullptr;
 
59
    connection = g_bus_get_finish(res, &error);
 
60
    if (error)
 
61
    {
 
62
        if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 
63
            g_warning("Couldn't get bus: %s", error->message);
 
64
 
 
65
        g_error_free(error);
 
66
    }
 
67
    else
 
68
    {
 
69
        auto self = static_cast<GeoclueTimezone*>(gself);
 
70
 
 
71
        self->m_connection = connection;
 
72
 
 
73
        g_dbus_connection_call(self->m_connection,
 
74
                               GEOCLUE_BUS_NAME,
 
75
                               "/org/freedesktop/Geoclue/Master",
 
76
                               "org.freedesktop.Geoclue.Master",
 
77
                               "Create",
 
78
                               nullptr, // parameters
 
79
                               G_VARIANT_TYPE("(o)"),
 
80
                               G_DBUS_CALL_FLAGS_NONE,
 
81
                               -1,
 
82
                               self->m_cancellable,
 
83
                               on_client_created,
 
84
                               self);
 
85
    }
 
86
}
 
87
 
 
88
void
 
89
GeoclueTimezone::on_client_created(GObject * source, GAsyncResult * res, gpointer gself)
 
90
{
 
91
    GVariant * result;
 
92
 
 
93
    if ((result = call_finish(source, res)))
 
94
    {
 
95
        auto self = static_cast<GeoclueTimezone*>(gself);
 
96
 
 
97
        GVariant * child = g_variant_get_child_value(result, 0);
 
98
        self->m_client_object_path = g_variant_get_string(child, nullptr);
 
99
        g_variant_unref(child);
 
100
        g_variant_unref(result);
 
101
 
 
102
        self->m_signal_subscription = g_dbus_connection_signal_subscribe(
 
103
                    self->m_connection,
 
104
                    GEOCLUE_BUS_NAME,
 
105
                    "org.freedesktop.Geoclue.Address", // inteface
 
106
                    "AddressChanged", // signal name
 
107
                    self->m_client_object_path.c_str(), // object path
 
108
                    nullptr, // arg0
 
109
                    G_DBUS_SIGNAL_FLAGS_NONE,
 
110
                    on_address_changed,
 
111
                    self,
 
112
                    nullptr);
 
113
 
 
114
        g_dbus_connection_call(self->m_connection,
 
115
                               GEOCLUE_BUS_NAME,
 
116
                               self->m_client_object_path.c_str(),
 
117
                               "org.freedesktop.Geoclue.MasterClient",
 
118
                               "SetRequirements",
 
119
                               g_variant_new("(iibi)", 2, 0, FALSE, 1023),
 
120
                               nullptr,
 
121
                               G_DBUS_CALL_FLAGS_NONE,
 
122
                               -1,
 
123
                               self->m_cancellable,
 
124
                               on_requirements_set,
 
125
                               self);
 
126
    }
 
127
}
 
128
 
 
129
void
 
130
GeoclueTimezone::on_address_changed(GDBusConnection* /*connection*/,
 
131
                                    const gchar*     /*sender_name*/,
 
132
                                    const gchar*     /*object_path*/,
 
133
                                    const gchar*     /*interface_name*/,
 
134
                                    const gchar*     /*signal_name*/,
 
135
                                    GVariant*          parameters,
 
136
                                    gpointer           gself)
 
137
{
 
138
    static_cast<GeoclueTimezone*>(gself)->setTimezoneFromAddressVariant(parameters);
 
139
}
 
140
 
 
141
void
 
142
GeoclueTimezone::on_requirements_set(GObject* source, GAsyncResult* res, gpointer gself)
 
143
{
 
144
    GVariant * result;
 
145
 
 
146
    if ((result = call_finish(source, res)))
 
147
    {
 
148
        auto self = static_cast<GeoclueTimezone*>(gself);
 
149
 
 
150
        g_dbus_connection_call(self->m_connection,
 
151
                               GEOCLUE_BUS_NAME,
 
152
                               self->m_client_object_path.c_str(),
 
153
                               "org.freedesktop.Geoclue.MasterClient",
 
154
                               "AddressStart",
 
155
                               nullptr,
 
156
                               nullptr,
 
157
                               G_DBUS_CALL_FLAGS_NONE,
 
158
                               -1,
 
159
                               self->m_cancellable,
 
160
                               on_address_started,
 
161
                               self);
 
162
 
 
163
        g_variant_unref(result);
 
164
    }
 
165
}
 
166
 
 
167
void
 
168
GeoclueTimezone::on_address_started(GObject * source, GAsyncResult * res, gpointer gself)
 
169
{
 
170
    GVariant * result;
 
171
 
 
172
    if ((result = call_finish(source, res)))
 
173
    {
 
174
        auto self = static_cast<GeoclueTimezone*>(gself);
 
175
 
 
176
        g_dbus_connection_call(self->m_connection,
 
177
                               GEOCLUE_BUS_NAME,
 
178
                               self->m_client_object_path.c_str(),
 
179
                               "org.freedesktop.Geoclue.Address",
 
180
                               "GetAddress",
 
181
                               nullptr,
 
182
                               G_VARIANT_TYPE("(ia{ss}(idd))"),
 
183
                               G_DBUS_CALL_FLAGS_NONE,
 
184
                               -1,
 
185
                               self->m_cancellable,
 
186
                               on_address_got,
 
187
                               self);
 
188
 
 
189
        g_variant_unref(result);
 
190
    }
 
191
}
 
192
 
 
193
void
 
194
GeoclueTimezone::on_address_got(GObject * source, GAsyncResult * res, gpointer gself)
 
195
{
 
196
    GVariant * result;
 
197
 
 
198
    if ((result = call_finish(source, res)))
 
199
    {
 
200
        static_cast<GeoclueTimezone*>(gself)->setTimezoneFromAddressVariant(result);
 
201
        g_variant_unref(result);
 
202
    }
 
203
}
 
204
 
 
205
void
 
206
GeoclueTimezone::setTimezoneFromAddressVariant(GVariant * variant)
 
207
{
 
208
    g_return_if_fail(g_variant_is_of_type(variant, G_VARIANT_TYPE("(ia{ss}(idd))")));
 
209
 
 
210
    const gchar * timezone_string = nullptr;
 
211
    GVariant * dict = g_variant_get_child_value(variant, 1);
 
212
    if (dict)
 
213
    {
 
214
        if (g_variant_lookup(dict, "timezone", "&s", &timezone_string))
 
215
            timezone.set(timezone_string);
 
216
 
 
217
        g_variant_unref(dict);
 
218
    }
 
219
}
 
220
 
 
221
GVariant*
 
222
GeoclueTimezone::call_finish(GObject * source, GAsyncResult * res)
 
223
{
 
224
    GError * error;
 
225
    GVariant * result;
 
226
 
 
227
    error = nullptr;
 
228
    result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &error);
 
229
 
 
230
    if (error)
 
231
    {
 
232
            if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 
233
                g_warning("AddressStart() failed: %s", error->message);
 
234
 
 
235
            g_error_free(error);
 
236
 
 
237
            g_clear_pointer(&result, g_variant_unref);
 
238
    }
 
239
 
 
240
    return result;
 
241
}
 
242
 
 
243
/****
 
244
*****
 
245
****/
 
246
 
 
247
} // namespace datetime
 
248
} // namespace indicator
 
249
} // namespace unity
 
250