Commit 45128bdc authored by Alexandre Julliard's avatar Alexandre Julliard

Make the clipboard information local to the process window station.

parent 36b85d02
...@@ -29,145 +29,204 @@ ...@@ -29,145 +29,204 @@
#include "request.h" #include "request.h"
#include "object.h" #include "object.h"
#include "user.h" #include "user.h"
#include "winuser.h"
static struct thread *cbthread; /* thread id that has clipboard open */ struct clipboard
static user_handle_t clipboard; /* window that has clipboard open */ {
struct object obj; /* object header */
static struct thread *cbowner; /* thread id that owns the clipboard */ struct thread *open_thread; /* thread id that has clipboard open */
static user_handle_t owner; /* window that owns the clipboard data */ 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 void clipboard_dump( struct object *obj, int verbose );
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 */
};
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 */
#define MINUPDATELAPSE 2 #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 */ /* Called when thread terminates to allow release of clipboard */
void cleanup_clipboard_thread(struct thread *thread) 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; if (thread == clipboard->open_thread)
cbthread = NULL; {
clipboard->open_win = 0;
clipboard->open_thread = NULL;
} }
if (thread == cbowner) if (thread == clipboard->owner_thread)
{ {
owner = 0; clipboard->owner_win = 0;
cbowner = NULL; clipboard->owner_thread = 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); set_error(STATUS_WAS_LOCKED);
return 0; return 0;
} }
else if (!clear) else if (!clear)
{ {
clipboard = win; clipboard->open_win = win;
cbthread = current; clipboard->open_thread = current;
} }
else else
{ {
cbthread = NULL; clipboard->open_thread = NULL;
clipboard = 0; clipboard->open_win = 0;
} }
return 1; 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); set_error(STATUS_WAS_LOCKED);
return 0; return 0;
} }
else if (!clear) else if (!clear)
{ {
owner = win; clipboard->owner_win = win;
cbowner = current; clipboard->owner_thread = current;
} }
else else
{ {
owner = 0; clipboard->owner_win = 0;
cbowner = NULL; clipboard->owner_thread = NULL;
} }
return 1; return 1;
} }
static int get_seqno(void) static int get_seqno( struct clipboard *clipboard )
{ {
time_t tm = time(NULL); time_t tm = time(NULL);
if (!cbowner && (tm > (seqnots + MINUPDATELAPSE))) if (!clipboard->owner_thread && (tm > (clipboard->seqno_timestamp + MINUPDATELAPSE)))
{ {
seqnots = tm; clipboard->seqno_timestamp = tm;
seqno++; clipboard->seqno++;
} }
return seqno; return clipboard->seqno;
} }
DECL_HANDLER(set_clipboard_info) DECL_HANDLER(set_clipboard_info)
{ {
reply->old_clipboard = clipboard; struct clipboard *clipboard = get_process_clipboard();
reply->old_owner = owner;
reply->old_viewer = viewer; 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 (req->flags & SET_CB_OPEN)
{ {
if (cbthread) if (clipboard->open_thread)
{ {
/* clipboard already opened */ /* clipboard already opened */
set_error(STATUS_WAS_LOCKED); set_error(STATUS_WAS_LOCKED);
return; return;
} }
if (!set_clipboard_window(req->clipboard, 0)) if (!set_clipboard_window( clipboard, req->clipboard, 0 )) return;
return;
} }
else if (req->flags & SET_CB_CLOSE) else if (req->flags & SET_CB_CLOSE)
{ {
if (cbthread != current) if (clipboard->open_thread != current)
{ {
set_win32_error(ERROR_CLIPBOARD_NOT_OPEN); set_win32_error(ERROR_CLIPBOARD_NOT_OPEN);
return; return;
} }
if (!set_clipboard_window(0, 1)) if (!set_clipboard_window( clipboard, 0, 1 )) return;
return;
} }
if (req->flags & SET_CB_OWNER) if (req->flags & SET_CB_OWNER)
{ {
if (!set_clipboard_owner(req->owner, 0)) if (!set_clipboard_owner( clipboard, req->owner, 0 )) return;
return;
} }
else if (req->flags & SET_CB_RELOWNER) else if (req->flags & SET_CB_RELOWNER)
{ {
if (!set_clipboard_owner(0, 1)) if (!set_clipboard_owner( clipboard, 0, 1 )) return;
return;
} }
if (req->flags & SET_CB_VIEWER) if (req->flags & SET_CB_VIEWER) clipboard->viewer = req->viewer;
viewer = req->viewer;
if (req->flags & SET_CB_SEQNO)
seqno++;
reply->seqno = get_seqno();
if (cbthread == current) if (req->flags & SET_CB_SEQNO) clipboard->seqno++;
reply->flags |= CB_OPEN;
if (cbowner == current) reply->seqno = get_seqno( clipboard );
reply->flags |= CB_OWNER;
if (cbowner && if (clipboard->open_thread == current) reply->flags |= CB_OPEN;
cbowner->process == current->process) if (clipboard->owner_thread == current) reply->flags |= CB_OWNER;
if (clipboard->owner_thread && clipboard->owner_thread->process == current->process)
reply->flags |= CB_PROCESS; reply->flags |= CB_PROCESS;
} }
...@@ -29,6 +29,7 @@ struct window; ...@@ -29,6 +29,7 @@ struct window;
struct msg_queue; struct msg_queue;
struct hook_table; struct hook_table;
struct window_class; struct window_class;
struct clipboard;
enum user_object enum user_object
{ {
...@@ -120,6 +121,9 @@ extern void *get_class_client_ptr( struct window_class *class ); ...@@ -120,6 +121,9 @@ extern void *get_class_client_ptr( struct window_class *class );
/* windows station functions */ /* 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_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 connect_process_desktop( struct process *process, const WCHAR *name, size_t len );
extern void close_thread_desktop( struct thread *thread ); extern void close_thread_desktop( struct thread *thread );
......
...@@ -41,6 +41,7 @@ struct winstation ...@@ -41,6 +41,7 @@ struct winstation
unsigned int flags; /* winstation flags */ unsigned int flags; /* winstation flags */
struct list entry; /* entry in global winstation list */ struct list entry; /* entry in global winstation list */
struct list desktops; /* list of desktops of this winstation */ struct list desktops; /* list of desktops of this winstation */
struct clipboard *clipboard; /* clipboard information */
}; };
struct desktop struct desktop
...@@ -113,6 +114,7 @@ static struct winstation *create_winstation( const WCHAR *name, size_t len, unsi ...@@ -113,6 +114,7 @@ static struct winstation *create_winstation( const WCHAR *name, size_t len, unsi
{ {
/* initialize it if it didn't already exist */ /* initialize it if it didn't already exist */
winstation->flags = flags; winstation->flags = flags;
winstation->clipboard = NULL;
list_add_tail( &winstation_list, &winstation->entry ); list_add_tail( &winstation_list, &winstation->entry );
list_init( &winstation->desktops ); list_init( &winstation->desktops );
} }
...@@ -140,16 +142,28 @@ static void winstation_destroy( struct object *obj ) ...@@ -140,16 +142,28 @@ static void winstation_destroy( struct object *obj )
if (winstation == interactive_winstation) interactive_winstation = NULL; if (winstation == interactive_winstation) interactive_winstation = NULL;
list_remove( &winstation->entry ); list_remove( &winstation->entry );
if (winstation->clipboard) release_object( winstation->clipboard );
} }
/* retrieve the process window station, checking the handle access rights */ /* retrieve the process window station, checking the handle access rights */
inline static struct winstation *get_process_winstation( struct process *process, struct winstation *get_process_winstation( struct process *process, unsigned int access )
unsigned int access )
{ {
return (struct winstation *)get_handle_obj( process, process->winstation, return (struct winstation *)get_handle_obj( process, process->winstation,
access, &winstation_ops ); 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 */ /* build the full name of a desktop object */
static WCHAR *build_desktop_name( const WCHAR *name, size_t len, static WCHAR *build_desktop_name( const WCHAR *name, size_t len,
struct winstation *winstation, size_t *res_len ) struct winstation *winstation, size_t *res_len )
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment