/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2007-2008 Richard Hughes <richard@hughsie.com> * * Licensed under the GNU General Public License Version 2 * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include <string.h> #include <glib.h> #include <glib/gi18n.h> #include <dbus/dbus-glib.h> #include "gpm-phone.h" #include "egg-debug.h" #include "gpm-marshal.h" #include "egg-dbus-monitor.h" static void gpm_phone_finalize (GObject *object); #define GPM_PHONE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPM_TYPE_PHONE, GpmPhonePrivate)) struct GpmPhonePrivate { DBusGProxy *proxy; DBusGConnection *connection; EggDbusMonitor *monitor; gboolean present; guint percentage; gboolean onac; }; enum { DEVICE_ADDED, DEVICE_REMOVED, DEVICE_REFRESH, LAST_SIGNAL }; static guint signals [LAST_SIGNAL] = { 0 }; static gpointer gpm_phone_object = NULL; G_DEFINE_TYPE (GpmPhone, gpm_phone, G_TYPE_OBJECT) /** * gpm_phone_coldplug: * Return value: Success value, or zero for failure **/ gboolean gpm_phone_coldplug (GpmPhone *phone) { GError *error = NULL; gboolean ret; g_return_val_if_fail (phone != NULL, FALSE); g_return_val_if_fail (GPM_IS_PHONE (phone), FALSE); if (phone->priv->proxy == NULL) { egg_warning ("not connected"); return FALSE; } ret = dbus_g_proxy_call (phone->priv->proxy, "Coldplug", &error, G_TYPE_INVALID, G_TYPE_INVALID); if (error != NULL) { egg_warning ("DEBUG: ERROR: %s", error->message); g_error_free (error); } return ret; } /** * gpm_phone_coldplug: * Return value: if present **/ gboolean gpm_phone_get_present (GpmPhone *phone, guint idx) { g_return_val_if_fail (phone != NULL, FALSE); g_return_val_if_fail (GPM_IS_PHONE (phone), FALSE); return phone->priv->present; } /** * gpm_phone_coldplug: * Return value: if present **/ guint gpm_phone_get_percentage (GpmPhone *phone, guint idx) { g_return_val_if_fail (phone != NULL, 0); g_return_val_if_fail (GPM_IS_PHONE (phone), 0); return phone->priv->percentage; } /** * gpm_phone_coldplug: * Return value: if present **/ gboolean gpm_phone_get_on_ac (GpmPhone *phone, guint idx) { g_return_val_if_fail (phone != NULL, FALSE); g_return_val_if_fail (GPM_IS_PHONE (phone), FALSE); return phone->priv->onac; } /** * gpm_phone_get_num_batteries: * Return value: number of phone batteries monitored **/ guint gpm_phone_get_num_batteries (GpmPhone *phone) { g_return_val_if_fail (phone != NULL, 0); g_return_val_if_fail (GPM_IS_PHONE (phone), 0); if (phone->priv->present) { return 1; } return 0; } /** Invoked when we get the BatteryStateChanged */ static void gpm_phone_battery_state_changed (DBusGProxy *proxy, guint idx, guint percentage, gboolean on_ac, GpmPhone *phone) { g_return_if_fail (GPM_IS_PHONE (phone)); egg_debug ("got BatteryStateChanged %i = %i (%i)", idx, percentage, on_ac); phone->priv->percentage = percentage; phone->priv->onac = on_ac; phone->priv->present = TRUE; egg_debug ("emitting device-refresh : (%i)", idx); g_signal_emit (phone, signals [DEVICE_REFRESH], 0, idx); } /** Invoked when we get NumberBatteriesChanged */ static void gpm_phone_num_batteries_changed (DBusGProxy *proxy, guint number, GpmPhone *phone) { g_return_if_fail (GPM_IS_PHONE (phone)); egg_debug ("got NumberBatteriesChanged %i", number); if (number > 1) { egg_warning ("number not 0 or 1, not valid!"); return; } /* are we removed? */ if (number == 0) { phone->priv->present = FALSE; phone->priv->percentage = 0; phone->priv->onac = FALSE; egg_debug ("emitting device-removed : (%i)", 0); g_signal_emit (phone, signals [DEVICE_REMOVED], 0, 0); return; } if (phone->priv->present) { egg_warning ("duplicate NumberBatteriesChanged with no change"); return; } /* reset to defaults until we get BatteryStateChanged */ phone->priv->present = TRUE; phone->priv->percentage = 0; phone->priv->onac = FALSE; egg_debug ("emitting device-added : (%i)", 0); g_signal_emit (phone, signals [DEVICE_ADDED], 0, 0); } /** * gpm_phone_class_init: * @klass: This class instance **/ static void gpm_phone_class_init (GpmPhoneClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gpm_phone_finalize; g_type_class_add_private (klass, sizeof (GpmPhonePrivate)); signals [DEVICE_ADDED] = g_signal_new ("device-added", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GpmPhoneClass, device_added), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals [DEVICE_REMOVED] = g_signal_new ("device-removed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GpmPhoneClass, device_removed), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals [DEVICE_REFRESH] = g_signal_new ("device-refresh", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GpmPhoneClass, device_refresh), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); } /** * gpm_phone_dbus_connect: **/ static gboolean gpm_phone_dbus_connect (GpmPhone *phone) { GError *error = NULL; g_return_val_if_fail (phone != NULL, FALSE); g_return_val_if_fail (GPM_IS_PHONE (phone), FALSE); if (phone->priv->connection == NULL) { egg_debug ("get connection"); g_clear_error (&error); phone->priv->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); if (error != NULL) { egg_warning ("Could not connect to DBUS daemon: %s", error->message); g_error_free (error); phone->priv->connection = NULL; return FALSE; } } if (phone->priv->proxy == NULL) { egg_debug ("get proxy"); g_clear_error (&error); phone->priv->proxy = dbus_g_proxy_new_for_name_owner (phone->priv->connection, MATE_PHONE_MANAGER_DBUS_SERVICE, MATE_PHONE_MANAGER_DBUS_PATH, MATE_PHONE_MANAGER_DBUS_INTERFACE, &error); if (error != NULL) { egg_warning ("Cannot connect, maybe the daemon is not running: %s", error->message); g_error_free (error); phone->priv->proxy = NULL; return FALSE; } /* complicated type. ick */ dbus_g_object_register_marshaller(gpm_marshal_VOID__UINT_UINT_BOOLEAN, G_TYPE_NONE, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_BOOLEAN, G_TYPE_INVALID); /* get BatteryStateChanged */ dbus_g_proxy_add_signal (phone->priv->proxy, "BatteryStateChanged", G_TYPE_UINT, G_TYPE_UINT, G_TYPE_BOOLEAN, G_TYPE_INVALID); dbus_g_proxy_connect_signal (phone->priv->proxy, "BatteryStateChanged", G_CALLBACK (gpm_phone_battery_state_changed), phone, NULL); /* get NumberBatteriesChanged */ dbus_g_proxy_add_signal (phone->priv->proxy, "NumberBatteriesChanged", G_TYPE_UINT, G_TYPE_INVALID); dbus_g_proxy_connect_signal (phone->priv->proxy, "NumberBatteriesChanged", G_CALLBACK (gpm_phone_num_batteries_changed), phone, NULL); } return TRUE; } /** * gpm_phone_dbus_disconnect: **/ static gboolean gpm_phone_dbus_disconnect (GpmPhone *phone) { g_return_val_if_fail (phone != NULL, FALSE); g_return_val_if_fail (GPM_IS_PHONE (phone), FALSE); if (phone->priv->proxy != NULL) { egg_debug ("removing proxy"); g_object_unref (phone->priv->proxy); phone->priv->proxy = NULL; if (phone->priv->present) { phone->priv->present = FALSE; phone->priv->percentage = 0; egg_debug ("emitting device-removed : (%i)", 0); g_signal_emit (phone, signals [DEVICE_REMOVED], 0, 0); } } return TRUE; } /** * monitor_connection_cb: * @proxy: The dbus raw proxy * @status: The status of the service, where TRUE is connected * @screensaver: This class instance **/ static void monitor_connection_cb (EggDbusMonitor *monitor, gboolean status, GpmPhone *phone) { if (status) gpm_phone_dbus_connect (phone); else gpm_phone_dbus_disconnect (phone); } /** * gpm_phone_init: * @phone: This class instance **/ static void gpm_phone_init (GpmPhone *phone) { DBusGConnection *connection; phone->priv = GPM_PHONE_GET_PRIVATE (phone); phone->priv->connection = NULL; phone->priv->proxy = NULL; phone->priv->present = FALSE; phone->priv->percentage = 0; phone->priv->onac = FALSE; phone->priv->monitor = egg_dbus_monitor_new (); g_signal_connect (phone->priv->monitor, "connection-changed", G_CALLBACK (monitor_connection_cb), phone); connection = dbus_g_bus_get (DBUS_BUS_SESSION, NULL); egg_dbus_monitor_assign (phone->priv->monitor, connection, MATE_PHONE_MANAGER_DBUS_SERVICE); gpm_phone_dbus_connect (phone); } /** * gpm_phone_finalize: * @object: This class instance **/ static void gpm_phone_finalize (GObject *object) { GpmPhone *phone; g_return_if_fail (object != NULL); g_return_if_fail (GPM_IS_PHONE (object)); phone = GPM_PHONE (object); phone->priv = GPM_PHONE_GET_PRIVATE (phone); gpm_phone_dbus_disconnect (phone); if (phone->priv->monitor != NULL) g_object_unref (phone->priv->monitor); G_OBJECT_CLASS (gpm_phone_parent_class)->finalize (object); } /** * gpm_phone_new: * Return value: new GpmPhone instance. **/ GpmPhone * gpm_phone_new (void) { if (gpm_phone_object != NULL) { g_object_ref (gpm_phone_object); } else { gpm_phone_object = g_object_new (GPM_TYPE_PHONE, NULL); g_object_add_weak_pointer (gpm_phone_object, &gpm_phone_object); } return GPM_PHONE (gpm_phone_object); } /*************************************************************************** *** MAKE CHECK TESTS *** ***************************************************************************/ #ifdef EGG_TEST #include "egg-test.h" static gboolean test_got_refresh = FALSE; static void egg_test_mainloop_wait (guint ms) { GMainLoop *loop; loop = g_main_loop_new (NULL, FALSE); g_timeout_add (ms, (GSourceFunc) g_main_loop_quit, loop); g_main_loop_run (loop); } static void phone_device_refresh_cb (GpmPhone *phone, guint idx, gpointer *data) { g_debug ("idx refresh = %i", idx); if (idx == 0 && GPOINTER_TO_UINT (data) == 44) test_got_refresh = TRUE; } void gpm_phone_test (gpointer data) { GpmPhone *phone; guint value; gboolean ret; EggTest *test = (EggTest *) data; if (egg_test_start (test, "GpmPhone") == FALSE) return; /************************************************************/ egg_test_title (test, "make sure we get a non null phone"); phone = gpm_phone_new (); if (phone != NULL) egg_test_success (test, "got GpmPhone"); else egg_test_failed (test, "could not get GpmPhone"); /* connect signals */ g_signal_connect (phone, "device-refresh", G_CALLBACK (phone_device_refresh_cb), GUINT_TO_POINTER(44)); /************************************************************/ egg_test_title (test, "make sure we got a connection"); if (phone->priv->proxy != NULL) { egg_test_success (test, "got connection"); } else { /* skip this part of the test */ egg_test_success (test, "could not get a connection!"); goto out; } /************************************************************/ egg_test_title (test, "coldplug the data"); ret = gpm_phone_coldplug (phone); if (ret) { egg_test_success (test, "coldplug okay"); } else { egg_test_failed (test, "could not coldplug"); } egg_test_mainloop_wait (500); /************************************************************/ egg_test_title (test, "got refresh"); if (test_got_refresh) { egg_test_success (test, NULL); } else { egg_test_failed (test, "did not get refresh"); } /************************************************************/ egg_test_title (test, "check the connected phones"); value = gpm_phone_get_num_batteries (phone); if (value == 1) { egg_test_success (test, "connected phone"); } else { egg_test_failed (test, "not connected with %i (phone not connected?)", value); } /************************************************************/ egg_test_title (test, "check the present value"); ret = gpm_phone_get_present (phone, 0); if (ret) { egg_test_success (test, "we are here!"); } else { egg_test_failed (test, "not here..."); } /************************************************************/ egg_test_title (test, "check the percentage"); value = gpm_phone_get_percentage (phone, 0); if (value != 0) { egg_test_success (test, "percentage is %i", phone->priv->percentage); } else { egg_test_failed (test, "could not get value"); } /************************************************************/ egg_test_title (test, "check the ac value"); ret = gpm_phone_get_on_ac (phone, 0); if (!ret) { egg_test_success (test, "not charging, correct"); } else { egg_test_failed (test, "charging?"); } out: g_object_unref (phone); egg_test_end (test); } #endif