Merge lp:~larsu/unity-control-center/bluez5-gnome-bluetooth into lp:unity-control-center
- bluez5-gnome-bluetooth
- Merge into trunk
Proposed by
Sebastien Bacher
Status: | Merged |
---|---|
Approved by: | Sebastien Bacher |
Approved revision: | 12808 |
Merged at revision: | 12820 |
Proposed branch: | lp:~larsu/unity-control-center/bluez5-gnome-bluetooth |
Merge into: | lp:unity-control-center |
Diff against target: |
11178 lines (+10736/-93) 46 files modified
configure.ac (+4/-10) panels/Makefile.am (+2/-5) panels/bluetooth/Makefile.am (+16/-4) panels/bluetooth/bluetooth-killswitch.c (+387/-0) panels/bluetooth/bluetooth-killswitch.h (+78/-0) panels/bluetooth/cc-bluetooth-panel.c (+3/-74) panels/bluetooth/gnome-bluetooth/Makefile.am (+1/-0) panels/bluetooth/gnome-bluetooth/lib/Makefile.am (+99/-0) panels/bluetooth/gnome-bluetooth/lib/bluetooth-agent.c (+681/-0) panels/bluetooth/gnome-bluetooth/lib/bluetooth-agent.h (+127/-0) panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-button.c (+419/-0) panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-button.h (+55/-0) panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-combo.c (+365/-0) panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-combo.h (+69/-0) panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-private.h (+39/-0) panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser.c (+1173/-0) panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser.h (+86/-0) panels/bluetooth/gnome-bluetooth/lib/bluetooth-client-private.h (+61/-0) panels/bluetooth/gnome-bluetooth/lib/bluetooth-client.c (+1757/-0) panels/bluetooth/gnome-bluetooth/lib/bluetooth-client.h (+87/-0) panels/bluetooth/gnome-bluetooth/lib/bluetooth-client.xml (+59/-0) panels/bluetooth/gnome-bluetooth/lib/bluetooth-enums.h (+177/-0) panels/bluetooth/gnome-bluetooth/lib/bluetooth-fdo.xml (+33/-0) panels/bluetooth/gnome-bluetooth/lib/bluetooth-filter-widget.c (+477/-0) panels/bluetooth/gnome-bluetooth/lib/bluetooth-filter-widget.h (+67/-0) panels/bluetooth/gnome-bluetooth/lib/bluetooth-utils.c (+342/-0) panels/bluetooth/gnome-bluetooth/lib/bluetooth-utils.h (+72/-0) panels/bluetooth/gnome-bluetooth/lib/pin-code-database.xml (+155/-0) panels/bluetooth/gnome-bluetooth/lib/test-agent.c (+86/-0) panels/bluetooth/gnome-bluetooth/lib/test-class.c (+66/-0) panels/bluetooth/gnome-bluetooth/lib/test-client.c (+326/-0) panels/bluetooth/gnome-bluetooth/lib/test-deviceselection.c (+421/-0) panels/bluetooth/gnome-bluetooth/wizard/Makefile.am (+38/-0) panels/bluetooth/gnome-bluetooth/wizard/TEST-PROCEDURE.txt (+33/-0) panels/bluetooth/gnome-bluetooth/wizard/bluetooth-input.c (+239/-0) panels/bluetooth/gnome-bluetooth/wizard/bluetooth-input.h (+65/-0) panels/bluetooth/gnome-bluetooth/wizard/bluetooth-wizard.1 (+29/-0) panels/bluetooth/gnome-bluetooth/wizard/main.c (+1115/-0) panels/bluetooth/gnome-bluetooth/wizard/pin-code-database.xml (+155/-0) panels/bluetooth/gnome-bluetooth/wizard/pin.c (+174/-0) panels/bluetooth/gnome-bluetooth/wizard/pin.h (+33/-0) panels/bluetooth/gnome-bluetooth/wizard/test-input.c (+54/-0) panels/bluetooth/gnome-bluetooth/wizard/wizard.ui (+540/-0) panels/bluetooth/rfkill-glib.c (+299/-0) panels/bluetooth/rfkill-glib.h (+65/-0) panels/bluetooth/rfkill.h (+107/-0) |
To merge this branch: | bzr merge lp:~larsu/unity-control-center/bluez5-gnome-bluetooth |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Sebastien Bacher | Approve | ||
Review via email: mp+267835@code.launchpad.net |
Commit message
bluetooth: make compatible with bluez5
Since we don't want to update to gnome bluetooth's new UI, import
gnome-bluetooth until commit ef7d546, which has bluez5 support but no UI
changes.
Description of the change
bluetooth: make compatible with bluez5
Since we don't want to update to gnome bluetooth's new UI, import
gnome-bluetooth until commit ef7d546, which has bluez5 support but no UI
changes.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'configure.ac' |
2 | --- configure.ac 2015-02-12 14:09:23 +0000 |
3 | +++ configure.ac 2015-08-12 15:47:27 +0000 |
4 | @@ -171,6 +171,7 @@ |
5 | gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION |
6 | pwquality |
7 | accountsservice >= $ACCOUNTSSERVICE_REQUIRED_VERSION) |
8 | +PKG_CHECK_MODULES(BLUETOOTH_PANEL, $COMMON_MODULES) |
9 | |
10 | AM_PROG_VALAC([0.20.0]) |
11 | |
12 | @@ -188,11 +189,6 @@ |
13 | fi |
14 | AM_CONDITIONAL(BUILD_NETWORK, [test x$have_networkmanager = xyes]) |
15 | |
16 | -# Check for gnome-bluetooth |
17 | -PKG_CHECK_MODULES(BLUETOOTH, $COMMON_MODULES gnome-bluetooth-1.0 >= 3.5.5, |
18 | - [have_bluetooth=yes], have_bluetooth=no) |
19 | -AM_CONDITIONAL(BUILD_BLUETOOTH, [test x$have_bluetooth = xyes]) |
20 | - |
21 | # Check for CUPS 1.4 or newer |
22 | AC_ARG_ENABLE([cups], |
23 | AS_HELP_STRING([--disable-cups], [disable CUPS support (default: enabled)]),, |
24 | @@ -419,6 +415,9 @@ |
25 | panels/appearance/Makefile |
26 | panels/appearance/unity-appearance-panel.desktop.in |
27 | panels/bluetooth/Makefile |
28 | +panels/bluetooth/gnome-bluetooth/Makefile |
29 | +panels/bluetooth/gnome-bluetooth/lib/Makefile |
30 | +panels/bluetooth/gnome-bluetooth/wizard/Makefile |
31 | panels/bluetooth/unity-bluetooth-panel.desktop.in |
32 | panels/datetime/Makefile |
33 | panels/datetime/unity-datetime-panel.desktop.in |
34 | @@ -502,11 +501,6 @@ |
35 | else |
36 | AC_MSG_NOTICE([ Network panel disabled]) |
37 | fi |
38 | -if test "x$have_bluetooth" = "xyes"; then |
39 | - AC_MSG_NOTICE([** gnome-bluetooth (Bluetooth panel)]) |
40 | -else |
41 | - AC_MSG_NOTICE([ Bluetooth panel disabled]) |
42 | -fi |
43 | if test "x$enable_cups" = "xyes"; then |
44 | AC_MSG_NOTICE([** CUPS (Printers panel)]) |
45 | else |
46 | |
47 | === modified file 'panels/Makefile.am' |
48 | --- panels/Makefile.am 2014-02-10 22:19:33 +0000 |
49 | +++ panels/Makefile.am 2015-08-12 15:47:27 +0000 |
50 | @@ -12,7 +12,8 @@ |
51 | sound \ |
52 | keyboard \ |
53 | universal-access \ |
54 | - user-accounts |
55 | + user-accounts \ |
56 | + bluetooth |
57 | |
58 | if BUILD_WACOM |
59 | SUBDIRS += wacom |
60 | @@ -26,8 +27,4 @@ |
61 | SUBDIRS += network |
62 | endif |
63 | |
64 | -if BUILD_BLUETOOTH |
65 | -SUBDIRS += bluetooth |
66 | -endif |
67 | - |
68 | -include $(top_srcdir)/git.mk |
69 | |
70 | === modified file 'panels/bluetooth/Makefile.am' |
71 | --- panels/bluetooth/Makefile.am 2014-02-19 23:36:18 +0000 |
72 | +++ panels/bluetooth/Makefile.am 2015-08-12 15:47:27 +0000 |
73 | @@ -1,3 +1,5 @@ |
74 | +SUBDIRS = gnome-bluetooth |
75 | + |
76 | # This is used in PANEL_CFLAGS |
77 | cappletname = bluetooth |
78 | |
79 | @@ -6,7 +8,8 @@ |
80 | |
81 | INCLUDES = \ |
82 | $(PANEL_CFLAGS) \ |
83 | - $(BLUETOOTH_CFLAGS) \ |
84 | + $(BLUETOOTH_PANEL_CFLAGS) \ |
85 | + -I$(srcdir)/gnome-bluetooth/lib \ |
86 | -DGNOMELOCALEDIR="\"$(datadir)/locale\"" \ |
87 | $(NULL) |
88 | |
89 | @@ -17,9 +20,18 @@ |
90 | libbluetooth_la_SOURCES = \ |
91 | $(BUILT_SOURCES) \ |
92 | cc-bluetooth-panel.c \ |
93 | - cc-bluetooth-panel.h |
94 | - |
95 | -libbluetooth_la_LIBADD = $(PANEL_LIBS) $(BLUETOOTH_LIBS) |
96 | + cc-bluetooth-panel.h \ |
97 | + bluetooth-killswitch.c \ |
98 | + bluetooth-killswitch.h \ |
99 | + rfkill.h \ |
100 | + rfkill-glib.c \ |
101 | + rfkill-glib.h |
102 | + |
103 | +libbluetooth_la_LIBADD = \ |
104 | + $(PANEL_LIBS) \ |
105 | + $(BLUETOOTH_PANEL_LIBS) \ |
106 | + $(builddir)/gnome-bluetooth/lib/libgnome-bluetooth.la |
107 | + |
108 | libbluetooth_la_LDFLAGS = $(PANEL_LDFLAGS) |
109 | |
110 | resource_files = $(shell glib-compile-resources --sourcedir=$(srcdir) --generate-dependencies $(srcdir)/bluetooth.gresource.xml) |
111 | |
112 | === added file 'panels/bluetooth/bluetooth-killswitch.c' |
113 | --- panels/bluetooth/bluetooth-killswitch.c 1970-01-01 00:00:00 +0000 |
114 | +++ panels/bluetooth/bluetooth-killswitch.c 2015-08-12 15:47:27 +0000 |
115 | @@ -0,0 +1,387 @@ |
116 | +/* |
117 | + * |
118 | + * BlueZ - Bluetooth protocol stack for Linux |
119 | + * |
120 | + * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org> |
121 | + * Copyright (C) 2006-2009 Bastien Nocera <hadess@hadess.net> |
122 | + * |
123 | + * |
124 | + * This program is free software; you can redistribute it and/or modify |
125 | + * it under the terms of the GNU General Public License as published by |
126 | + * the Free Software Foundation; either version 2 of the License, or |
127 | + * (at your option) any later version. |
128 | + * |
129 | + * This program is distributed in the hope that it will be useful, |
130 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
131 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
132 | + * GNU General Public License for more details. |
133 | + * |
134 | + * You should have received a copy of the GNU General Public License |
135 | + * along with this program; if not, write to the Free Software |
136 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
137 | + * |
138 | + */ |
139 | + |
140 | +/** |
141 | + * SECTION:bluetooth-killswitch |
142 | + * @short_description: a Bluetooth killswitch object |
143 | + * @stability: Stable |
144 | + * @include: bluetooth-killswitch.h |
145 | + * |
146 | + * An object to manipulate Bluetooth killswitches. |
147 | + **/ |
148 | + |
149 | +#ifdef HAVE_CONFIG_H |
150 | +#include <config.h> |
151 | +#endif |
152 | + |
153 | +#include <errno.h> |
154 | +#include <sys/types.h> |
155 | +#include <string.h> |
156 | +#include <glib.h> |
157 | + |
158 | +#include "bluetooth-killswitch.h" |
159 | +#include "rfkill-glib.h" |
160 | + |
161 | +enum { |
162 | + STATE_CHANGED, |
163 | + LAST_SIGNAL |
164 | +}; |
165 | + |
166 | +static int signals[LAST_SIGNAL] = { 0 }; |
167 | + |
168 | +#define BLUETOOTH_KILLSWITCH_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ |
169 | + BLUETOOTH_TYPE_KILLSWITCH, BluetoothKillswitchPrivate)) |
170 | + |
171 | +typedef struct _BluetoothIndKillswitch BluetoothIndKillswitch; |
172 | +struct _BluetoothIndKillswitch { |
173 | + guint index; |
174 | + BluetoothKillswitchState state; |
175 | +}; |
176 | + |
177 | +struct _BluetoothKillswitchPrivate { |
178 | + RfkillGlib *rfkill; |
179 | + gboolean in_init; |
180 | + GList *killswitches; /* a GList of BluetoothIndKillswitch */ |
181 | + BluetoothKillswitchPrivate *priv; |
182 | +}; |
183 | + |
184 | +G_DEFINE_TYPE(BluetoothKillswitch, bluetooth_killswitch, G_TYPE_OBJECT) |
185 | + |
186 | +static BluetoothKillswitchState |
187 | +event_to_state (guint soft, guint hard) |
188 | +{ |
189 | + if (hard) |
190 | + return BLUETOOTH_KILLSWITCH_STATE_HARD_BLOCKED; |
191 | + else if (soft) |
192 | + return BLUETOOTH_KILLSWITCH_STATE_SOFT_BLOCKED; |
193 | + else |
194 | + return BLUETOOTH_KILLSWITCH_STATE_UNBLOCKED; |
195 | +} |
196 | + |
197 | +static const char * |
198 | +state_to_string (BluetoothKillswitchState state) |
199 | +{ |
200 | + switch (state) { |
201 | + case BLUETOOTH_KILLSWITCH_STATE_NO_ADAPTER: |
202 | + return "no-adapter"; |
203 | + case BLUETOOTH_KILLSWITCH_STATE_SOFT_BLOCKED: |
204 | + return "soft-blocked"; |
205 | + case BLUETOOTH_KILLSWITCH_STATE_UNBLOCKED: |
206 | + return "unblocked"; |
207 | + case BLUETOOTH_KILLSWITCH_STATE_HARD_BLOCKED: |
208 | + return "hard-blocked"; |
209 | + default: |
210 | + g_assert_not_reached (); |
211 | + } |
212 | +} |
213 | + |
214 | +const char * |
215 | +bluetooth_killswitch_state_to_string (BluetoothKillswitchState state) |
216 | +{ |
217 | + g_return_val_if_fail (state >= BLUETOOTH_KILLSWITCH_STATE_NO_ADAPTER, NULL); |
218 | + g_return_val_if_fail (state <= BLUETOOTH_KILLSWITCH_STATE_HARD_BLOCKED, NULL); |
219 | + |
220 | + return state_to_string (state); |
221 | +} |
222 | + |
223 | +static void |
224 | +update_killswitch (BluetoothKillswitch *killswitch, |
225 | + guint index, guint soft, guint hard) |
226 | +{ |
227 | + BluetoothKillswitchPrivate *priv; |
228 | + gboolean changed; |
229 | + GList *l; |
230 | + |
231 | + priv = killswitch->priv; |
232 | + changed = FALSE; |
233 | + |
234 | + for (l = priv->killswitches; l != NULL; l = l->next) { |
235 | + BluetoothIndKillswitch *ind = l->data; |
236 | + |
237 | + if (ind->index == index) { |
238 | + BluetoothKillswitchState state = event_to_state (soft, hard); |
239 | + if (state != ind->state) { |
240 | + ind->state = state; |
241 | + changed = TRUE; |
242 | + } |
243 | + break; |
244 | + } |
245 | + } |
246 | + |
247 | + if (changed != FALSE) { |
248 | + g_debug ("updating killswitch status %d to %s", |
249 | + index, state_to_string (bluetooth_killswitch_get_state (killswitch))); |
250 | + g_signal_emit (G_OBJECT (killswitch), |
251 | + signals[STATE_CHANGED], |
252 | + 0, bluetooth_killswitch_get_state (killswitch)); |
253 | + } |
254 | +} |
255 | + |
256 | +void |
257 | +bluetooth_killswitch_set_state (BluetoothKillswitch *killswitch, |
258 | + BluetoothKillswitchState state) |
259 | +{ |
260 | + BluetoothKillswitchPrivate *priv; |
261 | + struct rfkill_event event; |
262 | + ssize_t len; |
263 | + |
264 | + g_return_if_fail (BLUETOOTH_IS_KILLSWITCH (killswitch)); |
265 | + g_return_if_fail (state != BLUETOOTH_KILLSWITCH_STATE_HARD_BLOCKED); |
266 | + |
267 | + priv = killswitch->priv; |
268 | + |
269 | + memset (&event, 0, sizeof(event)); |
270 | + event.op = RFKILL_OP_CHANGE_ALL; |
271 | + event.type = RFKILL_TYPE_BLUETOOTH; |
272 | + if (state == BLUETOOTH_KILLSWITCH_STATE_SOFT_BLOCKED) |
273 | + event.soft = 1; |
274 | + else if (state == BLUETOOTH_KILLSWITCH_STATE_UNBLOCKED) |
275 | + event.soft = 0; |
276 | + else |
277 | + g_assert_not_reached (); |
278 | + |
279 | + len = rfkill_glib_send_event (priv->rfkill, &event); |
280 | + if (len < 0) |
281 | + g_warning ("Failed to change RFKILL state: %s", |
282 | + g_strerror (errno)); |
283 | +} |
284 | + |
285 | +BluetoothKillswitchState |
286 | +bluetooth_killswitch_get_state (BluetoothKillswitch *killswitch) |
287 | +{ |
288 | + BluetoothKillswitchPrivate *priv; |
289 | + int state = BLUETOOTH_KILLSWITCH_STATE_UNBLOCKED; |
290 | + GList *l; |
291 | + |
292 | + g_return_val_if_fail (BLUETOOTH_IS_KILLSWITCH (killswitch), state); |
293 | + |
294 | + priv = killswitch->priv; |
295 | + |
296 | + if (priv->killswitches == NULL) |
297 | + return BLUETOOTH_KILLSWITCH_STATE_NO_ADAPTER; |
298 | + |
299 | + for (l = priv->killswitches ; l ; l = l->next) { |
300 | + BluetoothIndKillswitch *ind = l->data; |
301 | + |
302 | + g_debug ("killswitch %d is %s", |
303 | + ind->index, state_to_string (ind->state)); |
304 | + |
305 | + if (ind->state == BLUETOOTH_KILLSWITCH_STATE_HARD_BLOCKED) { |
306 | + state = BLUETOOTH_KILLSWITCH_STATE_HARD_BLOCKED; |
307 | + break; |
308 | + } |
309 | + |
310 | + if (ind->state == BLUETOOTH_KILLSWITCH_STATE_SOFT_BLOCKED) { |
311 | + state = BLUETOOTH_KILLSWITCH_STATE_SOFT_BLOCKED; |
312 | + continue; |
313 | + } |
314 | + |
315 | + state = ind->state; |
316 | + } |
317 | + |
318 | + g_debug ("killswitches state %s", state_to_string (state)); |
319 | + |
320 | + return state; |
321 | +} |
322 | + |
323 | +gboolean |
324 | +bluetooth_killswitch_has_killswitches (BluetoothKillswitch *killswitch) |
325 | +{ |
326 | + BluetoothKillswitchPrivate *priv = killswitch->priv; |
327 | + |
328 | + g_return_val_if_fail (BLUETOOTH_IS_KILLSWITCH (killswitch), FALSE); |
329 | + |
330 | + return (priv->killswitches != NULL); |
331 | +} |
332 | + |
333 | +static void |
334 | +remove_killswitch (BluetoothKillswitch *killswitch, |
335 | + guint index) |
336 | +{ |
337 | + BluetoothKillswitchPrivate *priv; |
338 | + GList *l; |
339 | + |
340 | + priv = killswitch->priv; |
341 | + |
342 | + for (l = priv->killswitches; l != NULL; l = l->next) { |
343 | + BluetoothIndKillswitch *ind = l->data; |
344 | + if (ind->index == index) { |
345 | + priv->killswitches = g_list_remove (priv->killswitches, ind); |
346 | + g_debug ("removing killswitch idx %d", index); |
347 | + g_free (ind); |
348 | + g_signal_emit (G_OBJECT (killswitch), |
349 | + signals[STATE_CHANGED], |
350 | + 0, bluetooth_killswitch_get_state (killswitch)); |
351 | + return; |
352 | + } |
353 | + } |
354 | +} |
355 | + |
356 | +static void |
357 | +add_killswitch (BluetoothKillswitch *killswitch, |
358 | + guint index, |
359 | + BluetoothKillswitchState state) |
360 | + |
361 | +{ |
362 | + BluetoothKillswitchPrivate *priv; |
363 | + BluetoothIndKillswitch *ind; |
364 | + |
365 | + priv = killswitch->priv; |
366 | + |
367 | + g_debug ("adding killswitch idx %d state %s", index, state_to_string (state)); |
368 | + ind = g_new0 (BluetoothIndKillswitch, 1); |
369 | + ind->index = index; |
370 | + ind->state = state; |
371 | + priv->killswitches = g_list_append (priv->killswitches, ind); |
372 | +} |
373 | + |
374 | +static void |
375 | +killswitch_changed (RfkillGlib *rfkill, |
376 | + GList *events, |
377 | + BluetoothKillswitch *killswitch) |
378 | +{ |
379 | + BluetoothKillswitchState state; |
380 | + gboolean changed; |
381 | + GList *l; |
382 | + |
383 | + if (killswitch->priv->in_init) { |
384 | + for (l = events; l != NULL; l = l->next) { |
385 | + struct rfkill_event *event = l->data; |
386 | + |
387 | + if (event->op != RFKILL_OP_ADD) |
388 | + continue; |
389 | + if (event->type != RFKILL_TYPE_BLUETOOTH) |
390 | + continue; |
391 | + |
392 | + state = event_to_state (event->soft, event->hard); |
393 | + |
394 | + g_debug ("Read killswitch (idx=%d): %s", |
395 | + event->idx, bluetooth_killswitch_state_to_string (state)); |
396 | + |
397 | + add_killswitch (killswitch, event->idx, state); |
398 | + } |
399 | + |
400 | + g_signal_emit (G_OBJECT (killswitch), |
401 | + signals[STATE_CHANGED], |
402 | + 0, bluetooth_killswitch_get_state (killswitch)); |
403 | + return; |
404 | + } |
405 | + |
406 | + changed = FALSE; |
407 | + |
408 | + /* Gather the previous killswitch so we can |
409 | + * see what really changed */ |
410 | + state = bluetooth_killswitch_get_state (killswitch); |
411 | + |
412 | + for (l = events; l != NULL; l = l->next) { |
413 | + struct rfkill_event *event = l->data; |
414 | + |
415 | + if (event->type != RFKILL_TYPE_BLUETOOTH && |
416 | + event->type != RFKILL_TYPE_ALL) |
417 | + continue; |
418 | + |
419 | + if (event->op == RFKILL_OP_CHANGE) { |
420 | + update_killswitch (killswitch, event->idx, event->soft, event->hard); |
421 | + /* No changed here because update_killswitch |
422 | + * handles sending the state-changed signal */ |
423 | + } else if (event->op == RFKILL_OP_DEL) { |
424 | + remove_killswitch (killswitch, event->idx); |
425 | + changed = TRUE; |
426 | + } else if (event->op == RFKILL_OP_ADD) { |
427 | + BluetoothKillswitchState state; |
428 | + state = event_to_state (event->soft, event->hard); |
429 | + add_killswitch (killswitch, event->idx, state); |
430 | + changed = TRUE; |
431 | + } |
432 | + } |
433 | + |
434 | + if (changed) { |
435 | + BluetoothKillswitchState new_state; |
436 | + |
437 | + new_state = bluetooth_killswitch_get_state (killswitch); |
438 | + if (new_state != state) { |
439 | + g_signal_emit (G_OBJECT (killswitch), |
440 | + signals[STATE_CHANGED], |
441 | + 0, bluetooth_killswitch_get_state (killswitch)); |
442 | + } |
443 | + } |
444 | +} |
445 | + |
446 | +static void |
447 | +bluetooth_killswitch_init (BluetoothKillswitch *killswitch) |
448 | +{ |
449 | + BluetoothKillswitchPrivate *priv; |
450 | + |
451 | + priv = BLUETOOTH_KILLSWITCH_GET_PRIVATE (killswitch); |
452 | + killswitch->priv = priv; |
453 | + |
454 | + priv->rfkill = rfkill_glib_new (); |
455 | + g_signal_connect (priv->rfkill, "changed", |
456 | + G_CALLBACK (killswitch_changed), killswitch); |
457 | + |
458 | + priv->in_init = TRUE; |
459 | + if (rfkill_glib_open (priv->rfkill) < 0) |
460 | + return; |
461 | + priv->in_init = FALSE; |
462 | +} |
463 | + |
464 | +static void |
465 | +bluetooth_killswitch_finalize (GObject *object) |
466 | +{ |
467 | + BluetoothKillswitch *killswitch; |
468 | + |
469 | + killswitch = BLUETOOTH_KILLSWITCH (object); |
470 | + |
471 | + g_clear_object (&killswitch->priv->rfkill); |
472 | + |
473 | + g_list_free_full (killswitch->priv->killswitches, g_free); |
474 | + killswitch->priv->killswitches = NULL; |
475 | + |
476 | + G_OBJECT_CLASS(bluetooth_killswitch_parent_class)->finalize(object); |
477 | +} |
478 | + |
479 | +static void |
480 | +bluetooth_killswitch_class_init(BluetoothKillswitchClass *klass) |
481 | +{ |
482 | + GObjectClass *object_class = (GObjectClass *) klass; |
483 | + |
484 | + g_type_class_add_private(klass, sizeof(BluetoothKillswitchPrivate)); |
485 | + object_class->finalize = bluetooth_killswitch_finalize; |
486 | + |
487 | + signals[STATE_CHANGED] = |
488 | + g_signal_new ("state-changed", |
489 | + G_TYPE_FROM_CLASS (klass), |
490 | + G_SIGNAL_RUN_LAST, |
491 | + G_STRUCT_OFFSET (BluetoothKillswitchClass, state_changed), |
492 | + NULL, NULL, |
493 | + g_cclosure_marshal_VOID__INT, |
494 | + G_TYPE_NONE, 1, G_TYPE_INT); |
495 | + |
496 | +} |
497 | + |
498 | +BluetoothKillswitch * |
499 | +bluetooth_killswitch_new (void) |
500 | +{ |
501 | + return BLUETOOTH_KILLSWITCH (g_object_new (BLUETOOTH_TYPE_KILLSWITCH, NULL)); |
502 | +} |
503 | |
504 | === added file 'panels/bluetooth/bluetooth-killswitch.h' |
505 | --- panels/bluetooth/bluetooth-killswitch.h 1970-01-01 00:00:00 +0000 |
506 | +++ panels/bluetooth/bluetooth-killswitch.h 2015-08-12 15:47:27 +0000 |
507 | @@ -0,0 +1,78 @@ |
508 | +/* |
509 | + * |
510 | + * BlueZ - Bluetooth protocol stack for Linux |
511 | + * |
512 | + * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org> |
513 | + * Copyright (C) 2006-2009 Bastien Nocera <hadess@hadess.net> |
514 | + * |
515 | + * |
516 | + * This program is free software; you can redistribute it and/or modify |
517 | + * it under the terms of the GNU General Public License as published by |
518 | + * the Free Software Foundation; either version 2 of the License, or |
519 | + * (at your option) any later version. |
520 | + * |
521 | + * This program is distributed in the hope that it will be useful, |
522 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
523 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
524 | + * GNU General Public License for more details. |
525 | + * |
526 | + * You should have received a copy of the GNU General Public License |
527 | + * along with this program; if not, write to the Free Software |
528 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
529 | + * |
530 | + */ |
531 | + |
532 | +#ifndef __BLUETOOTH_KILLSWITCH_H |
533 | +#define __BLUETOOTH_KILLSWITCH_H |
534 | + |
535 | +#include <glib-object.h> |
536 | + |
537 | +G_BEGIN_DECLS |
538 | + |
539 | +typedef enum { |
540 | + BLUETOOTH_KILLSWITCH_STATE_NO_ADAPTER = -1, |
541 | + BLUETOOTH_KILLSWITCH_STATE_SOFT_BLOCKED = 0, |
542 | + BLUETOOTH_KILLSWITCH_STATE_UNBLOCKED, |
543 | + BLUETOOTH_KILLSWITCH_STATE_HARD_BLOCKED |
544 | +} BluetoothKillswitchState; |
545 | + |
546 | +#define BLUETOOTH_TYPE_KILLSWITCH (bluetooth_killswitch_get_type()) |
547 | +#define BLUETOOTH_KILLSWITCH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ |
548 | + BLUETOOTH_TYPE_KILLSWITCH, BluetoothKillswitch)) |
549 | +#define BLUETOOTH_KILLSWITCH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \ |
550 | + BLUETOOTH_TYPE_KILLSWITCH, BluetoothKillswitchClass)) |
551 | +#define BLUETOOTH_IS_KILLSWITCH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \ |
552 | + BLUETOOTH_TYPE_KILLSWITCH)) |
553 | +#define BLUETOOTH_IS_KILLSWITCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \ |
554 | + BLUETOOTH_TYPE_KILLSWITCH)) |
555 | +#define BLUETOOTH_GET_KILLSWITCH_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \ |
556 | + BLUETOOTH_TYPE_KILLSWITCH, BluetoothKillswitchClass)) |
557 | + |
558 | +typedef struct _BluetoothKillswitch BluetoothKillswitch; |
559 | +typedef struct _BluetoothKillswitchClass BluetoothKillswitchClass; |
560 | +typedef struct _BluetoothKillswitchPrivate BluetoothKillswitchPrivate; |
561 | + |
562 | +struct _BluetoothKillswitch { |
563 | + GObject parent; |
564 | + BluetoothKillswitchPrivate *priv; |
565 | +}; |
566 | + |
567 | +struct _BluetoothKillswitchClass { |
568 | + GObjectClass parent_class; |
569 | + |
570 | + void (*state_changed) (BluetoothKillswitch *killswitch, BluetoothKillswitchState state); |
571 | +}; |
572 | + |
573 | +GType bluetooth_killswitch_get_type(void); |
574 | + |
575 | +BluetoothKillswitch * bluetooth_killswitch_new (void); |
576 | + |
577 | +gboolean bluetooth_killswitch_has_killswitches (BluetoothKillswitch *killswitch); |
578 | +void bluetooth_killswitch_set_state (BluetoothKillswitch *killswitch, |
579 | + BluetoothKillswitchState state); |
580 | +BluetoothKillswitchState bluetooth_killswitch_get_state (BluetoothKillswitch *killswitch); |
581 | +const char *bluetooth_killswitch_state_to_string (BluetoothKillswitchState state); |
582 | + |
583 | +G_END_DECLS |
584 | + |
585 | +#endif /* __BLUETOOTH_KILLSWITCH_H */ |
586 | |
587 | === modified file 'panels/bluetooth/cc-bluetooth-panel.c' |
588 | --- panels/bluetooth/cc-bluetooth-panel.c 2015-04-02 04:53:12 +0000 |
589 | +++ panels/bluetooth/cc-bluetooth-panel.c 2015-08-12 15:47:27 +0000 |
590 | @@ -35,7 +35,6 @@ |
591 | #include <bluetooth-utils.h> |
592 | #include <bluetooth-killswitch.h> |
593 | #include <bluetooth-chooser.h> |
594 | -#include <bluetooth-plugin-manager.h> |
595 | |
596 | CC_PANEL_REGISTER (CcBluetoothPanel, cc_bluetooth_panel) |
597 | |
598 | @@ -102,8 +101,6 @@ |
599 | { |
600 | CcBluetoothPanel *self; |
601 | |
602 | - bluetooth_plugin_manager_cleanup (); |
603 | - |
604 | self = CC_BLUETOOTH_PANEL (object); |
605 | g_cancellable_cancel (self->priv->cancellable); |
606 | g_clear_object (&self->priv->cancellable); |
607 | @@ -260,37 +257,6 @@ |
608 | } |
609 | |
610 | static void |
611 | -add_extra_setup_widgets (CcBluetoothPanel *self, |
612 | - const char *bdaddr) |
613 | -{ |
614 | - GValue value = { 0 }; |
615 | - char **uuids; |
616 | - GList *list, *l; |
617 | - GtkWidget *container; |
618 | - |
619 | - if (bluetooth_chooser_get_selected_device_info (BLUETOOTH_CHOOSER (self->priv->chooser), |
620 | - "uuids", &value) == FALSE) |
621 | - return; |
622 | - |
623 | - uuids = (char **) g_value_get_boxed (&value); |
624 | - list = bluetooth_plugin_manager_get_widgets (bdaddr, (const char **) uuids); |
625 | - if (list == NULL) { |
626 | - g_value_unset (&value); |
627 | - return; |
628 | - } |
629 | - |
630 | - container = WID ("additional_setup_box"); |
631 | - for (l = list; l != NULL; l = l->next) { |
632 | - GtkWidget *widget = l->data; |
633 | - gtk_box_pack_start (GTK_BOX (container), widget, |
634 | - FALSE, FALSE, 0); |
635 | - gtk_widget_show_all (widget); |
636 | - } |
637 | - gtk_widget_show (container); |
638 | - g_value_unset (&value); |
639 | -} |
640 | - |
641 | -static void |
642 | remove_extra_setup_widgets (CcBluetoothPanel *self) |
643 | { |
644 | GtkWidget *box; |
645 | @@ -397,10 +363,6 @@ |
646 | ; |
647 | } |
648 | |
649 | - /* Extra widgets */ |
650 | - if (g_strcmp0 (self->priv->selected_bdaddr, bdaddr) != 0) |
651 | - add_extra_setup_widgets (self, bdaddr); |
652 | - |
653 | gtk_label_set_text (GTK_LABEL (WID ("address_label")), bdaddr); |
654 | |
655 | gtk_widget_set_sensitive (WID ("button_delete"), TRUE); |
656 | @@ -544,34 +506,6 @@ |
657 | g_free (alias); |
658 | } |
659 | |
660 | -static void |
661 | -mount_finish_cb (GObject *source_object, |
662 | - GAsyncResult *res, |
663 | - gpointer user_data) |
664 | -{ |
665 | - GError *error = NULL; |
666 | - |
667 | - if (bluetooth_browse_address_finish (source_object, res, &error) == FALSE) { |
668 | - g_printerr ("Failed to mount OBEX volume: %s", error->message); |
669 | - g_error_free (error); |
670 | - return; |
671 | - } |
672 | -} |
673 | - |
674 | -static void |
675 | -browse_callback (GtkButton *button, |
676 | - CcBluetoothPanel *self) |
677 | -{ |
678 | - char *bdaddr; |
679 | - |
680 | - bdaddr = bluetooth_chooser_get_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser)); |
681 | - |
682 | - bluetooth_browse_address (G_OBJECT (self), bdaddr, |
683 | - GDK_CURRENT_TIME, mount_finish_cb, NULL); |
684 | - |
685 | - g_free (bdaddr); |
686 | -} |
687 | - |
688 | /* Visibility/Discoverable */ |
689 | static void discoverable_changed (BluetoothClient *client, |
690 | GParamSpec *spec, |
691 | @@ -693,7 +627,7 @@ |
692 | NULL, |
693 | "org.bluez", |
694 | adapter, |
695 | - "org.bluez.Adapter", |
696 | + "org.bluez.Adapter1", |
697 | NULL, |
698 | &error); |
699 | g_free (adapter); |
700 | @@ -736,10 +670,8 @@ |
701 | |
702 | name = bluetooth_chooser_get_selected_device_name (BLUETOOTH_CHOOSER (self->priv->chooser)); |
703 | |
704 | - if (show_confirm_dialog (self, name) != FALSE) { |
705 | - if (remove_selected_device (self)) |
706 | - bluetooth_plugin_manager_device_deleted (address); |
707 | - } |
708 | + if (show_confirm_dialog (self, name) != FALSE) |
709 | + remove_selected_device (self); |
710 | |
711 | g_free (address); |
712 | g_free (name); |
713 | @@ -828,7 +760,6 @@ |
714 | self->priv = BLUETOOTH_PANEL_PRIVATE (self); |
715 | g_resources_register (cc_bluetooth_get_resource ()); |
716 | |
717 | - bluetooth_plugin_manager_init (); |
718 | self->priv->cancellable = g_cancellable_new (); |
719 | self->priv->killswitch = bluetooth_killswitch_new (); |
720 | self->priv->client = bluetooth_client_new (); |
721 | @@ -914,8 +845,6 @@ |
722 | G_CALLBACK (keyboard_callback), self); |
723 | g_signal_connect (G_OBJECT (WID ("sound_link")), "activate-link", |
724 | G_CALLBACK (sound_callback), self); |
725 | - g_signal_connect (G_OBJECT (WID ("browse_button")), "clicked", |
726 | - G_CALLBACK (browse_callback), self); |
727 | g_signal_connect (G_OBJECT (WID ("send_button")), "clicked", |
728 | G_CALLBACK (send_callback), self); |
729 | g_signal_connect (G_OBJECT (WID ("switch_connection")), "notify::active", |
730 | |
731 | === added directory 'panels/bluetooth/gnome-bluetooth' |
732 | === added file 'panels/bluetooth/gnome-bluetooth/Makefile.am' |
733 | --- panels/bluetooth/gnome-bluetooth/Makefile.am 1970-01-01 00:00:00 +0000 |
734 | +++ panels/bluetooth/gnome-bluetooth/Makefile.am 2015-08-12 15:47:27 +0000 |
735 | @@ -0,0 +1,1 @@ |
736 | +SUBDIRS = lib wizard |
737 | |
738 | === added directory 'panels/bluetooth/gnome-bluetooth/lib' |
739 | === added file 'panels/bluetooth/gnome-bluetooth/lib/Makefile.am' |
740 | --- panels/bluetooth/gnome-bluetooth/lib/Makefile.am 1970-01-01 00:00:00 +0000 |
741 | +++ panels/bluetooth/gnome-bluetooth/lib/Makefile.am 2015-08-12 15:47:27 +0000 |
742 | @@ -0,0 +1,99 @@ |
743 | +EXTRA_DIST = |
744 | +CLEANFILES = |
745 | + |
746 | +lib_LTLIBRARIES = libgnome-bluetooth.la |
747 | + |
748 | +# will be scanned for introspection annotation, but won't be installed |
749 | +libgnome_bluetooth_c_sources = \ |
750 | + bluetooth-client.c \ |
751 | + bluetooth-utils.c \ |
752 | + bluetooth-agent.c \ |
753 | + gnome-bluetooth-enum-types.c \ |
754 | + bluetooth-chooser.c \ |
755 | + bluetooth-filter-widget.c \ |
756 | + bluetooth-chooser-button.c \ |
757 | + bluetooth-chooser-combo.c \ |
758 | + bluetooth-client-glue.c \ |
759 | + bluetooth-fdo-glue.c |
760 | + |
761 | +libgnome_bluetooth_private_headers = \ |
762 | + bluetooth-client-private.h \ |
763 | + bluetooth-agent.h \ |
764 | + gnome-bluetooth-enum-types.h \ |
765 | + bluetooth-chooser-private.h \ |
766 | + bluetooth-client-glue.h \ |
767 | + bluetooth-fdo-glue.h |
768 | + |
769 | +# public headers don't need to be listed, are handled by _HEADERS |
770 | +libgnome_bluetooth_la_SOURCES = \ |
771 | + $(libgnome_bluetooth_private_headers) \ |
772 | + $(libgnome_bluetooth_c_sources) |
773 | + |
774 | +libgnome_bluetooth_la_LIBADD = $(BLUETOOTH_PANEL_LIBS) |
775 | + |
776 | +libgnome_bluetooth_introspect_headers = \ |
777 | + bluetooth-client.h \ |
778 | + bluetooth-chooser.h \ |
779 | + bluetooth-chooser-button.h \ |
780 | + bluetooth-chooser-combo.h \ |
781 | + bluetooth-filter-widget.h \ |
782 | + bluetooth-enums.h \ |
783 | + bluetooth-utils.h |
784 | + |
785 | +gnomebluetoothdir = $(pkgincludedir) |
786 | +gnomebluetooth_HEADERS = $(libgnome_bluetooth_introspect_headers) |
787 | + |
788 | +AM_CFLAGS = \ |
789 | + -I$(srcdir) \ |
790 | + $(BLUETOOTH_PANEL_CFLAGS) \ |
791 | + $(WARN_CFLAGS) \ |
792 | + $(DISABLE_DEPRECATED) \ |
793 | + -DG_LOG_DOMAIN=\"Bluetooth\" |
794 | + |
795 | +BUILT_SOURCES = bluetooth-client-glue.h \ |
796 | + bluetooth-client-glue.c \ |
797 | + bluetooth-fdo-glue.h \ |
798 | + bluetooth-fdo-glue.c \ |
799 | + gnome-bluetooth-enum-types.h \ |
800 | + gnome-bluetooth-enum-types.c |
801 | + |
802 | +CLEANFILES += $(BUILT_SOURCES) |
803 | + |
804 | +EXTRA_DIST += bluetooth-client.xml bluetooth-fdo.xml |
805 | + |
806 | +MAINTAINERCLEANFILES = Makefile.in |
807 | + |
808 | +bluetooth-client-glue.c: bluetooth-client-glue.h |
809 | + |
810 | +bluetooth-client-glue.c bluetooth-client-glue.h: bluetooth-client.xml |
811 | + $(AM_V_GEN) gdbus-codegen --c-namespace= --generate-c-code=bluetooth-client-glue --interface-prefix=org.bluez $< |
812 | + |
813 | +bluetooth-fdo-glue.c: bluetooth-fdo-glue.h |
814 | + |
815 | +bluetooth-fdo-glue.c bluetooth-fdo-glue.h: bluetooth-fdo.xml |
816 | + $(AM_V_GEN) gdbus-codegen --c-namespace= --generate-c-code=bluetooth-fdo-glue --interface-prefix=org.freedesktop.DBus $< |
817 | + |
818 | +gnome_bluetooth_headers_to_scan_for_enums = bluetooth-enums.h |
819 | +# Generate the enums source code, with glib-mkenums: |
820 | +# This is based on the same Makefile.am stuff in pango: |
821 | +gnome_bluetooth_built_headers = gnome-bluetooth-enum-types.h |
822 | +gnome_bluetooth_built_cfiles = gnome-bluetooth-enum-types.c |
823 | + |
824 | +gnome-bluetooth-enum-types.h: $(gnome_bluetooth_headers_to_scan_for_enums) Makefile |
825 | + $(AM_V_GEN) (cd $(srcdir) && glib-mkenums \ |
826 | + --fhead "#ifndef __GNOME_BLUETOOTH_ENUM_TYPES_H__\n#define __GNOME_BLUETOOTH_ENUM_TYPES_H__\n\n#include <glib-object.h>\n\nG_BEGIN_DECLS\n" \ |
827 | + --fprod "/* enumerations from \"@filename@\" */\n" \ |
828 | + --vhead "GType @enum_name@_get_type (void);\n#define BLUETOOTH_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n" \ |
829 | + --ftail "G_END_DECLS\n\n#endif /* __GNOME_BLUETOOTH_ENUM_TYPES_H__ */" \ |
830 | + $(gnome_bluetooth_headers_to_scan_for_enums)) > $@ |
831 | + |
832 | +gnome-bluetooth-enum-types.c: $(gnome_bluetooth_headers_to_scan_for_enums) Makefile gnome-bluetooth-enum-types.h |
833 | + $(AM_V_GEN) (cd $(srcdir) && glib-mkenums \ |
834 | + --fhead "#include <bluetooth-enums.h>\n" \ |
835 | + --fhead "#include \"gnome-bluetooth-enum-types.h\"\n" \ |
836 | + --fhead "#include <glib-object.h>" \ |
837 | + --fprod "\n/* enumerations from \"@filename@\" */" \ |
838 | + --vhead "GType\n@enum_name@_get_type (void)\n{\n static GType etype = 0;\n if (etype == 0) {\n static const G@Type@Value values[] = {" \ |
839 | + --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \ |
840 | + --vtail " { 0, NULL, NULL }\n };\n etype = g_@type@_register_static (\"@EnumName@\", values);\n }\n return etype;\n}\n" \ |
841 | + $(gnome_bluetooth_headers_to_scan_for_enums)) > $@ |
842 | |
843 | === added file 'panels/bluetooth/gnome-bluetooth/lib/bluetooth-agent.c' |
844 | --- panels/bluetooth/gnome-bluetooth/lib/bluetooth-agent.c 1970-01-01 00:00:00 +0000 |
845 | +++ panels/bluetooth/gnome-bluetooth/lib/bluetooth-agent.c 2015-08-12 15:47:27 +0000 |
846 | @@ -0,0 +1,681 @@ |
847 | +/* |
848 | + * |
849 | + * BlueZ - Bluetooth protocol stack for Linux |
850 | + * |
851 | + * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org> |
852 | + * |
853 | + * |
854 | + * This library is free software; you can redistribute it and/or |
855 | + * modify it under the terms of the GNU Lesser General Public |
856 | + * License as published by the Free Software Foundation; either |
857 | + * version 2.1 of the License, or (at your option) any later version. |
858 | + * |
859 | + * This library is distributed in the hope that it will be useful, |
860 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
861 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
862 | + * Lesser General Public License for more details. |
863 | + * |
864 | + * You should have received a copy of the GNU Lesser General Public |
865 | + * License along with this library; if not, write to the Free Software |
866 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
867 | + * |
868 | + */ |
869 | + |
870 | +#ifdef HAVE_CONFIG_H |
871 | +#include <config.h> |
872 | +#endif |
873 | + |
874 | +#include <stdio.h> |
875 | +#include <gio/gio.h> |
876 | + |
877 | +#include "bluetooth-client-glue.h" |
878 | +#include "bluetooth-fdo-glue.h" |
879 | +#include "bluetooth-agent.h" |
880 | + |
881 | +#define BLUEZ_SERVICE "org.bluez" |
882 | +#define BLUEZ_AGENT_PATH "/org/bluez/agent/gnome" |
883 | +#define BLUEZ_MANAGER_PATH "/" |
884 | + |
885 | +static const gchar introspection_xml[] = |
886 | +"<node name='/'>" |
887 | +" <interface name='org.bluez.Agent1'>" |
888 | +" <method name='Release'/>" |
889 | +" <method name='RequestPinCode'>" |
890 | +" <arg type='o' name='device' direction='in'/>" |
891 | +" <arg type='s' name='pincode' direction='out'/>" |
892 | +" </method>" |
893 | +" <method name='RequestPasskey'>" |
894 | +" <arg type='o' name='device' direction='in'/>" |
895 | +" <arg type='u' name='passkey' direction='out'/>" |
896 | +" </method>" |
897 | +" <method name='DisplayPasskey'>" |
898 | +" <arg type='o' name='device' direction='in'/>" |
899 | +" <arg type='u' name='passkey' direction='in'/>" |
900 | +" <arg type='y' name='entered' direction='in'/>" |
901 | +" </method>" |
902 | +" <method name='DisplayPinCode'>" |
903 | +" <arg type='o' name='device' direction='in'/>" |
904 | +" <arg type='s' name='pincode' direction='in'/>" |
905 | +" </method>" |
906 | +" <method name='RequestConfirmation'>" |
907 | +" <arg type='o' name='device' direction='in'/>" |
908 | +" <arg type='u' name='passkey' direction='in'/>" |
909 | +" </method>" |
910 | +" <method name='RequestAuthorization'>" |
911 | +" <arg type='o' name='device' direction='in'/>" |
912 | +" </method>" |
913 | +" <method name='AuthorizeService'>" |
914 | +" <arg type='o' name='device' direction='in'/>" |
915 | +" <arg type='s' name='uuid' direction='in'/>" |
916 | +" </method>" |
917 | +" <method name='Cancel'/>" |
918 | +" </interface>" |
919 | +"</node>"; |
920 | + |
921 | +#define BLUETOOTH_AGENT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ |
922 | + BLUETOOTH_TYPE_AGENT, BluetoothAgentPrivate)) |
923 | + |
924 | +typedef struct _BluetoothAgentPrivate BluetoothAgentPrivate; |
925 | + |
926 | +struct _BluetoothAgentPrivate { |
927 | + GDBusConnection *conn; |
928 | + gchar *busname; |
929 | + gchar *path; |
930 | + AgentManager1 *agent_manager; |
931 | + GDBusNodeInfo *introspection_data; |
932 | + guint reg_id; |
933 | + guint watch_id; |
934 | + |
935 | + BluetoothAgentPasskeyFunc pincode_func; |
936 | + gpointer pincode_data; |
937 | + |
938 | + BluetoothAgentDisplayFunc display_func; |
939 | + gpointer display_data; |
940 | + |
941 | + BluetoothAgentDisplayPinCodeFunc display_pincode_func; |
942 | + gpointer display_pincode_data; |
943 | + |
944 | + BluetoothAgentPasskeyFunc passkey_func; |
945 | + gpointer passkey_data; |
946 | + |
947 | + BluetoothAgentConfirmFunc confirm_func; |
948 | + gpointer confirm_data; |
949 | + |
950 | + BluetoothAgentAuthorizeFunc authorize_func; |
951 | + gpointer authorize_data; |
952 | + |
953 | + BluetoothAgentAuthorizeServiceFunc authorize_service_func; |
954 | + gpointer authorize_service_data; |
955 | + |
956 | + BluetoothAgentCancelFunc cancel_func; |
957 | + gpointer cancel_data; |
958 | +}; |
959 | + |
960 | +static GDBusProxy *get_device_from_path (const char *path) |
961 | +{ |
962 | + Device1 *device; |
963 | + device = device1_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, |
964 | + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, |
965 | + BLUEZ_SERVICE, |
966 | + path, |
967 | + NULL, |
968 | + NULL); |
969 | + |
970 | + return G_DBUS_PROXY(device); |
971 | +} |
972 | + |
973 | +G_DEFINE_TYPE(BluetoothAgent, bluetooth_agent, G_TYPE_OBJECT) |
974 | + |
975 | +static gboolean bluetooth_agent_request_pincode(BluetoothAgent *agent, |
976 | + const char *path, GDBusMethodInvocation *invocation) |
977 | +{ |
978 | + BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
979 | + GDBusProxy *device; |
980 | + |
981 | + if (priv->pincode_func == NULL) |
982 | + return FALSE; |
983 | + |
984 | + device = get_device_from_path(path); |
985 | + if (device == NULL) |
986 | + return FALSE; |
987 | + |
988 | + priv->pincode_func(invocation, device, priv->pincode_data); |
989 | + |
990 | + g_object_unref(device); |
991 | + |
992 | + return TRUE; |
993 | +} |
994 | + |
995 | +static gboolean bluetooth_agent_request_passkey(BluetoothAgent *agent, |
996 | + const char *path, GDBusMethodInvocation *invocation) |
997 | +{ |
998 | + BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
999 | + GDBusProxy *device; |
1000 | + |
1001 | + if (priv->passkey_func == NULL) |
1002 | + return FALSE; |
1003 | + |
1004 | + device = get_device_from_path(path); |
1005 | + if (device == NULL) |
1006 | + return FALSE; |
1007 | + |
1008 | + priv->passkey_func(invocation, device, priv->passkey_data); |
1009 | + |
1010 | + g_object_unref(device); |
1011 | + |
1012 | + return TRUE; |
1013 | +} |
1014 | + |
1015 | +static gboolean bluetooth_agent_display_passkey(BluetoothAgent *agent, |
1016 | + const char *path, guint passkey, guint8 entered, |
1017 | + GDBusMethodInvocation *invocation) |
1018 | +{ |
1019 | + BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
1020 | + GDBusProxy *device; |
1021 | + |
1022 | + if (priv->display_func == NULL) |
1023 | + return FALSE; |
1024 | + |
1025 | + device = get_device_from_path(path); |
1026 | + if (device == NULL) |
1027 | + return FALSE; |
1028 | + |
1029 | + priv->display_func(invocation, device, passkey, entered, |
1030 | + priv->display_data); |
1031 | + |
1032 | + g_object_unref(device); |
1033 | + |
1034 | + return TRUE; |
1035 | +} |
1036 | + |
1037 | +static gboolean bluetooth_agent_display_pincode(BluetoothAgent *agent, |
1038 | + const char *path, const char *pincode, |
1039 | + GDBusMethodInvocation *invocation) |
1040 | +{ |
1041 | + BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
1042 | + GDBusProxy *device; |
1043 | + |
1044 | + if (priv->display_pincode_func == NULL) |
1045 | + return FALSE; |
1046 | + |
1047 | + device = get_device_from_path(path); |
1048 | + if (device == NULL) |
1049 | + return FALSE; |
1050 | + |
1051 | + priv->display_pincode_func(invocation, device, pincode, |
1052 | + priv->display_data); |
1053 | + |
1054 | + g_object_unref(device); |
1055 | + |
1056 | + return TRUE; |
1057 | +} |
1058 | + |
1059 | +static gboolean bluetooth_agent_request_confirmation(BluetoothAgent *agent, |
1060 | + const char *path, guint passkey, |
1061 | + GDBusMethodInvocation *invocation) |
1062 | +{ |
1063 | + BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
1064 | + GDBusProxy *device; |
1065 | + |
1066 | + if (priv->confirm_func == NULL) |
1067 | + return FALSE; |
1068 | + |
1069 | + device = get_device_from_path(path); |
1070 | + if (device == NULL) |
1071 | + return FALSE; |
1072 | + |
1073 | + priv->confirm_func(invocation, device, passkey, priv->confirm_data); |
1074 | + |
1075 | + g_object_unref(device); |
1076 | + |
1077 | + return TRUE; |
1078 | +} |
1079 | + |
1080 | +static gboolean bluetooth_agent_request_authorization(BluetoothAgent *agent, |
1081 | + const char *path, GDBusMethodInvocation *invocation) |
1082 | +{ |
1083 | + BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
1084 | + GDBusProxy *device; |
1085 | + |
1086 | + if (priv->authorize_func == NULL) |
1087 | + return FALSE; |
1088 | + |
1089 | + device = get_device_from_path(path); |
1090 | + if (device == NULL) |
1091 | + return FALSE; |
1092 | + |
1093 | + priv->authorize_func(invocation, device, priv->authorize_data); |
1094 | + |
1095 | + g_object_unref(device); |
1096 | + |
1097 | + return TRUE; |
1098 | +} |
1099 | + |
1100 | +static gboolean bluetooth_agent_authorize_service(BluetoothAgent *agent, |
1101 | + const char *path, const char *uuid, |
1102 | + GDBusMethodInvocation *invocation) |
1103 | +{ |
1104 | + BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
1105 | + GDBusProxy *device; |
1106 | + |
1107 | + if (priv->authorize_service_func == NULL) |
1108 | + return FALSE; |
1109 | + |
1110 | + device = get_device_from_path(path); |
1111 | + if (device == NULL) |
1112 | + return FALSE; |
1113 | + |
1114 | + priv->authorize_service_func(invocation, device, uuid, |
1115 | + priv->authorize_service_data); |
1116 | + |
1117 | + g_object_unref(device); |
1118 | + |
1119 | + return TRUE; |
1120 | +} |
1121 | + |
1122 | +static gboolean bluetooth_agent_cancel(BluetoothAgent *agent, |
1123 | + GDBusMethodInvocation *invocation) |
1124 | +{ |
1125 | + BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
1126 | + |
1127 | + if (priv->cancel_func == NULL) |
1128 | + return FALSE; |
1129 | + |
1130 | + return priv->cancel_func(invocation, priv->cancel_data); |
1131 | +} |
1132 | + |
1133 | +static void |
1134 | +name_appeared_cb (GDBusConnection *connection, |
1135 | + const gchar *name, |
1136 | + const gchar *name_owner, |
1137 | + BluetoothAgent *agent) |
1138 | +{ |
1139 | + BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
1140 | + |
1141 | + g_free (priv->busname); |
1142 | + priv->busname = g_strdup (name_owner); |
1143 | +} |
1144 | + |
1145 | +static void |
1146 | +name_vanished_cb (GDBusConnection *connection, |
1147 | + const gchar *name, |
1148 | + BluetoothAgent *agent) |
1149 | +{ |
1150 | + BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
1151 | + |
1152 | + g_free (priv->busname); |
1153 | + priv->busname = NULL; |
1154 | +} |
1155 | + |
1156 | +static void bluetooth_agent_init(BluetoothAgent *agent) |
1157 | +{ |
1158 | + BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
1159 | + |
1160 | + priv->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); |
1161 | + g_assert (priv->introspection_data); |
1162 | + priv->conn = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); |
1163 | + priv->watch_id = g_bus_watch_name_on_connection (priv->conn, |
1164 | + BLUEZ_SERVICE, |
1165 | + G_BUS_NAME_WATCHER_FLAGS_NONE, |
1166 | + (GBusNameAppearedCallback) name_appeared_cb, |
1167 | + (GBusNameVanishedCallback) name_vanished_cb, |
1168 | + agent, |
1169 | + NULL); |
1170 | +} |
1171 | + |
1172 | +static void bluetooth_agent_finalize(GObject *agent) |
1173 | +{ |
1174 | + BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
1175 | + |
1176 | + bluetooth_agent_unregister (BLUETOOTH_AGENT (agent)); |
1177 | + |
1178 | + g_bus_unwatch_name (priv->watch_id); |
1179 | + g_free (priv->busname); |
1180 | + g_dbus_node_info_unref (priv->introspection_data); |
1181 | + g_object_unref (priv->conn); |
1182 | + |
1183 | + G_OBJECT_CLASS(bluetooth_agent_parent_class)->finalize(agent); |
1184 | +} |
1185 | + |
1186 | +static void bluetooth_agent_class_init(BluetoothAgentClass *klass) |
1187 | +{ |
1188 | + GObjectClass *object_class = (GObjectClass *) klass; |
1189 | + |
1190 | + g_type_class_add_private(klass, sizeof(BluetoothAgentPrivate)); |
1191 | + |
1192 | + object_class->finalize = bluetooth_agent_finalize; |
1193 | +} |
1194 | + |
1195 | +BluetoothAgent * |
1196 | +bluetooth_agent_new (void) |
1197 | +{ |
1198 | + return BLUETOOTH_AGENT (g_object_new (BLUETOOTH_TYPE_AGENT, NULL)); |
1199 | +} |
1200 | + |
1201 | +static void |
1202 | +handle_method_call (GDBusConnection *connection, |
1203 | + const gchar *sender, |
1204 | + const gchar *object_path, |
1205 | + const gchar *interface_name, |
1206 | + const gchar *method_name, |
1207 | + GVariant *parameters, |
1208 | + GDBusMethodInvocation *invocation, |
1209 | + gpointer user_data) |
1210 | +{ |
1211 | + BluetoothAgent *agent = (BluetoothAgent *) user_data; |
1212 | + BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
1213 | + |
1214 | + if (g_str_equal (sender, priv->busname) == FALSE) { |
1215 | + GError *error = NULL; |
1216 | + error = g_error_new (AGENT_ERROR, AGENT_ERROR_REJECT, |
1217 | + "Permission Denied"); |
1218 | + g_dbus_method_invocation_take_error(invocation, error); |
1219 | + return; |
1220 | + } |
1221 | + |
1222 | + if (g_strcmp0 (method_name, "Release") == 0) { |
1223 | + g_dbus_method_invocation_return_value (invocation, NULL); |
1224 | + } else if (g_strcmp0 (method_name, "RequestPinCode") == 0) { |
1225 | + char *path; |
1226 | + g_variant_get (parameters, "(o)", &path); |
1227 | + bluetooth_agent_request_pincode (agent, path, invocation); |
1228 | + g_free (path); |
1229 | + } else if (g_strcmp0 (method_name, "RequestPasskey") == 0) { |
1230 | + char *path; |
1231 | + g_variant_get (parameters, "(o)", &path); |
1232 | + bluetooth_agent_request_passkey (agent, path, invocation); |
1233 | + g_free (path); |
1234 | + } else if (g_strcmp0 (method_name, "DisplayPasskey") == 0) { |
1235 | + char *path; |
1236 | + guint32 passkey; |
1237 | + guint8 entered; |
1238 | + |
1239 | + g_variant_get (parameters, "(ouy)", &path, &passkey, &entered); |
1240 | + bluetooth_agent_display_passkey (agent, path, passkey, entered, invocation); |
1241 | + g_free (path); |
1242 | + } else if (g_strcmp0 (method_name, "DisplayPinCode") == 0) { |
1243 | + char *path; |
1244 | + char *pincode; |
1245 | + |
1246 | + g_variant_get (parameters, "(os)", &path, &pincode); |
1247 | + bluetooth_agent_display_pincode (agent, path, pincode, invocation); |
1248 | + g_free (path); |
1249 | + } else if (g_strcmp0 (method_name, "RequestConfirmation") == 0) { |
1250 | + char *path; |
1251 | + guint32 passkey; |
1252 | + |
1253 | + g_variant_get (parameters, "(ou)", &path, &passkey); |
1254 | + bluetooth_agent_request_confirmation (agent, path, passkey, invocation); |
1255 | + g_free (path); |
1256 | + } else if (g_strcmp0 (method_name, "RequestAuthorization") == 0) { |
1257 | + char *path; |
1258 | + |
1259 | + g_variant_get (parameters, "(o)", &path); |
1260 | + bluetooth_agent_request_authorization (agent, path, invocation); |
1261 | + g_free (path); |
1262 | + } else if (g_strcmp0 (method_name, "AuthorizeService") == 0) { |
1263 | + char *path, *uuid; |
1264 | + g_variant_get (parameters, "(os)", &path, &uuid); |
1265 | + bluetooth_agent_authorize_service (agent, path, uuid, invocation); |
1266 | + g_free (path); |
1267 | + g_free (uuid); |
1268 | + } else if (g_strcmp0 (method_name, "Cancel") == 0) { |
1269 | + bluetooth_agent_cancel (agent, invocation); |
1270 | + } |
1271 | +} |
1272 | + |
1273 | +static const GDBusInterfaceVTable interface_vtable = |
1274 | +{ |
1275 | + handle_method_call, |
1276 | + NULL, /* GetProperty */ |
1277 | + NULL, /* SetProperty */ |
1278 | +}; |
1279 | + |
1280 | +gboolean bluetooth_agent_setup(BluetoothAgent *agent, const char *path) |
1281 | +{ |
1282 | + BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
1283 | + GError *error = NULL; |
1284 | + |
1285 | + if (priv->path != NULL) { |
1286 | + g_warning ("Agent already setup on '%s'", priv->path); |
1287 | + return FALSE; |
1288 | + } |
1289 | + |
1290 | + priv->path = g_strdup(path); |
1291 | + |
1292 | + priv->reg_id = g_dbus_connection_register_object (priv->conn, |
1293 | + priv->path, |
1294 | + priv->introspection_data->interfaces[0], |
1295 | + &interface_vtable, |
1296 | + agent, |
1297 | + NULL, |
1298 | + &error); |
1299 | + if (priv->reg_id == 0) { |
1300 | + g_warning ("Failed to register object: %s", error->message); |
1301 | + g_error_free (error); |
1302 | + } |
1303 | + |
1304 | + return TRUE; |
1305 | +} |
1306 | + |
1307 | +gboolean bluetooth_agent_register(BluetoothAgent *agent) |
1308 | +{ |
1309 | + BluetoothAgentPrivate *priv; |
1310 | + GError *error = NULL; |
1311 | + gboolean ret; |
1312 | + |
1313 | + g_return_val_if_fail (BLUETOOTH_IS_AGENT (agent), FALSE); |
1314 | + |
1315 | + priv = BLUETOOTH_AGENT_GET_PRIVATE (agent); |
1316 | + |
1317 | + priv->agent_manager = agent_manager1_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, |
1318 | + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, |
1319 | + BLUEZ_SERVICE, "/org/bluez", NULL, NULL); |
1320 | + |
1321 | + priv->reg_id = g_dbus_connection_register_object (priv->conn, |
1322 | + BLUEZ_AGENT_PATH, |
1323 | + priv->introspection_data->interfaces[0], |
1324 | + &interface_vtable, |
1325 | + agent, |
1326 | + NULL, |
1327 | + &error); |
1328 | + if (priv->reg_id == 0) { |
1329 | + g_warning ("Failed to register object: %s", error->message); |
1330 | + g_error_free (error); |
1331 | + error = NULL; |
1332 | + return FALSE; |
1333 | + } |
1334 | + |
1335 | + ret = agent_manager1_call_register_agent_sync (priv->agent_manager, |
1336 | + BLUEZ_AGENT_PATH, |
1337 | + "DisplayYesNo", |
1338 | + NULL, &error); |
1339 | + if (ret == FALSE) { |
1340 | + g_printerr ("Agent registration failed: %s\n", error->message); |
1341 | + g_error_free (error); |
1342 | + return FALSE; |
1343 | + } |
1344 | + |
1345 | + ret = agent_manager1_call_request_default_agent_sync (priv->agent_manager, |
1346 | + BLUEZ_AGENT_PATH, |
1347 | + NULL, &error); |
1348 | + if (ret == FALSE) { |
1349 | + g_printerr ("Agent registration failed: %s\n", error->message); |
1350 | + g_error_free (error); |
1351 | + return FALSE; |
1352 | + } |
1353 | + |
1354 | + return TRUE; |
1355 | +} |
1356 | + |
1357 | +gboolean bluetooth_agent_unregister(BluetoothAgent *agent) |
1358 | +{ |
1359 | + BluetoothAgentPrivate *priv; |
1360 | + GError *error = NULL; |
1361 | + |
1362 | + g_return_val_if_fail (BLUETOOTH_IS_AGENT (agent), FALSE); |
1363 | + |
1364 | + priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
1365 | + |
1366 | + if (priv->agent_manager == NULL) |
1367 | + return FALSE; |
1368 | + |
1369 | + if (agent_manager1_call_unregister_agent_sync (priv->agent_manager, |
1370 | + BLUEZ_AGENT_PATH, |
1371 | + NULL, &error) == FALSE) { |
1372 | + /* Ignore errors if the adapter is gone */ |
1373 | + if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD) == FALSE) { |
1374 | + g_printerr ("Agent unregistration failed: %s '%s'\n", |
1375 | + error->message, |
1376 | + g_quark_to_string (error->domain)); |
1377 | + } |
1378 | + g_error_free(error); |
1379 | + } |
1380 | + |
1381 | + g_object_unref(priv->agent_manager); |
1382 | + priv->agent_manager = NULL; |
1383 | + |
1384 | + g_free(priv->path); |
1385 | + priv->path = NULL; |
1386 | + |
1387 | + g_free(priv->busname); |
1388 | + priv->busname = NULL; |
1389 | + |
1390 | + if (priv->reg_id > 0) { |
1391 | + g_dbus_connection_unregister_object (priv->conn, priv->reg_id); |
1392 | + priv->reg_id = 0; |
1393 | + } |
1394 | + |
1395 | + return TRUE; |
1396 | +} |
1397 | + |
1398 | +void bluetooth_agent_set_pincode_func(BluetoothAgent *agent, |
1399 | + BluetoothAgentPasskeyFunc func, gpointer data) |
1400 | +{ |
1401 | + BluetoothAgentPrivate *priv; |
1402 | + |
1403 | + g_return_if_fail (BLUETOOTH_IS_AGENT (agent)); |
1404 | + |
1405 | + priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
1406 | + |
1407 | + priv->pincode_func = func; |
1408 | + priv->pincode_data = data; |
1409 | +} |
1410 | + |
1411 | +void bluetooth_agent_set_passkey_func(BluetoothAgent *agent, |
1412 | + BluetoothAgentPasskeyFunc func, gpointer data) |
1413 | +{ |
1414 | + BluetoothAgentPrivate *priv; |
1415 | + |
1416 | + g_return_if_fail (BLUETOOTH_IS_AGENT (agent)); |
1417 | + |
1418 | + priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
1419 | + |
1420 | + priv->passkey_func = func; |
1421 | + priv->passkey_data = data; |
1422 | +} |
1423 | + |
1424 | +void bluetooth_agent_set_display_func(BluetoothAgent *agent, |
1425 | + BluetoothAgentDisplayFunc func, gpointer data) |
1426 | +{ |
1427 | + BluetoothAgentPrivate *priv; |
1428 | + |
1429 | + g_return_if_fail (BLUETOOTH_IS_AGENT (agent)); |
1430 | + |
1431 | + priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
1432 | + |
1433 | + priv->display_func = func; |
1434 | + priv->display_data = data; |
1435 | +} |
1436 | + |
1437 | +void bluetooth_agent_set_display_pincode_func(BluetoothAgent *agent, |
1438 | + BluetoothAgentDisplayPinCodeFunc func, gpointer data) |
1439 | +{ |
1440 | + BluetoothAgentPrivate *priv; |
1441 | + |
1442 | + g_return_if_fail (BLUETOOTH_IS_AGENT (agent)); |
1443 | + |
1444 | + priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
1445 | + |
1446 | + priv->display_pincode_func = func; |
1447 | + priv->display_pincode_data = data; |
1448 | +} |
1449 | + |
1450 | +void bluetooth_agent_set_confirm_func(BluetoothAgent *agent, |
1451 | + BluetoothAgentConfirmFunc func, gpointer data) |
1452 | +{ |
1453 | + BluetoothAgentPrivate *priv; |
1454 | + |
1455 | + g_return_if_fail (BLUETOOTH_IS_AGENT (agent)); |
1456 | + |
1457 | + priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
1458 | + |
1459 | + priv->confirm_func = func; |
1460 | + priv->confirm_data = data; |
1461 | +} |
1462 | + |
1463 | +void bluetooth_agent_set_authorize_func(BluetoothAgent *agent, |
1464 | + BluetoothAgentAuthorizeFunc func, gpointer data) |
1465 | +{ |
1466 | + BluetoothAgentPrivate *priv; |
1467 | + |
1468 | + g_return_if_fail (BLUETOOTH_IS_AGENT (agent)); |
1469 | + |
1470 | + priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
1471 | + |
1472 | + priv->authorize_func = func; |
1473 | + priv->authorize_data = data; |
1474 | +} |
1475 | + |
1476 | +void bluetooth_agent_set_authorize_service_func(BluetoothAgent *agent, |
1477 | + BluetoothAgentAuthorizeServiceFunc func, gpointer data) |
1478 | +{ |
1479 | + BluetoothAgentPrivate *priv; |
1480 | + |
1481 | + g_return_if_fail (BLUETOOTH_IS_AGENT (agent)); |
1482 | + |
1483 | + priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
1484 | + |
1485 | + priv->authorize_service_func = func; |
1486 | + priv->authorize_service_data = data; |
1487 | +} |
1488 | + |
1489 | +void bluetooth_agent_set_cancel_func(BluetoothAgent *agent, |
1490 | + BluetoothAgentCancelFunc func, gpointer data) |
1491 | +{ |
1492 | + BluetoothAgentPrivate *priv; |
1493 | + |
1494 | + g_return_if_fail (BLUETOOTH_IS_AGENT (agent)); |
1495 | + |
1496 | + priv = BLUETOOTH_AGENT_GET_PRIVATE(agent); |
1497 | + |
1498 | + priv->cancel_func = func; |
1499 | + priv->cancel_data = data; |
1500 | +} |
1501 | + |
1502 | +GQuark bluetooth_agent_error_quark(void) |
1503 | +{ |
1504 | + static GQuark quark = 0; |
1505 | + if (!quark) |
1506 | + quark = g_quark_from_static_string("agent"); |
1507 | + |
1508 | + return quark; |
1509 | +} |
1510 | + |
1511 | +#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } |
1512 | + |
1513 | +GType bluetooth_agent_error_get_type(void) |
1514 | +{ |
1515 | + static GType etype = 0; |
1516 | + if (etype == 0) { |
1517 | + static const GEnumValue values[] = { |
1518 | + ENUM_ENTRY(AGENT_ERROR_REJECT, "Rejected"), |
1519 | + { 0, 0, 0 } |
1520 | + }; |
1521 | + |
1522 | + etype = g_enum_register_static("agent", values); |
1523 | + } |
1524 | + |
1525 | + return etype; |
1526 | +} |
1527 | + |
1528 | |
1529 | === added file 'panels/bluetooth/gnome-bluetooth/lib/bluetooth-agent.h' |
1530 | --- panels/bluetooth/gnome-bluetooth/lib/bluetooth-agent.h 1970-01-01 00:00:00 +0000 |
1531 | +++ panels/bluetooth/gnome-bluetooth/lib/bluetooth-agent.h 2015-08-12 15:47:27 +0000 |
1532 | @@ -0,0 +1,127 @@ |
1533 | +/* |
1534 | + * |
1535 | + * BlueZ - Bluetooth protocol stack for Linux |
1536 | + * |
1537 | + * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org> |
1538 | + * |
1539 | + * |
1540 | + * This library is free software; you can redistribute it and/or |
1541 | + * modify it under the terms of the GNU Lesser General Public |
1542 | + * License as published by the Free Software Foundation; either |
1543 | + * version 2.1 of the License, or (at your option) any later version. |
1544 | + * |
1545 | + * This library is distributed in the hope that it will be useful, |
1546 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1547 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1548 | + * Lesser General Public License for more details. |
1549 | + * |
1550 | + * You should have received a copy of the GNU Lesser General Public |
1551 | + * License along with this library; if not, write to the Free Software |
1552 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
1553 | + * |
1554 | + */ |
1555 | + |
1556 | +#ifndef __BLUETOOTH_AGENT_H |
1557 | +#define __BLUETOOTH_AGENT_H |
1558 | + |
1559 | +#include <glib-object.h> |
1560 | +#include <gio/gio.h> |
1561 | + |
1562 | +G_BEGIN_DECLS |
1563 | + |
1564 | +#define BLUETOOTH_TYPE_AGENT (bluetooth_agent_get_type()) |
1565 | +#define BLUETOOTH_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ |
1566 | + BLUETOOTH_TYPE_AGENT, BluetoothAgent)) |
1567 | +#define BLUETOOTH_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \ |
1568 | + BLUETOOTH_TYPE_AGENT, BluetoothAgentClass)) |
1569 | +#define BLUETOOTH_IS_AGENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \ |
1570 | + BLUETOOTH_TYPE_AGENT)) |
1571 | +#define BLUETOOTH_IS_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \ |
1572 | + BLUETOOTH_TYPE_AGENT)) |
1573 | +#define BLUETOOTH_GET_AGENT_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \ |
1574 | + BLUETOOTH_TYPE_AGENT, BluetoothAgentClass)) |
1575 | + |
1576 | +typedef struct _BluetoothAgent BluetoothAgent; |
1577 | +typedef struct _BluetoothAgentClass BluetoothAgentClass; |
1578 | + |
1579 | +struct _BluetoothAgent { |
1580 | + GObject parent; |
1581 | +}; |
1582 | + |
1583 | +struct _BluetoothAgentClass { |
1584 | + GObjectClass parent_class; |
1585 | +}; |
1586 | + |
1587 | +GType bluetooth_agent_get_type(void); |
1588 | + |
1589 | +BluetoothAgent *bluetooth_agent_new(void); |
1590 | + |
1591 | +gboolean bluetooth_agent_setup(BluetoothAgent *agent, const char *path); |
1592 | + |
1593 | +gboolean bluetooth_agent_register(BluetoothAgent *agent); |
1594 | +gboolean bluetooth_agent_unregister(BluetoothAgent *agent); |
1595 | + |
1596 | +typedef void (*BluetoothAgentPasskeyFunc) (GDBusMethodInvocation *invocation, |
1597 | + GDBusProxy *device, |
1598 | + gpointer data); |
1599 | +typedef void (*BluetoothAgentDisplayFunc) (GDBusMethodInvocation *invocation, |
1600 | + GDBusProxy *device, |
1601 | + guint passkey, |
1602 | + guint entered, |
1603 | + gpointer data); |
1604 | +typedef void (*BluetoothAgentDisplayPinCodeFunc) (GDBusMethodInvocation *invocation, |
1605 | + GDBusProxy *device, |
1606 | + const char *pincode, |
1607 | + gpointer data); |
1608 | +typedef void (*BluetoothAgentConfirmFunc) (GDBusMethodInvocation *invocation, |
1609 | + GDBusProxy *device, |
1610 | + guint passkey, |
1611 | + gpointer data); |
1612 | +typedef void (*BluetoothAgentAuthorizeFunc) (GDBusMethodInvocation *invocation, |
1613 | + GDBusProxy *device, |
1614 | + gpointer data); |
1615 | +typedef void (*BluetoothAgentAuthorizeServiceFunc) (GDBusMethodInvocation *invocation, |
1616 | + GDBusProxy *device, |
1617 | + const char *uuid, |
1618 | + gpointer data); |
1619 | +typedef gboolean (*BluetoothAgentCancelFunc) (GDBusMethodInvocation *invocation, |
1620 | + gpointer data); |
1621 | + |
1622 | +void bluetooth_agent_set_pincode_func (BluetoothAgent *agent, |
1623 | + BluetoothAgentPasskeyFunc func, |
1624 | + gpointer data); |
1625 | +void bluetooth_agent_set_passkey_func (BluetoothAgent *agent, |
1626 | + BluetoothAgentPasskeyFunc func, |
1627 | + gpointer data); |
1628 | +void bluetooth_agent_set_display_func (BluetoothAgent *agent, |
1629 | + BluetoothAgentDisplayFunc func, |
1630 | + gpointer data); |
1631 | +void bluetooth_agent_set_display_pincode_func (BluetoothAgent *agent, |
1632 | + BluetoothAgentDisplayPinCodeFunc func, |
1633 | + gpointer data); |
1634 | +void bluetooth_agent_set_confirm_func (BluetoothAgent *agent, |
1635 | + BluetoothAgentConfirmFunc func, |
1636 | + gpointer data); |
1637 | +void bluetooth_agent_set_authorize_func (BluetoothAgent *agent, |
1638 | + BluetoothAgentAuthorizeFunc func, |
1639 | + gpointer data); |
1640 | +void bluetooth_agent_set_authorize_service_func (BluetoothAgent *agent, |
1641 | + BluetoothAgentAuthorizeServiceFunc func, |
1642 | + gpointer data); |
1643 | +void bluetooth_agent_set_cancel_func (BluetoothAgent *agent, |
1644 | + BluetoothAgentCancelFunc func, |
1645 | + gpointer data); |
1646 | + |
1647 | +#define AGENT_ERROR (bluetooth_agent_error_quark()) |
1648 | +#define AGENT_ERROR_TYPE (bluetooth_agent_error_get_type()) |
1649 | + |
1650 | +typedef enum { |
1651 | + AGENT_ERROR_REJECT |
1652 | +} AgentError; |
1653 | + |
1654 | +GType bluetooth_agent_error_get_type (void); |
1655 | +GQuark bluetooth_agent_error_quark (void); |
1656 | + |
1657 | +G_END_DECLS |
1658 | + |
1659 | +#endif /* __BLUETOOTH_AGENT_H */ |
1660 | |
1661 | === added file 'panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-button.c' |
1662 | --- panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-button.c 1970-01-01 00:00:00 +0000 |
1663 | +++ panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-button.c 2015-08-12 15:47:27 +0000 |
1664 | @@ -0,0 +1,419 @@ |
1665 | +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ |
1666 | +/* |
1667 | + * (C) Copyright 2007-2009 Bastien Nocera <hadess@hadess.net> |
1668 | + * |
1669 | + * This library is free software; you can redistribute it and/or |
1670 | + * modify it under the terms of the GNU Library General Public |
1671 | + * License as published by the Free Software Foundation; either |
1672 | + * version 2 of the License, or (at your option) any later version. |
1673 | + * |
1674 | + * This library is distributed in the hope that it will be useful, |
1675 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1676 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1677 | + * Library General Public License for more details. |
1678 | + * |
1679 | + * You should have received a copy of the GNU Library General Public |
1680 | + * License along with this library; if not, write to the |
1681 | + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
1682 | + * Boston, MA 02111-1307, USA. |
1683 | + */ |
1684 | + |
1685 | +/** |
1686 | + * SECTION:bluetooth-chooser-button |
1687 | + * @short_description: a Bluetooth chooser button |
1688 | + * @stability: Stable |
1689 | + * @include: bluetooth-chooser-button.h |
1690 | + * |
1691 | + * A button used to select Bluetooth devices which will pop-up a |
1692 | + * #BluetoothChooser widget inside a dialogue when clicked. |
1693 | + **/ |
1694 | + |
1695 | +#ifdef HAVE_CONFIG_H |
1696 | +#include "config.h" |
1697 | +#endif |
1698 | + |
1699 | +#include <glib/gi18n.h> |
1700 | +#include <gtk/gtk.h> |
1701 | + |
1702 | +#include "bluetooth-chooser-button.h" |
1703 | +#include "bluetooth-client.h" |
1704 | +#include "bluetooth-chooser.h" |
1705 | +#include "bluetooth-utils.h" |
1706 | + |
1707 | +struct _BluetoothChooserButton { |
1708 | + GtkButton parent; |
1709 | + |
1710 | + BluetoothClient *client; |
1711 | + GtkWidget *image; |
1712 | + GtkWidget *dialog; |
1713 | + GtkWidget *chooser; |
1714 | + char *bdaddr; |
1715 | + guint is_available : 1; |
1716 | + guint has_selection : 1; |
1717 | +}; |
1718 | + |
1719 | +enum { |
1720 | + PROP_0, |
1721 | + PROP_DEVICE, |
1722 | + PROP_IS_AVAILABLE, |
1723 | +}; |
1724 | + |
1725 | +enum { |
1726 | + CHOOSER_CREATED, |
1727 | + LAST_SIGNAL |
1728 | +}; |
1729 | + |
1730 | +static int signals[LAST_SIGNAL] = { 0 }; |
1731 | + |
1732 | +static void bluetooth_chooser_button_class_init (BluetoothChooserButtonClass * klass); |
1733 | +static void bluetooth_chooser_button_init (BluetoothChooserButton * button); |
1734 | + |
1735 | +static GtkButtonClass *parent_class; |
1736 | + |
1737 | +G_DEFINE_TYPE(BluetoothChooserButton, bluetooth_chooser_button, GTK_TYPE_BUTTON); |
1738 | + |
1739 | +#define DEFAULT_STR N_("Click to select device...") |
1740 | + |
1741 | +static void |
1742 | +set_btdevname (BluetoothChooserButton *button, const char *bdaddr, const char *name, const char *icon) |
1743 | +{ |
1744 | + char *found_name, *found_icon; |
1745 | + |
1746 | + found_name = NULL; |
1747 | + found_icon = NULL; |
1748 | + |
1749 | + if (bdaddr != NULL && (name == NULL || icon == NULL)) { |
1750 | + GtkTreeModel *model; |
1751 | + GtkTreeIter iter; |
1752 | + gboolean cont = FALSE; |
1753 | + |
1754 | + model = bluetooth_client_get_device_model (button->client); |
1755 | + if (model != NULL) { |
1756 | + cont = gtk_tree_model_iter_children (GTK_TREE_MODEL(model), |
1757 | + &iter, NULL); |
1758 | + } |
1759 | + |
1760 | + while (cont == TRUE) { |
1761 | + char *value; |
1762 | + |
1763 | + gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, |
1764 | + BLUETOOTH_COLUMN_ADDRESS, &value, -1); |
1765 | + if (g_ascii_strcasecmp(bdaddr, value) == 0) { |
1766 | + gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, |
1767 | + BLUETOOTH_COLUMN_ALIAS, &found_name, |
1768 | + BLUETOOTH_COLUMN_ICON, &found_icon, |
1769 | + -1); |
1770 | + g_free (value); |
1771 | + break; |
1772 | + } |
1773 | + g_free (value); |
1774 | + cont = gtk_tree_model_iter_next (GTK_TREE_MODEL(model), &iter); |
1775 | + } |
1776 | + |
1777 | + if (model != NULL) |
1778 | + g_object_unref (model); |
1779 | + |
1780 | + if (found_name == NULL) { |
1781 | + found_name = g_strdup (bdaddr); |
1782 | + g_strdelimit (found_name, ":", '-'); |
1783 | + } |
1784 | + if (found_icon == NULL) |
1785 | + found_icon = g_strdup ("bluetooth"); |
1786 | + } |
1787 | + |
1788 | + if (bdaddr != NULL) { |
1789 | + /* Update the name */ |
1790 | + if (name == NULL) |
1791 | + gtk_button_set_label (GTK_BUTTON (button), found_name); |
1792 | + else |
1793 | + gtk_button_set_label (GTK_BUTTON (button), name); |
1794 | + /* And the icon */ |
1795 | + if (icon == NULL) |
1796 | + gtk_image_set_from_icon_name (GTK_IMAGE (button->image), found_icon, GTK_ICON_SIZE_MENU); |
1797 | + else |
1798 | + gtk_image_set_from_icon_name (GTK_IMAGE (button->image), icon, GTK_ICON_SIZE_MENU); |
1799 | + |
1800 | + /* And our copy of the address, and notify if it's actually changed */ |
1801 | + if (button->bdaddr == NULL || strcmp (bdaddr, button->bdaddr) != 0) { |
1802 | + g_free (button->bdaddr); |
1803 | + button->bdaddr = g_strdup (bdaddr); |
1804 | + g_object_notify (G_OBJECT (button), "device"); |
1805 | + } |
1806 | + } else { |
1807 | + gtk_button_set_label (GTK_BUTTON (button), _(DEFAULT_STR)); |
1808 | + if (button->bdaddr != NULL) { |
1809 | + g_free (button->bdaddr); |
1810 | + button->bdaddr = NULL; |
1811 | + gtk_image_clear (GTK_IMAGE (button->image)); |
1812 | + g_object_notify (G_OBJECT (button), "device"); |
1813 | + } |
1814 | + } |
1815 | + |
1816 | + g_free (found_name); |
1817 | + g_free (found_icon); |
1818 | +} |
1819 | + |
1820 | +static void select_device_changed(BluetoothChooser *self, gchar *address, gpointer data) |
1821 | +{ |
1822 | + BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (data); |
1823 | + |
1824 | + button->has_selection = (address != NULL); |
1825 | + gtk_dialog_set_response_sensitive(GTK_DIALOG (button->dialog), GTK_RESPONSE_ACCEPT, |
1826 | + button->has_selection && button->is_available); |
1827 | +} |
1828 | + |
1829 | +static void |
1830 | +dialog_response_cb (GtkDialog *dialog, int response_id, gpointer data) |
1831 | +{ |
1832 | + BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (data); |
1833 | + char *bdaddr, *icon, *name; |
1834 | + |
1835 | + if (response_id == GTK_RESPONSE_ACCEPT) { |
1836 | + BluetoothChooser *chooser = BLUETOOTH_CHOOSER (button->chooser); |
1837 | + bdaddr = bluetooth_chooser_get_selected_device (chooser); |
1838 | + name = bluetooth_chooser_get_selected_device_name (chooser); |
1839 | + icon = bluetooth_chooser_get_selected_device_icon (chooser); |
1840 | + } |
1841 | + |
1842 | + gtk_widget_destroy (GTK_WIDGET (dialog)); |
1843 | + button->dialog = NULL; |
1844 | + |
1845 | + if (response_id != GTK_RESPONSE_ACCEPT) |
1846 | + return; |
1847 | + |
1848 | + set_btdevname (button, bdaddr, name, icon); |
1849 | + g_free (bdaddr); |
1850 | + g_free (name); |
1851 | + g_free (icon); |
1852 | +} |
1853 | + |
1854 | +static void |
1855 | +bluetooth_chooser_button_clicked (GtkButton *widget) |
1856 | +{ |
1857 | + BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (widget); |
1858 | + GtkWidget *parent; |
1859 | + |
1860 | + if (button->dialog != NULL) { |
1861 | + gtk_window_present (GTK_WINDOW (button->dialog)); |
1862 | + return; |
1863 | + } |
1864 | + |
1865 | + parent = gtk_widget_get_toplevel (GTK_WIDGET (button)); |
1866 | + //FIXME title |
1867 | + button->dialog = gtk_dialog_new_with_buttons("", GTK_WINDOW (parent), |
1868 | + GTK_DIALOG_MODAL, |
1869 | + "_Cancel", GTK_RESPONSE_REJECT, |
1870 | + "_OK", GTK_RESPONSE_ACCEPT, NULL); |
1871 | + g_signal_connect (button->dialog, "response", |
1872 | + G_CALLBACK (dialog_response_cb), button); |
1873 | + gtk_dialog_set_response_sensitive (GTK_DIALOG(button->dialog), |
1874 | + GTK_RESPONSE_ACCEPT, FALSE); |
1875 | + gtk_window_set_default_size (GTK_WINDOW(button->dialog), 480, 400); |
1876 | + |
1877 | + gtk_container_set_border_width (GTK_CONTAINER (button->dialog), 5); |
1878 | + gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (button->dialog))), 2); |
1879 | + |
1880 | + /* Create the button->chooser */ |
1881 | + button->chooser = bluetooth_chooser_new (); |
1882 | + g_signal_connect(button->chooser, "selected-device-changed", |
1883 | + G_CALLBACK(select_device_changed), button); |
1884 | + g_signal_emit (G_OBJECT (button), |
1885 | + signals[CHOOSER_CREATED], |
1886 | + 0, button->chooser); |
1887 | + g_object_set (G_OBJECT (button->chooser), "device-selected", button->bdaddr, NULL); |
1888 | + gtk_container_set_border_width (GTK_CONTAINER(button->chooser), 5); |
1889 | + gtk_widget_show (button->chooser); |
1890 | + gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (button->dialog))), button->chooser, |
1891 | + TRUE, TRUE, 0); |
1892 | + |
1893 | + gtk_widget_show (button->dialog); |
1894 | +} |
1895 | + |
1896 | +static void |
1897 | +default_adapter_changed (GObject *object, GParamSpec *pspec, gpointer data) |
1898 | +{ |
1899 | + BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (data); |
1900 | + char *adapter; |
1901 | + gboolean powered; |
1902 | + |
1903 | + g_object_get (G_OBJECT (button->client), |
1904 | + "default-adapter", &adapter, |
1905 | + "default-adapter-powered", &powered, |
1906 | + NULL); |
1907 | + if (adapter != NULL) |
1908 | + button->is_available = powered; |
1909 | + else |
1910 | + button->is_available = FALSE; |
1911 | + |
1912 | + if (adapter != NULL && button->bdaddr != NULL) |
1913 | + set_btdevname (button, button->bdaddr, NULL, NULL); |
1914 | + g_free (adapter); |
1915 | + |
1916 | + if (button->dialog != NULL) |
1917 | + gtk_dialog_set_response_sensitive (GTK_DIALOG (button->dialog), GTK_RESPONSE_ACCEPT, |
1918 | + button->has_selection && button->is_available); |
1919 | + |
1920 | + g_object_notify (G_OBJECT (button), "is-available"); |
1921 | +} |
1922 | + |
1923 | +static void |
1924 | +bluetooth_chooser_button_finalize (GObject *object) |
1925 | +{ |
1926 | + BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (object); |
1927 | + |
1928 | + if (button->client != NULL) { |
1929 | + g_object_unref (button->client); |
1930 | + button->client = NULL; |
1931 | + } |
1932 | + if (button->dialog != NULL) { |
1933 | + gtk_widget_destroy (button->dialog); |
1934 | + button->dialog = NULL; |
1935 | + button->chooser = NULL; |
1936 | + } |
1937 | + |
1938 | + G_OBJECT_CLASS (parent_class)->finalize (object); |
1939 | +} |
1940 | + |
1941 | +static void |
1942 | +bluetooth_chooser_button_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) |
1943 | +{ |
1944 | + BluetoothChooserButton *button; |
1945 | + |
1946 | + g_return_if_fail (BLUETOOTH_IS_CHOOSER_BUTTON (object)); |
1947 | + button = BLUETOOTH_CHOOSER_BUTTON (object); |
1948 | + |
1949 | + switch (property_id) { |
1950 | + case PROP_DEVICE: { |
1951 | + const char *str = g_value_get_string (value); |
1952 | + g_return_if_fail (str == NULL || bluetooth_verify_address (str)); |
1953 | + set_btdevname (button, str, NULL, NULL); |
1954 | + break; |
1955 | + } |
1956 | + default: |
1957 | + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); |
1958 | + } |
1959 | +} |
1960 | + |
1961 | +static void |
1962 | +bluetooth_chooser_button_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) |
1963 | +{ |
1964 | + BluetoothChooserButton *button; |
1965 | + |
1966 | + g_return_if_fail (BLUETOOTH_IS_CHOOSER_BUTTON (object)); |
1967 | + button = BLUETOOTH_CHOOSER_BUTTON (object); |
1968 | + |
1969 | + switch (property_id) { |
1970 | + case PROP_DEVICE: |
1971 | + g_value_set_string (value, button->bdaddr); |
1972 | + break; |
1973 | + case PROP_IS_AVAILABLE: |
1974 | + g_value_set_boolean (value, button->is_available); |
1975 | + break; |
1976 | + default: |
1977 | + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); |
1978 | + } |
1979 | +} |
1980 | + |
1981 | +static void |
1982 | +bluetooth_chooser_button_class_init (BluetoothChooserButtonClass *klass) |
1983 | +{ |
1984 | + GObjectClass *object_class = G_OBJECT_CLASS (klass); |
1985 | + GtkButtonClass *button_class = GTK_BUTTON_CLASS (klass); |
1986 | + |
1987 | + parent_class = g_type_class_peek_parent (klass); |
1988 | + |
1989 | + object_class->finalize = bluetooth_chooser_button_finalize; |
1990 | + object_class->set_property = bluetooth_chooser_button_set_property; |
1991 | + object_class->get_property = bluetooth_chooser_button_get_property; |
1992 | + |
1993 | + button_class->clicked = bluetooth_chooser_button_clicked; |
1994 | + |
1995 | + /** |
1996 | + * BluetoothChooserButton::chooser-created: |
1997 | + * @self: a #BluetoothChooserButton widget |
1998 | + * @chooser: a #BluetoothChooser widget |
1999 | + * |
2000 | + * The signal is sent when a popup dialogue is created for the user to select |
2001 | + * a device. This signal allows you to change the configuration and filtering |
2002 | + * of the tree from its defaults. |
2003 | + **/ |
2004 | + signals[CHOOSER_CREATED] = |
2005 | + g_signal_new ("chooser-created", |
2006 | + G_TYPE_FROM_CLASS (klass), |
2007 | + G_SIGNAL_RUN_LAST, |
2008 | + G_STRUCT_OFFSET (BluetoothChooserButtonClass, chooser_created), |
2009 | + NULL, NULL, |
2010 | + g_cclosure_marshal_VOID__OBJECT, |
2011 | + G_TYPE_NONE, 1, G_TYPE_OBJECT); |
2012 | + |
2013 | + /** |
2014 | + * BluetoothChooserButton:device: |
2015 | + * |
2016 | + * The Bluetooth address of the selected device or %NULL. |
2017 | + **/ |
2018 | + g_object_class_install_property (object_class, PROP_DEVICE, |
2019 | + g_param_spec_string ("device", "Device", "The Bluetooth address of the selected device.", |
2020 | + NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); |
2021 | + /** |
2022 | + * BluetoothChooserButton:is-available: |
2023 | + * |
2024 | + * %TRUE if there is a powered Bluetooth adapter available. |
2025 | + * |
2026 | + * See also: bluetooth_chooser_button_available() |
2027 | + **/ |
2028 | + g_object_class_install_property (object_class, PROP_IS_AVAILABLE, |
2029 | + g_param_spec_boolean ("is-available", "Bluetooth is available", "Whether Bluetooth is available.", |
2030 | + TRUE, G_PARAM_READABLE)); |
2031 | +} |
2032 | + |
2033 | +static void |
2034 | +bluetooth_chooser_button_init (BluetoothChooserButton *button) |
2035 | +{ |
2036 | + gtk_button_set_label (GTK_BUTTON (button), _(DEFAULT_STR)); |
2037 | + |
2038 | + button->image = gtk_image_new (); |
2039 | + gtk_button_set_image (GTK_BUTTON (button), button->image); |
2040 | + |
2041 | + button->bdaddr = NULL; |
2042 | + button->dialog = NULL; |
2043 | + |
2044 | + button->client = bluetooth_client_new (); |
2045 | + g_signal_connect (G_OBJECT (button->client), "notify::default-adapter", |
2046 | + G_CALLBACK (default_adapter_changed), button); |
2047 | + g_signal_connect (G_OBJECT (button->client), "notify::default-adapter-powered", |
2048 | + G_CALLBACK (default_adapter_changed), button); |
2049 | + |
2050 | + /* And set the default value already */ |
2051 | + default_adapter_changed (NULL, NULL, button); |
2052 | +} |
2053 | + |
2054 | +/** |
2055 | + * bluetooth_chooser_button_new: |
2056 | + * |
2057 | + * Returns a new #BluetoothChooserButton widget. |
2058 | + * |
2059 | + * Return value: a #BluetoothChooserButton widget. |
2060 | + **/ |
2061 | +GtkWidget * |
2062 | +bluetooth_chooser_button_new (void) |
2063 | +{ |
2064 | + return g_object_new (BLUETOOTH_TYPE_CHOOSER_BUTTON, |
2065 | + NULL); |
2066 | +} |
2067 | + |
2068 | +/** |
2069 | + * bluetooth_chooser_button_available: |
2070 | + * @button: a #BluetoothChooserButton |
2071 | + * |
2072 | + * Returns whether there is a powered Bluetooth adapter. |
2073 | + * |
2074 | + * Return value: %TRUE if there is a powered Bluetooth adapter available, and the button should be sensitive. |
2075 | + **/ |
2076 | +gboolean |
2077 | +bluetooth_chooser_button_available (BluetoothChooserButton *button) |
2078 | +{ |
2079 | + g_return_val_if_fail (BLUETOOTH_IS_CHOOSER_BUTTON (button), FALSE); |
2080 | + |
2081 | + return button->is_available; |
2082 | +} |
2083 | + |
2084 | |
2085 | === added file 'panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-button.h' |
2086 | --- panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-button.h 1970-01-01 00:00:00 +0000 |
2087 | +++ panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-button.h 2015-08-12 15:47:27 +0000 |
2088 | @@ -0,0 +1,55 @@ |
2089 | +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ |
2090 | +/* |
2091 | + * (C) Copyright 2007 Bastien Nocera <hadess@hadess.net> |
2092 | + * |
2093 | + * This library is free software; you can redistribute it and/or |
2094 | + * modify it under the terms of the GNU Library General Public |
2095 | + * License as published by the Free Software Foundation; either |
2096 | + * version 2 of the License, or (at your option) any later version. |
2097 | + * |
2098 | + * This library is distributed in the hope that it will be useful, |
2099 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2100 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2101 | + * Library General Public License for more details. |
2102 | + * |
2103 | + * You should have received a copy of the GNU Library General Public |
2104 | + * License along with this library; if not, write to the |
2105 | + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
2106 | + * Boston, MA 02111-1307, USA. |
2107 | + */ |
2108 | + |
2109 | +#ifndef __BLUETOOTH_CHOOSER_BUTTON_H__ |
2110 | +#define __BLUETOOTH_CHOOSER_BUTTON_H__ |
2111 | + |
2112 | +#include <gtk/gtk.h> |
2113 | + |
2114 | +G_BEGIN_DECLS |
2115 | + |
2116 | +#define BLUETOOTH_TYPE_CHOOSER_BUTTON (bluetooth_chooser_button_get_type ()) |
2117 | +#define BLUETOOTH_CHOOSER_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BLUETOOTH_TYPE_CHOOSER_BUTTON, BluetoothChooserButton)) |
2118 | +#define BLUETOOTH_IS_CHOOSER_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BLUETOOTH_TYPE_CHOOSER_BUTTON)) |
2119 | + |
2120 | +/** |
2121 | + * BluetoothChooserButton: |
2122 | + * |
2123 | + * The <structname>BluetoothChooserButton</structname> struct contains |
2124 | + * only private fields and should not be directly accessed. |
2125 | + */ |
2126 | +typedef struct _BluetoothChooserButton BluetoothChooserButton; |
2127 | + |
2128 | +typedef struct _BluetoothChooserButtonClass BluetoothChooserButtonClass; |
2129 | + |
2130 | +struct _BluetoothChooserButtonClass { |
2131 | + GtkButtonClass parent_class; |
2132 | + |
2133 | + void (*chooser_created) (BluetoothChooserButton *self, GtkWidget *chooser); |
2134 | +}; |
2135 | + |
2136 | +GType bluetooth_chooser_button_get_type (void); |
2137 | + |
2138 | +GtkWidget * bluetooth_chooser_button_new (void); |
2139 | +gboolean bluetooth_chooser_button_available (BluetoothChooserButton *button); |
2140 | + |
2141 | +G_END_DECLS |
2142 | + |
2143 | +#endif /* __BLUETOOTH_CHOOSER_BUTTON_H__ */ |
2144 | |
2145 | === added file 'panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-combo.c' |
2146 | --- panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-combo.c 1970-01-01 00:00:00 +0000 |
2147 | +++ panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-combo.c 2015-08-12 15:47:27 +0000 |
2148 | @@ -0,0 +1,365 @@ |
2149 | +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ |
2150 | +/* |
2151 | + * (C) Copyright 2007-2009 Bastien Nocera <hadess@hadess.net> |
2152 | + * |
2153 | + * This library is free software; you can redistribute it and/or |
2154 | + * modify it under the terms of the GNU Library General Public |
2155 | + * License as published by the Free Software Foundation; either |
2156 | + * version 2 of the License, or (at your option) any later version. |
2157 | + * |
2158 | + * This library is distributed in the hope that it will be useful, |
2159 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2160 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2161 | + * Library General Public License for more details. |
2162 | + * |
2163 | + * You should have received a copy of the GNU Library General Public |
2164 | + * License along with this library; if not, write to the |
2165 | + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
2166 | + * Boston, MA 02111-1307, USA. |
2167 | + */ |
2168 | + |
2169 | +/** |
2170 | + * SECTION:bluetooth-chooser-combo |
2171 | + * @short_description: a Bluetooth chooser combo button |
2172 | + * @stability: Stable |
2173 | + * @include: bluetooth-chooser-combo.h |
2174 | + * |
2175 | + * A combo box used to select Bluetooth devices. |
2176 | + **/ |
2177 | + |
2178 | +#ifdef HAVE_CONFIG_H |
2179 | +#include "config.h" |
2180 | +#endif |
2181 | + |
2182 | +#include <glib/gi18n.h> |
2183 | +#include <gtk/gtk.h> |
2184 | + |
2185 | +#include "bluetooth-chooser-combo.h" |
2186 | +#include "bluetooth-client.h" |
2187 | +#include "bluetooth-chooser.h" |
2188 | +#include "bluetooth-chooser-private.h" |
2189 | +#include "bluetooth-utils.h" |
2190 | + |
2191 | +struct _BluetoothChooserComboPrivate { |
2192 | + GtkWidget *chooser; |
2193 | + GtkWidget *drop_box; |
2194 | + GtkWidget *drop; |
2195 | + GtkTreeModel *model; |
2196 | + guint model_notify_id; |
2197 | + GtkTreeSelection *selection; |
2198 | + |
2199 | + char *bdaddr; |
2200 | +}; |
2201 | + |
2202 | +enum { |
2203 | + PROP_0, |
2204 | + PROP_CHOOSER, |
2205 | + PROP_DEVICE, |
2206 | +}; |
2207 | + |
2208 | +enum { |
2209 | + CHOOSER_CREATED, |
2210 | + LAST_SIGNAL |
2211 | +}; |
2212 | + |
2213 | +static int signals[LAST_SIGNAL] = { 0 }; |
2214 | + |
2215 | +static void bluetooth_chooser_combo_class_init (BluetoothChooserComboClass * klass); |
2216 | +static void bluetooth_chooser_combo_init (BluetoothChooserCombo * combo); |
2217 | + |
2218 | +static GtkBoxClass *parent_class; |
2219 | + |
2220 | +G_DEFINE_TYPE(BluetoothChooserCombo, bluetooth_chooser_combo, GTK_TYPE_BOX); |
2221 | + |
2222 | +#define BLUETOOTH_CHOOSER_COMBO_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ |
2223 | + BLUETOOTH_TYPE_CHOOSER_COMBO, BluetoothChooserComboPrivate)) |
2224 | + |
2225 | +static void |
2226 | +bluetooth_chooser_combo_set_device (BluetoothChooserCombo *combo, |
2227 | + const char *bdaddr) |
2228 | +{ |
2229 | + if (bdaddr == NULL || combo->priv->model == NULL) { |
2230 | + g_free (combo->priv->bdaddr); |
2231 | + gtk_widget_set_sensitive (combo->priv->drop_box, FALSE); |
2232 | + } else { |
2233 | + GtkTreeIter iter; |
2234 | + gboolean cont = FALSE; |
2235 | + |
2236 | + gtk_widget_set_sensitive (combo->priv->drop_box, TRUE); |
2237 | + |
2238 | + g_free (combo->priv->bdaddr); |
2239 | + if (g_strcmp0 (BLUETOOTH_CHOOSER_COMBO_FIRST_DEVICE, bdaddr) != 0) |
2240 | + combo->priv->bdaddr = g_strdup (bdaddr); |
2241 | + else |
2242 | + combo->priv->bdaddr = NULL; |
2243 | + |
2244 | + cont = gtk_tree_model_iter_children (combo->priv->model, &iter, NULL); |
2245 | + while (cont == TRUE) { |
2246 | + char *value; |
2247 | + |
2248 | + gtk_tree_model_get (GTK_TREE_MODEL (combo->priv->model), &iter, |
2249 | + BLUETOOTH_COLUMN_ADDRESS, &value, -1); |
2250 | + |
2251 | + if (combo->priv->bdaddr == NULL) { |
2252 | + gtk_tree_selection_select_iter (combo->priv->selection, &iter); |
2253 | + combo->priv->bdaddr = value; |
2254 | + break; |
2255 | + } |
2256 | + |
2257 | + if (g_ascii_strcasecmp(bdaddr, value) == 0) { |
2258 | + gtk_tree_selection_select_iter (combo->priv->selection, &iter); |
2259 | + g_free (value); |
2260 | + break; |
2261 | + } |
2262 | + g_free (value); |
2263 | + cont = gtk_tree_model_iter_next (GTK_TREE_MODEL (combo->priv->model), &iter); |
2264 | + } |
2265 | + } |
2266 | + g_object_notify (G_OBJECT (combo), "device"); |
2267 | +} |
2268 | + |
2269 | +static void |
2270 | +bluetooth_chooser_combo_dispose (GObject *object) |
2271 | +{ |
2272 | + BluetoothChooserCombo *combo = BLUETOOTH_CHOOSER_COMBO (object); |
2273 | + |
2274 | + if (combo->priv->model_notify_id != 0) { |
2275 | + GtkWidget *treeview; |
2276 | + |
2277 | + treeview = bluetooth_chooser_get_treeview (BLUETOOTH_CHOOSER (combo->priv->chooser)); |
2278 | + g_signal_handler_disconnect (treeview, combo->priv->model_notify_id); |
2279 | + combo->priv->model_notify_id = 0; |
2280 | + } |
2281 | + if (combo->priv->model != NULL) { |
2282 | + g_object_unref (combo->priv->model); |
2283 | + combo->priv->model = NULL; |
2284 | + } |
2285 | + if (combo->priv->chooser != NULL) { |
2286 | + g_object_unref (combo->priv->chooser); |
2287 | + combo->priv->chooser = NULL; |
2288 | + } |
2289 | + |
2290 | + G_OBJECT_CLASS (parent_class)->dispose (object); |
2291 | +} |
2292 | + |
2293 | +static void |
2294 | +bluetooth_chooser_combo_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) |
2295 | +{ |
2296 | + BluetoothChooserCombo *combo; |
2297 | + |
2298 | + g_return_if_fail (BLUETOOTH_IS_CHOOSER_COMBO (object)); |
2299 | + combo = BLUETOOTH_CHOOSER_COMBO (object); |
2300 | + |
2301 | + switch (property_id) { |
2302 | + case PROP_DEVICE: |
2303 | + g_return_if_fail (bluetooth_verify_address (g_value_get_string (value)) || g_value_get_string (value) == NULL); |
2304 | + bluetooth_chooser_combo_set_device (combo, g_value_get_string (value)); |
2305 | + break; |
2306 | + default: |
2307 | + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); |
2308 | + } |
2309 | +} |
2310 | + |
2311 | +static void |
2312 | +bluetooth_chooser_combo_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) |
2313 | +{ |
2314 | + BluetoothChooserCombo *combo; |
2315 | + |
2316 | + g_return_if_fail (BLUETOOTH_IS_CHOOSER_COMBO (object)); |
2317 | + combo = BLUETOOTH_CHOOSER_COMBO (object); |
2318 | + |
2319 | + switch (property_id) { |
2320 | + case PROP_CHOOSER: |
2321 | + g_value_set_object (value, combo->priv->chooser); |
2322 | + break; |
2323 | + case PROP_DEVICE: |
2324 | + g_value_set_string (value, combo->priv->bdaddr); |
2325 | + break; |
2326 | + default: |
2327 | + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); |
2328 | + } |
2329 | +} |
2330 | + |
2331 | +static void |
2332 | +bluetooth_chooser_combo_class_init (BluetoothChooserComboClass *klass) |
2333 | +{ |
2334 | + GObjectClass *object_class = G_OBJECT_CLASS (klass); |
2335 | + |
2336 | + parent_class = g_type_class_peek_parent (klass); |
2337 | + |
2338 | + object_class->dispose = bluetooth_chooser_combo_dispose; |
2339 | + object_class->set_property = bluetooth_chooser_combo_set_property; |
2340 | + object_class->get_property = bluetooth_chooser_combo_get_property; |
2341 | + |
2342 | + g_type_class_add_private(klass, sizeof(BluetoothChooserComboPrivate)); |
2343 | + |
2344 | + /** |
2345 | + * BluetoothChooserCombo::chooser-created: |
2346 | + * @self: a #BluetoothChooserCombo widget |
2347 | + * @chooser: a #BluetoothChooser widget |
2348 | + * |
2349 | + * The signal is sent when a popup dialogue is created for the user to select |
2350 | + * a device. This signal allows you to change the configuration and filtering |
2351 | + * of the tree from its defaults. |
2352 | + **/ |
2353 | + signals[CHOOSER_CREATED] = |
2354 | + g_signal_new ("chooser-created", |
2355 | + G_TYPE_FROM_CLASS (klass), |
2356 | + G_SIGNAL_RUN_LAST, |
2357 | + G_STRUCT_OFFSET (BluetoothChooserComboClass, chooser_created), |
2358 | + NULL, NULL, |
2359 | + g_cclosure_marshal_VOID__OBJECT, |
2360 | + G_TYPE_NONE, 1, G_TYPE_OBJECT); |
2361 | + |
2362 | + /** |
2363 | + * BluetoothChooserCombo:chooser: |
2364 | + * |
2365 | + * The #BluetoothChooser used in the widget |
2366 | + **/ |
2367 | + g_object_class_install_property (object_class, PROP_CHOOSER, |
2368 | + g_param_spec_object ("chooser", "Chooser", "The #BluetoothChooser used in the widget", |
2369 | + BLUETOOTH_TYPE_CHOOSER, G_PARAM_READABLE)); |
2370 | + /** |
2371 | + * BluetoothChooserCombo:device: |
2372 | + * |
2373 | + * The Bluetooth address of the selected device or %NULL |
2374 | + **/ |
2375 | + g_object_class_install_property (object_class, PROP_DEVICE, |
2376 | + g_param_spec_string ("device", "Device", "The Bluetooth address of the selected device.", |
2377 | + NULL, G_PARAM_READWRITE)); |
2378 | +} |
2379 | + |
2380 | +static void |
2381 | +treeview_model_notify_cb (GObject *gobject, |
2382 | + GParamSpec *pspec, |
2383 | + gpointer user_data) |
2384 | +{ |
2385 | + BluetoothChooserCombo *combo = BLUETOOTH_CHOOSER_COMBO (user_data); |
2386 | + GtkTreeModel *model; |
2387 | + |
2388 | + g_object_get (gobject, "model", &model, NULL); |
2389 | + gtk_combo_box_set_model (GTK_COMBO_BOX (combo->priv->drop), model); |
2390 | + if (combo->priv->model != NULL) { |
2391 | + g_object_unref (combo->priv->model); |
2392 | + combo->priv->model = NULL; |
2393 | + } |
2394 | + combo->priv->model = model; |
2395 | +} |
2396 | + |
2397 | +static void |
2398 | +treeview_selection_changed_cb (GtkTreeSelection *treeselection, |
2399 | + gpointer user_data) |
2400 | +{ |
2401 | + BluetoothChooserCombo *combo = BLUETOOTH_CHOOSER_COMBO (user_data); |
2402 | + GtkTreeIter iter; |
2403 | + char *value = NULL; |
2404 | + |
2405 | + if (gtk_tree_selection_get_selected (combo->priv->selection, NULL, &iter)) { |
2406 | + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo->priv->drop), &iter); |
2407 | + if (combo->priv->model != NULL) |
2408 | + gtk_tree_model_get (GTK_TREE_MODEL (combo->priv->model), &iter, |
2409 | + BLUETOOTH_COLUMN_ADDRESS, &value, -1); |
2410 | + } else { |
2411 | + if (combo->priv->model != NULL) |
2412 | + gtk_combo_box_set_active (GTK_COMBO_BOX (combo->priv->drop), -1); |
2413 | + } |
2414 | + |
2415 | + if (g_strcmp0 (combo->priv->bdaddr, value) != 0) { |
2416 | + g_free (combo->priv->bdaddr); |
2417 | + combo->priv->bdaddr = value; |
2418 | + g_object_notify (G_OBJECT (combo), "device"); |
2419 | + } else { |
2420 | + g_free (value); |
2421 | + } |
2422 | +} |
2423 | + |
2424 | +static void |
2425 | +drop_changed_cb (GtkComboBox *widget, |
2426 | + gpointer user_data) |
2427 | +{ |
2428 | + BluetoothChooserCombo *combo = BLUETOOTH_CHOOSER_COMBO (user_data); |
2429 | + GtkTreeIter iter; |
2430 | + char *value = NULL; |
2431 | + |
2432 | + if (gtk_combo_box_get_active_iter (widget, &iter)) { |
2433 | + gtk_tree_selection_select_iter (combo->priv->selection, &iter); |
2434 | + if (combo->priv->model != NULL) |
2435 | + gtk_tree_model_get (GTK_TREE_MODEL (combo->priv->model), &iter, |
2436 | + BLUETOOTH_COLUMN_ADDRESS, &value, -1); |
2437 | + } else { |
2438 | + if (combo->priv->model != NULL) |
2439 | + gtk_tree_selection_unselect_all (combo->priv->selection); |
2440 | + } |
2441 | + |
2442 | + if (g_strcmp0 (combo->priv->bdaddr, value) != 0) { |
2443 | + g_free (combo->priv->bdaddr); |
2444 | + combo->priv->bdaddr = value; |
2445 | + g_object_notify (G_OBJECT (combo), "device"); |
2446 | + } else { |
2447 | + g_free (value); |
2448 | + } |
2449 | +} |
2450 | + |
2451 | +static void |
2452 | +bluetooth_chooser_combo_init (BluetoothChooserCombo *combo) |
2453 | +{ |
2454 | + GtkWidget *treeview; |
2455 | + GtkCellRenderer *renderer; |
2456 | + |
2457 | + combo->priv = BLUETOOTH_CHOOSER_COMBO_GET_PRIVATE (combo); |
2458 | + |
2459 | + combo->priv->drop_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); |
2460 | + gtk_box_set_homogeneous (GTK_BOX (combo->priv->drop_box), TRUE); |
2461 | + gtk_box_pack_start (GTK_BOX (combo), combo->priv->drop_box, |
2462 | + TRUE, FALSE, 0); |
2463 | + /* Setup the combo itself */ |
2464 | + combo->priv->drop = gtk_combo_box_new (); |
2465 | + gtk_box_pack_start (GTK_BOX (combo->priv->drop_box), combo->priv->drop, |
2466 | + TRUE, TRUE, 0); |
2467 | + renderer = gtk_cell_renderer_pixbuf_new (); |
2468 | + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo->priv->drop), |
2469 | + renderer, |
2470 | + FALSE); |
2471 | + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo->priv->drop), |
2472 | + renderer, |
2473 | + "icon-name", BLUETOOTH_COLUMN_ICON, |
2474 | + NULL); |
2475 | + renderer = gtk_cell_renderer_text_new (); |
2476 | + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo->priv->drop), |
2477 | + renderer, |
2478 | + TRUE); |
2479 | + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo->priv->drop), |
2480 | + renderer, |
2481 | + "text", BLUETOOTH_COLUMN_ALIAS, |
2482 | + NULL); |
2483 | + |
2484 | + combo->priv->chooser = bluetooth_chooser_new (); |
2485 | + |
2486 | + treeview = bluetooth_chooser_get_treeview (BLUETOOTH_CHOOSER (combo->priv->chooser)); |
2487 | + combo->priv->model_notify_id = g_signal_connect (G_OBJECT (treeview), "notify::model", |
2488 | + G_CALLBACK (treeview_model_notify_cb), combo); |
2489 | + treeview_model_notify_cb (G_OBJECT (treeview), NULL, combo); |
2490 | + gtk_combo_box_set_active (GTK_COMBO_BOX (combo->priv->drop), 0); |
2491 | + |
2492 | + combo->priv->selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); |
2493 | + g_signal_connect (G_OBJECT (combo->priv->selection), "changed", |
2494 | + G_CALLBACK (treeview_selection_changed_cb), combo); |
2495 | + g_signal_connect (G_OBJECT (combo->priv->drop), "changed", |
2496 | + G_CALLBACK (drop_changed_cb), combo); |
2497 | + |
2498 | + gtk_widget_show_all (GTK_WIDGET (combo)); |
2499 | +} |
2500 | + |
2501 | +/** |
2502 | + * bluetooth_chooser_combo_new: |
2503 | + * |
2504 | + * Returns a new #BluetoothChooserCombo widget. |
2505 | + * |
2506 | + * Return value: a #BluetoothChooserCombo widget. |
2507 | + **/ |
2508 | +GtkWidget * |
2509 | +bluetooth_chooser_combo_new (void) |
2510 | +{ |
2511 | + return g_object_new (BLUETOOTH_TYPE_CHOOSER_COMBO, NULL); |
2512 | +} |
2513 | + |
2514 | |
2515 | === added file 'panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-combo.h' |
2516 | --- panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-combo.h 1970-01-01 00:00:00 +0000 |
2517 | +++ panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-combo.h 2015-08-12 15:47:27 +0000 |
2518 | @@ -0,0 +1,69 @@ |
2519 | +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ |
2520 | +/* |
2521 | + * (C) Copyright 2007 Bastien Nocera <hadess@hadess.net> |
2522 | + * |
2523 | + * This library is free software; you can redistribute it and/or |
2524 | + * modify it under the terms of the GNU Library General Public |
2525 | + * License as published by the Free Software Foundation; either |
2526 | + * version 2 of the License, or (at your option) any later version. |
2527 | + * |
2528 | + * This library is distributed in the hope that it will be useful, |
2529 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2530 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2531 | + * Library General Public License for more details. |
2532 | + * |
2533 | + * You should have received a copy of the GNU Library General Public |
2534 | + * License along with this library; if not, write to the |
2535 | + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
2536 | + * Boston, MA 02111-1307, USA. |
2537 | + */ |
2538 | + |
2539 | +#ifndef __BLUETOOTH_CHOOSER_COMBO_H__ |
2540 | +#define __BLUETOOTH_CHOOSER_COMBO_H__ |
2541 | + |
2542 | +#include <gtk/gtk.h> |
2543 | + |
2544 | +G_BEGIN_DECLS |
2545 | + |
2546 | +#define BLUETOOTH_TYPE_CHOOSER_COMBO (bluetooth_chooser_combo_get_type ()) |
2547 | +#define BLUETOOTH_CHOOSER_COMBO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BLUETOOTH_TYPE_CHOOSER_COMBO, BluetoothChooserCombo)) |
2548 | +#define BLUETOOTH_IS_CHOOSER_COMBO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BLUETOOTH_TYPE_CHOOSER_COMBO)) |
2549 | +#define BLUETOOTH_IS_CHOOSER_COMBO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \ |
2550 | + BLUETOOTH_TYPE_CHOOSER_COMBO)) |
2551 | +#define BLUETOOTH_GET_CHOOSER_COMBO_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \ |
2552 | + BLUETOOTH_TYPE_CHOOSER_COMBO, BluetoothChooserComboClass)) |
2553 | + |
2554 | +/** |
2555 | +* BLUETOOTH_CHOOSER_COMBO_FIRST_DEVICE: |
2556 | +* |
2557 | +* A convenience value used to select the first device regardless of its address. |
2558 | +**/ |
2559 | +#define BLUETOOTH_CHOOSER_COMBO_FIRST_DEVICE "00:00:00:00:00:00" |
2560 | + |
2561 | +typedef struct _BluetoothChooserComboPrivate BluetoothChooserComboPrivate; |
2562 | +typedef struct _BluetoothChooserComboClass BluetoothChooserComboClass; |
2563 | + |
2564 | +/** |
2565 | + * BluetoothChooserCombo: |
2566 | + * |
2567 | + * The <structname>BluetoothChooserCombo</structname> struct contains |
2568 | + * only private fields and should not be directly accessed. |
2569 | + */ |
2570 | +typedef struct _BluetoothChooserCombo { |
2571 | + GtkBox parent; |
2572 | + BluetoothChooserComboPrivate *priv; |
2573 | +} BluetoothChooserCombo; |
2574 | + |
2575 | +struct _BluetoothChooserComboClass { |
2576 | + GtkBoxClass parent_class; |
2577 | + |
2578 | + void (*chooser_created) (BluetoothChooserCombo *self, GtkWidget *chooser); |
2579 | +}; |
2580 | + |
2581 | +GType bluetooth_chooser_combo_get_type (void); |
2582 | + |
2583 | +GtkWidget * bluetooth_chooser_combo_new (void); |
2584 | + |
2585 | +G_END_DECLS |
2586 | + |
2587 | +#endif /* __BLUETOOTH_CHOOSER_COMBO_H__ */ |
2588 | |
2589 | === added file 'panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-private.h' |
2590 | --- panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-private.h 1970-01-01 00:00:00 +0000 |
2591 | +++ panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-private.h 2015-08-12 15:47:27 +0000 |
2592 | @@ -0,0 +1,39 @@ |
2593 | +/* |
2594 | + * |
2595 | + * BlueZ - Bluetooth protocol stack for Linux |
2596 | + * |
2597 | + * Copyright (C) 2009 Bastien Nocera <hadess@hadess.net> |
2598 | + * |
2599 | + * |
2600 | + * This library is free software; you can redistribute it and/or |
2601 | + * modify it under the terms of the GNU Lesser General Public |
2602 | + * License as published by the Free Software Foundation; either |
2603 | + * version 2.1 of the License, or (at your option) any later version. |
2604 | + * |
2605 | + * This library is distributed in the hope that it will be useful, |
2606 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2607 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2608 | + * Lesser General Public License for more details. |
2609 | + * |
2610 | + * You should have received a copy of the GNU Lesser General Public |
2611 | + * License along with this library; if not, write to the Free Software |
2612 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
2613 | + * |
2614 | + */ |
2615 | + |
2616 | +#ifndef __BLUETOOTH_CHOOSER_PRIVATE_H |
2617 | +#define __BLUETOOTH_CHOOSER_PRIVATE_H |
2618 | + |
2619 | +#include <glib-object.h> |
2620 | +#include <gtk/gtk.h> |
2621 | +#include <bluetooth-enums.h> |
2622 | + |
2623 | +G_BEGIN_DECLS |
2624 | + |
2625 | +GtkTreeModel *bluetooth_chooser_get_model (BluetoothChooser *self); |
2626 | +GtkWidget *bluetooth_chooser_get_treeview (BluetoothChooser *self); |
2627 | +gboolean bluetooth_chooser_remove_selected_device (BluetoothChooser *self); |
2628 | + |
2629 | +G_END_DECLS |
2630 | + |
2631 | +#endif /* __BLUETOOTH_CHOOSER_PRIVATE_H */ |
2632 | |
2633 | === added file 'panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser.c' |
2634 | --- panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser.c 1970-01-01 00:00:00 +0000 |
2635 | +++ panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser.c 2015-08-12 15:47:27 +0000 |
2636 | @@ -0,0 +1,1173 @@ |
2637 | +/* |
2638 | + * |
2639 | + * BlueZ - Bluetooth protocol stack for Linux |
2640 | + * |
2641 | + * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org> |
2642 | + * Copyright (C) 2006-2007 Bastien Nocera <hadess@hadess.net> |
2643 | + * |
2644 | + * |
2645 | + * This library is free software; you can redistribute it and/or |
2646 | + * modify it under the terms of the GNU Lesser General Public |
2647 | + * License as published by the Free Software Foundation; either |
2648 | + * version 2.1 of the License, or (at your option) any later version. |
2649 | + * |
2650 | + * This library is distributed in the hope that it will be useful, |
2651 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2652 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2653 | + * Lesser General Public License for more details. |
2654 | + * |
2655 | + * You should have received a copy of the GNU Lesser General Public |
2656 | + * License along with this library; if not, write to the Free Software |
2657 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
2658 | + * |
2659 | + */ |
2660 | + |
2661 | +/** |
2662 | + * SECTION:bluetooth-chooser |
2663 | + * @short_description: a Bluetooth chooser widget |
2664 | + * @stability: Stable |
2665 | + * @include: bluetooth-chooser.h |
2666 | + * |
2667 | + * A tree-like widget used to select Bluetooth devices. |
2668 | + **/ |
2669 | + |
2670 | +#ifdef HAVE_CONFIG_H |
2671 | +#include <config.h> |
2672 | +#endif |
2673 | + |
2674 | +#include <gtk/gtk.h> |
2675 | + |
2676 | +#include <glib/gi18n-lib.h> |
2677 | + |
2678 | +#include "bluetooth-client.h" |
2679 | +#include "bluetooth-client-private.h" |
2680 | +#include "bluetooth-utils.h" |
2681 | +#include "bluetooth-chooser.h" |
2682 | +#include "bluetooth-chooser-private.h" |
2683 | +#include "gnome-bluetooth-enum-types.h" |
2684 | +#include "bluetooth-filter-widget.h" |
2685 | + |
2686 | +enum { |
2687 | + SELECTED_DEVICE_CHANGED, |
2688 | + SELECTED_DEVICE_ACTIVATED, |
2689 | + LAST_SIGNAL |
2690 | +}; |
2691 | + |
2692 | +static int selection_table_signals[LAST_SIGNAL] = { 0 }; |
2693 | + |
2694 | +#define BLUETOOTH_CHOOSER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ |
2695 | + BLUETOOTH_TYPE_CHOOSER, BluetoothChooserPrivate)) |
2696 | + |
2697 | +typedef struct _BluetoothChooserPrivate BluetoothChooserPrivate; |
2698 | + |
2699 | +struct _BluetoothChooserPrivate { |
2700 | + BluetoothClient *client; |
2701 | + GtkTreeSelection *selection; |
2702 | + GtkTreeModel *model, *filter, *adapter_model; |
2703 | + |
2704 | + gulong default_adapter_changed_id; |
2705 | + |
2706 | + /* Widgets/UI bits that can be shown or hidden */ |
2707 | + GtkCellRenderer *bonded_cell; |
2708 | + GtkCellRenderer *connected_cell; |
2709 | + GtkWidget *treeview, *scrolled_window; |
2710 | + GtkWidget *search_hbox, *search_label, *spinner; |
2711 | + GtkWidget *filters_vbox; |
2712 | + |
2713 | + /* Current filter */ |
2714 | + int device_type_filter; |
2715 | + GtkTreeModel *device_type_filter_model; |
2716 | + int device_category_filter; |
2717 | + char *device_service_filter; |
2718 | + |
2719 | + guint show_paired : 1; |
2720 | + guint show_connected : 1; |
2721 | + guint show_searching : 1; |
2722 | + guint show_device_type : 1; |
2723 | + guint show_device_category : 1; |
2724 | + guint disco_rq : 1; |
2725 | + guint internal_filter : 1; |
2726 | +}; |
2727 | + |
2728 | +G_DEFINE_TYPE(BluetoothChooser, bluetooth_chooser, GTK_TYPE_BOX) |
2729 | + |
2730 | +enum { |
2731 | + DEVICE_TYPE_FILTER_COL_NAME = 0, |
2732 | + DEVICE_TYPE_FILTER_COL_MASK, |
2733 | + DEVICE_TYPE_FILTER_NUM_COLS |
2734 | +}; |
2735 | + |
2736 | +enum { |
2737 | + TREEVIEW_COLUMN_DEVICE = 0, |
2738 | + TREEVIEW_COLUMN_TYPE = 1 |
2739 | +}; |
2740 | + |
2741 | +static void |
2742 | +bonded_to_icon (GtkTreeViewColumn *column, GtkCellRenderer *cell, |
2743 | + GtkTreeModel *model, GtkTreeIter *iter, gpointer data) |
2744 | +{ |
2745 | + gboolean bonded; |
2746 | + |
2747 | + gtk_tree_model_get (model, iter, BLUETOOTH_COLUMN_PAIRED, &bonded, -1); |
2748 | + |
2749 | + g_object_set (cell, "icon-name", bonded ? "bluetooth-paired" : NULL, NULL); |
2750 | +} |
2751 | + |
2752 | +static void |
2753 | +connected_to_icon (GtkTreeViewColumn *column, GtkCellRenderer *cell, |
2754 | + GtkTreeModel *model, GtkTreeIter *iter, gpointer data) |
2755 | +{ |
2756 | + gboolean connected; |
2757 | + |
2758 | + gtk_tree_model_get (model, iter, BLUETOOTH_COLUMN_CONNECTED, &connected, -1); |
2759 | + |
2760 | + g_object_set (cell, "icon-name", connected ? "gtk-connected" : NULL, NULL); |
2761 | +} |
2762 | + |
2763 | +static void |
2764 | +type_to_text (GtkTreeViewColumn *column, GtkCellRenderer *cell, |
2765 | + GtkTreeModel *model, GtkTreeIter *iter, gpointer data) |
2766 | +{ |
2767 | + guint type; |
2768 | + |
2769 | + gtk_tree_model_get (model, iter, BLUETOOTH_COLUMN_TYPE, &type, -1); |
2770 | + |
2771 | + g_object_set (cell, "text", (type == 0) ? _("Unknown") : bluetooth_type_to_string (type), NULL); |
2772 | +} |
2773 | + |
2774 | +static void |
2775 | +alias_to_label (GtkTreeViewColumn *column, GtkCellRenderer *cell, |
2776 | + GtkTreeModel *model, GtkTreeIter *iter, gpointer data) |
2777 | +{ |
2778 | + char *alias, *escaped, *label; |
2779 | + gboolean connected; |
2780 | + |
2781 | + gtk_tree_model_get (model, iter, |
2782 | + BLUETOOTH_COLUMN_ALIAS, &alias, |
2783 | + BLUETOOTH_COLUMN_CONNECTED, &connected, |
2784 | + -1); |
2785 | + |
2786 | + if (connected == FALSE) { |
2787 | + g_object_set (cell, "text", alias, NULL); |
2788 | + } else { |
2789 | + escaped = g_markup_escape_text (alias, -1); |
2790 | + label = g_strdup_printf ("<b>%s</b>", escaped); |
2791 | + g_free (escaped); |
2792 | + |
2793 | + g_object_set (cell, "markup", label, NULL); |
2794 | + g_free (label); |
2795 | + } |
2796 | + g_free (alias); |
2797 | +} |
2798 | + |
2799 | +static void |
2800 | +set_search_label (BluetoothChooser *self, gboolean state) |
2801 | +{ |
2802 | + BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self); |
2803 | + |
2804 | + if (priv->show_searching == FALSE) { |
2805 | + /* Just making sure */ |
2806 | + gtk_spinner_stop (GTK_SPINNER (priv->spinner)); |
2807 | + return; |
2808 | + } |
2809 | + if (state == FALSE) { |
2810 | + gtk_spinner_stop (GTK_SPINNER (priv->spinner)); |
2811 | + gtk_widget_hide (priv->spinner); |
2812 | + gtk_label_set_text (GTK_LABEL (priv->search_label), _("No adapters available")); |
2813 | + } else { |
2814 | + gtk_widget_show (priv->spinner); |
2815 | + gtk_spinner_start (GTK_SPINNER (priv->spinner)); |
2816 | + gtk_label_set_text (GTK_LABEL (priv->search_label), _("Searching for devices...")); |
2817 | + } |
2818 | +} |
2819 | + |
2820 | +/** |
2821 | + * bluetooth_chooser_start_discovery: |
2822 | + * @self: a #BluetoothChooser widget. |
2823 | + * |
2824 | + * Starts a discovery on the default Bluetooth adapter. Note that this will |
2825 | + * only work if the Search label is visible, as otherwise the user has no |
2826 | + * visual feedback that the process is on-going. |
2827 | + * |
2828 | + * See also: #BluetoothChooser:show-searching |
2829 | + **/ |
2830 | +void |
2831 | +bluetooth_chooser_start_discovery (BluetoothChooser *self) |
2832 | +{ |
2833 | + BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self); |
2834 | + |
2835 | + g_return_if_fail (priv->show_searching); |
2836 | + |
2837 | + g_object_set (G_OBJECT (priv->client), "default-adapter-discovering", TRUE, NULL); |
2838 | + set_search_label (self, TRUE); |
2839 | + priv->disco_rq = TRUE; |
2840 | +} |
2841 | + |
2842 | +/** |
2843 | + * bluetooth_chooser_stop_discovery: |
2844 | + * @self: a #BluetoothChooser widget. |
2845 | + * |
2846 | + * Stops a discovery started with #bluetooth_chooser_start_discovery. |
2847 | + **/ |
2848 | +void |
2849 | +bluetooth_chooser_stop_discovery (BluetoothChooser *self) |
2850 | +{ |
2851 | + BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self); |
2852 | + |
2853 | + g_return_if_fail (priv->show_searching); |
2854 | + |
2855 | + priv->disco_rq = FALSE; |
2856 | + g_object_set (G_OBJECT (priv->client), "default-adapter-discovering", FALSE, NULL); |
2857 | +} |
2858 | + |
2859 | +static char * |
2860 | +bluetooth_chooser_get_selected_device_data (BluetoothChooser *self, guint column) |
2861 | +{ |
2862 | + BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self); |
2863 | + GtkTreeIter iter; |
2864 | + gchar *str; |
2865 | + gboolean selected; |
2866 | + |
2867 | + selected = gtk_tree_selection_get_selected (priv->selection, NULL, &iter); |
2868 | + if (selected == FALSE) |
2869 | + return NULL; |
2870 | + |
2871 | + gtk_tree_model_get (priv->filter, &iter, column, &str, -1); |
2872 | + return str; |
2873 | +} |
2874 | + |
2875 | +/** |
2876 | + * bluetooth_chooser_get_selected_device: |
2877 | + * @self: a #BluetoothChooser widget. |
2878 | + * |
2879 | + * Returns the Bluetooth address for the currently selected device. |
2880 | + * |
2881 | + * Return value: the Bluetooth address for the currently selected device, or %NULL. |
2882 | + **/ |
2883 | +gchar * |
2884 | +bluetooth_chooser_get_selected_device (BluetoothChooser *self) |
2885 | +{ |
2886 | + return bluetooth_chooser_get_selected_device_data (self, BLUETOOTH_COLUMN_ADDRESS); |
2887 | +} |
2888 | + |
2889 | +/** |
2890 | + * bluetooth_chooser_get_selected_device_name: |
2891 | + * @self: a #BluetoothChooser widget. |
2892 | + * |
2893 | + * Returns the name for the currently selected device. |
2894 | + * |
2895 | + * Return value: the name for the currently selected device, or %NULL. |
2896 | + **/ |
2897 | +gchar * |
2898 | +bluetooth_chooser_get_selected_device_name (BluetoothChooser *self) |
2899 | +{ |
2900 | + return bluetooth_chooser_get_selected_device_data (self, BLUETOOTH_COLUMN_NAME); |
2901 | +} |
2902 | + |
2903 | +/** |
2904 | + * bluetooth_chooser_get_selected_device_icon: |
2905 | + * @self: a #BluetoothChooser widget. |
2906 | + * |
2907 | + * Returns the icon name to use to represent the currently selected device. |
2908 | + * |
2909 | + * Return value: the icon name to use to represent the currently selected device, or %NULL. |
2910 | + **/ |
2911 | +gchar * |
2912 | +bluetooth_chooser_get_selected_device_icon (BluetoothChooser *self) |
2913 | +{ |
2914 | + return bluetooth_chooser_get_selected_device_data (self, BLUETOOTH_COLUMN_ICON); |
2915 | +} |
2916 | + |
2917 | +/** |
2918 | + * bluetooth_chooser_get_selected_device_type: |
2919 | + * @self: a #BluetoothChooser widget. |
2920 | + * |
2921 | + * Returns the #BluetoothType of the device selected. |
2922 | + * |
2923 | + * Return value: the #BluetoothType of the device selected, or '0' if unknown. |
2924 | + **/ |
2925 | +BluetoothType |
2926 | +bluetooth_chooser_get_selected_device_type (BluetoothChooser *self) |
2927 | +{ |
2928 | + BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self); |
2929 | + GtkTreeIter iter; |
2930 | + guint type; |
2931 | + gboolean selected; |
2932 | + |
2933 | + selected = gtk_tree_selection_get_selected (priv->selection, NULL, &iter); |
2934 | + if (selected == FALSE) |
2935 | + return 0; |
2936 | + |
2937 | + gtk_tree_model_get (priv->filter, &iter, BLUETOOTH_COLUMN_TYPE, &type, -1); |
2938 | + return type; |
2939 | +} |
2940 | + |
2941 | +/** |
2942 | + * bluetooth_chooser_get_selected_device_is_connected: |
2943 | + * @self: a #BluetoothChooser widget. |
2944 | + * |
2945 | + * Returns whether the selected device is connected to this computer. |
2946 | + * |
2947 | + * Return value: whether the selected device is connected to this computer, |
2948 | + * will always be %FALSE if no devices are selected. |
2949 | + **/ |
2950 | +gboolean |
2951 | +bluetooth_chooser_get_selected_device_is_connected (BluetoothChooser *self) |
2952 | +{ |
2953 | + BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self); |
2954 | + GtkTreeIter iter; |
2955 | + gboolean selected, connected; |
2956 | + |
2957 | + selected = gtk_tree_selection_get_selected (priv->selection, NULL, &iter); |
2958 | + if (selected == FALSE) |
2959 | + return 0; |
2960 | + |
2961 | + gtk_tree_model_get (priv->filter, &iter, BLUETOOTH_COLUMN_CONNECTED, &connected, -1); |
2962 | + return connected; |
2963 | +} |
2964 | + |
2965 | +/** |
2966 | + * bluetooth_chooser_get_selected_device_info: |
2967 | + * @self: A #BluetoothChooser widget. |
2968 | + * @field: The identifier for the field to get data for. |
2969 | + * @value: An empty #GValue to set. |
2970 | + * |
2971 | + * Returns whether the @value has been set. |
2972 | + * |
2973 | + * Return value: %TRUE if the @value has been set. |
2974 | + **/ |
2975 | +gboolean |
2976 | +bluetooth_chooser_get_selected_device_info (BluetoothChooser *self, |
2977 | + const char *field, |
2978 | + GValue *value) |
2979 | +{ |
2980 | + BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self); |
2981 | + GEnumClass *eclass; |
2982 | + GEnumValue *ev; |
2983 | + GtkTreeIter iter; |
2984 | + |
2985 | + g_return_val_if_fail (field != NULL, FALSE); |
2986 | + |
2987 | + if (gtk_tree_selection_get_selected (priv->selection, NULL, &iter) == FALSE) |
2988 | + return FALSE; |
2989 | + |
2990 | + eclass = g_type_class_ref (BLUETOOTH_TYPE_COLUMN); |
2991 | + ev = g_enum_get_value_by_nick (eclass, field); |
2992 | + if (ev == NULL) { |
2993 | + g_warning ("Unknown field '%s'", field); |
2994 | + g_type_class_unref (eclass); |
2995 | + return FALSE; |
2996 | + } |
2997 | + |
2998 | + gtk_tree_model_get_value (priv->filter, &iter, ev->value, value); |
2999 | + |
3000 | + g_type_class_unref (eclass); |
3001 | + |
3002 | + return TRUE; |
3003 | +} |
3004 | + |
3005 | +/** |
3006 | + * bluetooth_chooser_dump_selected_device: |
3007 | + * @self: A #BluetoothChooser widget. |
3008 | + * |
3009 | + * Prints all the known attributes for the currently selected device |
3010 | + * on the standard output. Useful for debugging. |
3011 | + **/ |
3012 | +void |
3013 | +bluetooth_chooser_dump_selected_device (BluetoothChooser *self) |
3014 | +{ |
3015 | + BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self); |
3016 | + GtkTreeIter iter; |
3017 | + GtkTreeModel *model; |
3018 | + |
3019 | + gtk_tree_selection_get_selected (priv->selection, &model, &iter); |
3020 | + |
3021 | + bluetooth_client_dump_device (model, &iter); |
3022 | +} |
3023 | + |
3024 | +/** |
3025 | + * bluetooth_chooser_get_model: |
3026 | + * @self: A #BluetoothChooser widget. |
3027 | + * |
3028 | + * Returns the #BluetoothChooser's #GtkTreeModel. |
3029 | + * |
3030 | + * Return value: a #GtkTreeModel object. |
3031 | + **/ |
3032 | +GtkTreeModel * |
3033 | +bluetooth_chooser_get_model (BluetoothChooser *self) |
3034 | +{ |
3035 | + BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self); |
3036 | + |
3037 | + return priv->model; |
3038 | +} |
3039 | + |
3040 | +/** |
3041 | + * bluetooth_chooser_get_treeview: |
3042 | + * @self: A #BluetoothChooser widget. |
3043 | + * |
3044 | + * Returns the #GtkTreeView object for the #BluetoothChooser. |
3045 | + * |
3046 | + * Return value: a #GtkTreeView object. |
3047 | + **/ |
3048 | +GtkWidget * |
3049 | +bluetooth_chooser_get_treeview (BluetoothChooser *self) |
3050 | +{ |
3051 | + BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self); |
3052 | + |
3053 | + return priv->treeview; |
3054 | +} |
3055 | + |
3056 | +/** |
3057 | + * bluetooth_chooser_get_scrolled_window: |
3058 | + * @self: A #BluetoothChooser widget. |
3059 | + * |
3060 | + * Returns the #GtkScrolledWindow object for the #BluetoothChooser. |
3061 | + * This is useful to set a minimum height to the chooser using |
3062 | + * gtk_scrolled_window_set_min_content_height() or to join the |
3063 | + * chooser with a toolbar. |
3064 | + * |
3065 | + * Return value: (transfer none): a #GtkScrolledWindow object. |
3066 | + **/ |
3067 | +GtkWidget * |
3068 | +bluetooth_chooser_get_scrolled_window (BluetoothChooser *self) |
3069 | +{ |
3070 | + BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self); |
3071 | + |
3072 | + return priv->scrolled_window; |
3073 | +} |
3074 | + |
3075 | +static void |
3076 | +device_model_row_changed (GtkTreeModel *model, |
3077 | + GtkTreePath *path, |
3078 | + GtkTreeIter *iter, |
3079 | + gpointer data) |
3080 | +{ |
3081 | + BluetoothChooser *self = BLUETOOTH_CHOOSER (data); |
3082 | + BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self); |
3083 | + char *address; |
3084 | + |
3085 | + /* Not the selection changing? */ |
3086 | + if (gtk_tree_selection_path_is_selected (priv->selection, path) == FALSE) |
3087 | + return; |
3088 | + |
3089 | + g_object_notify (G_OBJECT (self), "device-selected"); |
3090 | + address = bluetooth_chooser_get_selected_device (self); |
3091 | + g_signal_emit (G_OBJECT (self), |
3092 | + selection_table_signals[SELECTED_DEVICE_CHANGED], |
3093 | + 0, address); |
3094 | + g_free (address); |
3095 | +} |
3096 | + |
3097 | +static void |
3098 | +select_browse_device_callback (GtkTreeSelection *selection, gpointer user_data) |
3099 | +{ |
3100 | + BluetoothChooser *self = user_data; |
3101 | + char *address; |
3102 | + |
3103 | + g_object_notify (G_OBJECT(self), "device-selected"); |
3104 | + address = bluetooth_chooser_get_selected_device (self); |
3105 | + g_signal_emit (G_OBJECT (self), |
3106 | + selection_table_signals[SELECTED_DEVICE_CHANGED], |
3107 | + 0, address); |
3108 | + g_free (address); |
3109 | +} |
3110 | + |
3111 | +static void |
3112 | +row_activated_cb (GtkTreeView *tree_view, |
3113 | + GtkTreePath *path, |
3114 | + GtkTreeViewColumn *column, |
3115 | + BluetoothChooser *self) |
3116 | +{ |
3117 | + char *address; |
3118 | + |
3119 | + address = bluetooth_chooser_get_selected_device (self); |
3120 | + g_signal_emit (G_OBJECT (self), |
3121 | + selection_table_signals[SELECTED_DEVICE_ACTIVATED], |
3122 | + 0, address); |
3123 | + g_free (address); |
3124 | +} |
3125 | + |
3126 | +static gboolean |
3127 | +filter_type_func (GtkTreeModel *model, GtkTreeIter *iter, BluetoothChooserPrivate *priv) |
3128 | +{ |
3129 | + int type; |
3130 | + |
3131 | + if (priv->device_type_filter == BLUETOOTH_TYPE_ANY) |
3132 | + return TRUE; |
3133 | + |
3134 | + gtk_tree_model_get (model, iter, BLUETOOTH_COLUMN_TYPE, &type, -1); |
3135 | + return (type & priv->device_type_filter); |
3136 | +} |
3137 | + |
3138 | +static gboolean |
3139 | +filter_category_func (GtkTreeModel *model, GtkTreeIter *iter, BluetoothChooserPrivate *priv) |
3140 | +{ |
3141 | + gboolean bonded, trusted; |
3142 | + |
3143 | + if (priv->device_category_filter == BLUETOOTH_CATEGORY_ALL) |
3144 | + return TRUE; |
3145 | + |
3146 | + gtk_tree_model_get (model, iter, |
3147 | + BLUETOOTH_COLUMN_PAIRED, &bonded, |
3148 | + BLUETOOTH_COLUMN_TRUSTED, &trusted, |
3149 | + -1); |
3150 | + |
3151 | + if (priv->device_category_filter == BLUETOOTH_CATEGORY_PAIRED) |
3152 | + return bonded; |
3153 | + if (priv->device_category_filter == BLUETOOTH_CATEGORY_TRUSTED) |
3154 | + return trusted; |
3155 | + if (priv->device_category_filter == BLUETOOTH_CATEGORY_NOT_PAIRED_OR_TRUSTED) |
3156 | + return (!bonded && !trusted); |
3157 | + if (priv->device_category_filter == BLUETOOTH_CATEGORY_PAIRED_OR_TRUSTED) |
3158 | + return (bonded || trusted); |
3159 | + |
3160 | + g_assert_not_reached (); |
3161 | + |
3162 | + return FALSE; |
3163 | +} |
3164 | + |
3165 | +static gboolean |
3166 | +filter_service_func (GtkTreeModel *model, GtkTreeIter *iter, BluetoothChooserPrivate *priv) |
3167 | +{ |
3168 | + char **services; |
3169 | + gboolean ret = FALSE; |
3170 | + guint i; |
3171 | + |
3172 | + if (priv->device_service_filter == NULL) |
3173 | + return TRUE; |
3174 | + |
3175 | + gtk_tree_model_get (model, iter, |
3176 | + BLUETOOTH_COLUMN_UUIDS, &services, |
3177 | + -1); |
3178 | + if (services == NULL) { |
3179 | + /* FIXME we need a way to discover the services here */ |
3180 | + return FALSE; |
3181 | + } |
3182 | + |
3183 | + for (i = 0; services[i] != NULL; i++) { |
3184 | + if (g_str_equal (priv->device_service_filter, services[i]) != FALSE) { |
3185 | + ret = TRUE; |
3186 | + break; |
3187 | + } |
3188 | + } |
3189 | + |
3190 | + g_strfreev (services); |
3191 | + |
3192 | + return ret; |
3193 | +} |
3194 | + |
3195 | +static gboolean |
3196 | +filter_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data) |
3197 | +{ |
3198 | + BluetoothChooser *self = BLUETOOTH_CHOOSER (data); |
3199 | + BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self); |
3200 | + |
3201 | + return filter_type_func (model, iter, priv) |
3202 | + && filter_category_func (model, iter, priv) |
3203 | + && filter_service_func (model, iter, priv); |
3204 | +} |
3205 | + |
3206 | +static void |
3207 | +filter_type_changed_cb (GObject *object, GParamSpec *spec, gpointer user_data) |
3208 | +{ |
3209 | + BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(object); |
3210 | + |
3211 | + if (priv->filter) |
3212 | + gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter)); |
3213 | +} |
3214 | + |
3215 | +static void |
3216 | +filter_category_changed_cb (GObject *object, GParamSpec *spec, gpointer user_data) |
3217 | +{ |
3218 | + BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(object); |
3219 | + |
3220 | + if (priv->filter) |
3221 | + gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter)); |
3222 | +} |
3223 | + |
3224 | +static void |
3225 | +adapter_model_row_changed (GtkTreeModel *model, |
3226 | + GtkTreePath *path, |
3227 | + GtkTreeIter *iter, |
3228 | + gpointer data) |
3229 | +{ |
3230 | + BluetoothChooser *self = BLUETOOTH_CHOOSER (data); |
3231 | + BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self); |
3232 | + gboolean discovering, is_default, powered; |
3233 | + |
3234 | + /* Not an adapter changing? */ |
3235 | + if (gtk_tree_path_get_depth (path) != 1) |
3236 | + return; |
3237 | + |
3238 | + gtk_tree_model_get (model, iter, |
3239 | + BLUETOOTH_COLUMN_DEFAULT, &is_default, |
3240 | + BLUETOOTH_COLUMN_DISCOVERING, &discovering, |
3241 | + BLUETOOTH_COLUMN_POWERED, &powered, |
3242 | + -1); |
3243 | + |
3244 | + if (is_default == FALSE) |
3245 | + return; |
3246 | + if (powered != FALSE && discovering == FALSE && priv->disco_rq != FALSE) { |
3247 | + g_object_set (G_OBJECT (priv->client), "default-adapter-discovering", TRUE, NULL); |
3248 | + set_search_label (self, TRUE); |
3249 | + return; |
3250 | + } |
3251 | + gtk_widget_set_sensitive (GTK_WIDGET (priv->treeview), powered); |
3252 | + set_search_label (self, discovering); |
3253 | +} |
3254 | + |
3255 | +static void default_adapter_changed (GObject *gobject, |
3256 | + GParamSpec *arg1, |
3257 | + gpointer data) |
3258 | +{ |
3259 | + BluetoothChooser *self = BLUETOOTH_CHOOSER (data); |
3260 | + BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self); |
3261 | + char *adapter; |
3262 | + |
3263 | + g_object_get (gobject, "default-adapter", &adapter, NULL); |
3264 | + |
3265 | + if (adapter == NULL) { |
3266 | + gtk_widget_set_sensitive (GTK_WIDGET (priv->treeview), FALSE); |
3267 | + set_search_label (self, FALSE); |
3268 | + gtk_tree_view_set_model (GTK_TREE_VIEW(priv->treeview), NULL); |
3269 | + } |
3270 | + |
3271 | + if (priv->model) { |
3272 | + g_object_unref (priv->model); |
3273 | + priv->model = NULL; |
3274 | + } |
3275 | + |
3276 | + if (adapter == NULL) |
3277 | + return; |
3278 | + |
3279 | + g_free (adapter); |
3280 | + |
3281 | + priv->model = bluetooth_client_get_device_model (priv->client); |
3282 | + if (priv->model) { |
3283 | + priv->filter = gtk_tree_model_filter_new (priv->model, NULL); |
3284 | + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (priv->filter), |
3285 | + filter_func, self, NULL); |
3286 | + gtk_tree_view_set_model (GTK_TREE_VIEW(priv->treeview), priv->filter); |
3287 | + g_signal_connect (priv->filter, "row-changed", |
3288 | + G_CALLBACK (device_model_row_changed), self); |
3289 | + g_object_unref (priv->filter); |
3290 | + gtk_widget_set_sensitive (GTK_WIDGET (priv->treeview), TRUE); |
3291 | + |
3292 | + /* Start a discovery if it was requested before we |
3293 | + * had an adapter available */ |
3294 | + if (priv->disco_rq != FALSE) { |
3295 | + bluetooth_chooser_start_discovery (self); |
3296 | + set_search_label (self, TRUE); |
3297 | + } |
3298 | + } |
3299 | +} |
3300 | + |
3301 | +static GtkWidget * |
3302 | +create_treeview (BluetoothChooser *self) |
3303 | +{ |
3304 | + BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self); |
3305 | + GtkWidget *scrolled, *tree; |
3306 | + GtkCellRenderer *renderer; |
3307 | + GtkTreeViewColumn *column; |
3308 | + |
3309 | + /* Create the scrolled window */ |
3310 | + scrolled = gtk_scrolled_window_new (NULL, NULL); |
3311 | + |
3312 | + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scrolled), |
3313 | + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); |
3314 | + |
3315 | + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(scrolled), |
3316 | + GTK_SHADOW_OUT); |
3317 | + |
3318 | + /* Create the tree view */ |
3319 | + tree = gtk_tree_view_new (); |
3320 | + |
3321 | + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(tree), TRUE); |
3322 | + |
3323 | + gtk_tree_view_set_rules_hint (GTK_TREE_VIEW(tree), TRUE); |
3324 | + |
3325 | + g_object_set (tree, "show-expanders", FALSE, NULL); |
3326 | + |
3327 | + g_signal_connect (G_OBJECT (tree), "row-activated", |
3328 | + G_CALLBACK (row_activated_cb), self); |
3329 | + |
3330 | + column = gtk_tree_view_column_new (); |
3331 | + |
3332 | + gtk_tree_view_column_set_title (column, _("Device")); |
3333 | + gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN(column), TRUE); |
3334 | + |
3335 | + /* The type icon */ |
3336 | + renderer = gtk_cell_renderer_pixbuf_new (); |
3337 | + gtk_tree_view_column_set_spacing (column, 4); |
3338 | + gtk_tree_view_column_pack_start (column, renderer, FALSE); |
3339 | + gtk_tree_view_column_set_attributes (column, renderer, |
3340 | + "icon-name", BLUETOOTH_COLUMN_ICON, NULL); |
3341 | + |
3342 | + /* The device name */ |
3343 | + renderer = gtk_cell_renderer_text_new (); |
3344 | + gtk_tree_view_column_pack_start (column, renderer, TRUE); |
3345 | + g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL); |
3346 | + gtk_tree_view_column_set_cell_data_func (column, renderer, |
3347 | + alias_to_label, NULL, NULL); |
3348 | + |
3349 | + /* The connected icon */ |
3350 | + priv->connected_cell = gtk_cell_renderer_pixbuf_new (); |
3351 | + gtk_tree_view_column_pack_start (column, priv->connected_cell, FALSE); |
3352 | + |
3353 | + gtk_tree_view_column_set_cell_data_func (column, priv->connected_cell, |
3354 | + connected_to_icon, NULL, NULL); |
3355 | + g_object_set (G_OBJECT (priv->connected_cell), "visible", priv->show_connected, NULL); |
3356 | + |
3357 | + /* The bonded icon */ |
3358 | + priv->bonded_cell = gtk_cell_renderer_pixbuf_new (); |
3359 | + gtk_tree_view_column_pack_end (column, priv->bonded_cell, FALSE); |
3360 | + |
3361 | + gtk_tree_view_column_set_cell_data_func (column, priv->bonded_cell, |
3362 | + bonded_to_icon, NULL, NULL); |
3363 | + g_object_set (G_OBJECT (priv->bonded_cell), "visible", priv->show_paired, NULL); |
3364 | + |
3365 | + gtk_tree_view_append_column (GTK_TREE_VIEW(tree), column); |
3366 | + |
3367 | + gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW(tree), -1, |
3368 | + _("Type"), gtk_cell_renderer_text_new(), |
3369 | + type_to_text, NULL, NULL); |
3370 | + |
3371 | + priv->selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(tree)); |
3372 | + |
3373 | + gtk_tree_selection_set_mode (priv->selection, GTK_SELECTION_SINGLE); |
3374 | + |
3375 | + g_signal_connect (G_OBJECT(priv->selection), "changed", |
3376 | + G_CALLBACK(select_browse_device_callback), self); |
3377 | + |
3378 | + /* Set the model, and filter */ |
3379 | + priv->model = bluetooth_client_get_device_model (priv->client); |
3380 | + if (priv->model) { |
3381 | + priv->filter = gtk_tree_model_filter_new (priv->model, NULL); |
3382 | + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (priv->filter), |
3383 | + filter_func, self, NULL); |
3384 | + gtk_tree_view_set_model (GTK_TREE_VIEW(tree), priv->filter); |
3385 | + g_signal_connect (priv->filter, "row-changed", |
3386 | + G_CALLBACK (device_model_row_changed), self); |
3387 | + g_object_unref (priv->filter); |
3388 | + } else { |
3389 | + gtk_widget_set_sensitive (GTK_WIDGET (tree), FALSE); |
3390 | + set_search_label (self, FALSE); |
3391 | + } |
3392 | + |
3393 | + gtk_container_add (GTK_CONTAINER(scrolled), tree); |
3394 | + priv->treeview = tree; |
3395 | + |
3396 | + return scrolled; |
3397 | +} |
3398 | + |
3399 | +static void |
3400 | +bluetooth_chooser_init(BluetoothChooser *self) |
3401 | +{ |
3402 | + BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self); |
3403 | + |
3404 | + GtkWidget *vbox; |
3405 | + GtkWidget *hbox; |
3406 | + |
3407 | + gtk_widget_push_composite_child (); |
3408 | + |
3409 | + g_object_set (G_OBJECT (self), "orientation", GTK_ORIENTATION_VERTICAL, NULL); |
3410 | + |
3411 | + priv->client = bluetooth_client_new (); |
3412 | + |
3413 | + /* Setup the widget itself */ |
3414 | + gtk_box_set_spacing (GTK_BOX(self), 18); |
3415 | + gtk_container_set_border_width (GTK_CONTAINER(self), 0); |
3416 | + |
3417 | + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); |
3418 | + gtk_widget_show (vbox); |
3419 | + gtk_box_pack_start (GTK_BOX (self), vbox, TRUE, TRUE, 0); |
3420 | + |
3421 | + /* The treeview label */ |
3422 | + priv->search_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 24); |
3423 | + gtk_widget_set_name (priv->search_hbox, "search_hbox"); |
3424 | + if (priv->show_searching) |
3425 | + gtk_widget_show (priv->search_hbox); |
3426 | + gtk_box_pack_end (GTK_BOX (vbox), priv->search_hbox, FALSE, TRUE, 0); |
3427 | + gtk_widget_set_no_show_all (priv->search_hbox, TRUE); |
3428 | + |
3429 | + /* Setup the adapter disco mode callback for the search button */ |
3430 | + priv->adapter_model = bluetooth_client_get_adapter_model (priv->client); |
3431 | + g_signal_connect (priv->adapter_model, "row-changed", |
3432 | + G_CALLBACK (adapter_model_row_changed), self); |
3433 | + |
3434 | + /* The searching label */ |
3435 | + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); |
3436 | + gtk_widget_set_name (hbox, "searching label hbox"); |
3437 | + priv->spinner = gtk_spinner_new (); |
3438 | + gtk_container_add (GTK_CONTAINER (hbox), priv->spinner); |
3439 | + gtk_widget_show (priv->spinner); |
3440 | + priv->search_label = gtk_label_new (_("Searching for devices...")); |
3441 | + gtk_container_add (GTK_CONTAINER (hbox), priv->search_label); |
3442 | + gtk_widget_show (priv->search_label); |
3443 | + gtk_widget_show (hbox); |
3444 | + |
3445 | + if (priv->show_searching) { |
3446 | + gboolean discovering; |
3447 | + |
3448 | + g_object_get (G_OBJECT (priv->client), "default-adapter-discovering", &discovering, NULL); |
3449 | + set_search_label (self, discovering); |
3450 | + } |
3451 | + |
3452 | + gtk_box_pack_start (GTK_BOX (priv->search_hbox), hbox, FALSE, TRUE, 0); |
3453 | + |
3454 | + /* The treeview */ |
3455 | + priv->scrolled_window = create_treeview (self); |
3456 | + gtk_widget_show_all (priv->scrolled_window); |
3457 | + gtk_box_pack_start (GTK_BOX (vbox), priv->scrolled_window, TRUE, TRUE, 0); |
3458 | + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); |
3459 | + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scrolled_window), GTK_SHADOW_IN); |
3460 | + |
3461 | + /* The filters */ |
3462 | + priv->device_type_filter_model = GTK_TREE_MODEL (gtk_list_store_new (DEVICE_TYPE_FILTER_NUM_COLS, |
3463 | + G_TYPE_STRING, G_TYPE_INT)); |
3464 | + priv->filters_vbox = bluetooth_filter_widget_new (); |
3465 | + gtk_widget_show (priv->filters_vbox); |
3466 | + gtk_box_pack_start (GTK_BOX (self), priv->filters_vbox, FALSE, TRUE, 0); |
3467 | + gtk_widget_set_no_show_all (priv->filters_vbox, TRUE); |
3468 | + |
3469 | + /* if filters are not visible hide the vbox */ |
3470 | + if (!priv->show_device_type && !priv->show_device_category) |
3471 | + gtk_widget_hide (priv->filters_vbox); |
3472 | + |
3473 | + priv->default_adapter_changed_id = g_signal_connect (priv->client, "notify::default-adapter", |
3474 | + G_CALLBACK (default_adapter_changed), self); |
3475 | + |
3476 | + g_signal_connect(self, "notify::device-type-filter", |
3477 | + G_CALLBACK(filter_type_changed_cb), NULL); |
3478 | + g_signal_connect(self, "notify::device-category-filter", |
3479 | + G_CALLBACK(filter_category_changed_cb), NULL); |
3480 | + |
3481 | + gtk_widget_pop_composite_child (); |
3482 | +} |
3483 | + |
3484 | +static GObject * |
3485 | +bluetooth_chooser_constructor (GType type, |
3486 | + guint n_construct_params, |
3487 | + GObjectConstructParam *construct_params) |
3488 | +{ |
3489 | + BluetoothChooser *self; |
3490 | + BluetoothChooserPrivate *priv; |
3491 | + GObject *object; |
3492 | + |
3493 | + object = G_OBJECT_CLASS (bluetooth_chooser_parent_class)->constructor (type, |
3494 | + n_construct_params, |
3495 | + construct_params); |
3496 | + self = BLUETOOTH_CHOOSER (object); |
3497 | + priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self); |
3498 | + |
3499 | + if (priv->internal_filter) { |
3500 | + bluetooth_filter_widget_bind_filter (BLUETOOTH_FILTER_WIDGET (priv->filters_vbox), self); |
3501 | + } |
3502 | + return object; |
3503 | +} |
3504 | + |
3505 | +static void |
3506 | +bluetooth_chooser_finalize (GObject *object) |
3507 | +{ |
3508 | + BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(object); |
3509 | + |
3510 | + if (priv->client) { |
3511 | + g_signal_handler_disconnect (G_OBJECT(priv->client), priv->default_adapter_changed_id); |
3512 | + priv->default_adapter_changed_id = 0; |
3513 | + |
3514 | + g_object_set (G_OBJECT (priv->client), "default-adapter-discovering", FALSE, NULL); |
3515 | + g_object_unref (priv->client); |
3516 | + priv->client = NULL; |
3517 | + } |
3518 | + if (priv->adapter_model) { |
3519 | + g_object_unref (priv->adapter_model); |
3520 | + priv->adapter_model = NULL; |
3521 | + } |
3522 | + if (priv->model != NULL) { |
3523 | + g_object_unref (priv->model); |
3524 | + priv->model = NULL; |
3525 | + } |
3526 | + g_free (priv->device_service_filter); |
3527 | + |
3528 | + G_OBJECT_CLASS(bluetooth_chooser_parent_class)->finalize(object); |
3529 | +} |
3530 | + |
3531 | +enum { |
3532 | + PROP_0, |
3533 | + PROP_DEVICE_SELECTED, |
3534 | + PROP_SHOW_PAIRING, |
3535 | + PROP_SHOW_CONNECTED, |
3536 | + PROP_SHOW_SEARCHING, |
3537 | + PROP_SHOW_DEVICE_TYPE, |
3538 | + PROP_SHOW_DEVICE_TYPE_COLUMN, |
3539 | + PROP_SHOW_DEVICE_CATEGORY, |
3540 | + PROP_DEVICE_TYPE_FILTER, |
3541 | + PROP_DEVICE_CATEGORY_FILTER, |
3542 | + PROP_DEVICE_SERVICE_FILTER, |
3543 | + PROP_INTERNAL_FILTER |
3544 | +}; |
3545 | + |
3546 | +static void |
3547 | +bluetooth_chooser_set_property (GObject *object, guint prop_id, |
3548 | + const GValue *value, GParamSpec *pspec) |
3549 | +{ |
3550 | + BluetoothChooser *self = BLUETOOTH_CHOOSER (object); |
3551 | + BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE (object); |
3552 | + |
3553 | + switch (prop_id) { |
3554 | + case PROP_DEVICE_SELECTED: { |
3555 | + const char *address; |
3556 | + char *selected; |
3557 | + GtkTreeIter iter; |
3558 | + gboolean cont; |
3559 | + |
3560 | + address = g_value_get_string (value); |
3561 | + if (address == NULL) { |
3562 | + gtk_tree_selection_unselect_all (priv->selection); |
3563 | + return; |
3564 | + } |
3565 | + |
3566 | + selected = bluetooth_chooser_get_selected_device (self); |
3567 | + if (g_strcmp0 (selected, address) == 0) { |
3568 | + g_free (selected); |
3569 | + return; |
3570 | + } |
3571 | + g_free (selected); |
3572 | + |
3573 | + cont = gtk_tree_model_get_iter_first (priv->filter, &iter); |
3574 | + while (cont == TRUE) { |
3575 | + char *iaddress; |
3576 | + gtk_tree_model_get (priv->filter, &iter, |
3577 | + BLUETOOTH_COLUMN_ADDRESS, &iaddress, -1); |
3578 | + if (g_strcmp0 (iaddress, address) == 0) { |
3579 | + gtk_tree_selection_select_iter (priv->selection, &iter); |
3580 | + g_free (iaddress); |
3581 | + return; |
3582 | + } |
3583 | + g_free (iaddress); |
3584 | + |
3585 | + cont = gtk_tree_model_iter_next (priv->filter, &iter); |
3586 | + } |
3587 | + break; |
3588 | + } |
3589 | + case PROP_SHOW_PAIRING: |
3590 | + priv->show_paired = g_value_get_boolean (value); |
3591 | + if (priv->bonded_cell != NULL) |
3592 | + g_object_set (G_OBJECT (priv->bonded_cell), "visible", priv->show_paired, NULL); |
3593 | + break; |
3594 | + case PROP_SHOW_CONNECTED: |
3595 | + priv->show_connected = g_value_get_boolean (value); |
3596 | + if (priv->connected_cell != NULL) |
3597 | + g_object_set (G_OBJECT (priv->connected_cell), "visible", priv->show_connected, NULL); |
3598 | + break; |
3599 | + case PROP_SHOW_SEARCHING: |
3600 | + priv->show_searching = g_value_get_boolean (value); |
3601 | + g_object_set (G_OBJECT (priv->search_hbox), "visible", priv->show_searching, NULL); |
3602 | + break; |
3603 | + case PROP_SHOW_DEVICE_TYPE: |
3604 | + priv->show_device_type = g_value_get_boolean (value); |
3605 | + if (priv->internal_filter) { |
3606 | + if (priv->show_device_type || priv->show_device_category) |
3607 | + g_object_set (G_OBJECT (priv->filters_vbox), "visible", TRUE, NULL); |
3608 | + else |
3609 | + g_object_set (G_OBJECT (priv->filters_vbox), "visible", FALSE, NULL); |
3610 | + } |
3611 | + break; |
3612 | + case PROP_SHOW_DEVICE_TYPE_COLUMN: { |
3613 | + GtkTreeViewColumn *column; |
3614 | + |
3615 | + column = gtk_tree_view_get_column (GTK_TREE_VIEW (priv->treeview), TREEVIEW_COLUMN_TYPE); |
3616 | + gtk_tree_view_column_set_visible (column, |
3617 | + g_value_get_boolean (value)); |
3618 | + |
3619 | + column = gtk_tree_view_get_column (GTK_TREE_VIEW (priv->treeview), TREEVIEW_COLUMN_DEVICE); |
3620 | + if (g_value_get_boolean (value)) |
3621 | + gtk_tree_view_column_set_title (column, _("Device")); |
3622 | + else |
3623 | + gtk_tree_view_column_set_title (column, _("Devices")); |
3624 | + break; |
3625 | + } |
3626 | + case PROP_SHOW_DEVICE_CATEGORY: |
3627 | + priv->show_device_category = g_value_get_boolean (value); |
3628 | + if (priv->internal_filter) { |
3629 | + if (priv->show_device_type || priv->show_device_category) |
3630 | + g_object_set (G_OBJECT (priv->filters_vbox), "visible", TRUE, NULL); |
3631 | + else |
3632 | + g_object_set (G_OBJECT (priv->filters_vbox), "visible", FALSE, NULL); |
3633 | + } |
3634 | + break; |
3635 | + case PROP_DEVICE_TYPE_FILTER: |
3636 | + priv->device_type_filter = g_value_get_int (value); |
3637 | + g_object_notify (object, "device-type-filter"); |
3638 | + break; |
3639 | + case PROP_DEVICE_CATEGORY_FILTER: |
3640 | + priv->device_category_filter = g_value_get_enum (value); |
3641 | + g_object_notify (object, "device-category-filter"); |
3642 | + break; |
3643 | + case PROP_DEVICE_SERVICE_FILTER: |
3644 | + g_free (priv->device_service_filter); |
3645 | + priv->device_service_filter = g_value_dup_string (value); |
3646 | + if (priv->filter) |
3647 | + gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter)); |
3648 | + break; |
3649 | + case PROP_INTERNAL_FILTER: |
3650 | + priv->internal_filter = g_value_get_boolean (value); |
3651 | + g_object_set (G_OBJECT (priv->filters_vbox), "visible", priv->internal_filter, NULL); |
3652 | + break; |
3653 | + default: |
3654 | + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); |
3655 | + break; |
3656 | + } |
3657 | +} |
3658 | + |
3659 | +static void |
3660 | +bluetooth_chooser_get_property (GObject *object, guint prop_id, |
3661 | + GValue *value, GParamSpec *pspec) |
3662 | +{ |
3663 | + BluetoothChooser *self = BLUETOOTH_CHOOSER(object); |
3664 | + BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(object); |
3665 | + |
3666 | + switch (prop_id) { |
3667 | + case PROP_DEVICE_SELECTED: |
3668 | + g_value_take_string (value, bluetooth_chooser_get_selected_device (self)); |
3669 | + break; |
3670 | + case PROP_SHOW_PAIRING: |
3671 | + g_value_set_boolean (value, priv->show_paired); |
3672 | + break; |
3673 | + case PROP_SHOW_CONNECTED: |
3674 | + g_value_set_boolean (value, priv->show_connected); |
3675 | + break; |
3676 | + case PROP_SHOW_SEARCHING: |
3677 | + g_value_set_boolean (value, priv->show_searching); |
3678 | + break; |
3679 | + case PROP_SHOW_DEVICE_TYPE: |
3680 | + g_value_set_boolean (value, priv->show_device_type); |
3681 | + break; |
3682 | + case PROP_SHOW_DEVICE_TYPE_COLUMN: |
3683 | + g_value_set_boolean (value, |
3684 | + gtk_tree_view_column_get_visible (gtk_tree_view_get_column (GTK_TREE_VIEW (priv->treeview), TREEVIEW_COLUMN_TYPE))); |
3685 | + break; |
3686 | + case PROP_SHOW_DEVICE_CATEGORY: |
3687 | + g_value_set_boolean (value, priv->show_device_category); |
3688 | + break; |
3689 | + case PROP_DEVICE_TYPE_FILTER: |
3690 | + g_value_set_int (value, priv->device_type_filter); |
3691 | + break; |
3692 | + case PROP_DEVICE_CATEGORY_FILTER: |
3693 | + g_value_set_enum (value, priv->device_category_filter); |
3694 | + break; |
3695 | + case PROP_DEVICE_SERVICE_FILTER: |
3696 | + g_value_set_string (value, priv->device_service_filter); |
3697 | + break; |
3698 | + case PROP_INTERNAL_FILTER: |
3699 | + g_value_set_boolean (value, priv->internal_filter); |
3700 | + break; |
3701 | + default: |
3702 | + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); |
3703 | + break; |
3704 | + } |
3705 | +} |
3706 | + |
3707 | +static void |
3708 | +bluetooth_chooser_class_init (BluetoothChooserClass *klass) |
3709 | +{ |
3710 | + /* Use to calculate the maximum value for the |
3711 | + * device-type-filter value */ |
3712 | + guint i; |
3713 | + int max_filter_val; |
3714 | + |
3715 | + bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); |
3716 | + |
3717 | + g_type_class_add_private(klass, sizeof(BluetoothChooserPrivate)); |
3718 | + |
3719 | + G_OBJECT_CLASS(klass)->constructor = bluetooth_chooser_constructor; |
3720 | + G_OBJECT_CLASS(klass)->finalize = bluetooth_chooser_finalize; |
3721 | + |
3722 | + G_OBJECT_CLASS(klass)->set_property = bluetooth_chooser_set_property; |
3723 | + G_OBJECT_CLASS(klass)->get_property = bluetooth_chooser_get_property; |
3724 | + |
3725 | + /** |
3726 | + * BluetoothChooser::selected-device-changed: |
3727 | + * @chooser: a #BluetoothChooser widget which received the signal |
3728 | + * @address: the Bluetooth address for the currently selected device, or %NULL |
3729 | + * |
3730 | + * The #BluetoothChooser::selected-device-changed signal is launched when the |
3731 | + * selected device is changed, it will be %NULL if a device was unselected. |
3732 | + **/ |
3733 | + selection_table_signals[SELECTED_DEVICE_CHANGED] = |
3734 | + g_signal_new ("selected-device-changed", |
3735 | + G_TYPE_FROM_CLASS (klass), |
3736 | + G_SIGNAL_RUN_LAST, |
3737 | + G_STRUCT_OFFSET (BluetoothChooserClass, selected_device_changed), |
3738 | + NULL, NULL, |
3739 | + g_cclosure_marshal_VOID__STRING, |
3740 | + G_TYPE_NONE, 1, G_TYPE_STRING); |
3741 | + /** |
3742 | + * BluetoothChooser::selected-device-activated: |
3743 | + * @chooser: a #BluetoothChooser widget which received the signal |
3744 | + * @address: the Bluetooth address for the currently selected device, or %NULL |
3745 | + * |
3746 | + * The #BluetoothChooser::selected-device-activated signal is launched when a |
3747 | + * device is double-clicked in the chooser. |
3748 | + **/ |
3749 | + selection_table_signals[SELECTED_DEVICE_ACTIVATED] = |
3750 | + g_signal_new ("selected-device-activated", |
3751 | + G_TYPE_FROM_CLASS (klass), |
3752 | + G_SIGNAL_RUN_LAST, |
3753 | + G_STRUCT_OFFSET (BluetoothChooserClass, selected_device_activated), |
3754 | + NULL, NULL, |
3755 | + g_cclosure_marshal_VOID__STRING, |
3756 | + G_TYPE_NONE, 1, G_TYPE_STRING); |
3757 | + |
3758 | + g_object_class_install_property (G_OBJECT_CLASS(klass), |
3759 | + PROP_DEVICE_SELECTED, g_param_spec_string ("device-selected", |
3760 | + "device-selected", "The Bluetooth address for the currently selected device, or %NULL", NULL, G_PARAM_READABLE | G_PARAM_WRITABLE)); |
3761 | + g_object_class_install_property (G_OBJECT_CLASS(klass), |
3762 | + PROP_SHOW_PAIRING, g_param_spec_boolean ("show-pairing", |
3763 | + "show-pairing", "Whether to show the pairing column in the tree.", FALSE, G_PARAM_READWRITE)); |
3764 | + g_object_class_install_property (G_OBJECT_CLASS(klass), |
3765 | + PROP_SHOW_CONNECTED, g_param_spec_boolean ("show-connected", |
3766 | + "show-connected", "Whether to show the connected column in the tree.", FALSE, G_PARAM_READWRITE)); |
3767 | + g_object_class_install_property (G_OBJECT_CLASS(klass), |
3768 | + PROP_SHOW_SEARCHING, g_param_spec_boolean ("show-searching", |
3769 | + "show-searching", |
3770 | + "Whether to show the Searching label , this is necessary if you want to programmatically start a discovery, using bluetooth_chooser_start_discovery()", |
3771 | + FALSE, G_PARAM_READWRITE)); |
3772 | + g_object_class_install_property (G_OBJECT_CLASS(klass), |
3773 | + PROP_SHOW_DEVICE_TYPE, g_param_spec_boolean ("show-device-type", |
3774 | + "show-device-type", "Whether to show the device type filter", TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); |
3775 | + g_object_class_install_property (G_OBJECT_CLASS(klass), |
3776 | + PROP_SHOW_DEVICE_TYPE_COLUMN, g_param_spec_boolean ("show-device-type-column", |
3777 | + "show-device-type-column", "Whether to show the device type column", TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); |
3778 | + g_object_class_install_property (G_OBJECT_CLASS(klass), |
3779 | + PROP_SHOW_DEVICE_CATEGORY, g_param_spec_boolean ("show-device-category", |
3780 | + "show-device-category", "Whether to show the device category filter", TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); |
3781 | + for (i = 0, max_filter_val = 0 ; i < _BLUETOOTH_TYPE_NUM_TYPES; i++) |
3782 | + max_filter_val += 1 << i; |
3783 | + g_object_class_install_property (G_OBJECT_CLASS(klass), |
3784 | + PROP_DEVICE_TYPE_FILTER, g_param_spec_int ("device-type-filter", |
3785 | + "device-type-filter", "A bitmask of #BluetoothType to show", BLUETOOTH_TYPE_ANY, max_filter_val, 1, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); |
3786 | + g_object_class_install_property (G_OBJECT_CLASS(klass), |
3787 | + PROP_DEVICE_CATEGORY_FILTER, g_param_spec_enum ("device-category-filter", |
3788 | + "device-category-filter", "The #BluetoothCategory to show", BLUETOOTH_TYPE_CATEGORY, BLUETOOTH_CATEGORY_ALL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); |
3789 | + g_object_class_install_property (G_OBJECT_CLASS(klass), |
3790 | + PROP_DEVICE_SERVICE_FILTER, g_param_spec_string ("device-service-filter", |
3791 | + "device-service-filter", "A string representing the service to filter for", NULL, G_PARAM_WRITABLE)); |
3792 | + g_object_class_install_property (G_OBJECT_CLASS(klass), |
3793 | + PROP_INTERNAL_FILTER, g_param_spec_boolean ("has-internal-device-filter", |
3794 | + "has-internal-device-filter", "Whether the #BluetoothChooser should be constructed with a visible #BluetoothFilterWidget", TRUE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); |
3795 | +} |
3796 | + |
3797 | +/** |
3798 | + * bluetooth_chooser_new: |
3799 | + * |
3800 | + * Returns a new #BluetoothChooser widget. |
3801 | + * |
3802 | + * Return value: A #BluetoothChooser widget |
3803 | + **/ |
3804 | +GtkWidget * |
3805 | +bluetooth_chooser_new (void) |
3806 | +{ |
3807 | + return g_object_new(BLUETOOTH_TYPE_CHOOSER, NULL); |
3808 | +} |
3809 | + |
3810 | |
3811 | === added file 'panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser.h' |
3812 | --- panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser.h 1970-01-01 00:00:00 +0000 |
3813 | +++ panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser.h 2015-08-12 15:47:27 +0000 |
3814 | @@ -0,0 +1,86 @@ |
3815 | +/* |
3816 | + * |
3817 | + * BlueZ - Bluetooth protocol stack for Linux |
3818 | + * |
3819 | + * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org> |
3820 | + * Copyright (C) 2006-2007 Bastien Nocera <hadess@hadess.net> |
3821 | + * |
3822 | + * |
3823 | + * This library is free software; you can redistribute it and/or |
3824 | + * modify it under the terms of the GNU Lesser General Public |
3825 | + * License as published by the Free Software Foundation; either |
3826 | + * version 2.1 of the License, or (at your option) any later version. |
3827 | + * |
3828 | + * This library is distributed in the hope that it will be useful, |
3829 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3830 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3831 | + * Lesser General Public License for more details. |
3832 | + * |
3833 | + * You should have received a copy of the GNU Lesser General Public |
3834 | + * License along with this library; if not, write to the Free Software |
3835 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
3836 | + * |
3837 | + */ |
3838 | + |
3839 | +#ifndef __BLUETOOTH_CHOOSER_H |
3840 | +#define __BLUETOOTH_CHOOSER_H |
3841 | + |
3842 | +#include <gtk/gtk.h> |
3843 | +#include <bluetooth-enums.h> |
3844 | + |
3845 | +G_BEGIN_DECLS |
3846 | + |
3847 | +#define BLUETOOTH_TYPE_CHOOSER (bluetooth_chooser_get_type()) |
3848 | +#define BLUETOOTH_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ |
3849 | + BLUETOOTH_TYPE_CHOOSER, BluetoothChooser)) |
3850 | +#define BLUETOOTH_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \ |
3851 | + BLUETOOTH_TYPE_CHOOSER, BluetoothChooserClass)) |
3852 | +#define BLUETOOTH_IS_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \ |
3853 | + BLUETOOTH_TYPE_CHOOSER)) |
3854 | +#define BLUETOOTH_IS_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \ |
3855 | + BLUETOOTH_TYPE_CHOOSER)) |
3856 | +#define BLUETOOTH_GET_CHOOSER_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \ |
3857 | + BLUETOOTH_TYPE_CHOOSER, BluetoothChooserClass)) |
3858 | + |
3859 | +/** |
3860 | + * BluetoothChooser: |
3861 | + * |
3862 | + * The <structname>BluetoothChooser</structname> struct contains |
3863 | + * only private fields and should not be directly accessed. |
3864 | + */ |
3865 | +typedef struct _BluetoothChooser BluetoothChooser; |
3866 | +typedef struct _BluetoothChooserClass BluetoothChooserClass; |
3867 | + |
3868 | +struct _BluetoothChooser { |
3869 | + GtkBox parent; |
3870 | +}; |
3871 | + |
3872 | +struct _BluetoothChooserClass { |
3873 | + GtkBoxClass parent_class; |
3874 | + |
3875 | + void (*selected_device_changed) (BluetoothChooser *chooser, const char *address); |
3876 | + void (*selected_device_activated) (BluetoothChooser *chooser, const char *address); |
3877 | +}; |
3878 | + |
3879 | +GType bluetooth_chooser_get_type (void); |
3880 | + |
3881 | +GtkWidget *bluetooth_chooser_new (void); |
3882 | + |
3883 | +char *bluetooth_chooser_get_selected_device (BluetoothChooser *self); |
3884 | +gboolean bluetooth_chooser_get_selected_device_info (BluetoothChooser *self, |
3885 | + const char *field, |
3886 | + GValue *value); |
3887 | +char *bluetooth_chooser_get_selected_device_name (BluetoothChooser *self); |
3888 | +char * bluetooth_chooser_get_selected_device_icon (BluetoothChooser *self); |
3889 | +BluetoothType bluetooth_chooser_get_selected_device_type (BluetoothChooser *self); |
3890 | +gboolean bluetooth_chooser_get_selected_device_is_connected (BluetoothChooser *self); |
3891 | +void bluetooth_chooser_dump_selected_device (BluetoothChooser *self); |
3892 | + |
3893 | +GtkWidget *bluetooth_chooser_get_scrolled_window (BluetoothChooser *self); |
3894 | + |
3895 | +void bluetooth_chooser_start_discovery (BluetoothChooser *self); |
3896 | +void bluetooth_chooser_stop_discovery (BluetoothChooser *self); |
3897 | + |
3898 | +G_END_DECLS |
3899 | + |
3900 | +#endif /* __BLUETOOTH_CHOOSER_H */ |
3901 | |
3902 | === added file 'panels/bluetooth/gnome-bluetooth/lib/bluetooth-client-private.h' |
3903 | --- panels/bluetooth/gnome-bluetooth/lib/bluetooth-client-private.h 1970-01-01 00:00:00 +0000 |
3904 | +++ panels/bluetooth/gnome-bluetooth/lib/bluetooth-client-private.h 2015-08-12 15:47:27 +0000 |
3905 | @@ -0,0 +1,61 @@ |
3906 | +/* |
3907 | + * |
3908 | + * BlueZ - Bluetooth protocol stack for Linux |
3909 | + * |
3910 | + * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org> |
3911 | + * |
3912 | + * |
3913 | + * This library is free software; you can redistribute it and/or |
3914 | + * modify it under the terms of the GNU Lesser General Public |
3915 | + * License as published by the Free Software Foundation; either |
3916 | + * version 2.1 of the License, or (at your option) any later version. |
3917 | + * |
3918 | + * This library is distributed in the hope that it will be useful, |
3919 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3920 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3921 | + * Lesser General Public License for more details. |
3922 | + * |
3923 | + * You should have received a copy of the GNU Lesser General Public |
3924 | + * License along with this library; if not, write to the Free Software |
3925 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
3926 | + * |
3927 | + */ |
3928 | + |
3929 | +#ifndef __BLUETOOTH_CLIENT_PRIVATE_H |
3930 | +#define __BLUETOOTH_CLIENT_PRIVATE_H |
3931 | + |
3932 | +#include <glib-object.h> |
3933 | +#include <gtk/gtk.h> |
3934 | +#include <bluetooth-enums.h> |
3935 | + |
3936 | +G_BEGIN_DECLS |
3937 | + |
3938 | +typedef void (*BluetoothClientSetupFunc) (BluetoothClient *client, |
3939 | + const GError *error, |
3940 | + const char *device_path); |
3941 | + |
3942 | +void bluetooth_client_setup_device (BluetoothClient *client, |
3943 | + const char *path, |
3944 | + gboolean pair, |
3945 | + GCancellable *cancellable, |
3946 | + GAsyncReadyCallback callback, |
3947 | + gpointer user_data); |
3948 | +gboolean bluetooth_client_setup_device_finish (BluetoothClient *client, |
3949 | + GAsyncResult *res, |
3950 | + char **path, |
3951 | + GError **error); |
3952 | + |
3953 | +gboolean bluetooth_client_set_trusted(BluetoothClient *client, |
3954 | + const char *device, gboolean trusted); |
3955 | + |
3956 | +GDBusProxy *bluetooth_client_get_device (BluetoothClient *client, |
3957 | + const char *path); |
3958 | + |
3959 | +void bluetooth_client_dump_device (GtkTreeModel *model, |
3960 | + GtkTreeIter *iter); |
3961 | + |
3962 | +gboolean bluetooth_client_get_connectable(const char **uuids); |
3963 | + |
3964 | +G_END_DECLS |
3965 | + |
3966 | +#endif /* __BLUETOOTH_CLIENT_PRIVATE_H */ |
3967 | |
3968 | === added file 'panels/bluetooth/gnome-bluetooth/lib/bluetooth-client.c' |
3969 | --- panels/bluetooth/gnome-bluetooth/lib/bluetooth-client.c 1970-01-01 00:00:00 +0000 |
3970 | +++ panels/bluetooth/gnome-bluetooth/lib/bluetooth-client.c 2015-08-12 15:47:27 +0000 |
3971 | @@ -0,0 +1,1757 @@ |
3972 | +/* |
3973 | + * |
3974 | + * BlueZ - Bluetooth protocol stack for Linux |
3975 | + * |
3976 | + * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org> |
3977 | + * Copyright (C) 2010 Giovanni Campagna <scampa.giovanni@gmail.com> |
3978 | + * Copyright (C) 2013 Intel Corporation. |
3979 | + * |
3980 | + * |
3981 | + * This library is free software; you can redistribute it and/or |
3982 | + * modify it under the terms of the GNU Lesser General Public |
3983 | + * License as published by the Free Software Foundation; either |
3984 | + * version 2.1 of the License, or (at your option) any later version. |
3985 | + * |
3986 | + * This library is distributed in the hope that it will be useful, |
3987 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3988 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3989 | + * Lesser General Public License for more details. |
3990 | + * |
3991 | + * You should have received a copy of the GNU Lesser General Public |
3992 | + * License along with this library; if not, write to the Free Software |
3993 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
3994 | + * |
3995 | + */ |
3996 | + |
3997 | +/** |
3998 | + * SECTION:bluetooth-client |
3999 | + * @short_description: Bluetooth client object |
4000 | + * @stability: Stable |
4001 | + * @include: bluetooth-client.h |
4002 | + * |
4003 | + * The #BluetoothClient object is used to query the state of Bluetooth |
4004 | + * devices and adapters. |
4005 | + **/ |
4006 | + |
4007 | +#ifdef HAVE_CONFIG_H |
4008 | +#include <config.h> |
4009 | +#endif |
4010 | + |
4011 | +#include <string.h> |
4012 | +#include <glib/gi18n-lib.h> |
4013 | +#include <gtk/gtk.h> |
4014 | + |
4015 | +#include "bluetooth-client.h" |
4016 | +#include "bluetooth-client-private.h" |
4017 | +#include "bluetooth-client-glue.h" |
4018 | +#include "bluetooth-fdo-glue.h" |
4019 | +#include "bluetooth-utils.h" |
4020 | +#include "gnome-bluetooth-enum-types.h" |
4021 | + |
4022 | +#define BLUEZ_SERVICE "org.bluez" |
4023 | +#define BLUEZ_MANAGER_PATH "/" |
4024 | +#define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter1" |
4025 | +#define BLUEZ_DEVICE_INTERFACE "org.bluez.Device1" |
4026 | +#define FDO_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties" |
4027 | + |
4028 | +#define BLUETOOTH_CLIENT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ |
4029 | + BLUETOOTH_TYPE_CLIENT, BluetoothClientPrivate)) |
4030 | + |
4031 | +typedef struct _BluetoothClientPrivate BluetoothClientPrivate; |
4032 | + |
4033 | +struct _BluetoothClientPrivate { |
4034 | + guint owner_change_id; |
4035 | + ObjectManager *manager; |
4036 | + GtkTreeStore *store; |
4037 | + GtkTreeRowReference *default_adapter; |
4038 | +}; |
4039 | + |
4040 | +enum { |
4041 | + PROP_0, |
4042 | + PROP_DEFAULT_ADAPTER, |
4043 | + PROP_DEFAULT_ADAPTER_POWERED, |
4044 | + PROP_DEFAULT_ADAPTER_DISCOVERABLE, |
4045 | + PROP_DEFAULT_ADAPTER_NAME, |
4046 | + PROP_DEFAULT_ADAPTER_DISCOVERING |
4047 | +}; |
4048 | + |
4049 | +enum { |
4050 | + DEVICE_REMOVED, |
4051 | + LAST_SIGNAL |
4052 | +}; |
4053 | + |
4054 | +static guint signals[LAST_SIGNAL] = { 0 }; |
4055 | + |
4056 | +static const char *connectable_uuids[] = { |
4057 | + "HSP", |
4058 | + "AudioSource", |
4059 | + "AudioSink", |
4060 | + "A/V_RemoteControlTarget", |
4061 | + "A/V_RemoteControl", |
4062 | + "Headset_-_AG", |
4063 | + "Handsfree", |
4064 | + "HandsfreeAudioGateway", |
4065 | + "HumanInterfaceDeviceService", |
4066 | +}; |
4067 | + |
4068 | +G_DEFINE_TYPE(BluetoothClient, bluetooth_client, G_TYPE_OBJECT) |
4069 | + |
4070 | +typedef gboolean (*IterSearchFunc) (GtkTreeStore *store, |
4071 | + GtkTreeIter *iter, gpointer user_data); |
4072 | + |
4073 | +static gboolean iter_search(GtkTreeStore *store, |
4074 | + GtkTreeIter *iter, GtkTreeIter *parent, |
4075 | + IterSearchFunc func, gpointer user_data) |
4076 | +{ |
4077 | + gboolean cont, found = FALSE; |
4078 | + |
4079 | + if (parent == NULL) |
4080 | + cont = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), |
4081 | + iter); |
4082 | + else |
4083 | + cont = gtk_tree_model_iter_children(GTK_TREE_MODEL(store), |
4084 | + iter, parent); |
4085 | + |
4086 | + while (cont == TRUE) { |
4087 | + GtkTreeIter child; |
4088 | + |
4089 | + found = func(store, iter, user_data); |
4090 | + if (found == TRUE) |
4091 | + break; |
4092 | + |
4093 | + found = iter_search(store, &child, iter, func, user_data); |
4094 | + if (found == TRUE) { |
4095 | + *iter = child; |
4096 | + break; |
4097 | + } |
4098 | + |
4099 | + cont = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), iter); |
4100 | + } |
4101 | + |
4102 | + return found; |
4103 | +} |
4104 | + |
4105 | +static gboolean compare_path(GtkTreeStore *store, |
4106 | + GtkTreeIter *iter, gpointer user_data) |
4107 | +{ |
4108 | + const gchar *path = user_data; |
4109 | + GDBusProxy *object; |
4110 | + gboolean found = FALSE; |
4111 | + |
4112 | + gtk_tree_model_get(GTK_TREE_MODEL(store), iter, |
4113 | + BLUETOOTH_COLUMN_PROXY, &object, -1); |
4114 | + |
4115 | + if (object != NULL) { |
4116 | + found = g_str_equal(path, g_dbus_proxy_get_object_path(object)); |
4117 | + g_object_unref(object); |
4118 | + } |
4119 | + |
4120 | + return found; |
4121 | +} |
4122 | + |
4123 | +static gboolean |
4124 | +compare_address (GtkTreeStore *store, |
4125 | + GtkTreeIter *iter, |
4126 | + gpointer user_data) |
4127 | +{ |
4128 | + const char *address = user_data; |
4129 | + char *tmp_address; |
4130 | + gboolean found = FALSE; |
4131 | + |
4132 | + gtk_tree_model_get (GTK_TREE_MODEL(store), iter, |
4133 | + BLUETOOTH_COLUMN_ADDRESS, &tmp_address, -1); |
4134 | + found = g_str_equal (address, tmp_address); |
4135 | + g_free (tmp_address); |
4136 | + |
4137 | + return found; |
4138 | +} |
4139 | + |
4140 | +static gboolean |
4141 | +get_iter_from_path (GtkTreeStore *store, |
4142 | + GtkTreeIter *iter, |
4143 | + const char *path) |
4144 | +{ |
4145 | + return iter_search(store, iter, NULL, compare_path, (gpointer) path); |
4146 | +} |
4147 | + |
4148 | +static gboolean |
4149 | +get_iter_from_proxy(GtkTreeStore *store, |
4150 | + GtkTreeIter *iter, |
4151 | + GDBusProxy *proxy) |
4152 | +{ |
4153 | + return iter_search(store, iter, NULL, compare_path, |
4154 | + (gpointer) g_dbus_proxy_get_object_path (proxy)); |
4155 | +} |
4156 | + |
4157 | +static gboolean |
4158 | +get_iter_from_address (GtkTreeStore *store, |
4159 | + GtkTreeIter *iter, |
4160 | + const char *address, |
4161 | + GDBusProxy *adapter) |
4162 | +{ |
4163 | + GtkTreeIter parent_iter; |
4164 | + |
4165 | + if (get_iter_from_proxy (store, &parent_iter, adapter) == FALSE) |
4166 | + return FALSE; |
4167 | + |
4168 | + return iter_search (store, iter, &parent_iter, compare_address, (gpointer) address); |
4169 | +} |
4170 | + |
4171 | +static char ** |
4172 | +device_list_uuids (GVariant *variant) |
4173 | +{ |
4174 | + GPtrArray *ret; |
4175 | + const char **uuids; |
4176 | + guint i; |
4177 | + |
4178 | + if (variant == NULL) |
4179 | + return NULL; |
4180 | + |
4181 | + uuids = g_variant_get_strv (variant, NULL); |
4182 | + if (uuids == NULL) |
4183 | + return NULL; |
4184 | + |
4185 | + ret = g_ptr_array_new (); |
4186 | + |
4187 | + for (i = 0; uuids[i] != NULL; i++) { |
4188 | + const char *uuid; |
4189 | + |
4190 | + uuid = bluetooth_uuid_to_string (uuids[i]); |
4191 | + if (uuid == NULL) |
4192 | + continue; |
4193 | + g_ptr_array_add (ret, g_strdup (uuid)); |
4194 | + } |
4195 | + g_free (uuids); |
4196 | + |
4197 | + if (ret->len == 0) { |
4198 | + g_ptr_array_free (ret, TRUE); |
4199 | + return NULL; |
4200 | + } |
4201 | + |
4202 | + g_ptr_array_add (ret, NULL); |
4203 | + |
4204 | + return (char **) g_ptr_array_free (ret, FALSE); |
4205 | +} |
4206 | + |
4207 | +gboolean |
4208 | +bluetooth_client_get_connectable(const char **uuids) |
4209 | +{ |
4210 | + int i, j; |
4211 | + |
4212 | + for (i = 0; uuids && uuids[i] != NULL; i++) { |
4213 | + for (j = 0; j < G_N_ELEMENTS (connectable_uuids); j++) { |
4214 | + if (g_str_equal (connectable_uuids[j], uuids[i])) |
4215 | + return TRUE; |
4216 | + } |
4217 | + } |
4218 | + |
4219 | + return FALSE; |
4220 | +} |
4221 | + |
4222 | +static void |
4223 | +device_g_properties_changed (GDBusProxy *device, |
4224 | + GVariant *changed_p, |
4225 | + GStrv invalidated_p, |
4226 | + BluetoothClient *client) |
4227 | +{ |
4228 | + BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client); |
4229 | + GVariantIter i; |
4230 | + const char *property; |
4231 | + GtkTreeIter iter; |
4232 | + GVariant *v; |
4233 | + |
4234 | + if (get_iter_from_proxy (priv->store, &iter, device) == FALSE) |
4235 | + return; |
4236 | + |
4237 | + g_variant_iter_init (&i, changed_p); |
4238 | + while (g_variant_iter_next (&i, "{&sv}", &property, &v)) { |
4239 | + |
4240 | + if (g_str_equal (property, "Name") == TRUE) { |
4241 | + const gchar *name = g_variant_get_string (v, NULL); |
4242 | + |
4243 | + gtk_tree_store_set (priv->store, &iter, |
4244 | + BLUETOOTH_COLUMN_NAME, name, -1); |
4245 | + } else if (g_str_equal (property, "Alias") == TRUE) { |
4246 | + const gchar *alias = g_variant_get_string (v, NULL); |
4247 | + |
4248 | + gtk_tree_store_set (priv->store, &iter, |
4249 | + BLUETOOTH_COLUMN_ALIAS, alias, -1); |
4250 | + } else if (g_str_equal (property, "Icon") == TRUE) { |
4251 | + const gchar *icon = g_variant_get_string (v, NULL); |
4252 | + |
4253 | + gtk_tree_store_set (priv->store, &iter, |
4254 | + BLUETOOTH_COLUMN_ICON, icon, -1); |
4255 | + } else if (g_str_equal (property, "Paired") == TRUE) { |
4256 | + gboolean paired = g_variant_get_boolean (v); |
4257 | + |
4258 | + gtk_tree_store_set (priv->store, &iter, |
4259 | + BLUETOOTH_COLUMN_PAIRED, paired, -1); |
4260 | + } else if (g_str_equal (property, "Trusted") == TRUE) { |
4261 | + gboolean trusted = g_variant_get_boolean (v); |
4262 | + |
4263 | + gtk_tree_store_set (priv->store, &iter, |
4264 | + BLUETOOTH_COLUMN_TRUSTED, trusted, -1); |
4265 | + } else if (g_str_equal (property, "Connected") == TRUE) { |
4266 | + gboolean connected = g_variant_get_boolean (v); |
4267 | + |
4268 | + gtk_tree_store_set (priv->store, &iter, |
4269 | + BLUETOOTH_COLUMN_CONNECTED, connected, -1); |
4270 | + } else if (g_str_equal (property, "UUIDs") == TRUE) { |
4271 | + char **uuids; |
4272 | + |
4273 | + uuids = device_list_uuids (v); |
4274 | + gtk_tree_store_set (priv->store, &iter, |
4275 | + BLUETOOTH_COLUMN_UUIDS, uuids, -1); |
4276 | + g_strfreev (uuids); |
4277 | + } else if (g_str_equal (property, "LegacyPairing") == TRUE) { |
4278 | + gboolean legacypairing; |
4279 | + |
4280 | + legacypairing = g_variant_get_boolean (v); |
4281 | + gtk_tree_store_set (priv->store, &iter, |
4282 | + BLUETOOTH_COLUMN_LEGACYPAIRING, legacypairing, |
4283 | + -1); |
4284 | + } else if (g_str_equal (property, "Class") == TRUE) { |
4285 | + BluetoothType type; |
4286 | + |
4287 | + type = v ? bluetooth_class_to_type (g_variant_get_uint32 (v)) : BLUETOOTH_TYPE_ANY; |
4288 | + gtk_tree_store_set (priv->store, &iter, |
4289 | + BLUETOOTH_COLUMN_TYPE, type, |
4290 | + -1); |
4291 | + } else { |
4292 | + g_debug ("Unhandled property: %s", property); |
4293 | + } |
4294 | + |
4295 | + g_variant_unref (v); |
4296 | + } |
4297 | +} |
4298 | + |
4299 | +static void |
4300 | +device_added (ObjectManager *manager, |
4301 | + BluetoothClient *client, |
4302 | + const char *path, |
4303 | + GVariant *variant) |
4304 | +{ |
4305 | + BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client); |
4306 | + GDBusProxy *adapter; |
4307 | + Device1 *device; |
4308 | + Properties *properties; |
4309 | + GVariant *v, *dict; |
4310 | + const char *adapter_path, *address, *alias, *name, *icon; |
4311 | + char **uuids; |
4312 | + gboolean paired, trusted, connected; |
4313 | + int legacypairing; |
4314 | + BluetoothType type; |
4315 | + GtkTreeIter iter, parent; |
4316 | + |
4317 | + device = device1_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, |
4318 | + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, |
4319 | + BLUEZ_SERVICE, |
4320 | + path, |
4321 | + NULL, |
4322 | + NULL); |
4323 | + if (device == NULL) |
4324 | + return; |
4325 | + |
4326 | + properties = properties_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, |
4327 | + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, |
4328 | + BLUEZ_SERVICE, |
4329 | + path, |
4330 | + NULL, |
4331 | + NULL); |
4332 | + |
4333 | + dict = g_variant_lookup_value (variant, BLUEZ_DEVICE_INTERFACE, |
4334 | + G_VARIANT_TYPE_DICTIONARY); |
4335 | + |
4336 | + v = g_variant_lookup_value (dict, "Adapter", G_VARIANT_TYPE_OBJECT_PATH); |
4337 | + adapter_path = v ? g_variant_get_string (v, NULL) : NULL; |
4338 | + |
4339 | + v = g_variant_lookup_value (dict, "Address", G_VARIANT_TYPE_STRING); |
4340 | + address = v ? g_variant_get_string (v, NULL) : NULL; |
4341 | + |
4342 | + v = g_variant_lookup_value (dict, "Alias", G_VARIANT_TYPE_STRING); |
4343 | + alias = v ? g_variant_get_string (v, NULL) : NULL; |
4344 | + |
4345 | + v = g_variant_lookup_value (dict, "Name", G_VARIANT_TYPE_STRING); |
4346 | + name = v ? g_variant_get_string (v, NULL) : NULL; |
4347 | + |
4348 | + v = g_variant_lookup_value (dict, "Class", G_VARIANT_TYPE_UINT32); |
4349 | + type = v ? bluetooth_class_to_type (g_variant_get_uint32 (v)) : BLUETOOTH_TYPE_ANY; |
4350 | + |
4351 | + v = g_variant_lookup_value (dict, "Icon", G_VARIANT_TYPE_STRING); |
4352 | + icon = v ? g_variant_get_string (v, NULL) : "bluetooth"; |
4353 | + |
4354 | + v = g_variant_lookup_value (dict, "Paired", G_VARIANT_TYPE_BOOLEAN); |
4355 | + paired = v ? g_variant_get_boolean (v) : FALSE; |
4356 | + |
4357 | + v = g_variant_lookup_value (dict, "Trusted", G_VARIANT_TYPE_BOOLEAN); |
4358 | + trusted = v ? g_variant_get_boolean (v) : FALSE; |
4359 | + |
4360 | + v = g_variant_lookup_value (dict, "Connected", G_VARIANT_TYPE_BOOLEAN); |
4361 | + connected = v ? g_variant_get_boolean (v) : FALSE; |
4362 | + |
4363 | + v = g_variant_lookup_value (dict, "UUIDs", G_VARIANT_TYPE_STRING_ARRAY); |
4364 | + uuids = device_list_uuids (v); |
4365 | + |
4366 | + v = g_variant_lookup_value (dict, "LegacyPairing", G_VARIANT_TYPE_BOOLEAN); |
4367 | + legacypairing = v ? g_variant_get_boolean (v) : -1; |
4368 | + |
4369 | + if (get_iter_from_path (priv->store, &parent, adapter_path) == FALSE) { |
4370 | + g_object_unref (device); |
4371 | + return; |
4372 | + } |
4373 | + |
4374 | + gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &parent, |
4375 | + BLUETOOTH_COLUMN_PROXY, &adapter, -1); |
4376 | + |
4377 | + if (get_iter_from_address (priv->store, &iter, address, adapter) == FALSE) { |
4378 | + gtk_tree_store_insert_with_values (priv->store, &iter, &parent, -1, |
4379 | + BLUETOOTH_COLUMN_ADDRESS, address, |
4380 | + BLUETOOTH_COLUMN_ALIAS, alias, |
4381 | + BLUETOOTH_COLUMN_NAME, name, |
4382 | + BLUETOOTH_COLUMN_TYPE, type, |
4383 | + BLUETOOTH_COLUMN_ICON, icon, |
4384 | + BLUETOOTH_COLUMN_LEGACYPAIRING, legacypairing, |
4385 | + BLUETOOTH_COLUMN_UUIDS, uuids, |
4386 | + BLUETOOTH_COLUMN_PAIRED, paired, |
4387 | + BLUETOOTH_COLUMN_CONNECTED, connected, |
4388 | + BLUETOOTH_COLUMN_TRUSTED, trusted, |
4389 | + BLUETOOTH_COLUMN_PROXY, device, |
4390 | + BLUETOOTH_COLUMN_PROPERTIES, properties, |
4391 | + -1); |
4392 | + } else { |
4393 | + gtk_tree_store_set(priv->store, &iter, |
4394 | + BLUETOOTH_COLUMN_ADDRESS, address, |
4395 | + BLUETOOTH_COLUMN_ALIAS, alias, |
4396 | + BLUETOOTH_COLUMN_NAME, name, |
4397 | + BLUETOOTH_COLUMN_TYPE, type, |
4398 | + BLUETOOTH_COLUMN_ICON, icon, |
4399 | + BLUETOOTH_COLUMN_LEGACYPAIRING, legacypairing, |
4400 | + BLUETOOTH_COLUMN_UUIDS, uuids, |
4401 | + BLUETOOTH_COLUMN_PAIRED, paired, |
4402 | + BLUETOOTH_COLUMN_CONNECTED, connected, |
4403 | + BLUETOOTH_COLUMN_TRUSTED, trusted, |
4404 | + BLUETOOTH_COLUMN_PROXY, device, |
4405 | + BLUETOOTH_COLUMN_PROPERTIES, properties, |
4406 | + -1); |
4407 | + } |
4408 | + g_strfreev (uuids); |
4409 | + |
4410 | + g_signal_connect (G_OBJECT (device), "g-properties-changed", |
4411 | + G_CALLBACK (device_g_properties_changed), client); |
4412 | + |
4413 | + g_object_unref (properties); |
4414 | + g_object_unref (device); |
4415 | + g_object_unref (adapter); |
4416 | +} |
4417 | + |
4418 | +static void |
4419 | +device_removed (const char *path, |
4420 | + BluetoothClient *client) |
4421 | +{ |
4422 | + BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client); |
4423 | + GtkTreeIter iter; |
4424 | + |
4425 | + if (get_iter_from_path(priv->store, &iter, path) == TRUE) { |
4426 | + g_signal_emit (G_OBJECT (client), signals[DEVICE_REMOVED], 0, path); |
4427 | + gtk_tree_store_remove(priv->store, &iter); |
4428 | + } |
4429 | +} |
4430 | + |
4431 | +static void |
4432 | +powered_callback (GDBusProxy *proxy, |
4433 | + GAsyncResult *res, |
4434 | + gpointer data) |
4435 | +{ |
4436 | + GError *error = NULL; |
4437 | + |
4438 | + if (!properties_call_set_finish (PROPERTIES(proxy), res, &error)) { |
4439 | + g_debug ("Call to Set Powered failed %s: %s", |
4440 | + g_dbus_proxy_get_object_path (proxy), error->message); |
4441 | + g_error_free (error); |
4442 | + } |
4443 | + |
4444 | + g_object_unref (proxy); |
4445 | +} |
4446 | + |
4447 | +static gboolean |
4448 | +adapter_set_powered (BluetoothClient *client, |
4449 | + const char *path, |
4450 | + gboolean powered) |
4451 | +{ |
4452 | + BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client); |
4453 | + Properties *properties; |
4454 | + GtkTreeIter iter; |
4455 | + |
4456 | + g_return_val_if_fail (BLUETOOTH_IS_CLIENT (client), FALSE); |
4457 | + |
4458 | + if (get_iter_from_path (priv->store, &iter, path) == FALSE) |
4459 | + return FALSE; |
4460 | + |
4461 | + gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter, |
4462 | + BLUETOOTH_COLUMN_PROPERTIES, &properties, -1); |
4463 | + |
4464 | + if (properties == NULL) |
4465 | + return FALSE; |
4466 | + |
4467 | + |
4468 | + properties_call_set (properties, |
4469 | + BLUEZ_ADAPTER_INTERFACE, |
4470 | + "Powered", |
4471 | + g_variant_new_variant (g_variant_new_boolean (powered)), |
4472 | + NULL, |
4473 | + (GAsyncReadyCallback) powered_callback, |
4474 | + NULL); |
4475 | + |
4476 | + return TRUE; |
4477 | +} |
4478 | + |
4479 | +static void |
4480 | +default_adapter_changed (ObjectManager *manager, |
4481 | + const char *path, |
4482 | + BluetoothClient *client) |
4483 | +{ |
4484 | + BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client); |
4485 | + GtkTreeIter iter; |
4486 | + GtkTreePath *tree_path; |
4487 | + gboolean powered; |
4488 | + |
4489 | + g_assert (!priv->default_adapter); |
4490 | + |
4491 | + if (get_iter_from_path (priv->store, &iter, path) == FALSE) |
4492 | + return; |
4493 | + |
4494 | + tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), &iter); |
4495 | + priv->default_adapter = gtk_tree_row_reference_new (GTK_TREE_MODEL (priv->store), tree_path); |
4496 | + gtk_tree_path_free (tree_path); |
4497 | + |
4498 | + gtk_tree_store_set (priv->store, &iter, |
4499 | + BLUETOOTH_COLUMN_DEFAULT, TRUE, -1); |
4500 | + |
4501 | + gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter, |
4502 | + BLUETOOTH_COLUMN_POWERED, &powered, -1); |
4503 | + |
4504 | + if (powered) { |
4505 | + g_object_notify (G_OBJECT (client), "default-adapter"); |
4506 | + g_object_notify (G_OBJECT (client), "default-adapter-powered"); |
4507 | + g_object_notify (G_OBJECT (client), "default-adapter-discoverable"); |
4508 | + g_object_notify (G_OBJECT (client), "default-adapter-discovering"); |
4509 | + g_object_notify (G_OBJECT (client), "default-adapter-name"); |
4510 | + return; |
4511 | + } |
4512 | + |
4513 | + /* |
4514 | + * If the adapter is turn off (Powered = False in bluetooth) object |
4515 | + * notifications will be sent only when a Powered = True signal arrives |
4516 | + * from bluetoothd |
4517 | + */ |
4518 | + adapter_set_powered (client, path, TRUE); |
4519 | +} |
4520 | + |
4521 | +static void |
4522 | +adapter_g_properties_changed (GDBusProxy *adapter, |
4523 | + GVariant *changed_p, |
4524 | + GStrv invalidated_p, |
4525 | + BluetoothClient *client) |
4526 | +{ |
4527 | + BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client); |
4528 | + GVariantIter i; |
4529 | + const char *property; |
4530 | + GtkTreeIter iter; |
4531 | + GVariant *v; |
4532 | + gboolean notify = FALSE; |
4533 | + |
4534 | + if (get_iter_from_proxy (priv->store, &iter, adapter) == FALSE) |
4535 | + return; |
4536 | + |
4537 | + g_variant_iter_init (&i, changed_p); |
4538 | + while (g_variant_iter_next (&i, "{&sv}", &property, &v)) { |
4539 | + if (g_str_equal (property, "Name") == TRUE) { |
4540 | + const gchar *name = g_variant_get_string (v, NULL); |
4541 | + gboolean is_default; |
4542 | + |
4543 | + gtk_tree_store_set (priv->store, &iter, |
4544 | + BLUETOOTH_COLUMN_NAME, name, -1); |
4545 | + gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter, |
4546 | + BLUETOOTH_COLUMN_DEFAULT, &is_default, -1); |
4547 | + if (is_default != FALSE) { |
4548 | + g_object_notify (G_OBJECT (client), "default-adapter-powered"); |
4549 | + g_object_notify (G_OBJECT (client), "default-adapter-name"); |
4550 | + } |
4551 | + notify = TRUE; |
4552 | + } else if (g_str_equal (property, "Discovering") == TRUE) { |
4553 | + gboolean discovering = g_variant_get_boolean (v); |
4554 | + gboolean is_default; |
4555 | + |
4556 | + gtk_tree_store_set (priv->store, &iter, |
4557 | + BLUETOOTH_COLUMN_DISCOVERING, discovering, -1); |
4558 | + gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter, |
4559 | + BLUETOOTH_COLUMN_DEFAULT, &is_default, -1); |
4560 | + if (is_default != FALSE) |
4561 | + g_object_notify (G_OBJECT (client), "default-adapter-discovering"); |
4562 | + notify = TRUE; |
4563 | + } else if (g_str_equal (property, "Powered") == TRUE) { |
4564 | + gboolean powered = g_variant_get_boolean (v); |
4565 | + gboolean is_default; |
4566 | + |
4567 | + gtk_tree_store_set (priv->store, &iter, |
4568 | + BLUETOOTH_COLUMN_POWERED, powered, -1); |
4569 | + gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter, |
4570 | + BLUETOOTH_COLUMN_DEFAULT, &is_default, -1); |
4571 | + if (is_default != FALSE && powered) { |
4572 | + g_object_notify (G_OBJECT (client), "default-adapter"); |
4573 | + g_object_notify (G_OBJECT (client), "default-adapter-powered"); |
4574 | + g_object_notify (G_OBJECT (client), "default-adapter-discoverable"); |
4575 | + g_object_notify (G_OBJECT (client), "default-adapter-discovering"); |
4576 | + g_object_notify (G_OBJECT (client), "default-adapter-name"); |
4577 | + } |
4578 | + notify = TRUE; |
4579 | + } else if (g_str_equal (property, "Discoverable") == TRUE) { |
4580 | + gboolean discoverable = g_variant_get_boolean (v); |
4581 | + gboolean is_default; |
4582 | + |
4583 | + gtk_tree_store_set (priv->store, &iter, |
4584 | + BLUETOOTH_COLUMN_DISCOVERABLE, discoverable, -1); |
4585 | + gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter, |
4586 | + BLUETOOTH_COLUMN_DEFAULT, &is_default, -1); |
4587 | + if (is_default != FALSE) |
4588 | + g_object_notify (G_OBJECT (client), "default-adapter-discoverable"); |
4589 | + notify = TRUE; |
4590 | + } |
4591 | + |
4592 | + if (notify != FALSE) { |
4593 | + GtkTreePath *path; |
4594 | + |
4595 | + /* Tell the world */ |
4596 | + path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), &iter); |
4597 | + gtk_tree_model_row_changed (GTK_TREE_MODEL (priv->store), path, &iter); |
4598 | + gtk_tree_path_free (path); |
4599 | + } |
4600 | + g_variant_unref (v); |
4601 | + } |
4602 | +} |
4603 | + |
4604 | +static void |
4605 | +adapter_added (ObjectManager *manager, |
4606 | + const char *path, |
4607 | + GVariant *variant, |
4608 | + BluetoothClient *client) |
4609 | +{ |
4610 | + BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client); |
4611 | + GtkTreeIter iter; |
4612 | + Adapter1 *adapter; |
4613 | + Properties *properties; |
4614 | + const gchar *address, *name; |
4615 | + GVariant *v, *dict; |
4616 | + gboolean discovering, discoverable, powered; |
4617 | + |
4618 | + adapter = adapter1_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, |
4619 | + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, |
4620 | + BLUEZ_SERVICE, |
4621 | + path, |
4622 | + NULL, |
4623 | + NULL); |
4624 | + |
4625 | + properties = properties_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, |
4626 | + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, |
4627 | + BLUEZ_SERVICE, |
4628 | + path, |
4629 | + NULL, |
4630 | + NULL); |
4631 | + |
4632 | + dict = g_variant_lookup_value (variant, BLUEZ_ADAPTER_INTERFACE, |
4633 | + G_VARIANT_TYPE_DICTIONARY); |
4634 | + |
4635 | + v = g_variant_lookup_value (dict, "Address", G_VARIANT_TYPE_STRING); |
4636 | + address = v ? g_variant_get_string (v, NULL) : NULL; |
4637 | + |
4638 | + v = g_variant_lookup_value (dict, "Name", G_VARIANT_TYPE_STRING); |
4639 | + name = v ? g_variant_get_string (v, NULL) : NULL; |
4640 | + |
4641 | + v = g_variant_lookup_value (dict, "Discovering", G_VARIANT_TYPE_BOOLEAN); |
4642 | + discovering = v ? g_variant_get_boolean (v) : FALSE; |
4643 | + |
4644 | + v = g_variant_lookup_value (dict, "Powered", G_VARIANT_TYPE_BOOLEAN); |
4645 | + powered = v ? g_variant_get_boolean (v) : FALSE; |
4646 | + |
4647 | + v = g_variant_lookup_value (dict, "Discoverable", G_VARIANT_TYPE_BOOLEAN); |
4648 | + discoverable = v ? g_variant_get_boolean (v) : FALSE; |
4649 | + |
4650 | + gtk_tree_store_insert_with_values(priv->store, &iter, NULL, -1, |
4651 | + BLUETOOTH_COLUMN_PROXY, adapter, |
4652 | + BLUETOOTH_COLUMN_PROPERTIES, properties, |
4653 | + BLUETOOTH_COLUMN_ADDRESS, address, |
4654 | + BLUETOOTH_COLUMN_NAME, name, |
4655 | + BLUETOOTH_COLUMN_DISCOVERING, discovering, |
4656 | + BLUETOOTH_COLUMN_DISCOVERABLE, discoverable, |
4657 | + BLUETOOTH_COLUMN_POWERED, powered, |
4658 | + -1); |
4659 | + |
4660 | + g_signal_connect (G_OBJECT (adapter), "g-properties-changed", |
4661 | + G_CALLBACK (adapter_g_properties_changed), client); |
4662 | + |
4663 | + if (!priv->default_adapter) |
4664 | + default_adapter_changed (manager, path, client); |
4665 | + |
4666 | + g_object_unref (properties); |
4667 | + g_object_unref (adapter); |
4668 | +} |
4669 | + |
4670 | +static void |
4671 | +adapter_removed (ObjectManager *manager, |
4672 | + const char *path, |
4673 | + BluetoothClient *client) |
4674 | +{ |
4675 | + BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client); |
4676 | + GtkTreeIter iter; |
4677 | + gboolean was_default; |
4678 | + |
4679 | + if (get_iter_from_path (priv->store, &iter, path) == FALSE) |
4680 | + return; |
4681 | + |
4682 | + gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter, |
4683 | + BLUETOOTH_COLUMN_DEFAULT, &was_default, -1); |
4684 | + |
4685 | + if (!was_default) |
4686 | + return; |
4687 | + |
4688 | + g_clear_pointer (&priv->default_adapter, gtk_tree_row_reference_free); |
4689 | + gtk_tree_store_remove (priv->store, &iter); |
4690 | + |
4691 | + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL(priv->store), |
4692 | + &iter)) { |
4693 | + GDBusProxy *adapter; |
4694 | + const char *adapter_path; |
4695 | + |
4696 | + gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter, |
4697 | + BLUETOOTH_COLUMN_PROXY, &adapter, -1); |
4698 | + |
4699 | + adapter_path = g_dbus_proxy_get_object_path (adapter); |
4700 | + default_adapter_changed (manager, adapter_path, client); |
4701 | + |
4702 | + g_object_unref(adapter); |
4703 | + } else { |
4704 | + g_object_notify (G_OBJECT (client), "default-adapter"); |
4705 | + g_object_notify (G_OBJECT (client), "default-adapter-powered"); |
4706 | + g_object_notify (G_OBJECT (client), "default-adapter-discoverable"); |
4707 | + g_object_notify (G_OBJECT (client), "default-adapter-discovering"); |
4708 | + } |
4709 | +} |
4710 | + |
4711 | +static void |
4712 | +interface_added (BluetoothClient *client, |
4713 | + const char *path, |
4714 | + GVariant *variant) |
4715 | +{ |
4716 | + BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client); |
4717 | + |
4718 | + if (g_variant_lookup_value (variant, BLUEZ_ADAPTER_INTERFACE, |
4719 | + G_VARIANT_TYPE_DICTIONARY)) { |
4720 | + g_debug ("New Adapter interface added."); |
4721 | + adapter_added (priv->manager, path, variant, client); |
4722 | + return; |
4723 | + } |
4724 | + |
4725 | + if (g_variant_lookup_value (variant, BLUEZ_DEVICE_INTERFACE, |
4726 | + G_VARIANT_TYPE_DICTIONARY)) { |
4727 | + g_debug ("New Device interface added."); |
4728 | + device_added (priv->manager, client, path, variant); |
4729 | + return; |
4730 | + } |
4731 | +} |
4732 | + |
4733 | +static void |
4734 | +interface_removed (BluetoothClient *client, |
4735 | + const char *path, |
4736 | + GVariant *variant) |
4737 | +{ |
4738 | + BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client); |
4739 | + const char **ifaces; |
4740 | + int i; |
4741 | + |
4742 | + ifaces = g_variant_get_strv (variant, NULL); |
4743 | + |
4744 | + for (i = 0 ; ifaces[i] != NULL ; i++) { |
4745 | + if (g_strcmp0(ifaces[i], BLUEZ_ADAPTER_INTERFACE) == 0) { |
4746 | + adapter_removed(priv->manager, path, client); |
4747 | + return; |
4748 | + } |
4749 | + |
4750 | + if (g_strcmp0(ifaces[i], BLUEZ_DEVICE_INTERFACE) == 0) { |
4751 | + device_removed (path, client); |
4752 | + return; |
4753 | + } |
4754 | + } |
4755 | +} |
4756 | + |
4757 | +static void |
4758 | +object_manager_g_signal (GDBusProxy *proxy, |
4759 | + gchar *sender_name, |
4760 | + gchar *signal_name, |
4761 | + GVariant *parameters, |
4762 | + BluetoothClient *client) |
4763 | +{ |
4764 | + char *object_path; |
4765 | + GVariant *variant; |
4766 | + |
4767 | + g_variant_get (parameters, "(o*)", &object_path, &variant); |
4768 | + |
4769 | + if (g_strcmp0 (signal_name, "InterfacesAdded") == 0) { |
4770 | + interface_added (client, object_path, variant); |
4771 | + } else if (g_strcmp0 (signal_name, "InterfacesRemoved") == 0) { |
4772 | + interface_removed (client, object_path, variant); |
4773 | + } else { |
4774 | + g_assert_not_reached (); |
4775 | + } |
4776 | + |
4777 | + g_free (object_path); |
4778 | +} |
4779 | + |
4780 | +static void |
4781 | +bluez_appeared_cb (GDBusConnection *connection, |
4782 | + const gchar *name, |
4783 | + const gchar *name_owner, |
4784 | + BluetoothClient *client) |
4785 | +{ |
4786 | + BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client); |
4787 | + GVariantIter iter; |
4788 | + GVariant *variant, *v, *ifaces; |
4789 | + char *key; |
4790 | + |
4791 | + priv->manager = object_manager_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, |
4792 | + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, |
4793 | + BLUEZ_SERVICE, |
4794 | + BLUEZ_MANAGER_PATH, |
4795 | + NULL, |
4796 | + NULL); |
4797 | + |
4798 | + g_signal_connect (G_OBJECT (priv->manager), "g-signal", |
4799 | + G_CALLBACK (object_manager_g_signal), client); |
4800 | + |
4801 | + variant = NULL; |
4802 | + object_manager_call_get_managed_objects_sync (OBJECT_MANAGER (priv->manager), |
4803 | + &variant, NULL, NULL); |
4804 | + if (variant == NULL) |
4805 | + return; |
4806 | + |
4807 | + g_variant_iter_init (&iter, variant); |
4808 | + while ((v = g_variant_iter_next_value (&iter))) { |
4809 | + g_variant_get (v, "{o*}", &key, &ifaces); |
4810 | + interface_added (client, key, ifaces); |
4811 | + } |
4812 | + |
4813 | + g_variant_unref (variant); |
4814 | +} |
4815 | + |
4816 | +static void |
4817 | +bluez_vanished_cb (GDBusConnection *connection, |
4818 | + const gchar *name, |
4819 | + BluetoothClient *client) |
4820 | +{ |
4821 | + BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client); |
4822 | + |
4823 | + g_clear_pointer (&priv->default_adapter, gtk_tree_row_reference_free); |
4824 | + |
4825 | + gtk_tree_store_clear (priv->store); |
4826 | + |
4827 | + g_clear_object (&priv->manager); |
4828 | +} |
4829 | + |
4830 | +static void bluetooth_client_init(BluetoothClient *client) |
4831 | +{ |
4832 | + BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client); |
4833 | + |
4834 | + priv->store = gtk_tree_store_new(_BLUETOOTH_NUM_COLUMNS, G_TYPE_OBJECT, |
4835 | + G_TYPE_OBJECT, G_TYPE_STRING, |
4836 | + G_TYPE_STRING, G_TYPE_STRING, |
4837 | + G_TYPE_UINT, G_TYPE_STRING, |
4838 | + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, |
4839 | + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_INT, |
4840 | + G_TYPE_BOOLEAN, G_TYPE_HASH_TABLE, G_TYPE_STRV); |
4841 | + |
4842 | + priv->owner_change_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM, |
4843 | + BLUEZ_SERVICE, |
4844 | + G_BUS_NAME_WATCHER_FLAGS_NONE, |
4845 | + (GBusNameAppearedCallback) bluez_appeared_cb, |
4846 | + (GBusNameVanishedCallback) bluez_vanished_cb, |
4847 | + client, NULL); |
4848 | +} |
4849 | + |
4850 | +static GDBusProxy * |
4851 | +_bluetooth_client_get_default_adapter(BluetoothClient *client) |
4852 | +{ |
4853 | + BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client); |
4854 | + GtkTreePath *path; |
4855 | + GtkTreeIter iter; |
4856 | + GDBusProxy *adapter; |
4857 | + |
4858 | + g_return_val_if_fail (BLUETOOTH_IS_CLIENT (client), NULL); |
4859 | + |
4860 | + if (priv->default_adapter == NULL) |
4861 | + return NULL; |
4862 | + |
4863 | + path = gtk_tree_row_reference_get_path (priv->default_adapter); |
4864 | + gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->store), &iter, path); |
4865 | + gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter, |
4866 | + BLUETOOTH_COLUMN_PROXY, &adapter, -1); |
4867 | + gtk_tree_path_free (path); |
4868 | + |
4869 | + return adapter; |
4870 | +} |
4871 | + |
4872 | +static const char* |
4873 | +_bluetooth_client_get_default_adapter_path (BluetoothClient *self) |
4874 | +{ |
4875 | + GDBusProxy *adapter = _bluetooth_client_get_default_adapter (self); |
4876 | + |
4877 | + if (adapter != NULL) { |
4878 | + const char *ret = g_dbus_proxy_get_object_path (adapter); |
4879 | + g_object_unref (adapter); |
4880 | + return ret; |
4881 | + } |
4882 | + return NULL; |
4883 | +} |
4884 | + |
4885 | +static gboolean |
4886 | +_bluetooth_client_get_default_adapter_powered (BluetoothClient *self) |
4887 | +{ |
4888 | + BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE (self); |
4889 | + GtkTreePath *path; |
4890 | + GtkTreeIter iter; |
4891 | + gboolean ret; |
4892 | + |
4893 | + if (priv->default_adapter == NULL) |
4894 | + return FALSE; |
4895 | + |
4896 | + path = gtk_tree_row_reference_get_path (priv->default_adapter); |
4897 | + gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->store), &iter, path); |
4898 | + gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter, BLUETOOTH_COLUMN_POWERED, &ret, -1); |
4899 | + gtk_tree_path_free (path); |
4900 | + |
4901 | + return ret; |
4902 | +} |
4903 | + |
4904 | +static char * |
4905 | +_bluetooth_client_get_default_adapter_name (BluetoothClient *self) |
4906 | +{ |
4907 | + BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE (self); |
4908 | + GtkTreePath *path; |
4909 | + GtkTreeIter iter; |
4910 | + char *ret; |
4911 | + |
4912 | + if (priv->default_adapter == NULL) |
4913 | + return NULL; |
4914 | + |
4915 | + path = gtk_tree_row_reference_get_path (priv->default_adapter); |
4916 | + gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->store), &iter, path); |
4917 | + gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter, BLUETOOTH_COLUMN_NAME, &ret, -1); |
4918 | + gtk_tree_path_free (path); |
4919 | + |
4920 | + return ret; |
4921 | +} |
4922 | + |
4923 | +/** |
4924 | + * _bluetooth_client_get_discoverable: |
4925 | + * @client: a #BluetoothClient |
4926 | + * |
4927 | + * Gets the default adapter's discoverable status, cached in the adapter model. |
4928 | + * |
4929 | + * Returns: the discoverable status, or FALSE if no default adapter exists |
4930 | + */ |
4931 | +static gboolean |
4932 | +_bluetooth_client_get_discoverable (BluetoothClient *client) |
4933 | +{ |
4934 | + BluetoothClientPrivate *priv; |
4935 | + GtkTreePath *path; |
4936 | + GtkTreeIter iter; |
4937 | + gboolean ret; |
4938 | + |
4939 | + g_return_val_if_fail (BLUETOOTH_IS_CLIENT (client), FALSE); |
4940 | + |
4941 | + priv = BLUETOOTH_CLIENT_GET_PRIVATE (client); |
4942 | + if (priv->default_adapter == NULL) |
4943 | + return FALSE; |
4944 | + |
4945 | + path = gtk_tree_row_reference_get_path (priv->default_adapter); |
4946 | + gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->store), &iter, path); |
4947 | + gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter, |
4948 | + BLUETOOTH_COLUMN_DISCOVERABLE, &ret, -1); |
4949 | + |
4950 | + return ret; |
4951 | +} |
4952 | + |
4953 | +/** |
4954 | + * _bluetooth_client_set_discoverable: |
4955 | + * @client: a #BluetoothClient object |
4956 | + * @discoverable: whether the device should be discoverable |
4957 | + * @timeout: timeout in seconds for making undiscoverable, or 0 for never |
4958 | + * |
4959 | + * Sets the default adapter's discoverable status. |
4960 | + * |
4961 | + * Return value: Whether setting the state on the default adapter was successful. |
4962 | + **/ |
4963 | +static gboolean |
4964 | +_bluetooth_client_set_discoverable (BluetoothClient *client, |
4965 | + gboolean discoverable, |
4966 | + guint timeout) |
4967 | +{ |
4968 | + BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE (client); |
4969 | + GError *error = NULL; |
4970 | + GtkTreePath *path; |
4971 | + Properties *properties; |
4972 | + gboolean ret; |
4973 | + GtkTreeIter iter; |
4974 | + |
4975 | + g_return_val_if_fail (BLUETOOTH_IS_CLIENT (client), FALSE); |
4976 | + |
4977 | + if (priv->default_adapter == NULL) |
4978 | + return FALSE; |
4979 | + |
4980 | + path = gtk_tree_row_reference_get_path (priv->default_adapter); |
4981 | + gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->store), &iter, path); |
4982 | + gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter, |
4983 | + BLUETOOTH_COLUMN_PROPERTIES, &properties, -1); |
4984 | + gtk_tree_path_free (path); |
4985 | + |
4986 | + if (properties == NULL) |
4987 | + return FALSE; |
4988 | + |
4989 | + ret = properties_call_set_sync (properties, |
4990 | + BLUEZ_ADAPTER_INTERFACE, |
4991 | + "Discoverable", |
4992 | + g_variant_new_variant (g_variant_new_boolean (discoverable)), |
4993 | + NULL, &error); |
4994 | + if (ret == FALSE) { |
4995 | + g_warning ("Failed to set Discoverable to %d: %s", discoverable, error->message); |
4996 | + g_error_free (error); |
4997 | + } else { |
4998 | + ret = properties_call_set_sync (properties, |
4999 | + BLUEZ_ADAPTER_INTERFACE, |
5000 | + "DiscoverableTimeout", |
The diff has been truncated for viewing.
Lars is not around, merge proposing for him, I stack a branch with some addition tweaks/fixes on top of that one. The changes could be nicer but that should do the job to unblock the bluez5 migration, we can iterate more later