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