Line |
Branch |
Exec |
Source |
1 |
|
|
/* |
2 |
|
|
* |
3 |
|
|
* Copyright (C) 2013 Bastien Nocera <hadess@hadess.net> |
4 |
|
|
* |
5 |
|
|
* This program is free software; you can redistribute it and/or modify |
6 |
|
|
* it under the terms of the GNU General Public License as published by |
7 |
|
|
* the Free Software Foundation; either version 2 of the License, or |
8 |
|
|
* (at your option) any later version. |
9 |
|
|
* |
10 |
|
|
* This program is distributed in the hope that it will be useful, |
11 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 |
|
|
* GNU General Public License for more details. |
14 |
|
|
* |
15 |
|
|
* You should have received a copy of the GNU General Public License |
16 |
|
|
* along with this program; if not, write to the Free Software |
17 |
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
18 |
|
|
* |
19 |
|
|
*/ |
20 |
|
|
|
21 |
|
|
#ifdef HAVE_CONFIG_H |
22 |
|
|
#include <config.h> |
23 |
|
|
#endif |
24 |
|
|
|
25 |
|
|
#include <adwaita.h> |
26 |
|
|
|
27 |
|
|
#include <shell/cc-shell.h> |
28 |
|
|
#include <shell/cc-object-storage.h> |
29 |
|
|
#include <bluetooth-settings-widget.h> |
30 |
|
|
|
31 |
|
|
#include "cc-bluetooth-panel.h" |
32 |
|
|
#include "cc-bluetooth-resources.h" |
33 |
|
|
|
34 |
|
|
struct _CcBluetoothPanel { |
35 |
|
|
CcPanel parent_instance; |
36 |
|
|
|
37 |
|
|
AdwStatusPage *airplane_page; |
38 |
|
|
AdwStatusPage *disabled_page; |
39 |
|
|
GtkSwitch *enable_switch; |
40 |
|
|
GtkBox *header_box; |
41 |
|
|
AdwStatusPage *hw_airplane_page; |
42 |
|
|
AdwStatusPage *no_devices_page; |
43 |
|
|
BluetoothSettingsWidget *settings_widget; |
44 |
|
|
GtkStack *stack; |
45 |
|
|
|
46 |
|
|
/* Killswitch */ |
47 |
|
|
GDBusProxy *rfkill; |
48 |
|
|
GDBusProxy *properties; |
49 |
|
|
gboolean airplane_mode; |
50 |
|
|
gboolean bt_airplane_mode; |
51 |
|
|
gboolean hardware_airplane_mode; |
52 |
|
|
gboolean has_airplane_mode; |
53 |
|
|
}; |
54 |
|
|
|
55 |
|
✗ |
CC_PANEL_REGISTER (CcBluetoothPanel, cc_bluetooth_panel) |
56 |
|
|
|
57 |
|
|
static const char * |
58 |
|
✗ |
cc_bluetooth_panel_get_help_uri (CcPanel *panel) |
59 |
|
|
{ |
60 |
|
✗ |
return "help:gnome-help/bluetooth"; |
61 |
|
|
} |
62 |
|
|
|
63 |
|
|
static void |
64 |
|
✗ |
cc_bluetooth_panel_finalize (GObject *object) |
65 |
|
|
{ |
66 |
|
|
CcBluetoothPanel *self; |
67 |
|
|
|
68 |
|
✗ |
self = CC_BLUETOOTH_PANEL (object); |
69 |
|
|
|
70 |
|
✗ |
g_clear_object (&self->properties); |
71 |
|
✗ |
g_clear_object (&self->rfkill); |
72 |
|
|
|
73 |
|
✗ |
G_OBJECT_CLASS (cc_bluetooth_panel_parent_class)->finalize (object); |
74 |
|
✗ |
} |
75 |
|
|
|
76 |
|
|
static void |
77 |
|
✗ |
airplane_mode_changed_cb (GObject *source_object, |
78 |
|
|
GAsyncResult *res, |
79 |
|
|
gpointer user_data) |
80 |
|
|
{ |
81 |
|
✗ |
g_autoptr(GVariant) ret = NULL; |
82 |
|
✗ |
g_autoptr(GError) error = NULL; |
83 |
|
|
|
84 |
|
✗ |
if (!g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), |
85 |
|
|
res, &error)) { |
86 |
|
✗ |
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { |
87 |
|
✗ |
CcBluetoothPanel *self = CC_BLUETOOTH_PANEL (user_data); |
88 |
|
✗ |
gboolean state = gtk_switch_get_active (self->enable_switch); |
89 |
|
✗ |
g_warning ("Failed to change Bluetooth killswitch state to %s: %s", |
90 |
|
|
state ? "on" : "off", error->message); |
91 |
|
|
} |
92 |
|
|
} else { |
93 |
|
✗ |
CcBluetoothPanel *self = CC_BLUETOOTH_PANEL (user_data); |
94 |
|
✗ |
gboolean state = gtk_switch_get_active (self->enable_switch); |
95 |
|
|
|
96 |
|
✗ |
g_debug ("Changed Bluetooth killswitch state to %s", |
97 |
|
|
state ? "on" : "off"); |
98 |
|
|
|
99 |
|
✗ |
gtk_switch_set_state (self->enable_switch, state); |
100 |
|
✗ |
if (!bluetooth_settings_widget_get_default_adapter_powered (self->settings_widget)) |
101 |
|
✗ |
bluetooth_settings_widget_set_default_adapter_powered(self->settings_widget, TRUE); |
102 |
|
|
} |
103 |
|
✗ |
} |
104 |
|
|
|
105 |
|
|
static gboolean |
106 |
|
✗ |
enable_switch_state_set_cb (CcBluetoothPanel *self, gboolean state) |
107 |
|
|
{ |
108 |
|
✗ |
g_debug ("Power switched to %s", state ? "on" : "off"); |
109 |
|
✗ |
g_dbus_proxy_call (self->properties, |
110 |
|
|
"Set", |
111 |
|
|
g_variant_new_parsed ("('org.gnome.SettingsDaemon.Rfkill', 'BluetoothAirplaneMode', %v)", |
112 |
|
|
g_variant_new_boolean (!state)), |
113 |
|
|
G_DBUS_CALL_FLAGS_NONE, |
114 |
|
|
-1, |
115 |
|
|
cc_panel_get_cancellable (CC_PANEL (self)), |
116 |
|
|
airplane_mode_changed_cb, self); |
117 |
|
|
|
118 |
|
✗ |
return TRUE; |
119 |
|
|
} |
120 |
|
|
|
121 |
|
|
static void |
122 |
|
✗ |
adapter_status_changed_cb (CcBluetoothPanel *self) |
123 |
|
|
{ |
124 |
|
|
GtkAlign valign; |
125 |
|
|
gboolean sensitive, powered; |
126 |
|
|
GtkWidget *page; |
127 |
|
|
|
128 |
|
✗ |
g_debug ("Updating airplane mode: BluetoothHasAirplaneMode %d, BluetoothHardwareAirplaneMode %d, BluetoothAirplaneMode %d, AirplaneMode %d", |
129 |
|
|
self->has_airplane_mode, self->hardware_airplane_mode, self->bt_airplane_mode, self->airplane_mode); |
130 |
|
|
|
131 |
|
✗ |
valign = GTK_ALIGN_CENTER; |
132 |
|
|
|
133 |
|
✗ |
if (self->has_airplane_mode == FALSE) { |
134 |
|
✗ |
g_debug ("No Bluetooth available"); |
135 |
|
✗ |
sensitive = FALSE; |
136 |
|
✗ |
powered = FALSE; |
137 |
|
✗ |
page = GTK_WIDGET (self->no_devices_page); |
138 |
|
✗ |
} else if (self->hardware_airplane_mode) { |
139 |
|
✗ |
g_debug ("Bluetooth is Hard blocked"); |
140 |
|
✗ |
sensitive = FALSE; |
141 |
|
✗ |
powered = FALSE; |
142 |
|
✗ |
page = GTK_WIDGET (self->hw_airplane_page); |
143 |
|
✗ |
} else if (self->airplane_mode) { |
144 |
|
✗ |
g_debug ("Airplane mode is on, Wi-Fi and Bluetooth are disabled"); |
145 |
|
✗ |
sensitive = FALSE; |
146 |
|
✗ |
powered = FALSE; |
147 |
|
✗ |
page = GTK_WIDGET (self->airplane_page); |
148 |
|
✗ |
} else if (self->bt_airplane_mode || |
149 |
|
✗ |
!bluetooth_settings_widget_get_default_adapter_powered (self->settings_widget)) { |
150 |
|
✗ |
g_debug ("Default adapter is unpowered"); |
151 |
|
✗ |
sensitive = TRUE; |
152 |
|
✗ |
powered = FALSE; |
153 |
|
✗ |
page = GTK_WIDGET (self->disabled_page); |
154 |
|
|
} else { |
155 |
|
✗ |
g_debug ("Bluetooth is available and powered"); |
156 |
|
✗ |
sensitive = TRUE; |
157 |
|
✗ |
powered = TRUE; |
158 |
|
✗ |
page = GTK_WIDGET (self->settings_widget); |
159 |
|
✗ |
valign = GTK_ALIGN_FILL; |
160 |
|
|
} |
161 |
|
|
|
162 |
|
✗ |
gtk_widget_set_valign (GTK_WIDGET (self->stack), valign); |
163 |
|
✗ |
gtk_widget_set_sensitive (GTK_WIDGET (self->header_box), sensitive); |
164 |
|
✗ |
g_signal_handlers_block_by_func (self->enable_switch, enable_switch_state_set_cb, self); |
165 |
|
✗ |
gtk_switch_set_active (self->enable_switch, powered); |
166 |
|
✗ |
g_signal_handlers_unblock_by_func (self->enable_switch, enable_switch_state_set_cb, self); |
167 |
|
|
|
168 |
|
✗ |
gtk_stack_set_visible_child (self->stack, page); |
169 |
|
✗ |
} |
170 |
|
|
|
171 |
|
|
static void |
172 |
|
✗ |
airplane_mode_changed (CcBluetoothPanel *self) |
173 |
|
|
{ |
174 |
|
✗ |
g_autoptr(GVariant) airplane_mode = NULL; |
175 |
|
✗ |
g_autoptr(GVariant) bluetooth_airplane_mode = NULL; |
176 |
|
✗ |
g_autoptr(GVariant) bluetooth_hardware_airplane_mode = NULL; |
177 |
|
✗ |
g_autoptr(GVariant) bluetooth_has_airplane_mode = NULL; |
178 |
|
|
|
179 |
|
✗ |
airplane_mode = g_dbus_proxy_get_cached_property (self->rfkill, "AirplaneMode"); |
180 |
|
✗ |
self->airplane_mode = g_variant_get_boolean (airplane_mode); |
181 |
|
|
|
182 |
|
✗ |
bluetooth_airplane_mode = g_dbus_proxy_get_cached_property (self->rfkill, "BluetoothAirplaneMode"); |
183 |
|
✗ |
self->bt_airplane_mode = g_variant_get_boolean (bluetooth_airplane_mode); |
184 |
|
|
|
185 |
|
✗ |
bluetooth_hardware_airplane_mode = g_dbus_proxy_get_cached_property (self->rfkill, "BluetoothHardwareAirplaneMode"); |
186 |
|
✗ |
self->hardware_airplane_mode = g_variant_get_boolean (bluetooth_hardware_airplane_mode); |
187 |
|
|
|
188 |
|
✗ |
bluetooth_has_airplane_mode = g_dbus_proxy_get_cached_property (self->rfkill, "BluetoothHasAirplaneMode"); |
189 |
|
✗ |
self->has_airplane_mode = g_variant_get_boolean (bluetooth_has_airplane_mode); |
190 |
|
|
|
191 |
|
✗ |
adapter_status_changed_cb (self); |
192 |
|
✗ |
} |
193 |
|
|
|
194 |
|
|
static void |
195 |
|
✗ |
airplane_mode_off_button_clicked_cb (CcBluetoothPanel *self) |
196 |
|
|
{ |
197 |
|
✗ |
g_debug ("Airplane Mode Off clicked, disabling airplane mode"); |
198 |
|
✗ |
g_dbus_proxy_call (self->rfkill, |
199 |
|
|
"org.freedesktop.DBus.Properties.Set", |
200 |
|
|
g_variant_new_parsed ("('org.gnome.SettingsDaemon.Rfkill'," |
201 |
|
|
"'AirplaneMode', %v)", |
202 |
|
|
g_variant_new_boolean (FALSE)), |
203 |
|
|
G_DBUS_CALL_FLAGS_NONE, |
204 |
|
|
-1, |
205 |
|
|
cc_panel_get_cancellable (CC_PANEL (self)), |
206 |
|
|
NULL, NULL); |
207 |
|
✗ |
} |
208 |
|
|
|
209 |
|
|
static void |
210 |
|
✗ |
panel_changed_cb (CcBluetoothPanel *self, |
211 |
|
|
const char *panel) |
212 |
|
|
{ |
213 |
|
|
CcShell *shell; |
214 |
|
✗ |
g_autoptr(GError) error = NULL; |
215 |
|
|
|
216 |
|
✗ |
shell = cc_panel_get_shell (CC_PANEL (self)); |
217 |
|
✗ |
if (cc_shell_set_active_panel_from_id (shell, panel, NULL, &error) == FALSE) |
218 |
|
✗ |
g_warning ("Failed to activate '%s' panel: %s", panel, error->message); |
219 |
|
✗ |
} |
220 |
|
|
|
221 |
|
|
static void |
222 |
|
✗ |
cc_bluetooth_panel_class_init (CcBluetoothPanelClass *klass) |
223 |
|
|
{ |
224 |
|
✗ |
GObjectClass *object_class = G_OBJECT_CLASS (klass); |
225 |
|
✗ |
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); |
226 |
|
✗ |
CcPanelClass *panel_class = CC_PANEL_CLASS (klass); |
227 |
|
|
|
228 |
|
✗ |
object_class->finalize = cc_bluetooth_panel_finalize; |
229 |
|
|
|
230 |
|
✗ |
panel_class->get_help_uri = cc_bluetooth_panel_get_help_uri; |
231 |
|
|
|
232 |
|
✗ |
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/bluetooth/cc-bluetooth-panel.ui"); |
233 |
|
|
|
234 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcBluetoothPanel, airplane_page); |
235 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcBluetoothPanel, disabled_page); |
236 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcBluetoothPanel, enable_switch); |
237 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcBluetoothPanel, header_box); |
238 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcBluetoothPanel, no_devices_page); |
239 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcBluetoothPanel, hw_airplane_page); |
240 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcBluetoothPanel, settings_widget); |
241 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcBluetoothPanel, stack); |
242 |
|
|
|
243 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, adapter_status_changed_cb); |
244 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, airplane_mode_off_button_clicked_cb); |
245 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, enable_switch_state_set_cb); |
246 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, panel_changed_cb); |
247 |
|
✗ |
} |
248 |
|
|
|
249 |
|
|
static void |
250 |
|
✗ |
cc_bluetooth_panel_init (CcBluetoothPanel *self) |
251 |
|
|
{ |
252 |
|
✗ |
bluetooth_settings_widget_get_type (); |
253 |
|
✗ |
g_resources_register (cc_bluetooth_get_resource ()); |
254 |
|
|
|
255 |
|
✗ |
gtk_widget_init_template (GTK_WIDGET (self)); |
256 |
|
|
|
257 |
|
|
/* RFKill */ |
258 |
|
✗ |
self->rfkill = cc_object_storage_create_dbus_proxy_sync (G_BUS_TYPE_SESSION, |
259 |
|
|
G_DBUS_PROXY_FLAGS_NONE, |
260 |
|
|
"org.gnome.SettingsDaemon.Rfkill", |
261 |
|
|
"/org/gnome/SettingsDaemon/Rfkill", |
262 |
|
|
"org.gnome.SettingsDaemon.Rfkill", |
263 |
|
|
NULL, NULL); |
264 |
|
✗ |
self->properties = cc_object_storage_create_dbus_proxy_sync (G_BUS_TYPE_SESSION, |
265 |
|
|
G_DBUS_PROXY_FLAGS_NONE, |
266 |
|
|
"org.gnome.SettingsDaemon.Rfkill", |
267 |
|
|
"/org/gnome/SettingsDaemon/Rfkill", |
268 |
|
|
"org.freedesktop.DBus.Properties", |
269 |
|
|
NULL, NULL); |
270 |
|
|
|
271 |
|
✗ |
airplane_mode_changed (self); |
272 |
|
✗ |
g_signal_connect_object (self->rfkill, "g-properties-changed", |
273 |
|
|
G_CALLBACK (airplane_mode_changed), self, G_CONNECT_SWAPPED); |
274 |
|
✗ |
} |
275 |
|
|
|