9dc8aa8d6008c9f37947f2b7b5be780dc5ccc91f
[flashlight-appl] / src / flashlight_applet.c
1 /*
2  *  Flashlight applet (widget) for Maemo.
3  *  Copyright (C) 2009 Roman Moravcik
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <gtk/gtk.h>
27 #include <hildon/hildon.h>
28 #include <glib/gi18n-lib.h>
29 #include <libhal.h>
30 #include <dbus/dbus.h>
31
32 #include "flashlight_applet.h"
33 #include "flashlight_lib.h"
34
35 #define MSG_FLASHLIGHT_ON _("On")
36 #define MSG_FLASHLIGHT_OFF _("Off")
37
38 #define ICON_FLASHLIGHT_ON "statusarea_flashlight_on"
39 #define ICON_FLASHLIGHT_OFF "statusarea_flashlight_off"
40
41 #define CAM_COVER_UDI "/org/freedesktop/Hal/devices/platform_cam_shutter"
42 #define CAM_COVER_STATE "button.state.value"
43
44 #define FLASHLIGHT_STATUS_PLUGIN_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE (obj,   \
45                             TYPE_FLASHLIGHT_STATUS_PLUGIN, FlashlightPluginPrivate))
46
47 struct _FlashlightPluginPrivate
48 {
49         GtkWidget *button;
50         FlashlightContext_t *flashlight;
51         LibHalContext *hal;
52 };
53
54 HD_DEFINE_PLUGIN_MODULE (FlashlightPlugin, flashlight_status_plugin, HD_TYPE_STATUS_MENU_ITEM)
55
56 static void
57 flashlight_status_plugin_finalize (GObject *object);
58
59 static void
60 flashlight_status_plugin_show_notification (FlashlightPlugin *plugin,
61                                             const gchar *text)
62 {
63         FlashlightPluginPrivate *priv = FLASHLIGHT_STATUS_PLUGIN_GET_PRIVATE (plugin);
64         GtkWidget *banner;
65
66         g_return_if_fail (priv);
67
68         banner = hildon_banner_show_information (GTK_WIDGET (priv->button), NULL, text);
69         hildon_banner_set_timeout (HILDON_BANNER (banner), 9000);
70 }
71
72 static void
73 flashlight_status_plugin_enable (FlashlightPlugin *plugin,
74                                  gboolean enable)
75 {
76         FlashlightPluginPrivate *priv = FLASHLIGHT_STATUS_PLUGIN_GET_PRIVATE (plugin);
77
78         g_return_if_fail (priv);
79
80         if (enable) {
81                 if (flashlight_open (priv->flashlight, "/dev/video0") == -1) {
82                         flashlight_status_plugin_show_notification (plugin,
83                                 _("Unable to initialize flashlight.\nCamera in use by another application."));
84                         return;
85                 }
86
87                 if (flashlight_set_intensity (priv->flashlight, 10) == -1) {
88                         flashlight_status_plugin_show_notification (plugin,
89                                 _("Unable to turn on flashlight."));
90                         return;
91                 }
92
93                 hildon_button_set_value (HILDON_BUTTON (priv->button), MSG_FLASHLIGHT_ON);
94                 hildon_button_set_image (HILDON_BUTTON (priv->button),
95                                          gtk_image_new_from_icon_name (ICON_FLASHLIGHT_ON, -1));
96         } else {
97                 if (flashlight_set_intensity (priv->flashlight, 0) == -1) {
98                         flashlight_status_plugin_show_notification (plugin,
99                                 _("Unable to turn off flashlight."));
100                         return;
101                 }
102
103                 if (flashlight_close (priv->flashlight) == -1) {
104                         return;
105                 }
106
107                 hildon_button_set_value (HILDON_BUTTON (priv->button), MSG_FLASHLIGHT_OFF);
108                 hildon_button_set_image (HILDON_BUTTON (priv->button),
109                                          gtk_image_new_from_icon_name (ICON_FLASHLIGHT_OFF, -1));
110         }
111 }
112
113 static void
114 flashlight_status_plugin_on_hal_property_modified (LibHalContext *ctx,
115                                                    const char *udi,
116                                                    const char *key,
117                                                    dbus_bool_t is_removed,
118                                                    dbus_bool_t is_added)
119 {
120         FlashlightPlugin *plugin = libhal_ctx_get_user_data (ctx);
121         FlashlightPluginPrivate *priv = FLASHLIGHT_STATUS_PLUGIN_GET_PRIVATE (plugin);
122         gboolean is_open;
123         int intensity = 0;
124
125         g_return_if_fail (priv);
126
127         if (strcmp (key, CAM_COVER_STATE) != 0)
128                 return;
129
130         is_open = !libhal_device_get_property_bool (ctx, udi, key, NULL);
131
132         if (is_open) {
133                 /* show widget */
134                 gtk_widget_show_all (GTK_WIDGET (plugin));
135         } else {
136                 /* turn off flashlight if flashlight is enabled */
137                 flashlight_get_intensity (priv->flashlight, &intensity);
138
139                 if (intensity > 0) {
140                         flashlight_status_plugin_enable (plugin, FALSE);
141                 }
142
143                 /* hide widget */
144                 gtk_widget_hide_all (GTK_WIDGET (plugin));
145         }
146 }
147
148 static void
149 flashlight_status_plugin_on_clicked (HildonButton *button,
150                                      gpointer data)
151 {
152         FlashlightPluginPrivate *priv = FLASHLIGHT_STATUS_PLUGIN_GET_PRIVATE (data);
153
154         g_return_if_fail (priv);
155
156         if (!strcmp (hildon_button_get_value (button), MSG_FLASHLIGHT_ON)) {
157                 flashlight_status_plugin_enable (data, FALSE);
158         } else {
159                 flashlight_status_plugin_enable (data, TRUE);
160
161                 /* fixme periodicaly check status */
162         }
163 }
164
165 static GtkWidget *
166 flashlight_status_plugin_ui (FlashlightPlugin *plugin)
167 {
168         GtkWidget *button;
169
170         button = hildon_button_new (HILDON_SIZE_FINGER_HEIGHT, HILDON_BUTTON_ARRANGEMENT_VERTICAL);
171         gtk_button_set_alignment (GTK_BUTTON (button), 0.0, 0.5);
172         hildon_button_set_title (HILDON_BUTTON (button), _("Flashlight"));
173         hildon_button_set_value (HILDON_BUTTON (button), MSG_FLASHLIGHT_OFF);
174         hildon_button_set_image (HILDON_BUTTON (button),
175                                  gtk_image_new_from_icon_name (ICON_FLASHLIGHT_OFF, -1));
176         hildon_button_set_image_position (HILDON_BUTTON (button), GTK_POS_LEFT);
177
178         g_signal_connect (button, "clicked",
179                                         G_CALLBACK (flashlight_status_plugin_on_clicked), plugin);
180
181         return button;
182 }
183
184 static void
185 flashlight_status_plugin_class_init (FlashlightPluginClass *class)
186 {
187         GObjectClass *object_class = G_OBJECT_CLASS (class);
188
189         object_class->finalize = flashlight_status_plugin_finalize;
190
191         g_type_class_add_private (class, sizeof (FlashlightPluginPrivate));
192 }
193
194 static void
195 flashlight_status_plugin_class_finalize (FlashlightPluginClass *class)
196 {
197 }
198
199 static void
200 flashlight_status_plugin_init (FlashlightPlugin *plugin)
201 {
202         FlashlightPluginPrivate *priv = FLASHLIGHT_STATUS_PLUGIN_GET_PRIVATE (plugin);
203         DBusConnection *dbus_connection;
204         DBusError error;
205
206         dbus_error_init (&error);
207         dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
208         if (dbus_error_is_set (&error)) {
209                 g_critical ("flashlight_status_plugin_init: Could not get the system DBus connection, %s",
210                             error.message);
211                 dbus_error_free (&error);
212                 return;
213         }
214
215         if (flashlight_init (&priv->flashlight) == -1) {
216                 g_critical ("flashlight_status_plugin_init: Unable to create Flashlight context\n");
217                 return;
218         }
219
220         priv->hal = libhal_ctx_new ();
221         if (!priv->hal) {
222                 g_critical ("flashlight_status_plugin_init: Unable to create HAL context\n");
223                 return;
224         }
225
226         libhal_ctx_set_dbus_connection (priv->hal, dbus_connection);
227         libhal_ctx_set_user_data (priv->hal, plugin);
228         libhal_ctx_set_device_property_modified (priv->hal,
229                                                  flashlight_status_plugin_on_hal_property_modified);
230
231         if (!libhal_ctx_init (priv->hal, &error)) {
232                 if (dbus_error_is_set (&error)) {
233                         g_critical ("Could not initialize the HAL context, %s",
234                                     error.message);
235                         dbus_error_free (&error);
236                 } else {
237                         g_critical ("Could not initialize the HAL context, "
238                                     "no error, is hald running?");
239                 }
240                 libhal_ctx_set_user_data (priv->hal, NULL);
241                 libhal_ctx_free (priv->hal);
242         }
243
244         libhal_device_add_property_watch (priv->hal, CAM_COVER_UDI, NULL);
245
246         priv->button = flashlight_status_plugin_ui (plugin);
247         gtk_container_add (GTK_CONTAINER (plugin), priv->button);
248
249         /* show widget if camera cover is open */
250         if ( !libhal_device_get_property_bool (priv->hal, CAM_COVER_UDI, CAM_COVER_STATE, NULL))
251                 gtk_widget_show_all (GTK_WIDGET (plugin));
252
253 }
254
255 static void
256 flashlight_status_plugin_finalize (GObject *object)
257 {
258         FlashlightPlugin *plugin = FLASHLIGHT_STATUS_PLUGIN (object);
259         FlashlightPluginPrivate *priv = FLASHLIGHT_STATUS_PLUGIN_GET_PRIVATE (plugin);
260
261         if (priv->hal) {
262                 libhal_device_remove_property_watch (priv->hal, CAM_COVER_UDI, NULL);
263                 libhal_ctx_set_user_data (priv->hal, NULL);
264                 libhal_ctx_free (priv->hal);
265                 priv->hal = NULL;
266         }
267
268         if (priv->flashlight) {
269                 flashlight_deinit (priv->flashlight);
270                 priv->flashlight = NULL;
271         }
272
273         G_OBJECT_CLASS (flashlight_status_plugin_parent_class)->finalize (object);
274 }