clipboard.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  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. &no_type, /* type */
  69. clipboard_dump, /* dump */
  70. no_add_queue, /* add_queue */
  71. NULL, /* remove_queue */
  72. NULL, /* signaled */
  73. NULL, /* satisfied */
  74. no_signal, /* signal */
  75. no_get_fd, /* get_fd */
  76. default_map_access, /* map_access */
  77. default_get_sd, /* get_sd */
  78. default_set_sd, /* set_sd */
  79. no_get_full_name, /* get_full_name */
  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_close_handle, /* close_handle */
  86. clipboard_destroy /* destroy */
  87. };
  88. #define HAS_FORMAT(map,id) ((map) & (1 << (id))) /* only for formats < CF_MAX */
  89. /* find a data format in the clipboard */
  90. static struct clip_format *get_format( struct clipboard *clipboard, unsigned int id )
  91. {
  92. struct clip_format *format;
  93. LIST_FOR_EACH_ENTRY( format, &clipboard->formats, struct clip_format, entry )
  94. if (format->id == id) return format;
  95. return NULL;
  96. }
  97. /* add a data format to the clipboard */
  98. static struct clip_format *add_format( struct clipboard *clipboard, unsigned int id )
  99. {
  100. struct clip_format *format;
  101. if (!(format = mem_alloc( sizeof(*format )))) return NULL;
  102. format->id = id;
  103. format->from = 0;
  104. format->size = 0;
  105. format->data = NULL;
  106. list_add_tail( &clipboard->formats, &format->entry );
  107. clipboard->format_count++;
  108. if (id < CF_MAX) clipboard->format_map |= 1 << id;
  109. return format;
  110. }
  111. /* free all clipboard formats */
  112. static void free_clipboard_formats( struct clipboard *clipboard )
  113. {
  114. struct clip_format *format, *next;
  115. LIST_FOR_EACH_ENTRY_SAFE( format, next, &clipboard->formats, struct clip_format, entry )
  116. {
  117. list_remove( &format->entry );
  118. free( format->data );
  119. free( format );
  120. }
  121. clipboard->format_count = 0;
  122. clipboard->format_map = 0;
  123. }
  124. /* dump a clipboard object */
  125. static void clipboard_dump( struct object *obj, int verbose )
  126. {
  127. struct clipboard *clipboard = (struct clipboard *)obj;
  128. fprintf( stderr, "Clipboard open_thread=%p open_win=%08x owner=%08x viewer=%08x seq=%u\n",
  129. clipboard->open_thread, clipboard->open_win,
  130. clipboard->owner, clipboard->viewer, clipboard->seqno );
  131. }
  132. static void clipboard_destroy( struct object *obj )
  133. {
  134. struct clipboard *clipboard = (struct clipboard *)obj;
  135. free( clipboard->listeners );
  136. free_clipboard_formats( clipboard );
  137. }
  138. /* retrieve the clipboard info for the current process, allocating it if needed */
  139. static struct clipboard *get_process_clipboard(void)
  140. {
  141. struct clipboard *clipboard;
  142. struct winstation *winstation = get_process_winstation( current->process, WINSTA_ACCESSCLIPBOARD );
  143. if (!winstation) return NULL;
  144. if (!(clipboard = winstation->clipboard))
  145. {
  146. if ((clipboard = alloc_object( &clipboard_ops )))
  147. {
  148. clipboard->open_thread = NULL;
  149. clipboard->open_win = 0;
  150. clipboard->owner = 0;
  151. clipboard->viewer = 0;
  152. clipboard->seqno = 0;
  153. clipboard->format_count = 0;
  154. clipboard->format_map = 0;
  155. clipboard->listen_size = 0;
  156. clipboard->listen_count = 0;
  157. clipboard->listeners = NULL;
  158. list_init( &clipboard->formats );
  159. winstation->clipboard = clipboard;
  160. }
  161. }
  162. release_object( winstation );
  163. return clipboard;
  164. }
  165. /* add synthesized formats upon clipboard close */
  166. static int synthesize_formats( struct clipboard *clipboard )
  167. {
  168. static const unsigned int formats[][3] =
  169. {
  170. { CF_TEXT, CF_OEMTEXT, CF_UNICODETEXT },
  171. { CF_OEMTEXT, CF_UNICODETEXT, CF_TEXT },
  172. { CF_UNICODETEXT, CF_TEXT, CF_OEMTEXT },
  173. { CF_METAFILEPICT, CF_ENHMETAFILE },
  174. { CF_ENHMETAFILE, CF_METAFILEPICT },
  175. { CF_BITMAP, CF_DIB, CF_DIBV5 },
  176. { CF_DIB, CF_BITMAP, CF_DIBV5 },
  177. { CF_DIBV5, CF_BITMAP, CF_DIB }
  178. };
  179. unsigned int i, from, total = 0, map = clipboard->format_map;
  180. struct clip_format *format;
  181. if (!HAS_FORMAT( map, CF_LOCALE ) &&
  182. (HAS_FORMAT( map, CF_TEXT ) || HAS_FORMAT( map, CF_OEMTEXT ) || HAS_FORMAT( map, CF_UNICODETEXT )))
  183. {
  184. void *data = memdup( &clipboard->lcid, sizeof(clipboard->lcid) );
  185. if (data && (format = add_format( clipboard, CF_LOCALE )))
  186. {
  187. format->seqno = clipboard->seqno++;
  188. format->data = data;
  189. format->size = sizeof(clipboard->lcid);
  190. }
  191. else free( data );
  192. }
  193. for (i = 0; i < ARRAY_SIZE( formats ); i++)
  194. {
  195. if (HAS_FORMAT( map, formats[i][0] )) continue;
  196. if (HAS_FORMAT( map, formats[i][1] )) from = formats[i][1];
  197. else if (HAS_FORMAT( map, formats[i][2] )) from = formats[i][2];
  198. else continue;
  199. if (!(format = add_format( clipboard, formats[i][0] ))) continue;
  200. format->from = from;
  201. format->seqno = clipboard->seqno;
  202. total++;
  203. }
  204. return total;
  205. }
  206. /* add a clipboard listener */
  207. static void add_listener( struct clipboard *clipboard, user_handle_t window )
  208. {
  209. unsigned int i;
  210. for (i = 0; i < clipboard->listen_count; i++)
  211. {
  212. if (clipboard->listeners[i] != window) continue;
  213. set_error( STATUS_INVALID_PARAMETER ); /* already set */
  214. return;
  215. }
  216. if (clipboard->listen_size == clipboard->listen_count)
  217. {
  218. unsigned int new_size = max( 8, clipboard->listen_size * 2 );
  219. user_handle_t *new = realloc( clipboard->listeners, new_size * sizeof(*new) );
  220. if (!new)
  221. {
  222. set_error( STATUS_NO_MEMORY );
  223. return;
  224. }
  225. clipboard->listeners = new;
  226. clipboard->listen_size = new_size;
  227. }
  228. clipboard->listeners[clipboard->listen_count++] = window;
  229. }
  230. /* remove a clipboard listener */
  231. static int remove_listener( struct clipboard *clipboard, user_handle_t window )
  232. {
  233. unsigned int i;
  234. for (i = 0; i < clipboard->listen_count; i++)
  235. {
  236. if (clipboard->listeners[i] != window) continue;
  237. memmove( clipboard->listeners + i, clipboard->listeners + i + 1,
  238. (clipboard->listen_count - i - 1) * sizeof(*clipboard->listeners) );
  239. clipboard->listen_count--;
  240. return 1;
  241. }
  242. return 0;
  243. }
  244. /* notify all listeners, and return the viewer window that should be notified if any */
  245. static user_handle_t notify_listeners( struct clipboard *clipboard )
  246. {
  247. unsigned int i;
  248. for (i = 0; i < clipboard->listen_count; i++)
  249. post_message( clipboard->listeners[i], WM_CLIPBOARDUPDATE, 0, 0 );
  250. return clipboard->viewer;
  251. }
  252. /* close the clipboard, and return the viewer window that should be notified if any */
  253. static user_handle_t close_clipboard( struct clipboard *clipboard )
  254. {
  255. clipboard->open_win = 0;
  256. clipboard->open_thread = NULL;
  257. if (clipboard->seqno == clipboard->open_seqno) return 0; /* unchanged */
  258. if (synthesize_formats( clipboard )) clipboard->seqno++;
  259. return notify_listeners( clipboard );
  260. }
  261. /* release the clipboard owner, and return the viewer window that should be notified if any */
  262. static user_handle_t release_clipboard( struct clipboard *clipboard )
  263. {
  264. struct clip_format *format, *next;
  265. int changed = 0;
  266. clipboard->owner = 0;
  267. /* free the delayed-rendered formats, since we no longer have an owner to render them */
  268. LIST_FOR_EACH_ENTRY_SAFE( format, next, &clipboard->formats, struct clip_format, entry )
  269. {
  270. if (format->data || format->from) continue;
  271. list_remove( &format->entry );
  272. if (format->id < CF_MAX) clipboard->format_map &= ~(1 << format->id);
  273. clipboard->format_count--;
  274. free( format );
  275. changed = 1;
  276. }
  277. if (!changed) return 0;
  278. clipboard->seqno++;
  279. return notify_listeners( clipboard );
  280. }
  281. /* cleanup clipboard information upon window destruction */
  282. void cleanup_clipboard_window( struct desktop *desktop, user_handle_t window )
  283. {
  284. struct clipboard *clipboard = desktop->winstation->clipboard;
  285. if (!clipboard) return;
  286. remove_listener( clipboard, window );
  287. if (clipboard->viewer == window) clipboard->viewer = 0;
  288. if (clipboard->owner == window) release_clipboard( clipboard );
  289. if (clipboard->open_win == window)
  290. {
  291. user_handle_t viewer = close_clipboard( clipboard );
  292. if (viewer) send_notify_message( viewer, WM_DRAWCLIPBOARD, clipboard->owner, 0 );
  293. }
  294. }
  295. /* Called when thread terminates to allow release of clipboard */
  296. void cleanup_clipboard_thread(struct thread *thread)
  297. {
  298. struct clipboard *clipboard;
  299. struct winstation *winstation;
  300. if (!thread->process->winstation) return;
  301. if (!(winstation = get_process_winstation( thread->process, WINSTA_ACCESSCLIPBOARD ))) return;
  302. if ((clipboard = winstation->clipboard))
  303. {
  304. if (thread == clipboard->open_thread)
  305. {
  306. user_handle_t viewer = close_clipboard( clipboard );
  307. if (viewer) send_notify_message( viewer, WM_DRAWCLIPBOARD, clipboard->owner, 0 );
  308. }
  309. }
  310. release_object( winstation );
  311. }
  312. /* open the clipboard */
  313. DECL_HANDLER(open_clipboard)
  314. {
  315. struct clipboard *clipboard = get_process_clipboard();
  316. user_handle_t win = 0;
  317. if (!clipboard) return;
  318. if (req->window && !(win = get_valid_window_handle( req->window ))) return;
  319. if (clipboard->open_thread && clipboard->open_win != win)
  320. {
  321. set_error( STATUS_INVALID_LOCK_SEQUENCE );
  322. return;
  323. }
  324. if (!clipboard->open_thread) clipboard->open_seqno = clipboard->seqno; /* first open */
  325. if (clipboard->open_thread != current) clipboard->rendering = 0;
  326. clipboard->open_win = win;
  327. clipboard->open_thread = current;
  328. reply->owner = clipboard->owner;
  329. }
  330. /* close the clipboard */
  331. DECL_HANDLER(close_clipboard)
  332. {
  333. struct clipboard *clipboard = get_process_clipboard();
  334. if (!clipboard) return;
  335. if (clipboard->open_thread != current)
  336. {
  337. set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
  338. return;
  339. }
  340. reply->viewer = close_clipboard( clipboard );
  341. reply->owner = clipboard->owner;
  342. }
  343. /* add a data format to the clipboard */
  344. DECL_HANDLER(set_clipboard_data)
  345. {
  346. struct clip_format *format;
  347. struct clipboard *clipboard = get_process_clipboard();
  348. void *data = NULL;
  349. if (!clipboard) return;
  350. if (!req->format || !clipboard->open_thread)
  351. {
  352. set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
  353. return;
  354. }
  355. if (get_req_data_size() && !(data = memdup( get_req_data(), get_req_data_size() ))) return;
  356. if (!(format = get_format( clipboard, req->format )))
  357. {
  358. if (!(format = add_format( clipboard, req->format )))
  359. {
  360. free( data );
  361. return;
  362. }
  363. }
  364. free( format->data );
  365. format->from = 0;
  366. format->seqno = clipboard->seqno;
  367. format->size = get_req_data_size();
  368. format->data = data;
  369. if (!clipboard->rendering) clipboard->seqno++;
  370. if (req->format == CF_TEXT || req->format == CF_OEMTEXT || req->format == CF_UNICODETEXT)
  371. clipboard->lcid = req->lcid;
  372. reply->seqno = format->seqno;
  373. }
  374. /* fetch a data format from the clipboard */
  375. DECL_HANDLER(get_clipboard_data)
  376. {
  377. struct clip_format *format;
  378. struct clipboard *clipboard = get_process_clipboard();
  379. if (!clipboard) return;
  380. if (clipboard->open_thread != current)
  381. {
  382. set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
  383. return;
  384. }
  385. if (!(format = get_format( clipboard, req->format )))
  386. {
  387. set_error( STATUS_OBJECT_NAME_NOT_FOUND );
  388. goto done;
  389. }
  390. reply->from = format->from;
  391. reply->total = format->size;
  392. reply->seqno = format->seqno;
  393. reply->owner = clipboard->owner;
  394. if (!format->data && req->render) /* try rendering it client-side */
  395. {
  396. if (format->from || clipboard->owner) clipboard->rendering++;
  397. return;
  398. }
  399. if (req->cached && req->seqno == format->seqno) goto done; /* client-side cache still valid */
  400. if (format->size > get_reply_max_size())
  401. {
  402. set_error( STATUS_BUFFER_OVERFLOW );
  403. return;
  404. }
  405. set_reply_data( format->data, format->size );
  406. done:
  407. if (!req->render) clipboard->rendering--;
  408. }
  409. /* retrieve a list of available formats */
  410. DECL_HANDLER(get_clipboard_formats)
  411. {
  412. struct clipboard *clipboard = get_process_clipboard();
  413. if (!clipboard) return;
  414. if (!req->format)
  415. {
  416. struct clip_format *format;
  417. unsigned int i = 0, *ptr;
  418. data_size_t size = clipboard->format_count * sizeof(unsigned int);
  419. reply->count = clipboard->format_count;
  420. if (size <= get_reply_max_size())
  421. {
  422. if ((ptr = mem_alloc( size )))
  423. {
  424. LIST_FOR_EACH_ENTRY( format, &clipboard->formats, struct clip_format, entry )
  425. ptr[i++] = format->id;
  426. assert( i == clipboard->format_count );
  427. set_reply_data_ptr( ptr, size );
  428. }
  429. }
  430. else set_error( STATUS_BUFFER_TOO_SMALL );
  431. }
  432. else reply->count = (get_format( clipboard, req->format ) != NULL); /* query a single format */
  433. }
  434. /* retrieve the next available format */
  435. DECL_HANDLER(enum_clipboard_formats)
  436. {
  437. struct list *ptr;
  438. struct clipboard *clipboard = get_process_clipboard();
  439. if (!clipboard) return;
  440. if (clipboard->open_thread != current)
  441. {
  442. set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
  443. return;
  444. }
  445. ptr = list_head( &clipboard->formats );
  446. if (req->previous)
  447. {
  448. while (ptr && LIST_ENTRY( ptr, struct clip_format, entry )->id != req->previous)
  449. ptr = list_next( &clipboard->formats, ptr );
  450. if (ptr) ptr = list_next( &clipboard->formats, ptr );
  451. }
  452. if (ptr) reply->format = LIST_ENTRY( ptr, struct clip_format, entry )->id;
  453. }
  454. /* empty the clipboard and grab ownership */
  455. DECL_HANDLER(empty_clipboard)
  456. {
  457. struct clipboard *clipboard = get_process_clipboard();
  458. if (!clipboard) return;
  459. if (clipboard->open_thread != current)
  460. {
  461. set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
  462. return;
  463. }
  464. free_clipboard_formats( clipboard );
  465. clipboard->owner = clipboard->open_win;
  466. clipboard->seqno++;
  467. }
  468. /* release ownership of the clipboard */
  469. DECL_HANDLER(release_clipboard)
  470. {
  471. struct clipboard *clipboard = get_process_clipboard();
  472. user_handle_t owner;
  473. if (!clipboard) return;
  474. if (!(owner = get_valid_window_handle( req->owner ))) return;
  475. if (clipboard->owner == owner)
  476. {
  477. reply->viewer = release_clipboard( clipboard );
  478. reply->owner = clipboard->owner;
  479. }
  480. else set_error( STATUS_INVALID_OWNER );
  481. }
  482. /* get clipboard information */
  483. DECL_HANDLER(get_clipboard_info)
  484. {
  485. struct clipboard *clipboard = get_process_clipboard();
  486. if (!clipboard) return;
  487. reply->window = clipboard->open_win;
  488. reply->owner = clipboard->owner;
  489. reply->viewer = clipboard->viewer;
  490. reply->seqno = clipboard->seqno;
  491. }
  492. /* set the clipboard viewer window */
  493. DECL_HANDLER(set_clipboard_viewer)
  494. {
  495. struct clipboard *clipboard = get_process_clipboard();
  496. user_handle_t viewer = 0, previous = 0;
  497. if (!clipboard) return;
  498. if (req->viewer && !(viewer = get_valid_window_handle( req->viewer ))) return;
  499. if (req->previous && !(previous = get_valid_window_handle( req->previous ))) return;
  500. reply->old_viewer = clipboard->viewer;
  501. reply->owner = clipboard->owner;
  502. if (!previous || clipboard->viewer == previous)
  503. clipboard->viewer = viewer;
  504. else
  505. set_error( STATUS_PENDING ); /* need to send message instead */
  506. }
  507. /* add a clipboard listener window */
  508. DECL_HANDLER(add_clipboard_listener)
  509. {
  510. struct clipboard *clipboard = get_process_clipboard();
  511. user_handle_t win;
  512. if (!clipboard) return;
  513. if (!(win = get_valid_window_handle( req->window ))) return;
  514. add_listener( clipboard, win );
  515. }
  516. /* remove a clipboard listener window */
  517. DECL_HANDLER(remove_clipboard_listener)
  518. {
  519. struct clipboard *clipboard = get_process_clipboard();
  520. user_handle_t win;
  521. if (!clipboard) return;
  522. if (!(win = get_valid_window_handle( req->window ))) return;
  523. if (!remove_listener( clipboard, win )) set_error( STATUS_INVALID_PARAMETER );
  524. }