--- /dev/null
+/*
+ * Camera Launcher for Maemo.
+ * Copyright (C) 2009 Roman Moravcik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gconf/gconf-client.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
+#include <gtk/gtk.h>
+#include <hildon/hildon.h>
+
+#include <libosso.h>
+
+#include <libhal.h>
+#include <dbus/dbus.h>
+
+#include "cl-utils.h"
+
+#define CAM_COVER_UDI "/org/freedesktop/Hal/devices/platform_cam_shutter"
+#define CAM_FOCUS_UDI "/org/freedesktop/Hal/devices/platform_cam_focus"
+#define CAM_COVER_STATE "button.state.value"
+
+#define CAMERA_APPLICATION "camera-ui.desktop"
+
+typedef struct _CLLauncherData CLLauncherData;
+struct _CLLauncherData {
+ GtkWidget *dialog;
+
+ CLLauncherAction action;
+ gchar *application;
+
+ osso_context_t *osso_context;
+ GConfClient *gconf_client;
+};
+
+static void launcher_popup_show (CLLauncherData *data);
+static void launcher_popup_hide (CLLauncherData *data);
+
+static void
+run_application (CLLauncherData *data, DesktopFileInfo *application)
+{
+ g_return_if_fail (data);
+
+ if (application->osso_service) {
+ if (strcmp (application->osso_service, "")) {
+ if (osso_rpc_run_with_defaults (data->osso_context,
+ application->osso_service,
+ "top_application",
+ NULL,
+ DBUS_TYPE_INVALID) != OSSO_OK) {
+ }
+ }
+ } else if (application->exec) {
+ if (strcmp (application->exec, "")) {
+ if (!g_spawn_command_line_async (application->exec, NULL)) {
+ }
+ }
+ } else {
+ }
+}
+
+static void
+kill_camera_application (void)
+{
+ system ("killall -9 camera-ui");
+}
+
+static void
+launcher_popup_selected (GtkTreeSelection *selection,
+ gpointer user_data)
+{
+ CLLauncherData *data = (CLLauncherData *) user_data;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ g_return_if_fail (data);
+
+ if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+ DesktopFileInfo application;
+
+ gtk_tree_model_get (model, &iter,
+ SELECTOR_COLUMN_NAME, &application.name,
+ SELECTOR_COLUMN_OSSO_SERVICE, &application.osso_service,
+ SELECTOR_COLUMN_EXEC, &application.exec,
+ -1);
+
+ run_application (data, &application);
+ }
+
+ /* destroy selector popup window */
+ launcher_popup_hide (data);
+}
+
+static void
+launcher_popup_response (GtkDialog *dialog,
+ gint response_id,
+ gpointer user_data)
+{
+ CLLauncherData *data = (CLLauncherData *) user_data;
+
+ g_return_if_fail (data);
+
+ gtk_widget_hide_all (data->dialog);
+ gtk_widget_destroy (data->dialog);
+ data->dialog = NULL;
+}
+
+static void
+launcher_popup_hide (CLLauncherData *data)
+{
+ g_return_if_fail (data);
+
+ if (data->dialog) {
+ gtk_widget_hide_all (data->dialog);
+ gtk_widget_destroy (data->dialog);
+ data->dialog = NULL;
+ }
+}
+
+static void
+launcher_popup_show (CLLauncherData *data)
+{
+ GtkWidget *label, *alignment, *pannable, *tree_view;
+ GtkListStore *application_list;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+ GtkTreeSelection *selection;
+
+ g_return_if_fail (data);
+
+ /* popup dialog */
+ data->dialog = gtk_dialog_new ();
+ gtk_window_set_title (GTK_WINDOW (data->dialog), _("Select application"));
+ gtk_widget_set_size_request (GTK_WIDGET (GTK_DIALOG (data->dialog)->vbox), -1, 270);
+ g_signal_connect (G_OBJECT (data->dialog), "response", G_CALLBACK (launcher_popup_response), data);
+
+ /* create application list */
+ application_list = gtk_list_store_new (NUM_COLS,
+ GDK_TYPE_PIXBUF, /* SELECTOR_COLUMN_ICON */
+ G_TYPE_STRING, /* SELECTOR_COLUMN_NAME */
+ G_TYPE_STRING, /* SELECTOR_COLUMN_OSSO_SERVICE */
+ G_TYPE_STRING); /* SELECTOR_COLUMN_EXEC */
+
+ /* get application list */
+ if (get_application_list (application_list)) {
+ GtkTreeSelection *selection;
+
+ /* sort list of calendars */
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (application_list),
+ SELECTOR_COLUMN_NAME, GTK_SORT_ASCENDING);
+
+ /* alignment */
+ alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment),
+ 0, 0, HILDON_MARGIN_DEFAULT, 0);
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG (data->dialog)->vbox), alignment);
+
+ /* pannable */
+ pannable = hildon_pannable_area_new ();
+ gtk_container_add (GTK_CONTAINER (alignment), pannable);
+
+ /* tree view */
+ tree_view = hildon_gtk_tree_view_new_with_model (HILDON_UI_MODE_EDIT,
+ GTK_TREE_MODEL (application_list));
+ gtk_container_add (GTK_CONTAINER (pannable), tree_view);
+
+ /* application icon */
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_fixed_width (column, 75);
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ g_object_set(G_OBJECT(renderer), "xpad", 10, NULL);
+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
+ gtk_tree_view_column_set_attributes (column, renderer,
+ "pixbuf", SELECTOR_COLUMN_ICON,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+
+ /* application name */
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_end (column, renderer, TRUE);
+ gtk_tree_view_column_set_attributes (column, renderer, "text",
+ SELECTOR_COLUMN_NAME,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+ } else {
+ label = gtk_label_new (_("No applications"));
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG (data->dialog)->vbox), label);
+ }
+
+ /* unref application list */
+ g_object_unref (application_list);
+
+ /* show selector popup */
+ gtk_widget_show_all (data->dialog);
+
+ /* unselect all entries */
+ if (tree_view) {
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+ gtk_tree_selection_unselect_all (selection);
+ g_signal_connect (G_OBJECT (selection), "changed", G_CALLBACK (launcher_popup_selected), data);
+ }
+}
+
+static void
+camera_launcher_on_gconf_changed (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ CLLauncherData *data)
+{
+ const gchar *key;
+ GConfValue *value;
+ CLLauncherAction action;
+ const gchar *application;
+
+ key = gconf_entry_get_key (entry);
+ value = gconf_entry_get_value (entry);
+
+ g_return_if_fail (data);
+ g_return_if_fail (value);
+
+ /* Only key without absolute path is required */
+ key += strlen (GCONF_CL_LAUNCHER) + 1;
+
+ if (!strcmp (key, "action")) {
+ action = gconf_value_get_int (value);
+ if ((action < CL_LAUNCHER_ACTION_DO_NOTHING) ||
+ (action > CL_LAUNCHER_ACTION_SHOW_SELECTOR_POPUP)) {
+ g_warning("camera_launcher_on_gconf_changed: Wrong value %d of key %s/%s", action, GCONF_CL_LAUNCHER, key);
+ } else {
+ data->action = action;
+ }
+ } else if (!strcmp (key, "application")) {
+ application = gconf_value_get_string (value);
+ if (strcmp (application, "") &&
+ g_str_has_suffix (application, ".desktop"))
+ {
+ if (data->application)
+ g_free (data->application);
+ data->application = g_strdup (application);
+ } else {
+ g_warning("camera_launcher_on_gconf_changed: Wrong value %s of key %s/%s", application, GCONF_CL_LAUNCHER, key);
+ }
+ } else {
+ g_warning("camera_launcher_on_gconf_changed: Wrong %s key, %s", GCONF_CL_LAUNCHER, key);
+ }
+ gconf_value_free (value);
+}
+
+static void
+camera_launcher_on_hal_property_modified (LibHalContext *ctx,
+ const char *udi,
+ const char *key,
+ dbus_bool_t is_removed,
+ dbus_bool_t is_added)
+{
+ CLLauncherData *data = libhal_ctx_get_user_data (ctx);
+ gboolean state;
+ DesktopFileInfo *application;
+
+ g_return_if_fail (data);
+
+ if (strcmp (key, CAM_COVER_STATE) != 0)
+ return;
+
+ state = !libhal_device_get_property_bool (ctx, udi, key, NULL);
+
+ if (!strcmp (udi, CAM_COVER_UDI)) {
+ if (state) {
+ switch (data->action) {
+ case CL_LAUNCHER_ACTION_DO_NOTHING:
+ /* just only kill camera application if it's running */
+ kill_camera_application ();
+ break;
+
+ case CL_LAUNCHER_ACTION_RUN_PREFERED_APPLICATION:
+ /* kill camera application only if it's not selected as prefered */
+ if (strcmp (data->application, CAMERA_APPLICATION))
+ kill_camera_application ();
+
+ /* run prefered application */
+ application = get_desktop_file_info (data->application);
+ if (application) {
+ run_application (data, application);
+ g_free (application);
+ }
+ break;
+
+ case CL_LAUNCHER_ACTION_SHOW_SELECTOR_POPUP:
+ /* kill camera application if it's running */
+ kill_camera_application ();
+
+ /* create selector popup window */
+ launcher_popup_show (data);
+ break;
+ }
+ } else {
+ switch (data->action) {
+ case CL_LAUNCHER_ACTION_DO_NOTHING:
+ case CL_LAUNCHER_ACTION_RUN_PREFERED_APPLICATION:
+ /* do nothing */
+ break;
+
+ case CL_LAUNCHER_ACTION_SHOW_SELECTOR_POPUP:
+ /* destroy selector popup window */
+ launcher_popup_hide (data);
+ break;
+ }
+ }
+ } else if (!strcmp (udi, CAM_FOCUS_UDI)) {
+ if (state) {
+ /* run camera application when focus key was pressed */
+ application = get_desktop_file_info (CAMERA_APPLICATION);
+ if (application) {
+ run_application (data, application);
+ g_free (application);
+ }
+ }
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ CLLauncherData *data;
+ DBusConnection *dbus_connection;
+ LibHalContext *hal;
+ DBusError dbus_error;
+ GError *error = NULL;
+
+ hildon_gtk_init (&argc, &argv);
+
+ /* create CLLauncherData */
+ data = g_new0 (CLLauncherData, 1);
+ data->dialog = NULL;
+// data->action = CL_LAUNCHER_ACTION_RUN_PREFERED_APPLICATION;
+ data->action = CL_LAUNCHER_ACTION_SHOW_SELECTOR_POPUP;
+ data->application = g_strdup (CAMERA_APPLICATION);
+
+ /* initialize osso */
+ data->osso_context = osso_initialize (PACKAGE, VERSION, TRUE, NULL);
+
+ /* initialize gconf */
+ data->gconf_client = gconf_client_get_default ();
+ gconf_client_add_dir (data->gconf_client, GCONF_CL_LAUNCHER, GCONF_CLIENT_PRELOAD_ONELEVEL, &error);
+ if (error) {
+ g_warning ("camera-launcher: Unable to add GConf client, %s", error->message);
+ g_error_free (error);
+ error = NULL;
+ }
+
+ gconf_client_notify_add (data->gconf_client, GCONF_CL_LAUNCHER,
+ (GConfClientNotifyFunc) camera_launcher_on_gconf_changed, data, NULL, &error);
+ if (error) {
+ g_warning ("camera-launcher: Unable to add GConf client notification, %s", error->message);
+ g_error_free (error);
+ }
+
+ gconf_client_notify (data->gconf_client, GCONF_CL_LAUNCHER "/action");
+ gconf_client_notify (data->gconf_client, GCONF_CL_LAUNCHER "/application");
+
+ /* initialize dbus */
+ dbus_error_init (&dbus_error);
+ dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_error);
+ if (dbus_error_is_set (&dbus_error)) {
+ g_critical ("camera-launcher: Could not get the system DBus connection, %s",
+ dbus_error.message);
+ dbus_error_free (&dbus_error);
+ goto osso_error;
+ }
+
+ /* initialize hal */
+ hal = libhal_ctx_new ();
+ if (!hal) {
+ g_critical ("camera-launcher: Unable to create HAL context\n");
+ goto osso_error;
+ }
+
+ libhal_ctx_set_dbus_connection (hal, dbus_connection);
+ libhal_ctx_set_user_data (hal, data);
+ libhal_ctx_set_device_property_modified (hal, camera_launcher_on_hal_property_modified);
+
+ if (!libhal_ctx_init (hal, &dbus_error)) {
+ if (dbus_error_is_set (&dbus_error)) {
+ g_critical ("camera-launcher: Could not initialize the HAL context, %s",
+ dbus_error.message);
+ dbus_error_free (&dbus_error);
+ } else {
+ g_critical ("camera-launcher: Could not initialize the HAL context, "
+ "no error, is hald running?");
+ }
+ goto hal_error;
+ }
+
+ libhal_device_add_property_watch (hal, CAM_COVER_UDI, NULL);
+ libhal_device_add_property_watch (hal, CAM_FOCUS_UDI, NULL);
+
+ gtk_main ();
+
+ /* deinitialize hal */
+ if (hal) {
+ libhal_device_remove_property_watch (hal, CAM_COVER_UDI, NULL);
+ libhal_device_remove_property_watch (hal, CAM_FOCUS_UDI, NULL);
+hal_error:
+ libhal_ctx_set_user_data (hal, NULL);
+ libhal_ctx_shutdown (hal, NULL);
+ libhal_ctx_free (hal);
+ }
+
+osso_error:
+ /* deinitialize osso */
+ if (data->osso_context) {
+ osso_deinitialize (data->osso_context);
+ }
+
+ return 0;
+}