Make the clipboard information local to the process window station.
diff --git a/server/clipboard.c b/server/clipboard.c
index 3f9db20..9b3cac0 100644
--- a/server/clipboard.c
+++ b/server/clipboard.c
@@ -29,145 +29,204 @@
#include "request.h"
#include "object.h"
#include "user.h"
+#include "winuser.h"
-static struct thread *cbthread; /* thread id that has clipboard open */
-static user_handle_t clipboard; /* window that has clipboard open */
+struct clipboard
+{
+ struct object obj; /* object header */
+ struct thread *open_thread; /* thread id that has clipboard open */
+ user_handle_t open_win; /* window that has clipboard open */
+ struct thread *owner_thread; /* thread id that owns the clipboard */
+ user_handle_t owner_win; /* window that owns the clipboard data */
+ user_handle_t viewer; /* first window in clipboard viewer list */
+ unsigned int seqno; /* clipboard change sequence number */
+ time_t seqno_timestamp; /* time stamp of last seqno increment */
+};
-static struct thread *cbowner; /* thread id that owns the clipboard */
-static user_handle_t owner; /* window that owns the clipboard data */
+static void clipboard_dump( struct object *obj, int verbose );
-static user_handle_t viewer; /* first window in clipboard viewer list */
-static unsigned int seqno; /* clipboard change sequence number */
-static time_t seqnots; /* time stamp of last seqno increment */
+static const struct object_ops clipboard_ops =
+{
+ sizeof(struct clipboard), /* size */
+ clipboard_dump, /* dump */
+ no_add_queue, /* add_queue */
+ NULL, /* remove_queue */
+ NULL, /* signaled */
+ NULL, /* satisfied */
+ no_signal, /* signal */
+ no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
+ no_destroy /* destroy */
+};
+
#define MINUPDATELAPSE 2
+/* dump a clipboard object */
+static void clipboard_dump( struct object *obj, int verbose )
+{
+ struct clipboard *clipboard = (struct clipboard *)obj;
+
+ fprintf( stderr, "Clipboard open_thread=%p open_win=%p owner_thread=%p owner_win=%p viewer=%p seq=%u\n",
+ clipboard->open_thread, clipboard->open_win, clipboard->owner_thread,
+ clipboard->owner_win, clipboard->viewer, clipboard->seqno );
+}
+
+/* retrieve the clipboard info for the current process, allocating it if needed */
+static struct clipboard *get_process_clipboard(void)
+{
+ struct clipboard *clipboard;
+ struct winstation *winstation = get_process_winstation( current->process, WINSTA_ACCESSCLIPBOARD );
+
+ if (!winstation) return NULL;
+
+ if (!(clipboard = get_winstation_clipboard( winstation )))
+ {
+ if ((clipboard = alloc_object( &clipboard_ops )))
+ {
+ clipboard->open_thread = NULL;
+ clipboard->open_win = 0;
+ clipboard->owner_thread = NULL;
+ clipboard->owner_win = 0;
+ clipboard->viewer = 0;
+ clipboard->seqno = 0;
+ clipboard->seqno_timestamp = 0;
+ set_winstation_clipboard( winstation, clipboard );
+ }
+ }
+ release_object( winstation );
+ return clipboard;
+}
+
+
/* Called when thread terminates to allow release of clipboard */
void cleanup_clipboard_thread(struct thread *thread)
{
- if (thread == cbthread)
+ struct clipboard *clipboard;
+ struct winstation *winstation = get_process_winstation( thread->process, WINSTA_ACCESSCLIPBOARD );
+
+ if (!winstation) return;
+
+ if ((clipboard = get_winstation_clipboard( winstation )))
{
- clipboard = 0;
- cbthread = NULL;
+ if (thread == clipboard->open_thread)
+ {
+ clipboard->open_win = 0;
+ clipboard->open_thread = NULL;
+ }
+ if (thread == clipboard->owner_thread)
+ {
+ clipboard->owner_win = 0;
+ clipboard->owner_thread = NULL;
+ }
}
- if (thread == cbowner)
- {
- owner = 0;
- cbowner = NULL;
- }
+ release_object( winstation );
}
-static int set_clipboard_window(user_handle_t win, int clear)
+static int set_clipboard_window( struct clipboard *clipboard, user_handle_t win, int clear )
{
- if (cbthread && cbthread != current)
+ if (clipboard->open_thread && clipboard->open_thread != current)
{
set_error(STATUS_WAS_LOCKED);
return 0;
}
else if (!clear)
{
- clipboard = win;
- cbthread = current;
+ clipboard->open_win = win;
+ clipboard->open_thread = current;
}
else
{
- cbthread = NULL;
- clipboard = 0;
+ clipboard->open_thread = NULL;
+ clipboard->open_win = 0;
}
return 1;
}
-static int set_clipboard_owner(user_handle_t win, int clear)
+static int set_clipboard_owner( struct clipboard *clipboard, user_handle_t win, int clear )
{
- if (cbthread && cbthread->process != current->process)
+ if (clipboard->open_thread && clipboard->open_thread->process != current->process)
{
set_error(STATUS_WAS_LOCKED);
return 0;
}
else if (!clear)
{
- owner = win;
- cbowner = current;
+ clipboard->owner_win = win;
+ clipboard->owner_thread = current;
}
else
{
- owner = 0;
- cbowner = NULL;
+ clipboard->owner_win = 0;
+ clipboard->owner_thread = NULL;
}
return 1;
}
-static int get_seqno(void)
+static int get_seqno( struct clipboard *clipboard )
{
time_t tm = time(NULL);
- if (!cbowner && (tm > (seqnots + MINUPDATELAPSE)))
+ if (!clipboard->owner_thread && (tm > (clipboard->seqno_timestamp + MINUPDATELAPSE)))
{
- seqnots = tm;
- seqno++;
+ clipboard->seqno_timestamp = tm;
+ clipboard->seqno++;
}
- return seqno;
+ return clipboard->seqno;
}
DECL_HANDLER(set_clipboard_info)
{
- reply->old_clipboard = clipboard;
- reply->old_owner = owner;
- reply->old_viewer = viewer;
+ struct clipboard *clipboard = get_process_clipboard();
+
+ if (!clipboard) return;
+
+ reply->old_clipboard = clipboard->open_win;
+ reply->old_owner = clipboard->owner_win;
+ reply->old_viewer = clipboard->viewer;
if (req->flags & SET_CB_OPEN)
{
- if (cbthread)
+ if (clipboard->open_thread)
{
/* clipboard already opened */
set_error(STATUS_WAS_LOCKED);
return;
}
- if (!set_clipboard_window(req->clipboard, 0))
- return;
+ if (!set_clipboard_window( clipboard, req->clipboard, 0 )) return;
}
else if (req->flags & SET_CB_CLOSE)
{
- if (cbthread != current)
+ if (clipboard->open_thread != current)
{
set_win32_error(ERROR_CLIPBOARD_NOT_OPEN);
return;
}
- if (!set_clipboard_window(0, 1))
- return;
+ if (!set_clipboard_window( clipboard, 0, 1 )) return;
}
if (req->flags & SET_CB_OWNER)
{
- if (!set_clipboard_owner(req->owner, 0))
- return;
+ if (!set_clipboard_owner( clipboard, req->owner, 0 )) return;
}
else if (req->flags & SET_CB_RELOWNER)
{
- if (!set_clipboard_owner(0, 1))
- return;
+ if (!set_clipboard_owner( clipboard, 0, 1 )) return;
}
- if (req->flags & SET_CB_VIEWER)
- viewer = req->viewer;
+ if (req->flags & SET_CB_VIEWER) clipboard->viewer = req->viewer;
- if (req->flags & SET_CB_SEQNO)
- seqno++;
+ if (req->flags & SET_CB_SEQNO) clipboard->seqno++;
- reply->seqno = get_seqno();
+ reply->seqno = get_seqno( clipboard );
- if (cbthread == current)
- reply->flags |= CB_OPEN;
-
- if (cbowner == current)
- reply->flags |= CB_OWNER;
-
- if (cbowner &&
- cbowner->process == current->process)
+ if (clipboard->open_thread == current) reply->flags |= CB_OPEN;
+ if (clipboard->owner_thread == current) reply->flags |= CB_OWNER;
+ if (clipboard->owner_thread && clipboard->owner_thread->process == current->process)
reply->flags |= CB_PROCESS;
}
diff --git a/server/user.h b/server/user.h
index ec83199..2c84f06 100644
--- a/server/user.h
+++ b/server/user.h
@@ -29,6 +29,7 @@
struct msg_queue;
struct hook_table;
struct window_class;
+struct clipboard;
enum user_object
{
@@ -120,6 +121,9 @@
/* windows station functions */
+extern struct winstation *get_process_winstation( struct process *process, unsigned int access );
+extern void set_winstation_clipboard( struct winstation *winstation, struct clipboard *clipboard );
+extern struct clipboard *get_winstation_clipboard( struct winstation *winstation );
extern void connect_process_winstation( struct process *process, const WCHAR *name, size_t len );
extern void connect_process_desktop( struct process *process, const WCHAR *name, size_t len );
extern void close_thread_desktop( struct thread *thread );
diff --git a/server/winstation.c b/server/winstation.c
index ed61df9..54d95d0 100644
--- a/server/winstation.c
+++ b/server/winstation.c
@@ -41,6 +41,7 @@
unsigned int flags; /* winstation flags */
struct list entry; /* entry in global winstation list */
struct list desktops; /* list of desktops of this winstation */
+ struct clipboard *clipboard; /* clipboard information */
};
struct desktop
@@ -113,6 +114,7 @@
{
/* initialize it if it didn't already exist */
winstation->flags = flags;
+ winstation->clipboard = NULL;
list_add_tail( &winstation_list, &winstation->entry );
list_init( &winstation->desktops );
}
@@ -140,16 +142,28 @@
if (winstation == interactive_winstation) interactive_winstation = NULL;
list_remove( &winstation->entry );
+ if (winstation->clipboard) release_object( winstation->clipboard );
}
/* retrieve the process window station, checking the handle access rights */
-inline static struct winstation *get_process_winstation( struct process *process,
- unsigned int access )
+struct winstation *get_process_winstation( struct process *process, unsigned int access )
{
return (struct winstation *)get_handle_obj( process, process->winstation,
access, &winstation_ops );
}
+/* set the pointer to the (opaque) clipboard info */
+void set_winstation_clipboard( struct winstation *winstation, struct clipboard *clipboard )
+{
+ winstation->clipboard = clipboard;
+}
+
+/* retrieve the pointer to the (opaque) clipboard info */
+struct clipboard *get_winstation_clipboard( struct winstation *winstation )
+{
+ return winstation->clipboard;
+}
+
/* build the full name of a desktop object */
static WCHAR *build_desktop_name( const WCHAR *name, size_t len,
struct winstation *winstation, size_t *res_len )