rework keyframe hide popup, keyframe auto render, textbox set_selection wide text
[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 + 1)
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                 memcpy(this->data[clipboard_num], data, len);
254                 this->data[clipboard_num][len] = 0;
255         }
256
257         if(clipboard_num == PRIMARY_SELECTION)
258         {
259                 XSetSelectionOwner(out_display, 
260                         primary, 
261                         out_win, 
262                         CurrentTime);
263         }
264         else
265         if(clipboard_num == SECONDARY_SELECTION)
266         {
267                 XSetSelectionOwner(out_display, 
268                         secondary, 
269                         out_win, 
270                         CurrentTime);
271         }
272
273
274         XFlush(out_display);
275
276
277 #ifdef SINGLE_THREAD
278         BC_Display::unlock_display();
279 #else
280         XUnlockDisplay(out_display);
281 #endif
282         return 0;
283 }
284
285 int BC_Clipboard::from_clipboard(char *data, long maxlen, int clipboard_num)
286 {
287
288
289
290         if(clipboard_num == BC_PRIMARY_SELECTION)
291         {
292                 char *data2;
293                 int len, i;
294                 data2 = XFetchBuffer(in_display, &len, clipboard_num);
295                 for(i = 0; i < len && i < maxlen; i++)
296                         data[i] = data2[i];
297
298                 data[i] = 0;
299
300                 XFree(data2);
301                 
302                 
303                 return 0;
304         }
305
306
307
308 #ifdef SINGLE_THREAD
309         BC_Display::lock_display("BC_Clipboard::from_clipboard");
310 #else
311         XLockDisplay(in_display);
312 #endif
313
314         XEvent event;
315         Atom type_return, pty;
316         int format;
317         unsigned long nitems, size, new_size;
318         char *temp_data = 0;
319
320         pty = (clipboard_num == PRIMARY_SELECTION) ? primary : secondary; 
321                                                 /* a property of our window
322                                                    for apps to put their
323                                                    selection into */
324
325         XConvertSelection(in_display, 
326                 clipboard_num == PRIMARY_SELECTION ? primary : secondary, 
327                 strtype_atom,
328                 pty,
329                 in_win, 
330                 CurrentTime);
331
332         data[0] = 0;
333         do
334         {
335                 XNextEvent(in_display, &event);
336         }while(event.type != SelectionNotify && event.type != None);
337
338         if(event.type != None)
339         {
340 // Get size
341                 XGetWindowProperty(in_display,
342                         in_win, pty, 0, 0, False, AnyPropertyType,
343                         &type_return, &format, &nitems, &size,
344                         (unsigned char**)&temp_data);
345
346                 if(temp_data) XFree(temp_data);
347                 temp_data = 0;
348
349 // Get data
350                 XGetWindowProperty(in_display,
351                         in_win, pty, 0, size, False, AnyPropertyType,
352                         &type_return, &format, &nitems, &new_size,
353                         (unsigned char**)&temp_data);
354
355
356                 if(type_return && temp_data)
357                 {
358                         strncpy(data, temp_data, maxlen);
359                         data[maxlen] = 0;
360                 }
361                 else
362                         data[0] = 0;
363
364                 if(temp_data) XFree(temp_data);
365         }
366
367
368 #ifdef SINGLE_THREAD
369         BC_Display::unlock_display();
370 #else
371         XUnlockDisplay(in_display);
372 #endif
373
374         return 0;
375 }
376
377 long BC_Clipboard::clipboard_len(int clipboard_num)
378 {
379
380         if(clipboard_num == BC_PRIMARY_SELECTION)
381         {
382                 char *data2;
383                 int len;
384
385                 data2 = XFetchBuffer(in_display, &len, clipboard_num);
386                 XFree(data2);
387                 return len;
388         }
389
390
391
392
393 #ifdef SINGLE_THREAD
394         BC_Display::lock_display("BC_Clipboard::clipboard_len");
395 #else
396         XLockDisplay(in_display);
397 #endif
398
399         XEvent event;
400         Atom type_return, pty;
401         int format;
402         unsigned long nitems, pty_size;
403         char *temp_data = 0;
404         int result = 0;
405
406         pty = (clipboard_num == PRIMARY_SELECTION) ? primary : secondary; 
407                                                 /* a property of our window
408                                                    for apps to put their
409                                                    selection into */
410         XConvertSelection(in_display, 
411                 (clipboard_num == PRIMARY_SELECTION) ? primary : secondary, 
412                 strtype_atom, pty, in_win, CurrentTime);
413
414         do
415         {
416                 XNextEvent(in_display, &event);
417         }while(event.type != SelectionNotify && event.type != None);
418
419         if(event.type != None)
420         {
421 // Get size
422         XGetWindowProperty(in_display,
423                 in_win, pty, 0, 0, False, AnyPropertyType,
424                 &type_return, &format, &nitems, &pty_size,
425                 (unsigned char**)&temp_data);
426
427                 if(type_return)
428                 {
429                         result = pty_size + 1;
430                 }
431                 else
432                         result = 0;
433
434                 if(temp_data)
435                         XFree(temp_data);
436         }
437
438
439 #ifdef SINGLE_THREAD
440         BC_Display::unlock_display();
441 #else
442         XUnlockDisplay(in_display);
443 #endif
444
445         return result;
446 }