From: Sergei Chernyadyev 1892-Cherser-s@users.noreply.gitlab.winehq.org
--- dlls/winesni.drv/Makefile.in | 2 +- dlls/winesni.drv/dbus.c | 157 ++++++++++++++++++++++++++++------- 2 files changed, 129 insertions(+), 30 deletions(-)
diff --git a/dlls/winesni.drv/Makefile.in b/dlls/winesni.drv/Makefile.in index 6c488d5210b..0179dd9a018 100644 --- a/dlls/winesni.drv/Makefile.in +++ b/dlls/winesni.drv/Makefile.in @@ -2,7 +2,7 @@ MODULE = winesni.drv UNIXLIB = winesni.so IMPORTS = uuid win32u UNIX_CFLAGS = $(DBUS_CFLAGS) $(HAL_CFLAGS) -UNIX_LIBS = -lwin32u +UNIX_LIBS = -lwin32u $(PTHREAD_LIBS)
SOURCES = \ dllmain.c \ diff --git a/dlls/winesni.drv/dbus.c b/dlls/winesni.drv/dbus.c index d3df503e8e8..743ea27fe56 100644 --- a/dlls/winesni.drv/dbus.c +++ b/dlls/winesni.drv/dbus.c @@ -73,6 +73,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(winesni); DO_FUNC(dbus_connection_unref); \ DO_FUNC(dbus_connection_get_object_path_data); \ DO_FUNC(dbus_connection_get_unix_fd); \ + DO_FUNC(dbus_connection_set_watch_functions); \ + DO_FUNC(dbus_watch_get_unix_fd); \ + DO_FUNC(dbus_watch_handle); \ + DO_FUNC(dbus_watch_get_flags); \ + DO_FUNC(dbus_watch_get_enabled); \ DO_FUNC(dbus_error_free); \ DO_FUNC(dbus_error_init); \ DO_FUNC(dbus_error_is_set); \ @@ -127,11 +132,14 @@ struct tray_icon char tiptext[128 * 3]; /* tooltip text */ UINT version; /* notify icon api version */ DBusConnection* connection; + DBusWatch* watch; + int watch_fd; + UINT watch_flags; pthread_mutex_t mutex; /* mutex */ };
static struct list sni_list = LIST_INIT( sni_list ); -static pthread_mutex_t list_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t list_mutex;
#define BALLOON_SHOW_MIN_TIMEOUT 10000 #define BALLOON_SHOW_MAX_TIMEOUT 30000 @@ -146,6 +154,10 @@ static const char* freedesktop_item_interface_name = "org.freedesktop.StatusNoti static const char* item_interface_name = "org.kde.StatusNotifierItem";
static DBusConnection *global_connection; +static DBusWatch *global_connection_watch; +static int global_connection_watch_fd; +static UINT global_connection_watch_flags; + static char* status_notifier_dst_path = NULL;
static const char *status_field = "Status"; @@ -261,7 +273,6 @@ static BOOL get_owner_for_interface(DBusConnection* connection, const char* inte if (!pending) { goto err; } - p_dbus_connection_flush(connection);
p_dbus_message_unref(msg);
@@ -302,19 +313,90 @@ BOOL get_notifier_watcher_owner_for_interface(DBusConnection* connection, const return TRUE; }
+ +static dbus_bool_t add_watch(DBusWatch *w, void *data) +{ + int fd; + unsigned int flags, poll_flags; + if (!p_dbus_watch_get_enabled(w)) + return TRUE; + + fd = p_dbus_watch_get_unix_fd(w); + flags = p_dbus_watch_get_flags(w); + poll_flags = 0; + + if (flags & DBUS_WATCH_READABLE) + poll_flags |= POLLIN; + if (flags & DBUS_WATCH_WRITABLE) + poll_flags |= POLLOUT; + + pthread_mutex_lock(&list_mutex); + if (data != NULL) { + struct tray_icon *icon = (struct tray_icon *) data; + icon->watch_fd = fd; + icon->watch_flags = poll_flags; + icon->watch = w; + } else { + /* global connection */ + global_connection_watch_fd = fd; + global_connection_watch_flags = poll_flags; + global_connection_watch = w; + } + pthread_mutex_unlock(&list_mutex); + + return TRUE; +} +static void remove_watch(DBusWatch *w, void *data) +{ + pthread_mutex_lock(&list_mutex); + if (data != NULL) { + struct tray_icon *icon = (struct tray_icon *) data; + icon->watch_fd = 0; + icon->watch_flags = 0; + icon->watch = NULL; + } else { + /* global connection */ + global_connection_watch_fd = 0; + global_connection_watch_flags = 0; + global_connection_watch = NULL; + } + pthread_mutex_unlock(&list_mutex); +} + + +static void toggle_watch(DBusWatch *w, void *data) +{ + if (p_dbus_watch_get_enabled(w)) + add_watch(w, data); + else + remove_watch(w, data); +} + BOOL get_notifier_watcher_owner(void) { DBusError error; + pthread_mutexattr_t attr; p_dbus_error_init( &error ); if (!p_dbus_threads_init_default()) { goto err; } + + pthread_mutexattr_init( &attr ); + pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ); + pthread_mutex_init( &list_mutex, &attr ); + if (!(global_connection = p_dbus_bus_get_private( DBUS_BUS_SESSION, &error ))) { WARN("failed to get system dbus connection: %s\n", error.message ); p_dbus_error_free( &error ); goto err; }
+ if (!p_dbus_connection_set_watch_functions(global_connection, add_watch, remove_watch, + toggle_watch, NULL, NULL)) { + WARN("dbus_set_watch_functions() failed\n"); + goto err; + } + if (!get_notifier_watcher_owner_for_interface(global_connection, kde_watcher_interface_name, kde_item_interface_name) && !get_notifier_watcher_owner_for_interface(global_connection, freedesktop_watcher_interface_name, freedesktop_item_interface_name)) { WARN("failed to query watcher interface owner\n"); @@ -328,9 +410,11 @@ BOOL get_notifier_watcher_owner(void) p_dbus_error_free( &error); goto err; } + pthread_mutexattr_destroy( &attr ); return TRUE;
err: + pthread_mutexattr_destroy( &attr ); return FALSE; }
@@ -508,7 +592,6 @@ static BOOL send_notification(DBusConnection* connection, const WCHAR* title, co if (!pending) { goto err; } - p_dbus_connection_flush(connection);
p_dbus_message_unref(msg);
@@ -535,9 +618,11 @@ err:
void dbus_finalize() { if (global_connection != NULL) { + p_dbus_connection_flush(global_connection); p_dbus_connection_close(global_connection); p_dbus_connection_unref(global_connection); } + pthread_mutex_destroy(&list_mutex); if (dbus_module != NULL) { dlclose(dbus_module); } @@ -635,7 +720,7 @@ static DBusHandlerResult notification_send_error(DBusConnection *conn, DBusMessa p_dbus_message_unref(reply); return DBUS_HANDLER_RESULT_NEED_MEMORY; } - p_dbus_connection_flush(conn); + p_dbus_message_unref(reply); return DBUS_HANDLER_RESULT_HANDLED; } @@ -776,7 +861,7 @@ DBusHandlerResult get_all_tray_properties(DBusConnection* conn, DBusMessage *mes if (!p_dbus_connection_send(conn, reply, &serial)) { goto send_fail; } - p_dbus_connection_flush(conn); + p_dbus_message_unref(reply); return DBUS_HANDLER_RESULT_HANDLED; fail: @@ -868,7 +953,6 @@ DBusHandlerResult notification_message_handler(DBusConnection *conn, DBusMessage goto err_get; }
- p_dbus_connection_flush(conn); p_dbus_message_unref(reply); err_get: pthread_mutex_unlock((pthread_mutex_t*)&icon->mutex); @@ -962,39 +1046,43 @@ const DBusObjectPathVTable notification_vtable =
void run_dbus_loop(void) { - int dbus_conn_fd; DBusConnection* conns[128]; + DBusWatch* watches[128]; struct pollfd fd_info[128]; int fd_count; struct pollfd* fd_ptr = fd_info; - p_dbus_connection_get_unix_fd(global_connection, &dbus_conn_fd);
- conns[0] = global_connection; - fd_info[0] = (struct pollfd) { - .fd = dbus_conn_fd, - .events = POLLIN, - }; while (true) { int i, poll_ret; struct tray_icon* icon; - fd_count = 1; + fd_count = 0; pthread_mutex_lock(&list_mutex); + if (global_connection_watch_fd) { + conns[fd_count] = p_dbus_connection_ref(global_connection); + watches[fd_count] = global_connection_watch; + fd_info[fd_count++] = (struct pollfd) { + .fd = global_connection_watch_fd, + .events = global_connection_watch_flags, + .revents = 0, + }; + } LIST_FOR_EACH_ENTRY( icon, &sni_list, struct tray_icon, entry ) { - int sni_dbus_conn_fd; if (fd_count >= 128) { break; } - - p_dbus_connection_get_unix_fd(icon->connection, &sni_dbus_conn_fd); + if (!icon->watch_fd) { + continue; + } conns[fd_count] = p_dbus_connection_ref(icon->connection); + watches[fd_count] = icon->watch; fd_info[fd_count++] = (struct pollfd) { - .fd = sni_dbus_conn_fd, - .events = POLLIN, + .fd = icon->watch_fd, + .events = icon->watch_flags, .revents = 0, }; } pthread_mutex_unlock(&list_mutex); - /* TODO: utilize DBusWatch */ + poll_ret = poll(fd_ptr, fd_count, 100); if (poll_ret == 0) { continue; @@ -1004,17 +1092,20 @@ void run_dbus_loop(void) continue; } for ( i = 0; i < fd_count; i++ ) { - if ((fd_info[i].revents & POLLIN) && !(fd_info[i].revents & (POLLERR | POLLHUP | POLLNVAL))) { - /* non blocking read of the next available message */ - if (!p_dbus_connection_read_write(conns[i], 0)) { - break; - } + if (fd_info[i].revents & (POLLERR | POLLHUP | POLLNVAL)) continue; + if (fd_info[i].revents & POLLIN) { + p_dbus_watch_handle(watches[i], DBUS_WATCH_READABLE); while ( p_dbus_connection_get_dispatch_status ( conns[i] ) == DBUS_DISPATCH_DATA_REMAINS ) { p_dbus_connection_dispatch ( conns[i] ) ; } } - if (i > 0) p_dbus_connection_unref(conns[i]); + if (fd_info[i].revents & POLLOUT) { + p_dbus_watch_handle(watches[i], DBUS_WATCH_WRITABLE); + } + } + for ( i = 0; i < fd_count; i++ ) { + p_dbus_connection_unref(conns[i]); } } } @@ -1066,7 +1157,7 @@ static BOOL register_notification_item(DBusConnection* connection) if (!pending) { goto err; } - p_dbus_connection_flush(connection); + p_dbus_message_unref(msg);
p_dbus_pending_call_block(pending); @@ -1109,7 +1200,6 @@ static BOOL send_signal_to_item(DBusConnection* connection, const char* signal_n p_dbus_message_unref(msg); return FALSE; } - p_dbus_connection_flush(connection);
p_dbus_message_unref(msg);
@@ -1153,6 +1243,7 @@ BOOL add_icon(const NOTIFYICONDATAW* icon_data) p_dbus_error_free( &error ); goto fail; } + icon = malloc(sizeof(struct tray_icon)); if (!icon) { goto fail; @@ -1166,6 +1257,13 @@ BOOL add_icon(const NOTIFYICONDATAW* icon_data) WARN("failed to initialize mutex\n" ); goto fail; } + + if (!p_dbus_connection_set_watch_functions(connection, add_watch, remove_watch, + toggle_watch, icon, NULL)) { + WARN("dbus_set_watch_functions() failed\n"); + goto fail; + } + if (icon_data->uFlags & NIF_ICON) { if (!get_icon_data(icon_data, icon)) { @@ -1221,9 +1319,11 @@ fail: BOOL cleanup_icon(struct tray_icon* icon) { pthread_mutex_lock(&icon->mutex); + p_dbus_connection_flush(icon->connection); p_dbus_connection_close(icon->connection); p_dbus_connection_unref(icon->connection); pthread_mutex_unlock(&icon->mutex); + if (icon->hIcon) NtUserDestroyCursor(icon->hIcon, 0); if (icon->icon_bitmap) free(icon->icon_bitmap); if (icon) pthread_mutex_destroy(&icon->mutex); @@ -1333,6 +1433,5 @@ BOOL cleanup_icons(HWND owner) } } pthread_mutex_unlock(&list_mutex); - return TRUE; }