Make the clipboard information local to the process window station.
This commit is contained in:
parent
36b85d02f6
commit
45128bdcdd
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 )
|
||||
|
|
Loading…
Reference in New Issue