mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	
		
			
	
	
		
			312 lines
		
	
	
	
		
			9.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			312 lines
		
	
	
	
		
			9.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/* Spa Bluez5 UPower proxy
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Copyright © 2022 Collabora
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Permission is hereby granted, free of charge, to any person obtaining a
							 | 
						||
| 
								 | 
							
								 * copy of this software and associated documentation files (the "Software"),
							 | 
						||
| 
								 | 
							
								 * to deal in the Software without restriction, including without limitation
							 | 
						||
| 
								 | 
							
								 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
							 | 
						||
| 
								 | 
							
								 * and/or sell copies of the Software, and to permit persons to whom the
							 | 
						||
| 
								 | 
							
								 * Software is furnished to do so, subject to the following conditions:
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * The above copyright notice and this permission notice (including the next
							 | 
						||
| 
								 | 
							
								 * paragraph) shall be included in all copies or substantial portions of the
							 | 
						||
| 
								 | 
							
								 * Software.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
							 | 
						||
| 
								 | 
							
								 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
							 | 
						||
| 
								 | 
							
								 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
							 | 
						||
| 
								 | 
							
								 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
							 | 
						||
| 
								 | 
							
								 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
							 | 
						||
| 
								 | 
							
								 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
							 | 
						||
| 
								 | 
							
								 * DEALINGS IN THE SOFTWARE.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <errno.h>
							 | 
						||
| 
								 | 
							
								#include <spa/utils/string.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "upower.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define UPOWER_SERVICE "org.freedesktop.UPower"
							 | 
						||
| 
								 | 
							
								#define UPOWER_DEVICE_INTERFACE UPOWER_SERVICE ".Device"
							 | 
						||
| 
								 | 
							
								#define UPOWER_DISPLAY_DEVICE_OBJECT "/org/freedesktop/UPower/devices/DisplayDevice"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								struct impl {
							 | 
						||
| 
								 | 
							
									struct spa_bt_monitor *monitor;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									struct spa_log *log;
							 | 
						||
| 
								 | 
							
									DBusConnection *conn;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bool filters_added;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									void *user_data;
							 | 
						||
| 
								 | 
							
									void (*set_battery_level)(unsigned int level, void *user_data);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static DBusHandlerResult upower_parse_percentage(struct impl *this, DBusMessageIter *variant_i)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									double percentage;
							 | 
						||
| 
								 | 
							
									unsigned int battery_level;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									dbus_message_iter_get_basic(variant_i, &percentage);
							 | 
						||
| 
								 | 
							
									spa_log_debug(this->log, "Battery level: %f %%", percentage);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									battery_level = (unsigned int) round(percentage / 20.0);
							 | 
						||
| 
								 | 
							
									this->set_battery_level(battery_level, this->user_data);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return DBUS_HANDLER_RESULT_HANDLED;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void upower_get_percentage_properties_reply(DBusPendingCall *pending, void *user_data)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									struct impl *backend = user_data;
							 | 
						||
| 
								 | 
							
									DBusMessage *r;
							 | 
						||
| 
								 | 
							
									DBusMessageIter i, variant_i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									r = dbus_pending_call_steal_reply(pending);
							 | 
						||
| 
								 | 
							
									if (r == NULL)
							 | 
						||
| 
								 | 
							
										return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
							 | 
						||
| 
								 | 
							
										spa_log_error(backend->log, "Failed to get percentage from UPower: %s",
							 | 
						||
| 
								 | 
							
												dbus_message_get_error_name(r));
							 | 
						||
| 
								 | 
							
										goto finish;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (!dbus_message_iter_init(r, &i) || !spa_streq(dbus_message_get_signature(r), "v")) {
							 | 
						||
| 
								 | 
							
										spa_log_error(backend->log, "Invalid arguments in Get() reply");
							 | 
						||
| 
								 | 
							
										goto finish;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									dbus_message_iter_recurse(&i, &variant_i);
							 | 
						||
| 
								 | 
							
									upower_parse_percentage(backend, &variant_i);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								finish:
							 | 
						||
| 
								 | 
							
									dbus_message_unref(r);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void upower_clean(struct impl *this)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									this->set_battery_level(0, this->user_data);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static DBusHandlerResult upower_filter_cb(DBusConnection *bus, DBusMessage *m, void *user_data)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									struct impl *this = user_data;
							 | 
						||
| 
								 | 
							
									DBusError err;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									dbus_error_init(&err);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (dbus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged")) {
							 | 
						||
| 
								 | 
							
										const char *name, *old_owner, *new_owner;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										spa_log_debug(this->log, "Name owner changed %s", dbus_message_get_path(m));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (!dbus_message_get_args(m, &err,
							 | 
						||
| 
								 | 
							
													   DBUS_TYPE_STRING, &name,
							 | 
						||
| 
								 | 
							
													   DBUS_TYPE_STRING, &old_owner,
							 | 
						||
| 
								 | 
							
													   DBUS_TYPE_STRING, &new_owner,
							 | 
						||
| 
								 | 
							
													   DBUS_TYPE_INVALID)) {
							 | 
						||
| 
								 | 
							
											spa_log_error(this->log, "Failed to parse org.freedesktop.DBus.NameOwnerChanged: %s", err.message);
							 | 
						||
| 
								 | 
							
											goto finish;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (spa_streq(name, UPOWER_SERVICE)) {
							 | 
						||
| 
								 | 
							
											if (old_owner && *old_owner) {
							 | 
						||
| 
								 | 
							
												spa_log_debug(this->log, "UPower daemon disappeared (%s)", old_owner);
							 | 
						||
| 
								 | 
							
												upower_clean(this);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if (new_owner && *new_owner) {
							 | 
						||
| 
								 | 
							
												DBusPendingCall *call;
							 | 
						||
| 
								 | 
							
												static const char* upower_device_interface = UPOWER_DEVICE_INTERFACE;
							 | 
						||
| 
								 | 
							
												static const char* percentage_property = "Percentage";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												spa_log_debug(this->log, "UPower daemon appeared (%s)", new_owner);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												m = dbus_message_new_method_call(UPOWER_SERVICE, UPOWER_DISPLAY_DEVICE_OBJECT, DBUS_INTERFACE_PROPERTIES, "Get");
							 | 
						||
| 
								 | 
							
												if (m == NULL)
							 | 
						||
| 
								 | 
							
													goto finish;
							 | 
						||
| 
								 | 
							
												dbus_message_append_args(m, DBUS_TYPE_STRING, &upower_device_interface,
							 | 
						||
| 
								 | 
							
														         DBUS_TYPE_STRING, &percentage_property, DBUS_TYPE_INVALID);
							 | 
						||
| 
								 | 
							
												dbus_connection_send_with_reply(this->conn, m, &call, -1);
							 | 
						||
| 
								 | 
							
												dbus_pending_call_set_notify(call, upower_get_percentage_properties_reply, this, NULL);
							 | 
						||
| 
								 | 
							
												dbus_message_unref(m);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									} else if (dbus_message_is_signal(m, DBUS_INTERFACE_PROPERTIES, DBUS_SIGNAL_PROPERTIES_CHANGED)) {
							 | 
						||
| 
								 | 
							
										const char *path;
							 | 
						||
| 
								 | 
							
										DBusMessageIter iface_i, props_i;
							 | 
						||
| 
								 | 
							
										const char *interface;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (!dbus_message_iter_init(m, &iface_i) || !spa_streq(dbus_message_get_signature(m), "sa{sv}as")) {
							 | 
						||
| 
								 | 
							
												spa_log_error(this->log, "Invalid signature found in PropertiesChanged");
							 | 
						||
| 
								 | 
							
												goto finish;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										dbus_message_iter_get_basic(&iface_i, &interface);
							 | 
						||
| 
								 | 
							
										dbus_message_iter_next(&iface_i);
							 | 
						||
| 
								 | 
							
										spa_assert(dbus_message_iter_get_arg_type(&iface_i) == DBUS_TYPE_ARRAY);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										dbus_message_iter_recurse(&iface_i, &props_i);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										path = dbus_message_get_path(m);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (spa_streq(interface, UPOWER_DEVICE_INTERFACE)) {
							 | 
						||
| 
								 | 
							
											spa_log_debug(this->log, "Properties changed on %s", path);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											while (dbus_message_iter_get_arg_type(&props_i) != DBUS_TYPE_INVALID) {
							 | 
						||
| 
								 | 
							
												DBusMessageIter i, value_i;
							 | 
						||
| 
								 | 
							
												const char *key;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												dbus_message_iter_recurse(&props_i, &i);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												dbus_message_iter_get_basic(&i, &key);
							 | 
						||
| 
								 | 
							
												dbus_message_iter_next(&i);
							 | 
						||
| 
								 | 
							
												dbus_message_iter_recurse(&i, &value_i);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if(spa_streq(key, "Percentage"))
							 | 
						||
| 
								 | 
							
													upower_parse_percentage(this, &value_i);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												dbus_message_iter_next(&props_i);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								finish:
							 | 
						||
| 
								 | 
							
									return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int add_filters(struct impl *this)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									DBusError err;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (this->filters_added)
							 | 
						||
| 
								 | 
							
										return 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									dbus_error_init(&err);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (!dbus_connection_add_filter(this->conn, upower_filter_cb, this, NULL)) {
							 | 
						||
| 
								 | 
							
										spa_log_error(this->log, "failed to add filter function");
							 | 
						||
| 
								 | 
							
										goto fail;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									dbus_bus_add_match(this->conn,
							 | 
						||
| 
								 | 
							
											"type='signal',sender='org.freedesktop.DBus',"
							 | 
						||
| 
								 | 
							
											"interface='org.freedesktop.DBus',member='NameOwnerChanged'," "arg0='" UPOWER_SERVICE "'", &err);
							 | 
						||
| 
								 | 
							
									dbus_bus_add_match(this->conn,
							 | 
						||
| 
								 | 
							
											"type='signal',sender='" UPOWER_SERVICE "',"
							 | 
						||
| 
								 | 
							
											"interface='" DBUS_INTERFACE_PROPERTIES "',member='" DBUS_SIGNAL_PROPERTIES_CHANGED "',"
							 | 
						||
| 
								 | 
							
											"path='" UPOWER_DISPLAY_DEVICE_OBJECT "',arg0='" UPOWER_DEVICE_INTERFACE "'", &err);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									this->filters_added = true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fail:
							 | 
						||
| 
								 | 
							
									dbus_error_free(&err);
							 | 
						||
| 
								 | 
							
									return -EIO;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static bool is_dbus_service_available(struct impl *this, const char *service)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									DBusMessage *m, *r;
							 | 
						||
| 
								 | 
							
									DBusError err;
							 | 
						||
| 
								 | 
							
									bool success = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									m = dbus_message_new_method_call("org.freedesktop.DBus", "/org/freedesktop/DBus",
							 | 
						||
| 
								 | 
							
									                                  "org.freedesktop.DBus", "NameHasOwner");
							 | 
						||
| 
								 | 
							
									if (m == NULL)
							 | 
						||
| 
								 | 
							
										return false;
							 | 
						||
| 
								 | 
							
									dbus_message_append_args(m, DBUS_TYPE_STRING, &service, DBUS_TYPE_INVALID);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									dbus_error_init(&err);
							 | 
						||
| 
								 | 
							
									r = dbus_connection_send_with_reply_and_block(this->conn, m, -1, &err);
							 | 
						||
| 
								 | 
							
									dbus_message_unref(m);
							 | 
						||
| 
								 | 
							
									m = NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (r == NULL) {
							 | 
						||
| 
								 | 
							
										spa_log_info(this->log, "NameHasOwner failed for %s", service);
							 | 
						||
| 
								 | 
							
										dbus_error_free(&err);
							 | 
						||
| 
								 | 
							
										goto finish;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
							 | 
						||
| 
								 | 
							
										spa_log_error(this->log, "NameHasOwner() returned error: %s", dbus_message_get_error_name(r));
							 | 
						||
| 
								 | 
							
										goto finish;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (!dbus_message_get_args(r, &err,
							 | 
						||
| 
								 | 
							
												   DBUS_TYPE_BOOLEAN, &success,
							 | 
						||
| 
								 | 
							
												   DBUS_TYPE_INVALID)) {
							 | 
						||
| 
								 | 
							
										spa_log_error(this->log, "Failed to parse NameHasOwner() reply: %s", err.message);
							 | 
						||
| 
								 | 
							
										dbus_error_free(&err);
							 | 
						||
| 
								 | 
							
										goto finish;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								finish:
							 | 
						||
| 
								 | 
							
									if (r)
							 | 
						||
| 
								 | 
							
										dbus_message_unref(r);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return success;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void *upower_register(struct spa_log *log,
							 | 
						||
| 
								 | 
							
								                      void *dbus_connection,
							 | 
						||
| 
								 | 
							
								                      void (*set_battery_level)(unsigned int level, void *user_data),
							 | 
						||
| 
								 | 
							
								                      void *user_data)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									struct impl *this;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									spa_assert(log);
							 | 
						||
| 
								 | 
							
									spa_assert(dbus_connection);
							 | 
						||
| 
								 | 
							
									spa_assert(set_battery_level);
							 | 
						||
| 
								 | 
							
									spa_assert(user_data);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									this = calloc(1, sizeof(struct impl));
							 | 
						||
| 
								 | 
							
									if (this == NULL)
							 | 
						||
| 
								 | 
							
										return NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									this->log = log;
							 | 
						||
| 
								 | 
							
									this->conn = dbus_connection;
							 | 
						||
| 
								 | 
							
									this->set_battery_level = set_battery_level;
							 | 
						||
| 
								 | 
							
								    this->user_data = user_data;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (add_filters(this) < 0) {
							 | 
						||
| 
								 | 
							
										goto fail4;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (is_dbus_service_available(this, UPOWER_SERVICE)) {
							 | 
						||
| 
								 | 
							
										DBusMessage *m;
							 | 
						||
| 
								 | 
							
										DBusPendingCall *call;
							 | 
						||
| 
								 | 
							
										static const char* upower_device_interface = UPOWER_DEVICE_INTERFACE;
							 | 
						||
| 
								 | 
							
										static const char* percentage_property = "Percentage";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										m = dbus_message_new_method_call(UPOWER_SERVICE, UPOWER_DISPLAY_DEVICE_OBJECT, DBUS_INTERFACE_PROPERTIES, "Get");
							 | 
						||
| 
								 | 
							
										if (m == NULL)
							 | 
						||
| 
								 | 
							
											goto fail4;
							 | 
						||
| 
								 | 
							
										dbus_message_append_args(m, DBUS_TYPE_STRING, &upower_device_interface,
							 | 
						||
| 
								 | 
							
										                         DBUS_TYPE_STRING, &percentage_property, DBUS_TYPE_INVALID);
							 | 
						||
| 
								 | 
							
										dbus_connection_send_with_reply(this->conn, m, &call, -1);
							 | 
						||
| 
								 | 
							
										dbus_pending_call_set_notify(call, upower_get_percentage_properties_reply, this, NULL);
							 | 
						||
| 
								 | 
							
										dbus_message_unref(m);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return this;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fail4:
							 | 
						||
| 
								 | 
							
								    free(this);
							 | 
						||
| 
								 | 
							
								    return NULL;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void upower_unregister(void *data)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									struct impl *this = data;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (this->filters_added) {
							 | 
						||
| 
								 | 
							
										dbus_connection_remove_filter(this->conn, upower_filter_cb, this);
							 | 
						||
| 
								 | 
							
										this->filters_added = false;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									free(this);
							 | 
						||
| 
								 | 
							
								}
							 |