From 121e9087059524094839adebafd6d26964326db7 Mon Sep 17 00:00:00 2001
From: Andrew Riedi <andrewriedi@gmail.com>
Date: Mon, 19 Jan 2009 22:24:12 -0800
Subject: [PATCH] server: Add functions for storing cursors in the server.

Based on a patch by Henri Verbeet.
---
 server/Makefile.in  |    1 +
 server/cursoricon.c |  120 +++++++++++++++++++++++++++++++++++++++++++++++++++
 server/process.c    |    1 +
 server/protocol.def |   24 ++++++++++
 server/user.h       |    7 +++-
 5 files changed, 152 insertions(+), 1 deletions(-)
 create mode 100644 server/cursoricon.c

diff --git a/server/Makefile.in b/server/Makefile.in
index 044c0c1..7926c68 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -19,6 +19,7 @@ C_SRCS = \
 	context_powerpc.c \
 	context_sparc.c \
 	context_x86_64.c \
+	cursoricon.c \
 	debugger.c \
 	device.c \
 	directory.c \
diff --git a/server/cursoricon.c b/server/cursoricon.c
new file mode 100644
index 0000000..0c38a29
--- /dev/null
+++ b/server/cursoricon.c
@@ -0,0 +1,120 @@
+/*
+ * Server-side cursor and icon code.
+ *
+ * Copyright (C) 2007 Henri Verbeet
+ * Copyright (C) 2009 Andrew Riedi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "winternl.h"
+#include "object.h"
+#include "request.h"
+#include "user.h"
+
+struct cursor
+{
+    struct process *process;
+    data_size_t size;
+    /* Transfer the entire cursor at once.  There is no need for wineserver to
+     * know the internal makeup of the cursor. */
+    void *data;
+};
+
+/* Destroy a single cursor. */
+void destroy_cursor(struct cursor *cursor)
+{
+    if (cursor)
+        free(cursor->data);
+
+    free(cursor);
+}
+
+/* Destroy all cursors belonging to a given process. */
+void destroy_process_cursors(struct process *process)
+{
+    user_handle_t handle = 0;
+    struct cursor *cursor;
+
+    while ((cursor = next_user_handle(&handle, USER_CURSOR)))
+    {
+        if (cursor->process != process)
+            continue;
+
+        destroy_cursor(cursor);
+        free_user_handle(handle);
+    }
+}
+
+/* Create a cursor given correct cursor data. */
+DECL_HANDLER(create_cursor)
+{
+    const size_t cursor_size = get_req_data_size();
+    struct cursor *cursor = mem_alloc(sizeof(struct cursor));
+
+    if (!cursor)
+    {
+        reply->handle = 0;
+        return;
+    }
+
+    cursor->process = current->process;
+    cursor->size = cursor_size;
+
+    if (!cursor_size || !(cursor->data = mem_alloc(cursor_size)))
+    {
+        destroy_cursor(cursor);
+        reply->handle = 0;
+        return;
+    }
+    memcpy(cursor->data, get_req_data(), cursor_size);
+
+    reply->handle = alloc_user_handle(cursor, USER_CURSOR);
+}
+
+/* Destroy a cursor. */
+DECL_HANDLER(destroy_cursor)
+{
+    struct cursor *cursor = free_user_handle(req->handle);
+
+    if (cursor)
+        destroy_cursor(cursor);
+}
+
+/* Get cursor data.  This is opaque to wineserver. */
+DECL_HANDLER(get_cursor_data)
+{
+    struct cursor *cursor = get_user_object(req->handle, USER_CURSOR);
+
+    if (!cursor)
+    {
+        reply->cursor_size = 0;
+        return;
+    }
+    reply->cursor_size = cursor->size;
+
+    if (cursor->size > get_reply_max_size())
+    {
+        set_error(STATUS_BUFFER_OVERFLOW);
+        return;
+    }
+
+    if (cursor->data)
+        set_reply_data(cursor->data, cursor->size);
+}
diff --git a/server/process.c b/server/process.c
index 8a4fb15..9252c78 100644
--- a/server/process.c
+++ b/server/process.c
@@ -647,6 +647,7 @@ static void process_killed( struct process *process )
         free( dll );
     }
     destroy_process_classes( process );
+    destroy_process_cursors( process );
     remove_process_locks( process );
     set_process_startup_state( process, STARTUP_ABORTED );
     finish_process_tracing( process );
diff --git a/server/protocol.def b/server/protocol.def
index a8f3569..a37045e 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2066,6 +2066,30 @@ enum message_type
 @END
 
 
+/* Create a cursor. */
+@REQ(create_cursor)
+    VARARG(data,bytes);
+@REPLY
+    user_handle_t       handle;
+@END
+
+
+/* Destroy a cursor. */
+@REQ(destroy_cursor)
+    user_handle_t       handle;
+@END
+
+
+/* Get cursor data. */
+@REQ(get_cursor_data)
+    user_handle_t       handle;
+    data_size_t         guess_size;
+@REPLY
+    data_size_t         cursor_size;
+    VARARG(data,bytes);
+@END
+
+
 /* Create a window */
 @REQ(create_window)
     user_handle_t  parent;      /* parent window */
diff --git a/server/user.h b/server/user.h
index 166d20b..95b9c7e 100644
--- a/server/user.h
+++ b/server/user.h
@@ -35,7 +35,8 @@ struct clipboard;
 enum user_object
 {
     USER_WINDOW = 1,
-    USER_HOOK
+    USER_HOOK,
+    USER_CURSOR
 };
 
 #define DESKTOP_ATOM  ((atom_t)32769)
@@ -76,6 +77,10 @@ extern void *next_user_handle( user_handle_t *handle, enum user_object type );
 
 extern void cleanup_clipboard_thread( struct thread *thread );
 
+/* cursor functions */
+
+extern void destroy_process_cursors( struct process *process );
+
 /* hook functions */
 
 extern void remove_thread_hooks( struct thread *thread );
-- 
1.5.6.3

