1 /* $Id$ */
2 /* Copyright (c) 2010-2015 Pierre Pronchery <khorben@defora.org> */
3 /* This file is part of DeforaOS Desktop Panel */
4 /* This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, version 3 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>. */
15
16
17
18 #if defined(__NetBSD__)
19 # include <sys/types.h>
20 # include <sys/ioctl.h>
21 # include <bluetooth.h>
22 # include <unistd.h>
23 # include <stdio.h>
24 #elif defined(__linux__)
25 # include <fcntl.h>
26 # include <unistd.h>
27 #endif
28 # include <string.h>
29 # include <errno.h>
30 #include <stdlib.h>
31 #include <libintl.h>
32 #include <System.h>
33 #include "Panel/applet.h"
34 #define _(string) gettext(string)
35
36
37 /* Bluetooth */
38 /* private */
39 /* types */
40 typedef struct _PanelApplet
41 {
42 PanelAppletHelper * helper;
43 GtkWidget * image;
44 guint timeout;
45 #if defined(__NetBSD__) || defined(__linux__)
46 int fd;
47 #endif
48 } Bluetooth;
49
50
51 /* prototypes */
52 static Bluetooth * _bluetooth_init(PanelAppletHelper * helper,
53 GtkWidget ** widget);
54 static void _bluetooth_destroy(Bluetooth * bluetooth);
55
56 /* accessors */
57 static gboolean _bluetooth_get(Bluetooth * bluetooth, gboolean * active);
58 static void _bluetooth_set(Bluetooth * bluetooth, gboolean active);
59
60 /* callbacks */
61 static gboolean _bluetooth_on_timeout(gpointer data);
62
63
64 /* public */
65 /* variables */
66 PanelAppletDefinition applet =
67 {
68 "Bluetooth",
69 "panel-applet-bluetooth",
70 NULL,
71 _bluetooth_init,
72 _bluetooth_destroy,
73 NULL,
74 FALSE,
75 TRUE
76 };
77
78
79 /* private */
80 /* functions */
81 /* bluetooth_init */
_bluetooth_init(PanelAppletHelper * helper,GtkWidget ** widget)82 static Bluetooth * _bluetooth_init(PanelAppletHelper * helper,
83 GtkWidget ** widget)
84 {
85 const int timeout = 1000;
86 Bluetooth * bluetooth;
87 GtkIconSize iconsize;
88
89 if((bluetooth = object_new(sizeof(*bluetooth))) == NULL)
90 return NULL;
91 bluetooth->helper = helper;
92 #if defined(__NetBSD__) || defined(__linux__)
93 bluetooth->fd = -1;
94 #endif
95 iconsize = panel_window_get_icon_size(helper->window);
96 #if GTK_CHECK_VERSION(3, 0, 0)
97 *widget = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
98 #else
99 *widget = gtk_hbox_new(FALSE, 0);
100 #endif
101 bluetooth->image = gtk_image_new_from_icon_name(
102 "panel-applet-bluetooth", iconsize);
103 #if GTK_CHECK_VERSION(2, 12, 0)
104 gtk_widget_set_tooltip_text(bluetooth->image,
105 _("Bluetooth is enabled"));
106 #endif
107 gtk_box_pack_start(GTK_BOX(*widget), bluetooth->image, TRUE, TRUE, 0);
108 gtk_widget_set_no_show_all(*widget, TRUE);
109 bluetooth->timeout = (_bluetooth_on_timeout(bluetooth) == TRUE)
110 ? g_timeout_add(timeout, _bluetooth_on_timeout, bluetooth) : 0;
111 return bluetooth;
112 }
113
114
115 /* bluetooth_destroy */
_bluetooth_destroy(Bluetooth * bluetooth)116 static void _bluetooth_destroy(Bluetooth * bluetooth)
117 {
118 if(bluetooth->timeout > 0)
119 g_source_remove(bluetooth->timeout);
120 #if defined(__NetBSD__) || defined(__linux__)
121 if(bluetooth->fd >= 0)
122 close(bluetooth->fd);
123 #endif
124 gtk_widget_destroy(bluetooth->image);
125 object_delete(bluetooth);
126 }
127
128
129 /* accessors */
130 /* bluetooth_get */
_bluetooth_get(Bluetooth * bluetooth,gboolean * active)131 static gboolean _bluetooth_get(Bluetooth * bluetooth, gboolean * active)
132 {
133 #if defined(__NetBSD__)
134 struct btreq btr;
135 const char name[] = "ubt0";
136
137 if(bluetooth->fd < 0 && (bluetooth->fd = socket(AF_BLUETOOTH,
138 SOCK_RAW, BTPROTO_HCI)) < 0)
139 {
140 *active = FALSE;
141 error_set("%s: %s: %s", applet.name, "socket", strerror(errno));
142 return TRUE;
143 }
144 memset(&btr, 0, sizeof(btr));
145 strncpy(btr.btr_name, name, sizeof(name));
146 if(ioctl(bluetooth->fd, SIOCGBTINFO, &btr) == -1)
147 {
148 *active = FALSE;
149 error_set("%s: %s: %s", applet.name, name, strerror(errno));
150 close(bluetooth->fd);
151 bluetooth->fd = -1;
152 }
153 else
154 {
155 *active = TRUE;
156 /* XXX should not be needed but EBADF happens once otherwise */
157 close(bluetooth->fd);
158 bluetooth->fd = -1;
159 }
160 return TRUE;
161 #elif defined(__linux__)
162 /* XXX currently hard-coded for the Openmoko Freerunner */
163 char const dv1[] = "/sys/bus/platform/devices/gta02-pm-bt.0/power_on";
164 char const dv2[] = "/sys/bus/platform/devices/neo1973-pm-bt.0/power_on";
165 char const * dev = dv1;
166 char on;
167
168 if(bluetooth->fd < 0)
169 {
170 if((bluetooth->fd = open(dev, O_RDONLY)) < 0)
171 {
172 dev = dv2;
173 bluetooth->fd = open(dev, O_RDONLY);
174 }
175 if(bluetooth->fd < 0)
176 {
177 *active = FALSE;
178 error_set("%s: %s: %s", applet.name, dev,
179 strerror(errno));
180 return TRUE;
181 }
182 }
183 errno = ENODATA; /* in case the pseudo-file is empty */
184 if(lseek(bluetooth->fd, 0, SEEK_SET) != 0
185 || read(bluetooth->fd, &on, sizeof(on)) != sizeof(on))
186 {
187 *active = FALSE;
188 error_set("%s: %s: %s", applet.name, dev, strerror(errno));
189 close(bluetooth->fd);
190 bluetooth->fd = -1;
191 return TRUE;
192 }
193 *active = (on == '1') ? TRUE : FALSE;
194 return TRUE;
195 #else
196 /* FIXME not supported */
197 *active = FALSE;
198 error_set("%s: %s", applet.name, strerror(ENOSYS));
199 return FALSE;
200 #endif
201 }
202
203
204 /* bluetooth_set */
_bluetooth_set(Bluetooth * bluetooth,gboolean active)205 static void _bluetooth_set(Bluetooth * bluetooth, gboolean active)
206 {
207 if(active == TRUE)
208 gtk_widget_show(bluetooth->image);
209 else
210 gtk_widget_hide(bluetooth->image);
211 }
212
213
214 /* callbacks */
215 /* bluetooth_on_timeout */
_bluetooth_on_timeout(gpointer data)216 static gboolean _bluetooth_on_timeout(gpointer data)
217 {
218 Bluetooth * bluetooth = data;
219 gboolean active;
220
221 if(_bluetooth_get(bluetooth, &active) == FALSE)
222 {
223 bluetooth->helper->error(NULL, error_get(NULL), 1);
224 _bluetooth_set(bluetooth, FALSE);
225 bluetooth->timeout = 0;
226 return FALSE;
227 }
228 _bluetooth_set(bluetooth, active);
229 return TRUE;
230 }
231