remove whitespace at eol
[goodguy/history.git] / cinelerra-5.1 / guicast / bcclipboard.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcclipboard.h"
23 #include "bcdisplay.h"
24 #include "bcresources.h"
25 #include "bcsignals.h"
26 #include "bcwindowbase.h"
27 #include "bcwindowbase.inc"
28 #include <string.h>
29 #include <unistd.h>
30
31 BC_Clipboard::BC_Clipboard(const char *display_name)
32  : Thread(1, 0, 0)
33 {
34         if(display_name)
35                 strcpy(this->display_name, display_name);
36         else
37                 this->display_name[0] = 0;
38
39 #ifdef SINGLE_THREAD
40         in_display = out_display = BC_Display::get_display(display_name);
41 #else
42         in_display = BC_WindowBase::init_display(display_name);
43         out_display = BC_WindowBase::init_display(display_name);
44 #endif
45
46         completion_atom = XInternAtom(out_display, "BC_CLOSE_EVENT", False);
47         primary = XA_PRIMARY;
48         secondary = XInternAtom(out_display, "CLIPBOARD", False);
49         targets_atom = XInternAtom(out_display, "TARGETS", False);
50         if(BC_Resources::locale_utf8)
51                 strtype_atom = XInternAtom(out_display, "UTF8_STRING", False);
52         else
53                 strtype_atom = XA_STRING;
54         in_win = XCreateSimpleWindow(in_display,
55                                 DefaultRootWindow(in_display),
56                                 0, 0, 1, 1, 0, 0, 0);
57         out_win = XCreateSimpleWindow(out_display,
58                                 DefaultRootWindow(out_display),
59                                 0, 0, 1, 1, 0, 0, 0);
60         data[0] = 0;
61         data[1] = 0;
62 }
63
64 BC_Clipboard::~BC_Clipboard()
65 {
66         if(data[0]) delete [] data[0];
67         if(data[1]) delete [] data[1];
68
69         XDestroyWindow(in_display, in_win);
70         XCloseDisplay(in_display);
71         XDestroyWindow(out_display, out_win);
72         XCloseDisplay(out_display);
73 }
74
75 int BC_Clipboard::start_clipboard()
76 {
77 #ifndef SINGLE_THREAD
78         Thread::start();
79 #endif
80         return 0;
81 }
82
83 int BC_Clipboard::stop_clipboard()
84 {
85 #ifdef SINGLE_THREAD
86         XFlush(in_display);
87 #else
88         XFlush(in_display);
89         XFlush(out_display);
90 #endif
91 // Must use a different display handle to send events.
92         Display *display = BC_WindowBase::init_display(display_name);
93         XEvent event;  memset(&event, 0, sizeof(event));
94         XClientMessageEvent *ptr = (XClientMessageEvent*)&event;
95
96         event.type = ClientMessage;
97         ptr->message_type = completion_atom;
98         ptr->format = 32;
99 //printf("BC_Clipboard::stop_clipboard %d\n", __LINE__);
100         XSendEvent(display, out_win, 0, 0, &event);
101         XFlush(display);
102         XCloseDisplay(display);
103
104         Thread::join();
105         return 0;
106 }
107
108 void BC_Clipboard::run()
109 {
110         XEvent event;
111         XClientMessageEvent *ptr;
112         int done = 0;
113 #ifndef SINGLE_THREAD
114         int x_fd = ConnectionNumber(out_display);
115 #endif
116
117         while(!done)
118         {
119 #ifndef SINGLE_THREAD
120 // see bcwindowevents.C regarding XNextEvent
121                 fd_set x_fds;
122                 FD_ZERO(&x_fds);
123                 FD_SET(x_fd, &x_fds);
124                 struct timeval tv;
125                 tv.tv_sec = 0;  tv.tv_usec = 200000;
126                 select(x_fd + 1, &x_fds, 0, 0, &tv);
127                 XLockDisplay(out_display);
128
129                 while(XPending(out_display))
130                 {
131 #endif
132 //printf("BC_Clipboard::run 1\n");
133                         XNextEvent(out_display, &event);
134 //printf("BC_Clipboard::run 2 %d\n", event.type);
135
136 #ifdef SINGLE_THREAD
137                         BC_Display::lock_display("BC_Clipboard::run");
138 #endif
139                         switch(event.type)
140                         {
141 // Termination signal
142                         case ClientMessage:
143                                 ptr = (XClientMessageEvent*)&event;
144                                 if(ptr->message_type == completion_atom)
145                                 {
146                                         done = 1;
147                                 }
148 //printf("ClientMessage %x %x %d\n", ptr->message_type, ptr->data.l[0], primary_atom);
149                                 break;
150
151
152                         case SelectionRequest:
153                                 handle_selectionrequest((XSelectionRequestEvent*)&event);
154                                 break;
155
156                         case SelectionClear:
157                                 if(data[0]) data[0][0] = 0;
158                                 if(data[1]) data[1][0] = 0;
159                                 break;
160                         }
161 #ifndef SINGLE_THREAD
162                 }
163                 XUnlockDisplay(out_display);
164 #else
165                 BC_Display::unlock_display();
166 #endif
167         }
168 }
169
170 void BC_Clipboard::handle_selectionrequest(XSelectionRequestEvent *request)
171 {
172         int success = 0;
173         if (request->target == strtype_atom)
174                 success = handle_request_string(request);
175         else if (request->target == targets_atom)
176                 success = handle_request_targets(request);
177
178         XEvent reply;  memset(&reply, 0, sizeof(reply));
179 // 'None' tells the client that the request was denied
180         reply.xselection.property  = success ? request->property : None;
181         reply.xselection.type      = SelectionNotify;
182         reply.xselection.display   = request->display;
183         reply.xselection.requestor = request->requestor;
184         reply.xselection.selection = request->selection;
185         reply.xselection.target    = request->target;
186         reply.xselection.time      = request->time;
187
188
189         XSendEvent(out_display, request->requestor, 0, 0, &reply);
190         XFlush(out_display);
191 //printf("SelectionRequest\n");
192 }
193
194 int BC_Clipboard::handle_request_string(XSelectionRequestEvent *request)
195 {
196         char *data_ptr = (request->selection == primary ? data[0] : data[1]);
197
198         XChangeProperty(out_display,
199                         request->requestor,
200                         request->property,
201                         strtype_atom,
202                         8,
203                         PropModeReplace,
204                         (unsigned char*)data_ptr,
205                         strlen(data_ptr));
206         return 1;
207 }
208
209 int BC_Clipboard::handle_request_targets(XSelectionRequestEvent *request)
210 {
211         Atom targets[] = {
212                 targets_atom,
213                 strtype_atom
214         };
215         XChangeProperty(out_display,
216                         request->requestor,
217                         request->property,
218                         XA_ATOM,
219                         32,
220                         PropModeReplace,
221                         (unsigned char*)targets,
222                         sizeof(targets)/sizeof(targets[0]));
223 //printf("BC_Clipboard::handle_request_targets\n");
224         return 1;
225 }
226
227 int BC_Clipboard::to_clipboard(const char *data, long len, int clipboard_num)
228 {
229 //printf("BC_Clipboard::to_clipboard %d: %d '%*.*s'\n",clipboard_num,len,len,len,data);
230         if(clipboard_num == BC_PRIMARY_SELECTION)
231         {
232                 XStoreBuffer(out_display, data, len, clipboard_num);
233                 return 0;
234         }
235
236 #ifdef SINGLE_THREAD
237         BC_Display::lock_display("BC_Clipboard::to_clipboard");
238 #else
239         XLockDisplay(out_display);
240 #endif
241
242 // Store in local buffer
243         if(this->data[clipboard_num] && length[clipboard_num] != len)
244         {
245                 delete [] this->data[clipboard_num];
246                 this->data[clipboard_num] = 0;
247         }
248
249         if(!this->data[clipboard_num])
250         {
251                 length[clipboard_num] = len;
252                 this->data[clipboard_num] = new char[len + 1];
253         }
254
255         memcpy(this->data[clipboard_num], data, len);
256         this->data[clipboard_num][len] = 0;
257
258         if(clipboard_num == PRIMARY_SELECTION)
259         {
260                 XSetSelectionOwner(out_display,
261                         primary,
262                         out_win,
263                         CurrentTime);
264         }
265         else
266         if(clipboard_num == SECONDARY_SELECTION)
267         {
268                 XSetSelectionOwner(out_display,
269                         secondary,
270                         out_win,
271                         CurrentTime);
272         }
273
274
275         XFlush(out_display);
276
277
278 #ifdef SINGLE_THREAD
279         BC_Display::unlock_display();
280 #else
281         XUnlockDisplay(out_display);
282 #endif
283         return 0;
284 }
285
286 int BC_Clipboard::from_clipboard(char *data, long maxlen, int clipboard_num)
287 {
288
289
290
291         if(clipboard_num == BC_PRIMARY_SELECTION)
292         {
293                 char *data2;
294                 int len, i;
295                 data2 = XFetchBuffer(in_display, &len, clipboard_num);
296                 for(i = 0; i < len && i < maxlen; i++)
297                         data[i] = data2[i];
298
299                 data[i] = 0;
300
301                 XFree(data2);
302
303
304                 return 0;
305         }
306
307
308
309 #ifdef SINGLE_THREAD
310         BC_Display::lock_display("BC_Clipboard::from_clipboard");
311 #else
312         XLockDisplay(in_display);
313 #endif
314
315         XEvent event;
316         Atom type_return, pty;
317         int format;
318         unsigned long nitems, size, new_size;
319         char *temp_data = 0;
320
321         pty = (clipboard_num == PRIMARY_SELECTION) ? primary : secondary;
322                                                 /* a property of our window
323                                                    for apps to put their
324                                                    selection into */
325
326         XConvertSelection(in_display,
327                 clipboard_num == PRIMARY_SELECTION ? primary : secondary,
328                 strtype_atom,
329                 pty,
330                 in_win,
331                 CurrentTime);
332
333         data[0] = 0;
334         do
335         {
336                 XNextEvent(in_display, &event);
337         }while(event.type != SelectionNotify && event.type != None);
338
339         if(event.type != None)
340         {
341 // Get size
342                 XGetWindowProperty(in_display,
343                         in_win, pty, 0, 0, False, AnyPropertyType,
344                         &type_return, &format, &nitems, &size,
345                         (unsigned char**)&temp_data);
346
347                 if(temp_data) XFree(temp_data);
348                 temp_data = 0;
349
350 // Get data
351                 XGetWindowProperty(in_display,
352                         in_win, pty, 0, size, False, AnyPropertyType,
353                         &type_return, &format, &nitems, &new_size,
354                         (unsigned char**)&temp_data);
355
356
357                 if(type_return && temp_data)
358                 {
359                         strncpy(data, temp_data, maxlen);
360                         data[maxlen] = 0;
361                 }
362                 else
363                         data[0] = 0;
364
365                 if(temp_data) XFree(temp_data);
366         }
367
368
369 #ifdef SINGLE_THREAD
370         BC_Display::unlock_display();
371 #else
372         XUnlockDisplay(in_display);
373 #endif
374 //int len = strlen(data);
375 //printf("BC_Clipboard::from_clipboard %d: %d '%*.*s'\n",clipboard_num,len,len,len,data);
376         return 0;
377 }
378
379 long BC_Clipboard::clipboard_len(int clipboard_num)
380 {
381
382         if(clipboard_num == BC_PRIMARY_SELECTION)
383         {
384                 char *data2;
385                 int len;
386
387                 data2 = XFetchBuffer(in_display, &len, clipboard_num);
388                 XFree(data2);
389                 return len;
390         }
391
392
393
394
395 #ifdef SINGLE_THREAD
396         BC_Display::lock_display("BC_Clipboard::clipboard_len");
397 #else
398         XLockDisplay(in_display);
399 #endif
400
401         XEvent event;
402         Atom type_return, pty;
403         int format;
404         unsigned long nitems, pty_size;
405         char *temp_data = 0;
406         int result = 0;
407
408         pty = (clipboard_num == PRIMARY_SELECTION) ? primary : secondary;
409                                                 /* a property of our window
410                                                    for apps to put their
411                                                    selection into */
412         XConvertSelection(in_display,
413                 (clipboard_num == PRIMARY_SELECTION) ? primary : secondary,
414                 strtype_atom, pty, in_win, CurrentTime);
415
416         do
417         {
418                 XNextEvent(in_display, &event);
419         }while(event.type != SelectionNotify && event.type != None);
420
421         if(event.type != None)
422         {
423 // Get size
424         XGetWindowProperty(in_display,
425                 in_win, pty, 0, 0, False, AnyPropertyType,
426                 &type_return, &format, &nitems, &pty_size,
427                 (unsigned char**)&temp_data);
428
429                 if(type_return)
430                 {
431                         result = pty_size + 1;
432                 }
433                 else
434                         result = 0;
435
436                 if(temp_data)
437                         XFree(temp_data);
438         }
439
440
441 #ifdef SINGLE_THREAD
442         BC_Display::unlock_display();
443 #else
444         XUnlockDisplay(in_display);
445 #endif
446
447         return result;
448 }