From 7258793169e34a1efc239f01b6e99b1d338a8b6f Mon Sep 17 00:00:00 2001
From: Alexandre Julliard <julliard@winehq.org>
Date: Mon, 22 Aug 2016 15:31:21 +0900
Subject: [PATCH] server: Add separate requests for opening and closing the
 clipboard.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
---
 dlls/user32/clipboard.c        | 43 +++++++------------
 include/wine/server_protocol.h | 40 +++++++++++++++---
 server/clipboard.c             | 76 +++++++++++++++++++---------------
 server/protocol.def            | 21 ++++++++--
 server/request.h               | 21 +++++++---
 server/trace.c                 | 29 ++++++++++++-
 6 files changed, 153 insertions(+), 77 deletions(-)

diff --git a/dlls/user32/clipboard.c b/dlls/user32/clipboard.c
index 47647845ee1..915c370ea62 100644
--- a/dlls/user32/clipboard.c
+++ b/dlls/user32/clipboard.c
@@ -172,33 +172,24 @@ INT WINAPI GetClipboardFormatNameA(UINT wFormat, LPSTR retStr, INT maxlen)
 
 /**************************************************************************
  *		OpenClipboard (USER32.@)
- *
- * Note: Netscape uses NULL hWnd to open the clipboard.
  */
-BOOL WINAPI OpenClipboard( HWND hWnd )
+BOOL WINAPI OpenClipboard( HWND hwnd )
 {
-    BOOL bRet;
-    UINT flags;
+    BOOL ret;
 
-    TRACE("(%p)...\n", hWnd);
+    TRACE( "%p\n", hwnd );
 
-    SERVER_START_REQ( set_clipboard_info )
+    SERVER_START_REQ( open_clipboard )
     {
-        req->flags = SET_CB_OPEN;
-        req->clipboard = wine_server_user_handle( hWnd );
-        if ((bRet = !wine_server_call( req )))
-            flags = reply->flags;
+        req->window = wine_server_user_handle( hwnd );
+        if ((ret = !wine_server_call( req )))
+        {
+            if (!reply->owner) bCBHasChanged = FALSE;
+        }
     }
     SERVER_END_REQ;
 
-    if (bRet && !(flags & CB_PROCESS))
-    {
-        bCBHasChanged = FALSE;
-    }
-
-    TRACE(" returning %i\n", bRet);
-
-    return bRet;
+    return ret;
 }
 
 
