clipboard.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  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 <assert.h>
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include "ntstatus.h"
  27. #define WIN32_NO_STATUS
  28. #include "request.h"
  29. #include "object.h"
  30. #include "file.h"
  31. #include "process.h"
  32. #include "user.h"
  33. #include "winuser.h"
  34. #include "winternl.h"
  35. struct clip_format
  36. {
  37. struct list entry; /* entry in format list */
  38. unsigned int id; /* format id */
  39. unsigned int from; /* for synthesized data, format to generate it from */
  40. unsigned int seqno; /* sequence number when the data was set */
  41. data_size_t size; /* size of the data block */
  42. void *data; /* data contents, or NULL for delay-rendered */
  43. };
  44. struct clipboard
  45. {
  46. struct object obj; /* object header */
  47. struct thread *open_thread; /* thread id that has clipboard open */
  48. user_handle_t open_win; /* window that has clipboard open */
  49. user_handle_t owner; /* window that owns the clipboard */
  50. user_handle_t viewer; /* first window in clipboard viewer list */
  51. unsigned int lcid; /* locale id to use for synthesizing text formats */
  52. unsigned int seqno; /* clipboard change sequence number */
  53. unsigned int open_seqno; /* sequence number at open time */
  54. unsigned int rendering; /* format rendering recursion counter */
  55. struct list formats; /* list of data formats */
  56. unsigned int format_count; /* count of data formats */
  57. unsigned int format_map; /* existence bitmap for formats < CF_MAX */
  58. unsigned int listen_size; /* size of listeners array */
  59. unsigned int listen_count; /* count of listeners */
  60. user_handle_t *listeners; /* array of listener windows */
  61. };
  62. static void clipboard_dump( struct object *obj, int verbose );
  63. static void clipboard_destroy( struct object *obj );
  64. static const struct object_ops clipboard_ops =
  65. {
  66. sizeof(struct clipboard), /* size */
  67. &no_type, /* type */
  68. clipboard_dump, /* dump */
  69. no_add_queue, /* add_queue */
  70. NULL, /* remove_queue */
  71. NULL, /* signaled */
  72. NULL, /* satisfied */
  73. no_signal, /* signal */
  74. no_get_fd, /* get_fd */
  75. default_map_access, /* map_access */
  76. default_get_sd, /* get_sd */
  77. default_set_sd, /* set_sd */
  78. no_get_full_name, /* get_full_name */
  79. no_lookup_name, /* lookup_name */
  80. no_link_name, /* link_name */
  81. NULL, /* unlink_name */
  82. no_open_file, /* open_file */
  83. no_kernel_obj_list, /* get_kernel_obj_list */
  84. no_get_fast_sync, /* get_fast_sync */
  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) continue;
  271. /* format->from is earlier in the list and thus has already been
  272. * removed if not available anymore (it is also < CF_MAX)
  273. */
  274. if (format->from && HAS_FORMAT( clipboard->format_map, format->from )) continue;
  275. list_remove( &format->entry );
  276. if (format->id < CF_MAX) clipboard->format_map &= ~(1 << format->id);
  277. clipboard->format_count--;
  278. free( format );
  279. changed = 1;
  280. }
  281. if (!changed) return 0;
  282. clipboard->seqno++;
  283. return notify_listeners( clipboard );
  284. }
  285. /* cleanup clipboard information upon window destruction */
  286. void cleanup_clipboard_window( struct desktop *desktop, user_handle_t window )
  287. {
  288. struct clipboard *clipboard = desktop->winstation->clipboard;
  289. if (!clipboard) return;
  290. remove_listener( clipboard, window );
  291. if (clipboard->viewer == window) clipboard->viewer = 0;
  292. if (clipboard->owner == window) release_clipboard( clipboard );
  293. if (clipboard->open_win == window)
  294. {
  295. user_handle_t viewer = close_clipboard( clipboard );
  296. if (viewer) send_notify_message( viewer, WM_DRAWCLIPBOARD, clipboard->owner, 0 );
  297. }
  298. }
  299. /* Called when thread terminates to allow release of clipboard */
  300. void cleanup_clipboard_thread(struct thread *thread)
  301. {
  302. struct clipboard *clipboard;
  303. struct winstation *winstation;
  304. if (!thread->process->winstation) return;
  305. if (!(winstation = get_process_winstation( thread->process, WINSTA_ACCESSCLIPBOARD ))) return;
  306. if ((clipboard = winstation->clipboard))
  307. {
  308. if (thread == clipboard->open_thread)
  309. {
  310. user_handle_t viewer = close_clipboard( clipboard );
  311. if (viewer) send_notify_message( viewer, WM_DRAWCLIPBOARD, clipboard->owner, 0 );
  312. }
  313. }
  314. release_object( winstation );
  315. }
  316. /* open the clipboard */
  317. DECL_HANDLER(open_clipboard)
  318. {
  319. struct clipboard *clipboard = get_process_clipboard();
  320. user_handle_t win = 0;
  321. if (!clipboard) return;
  322. if (req->window && !(win = get_valid_window_handle( req->window ))) return;
  323. if (clipboard->open_thread && clipboard->open_win != win)
  324. {
  325. set_error( STATUS_INVALID_LOCK_SEQUENCE );
  326. return;
  327. }
  328. if (!clipboard->open_thread) clipboard->open_seqno = clipboard->seqno; /* first open */
  329. if (clipboard->open_thread != current) clipboard->rendering = 0;
  330. clipboard->open_win = win;
  331. clipboard->open_thread = current;
  332. reply->owner = clipboard->owner;
  333. }
  334. /* close the clipboard */
  335. DECL_HANDLER(close_clipboard)
  336. {
  337. struct clipboard *clipboard = get_process_clipboard();
  338. if (!clipboard) return;
  339. if (clipboard->open_thread != current)
  340. {
  341. set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
  342. return;
  343. }
  344. reply->viewer = close_clipboard( clipboard );
  345. reply->owner = clipboard->owner;
  346. }
  347. /* add a data format to the clipboard */
  348. DECL_HANDLER(set_clipboard_data)
  349. {
  350. struct clip_format *format;
  351. struct clipboard *clipboard = get_process_clipboard();
  352. void *data = NULL;
  353. if (!clipboard) return;
  354. if (!req->format || !clipboard->open_thread)
  355. {
  356. set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
  357. return;
  358. }
  359. if (get_req_data_size() && !(data = memdup( get_req_data(), get_req_data_size() ))) return;
  360. if (!(format = get_format( clipboard, req->format )))
  361. {
  362. if (!(format = add_format( clipboard, req->format )))
  363. {
  364. free( data );
  365. return;
  366. }
  367. }
  368. free( format->data );
  369. format->from = 0;
  370. format->seqno = clipboard->seqno;
  371. format->size = get_req_data_size();
  372. format->data = data;
  373. if (!clipboard->rendering) clipboard->seqno++;
  374. if (req->format == CF_TEXT || req->format == CF_OEMTEXT || req->format == CF_UNICODETEXT)
  375. clipboard->lcid = req->lcid;
  376. reply->seqno = format->seqno;
  377. }
  378. /* fetch a data format from the clipboard */
  379. DECL_HANDLER(get_clipboard_data)
  380. {
  381. struct clip_format *format;
  382. struct clipboard *clipboard = get_process_clipboard();
  383. if (!clipboard) return;
  384. if (clipboard->open_thread != current)
  385. {
  386. set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
  387. return;
  388. }
  389. if (!(format = get_format( clipboard, req->format )))
  390. {
  391. set_error( STATUS_OBJECT_NAME_NOT_FOUND );
  392. goto done;
  393. }
  394. reply->from = format->from;
  395. reply->total = format->size;
  396. reply->seqno = format->seqno;
  397. reply->owner = clipboard->owner;
  398. if (!format->data && req->render) /* try rendering it client-side */
  399. {
  400. if (format->from || clipboard->owner) clipboard->rendering++;
  401. return;
  402. }
  403. if (req->cached && req->seqno == format->seqno) goto done; /* client-side cache still valid */
  404. if (format->size > get_reply_max_size())
  405. {
  406. set_error( STATUS_BUFFER_OVERFLOW );
  407. return;
  408. }
  409. set_reply_data( format->data, format->size );
  410. done:
  411. if (!req->render) clipboard->rendering--;
  412. }
  413. /* retrieve a list of available formats */
  414. DECL_HANDLER(get_clipboard_formats)
  415. {
  416. struct clipboard *clipboard = get_process_clipboard();
  417. if (!clipboard) return;
  418. if (!req->format)
  419. {
  420. struct clip_format *format;
  421. unsigned int i = 0, *ptr;
  422. data_size_t size = clipboard->format_count * sizeof(unsigned int);
  423. reply->count = clipboard->format_count;
  424. if (size <= get_reply_max_size())
  425. {
  426. if ((ptr = mem_alloc( size )))
  427. {
  428. LIST_FOR_EACH_ENTRY( format, &clipboard->formats, struct clip_format, entry )
  429. ptr[i++] = format->id;
  430. assert( i == clipboard->format_count );
  431. set_reply_data_ptr( ptr, size );
  432. }
  433. }
  434. else set_error( STATUS_BUFFER_TOO_SMALL );
  435. }
  436. else reply->count = (get_format( clipboard, req->format ) != NULL); /* query a single format */
  437. }
  438. /* retrieve the next available format */
  439. DECL_HANDLER(enum_clipboard_formats)
  440. {
  441. struct list *ptr;
  442. struct clipboard *clipboard = get_process_clipboard();
  443. if (!clipboard) return;
  444. if (clipboard->open_thread != current)
  445. {
  446. set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
  447. return;
  448. }
  449. ptr = list_head( &clipboard->formats );
  450. if (req->previous)
  451. {
  452. while (ptr && LIST_ENTRY( ptr, struct clip_format, entry )->id != req->previous)
  453. ptr = list_next( &clipboard->formats, ptr );
  454. if (ptr) ptr = list_next( &clipboard->formats, ptr );
  455. }
  456. if (ptr) reply->format = LIST_ENTRY( ptr, struct clip_format, entry )->id;
  457. }
  458. /* empty the clipboard and grab ownership */
  459. DECL_HANDLER(empty_clipboard)
  460. {
  461. struct clipboard *clipboard = get_process_clipboard();
  462. if (!clipboard) return;
  463. if (clipboard->open_thread != current)
  464. {
  465. set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
  466. return;
  467. }
  468. free_clipboard_formats( clipboard );
  469. clipboard->owner = clipboard->open_win;
  470. clipboard->seqno++;
  471. }
  472. /* release ownership of the clipboard */
  473. DECL_HANDLER(release_clipboard)
  474. {
  475. struct clipboard *clipboard = get_process_clipboard();
  476. user_handle_t owner;
  477. if (!clipboard) return;
  478. if (!(owner = get_valid_window_handle( req->owner ))) return;
  479. if (clipboard->owner == owner)
  480. {
  481. reply->viewer = release_clipboard( clipboard );
  482. reply->owner = clipboard->owner;
  483. }
  484. else set_error( STATUS_INVALID_OWNER );
  485. }
  486. /* get clipboard information */
  487. DECL_HANDLER(get_clipboard_info)
  488. {
  489. struct clipboard *clipboard = get_process_clipboard();
  490. if (!clipboard) return;
  491. reply->window = clipboard->open_win;
  492. reply->owner = clipboard->owner;
  493. reply->viewer = clipboard->viewer;
  494. reply->seqno = clipboard->seqno;
  495. }
  496. /* set the clipboard viewer window */
  497. DECL_HANDLER(set_clipboard_viewer)
  498. {
  499. struct clipboard *clipboard = get_process_clipboard();
  500. user_handle_t viewer = 0, previous = 0;
  501. if (!clipboard) return;
  502. if (req->viewer && !(viewer = get_valid_window_handle( req->viewer ))) return;
  503. if (req->previous && !(previous = get_valid_window_handle( req->previous ))) return;
  504. reply->old_viewer = clipboard->viewer;
  505. reply->owner = clipboard->owner;
  506. if (!previous || clipboard->viewer == previous)
  507. clipboard->viewer = viewer;
  508. else
  509. set_error( STATUS_PENDING ); /* need to send message instead */
  510. }
  511. /* add a clipboard listener window */
  512. DECL_HANDLER(add_clipboard_listener)
  513. {
  514. struct clipboard *clipboard = get_process_clipboard();
  515. user_handle_t win;
  516. if (!clipboard) return;
  517. if (!(win = get_valid_window_handle( req->window ))) return;
  518. add_listener( clipboard, win );
  519. }
  520. /* remove a clipboard listener window */
  521. DECL_HANDLER(remove_clipboard_listener)
  522. {
  523. struct clipboard *clipboard = get_process_clipboard();
  524. user_handle_t win;
  525. if (!clipboard) return;
  526. if (!(win = get_valid_window_handle( req->window ))) return;
  527. if (!remove_listener( clipboard, win )) set_error( STATUS_INVALID_PARAMETER );
  528. }