diff --git a/server/clipboard.c b/server/clipboard.c index 3f9db20e663..9b3cac07c82 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 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; } diff --git a/server/user.h b/server/user.h index ec83199a664..2c84f06099f 100644 --- a/server/user.h +++ b/server/user.h @@ -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 ); diff --git a/server/winstation.c b/server/winstation.c index ed61df96420..54d95d03bb0 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -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 )