Imported version 0.1
[cl-launcher] / src / cl-launcher.c
diff --git a/src/cl-launcher.c b/src/cl-launcher.c
new file mode 100644 (file)
index 0000000..4d735bc
--- /dev/null
@@ -0,0 +1,443 @@
+/*
+ *  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;
+}