@@ -208,26 +199,24 @@ BOOL WINAPI OpenClipboard( HWND hWnd )
 BOOL WINAPI CloseClipboard(void)
 {
     HWND viewer = 0;
-    UINT flags;
-    BOOL ret;
+    BOOL ret, owner = FALSE;
 
     TRACE("() Changed=%d\n", bCBHasChanged);
 
-    SERVER_START_REQ( set_clipboard_info )
+    SERVER_START_REQ( close_clipboard )
     {
-        req->flags = SET_CB_CLOSE;
-        if (bCBHasChanged) req->flags |= SET_CB_SEQNO;
+        req->changed = bCBHasChanged;
         if ((ret = !wine_server_call_err( req )))
         {
-            viewer = wine_server_ptr_handle( reply->old_viewer );
-            flags = reply->flags;
+            viewer = wine_server_ptr_handle( reply->viewer );
+            owner = reply->owner;
         }
     }
     SERVER_END_REQ;
 
     if (!ret) return FALSE;
 
-    if (bCBHasChanged && (flags & CB_PROCESS))
+    if (bCBHasChanged && owner)
     {
         USER_Driver->pEndClipboardUpdate();
         if (viewer) SendNotifyMessageW(viewer, WM_DRAWCLIPBOARD, (WPARAM) GetClipboardOwner(), 0);
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 8f5b7aa7f1e..6576eb901c9 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -4460,14 +4460,40 @@ struct set_class_info_reply
 
 
 
+struct open_clipboard_request
+{
+    struct request_header __header;
+    user_handle_t  window;
+};
+struct open_clipboard_reply
+{
+    struct reply_header __header;
+    int            owner;
+    char __pad_12[4];
+};
+
+
+
+struct close_clipboard_request
+{
+    struct request_header __header;
+    int            changed;
+};
+struct close_clipboard_reply
+{
+    struct reply_header __header;
+    user_handle_t  viewer;
+    int            owner;
+};
+
+
+
 struct set_clipboard_info_request
 {
     struct request_header __header;
     unsigned int   flags;
-    user_handle_t  clipboard;
     user_handle_t  owner;
     user_handle_t  viewer;
-    unsigned int   seqno;
 };
 struct set_clipboard_info_reply
 {
@@ -4480,11 +4506,9 @@ struct set_clipboard_info_reply
     char __pad_28[4];
 };
 
-#define SET_CB_OPEN      0x001
 #define SET_CB_VIEWER    0x004
 #define SET_CB_SEQNO     0x008
 #define SET_CB_RELOWNER  0x010
-#define SET_CB_CLOSE     0x020
 #define CB_OPEN          0x040
 #define CB_OWNER         0x080
 #define CB_PROCESS       0x100
@@ -5631,6 +5655,8 @@ enum request
     REQ_create_class,
     REQ_destroy_class,
     REQ_set_class_info,
+    REQ_open_clipboard,
+    REQ_close_clipboard,
     REQ_set_clipboard_info,
     REQ_empty_clipboard,
     REQ_open_token,
@@ -5911,6 +5937,8 @@ union generic_request
     struct create_class_request create_class_request;
     struct destroy_class_request destroy_class_request;
     struct set_class_info_request set_class_info_request;
+    struct open_clipboard_request open_clipboard_request;
+    struct close_clipboard_request close_clipboard_request;
     struct set_clipboard_info_request set_clipboard_info_request;
     struct empty_clipboard_request empty_clipboard_request;
     struct open_token_request open_token_request;
@@ -6189,6 +6217,8 @@ union generic_reply
     struct create_class_reply create_class_reply;
     struct destroy_class_reply destroy_class_reply;
     struct set_class_info_reply set_class_info_reply;
+    struct open_clipboard_reply open_clipboard_reply;
+    struct close_clipboard_reply close_clipboard_reply;
     struct set_clipboard_info_reply set_clipboard_info_reply;
     struct empty_clipboard_reply empty_clipboard_reply;
     struct open_token_reply open_token_reply;
@@ -6250,6 +6280,6 @@ union generic_reply
     struct terminate_job_reply terminate_job_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 509
+#define SERVER_PROTOCOL_VERSION 510
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/clipboard.c b/server/clipboard.c
index 7b92706eaea..423892531c6 100644
--- a/server/clipboard.c
+++ b/server/clipboard.c
@@ -137,31 +137,6 @@ void cleanup_clipboard_thread(struct thread *thread)
     release_object( winstation );
 }
 
-static int open_clipboard( struct clipboard *clipboard, user_handle_t win )
-{
-    win = get_user_full_handle( win );
-    if (clipboard->open_thread && clipboard->open_win != win)
-    {
-        set_error(STATUS_WAS_LOCKED);
-        return 0;
-    }
-    clipboard->open_win = win;
-    clipboard->open_thread = current;
-    return 1;
-}
-
-static int close_clipboard( struct clipboard *clipboard )
-{
-    if (clipboard->open_thread != current)
-    {
-        set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
-        return 0;
-    }
-    clipboard->open_thread = NULL;
-    clipboard->open_win = 0;
-    return 1;
-}
-
 static int release_clipboard_owner( struct clipboard *clipboard, user_handle_t win )
 {
     if ((clipboard->open_thread && clipboard->open_thread->process != current->process) ||
@@ -187,24 +162,57 @@ static int get_seqno( struct clipboard *clipboard )
 }
 
 
-DECL_HANDLER(set_clipboard_info)
+/* open the clipboard */
+DECL_HANDLER(open_clipboard)
 {
     struct clipboard *clipboard = get_process_clipboard();
+    user_handle_t win;
 
     if (!clipboard) return;
+    win = get_user_full_handle( req->window );
 
-    reply->old_clipboard = clipboard->open_win;
-    reply->old_owner     = clipboard->owner_win;
-    reply->old_viewer    = clipboard->viewer;
-
-    if (req->flags & SET_CB_OPEN)
+    if (clipboard->open_thread && clipboard->open_win != win)
     {
-        if (!open_clipboard( clipboard, req->clipboard )) return;
+        set_error( STATUS_WAS_LOCKED );
+        return;
     }
-    else if (req->flags & SET_CB_CLOSE)
+    clipboard->open_win = win;
+    clipboard->open_thread = current;
+
+    reply->owner = (clipboard->owner_thread && clipboard->owner_thread->process == current->process);
+}
+
+
+/* close the clipboard */
+DECL_HANDLER(close_clipboard)
+{
+    struct clipboard *clipboard = get_process_clipboard();
+
+    if (!clipboard) return;
+
+    if (clipboard->open_thread != current)
     {
-        if (!close_clipboard( clipboard )) return;
+        set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
+        return;
     }
+    if (req->changed) clipboard->seqno++;
+    clipboard->open_thread = NULL;
+    clipboard->open_win = 0;
+
+    reply->viewer = clipboard->viewer;
+    reply->owner  = (clipboard->owner_thread && clipboard->owner_thread->process == current->process);
+}
+
+
+DECL_HANDLER(set_clipboard_info)
+{
+    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_RELOWNER)
     {
diff --git a/server/protocol.def b/server/protocol.def
index 8f285488229..4b800de59f7 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -3158,13 +3158,28 @@ enum caret_state
 #define SET_CLASS_EXTRA     0x0010
 
 
+/* Open the clipboard */
+@REQ(open_clipboard)
+    user_handle_t  window;         /* clipboard window */
+@REPLY
+    int            owner;          /* is the process already the owner? */
+@END
+
+
+/* Close the clipboard */
+@REQ(close_clipboard)
+    int            changed;        /* did it change since the open? */
+@REPLY
+    user_handle_t  viewer;         /* first clipboard viewer */
+    int            owner;          /* is the process already the owner? */
+@END
+
+
 /* Set/get clipboard information */
 @REQ(set_clipboard_info)
     unsigned int   flags;       /* flags for fields to set (see below) */
-    user_handle_t  clipboard;   /* clipboard window */
     user_handle_t  owner;       /* clipboard owner */
     user_handle_t  viewer;      /* first clipboard viewer */
-    unsigned int   seqno;       /* change sequence number */
 @REPLY
     unsigned int   flags;           /* status flags (see below) */
     user_handle_t  old_clipboard;   /* old clipboard window */
@@ -3173,11 +3188,9 @@ enum caret_state
     unsigned int   seqno;           /* current sequence number */
 @END
 
-#define SET_CB_OPEN      0x001
 #define SET_CB_VIEWER    0x004
 #define SET_CB_SEQNO     0x008
 #define SET_CB_RELOWNER  0x010
-#define SET_CB_CLOSE     0x020
 #define CB_OPEN          0x040
 #define CB_OWNER         0x080
 #define CB_PROCESS       0x100
diff --git a/server/request.h b/server/request.h
index d55b7e7ee13..4f0055c26f4 100644
--- a/server/request.h
+++ b/server/request.h
@@ -326,6 +326,8 @@ DECL_HANDLER(get_hook_info);
 DECL_HANDLER(create_class);
 DECL_HANDLER(destroy_class);
 DECL_HANDLER(set_class_info);
+DECL_HANDLER(open_clipboard);
+DECL_HANDLER(close_clipboard);
 DECL_HANDLER(set_clipboard_info);
 DECL_HANDLER(empty_clipboard);
 DECL_HANDLER(open_token);
@@ -605,6 +607,8 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
     (req_handler)req_create_class,
     (req_handler)req_destroy_class,
     (req_handler)req_set_class_info,
+    (req_handler)req_open_clipboard,
+    (req_handler)req_close_clipboard,
     (req_handler)req_set_clipboard_info,
     (req_handler)req_empty_clipboard,
     (req_handler)req_open_token,
@@ -2010,12 +2014,19 @@ C_ASSERT( FIELD_OFFSET(struct set_class_info_reply, old_win_extra) == 20 );
 C_ASSERT( FIELD_OFFSET(struct set_class_info_reply, old_instance) == 24 );
 C_ASSERT( FIELD_OFFSET(struct set_class_info_reply, old_extra_value) == 32 );
 C_ASSERT( sizeof(struct set_class_info_reply) == 40 );
+C_ASSERT( FIELD_OFFSET(struct open_clipboard_request, window) == 12 );
+C_ASSERT( sizeof(struct open_clipboard_request) == 16 );
+C_ASSERT( FIELD_OFFSET(struct open_clipboard_reply, owner) == 8 );
+C_ASSERT( sizeof(struct open_clipboard_reply) == 16 );
+C_ASSERT( FIELD_OFFSET(struct close_clipboard_request, changed) == 12 );
+C_ASSERT( sizeof(struct close_clipboard_request) == 16 );
+C_ASSERT( FIELD_OFFSET(struct close_clipboard_reply, viewer) == 8 );
+C_ASSERT( FIELD_OFFSET(struct close_clipboard_reply, owner) == 12 );
+C_ASSERT( sizeof(struct close_clipboard_reply) == 16 );
 C_ASSERT( FIELD_OFFSET(struct set_clipboard_info_request, flags) == 12 );
-C_ASSERT( FIELD_OFFSET(struct set_clipboard_info_request, clipboard) == 16 );
-C_ASSERT( FIELD_OFFSET(struct set_clipboard_info_request, owner) == 20 );
-C_ASSERT( FIELD_OFFSET(struct set_clipboard_info_request, viewer) == 24 );
-C_ASSERT( FIELD_OFFSET(struct set_clipboard_info_request, seqno) == 28 );
-C_ASSERT( sizeof(struct set_clipboard_info_request) == 32 );
+C_ASSERT( FIELD_OFFSET(struct set_clipboard_info_request, owner) == 16 );
+C_ASSERT( FIELD_OFFSET(struct set_clipboard_info_request, viewer) == 20 );
+C_ASSERT( sizeof(struct set_clipboard_info_request) == 24 );
 C_ASSERT( FIELD_OFFSET(struct set_clipboard_info_reply, flags) == 8 );
 C_ASSERT( FIELD_OFFSET(struct set_clipboard_info_reply, old_clipboard) == 12 );
 C_ASSERT( FIELD_OFFSET(struct set_clipboard_info_reply, old_owner) == 16 );
diff --git a/server/trace.c b/server/trace.c
index 4d8a2eb8185..dea9dce2f12 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -3734,13 +3734,32 @@ static void dump_set_class_info_reply( const struct set_class_info_reply *req )
     dump_uint64( ", old_extra_value=", &req->old_extra_value );
 }
 
+static void dump_open_clipboard_request( const struct open_clipboard_request *req )
+{
+    fprintf( stderr, " window=%08x", req->window );
+}
+
+static void dump_open_clipboard_reply( const struct open_clipboard_reply *req )
+{
+    fprintf( stderr, " owner=%d", req->owner );
+}
+
+static void dump_close_clipboard_request( const struct close_clipboard_request *req )
+{
+    fprintf( stderr, " changed=%d", req->changed );
+}
+
+static void dump_close_clipboard_reply( const struct close_clipboard_reply *req )
+{
+    fprintf( stderr, " viewer=%08x", req->viewer );
+    fprintf( stderr, ", owner=%d", req->owner );
+}
+
 static void dump_set_clipboard_info_request( const struct set_clipboard_info_request *req )
 {
     fprintf( stderr, " flags=%08x", req->flags );
-    fprintf( stderr, ", clipboard=%08x", req->clipboard );
     fprintf( stderr, ", owner=%08x", req->owner );
     fprintf( stderr, ", viewer=%08x", req->viewer );
-    fprintf( stderr, ", seqno=%08x", req->seqno );
 }
 
 static void dump_set_clipboard_info_reply( const struct set_clipboard_info_reply *req )
@@ -4579,6 +4598,8 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_create_class_request,
     (dump_func)dump_destroy_class_request,
     (dump_func)dump_set_class_info_request,
+    (dump_func)dump_open_clipboard_request,
+    (dump_func)dump_close_clipboard_request,
     (dump_func)dump_set_clipboard_info_request,
     (dump_func)dump_empty_clipboard_request,
     (dump_func)dump_open_token_request,
@@ -4855,6 +4876,8 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_create_class_reply,
     (dump_func)dump_destroy_class_reply,
     (dump_func)dump_set_class_info_reply,
+    (dump_func)dump_open_clipboard_reply,
+    (dump_func)dump_close_clipboard_reply,
     (dump_func)dump_set_clipboard_info_reply,
     NULL,
     (dump_func)dump_open_token_reply,
@@ -5131,6 +5154,8 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
     "create_class",
     "destroy_class",
     "set_class_info",
+    "open_clipboard",
+    "close_clipboard",
     "set_clipboard_info",
     "empty_clipboard",
     "open_token",
-- 
GitLab