2 * Camera Launcher for Maemo.
3 * Copyright (C) 2010 Roman Moravcik
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.
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.
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
28 #include <gconf/gconf-client.h>
31 #include <glib/gi18n-lib.h>
34 #include <hildon/hildon.h>
39 #include <dbus/dbus.h>
43 #define CAM_COVER_UDI "/org/freedesktop/Hal/devices/platform_cam_shutter"
44 #define CAM_FOCUS_UDI "/org/freedesktop/Hal/devices/platform_cam_focus"
45 #define CAM_COVER_STATE "button.state.value"
47 #define CAMERA_UI_SHOW_ON_LENSCOVER_KEY "/apps/camera/settings/extra-settings/disable-show-on-lenscover-open"
49 typedef struct _CLLauncherData CLLauncherData;
50 struct _CLLauncherData {
53 CLLauncherAction action;
54 gchar *prefered_application;
55 GtkListStore *application_list;
56 gboolean application_list_empty;
58 gboolean camera_ui2_installed;
60 osso_context_t *osso_context;
61 GConfClient *gconf_client;
64 static void launcher_popup_show (CLLauncherData *data);
65 static void launcher_popup_hide (CLLauncherData *data);
68 run_application (CLLauncherData *data, DesktopFileInfo *application)
70 g_return_if_fail (data);
71 g_return_if_fail (data->osso_context);
73 if (application->osso_service) {
74 if (strcmp (application->osso_service, "")) {
75 if (osso_rpc_run_with_defaults (data->osso_context,
76 application->osso_service,
79 DBUS_TYPE_INVALID) != OSSO_OK) {
82 } else if (application->exec) {
83 if (strcmp (application->exec, "")) {
84 if (!g_spawn_command_line_async (application->exec, NULL)) {
92 check_camera_ui2 (void)
94 if (system ("test -n \"`dpkg -l camera-ui | grep cssu`\"") == 0)
101 check_camera2_show_on_lenscover (CLLauncherData *data)
103 g_return_if_fail (data);
104 g_return_if_fail (data->gconf_client);
106 return gconf_client_get_bool (data->gconf_client, CAMERA_UI_SHOW_ON_LENSCOVER_KEY, NULL);
110 disable_camera2_show_on_lenscover (CLLauncherData *data)
112 g_return_if_fail (data);
113 g_return_if_fail (data->gconf_client);
115 gconf_client_set_bool (data->gconf_client, CAMERA_UI_SHOW_ON_LENSCOVER_KEY, TRUE, NULL);
119 kill_camera_application (void)
121 system ("killall -9 camera-ui");
125 launcher_popup_selected (GtkTreeSelection *selection,
128 CLLauncherData *data = (CLLauncherData *) user_data;
132 g_return_if_fail (data);
134 if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
135 DesktopFileInfo application;
137 gtk_tree_model_get (model, &iter,
138 SELECTOR_COLUMN_NAME, &application.name,
139 SELECTOR_COLUMN_OSSO_SERVICE, &application.osso_service,
140 SELECTOR_COLUMN_EXEC, &application.exec,
143 run_application (data, &application);
146 /* destroy selector popup window */
147 launcher_popup_hide (data);
151 launcher_popup_response (GtkDialog *dialog,
155 CLLauncherData *data = (CLLauncherData *) user_data;
157 g_return_if_fail (data);
158 g_return_if_fail (data->dialog);
160 gtk_widget_hide_all (data->dialog);
161 gtk_widget_destroy (data->dialog);
166 launcher_popup_hide (CLLauncherData *data)
168 g_return_if_fail (data);
171 gtk_widget_hide_all (data->dialog);
172 gtk_widget_destroy (data->dialog);
178 launcher_popup_show (CLLauncherData *data)
180 GtkWidget *label, *alignment, *pannable, *tree_view;
181 GtkTreeViewColumn *column;
182 GtkCellRenderer *renderer;
183 GtkTreeSelection *selection;
185 g_return_if_fail (data);
188 data->dialog = gtk_dialog_new ();
189 gtk_window_set_title (GTK_WINDOW (data->dialog), _("Select application"));
190 gtk_widget_set_size_request (GTK_WIDGET (GTK_DIALOG (data->dialog)->vbox), -1, 292);
191 hildon_gtk_window_set_portrait_flags (GTK_WINDOW (data->dialog), HILDON_PORTRAIT_MODE_SUPPORT);
192 g_signal_connect (G_OBJECT (data->dialog), "response", G_CALLBACK (launcher_popup_response), data);
194 /* check if application list is empty */
195 if (!data->application_list_empty) {
196 GtkTreeSelection *selection;
198 /* sort list of applications */
199 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (data->application_list),
200 SELECTOR_COLUMN_NAME, GTK_SORT_ASCENDING);
203 alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
204 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment),
205 0, 0, HILDON_MARGIN_DEFAULT, 0);
206 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (data->dialog)->vbox), alignment);
209 pannable = hildon_pannable_area_new ();
210 gtk_container_add (GTK_CONTAINER (alignment), pannable);
213 tree_view = hildon_gtk_tree_view_new_with_model (HILDON_UI_MODE_EDIT,
214 GTK_TREE_MODEL (data->application_list));
215 gtk_container_add (GTK_CONTAINER (pannable), tree_view);
217 /* application icon */
218 column = gtk_tree_view_column_new ();
219 gtk_tree_view_column_set_fixed_width (column, 75);
220 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
221 renderer = gtk_cell_renderer_pixbuf_new ();
222 g_object_set(G_OBJECT(renderer), "xpad", 10, NULL);
223 gtk_tree_view_column_pack_start (column, renderer, FALSE);
224 gtk_tree_view_column_set_attributes (column, renderer,
225 "pixbuf", SELECTOR_COLUMN_ICON,
227 gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
229 /* application name */
230 column = gtk_tree_view_column_new ();
231 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
232 renderer = gtk_cell_renderer_text_new ();
233 gtk_tree_view_column_pack_end (column, renderer, TRUE);
234 gtk_tree_view_column_set_attributes (column, renderer, "text",
235 SELECTOR_COLUMN_NAME,
237 gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
239 label = gtk_label_new (_("No applications"));
240 hildon_helper_set_logical_color (label, GTK_RC_FG, GTK_STATE_NORMAL,
241 "SecondaryTextColor");
242 hildon_helper_set_logical_font (label, "LargeSystemFont");
243 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (data->dialog)->vbox), label);
246 /* show selector popup */
247 gtk_widget_show_all (data->dialog);
249 /* unselect all entries */
251 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
252 gtk_tree_selection_unselect_all (selection);
253 g_signal_connect (G_OBJECT (selection), "changed", G_CALLBACK (launcher_popup_selected), data);
258 camera_launcher_on_gconf_changed (GConfClient *client,
261 CLLauncherData *data)
265 CLLauncherAction action;
266 const gchar *application;
267 const GSList *application_list;
269 g_return_if_fail (data);
271 key = gconf_entry_get_key (entry);
272 value = gconf_entry_get_value (entry);
274 g_return_if_fail (value);
276 /* Only key without absolute path is required */
277 key += strlen (GCONF_CL_LAUNCHER) + 1;
279 if (!strcmp (key, "action")) {
280 action = gconf_value_get_int (value);
281 if ((action < CL_LAUNCHER_ACTION_RUN_PREFERED_APPLICATION) ||
282 (action > CL_LAUNCHER_ACTION_DO_NOTHING)) {
283 g_warning("camera_launcher_on_gconf_changed: Wrong value %d of key %s/%s", action,
284 GCONF_CL_LAUNCHER, key);
286 data->action = action;
288 } else if (!strcmp (key, "prefered_application")) {
289 application = gconf_value_get_string (value);
290 if (strcmp (application, "") &&
291 g_str_has_suffix (application, ".desktop"))
293 if (data->prefered_application)
294 g_free (data->prefered_application);
295 data->prefered_application = g_strdup (application);
297 g_warning("camera_launcher_on_gconf_changed: Wrong value %s of key %s/%s", application,
298 GCONF_CL_LAUNCHER, key);
300 } else if (!strcmp (key, "application_list")) {
301 if (data->application_list) {
302 if (gconf_value_get_list_type (value) == GCONF_VALUE_STRING) {
303 application_list = gconf_value_get_list (value);
305 /* clear previous application list */
306 gtk_list_store_clear (data->application_list);
308 /* fill application list */
309 data->application_list_empty = get_application_list_from_list (data->application_list,
314 g_warning("camera_launcher_on_gconf_changed: Wrong %s key, %s", GCONF_CL_LAUNCHER, key);
319 camera_launcher_on_hal_property_modified (LibHalContext *ctx,
322 dbus_bool_t is_removed,
323 dbus_bool_t is_added)
325 CLLauncherData *data = libhal_ctx_get_user_data (ctx);
327 DesktopFileInfo *application;
329 g_return_if_fail (data);
331 if (strcmp (key, CAM_COVER_STATE) != 0)
334 state = !libhal_device_get_property_bool (ctx, udi, key, NULL);
336 if (!strcmp (udi, CAM_COVER_UDI)) {
338 switch (data->action) {
339 case CL_LAUNCHER_ACTION_DO_NOTHING:
341 only just kill camera application if it's running.
342 do nothing if camera2 (from cssu) is installed
344 if (!data->camera_ui2_installed)
345 kill_camera_application ();
348 case CL_LAUNCHER_ACTION_RUN_PREFERED_APPLICATION:
350 kill camera application only if it's not selected as prefered,
351 except camera2 (from cssu) is installed
353 if (strcmp (data->prefered_application, CAMERA_APPLICATION_DESKTOP_FILE)) {
354 if (!data->camera_ui2_installed)
355 kill_camera_application ();
358 /* run prefered application */
359 application = get_desktop_file_info (data->prefered_application);
361 run_application (data, application);
362 g_free (application);
366 case CL_LAUNCHER_ACTION_SHOW_SELECTOR_POPUP:
368 kill camera application if it's running, expect camera2 (from cssu)
371 if (!data->camera_ui2_installed)
372 kill_camera_application ();
374 /* create selector popup window */
375 launcher_popup_show (data);
379 switch (data->action) {
380 case CL_LAUNCHER_ACTION_DO_NOTHING:
381 case CL_LAUNCHER_ACTION_RUN_PREFERED_APPLICATION:
385 case CL_LAUNCHER_ACTION_SHOW_SELECTOR_POPUP:
386 /* destroy selector popup window */
387 launcher_popup_hide (data);
391 } else if (!strcmp (udi, CAM_FOCUS_UDI)) {
393 /* run camera application when focus key was pressed */
394 application = get_desktop_file_info (CAMERA_APPLICATION_DESKTOP_FILE);
396 run_application (data, application);
397 g_free (application);
404 main (int argc, char **argv)
406 CLLauncherData *data;
407 DBusConnection *dbus_connection;
409 DBusError dbus_error;
410 GError *error = NULL;
412 hildon_gtk_init (&argc, &argv);
414 /* allocate cllauncherdata */
415 data = g_new0 (CLLauncherData, 1);
417 data->action = CL_LAUNCHER_ACTION_RUN_PREFERED_APPLICATION;
418 data->prefered_application = g_strdup (CAMERA_APPLICATION_DESKTOP_FILE);
419 data->application_list = gtk_list_store_new (NUM_COLS,
420 G_TYPE_STRING, /* SELECTOR_COLUMN_FILENAME */
421 GDK_TYPE_PIXBUF, /* SELECTOR_COLUMN_ICON */
422 G_TYPE_STRING, /* SELECTOR_COLUMN_NAME */
423 G_TYPE_STRING, /* SELECTOR_COLUMN_OSSO_SERVICE */
424 G_TYPE_STRING); /* SELECTOR_COLUMN_EXEC */
425 data->application_list_empty = TRUE;
427 /* initialize osso */
428 data->osso_context = osso_initialize (PACKAGE, VERSION, TRUE, NULL);
430 /* initialize gconf */
431 data->gconf_client = gconf_client_get_default ();
432 gconf_client_add_dir (data->gconf_client, GCONF_CL_LAUNCHER, GCONF_CLIENT_PRELOAD_ONELEVEL, &error);
434 g_warning ("camera-launcher: Unable to add GConf client, %s", error->message);
435 g_error_free (error);
439 gconf_client_notify_add (data->gconf_client, GCONF_CL_LAUNCHER,
440 (GConfClientNotifyFunc) camera_launcher_on_gconf_changed, data, NULL, &error);
442 g_warning ("camera-launcher: Unable to add GConf client notification, %s", error->message);
443 g_error_free (error);
446 gconf_client_notify (data->gconf_client, GCONF_CL_LAUNCHER "/action");
447 gconf_client_notify (data->gconf_client, GCONF_CL_LAUNCHER "/prefered_application");
448 gconf_client_notify (data->gconf_client, GCONF_CL_LAUNCHER "/application_list");
450 /* initialize dbus */
451 dbus_error_init (&dbus_error);
452 dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_error);
453 if (dbus_error_is_set (&dbus_error)) {
454 g_critical ("camera-launcher: Could not get the system DBus connection, %s",
456 dbus_error_free (&dbus_error);
461 hal = libhal_ctx_new ();
463 g_critical ("camera-launcher: Unable to create HAL context\n");
467 libhal_ctx_set_dbus_connection (hal, dbus_connection);
468 libhal_ctx_set_user_data (hal, data);
469 libhal_ctx_set_device_property_modified (hal, camera_launcher_on_hal_property_modified);
471 if (!libhal_ctx_init (hal, &dbus_error)) {
472 if (dbus_error_is_set (&dbus_error)) {
473 g_critical ("camera-launcher: Could not initialize the HAL context, %s",
475 dbus_error_free (&dbus_error);
477 g_critical ("camera-launcher: Could not initialize the HAL context, "
478 "no error, is hald running?");
483 libhal_device_add_property_watch (hal, CAM_COVER_UDI, NULL);
484 /* libhal_device_add_property_watch (hal, CAM_FOCUS_UDI, NULL); */
486 /* disable showing of camera-ui if camera application from cssu is installed */
487 if (check_camera_ui2 ()) {
488 if (!check_camera2_show_on_lenscover (data)) {
489 disable_camera2_show_on_lenscover (data);
491 /* kill camera-ui process to reload new configuration */
492 kill_camera_application ();
494 data->camera_ui2_installed = TRUE;
496 data->camera_ui2_installed = FALSE;
501 /* deinitialize hal */
503 libhal_device_remove_property_watch (hal, CAM_COVER_UDI, NULL);
504 /* libhal_device_remove_property_watch (hal, CAM_FOCUS_UDI, NULL); */
506 libhal_ctx_set_user_data (hal, NULL);
507 libhal_ctx_shutdown (hal, NULL);
508 libhal_ctx_free (hal);
511 /* unreference dbus connection */
513 dbus_connection_unref (dbus_connection);
516 /* deinitialize osso */
517 if (data->osso_context) {
518 osso_deinitialize (data->osso_context);
521 /* free cllauncherdata */
523 if (data->prefered_application)
524 g_free (data->prefered_application);
526 /* unref application list */
527 g_object_unref (data->application_list);