From: Vibhav Pant vibhavp@gmail.com
When the unix bluez watcher receives a PropertiesChanged signal for a org.bluez.Device1 object, queue a BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_PROPERTIES_CHANGED event, containing the changed and invalidated properties for the associated remote device. --- dlls/winebth.sys/dbus.c | 141 ++++++++++++++++++++++++++++++++ dlls/winebth.sys/winebth.c | 46 +++++++++++ dlls/winebth.sys/winebth_priv.h | 13 ++- 3 files changed, 199 insertions(+), 1 deletion(-)
diff --git a/dlls/winebth.sys/dbus.c b/dlls/winebth.sys/dbus.c index 872e6fa83bf..153c4e60ad1 100644 --- a/dlls/winebth.sys/dbus.c +++ b/dlls/winebth.sys/dbus.c @@ -608,6 +608,29 @@ static NTSTATUS bluez_adapter_get_props_async( void *connection, const char *rad return STATUS_SUCCESS; }
+static NTSTATUS bluez_device_get_props_by_path_async( DBusConnection *connection, + const char *device_path, + DBusPendingCall **pending_call ) +{ + DBusMessage *request; + static const char *adapter_iface = BLUEZ_INTERFACE_DEVICE; + dbus_bool_t ret; + + request = p_dbus_message_new_method_call( BLUEZ_DEST, device_path, + DBUS_INTERFACE_PROPERTIES, "GetAll" ); + if (!request) return STATUS_NO_MEMORY; + + p_dbus_message_append_args( request, DBUS_TYPE_STRING, &adapter_iface, DBUS_TYPE_INVALID ); + ret = p_dbus_connection_send_with_reply( connection, request, pending_call, bluez_timeout ); + p_dbus_message_unref( request ); + if (!ret) + return STATUS_NO_MEMORY; + if (!*pending_call) + return STATUS_INTERNAL_ERROR; + + return STATUS_SUCCESS; +} + struct bluez_watcher_ctx { void *init_device_list_call; @@ -744,6 +767,42 @@ static void bluez_filter_radio_props_changed_callback( DBusPendingCall *call, vo p_dbus_message_unref( reply ); }
+static void bluez_filter_device_props_changed_callback( DBusPendingCall *call, void *user_data ) +{ + union winebluetooth_watcher_event_data *event = user_data; + struct winebluetooth_watcher_event_device_props_changed *changed = &event->device_props_changed; + const struct unix_name *device = (struct unix_name *)event->device_props_changed.device.handle; + DBusMessage *reply; + DBusMessageIter dict, prop_iter, variant; + const char *prop_name; + DBusError error; + + TRACE( "call %p, device %s\n", call, debugstr_a( device->str ) ); + + reply = p_dbus_pending_call_steal_reply( call ); + p_dbus_error_init( &error ); + if (p_dbus_set_error_from_message( &error, reply )) + { + ERR( "Failed to get device properties for %s: %s: %s\n", debugstr_a( device->str ), debugstr_a( error.name ), + debugstr_a( error.message ) ); + p_dbus_error_free( &error ); + p_dbus_message_unref( reply ); + return; + } + p_dbus_error_free( &error ); + + p_dbus_message_iter_init( reply, &dict ); + p_dbus_message_iter_recurse( &dict, &prop_iter ); + while((prop_name = bluez_next_dict_entry( &prop_iter, &variant ))) + { + bluez_device_prop_from_dict_entry( prop_name, &variant, &changed->props, + &changed->changed_props_mask, + changed->invalid_props_mask ); + } + changed->invalid_props_mask &= ~changed->changed_props_mask; + p_dbus_message_unref( reply ); +} + struct bluez_object_property_masks { const char *prop_name; @@ -1051,6 +1110,85 @@ static DBusHandlerResult bluez_filter( DBusConnection *conn, DBusMessage *msg, v } } } + else if (strcmp( iface, BLUEZ_INTERFACE_DEVICE ) == 0) + { + struct winebluetooth_watcher_event_device_props_changed props_changed = {0}; + struct unix_name *device; + const char *prop_name, *object_path; + union winebluetooth_watcher_event_data event; + DBusMessageIter changed_props_iter, invalid_props_iter, variant; + const static struct bluez_object_property_masks device_prop_masks[] = { + { "Name", WINEBLUETOOTH_DEVICE_PROPERTY_NAME }, + { "Address", WINEBLUETOOTH_DEVICE_PROPERTY_ADDRESS }, + { "Connected", WINEBLUETOOTH_DEVICE_PROPERTY_CONNECTED }, + { "Paired", WINEBLUETOOTH_DEVICE_PROPERTY_PAIRED }, + { "LegacyPairing", WINEBLUETOOTH_DEVICE_PROPERTY_LEGACY_PAIRING }, + { "Trusted", WINEBLUETOOTH_DEVICE_PROPERTY_TRUSTED }, + { "Class", WINEBLUETOOTH_DEVICE_PROPERTY_CLASS } + }; + + p_dbus_message_iter_next( &iter ); + p_dbus_message_iter_recurse( &iter, &changed_props_iter ); + while ((prop_name = bluez_next_dict_entry( &changed_props_iter, &variant ))) + { + bluez_device_prop_from_dict_entry( prop_name, &variant, &props_changed.props, + &props_changed.changed_props_mask, + WINEBLUETOOTH_DEVICE_ALL_PROPERTIES ); + } + p_dbus_message_iter_next( &iter ); + p_dbus_message_iter_recurse( &iter, &invalid_props_iter ); + props_changed.invalid_props_mask = bluez_dbus_get_invalidated_properties_from_iter( + &invalid_props_iter, device_prop_masks, ARRAY_SIZE( device_prop_masks ) ); + /* No properties that we're interested in have changed or been invalidated. */ + if (!props_changed.changed_props_mask && !props_changed.invalid_props_mask) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + object_path = p_dbus_message_get_path( msg ); + TRACE( "Properties changed for device %s, changed %#x, invalidated %#x\n", debugstr_a( object_path ), + props_changed.changed_props_mask, props_changed.invalid_props_mask ); + + device = unix_name_get_or_create( object_path ); + if (!device) + { + ERR( "Failed to allocate memory for device path %s\n", object_path ); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + props_changed.device.handle = (UINT_PTR)device; + event.device_props_changed = props_changed; + + if (props_changed.invalid_props_mask != 0) + { + DBusPendingCall *pending_call = NULL; + NTSTATUS status; + + status = bluez_device_get_props_by_path_async( conn, device->str, &pending_call ); + if (status) + { + ERR( "Failed to create async call to get device properties: %#x\n", (int)status ); + unix_name_free( device ); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + if (!bluez_event_list_queue_new_event_with_call( event_list, + BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_PROPERTIES_CHANGED, + event, pending_call, + bluez_filter_device_props_changed_callback )) + { + unix_name_free( device ); + p_dbus_pending_call_cancel( pending_call ); + p_dbus_pending_call_unref( pending_call ); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + } + else if (!bluez_event_list_queue_new_event( event_list, + BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_PROPERTIES_CHANGED, + event )) + { + + unix_name_free( device ); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + } }
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; @@ -1107,6 +1245,9 @@ static void bluez_watcher_free( struct bluez_watcher_ctx *watcher ) case BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_REMOVED: unix_name_free( (struct unix_name *)event1->event.device_removed.device.handle ); break; + case BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_PROPERTIES_CHANGED: + unix_name_free( (struct unix_name *)event1->event.device_props_changed.device.handle ); + break; } free( event1 ); } diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index 52f4a15c197..b47806de077 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -510,6 +510,49 @@ static void bluetooth_radio_remove_remote_device( struct winebluetooth_watcher_e winebluetooth_device_free( event.device ); }
+static void bluetooth_radio_update_device_props( struct winebluetooth_watcher_event_device_props_changed event ) +{ + struct bluetooth_radio *radio; + + EnterCriticalSection( &device_list_cs ); + LIST_FOR_EACH_ENTRY( radio, &device_list, struct bluetooth_radio, entry ) + { + struct bluetooth_remote_device *device; + + EnterCriticalSection( &radio->remote_devices_cs ); + LIST_FOR_EACH_ENTRY( device, &radio->remote_devices, struct bluetooth_remote_device, entry ) + { + if (winebluetooth_device_equal( event.device, device->device )) + { + EnterCriticalSection( &device->props_cs ); + device->props_mask |= event.changed_props_mask; + device->props_mask &= ~event.invalid_props_mask; + if (event.changed_props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_NAME) + memcpy( device->props.name, event.props.name, sizeof( event.props.name )); + if (event.changed_props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_ADDRESS) + device->props.address = event.props.address; + if (event.changed_props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_CONNECTED) + device->props.connected = event.props.connected; + if (event.changed_props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_PAIRED) + device->props.paired = event.props.paired; + if (event.changed_props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_LEGACY_PAIRING) + device->props.legacy_pairing = event.props.legacy_pairing; + if (event.changed_props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_TRUSTED) + device->props.trusted = event.props.trusted; + if (event.changed_props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_CLASS) + device->props.class = event.props.class; + LeaveCriticalSection( &device->props_cs ); + LeaveCriticalSection( &radio->remote_devices_cs ); + goto done; + } + } + LeaveCriticalSection( &radio->remote_devices_cs ); + } +done: + LeaveCriticalSection( &device_list_cs ); + winebluetooth_device_free( event.device ); +} + static DWORD CALLBACK bluetooth_event_loop_thread_proc( void *arg ) { NTSTATUS status; @@ -542,6 +585,9 @@ static DWORD CALLBACK bluetooth_event_loop_thread_proc( void *arg ) case BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_REMOVED: bluetooth_radio_remove_remote_device( event->event_data.device_removed ); break; + case BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_PROPERTIES_CHANGED: + bluetooth_radio_update_device_props( event->event_data.device_props_changed); + break; default: FIXME( "Unknown bluetooth watcher event code: %#x\n", event->event_type ); } diff --git a/dlls/winebth.sys/winebth_priv.h b/dlls/winebth.sys/winebth_priv.h index 59915b70805..b50935c091c 100644 --- a/dlls/winebth.sys/winebth_priv.h +++ b/dlls/winebth.sys/winebth_priv.h @@ -209,7 +209,8 @@ enum winebluetooth_watcher_event_type BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_REMOVED, BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_PROPERTIES_CHANGED, BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_ADDED, - BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_REMOVED + BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_REMOVED, + BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_PROPERTIES_CHANGED };
struct winebluetooth_watcher_event_radio_added @@ -236,6 +237,15 @@ struct winebluetooth_watcher_event_device_added winebluetooth_radio_t radio; };
+struct winebluetooth_watcher_event_device_props_changed +{ + winebluetooth_device_props_mask_t changed_props_mask; + struct winebluetooth_device_properties props; + + winebluetooth_device_props_mask_t invalid_props_mask; + winebluetooth_device_t device; +}; + struct winebluetooth_watcher_event_device_removed { winebluetooth_device_t device; @@ -248,6 +258,7 @@ union winebluetooth_watcher_event_data struct winebluetooth_watcher_event_radio_props_changed radio_props_changed; struct winebluetooth_watcher_event_device_added device_added; struct winebluetooth_watcher_event_device_removed device_removed; + struct winebluetooth_watcher_event_device_props_changed device_props_changed; };
struct winebluetooth_watcher_event