Make the clipboard information local to the process window station.

This commit is contained in:
Alexandre Julliard 2005-06-29 20:13:36 +00:00
parent 36b85d02f6
commit 45128bdcdd
3 changed files with 137 additions and 60 deletions

View File

@ -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 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
/* 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 == cbowner)
{
owner = 0;
cbowner = 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;
}
}
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;
}

View File

@ -29,6 +29,7 @@ struct window;
struct msg_queue;
struct hook_table;
struct window_class;
struct clipboard;
enum user_object
{
@ -120,6 +121,9 @@ extern void *get_class_client_ptr( struct window_class *class );
/* 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 );

View File

@ -41,6 +41,7 @@ struct winstation
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 @@ static struct winstation *create_winstation( const WCHAR *name, size_t len, unsi
{
/* 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 @@ static void winstation_destroy( struct object *obj )
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 )