Signed-off-by: Micah N Gorrell mgorrell@codeweavers.com --- server/protocol.def | 23 +++++++++ server/user.h | 3 +- server/window.c | 112 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 1 deletion(-)
diff --git a/server/protocol.def b/server/protocol.def index e450388c17..1645d09d5f 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3692,6 +3692,29 @@ struct handle_info @END
+/* Register a handle for device notifications */ +@REQ(register_device_notification) + user_handle_t recipient; /* handle to a window or service that will receive device events */ +@REPLY + user_handle_t handle; /* handle associated with the registration */ +@END + + +/* Unregister device notifications for a handle */ +@REQ(unregister_device_notification) + user_handle_t notification; /* handle that was previously returned by register_device_notification */ +@END + + +/* Return a list of handles that have registered for device notifications */ +@REQ(get_device_notifications) +@REPLY + int count; /* total count of registered handles */ + VARARG(handles,user_handles); /* registered handles */ +@END + + + /* Make the current process a system process */ @REQ(make_process_system) @REPLY diff --git a/server/user.h b/server/user.h index eb1b7ce1e4..282cb63339 100644 --- a/server/user.h +++ b/server/user.h @@ -36,7 +36,8 @@ enum user_object { USER_WINDOW = 1, USER_HOOK, - USER_CLIENT /* arbitrary client handle */ + USER_CLIENT, /* arbitrary client handle */ + USER_DEVNOTIFY };
#define DESKTOP_ATOM ((atom_t)32769) diff --git a/server/window.c b/server/window.c index c9b131cba5..80ac897ea6 100644 --- a/server/window.c +++ b/server/window.c @@ -129,6 +129,19 @@ static struct window *taskman_window; #define WINPTR_TOPMOST ((struct window *)3L) #define WINPTR_NOTOPMOST ((struct window *)4L)
+struct device_notification +{ + user_handle_t recipient; /* the window handle to send notifications to */ + user_handle_t handle; /* full handle for this window */ + struct process *process; /* process that owns this notification handle */ + struct list entry; /* entry in global notifications list */ + + /* FIXME: Add support for notification filters */ +}; + +/* global list of handles that have registered for device notifications */ +static struct list device_notifications = LIST_INIT(device_notifications); + /* retrieve a pointer to a window from its handle */ static inline struct window *get_window( user_handle_t handle ) { @@ -2880,3 +2893,102 @@ DECL_HANDLER(set_window_layered_info) } else set_win32_error( ERROR_INVALID_WINDOW_HANDLE ); } + +/* retrieve a pointer to a device_notification from its handle */ +static inline struct device_notification *get_device_notification( user_handle_t handle ) +{ + struct device_notification *ret = get_user_object( handle, USER_DEVNOTIFY ); + if (!ret) set_win32_error( ERROR_INVALID_HANDLE ); + return ret; +} + +/* create a new device notification structure and link it into the global list */ +static struct device_notification *register_device_notification( struct window *recipient ) +{ + struct device_notification *notification; + + if (!recipient) + { + return NULL; + } + + if (!(notification = mem_alloc( sizeof(*notification) ))) goto failed; + if (!(notification->handle = alloc_user_handle( notification, USER_DEVNOTIFY ))) goto failed; + + notification->recipient = recipient->handle; + notification->process = current->process; + /* FIXME: Add support for notification filters */ + + list_add_tail( &device_notifications, ¬ification->entry ); + + return notification; +failed: + if (notification) + { + if (notification->handle) free_user_handle( notification->handle ); + free( notification ); + } + + return NULL; +} + +static void unregister_device_notification( struct device_notification *notification) +{ + list_remove( ¬ification->entry ); + free_user_handle( notification->handle ); + memset( notification, 0x55, sizeof(*notification) ); + free( notification ); +} + +static int get_device_notifications( struct user_handle_array *array ) +{ + struct device_notification *notification; + + LIST_FOR_EACH_ENTRY( notification, &device_notifications, struct device_notification, entry ) + { + /* FIXME: Implement notification filtering */ + if (!add_handle_to_array( array, notification->recipient )) return 0; + } + + return 1; +} + +/* register for device notifications */ +DECL_HANDLER(register_device_notification) +{ + struct device_notification *notification = NULL; + struct window *recipient = get_window( req->recipient ); + + reply->handle = 0; + if (!recipient) return; + + if (!(notification = register_device_notification( recipient ))) return; + + reply->handle = notification->handle; +} + +DECL_HANDLER(unregister_device_notification) +{ + struct device_notification *notification = get_device_notification( req->notification ); + if (notification) { + if (notification->process == current->process) unregister_device_notification(notification); + else set_error( STATUS_ACCESS_DENIED ); + } +} + +DECL_HANDLER(get_device_notifications) +{ + struct user_handle_array array; + data_size_t len; + + array.handles = NULL; + array.count = 0; + array.total = 0; + + if (!get_device_notifications( &array )) return; + + reply->count = array.count; + len = min( get_reply_max_size(), array.count * sizeof(user_handle_t) ); + if (len) set_reply_data_ptr( array.handles, len ); + else free( array.handles ); +}