clipboard.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. /*
  2. * Server-side clipboard management
  3. *
  4. * Copyright 2002 Ulrich Czekalla
  5. * Copyright 2016 Alexandre Julliard
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  20. */
  21. #include "config.h"
  22. #include "wine/port.h"
  23. #include <assert.h>
  24. #include <stdlib.h>
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include "ntstatus.h"
  28. #define WIN32_NO_STATUS
  29. #include "request.h"
  30. #include "object.h"
  31. #include "file.h"
  32. #include "process.h"
  33. #include "user.h"
  34. #include "winuser.h"
  35. #include "winternl.h"
  36. struct clip_format
  37. {
  38. struct list entry; /* entry in format list */
  39. unsigned int id; /* format id */
  40. unsigned int from; /* for synthesized data, format to generate it from */
  41. unsigned int seqno; /* sequence number when the data was set */
  42. data_size_t size; /* size of the data block */
  43. void *data; /* data contents, or NULL for delay-rendered */
  44. };
  45. struct clipboard
  46. {
  47. struct object obj; /* object header */
  48. struct thread *open_thread; /* thread id that has clipboard open */
  49. user_handle_t open_win; /* window that has clipboard open */
  50. user_handle_t owner; /* window that owns the clipboard */
  51. user_handle_t viewer; /* first window in clipboard viewer list */
  52. unsigned int lcid; /* locale id to use for synthesizing text formats */
  53. unsigned int seqno; /* clipboard change sequence number */
  54. unsigned int open_seqno; /* sequence number at open time */
  55. unsigned int rendering; /* format rendering recursion counter */
  56. struct list formats; /* list of data formats */
  57. unsigned int format_count; /* count of data formats */
  58. unsigned int format_map; /* existence bitmap for formats < CF_MAX */
  59. unsigned int listen_size; /* size of listeners array */
  60. unsigned int listen_count; /* count of listeners */
  61. user_handle_t *listeners; /* array of listener windows */
  62. };
  63. static void clipboard_dump( struct object *obj, int verbose );
  64. static void clipboard_destroy( struct object *obj );
  65. static const struct object_ops clipboard_ops =
  66. {
  67. sizeof(struct clipboard), /* size */
  68. clipboard_dump, /* dump */
  69. no_get_type, /* get_type */
  70. no_add_queue, /* add_queue */
  71. NULL, /* remove_queue */
  72. NULL, /* signaled */
  73. NULL, /* get_esync_fd */
  74. NULL, /* satisfied */
  75. no_signal, /* signal */
  76. no_get_fd, /* get_fd */
  77. no_map_access, /* map_access */
  78. default_get_sd, /* get_sd */
  79. default_set_sd, /* set_sd */
  80. no_lookup_name, /* lookup_name */
  81. no_link_name, /* link_name */
  82. NULL, /* unlink_name */
  83. no_open_file, /* open_file */
  84. no_kernel_obj_list, /* get_kernel_obj_list */
  85. no_alloc_handle, /* alloc_handle */
  86. no_close_handle, /* close_handle */
  87. clipboard_destroy /* destroy */
  88. };
  89. #define HAS_FORMAT(map,id) ((map) & (1 << (id))) /* only for formats < CF_MAX */
  90. /* find a data format in the clipboard */
  91. static struct clip_format *get_format( struct clipboard *clipboard, unsigned int id )
  92. {
  93. struct clip_format *format;
  94. LIST_FOR_EACH_ENTRY( format, &clipboard->formats, struct clip_format, entry )
  95. if (format->id == id) return format;
  96. return NULL;
  97. }
  98. /* add a data format to the clipboard */
  99. static struct clip_format *add_format( struct clipboard *clipboard, unsigned int id )
  100. {
  101. struct clip_format *format;
  102. if (!(format = mem_alloc( sizeof(*format )))) return NULL;
  103. format->id = id;
  104. format->from = 0;
  105. format->size = 0;
  106. format->data = NULL;
  107. list_add_tail( &clipboard->formats, &format->entry );
  108. clipboard->format_count++;
  109. if (id < CF_MAX) clipboard->format_map |= 1 << id;
  110. return format;
  111. }
  112. /* free all clipboard formats */
  113. static void free_clipboard_formats( struct clipboard *clipboard )
  114. {
  115. struct clip_format *format, *next;
  116. LIST_FOR_EACH_ENTRY_SAFE( format, next, &clipboard->formats, struct clip_format, entry )
  117. {
  118. list_remove( &format->entry );
  119. free( format->data );
  120. free( format );
  121. }
  122. clipboard->format_count = 0;
  123. clipboard->format_map = 0;
  124. }
  125. /* dump a clipboard object */
  126. static void clipboard_dump( struct object *obj, int verbose )
  127. {
  128. struct clipboard *clipboard = (struct clipboard *)obj;
  129. fprintf( stderr, "Clipboard open_thread=%p open_win=%08x owner=%08x viewer=%08x seq=%u\n",
  130. clipboard->open_thread, clipboard->open_win,
  131. clipboard->owner, clipboard->viewer, clipboard->seqno );
  132. }
  133. static void clipboard_destroy( struct object *obj )
  134. {
  135. struct clipboard *clipboard = (struct clipboard *)obj;
  136. free( clipboard->listeners );
  137. free_clipboard_formats( clipboard );
  138. }
  139. /* retrieve the clipboard info for the current process, allocating it if needed */
  140. static struct clipboard *get_process_clipboard(void)
  141. {
  142. struct clipboard *clipboard;
  143. struct winstation *winstation = get_process_winstation( current->process, WINSTA_ACCESSCLIPBOARD );
  144. if (!winstation) return NULL;
  145. if (!(clipboard = winstation->clipboard))
  146. {
  147. if ((clipboard = alloc_object( &clipboard_ops )))
  148. {
  149. clipboard->open_thread = NULL;
  150. clipboard->open_win = 0;
  151. clipboard->owner = 0;
  152. clipboard->viewer = 0;
  153. clipboard->seqno = 0;
  154. clipboard->format_count = 0;
  155. clipboard->format_map = 0;
  156. clipboard->listen_size = 0;
  157. clipboard->listen_count = 0;
  158. clipboard->listeners = NULL;
  159. list_init( &clipboard->formats );
  160. winstation->clipboard = clipboard;
  161. }
  162. }
  163. release_object( winstation );
  164. return clipboard;
  165. }
  166. /* add synthesized formats upon clipboard close */
  167. static int synthesize_formats( struct clipboard *clipboard )
  168. {
  169. static const unsigned int formats[][3] =
  170. {
  171. { CF_TEXT, CF_OEMTEXT, CF_UNICODETEXT },
  172. { CF_OEMTEXT, CF_UNICODETEXT, CF_TEXT },
  173. { CF_UNICODETEXT, CF_TEXT, CF_OEMTEXT },
  174. { CF_METAFILEPICT, CF_ENHMETAFILE },
  175. { CF_ENHMETAFILE, CF_METAFILEPICT },
  176. { CF_BITMAP, CF_DIB, CF_DIBV5 },
  177. { CF_DIB, CF_BITMAP, CF_DIBV5 },
  178. { CF_DIBV5, CF_BITMAP, CF_DIB }
  179. };
  180. unsigned int i, from, total = 0, map = clipboard->format_map;
  181. struct clip_format *format;
  182. if (!HAS_FORMAT( map, CF_LOCALE ) &&
  183. (HAS_FORMAT( map, CF_TEXT ) || HAS_FORMAT( map, CF_OEMTEXT ) || HAS_FORMAT( map, CF_UNICODETEXT )))
  184. {
  185. void *data = memdup( &clipboard->lcid, sizeof(clipboard->lcid) );
  186. if (data && (format = add_format( clipboard, CF_LOCALE )))
  187. {
  188. format->seqno = clipboard->seqno++;
  189. format->data = data;
  190. format->size = sizeof(clipboard->lcid);
  191. }
  192. else free( data );
  193. }
  194. for (i = 0; i < ARRAY_SIZE( formats ); i++)
  195. {
  196. if (HAS_FORMAT( map, formats[i][0] )) continue;
  197. if (HAS_FORMAT( map, formats[i][1] )) from = formats[i][1];
  198. else if (HAS_FORMAT( map, formats[i][2] )) from = formats[i][2];
  199. else continue;
  200. if (!(format = add_format( clipboard, formats[i][0] ))) continue;
  201. format->from = from;
  202. format->seqno = clipboard->seqno;
  203. total++;
  204. }
  205. return total;
  206. }
  207. /* add a clipboard listener */
  208. static void add_listener( struct clipboard *clipboard, user_handle_t window )
  209. {
  210. unsigned int i;
  211. for (i = 0; i < clipboard->listen_count; i++)
  212. {
  213. if (clipboard->listeners[i] != window) continue;
  214. set_error( STATUS_INVALID_PARAMETER ); /* already set */
  215. return;
  216. }
  217. if (clipboard->listen_size == clipboard->listen_count)
  218. {
  219. unsigned int new_size = max( 8, clipboard->listen_size * 2 );
  220. user_handle_t *new = realloc( clipboard->listeners, new_size * sizeof(*new) );
  221. if (!new)
  222. {
  223. set_error( STATUS_NO_MEMORY );
  224. return;
  225. }
  226. clipboard->listeners = new;
  227. clipboard->listen_size = new_size;
  228. }
  229. clipboard->listeners[clipboard->listen_count++] = window;
  230. }
  231. /* remove a clipboard listener */
  232. static int remove_listener( struct clipboard *clipboard, user_handle_t window )
  233. {
  234. unsigned int i;
  235. for (i = 0; i < clipboard->listen_count; i++)
  236. {
  237. if (clipboard->listeners[i] != window) continue;
  238. memmove( clipboard->listeners + i, clipboard->listeners + i + 1,
  239. (clipboard->listen_count - i - 1) * sizeof(*clipboard->listeners) );
  240. clipboard->listen_count--;
  241. return 1;
  242. }
  243. return 0;
  244. }
  245. /* notify all listeners, and return the viewer window that should be notified if any */
  246. static user_handle_t notify_listeners( struct clipboard *clipboard )
  247. {
  248. unsigned int i;
  249. for (i = 0; i < clipboard->listen_count; i++)
  250. post_message( clipboard->listeners[i], WM_CLIPBOARDUPDATE, 0, 0 );
  251. return clipboard->viewer;
  252. }
  253. /* close the clipboard, and return the viewer window that should be notified if any */
  254. static user_handle_t close_clipboard( struct clipboard *clipboard )
  255. {
  256. clipboard->open_win = 0;
  257. clipboard->open_thread = NULL;
  258. if (clipboard->seqno == clipboard->open_seqno) return 0; /* unchanged */
  259. if (synthesize_formats( clipboard )) clipboard->seqno++;
  260. return notify_listeners( clipboard );
  261. }
  262. /* release the clipboard owner, and return the viewer window that should be notified if any */
  263. static user_handle_t release_clipboard( struct clipboard *clipboard )
  264. {
  265. struct clip_format *format, *next;
  266. int changed = 0;
  267. clipboard->owner = 0;
  268. /* free the delayed-rendered formats, since we no longer have an owner to render them */
  269. LIST_FOR_EACH_ENTRY_SAFE( format, next, &clipboard->formats, struct clip_format, entry )
  270. {
  271. if (format->data || format->from) continue;
  272. list_remove( &format->entry );
  273. if (format->id < CF_MAX) clipboard->format_map &= ~(1 << format->id);
  274. clipboard->format_count--;
  275. free( format );
  276. changed = 1;
  277. }
  278. if (!changed) return 0;
  279. clipboard->seqno++;
  280. return notify_listeners( clipboard );
  281. }
  282. /* cleanup clipboard information upon window destruction */
  283. void cleanup_clipboard_window( struct desktop *desktop, user_handle_t window )
  284. {
  285. struct clipboard *clipboard = desktop->winstation->clipboard;
  286. if (!clipboard) return;
  287. remove_listener( clipboard, window );
  288. if (clipboard->viewer == window) clipboard->viewer = 0;
  289. if (clipboard->owner == window) release_clipboard( clipboard );
  290. if (clipboard->open_win == window)
  291. {
  292. user_handle_t viewer = close_clipboard( clipboard );
  293. if (viewer) send_notify_message( viewer, WM_DRAWCLIPBOARD, clipboard->owner, 0 );
  294. }
  295. }
  296. /* Called when thread terminates to allow release of clipboard */
  297. void cleanup_clipboard_thread(struct thread *thread)
  298. {
  299. struct clipboard *clipboard;
  300. struct winstation *winstation;
  301. if (!thread->process->winstation) return;
  302. if (!(winstation = get_process_winstation( thread->process, WINSTA_ACCESSCLIPBOARD ))) return;
  303. if ((clipboard = winstation->clipboard))
  304. {
  305. if (thread == clipboard->open_thread)
  306. {
  307. user_handle_t viewer = close_clipboard( clipboard );
  308. if (viewer) send_notify_message( viewer, WM_DRAWCLIPBOARD, clipboard->owner, 0 );
  309. }
  310. }
  311. release_object( winstation );
  312. }
  313. /* open the clipboard */
  314. DECL_HANDLER(open_clipboard)
  315. {
  316. struct clipboard *clipboard = get_process_clipboard();
  317. user_handle_t win = 0;
  318. if (!clipboard) return;
  319. if (req->window && !(win = get_valid_window_handle( req->window ))) return;
  320. if (clipboard->open_thread && clipboard->open_win != win)
  321. {
  322. set_error( STATUS_INVALID_LOCK_SEQUENCE );
  323. return;
  324. }
  325. if (!clipboard->open_thread) clipboard->open_seqno = clipboard->seqno; /* first open */
  326. if (clipboard->open_thread != current) clipboard->rendering = 0;
  327. clipboard->open_win = win;
  328. clipboard->open_thread = current;
  329. reply->owner = clipboard->owner;
  330. }
  331. /* close the clipboard */
  332. DECL_HANDLER(close_clipboard)
  333. {
  334. struct clipboard *clipboard = get_process_clipboard();
  335. if (!clipboard) return;
  336. if (clipboard->open_thread != current)
  337. {
  338. set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
  339. return;
  340. }
  341. reply->viewer = close_clipboard( clipboard );
  342. reply->owner = clipboard->owner;
  343. }
  344. /* add a data format to the clipboard */
  345. DECL_HANDLER(set_clipboard_data)
  346. {
  347. struct clip_format *format;
  348. struct clipboard *clipboard = get_process_clipboard();
  349. void *data = NULL;
  350. if (!clipboard) return;
  351. if (!req->format || !clipboard->open_thread)
  352. {
  353. set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
  354. return;
  355. }
  356. if (get_req_data_size() && !(data = memdup( get_req_data(), get_req_data_size() ))) return;
  357. if (!(format = get_format( clipboard, req->format )))
  358. {
  359. if (!(format = add_format( clipboard, req->format )))
  360. {
  361. free( data );
  362. return;
  363. }
  364. }
  365. free( format->data );
  366. format->from = 0;
  367. format->seqno = clipboard->seqno;
  368. format->size = get_req_data_size();
  369. format->data = data;
  370. if (!clipboard->rendering) clipboard->seqno++;
  371. if (req->format == CF_TEXT || req->format == CF_OEMTEXT || req->format == CF_UNICODETEXT)
  372. clipboard->lcid = req->lcid;
  373. reply->seqno = format->seqno;
  374. }
  375. /* fetch a data format from the clipboard */
  376. DECL_HANDLER(get_clipboard_data)
  377. {
  378. struct clip_format *format;
  379. struct clipboard *clipboard = get_process_clipboard();
  380. if (!clipboard) return;
  381. if (clipboard->open_thread != current)
  382. {
  383. set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
  384. return;
  385. }
  386. if (!(format = get_format( clipboard, req->format )))
  387. {
  388. set_error( STATUS_OBJECT_NAME_NOT_FOUND );
  389. goto done;
  390. }
  391. reply->from = format->from;
  392. reply->total = format->size;
  393. reply->seqno = format->seqno;
  394. reply->owner = clipboard->owner;
  395. if (!format->data && req->render) /* try rendering it client-side */
  396. {
  397. if (format->from || clipboard->owner) clipboard->rendering++;
  398. return;
  399. }
  400. if (req->cached && req->seqno == format->seqno) goto done; /* client-side cache still valid */
  401. if (format->size > get_reply_max_size())
  402. {
  403. set_error( STATUS_BUFFER_OVERFLOW );
  404. return;
  405. }
  406. set_reply_data( format->data, format->size );
  407. done:
  408. if (!req->render) clipboard->rendering--;
  409. }
  410. /* retrieve a list of available formats */
  411. DECL_HANDLER(get_clipboard_formats)
  412. {
  413. struct clipboard *clipboard = get_process_clipboard();
  414. if (!clipboard) return;
  415. if (!req->format)
  416. {
  417. struct clip_format *format;
  418. unsigned int i = 0, *ptr;
  419. data_size_t size = clipboard->format_count * sizeof(unsigned int);
  420. reply->count = clipboard->format_count;
  421. if (size <= get_reply_max_size())
  422. {
  423. if ((ptr = mem_alloc( size )))
  424. {
  425. LIST_FOR_EACH_ENTRY( format, &clipboard->formats, struct clip_format, entry )
  426. ptr[i++] = format->id;
  427. assert( i == clipboard->format_count );
  428. set_reply_data_ptr( ptr, size );
  429. }
  430. }
  431. else set_error( STATUS_BUFFER_TOO_SMALL );
  432. }
  433. else reply->count = (get_format( clipboard, req->format ) != NULL); /* query a single format */
  434. }
  435. /* retrieve the next available format */
  436. DECL_HANDLER(enum_clipboard_formats)
  437. {
  438. struct list *ptr;
  439. struct clipboard *clipboard = get_process_clipboard();
  440. if (!clipboard) return;
  441. if (clipboard->open_thread != current)
  442. {
  443. set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
  444. return;
  445. }
  446. ptr = list_head( &clipboard->formats );
  447. if (req->previous)
  448. {
  449. while (ptr && LIST_ENTRY( ptr, struct clip_format, entry )->id != req->previous)
  450. ptr = list_next( &clipboard->formats, ptr );
  451. if (ptr) ptr = list_next( &clipboard->formats, ptr );
  452. }
  453. if (ptr) reply->format = LIST_ENTRY( ptr, struct clip_format, entry )->id;
  454. }
  455. /* empty the clipboard and grab ownership */
  456. DECL_HANDLER(empty_clipboard)
  457. {
  458. struct clipboard *clipboard = get_process_clipboard();
  459. if (!clipboard) return;
  460. if (clipboard->open_thread != current)
  461. {
  462. set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
  463. return;
  464. }
  465. free_clipboard_formats( clipboard );
  466. clipboard->owner = clipboard->open_win;
  467. clipboard->seqno++;
  468. }
  469. /* release ownership of the clipboard */
  470. DECL_HANDLER(release_clipboard)
  471. {
  472. struct clipboard *clipboard = get_process_clipboard();
  473. user_handle_t owner;
  474. if (!clipboard) return;
  475. if (!(owner = get_valid_window_handle( req->owner ))) return;
  476. if (clipboard->owner == owner)
  477. {
  478. reply->viewer = release_clipboard( clipboard );
  479. reply->owner = clipboard->owner;
  480. }
  481. else set_error( STATUS_INVALID_OWNER );
  482. }
  483. /* get clipboard information */
  484. DECL_HANDLER(get_clipboard_info)
  485. {
  486. struct clipboard *clipboard = get_process_clipboard();
  487. if (!clipboard) return;
  488. reply->window = clipboard->open_win;
  489. reply->owner = clipboard->owner;
  490. reply->viewer = clipboard->viewer;
  491. reply->seqno = clipboard->seqno;
  492. }
  493. /* set the clipboard viewer window */
  494. DECL_HANDLER(set_clipboard_viewer)
  495. {
  496. struct clipboard *clipboard = get_process_clipboard();
  497. user_handle_t viewer = 0, previous = 0;
  498. if (!clipboard) return;
  499. if (req->viewer && !(viewer = get_valid_window_handle( req->viewer ))) return;
  500. if (req->previous && !(previous = get_valid_window_handle( req->previous ))) return;
  501. reply->old_viewer = clipboard->viewer;
  502. reply->owner = clipboard->owner;
  503. if (!previous || clipboard->viewer == previous)
  504. clipboard->viewer = viewer;
  505. else
  506. set_error( STATUS_PENDING ); /* need to send message instead */
  507. }
  508. /* add a clipboard listener window */
  509. DECL_HANDLER(add_clipboard_listener)
  510. {
  511. struct clipboard *clipboard = get_process_clipboard();
  512. user_handle_t win;
  513. if (!clipboard) return;
  514. if (!(win = get_valid_window_handle( req->window ))) return;
  515. add_listener( clipboard, win );
  516. }
  517. /* remove a clipboard listener window */
  518. DECL_HANDLER(remove_clipboard_listener)
  519. {
  520. struct clipboard *clipboard = get_process_clipboard();
  521. user_handle_t win;
  522. if (!clipboard) return;
  523. if (!(win = get_valid_window_handle( req->window ))) return;
  524. if (!remove_listener( clipboard, win )) set_error( STATUS_INVALID_PARAMETER );
  525. }