Files
libmce-glib/src/mce_proxy.c
2023-09-21 04:17:10 +02:00

342 lines
9.3 KiB
C

/*
* Copyright (C) 2016-2022 Jolla Ltd.
* Copyright (C) 2016-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#include "mce_proxy.h"
#include "mce_log_p.h"
/* Generated headers */
#include "com.canonical.Unity.Screen.h"
#include "org.ayatana.indicator.power.Battery.h"
GLOG_MODULE_DEFINE("mce");
struct mce_proxy_priv {
GDBusConnection* bus;
GDBusConnection* session_bus;
guint mce_watch_id;
guint ayatana_watch_id;
gboolean unity_valid;
gboolean ayatana_valid;
};
enum mce_proxy_signal {
SIGNAL_VALID_CHANGED,
SIGNAL_COUNT
};
#define SIGNAL_VALID_CHANGED_NAME "mce-proxy-valid-changed"
#define MCE_SERVICE "com.canonical.Unity.Screen"
#define MCE_REQUEST_PATH "/com/canonical/Unity/Screen"
#define AYATANA_SERVICE "org.ayatana.indicator.power"
#define AYATANA_REQUEST_PATH "/org/ayatana/indicator/power/Battery"
static guint mce_proxy_signals[SIGNAL_COUNT] = { 0 };
typedef GObjectClass MceProxyClass;
GType mce_proxy_get_type() MCE_INTERNAL;
G_DEFINE_TYPE(MceProxy, mce_proxy, G_TYPE_OBJECT)
#define PARENT_CLASS mce_proxy_parent_class
#define MCE_PROXY_TYPE (mce_proxy_get_type())
#define MCE_PROXY(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj,\
MCE_PROXY_TYPE,MceProxy))
static
void
mce_name_appeared(
GDBusConnection* bus,
const gchar* name,
const gchar* owner,
gpointer arg)
{
MceProxy* self = MCE_PROXY(arg);
GDEBUG("Name '%s' is owned by %s", name, owner);
GASSERT(!self->valid);
self->valid = TRUE;
g_signal_emit(self, mce_proxy_signals[SIGNAL_VALID_CHANGED], 0);
}
static
void
mce_name_vanished(
GDBusConnection* bus,
const gchar* name,
gpointer arg)
{
MceProxy* self = MCE_PROXY(arg);
GDEBUG("Name '%s' has disappeared", name);
if (self->valid) {
self->valid = FALSE;
g_signal_emit(self, mce_proxy_signals[SIGNAL_VALID_CHANGED], 0);
}
}
static
void
mce_proxy_init_check(
MceProxy* self)
{
MceProxyPriv* priv = self->priv;
if ( self->unity_request && !priv->mce_watch_id) {
priv->mce_watch_id = g_bus_watch_name_on_connection(priv->bus,
MCE_SERVICE, G_BUS_NAME_WATCHER_FLAGS_NONE,
mce_name_appeared, mce_name_vanished, self, NULL);
}
if (self->ayatana_request && !priv->ayatana_watch_id) {
priv->ayatana_watch_id = g_bus_watch_name_on_connection(priv->session_bus,
AYATANA_SERVICE, G_BUS_NAME_WATCHER_FLAGS_NONE,
mce_name_appeared, mce_name_vanished, self, NULL);
}
}
static
void
mce_proxy_request_proxy_new_finished(
GObject* object,
GAsyncResult* result,
gpointer arg)
{
MceProxy* self = MCE_PROXY(arg);
GError* error = NULL;
GASSERT(!self->unity_request);
self->unity_request = com_canonical_unity_screen_proxy_new_finish(result, &error);
if (self->unity_request) {
mce_proxy_init_check(self);
} else {
GERR("Failed to initialize MCE request proxy: %s", GERRMSG(error));
g_error_free(error);
}
mce_proxy_unref(self);
}
static
void
mce_proxy_request_proxy_session_new_finished(
GObject* object,
GAsyncResult* result,
gpointer arg)
{
MceProxy* self = MCE_PROXY(arg);
GError* error = NULL;
GASSERT(!self->ayatana_request);
self->ayatana_request = org_ayatana_indicator_power_battery_proxy_new_finish(result, &error);
if (self->ayatana_request) {
mce_proxy_init_check(self);
} else {
GERR("Failed to initialize MCE ayatana request proxy: %s", GERRMSG(error));
g_error_free(error);
}
mce_proxy_unref(self);
}
static
void
mce_proxy_bus_get_finished(
GObject* object,
GAsyncResult* result,
gpointer arg)
{
MceProxy* self = MCE_PROXY(arg);
MceProxyPriv* priv = self->priv;
GError* error = NULL;
priv->bus = g_bus_get_finish(result, &error);
if (priv->bus) {
com_canonical_unity_screen_proxy_new(priv->bus,
G_DBUS_PROXY_FLAGS_NONE,
MCE_SERVICE, MCE_REQUEST_PATH, NULL,
mce_proxy_request_proxy_new_finished,
mce_proxy_ref(self));
} else {
GERR("Failed to attach to system bus: %s", GERRMSG(error));
g_error_free(error);
}
mce_proxy_unref(self);
}
static
void
mce_proxy_session_bus_get_finished(
GObject* object,
GAsyncResult* result,
gpointer arg)
{
MceProxy* self = MCE_PROXY(arg);
MceProxyPriv* priv = self->priv;
GError* error = NULL;
priv->session_bus = g_bus_get_finish(result, &error);
if (priv->session_bus) {
org_ayatana_indicator_power_battery_proxy_new(priv->session_bus,
G_DBUS_PROXY_FLAGS_NONE,
AYATANA_SERVICE, AYATANA_REQUEST_PATH, NULL,
mce_proxy_request_proxy_session_new_finished,
mce_proxy_ref(self));
} else{
GERR("Failed to attach to session bus: %s", GERRMSG(error));
g_error_free(error);
}
mce_proxy_unref(self);
}
MceProxy*
mce_proxy_new()
{
/*
* Since there's only one mce in the system, there's no need for
* more than one proxy object.
*/
static MceProxy* mce_proxy_instance = NULL;
if (mce_proxy_instance) {
mce_proxy_ref(mce_proxy_instance);
} else {
mce_proxy_instance = g_object_new(MCE_PROXY_TYPE, NULL);
g_bus_get(G_BUS_TYPE_SYSTEM, NULL, mce_proxy_bus_get_finished,
mce_proxy_ref(mce_proxy_instance));
g_bus_get(G_BUS_TYPE_SESSION, NULL, mce_proxy_session_bus_get_finished,
mce_proxy_ref(mce_proxy_instance));
g_object_add_weak_pointer(G_OBJECT(mce_proxy_instance),
(gpointer*)(&mce_proxy_instance));
}
return mce_proxy_instance;
}
MceProxy*
mce_proxy_ref(
MceProxy* self)
{
if (G_LIKELY(self)) {
g_object_ref(MCE_PROXY(self));
}
return self;
}
void
mce_proxy_unref(
MceProxy* self)
{
if (G_LIKELY(self)) {
g_object_unref(MCE_PROXY(self));
}
}
gulong
mce_proxy_add_valid_changed_handler(
MceProxy* self,
MceProxyFunc fn,
void* arg)
{
return (G_LIKELY(self) && G_LIKELY(fn)) ? g_signal_connect(self,
SIGNAL_VALID_CHANGED_NAME, G_CALLBACK(fn), arg) : 0;
}
void
mce_proxy_remove_handler(
MceProxy* self,
gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
g_signal_handler_disconnect(self, id);
}
}
static
void
mce_proxy_init(
MceProxy* self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
MCE_PROXY_TYPE, MceProxyPriv);
}
static
void
mce_proxy_finalize(
GObject* object)
{
MceProxy* self = MCE_PROXY(object);
MceProxyPriv* priv = self->priv;
if (priv->mce_watch_id) {
g_bus_unwatch_name(priv->mce_watch_id);
}
if (priv->ayatana_watch_id) {
g_bus_unwatch_name(priv->ayatana_watch_id);
}
if (self->unity_request) {
g_object_unref(self->unity_request);
}
if (self->ayatana_request) {
g_object_unref(self->ayatana_request);
}
if (priv->bus) {
g_object_unref(priv->bus);
}
if (priv->session_bus) {
g_object_unref(priv->session_bus);
}
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
}
static
void
mce_proxy_class_init(
MceProxyClass* klass)
{
GObjectClass* object_class = G_OBJECT_CLASS(klass);
object_class->finalize = mce_proxy_finalize;
g_type_class_add_private(klass, sizeof(MceProxyPriv));
mce_proxy_signals[SIGNAL_VALID_CHANGED] =
g_signal_new(SIGNAL_VALID_CHANGED_NAME,
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/