user32: Store clipboard data on the server side.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
ac005d460d
commit
79f90e4e41
|
@ -93,6 +93,76 @@ static const char *debugstr_format( UINT id )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* build the data to send to the server in SetClipboardData */
|
||||||
|
static HANDLE marshal_data( UINT format, HANDLE handle, data_size_t *ret_size )
|
||||||
|
{
|
||||||
|
SIZE_T size;
|
||||||
|
|
||||||
|
switch (format)
|
||||||
|
{
|
||||||
|
case CF_BITMAP:
|
||||||
|
case CF_DSPBITMAP:
|
||||||
|
{
|
||||||
|
BITMAP bitmap, *bm;
|
||||||
|
if (!GetObjectW( handle, sizeof(bitmap), &bitmap )) return 0;
|
||||||
|
size = abs( bitmap.bmHeight ) * ((((bitmap.bmWidth * bitmap.bmBitsPixel) + 15) >> 3) & ~1);
|
||||||
|
*ret_size = sizeof(bitmap) + size;
|
||||||
|
if (!(bm = GlobalAlloc( GMEM_FIXED, *ret_size ))) return 0;
|
||||||
|
*bm = bitmap;
|
||||||
|
GetBitmapBits( handle, size, bm + 1 );
|
||||||
|
return bm;
|
||||||
|
}
|
||||||
|
case CF_PALETTE:
|
||||||
|
{
|
||||||
|
LOGPALETTE *pal;
|
||||||
|
if (!(size = GetPaletteEntries( handle, 0, 0, NULL ))) return 0;
|
||||||
|
*ret_size = offsetof( LOGPALETTE, palPalEntry[size] );
|
||||||
|
if (!(pal = GlobalAlloc( GMEM_FIXED, *ret_size ))) return 0;
|
||||||
|
pal->palVersion = 0x300;
|
||||||
|
pal->palNumEntries = size;
|
||||||
|
GetPaletteEntries( handle, 0, size, pal->palPalEntry );
|
||||||
|
return pal;
|
||||||
|
}
|
||||||
|
case CF_ENHMETAFILE:
|
||||||
|
case CF_DSPENHMETAFILE:
|
||||||
|
{
|
||||||
|
BYTE *ret;
|
||||||
|
if (!(size = GetEnhMetaFileBits( handle, 0, NULL ))) return 0;
|
||||||
|
if (!(ret = GlobalAlloc( GMEM_FIXED, size ))) return 0;
|
||||||
|
GetEnhMetaFileBits( handle, size, ret );
|
||||||
|
*ret_size = size;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case CF_METAFILEPICT:
|
||||||
|
case CF_DSPMETAFILEPICT:
|
||||||
|
{
|
||||||
|
METAFILEPICT *mf, *mfbits;
|
||||||
|
if (!(mf = GlobalLock( handle ))) return 0;
|
||||||
|
if (!(size = GetMetaFileBitsEx( mf->hMF, 0, NULL )))
|
||||||
|
{
|
||||||
|
GlobalUnlock( handle );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*ret_size = sizeof(*mf) + size;
|
||||||
|
if (!(mfbits = GlobalAlloc( GMEM_FIXED, *ret_size )))
|
||||||
|
{
|
||||||
|
GlobalUnlock( handle );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*mfbits = *mf;
|
||||||
|
GetMetaFileBitsEx( mf->hMF, size, mfbits + 1 );
|
||||||
|
GlobalUnlock( handle );
|
||||||
|
return mfbits;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if (!(size = GlobalSize( handle ))) return 0;
|
||||||
|
if ((data_size_t)size != size) return 0;
|
||||||
|
*ret_size = size;
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* formats that can be synthesized are: CF_TEXT, CF_OEMTEXT, CF_UNICODETEXT,
|
/* formats that can be synthesized are: CF_TEXT, CF_OEMTEXT, CF_UNICODETEXT,
|
||||||
CF_BITMAP, CF_DIB, CF_DIBV5, CF_ENHMETAFILE, CF_METAFILEPICT */
|
CF_BITMAP, CF_DIB, CF_DIBV5, CF_ENHMETAFILE, CF_METAFILEPICT */
|
||||||
|
|
||||||
|
@ -563,7 +633,6 @@ BOOL WINAPI CloseClipboard(void)
|
||||||
|
|
||||||
SERVER_START_REQ( close_clipboard )
|
SERVER_START_REQ( close_clipboard )
|
||||||
{
|
{
|
||||||
req->changed = bCBHasChanged;
|
|
||||||
if ((ret = !wine_server_call_err( req )))
|
if ((ret = !wine_server_call_err( req )))
|
||||||
{
|
{
|
||||||
viewer = wine_server_ptr_handle( reply->viewer );
|
viewer = wine_server_ptr_handle( reply->viewer );
|
||||||
|
@ -727,32 +796,38 @@ BOOL WINAPI ChangeClipboardChain( HWND hwnd, HWND next )
|
||||||
*/
|
*/
|
||||||
HANDLE WINAPI SetClipboardData( UINT format, HANDLE data )
|
HANDLE WINAPI SetClipboardData( UINT format, HANDLE data )
|
||||||
{
|
{
|
||||||
HANDLE hResult = 0;
|
void *ptr = NULL;
|
||||||
UINT flags;
|
data_size_t size = 0;
|
||||||
|
HANDLE handle = data, retval = 0;
|
||||||
|
BOOL ret;
|
||||||
|
|
||||||
TRACE( "%s %p\n", debugstr_format( format ), data );
|
TRACE( "%s %p\n", debugstr_format( format ), data );
|
||||||
|
|
||||||
if (!format)
|
if (data)
|
||||||
{
|
{
|
||||||
SetLastError( ERROR_CLIPBOARD_NOT_OPEN );
|
if (!(handle = marshal_data( format, data, &size ))) return 0;
|
||||||
return 0;
|
if (!(ptr = GlobalLock( handle ))) goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
flags = get_clipboard_flags();
|
SERVER_START_REQ( set_clipboard_data )
|
||||||
if (!(flags & CB_OPEN_ANY))
|
|
||||||
{
|
{
|
||||||
SetLastError( ERROR_CLIPBOARD_NOT_OPEN );
|
req->format = format;
|
||||||
return 0;
|
wine_server_add_data( req, ptr, size );
|
||||||
|
ret = !wine_server_call_err( req );
|
||||||
}
|
}
|
||||||
|
SERVER_END_REQ;
|
||||||
|
|
||||||
if (USER_Driver->pSetClipboardData( format, data, flags & CB_OWNER))
|
if (ret && USER_Driver->pSetClipboardData( format, data, TRUE ))
|
||||||
{
|
{
|
||||||
hResult = data;
|
|
||||||
bCBHasChanged = TRUE;
|
bCBHasChanged = TRUE;
|
||||||
if (format < CF_MAX) synthesized_formats[format] = 0;
|
if (format < CF_MAX) synthesized_formats[format] = 0;
|
||||||
|
retval = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return hResult;
|
done:
|
||||||
|
if (ptr) GlobalUnlock( ptr );
|
||||||
|
if (handle != data) GlobalFree( handle );
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -207,7 +207,7 @@ static LRESULT CALLBACK winproc_wrapper( HWND hwnd, UINT msg, WPARAM wp, LPARAM
|
||||||
{
|
{
|
||||||
case WM_DESTROY:
|
case WM_DESTROY:
|
||||||
ok( wm_renderallformats, "didn't receive WM_RENDERALLFORMATS before WM_DESTROY\n" );
|
ok( wm_renderallformats, "didn't receive WM_RENDERALLFORMATS before WM_DESTROY\n" );
|
||||||
todo_wine ok( wm_drawclipboard, "didn't receive WM_DRAWCLIPBOARD before WM_DESTROY\n" );
|
ok( wm_drawclipboard, "didn't receive WM_DRAWCLIPBOARD before WM_DESTROY\n" );
|
||||||
break;
|
break;
|
||||||
case WM_DRAWCLIPBOARD:
|
case WM_DRAWCLIPBOARD:
|
||||||
ok( msg_flags == ISMEX_NOSEND, "WM_DRAWCLIPBOARD wrong flags %x\n", msg_flags );
|
ok( msg_flags == ISMEX_NOSEND, "WM_DRAWCLIPBOARD wrong flags %x\n", msg_flags );
|
||||||
|
@ -1092,7 +1092,7 @@ static DWORD WINAPI clipboard_thread(void *param)
|
||||||
if (pGetClipboardSequenceNumber)
|
if (pGetClipboardSequenceNumber)
|
||||||
{
|
{
|
||||||
seq = pGetClipboardSequenceNumber();
|
seq = pGetClipboardSequenceNumber();
|
||||||
todo_wine ok( (int)(seq - old_seq) == 1, "sequence diff %d\n", seq - old_seq );
|
ok( (int)(seq - old_seq) == 1, "sequence diff %d\n", seq - old_seq );
|
||||||
old_seq = seq;
|
old_seq = seq;
|
||||||
}
|
}
|
||||||
if (!cross_thread)
|
if (!cross_thread)
|
||||||
|
@ -1114,7 +1114,7 @@ static DWORD WINAPI clipboard_thread(void *param)
|
||||||
if (pGetClipboardSequenceNumber)
|
if (pGetClipboardSequenceNumber)
|
||||||
{
|
{
|
||||||
seq = pGetClipboardSequenceNumber();
|
seq = pGetClipboardSequenceNumber();
|
||||||
todo_wine ok( (int)(seq - old_seq) == 1, "sequence diff %d\n", seq - old_seq );
|
ok( (int)(seq - old_seq) == 1, "sequence diff %d\n", seq - old_seq );
|
||||||
old_seq = seq;
|
old_seq = seq;
|
||||||
}
|
}
|
||||||
if (!cross_thread)
|
if (!cross_thread)
|
||||||
|
@ -1136,7 +1136,7 @@ static DWORD WINAPI clipboard_thread(void *param)
|
||||||
if (pGetClipboardSequenceNumber)
|
if (pGetClipboardSequenceNumber)
|
||||||
{
|
{
|
||||||
seq = pGetClipboardSequenceNumber();
|
seq = pGetClipboardSequenceNumber();
|
||||||
todo_wine ok( (int)(seq - old_seq) == 1, "sequence diff %d\n", seq - old_seq );
|
ok( (int)(seq - old_seq) == 1, "sequence diff %d\n", seq - old_seq );
|
||||||
old_seq = seq;
|
old_seq = seq;
|
||||||
}
|
}
|
||||||
if (!cross_thread)
|
if (!cross_thread)
|
||||||
|
@ -1165,7 +1165,7 @@ static DWORD WINAPI clipboard_thread(void *param)
|
||||||
if (pGetClipboardSequenceNumber)
|
if (pGetClipboardSequenceNumber)
|
||||||
{
|
{
|
||||||
seq = pGetClipboardSequenceNumber();
|
seq = pGetClipboardSequenceNumber();
|
||||||
todo_wine ok( (int)(seq - old_seq) == 2, "sequence diff %d\n", seq - old_seq );
|
ok( (int)(seq - old_seq) == 2, "sequence diff %d\n", seq - old_seq );
|
||||||
old_seq = seq;
|
old_seq = seq;
|
||||||
}
|
}
|
||||||
if (!cross_thread)
|
if (!cross_thread)
|
||||||
|
@ -1222,7 +1222,7 @@ static DWORD WINAPI clipboard_thread(void *param)
|
||||||
if (pGetClipboardSequenceNumber)
|
if (pGetClipboardSequenceNumber)
|
||||||
{
|
{
|
||||||
seq = pGetClipboardSequenceNumber();
|
seq = pGetClipboardSequenceNumber();
|
||||||
todo_wine ok( (int)(seq - old_seq) == 1, "sequence diff %d\n", seq - old_seq );
|
ok( (int)(seq - old_seq) == 1, "sequence diff %d\n", seq - old_seq );
|
||||||
old_seq = seq;
|
old_seq = seq;
|
||||||
}
|
}
|
||||||
if (!cross_thread)
|
if (!cross_thread)
|
||||||
|
@ -1245,7 +1245,7 @@ static DWORD WINAPI clipboard_thread(void *param)
|
||||||
{
|
{
|
||||||
/* no synthesized format, so CloseClipboard doesn't change the sequence */
|
/* no synthesized format, so CloseClipboard doesn't change the sequence */
|
||||||
seq = pGetClipboardSequenceNumber();
|
seq = pGetClipboardSequenceNumber();
|
||||||
todo_wine ok( seq == old_seq, "sequence changed\n" );
|
ok( seq == old_seq, "sequence changed\n" );
|
||||||
old_seq = seq;
|
old_seq = seq;
|
||||||
}
|
}
|
||||||
if (!cross_thread)
|
if (!cross_thread)
|
||||||
|
@ -1347,7 +1347,7 @@ static DWORD WINAPI clipboard_thread(void *param)
|
||||||
if (pGetClipboardSequenceNumber)
|
if (pGetClipboardSequenceNumber)
|
||||||
{
|
{
|
||||||
seq = pGetClipboardSequenceNumber();
|
seq = pGetClipboardSequenceNumber();
|
||||||
todo_wine ok( seq == old_seq, "sequence changed\n" );
|
ok( seq == old_seq, "sequence changed\n" );
|
||||||
old_seq = seq;
|
old_seq = seq;
|
||||||
}
|
}
|
||||||
if (!cross_thread)
|
if (!cross_thread)
|
||||||
|
@ -1395,7 +1395,7 @@ static DWORD WINAPI clipboard_thread(void *param)
|
||||||
if (pGetClipboardSequenceNumber)
|
if (pGetClipboardSequenceNumber)
|
||||||
{
|
{
|
||||||
seq = pGetClipboardSequenceNumber();
|
seq = pGetClipboardSequenceNumber();
|
||||||
todo_wine ok( (int)(seq - old_seq) == 1, "sequence diff %d\n", seq - old_seq );
|
ok( (int)(seq - old_seq) == 1, "sequence diff %d\n", seq - old_seq );
|
||||||
old_seq = seq;
|
old_seq = seq;
|
||||||
}
|
}
|
||||||
if (!cross_thread)
|
if (!cross_thread)
|
||||||
|
@ -1420,7 +1420,7 @@ static DWORD WINAPI clipboard_thread(void *param)
|
||||||
if (pGetClipboardSequenceNumber)
|
if (pGetClipboardSequenceNumber)
|
||||||
{
|
{
|
||||||
seq = pGetClipboardSequenceNumber();
|
seq = pGetClipboardSequenceNumber();
|
||||||
todo_wine ok( seq == old_seq, "sequence changed\n" );
|
ok( seq == old_seq, "sequence changed\n" );
|
||||||
old_seq = seq;
|
old_seq = seq;
|
||||||
}
|
}
|
||||||
if (!cross_thread)
|
if (!cross_thread)
|
||||||
|
@ -1442,7 +1442,6 @@ static DWORD WINAPI clipboard_thread(void *param)
|
||||||
if (pGetClipboardSequenceNumber)
|
if (pGetClipboardSequenceNumber)
|
||||||
{
|
{
|
||||||
seq = pGetClipboardSequenceNumber();
|
seq = pGetClipboardSequenceNumber();
|
||||||
todo_wine_if (!cross_thread)
|
|
||||||
ok( (int)(seq - old_seq) == 2, "sequence diff %d\n", seq - old_seq );
|
ok( (int)(seq - old_seq) == 2, "sequence diff %d\n", seq - old_seq );
|
||||||
old_seq = seq;
|
old_seq = seq;
|
||||||
}
|
}
|
||||||
|
@ -1469,7 +1468,7 @@ static DWORD WINAPI clipboard_thread(void *param)
|
||||||
if (pGetClipboardSequenceNumber)
|
if (pGetClipboardSequenceNumber)
|
||||||
{
|
{
|
||||||
seq = pGetClipboardSequenceNumber();
|
seq = pGetClipboardSequenceNumber();
|
||||||
todo_wine ok( (int)(seq - old_seq) == 1, "sequence diff %d\n", seq - old_seq );
|
ok( (int)(seq - old_seq) == 1, "sequence diff %d\n", seq - old_seq );
|
||||||
old_seq = seq;
|
old_seq = seq;
|
||||||
}
|
}
|
||||||
if (!cross_thread)
|
if (!cross_thread)
|
||||||
|
@ -1494,7 +1493,7 @@ static DWORD WINAPI clipboard_thread(void *param)
|
||||||
if (pGetClipboardSequenceNumber)
|
if (pGetClipboardSequenceNumber)
|
||||||
{
|
{
|
||||||
seq = pGetClipboardSequenceNumber();
|
seq = pGetClipboardSequenceNumber();
|
||||||
todo_wine ok( seq == old_seq, "sequence changed\n" );
|
ok( seq == old_seq, "sequence changed\n" );
|
||||||
old_seq = seq;
|
old_seq = seq;
|
||||||
}
|
}
|
||||||
if (!cross_thread)
|
if (!cross_thread)
|
||||||
|
@ -1670,7 +1669,7 @@ static void test_handles( HWND hwnd )
|
||||||
ok( h == htext5, "got %p\n", h );
|
ok( h == htext5, "got %p\n", h );
|
||||||
ok( is_moveable( h ), "expected moveable mem %p\n", h );
|
ok( is_moveable( h ), "expected moveable mem %p\n", h );
|
||||||
h = SetClipboardData( format_id2, empty_moveable );
|
h = SetClipboardData( format_id2, empty_moveable );
|
||||||
todo_wine ok( !h, "got %p\n", h );
|
ok( !h, "got %p\n", h );
|
||||||
GlobalFree( empty_moveable );
|
GlobalFree( empty_moveable );
|
||||||
|
|
||||||
if (0) /* crashes on vista64 */
|
if (0) /* crashes on vista64 */
|
||||||
|
|
|
@ -4477,7 +4477,7 @@ struct open_clipboard_reply
|
||||||
struct close_clipboard_request
|
struct close_clipboard_request
|
||||||
{
|
{
|
||||||
struct request_header __header;
|
struct request_header __header;
|
||||||
int changed;
|
char __pad_12[4];
|
||||||
};
|
};
|
||||||
struct close_clipboard_reply
|
struct close_clipboard_reply
|
||||||
{
|
{
|
||||||
|
@ -4527,6 +4527,19 @@ struct empty_clipboard_reply
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct set_clipboard_data_request
|
||||||
|
{
|
||||||
|
struct request_header __header;
|
||||||
|
unsigned int format;
|
||||||
|
/* VARARG(data,bytes); */
|
||||||
|
};
|
||||||
|
struct set_clipboard_data_reply
|
||||||
|
{
|
||||||
|
struct reply_header __header;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct release_clipboard_request
|
struct release_clipboard_request
|
||||||
{
|
{
|
||||||
struct request_header __header;
|
struct request_header __header;
|
||||||
|
@ -5729,6 +5742,7 @@ enum request
|
||||||
REQ_close_clipboard,
|
REQ_close_clipboard,
|
||||||
REQ_set_clipboard_info,
|
REQ_set_clipboard_info,
|
||||||
REQ_empty_clipboard,
|
REQ_empty_clipboard,
|
||||||
|
REQ_set_clipboard_data,
|
||||||
REQ_release_clipboard,
|
REQ_release_clipboard,
|
||||||
REQ_get_clipboard_info,
|
REQ_get_clipboard_info,
|
||||||
REQ_set_clipboard_viewer,
|
REQ_set_clipboard_viewer,
|
||||||
|
@ -6016,6 +6030,7 @@ union generic_request
|
||||||
struct close_clipboard_request close_clipboard_request;
|
struct close_clipboard_request close_clipboard_request;
|
||||||
struct set_clipboard_info_request set_clipboard_info_request;
|
struct set_clipboard_info_request set_clipboard_info_request;
|
||||||
struct empty_clipboard_request empty_clipboard_request;
|
struct empty_clipboard_request empty_clipboard_request;
|
||||||
|
struct set_clipboard_data_request set_clipboard_data_request;
|
||||||
struct release_clipboard_request release_clipboard_request;
|
struct release_clipboard_request release_clipboard_request;
|
||||||
struct get_clipboard_info_request get_clipboard_info_request;
|
struct get_clipboard_info_request get_clipboard_info_request;
|
||||||
struct set_clipboard_viewer_request set_clipboard_viewer_request;
|
struct set_clipboard_viewer_request set_clipboard_viewer_request;
|
||||||
|
@ -6301,6 +6316,7 @@ union generic_reply
|
||||||
struct close_clipboard_reply close_clipboard_reply;
|
struct close_clipboard_reply close_clipboard_reply;
|
||||||
struct set_clipboard_info_reply set_clipboard_info_reply;
|
struct set_clipboard_info_reply set_clipboard_info_reply;
|
||||||
struct empty_clipboard_reply empty_clipboard_reply;
|
struct empty_clipboard_reply empty_clipboard_reply;
|
||||||
|
struct set_clipboard_data_reply set_clipboard_data_reply;
|
||||||
struct release_clipboard_reply release_clipboard_reply;
|
struct release_clipboard_reply release_clipboard_reply;
|
||||||
struct get_clipboard_info_reply get_clipboard_info_reply;
|
struct get_clipboard_info_reply get_clipboard_info_reply;
|
||||||
struct set_clipboard_viewer_reply set_clipboard_viewer_reply;
|
struct set_clipboard_viewer_reply set_clipboard_viewer_reply;
|
||||||
|
@ -6365,6 +6381,6 @@ union generic_reply
|
||||||
struct terminate_job_reply terminate_job_reply;
|
struct terminate_job_reply terminate_job_reply;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SERVER_PROTOCOL_VERSION 517
|
#define SERVER_PROTOCOL_VERSION 518
|
||||||
|
|
||||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
/*
|
/*
|
||||||
* Server-side clipboard management
|
* Server-side clipboard management
|
||||||
*
|
*
|
||||||
* Copyright (C) 2002 Ulrich Czekalla
|
* Copyright 2002 Ulrich Czekalla
|
||||||
|
* Copyright 2016 Alexandre Julliard
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -36,6 +37,14 @@
|
||||||
#include "winuser.h"
|
#include "winuser.h"
|
||||||
#include "winternl.h"
|
#include "winternl.h"
|
||||||
|
|
||||||
|
struct clip_format
|
||||||
|
{
|
||||||
|
struct list entry; /* entry in format list */
|
||||||
|
unsigned int id; /* format id */
|
||||||
|
data_size_t size; /* size of the data block */
|
||||||
|
void *data; /* data contents, or NULL for delay-rendered */
|
||||||
|
};
|
||||||
|
|
||||||
struct clipboard
|
struct clipboard
|
||||||
{
|
{
|
||||||
struct object obj; /* object header */
|
struct object obj; /* object header */
|
||||||
|
@ -46,6 +55,8 @@ struct clipboard
|
||||||
user_handle_t viewer; /* first window in clipboard viewer list */
|
user_handle_t viewer; /* first window in clipboard viewer list */
|
||||||
unsigned int seqno; /* clipboard change sequence number */
|
unsigned int seqno; /* clipboard change sequence number */
|
||||||
unsigned int open_seqno; /* sequence number at open time */
|
unsigned int open_seqno; /* sequence number at open time */
|
||||||
|
struct list formats; /* list of data formats */
|
||||||
|
unsigned int format_count; /* count of data formats */
|
||||||
unsigned int listen_size; /* size of listeners array */
|
unsigned int listen_size; /* size of listeners array */
|
||||||
unsigned int listen_count; /* count of listeners */
|
unsigned int listen_count; /* count of listeners */
|
||||||
user_handle_t *listeners; /* array of listener windows */
|
user_handle_t *listeners; /* array of listener windows */
|
||||||
|
@ -77,6 +88,45 @@ static const struct object_ops clipboard_ops =
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* find a data format in the clipboard */
|
||||||
|
static struct clip_format *get_format( struct clipboard *clipboard, unsigned int id )
|
||||||
|
{
|
||||||
|
struct clip_format *format;
|
||||||
|
|
||||||
|
LIST_FOR_EACH_ENTRY( format, &clipboard->formats, struct clip_format, entry )
|
||||||
|
if (format->id == id) return format;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add a data format to the clipboard */
|
||||||
|
static struct clip_format *add_format( struct clipboard *clipboard, unsigned int id )
|
||||||
|
{
|
||||||
|
struct clip_format *format;
|
||||||
|
|
||||||
|
if (!(format = mem_alloc( sizeof(*format )))) return NULL;
|
||||||
|
format->id = id;
|
||||||
|
format->size = 0;
|
||||||
|
format->data = NULL;
|
||||||
|
list_add_tail( &clipboard->formats, &format->entry );
|
||||||
|
clipboard->format_count++;
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free all clipboard formats */
|
||||||
|
static void free_clipboard_formats( struct clipboard *clipboard )
|
||||||
|
{
|
||||||
|
struct clip_format *format, *next;
|
||||||
|
|
||||||
|
LIST_FOR_EACH_ENTRY_SAFE( format, next, &clipboard->formats, struct clip_format, entry )
|
||||||
|
{
|
||||||
|
list_remove( &format->entry );
|
||||||
|
free( format->data );
|
||||||
|
free( format );
|
||||||
|
}
|
||||||
|
clipboard->format_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* dump a clipboard object */
|
/* dump a clipboard object */
|
||||||
static void clipboard_dump( struct object *obj, int verbose )
|
static void clipboard_dump( struct object *obj, int verbose )
|
||||||
{
|
{
|
||||||
|
@ -92,6 +142,7 @@ static void clipboard_destroy( struct object *obj )
|
||||||
struct clipboard *clipboard = (struct clipboard *)obj;
|
struct clipboard *clipboard = (struct clipboard *)obj;
|
||||||
|
|
||||||
free( clipboard->listeners );
|
free( clipboard->listeners );
|
||||||
|
free_clipboard_formats( clipboard );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* retrieve the clipboard info for the current process, allocating it if needed */
|
/* retrieve the clipboard info for the current process, allocating it if needed */
|
||||||
|
@ -112,9 +163,11 @@ static struct clipboard *get_process_clipboard(void)
|
||||||
clipboard->owner_win = 0;
|
clipboard->owner_win = 0;
|
||||||
clipboard->viewer = 0;
|
clipboard->viewer = 0;
|
||||||
clipboard->seqno = 0;
|
clipboard->seqno = 0;
|
||||||
|
clipboard->format_count = 0;
|
||||||
clipboard->listen_size = 0;
|
clipboard->listen_size = 0;
|
||||||
clipboard->listen_count = 0;
|
clipboard->listen_count = 0;
|
||||||
clipboard->listeners = NULL;
|
clipboard->listeners = NULL;
|
||||||
|
list_init( &clipboard->formats );
|
||||||
winstation->clipboard = clipboard;
|
winstation->clipboard = clipboard;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,28 +217,47 @@ static int remove_listener( struct clipboard *clipboard, user_handle_t window )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* close the clipboard, and return the viewer window that should be notified if any */
|
/* notify all listeners, and return the viewer window that should be notified if any */
|
||||||
static user_handle_t close_clipboard( struct clipboard *clipboard )
|
static user_handle_t notify_listeners( struct clipboard *clipboard )
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
clipboard->open_win = 0;
|
|
||||||
clipboard->open_thread = NULL;
|
|
||||||
|
|
||||||
if (clipboard->seqno == clipboard->open_seqno) return 0; /* unchanged */
|
|
||||||
|
|
||||||
for (i = 0; i < clipboard->listen_count; i++)
|
for (i = 0; i < clipboard->listen_count; i++)
|
||||||
post_message( clipboard->listeners[i], WM_CLIPBOARDUPDATE, 0, 0 );
|
post_message( clipboard->listeners[i], WM_CLIPBOARDUPDATE, 0, 0 );
|
||||||
return clipboard->viewer;
|
return clipboard->viewer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* close the clipboard, and return the viewer window that should be notified if any */
|
||||||
|
static user_handle_t close_clipboard( struct clipboard *clipboard )
|
||||||
|
{
|
||||||
|
clipboard->open_win = 0;
|
||||||
|
clipboard->open_thread = NULL;
|
||||||
|
if (clipboard->seqno == clipboard->open_seqno) return 0; /* unchanged */
|
||||||
|
return notify_listeners( clipboard );
|
||||||
|
}
|
||||||
|
|
||||||
/* release the clipboard owner, and return the viewer window that should be notified if any */
|
/* release the clipboard owner, and return the viewer window that should be notified if any */
|
||||||
static user_handle_t release_clipboard( struct clipboard *clipboard )
|
static user_handle_t release_clipboard( struct clipboard *clipboard )
|
||||||
{
|
{
|
||||||
|
struct clip_format *format, *next;
|
||||||
|
int changed = 0;
|
||||||
|
|
||||||
clipboard->owner_win = 0;
|
clipboard->owner_win = 0;
|
||||||
clipboard->owner_thread = NULL;
|
clipboard->owner_thread = NULL;
|
||||||
/* FIXME: free delay-rendered formats if any and notify listeners */
|
|
||||||
return 0;
|
/* free the delayed-rendered formats, since we no longer have an owner to render them */
|
||||||
|
LIST_FOR_EACH_ENTRY_SAFE( format, next, &clipboard->formats, struct clip_format, entry )
|
||||||
|
{
|
||||||
|
if (format->data) continue;
|
||||||
|
list_remove( &format->entry );
|
||||||
|
clipboard->format_count--;
|
||||||
|
free( format );
|
||||||
|
changed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!changed) return 0;
|
||||||
|
clipboard->seqno++;
|
||||||
|
return notify_listeners( clipboard );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* cleanup clipboard information upon window destruction */
|
/* cleanup clipboard information upon window destruction */
|
||||||
|
@ -275,8 +347,6 @@ DECL_HANDLER(close_clipboard)
|
||||||
set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
|
set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (req->changed) clipboard->seqno++;
|
|
||||||
|
|
||||||
reply->viewer = close_clipboard( clipboard );
|
reply->viewer = close_clipboard( clipboard );
|
||||||
reply->owner = clipboard->owner_win;
|
reply->owner = clipboard->owner_win;
|
||||||
}
|
}
|
||||||
|
@ -309,6 +379,38 @@ DECL_HANDLER(set_clipboard_info)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* add a data format to the clipboard */
|
||||||
|
DECL_HANDLER(set_clipboard_data)
|
||||||
|
{
|
||||||
|
struct clip_format *format;
|
||||||
|
struct clipboard *clipboard = get_process_clipboard();
|
||||||
|
void *data = NULL;
|
||||||
|
|
||||||
|
if (!clipboard) return;
|
||||||
|
|
||||||
|
if (!req->format || !clipboard->open_thread)
|
||||||
|
{
|
||||||
|
set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_req_data_size() && !(data = memdup( get_req_data(), get_req_data_size() ))) return;
|
||||||
|
|
||||||
|
if (!(format = get_format( clipboard, req->format )))
|
||||||
|
{
|
||||||
|
if (!(format = add_format( clipboard, req->format )))
|
||||||
|
{
|
||||||
|
free( data );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clipboard->seqno++;
|
||||||
|
format->size = get_req_data_size();
|
||||||
|
format->data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* empty the clipboard and grab ownership */
|
/* empty the clipboard and grab ownership */
|
||||||
DECL_HANDLER(empty_clipboard)
|
DECL_HANDLER(empty_clipboard)
|
||||||
{
|
{
|
||||||
|
@ -321,6 +423,8 @@ DECL_HANDLER(empty_clipboard)
|
||||||
set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
|
set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free_clipboard_formats( clipboard );
|
||||||
clipboard->owner_win = clipboard->open_win;
|
clipboard->owner_win = clipboard->open_win;
|
||||||
clipboard->owner_thread = clipboard->open_thread;
|
clipboard->owner_thread = clipboard->open_thread;
|
||||||
clipboard->seqno++;
|
clipboard->seqno++;
|
||||||
|
|
|
@ -3168,7 +3168,6 @@ enum caret_state
|
||||||
|
|
||||||
/* Close the clipboard */
|
/* Close the clipboard */
|
||||||
@REQ(close_clipboard)
|
@REQ(close_clipboard)
|
||||||
int changed; /* did it change since the open? */
|
|
||||||
@REPLY
|
@REPLY
|
||||||
user_handle_t viewer; /* first clipboard viewer */
|
user_handle_t viewer; /* first clipboard viewer */
|
||||||
user_handle_t owner; /* current clipboard owner */
|
user_handle_t owner; /* current clipboard owner */
|
||||||
|
@ -3200,6 +3199,13 @@ enum caret_state
|
||||||
@END
|
@END
|
||||||
|
|
||||||
|
|
||||||
|
/* Add a data format to the clipboard */
|
||||||
|
@REQ(set_clipboard_data)
|
||||||
|
unsigned int format; /* clipboard format of the data */
|
||||||
|
VARARG(data,bytes); /* data contents */
|
||||||
|
@END
|
||||||
|
|
||||||
|
|
||||||
/* Release ownership of the clipboard */
|
/* Release ownership of the clipboard */
|
||||||
@REQ(release_clipboard)
|
@REQ(release_clipboard)
|
||||||
user_handle_t owner; /* clipboard owner to release */
|
user_handle_t owner; /* clipboard owner to release */
|
||||||
|
|
|
@ -330,6 +330,7 @@ DECL_HANDLER(open_clipboard);
|
||||||
DECL_HANDLER(close_clipboard);
|
DECL_HANDLER(close_clipboard);
|
||||||
DECL_HANDLER(set_clipboard_info);
|
DECL_HANDLER(set_clipboard_info);
|
||||||
DECL_HANDLER(empty_clipboard);
|
DECL_HANDLER(empty_clipboard);
|
||||||
|
DECL_HANDLER(set_clipboard_data);
|
||||||
DECL_HANDLER(release_clipboard);
|
DECL_HANDLER(release_clipboard);
|
||||||
DECL_HANDLER(get_clipboard_info);
|
DECL_HANDLER(get_clipboard_info);
|
||||||
DECL_HANDLER(set_clipboard_viewer);
|
DECL_HANDLER(set_clipboard_viewer);
|
||||||
|
@ -616,6 +617,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
|
||||||
(req_handler)req_close_clipboard,
|
(req_handler)req_close_clipboard,
|
||||||
(req_handler)req_set_clipboard_info,
|
(req_handler)req_set_clipboard_info,
|
||||||
(req_handler)req_empty_clipboard,
|
(req_handler)req_empty_clipboard,
|
||||||
|
(req_handler)req_set_clipboard_data,
|
||||||
(req_handler)req_release_clipboard,
|
(req_handler)req_release_clipboard,
|
||||||
(req_handler)req_get_clipboard_info,
|
(req_handler)req_get_clipboard_info,
|
||||||
(req_handler)req_set_clipboard_viewer,
|
(req_handler)req_set_clipboard_viewer,
|
||||||
|
@ -2028,7 +2030,6 @@ C_ASSERT( FIELD_OFFSET(struct open_clipboard_request, window) == 12 );
|
||||||
C_ASSERT( sizeof(struct open_clipboard_request) == 16 );
|
C_ASSERT( sizeof(struct open_clipboard_request) == 16 );
|
||||||
C_ASSERT( FIELD_OFFSET(struct open_clipboard_reply, owner) == 8 );
|
C_ASSERT( FIELD_OFFSET(struct open_clipboard_reply, owner) == 8 );
|
||||||
C_ASSERT( sizeof(struct open_clipboard_reply) == 16 );
|
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( sizeof(struct close_clipboard_request) == 16 );
|
||||||
C_ASSERT( FIELD_OFFSET(struct close_clipboard_reply, viewer) == 8 );
|
C_ASSERT( FIELD_OFFSET(struct close_clipboard_reply, viewer) == 8 );
|
||||||
C_ASSERT( FIELD_OFFSET(struct close_clipboard_reply, owner) == 12 );
|
C_ASSERT( FIELD_OFFSET(struct close_clipboard_reply, owner) == 12 );
|
||||||
|
@ -2043,6 +2044,8 @@ C_ASSERT( FIELD_OFFSET(struct set_clipboard_info_reply, old_viewer) == 20 );
|
||||||
C_ASSERT( FIELD_OFFSET(struct set_clipboard_info_reply, seqno) == 24 );
|
C_ASSERT( FIELD_OFFSET(struct set_clipboard_info_reply, seqno) == 24 );
|
||||||
C_ASSERT( sizeof(struct set_clipboard_info_reply) == 32 );
|
C_ASSERT( sizeof(struct set_clipboard_info_reply) == 32 );
|
||||||
C_ASSERT( sizeof(struct empty_clipboard_request) == 16 );
|
C_ASSERT( sizeof(struct empty_clipboard_request) == 16 );
|
||||||
|
C_ASSERT( FIELD_OFFSET(struct set_clipboard_data_request, format) == 12 );
|
||||||
|
C_ASSERT( sizeof(struct set_clipboard_data_request) == 16 );
|
||||||
C_ASSERT( FIELD_OFFSET(struct release_clipboard_request, owner) == 12 );
|
C_ASSERT( FIELD_OFFSET(struct release_clipboard_request, owner) == 12 );
|
||||||
C_ASSERT( sizeof(struct release_clipboard_request) == 16 );
|
C_ASSERT( sizeof(struct release_clipboard_request) == 16 );
|
||||||
C_ASSERT( FIELD_OFFSET(struct release_clipboard_reply, viewer) == 8 );
|
C_ASSERT( FIELD_OFFSET(struct release_clipboard_reply, viewer) == 8 );
|
||||||
|
|
|
@ -3746,7 +3746,6 @@ static void dump_open_clipboard_reply( const struct open_clipboard_reply *req )
|
||||||
|
|
||||||
static void dump_close_clipboard_request( const struct close_clipboard_request *req )
|
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 )
|
static void dump_close_clipboard_reply( const struct close_clipboard_reply *req )
|
||||||
|
@ -3774,6 +3773,12 @@ static void dump_empty_clipboard_request( const struct empty_clipboard_request *
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dump_set_clipboard_data_request( const struct set_clipboard_data_request *req )
|
||||||
|
{
|
||||||
|
fprintf( stderr, " format=%08x", req->format );
|
||||||
|
dump_varargs_bytes( ", data=", cur_size );
|
||||||
|
}
|
||||||
|
|
||||||
static void dump_release_clipboard_request( const struct release_clipboard_request *req )
|
static void dump_release_clipboard_request( const struct release_clipboard_request *req )
|
||||||
{
|
{
|
||||||
fprintf( stderr, " owner=%08x", req->owner );
|
fprintf( stderr, " owner=%08x", req->owner );
|
||||||
|
@ -4646,6 +4651,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
||||||
(dump_func)dump_close_clipboard_request,
|
(dump_func)dump_close_clipboard_request,
|
||||||
(dump_func)dump_set_clipboard_info_request,
|
(dump_func)dump_set_clipboard_info_request,
|
||||||
(dump_func)dump_empty_clipboard_request,
|
(dump_func)dump_empty_clipboard_request,
|
||||||
|
(dump_func)dump_set_clipboard_data_request,
|
||||||
(dump_func)dump_release_clipboard_request,
|
(dump_func)dump_release_clipboard_request,
|
||||||
(dump_func)dump_get_clipboard_info_request,
|
(dump_func)dump_get_clipboard_info_request,
|
||||||
(dump_func)dump_set_clipboard_viewer_request,
|
(dump_func)dump_set_clipboard_viewer_request,
|
||||||
|
@ -4929,6 +4935,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
||||||
(dump_func)dump_close_clipboard_reply,
|
(dump_func)dump_close_clipboard_reply,
|
||||||
(dump_func)dump_set_clipboard_info_reply,
|
(dump_func)dump_set_clipboard_info_reply,
|
||||||
NULL,
|
NULL,
|
||||||
|
NULL,
|
||||||
(dump_func)dump_release_clipboard_reply,
|
(dump_func)dump_release_clipboard_reply,
|
||||||
(dump_func)dump_get_clipboard_info_reply,
|
(dump_func)dump_get_clipboard_info_reply,
|
||||||
(dump_func)dump_set_clipboard_viewer_reply,
|
(dump_func)dump_set_clipboard_viewer_reply,
|
||||||
|
@ -5212,6 +5219,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
|
||||||
"close_clipboard",
|
"close_clipboard",
|
||||||
"set_clipboard_info",
|
"set_clipboard_info",
|
||||||
"empty_clipboard",
|
"empty_clipboard",
|
||||||
|
"set_clipboard_data",
|
||||||
"release_clipboard",
|
"release_clipboard",
|
||||||
"get_clipboard_info",
|
"get_clipboard_info",
|
||||||
"set_clipboard_viewer",
|
"set_clipboard_viewer",
|
||||||
|
|
Loading…
Reference in New Issue