4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
22 #include "bcclipboard.h"
23 #include "bcdisplay.h"
24 #include "bcresources.h"
25 #include "bcsignals.h"
26 #include "bcwindowbase.h"
27 #include "bcwindowbase.inc"
31 BC_Clipboard::BC_Clipboard(const char *display_name)
35 strcpy(this->display_name, display_name);
37 this->display_name[0] = 0;
40 in_display = out_display = BC_Display::get_display(display_name);
42 in_display = BC_WindowBase::init_display(display_name);
43 out_display = BC_WindowBase::init_display(display_name);
46 completion_atom = XInternAtom(out_display, "BC_CLOSE_EVENT", False);
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);
53 strtype_atom = XA_STRING;
54 in_win = XCreateSimpleWindow(in_display,
55 DefaultRootWindow(in_display),
57 out_win = XCreateSimpleWindow(out_display,
58 DefaultRootWindow(out_display),
64 BC_Clipboard::~BC_Clipboard()
66 if(data[0]) delete [] data[0];
67 if(data[1]) delete [] data[1];
69 XDestroyWindow(in_display, in_win);
70 XCloseDisplay(in_display);
71 XDestroyWindow(out_display, out_win);
72 XCloseDisplay(out_display);
75 int BC_Clipboard::start_clipboard()
83 int BC_Clipboard::stop_clipboard()
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;
96 event.type = ClientMessage;
97 ptr->message_type = completion_atom;
99 //printf("BC_Clipboard::stop_clipboard %d\n", __LINE__);
100 XSendEvent(display, out_win, 0, 0, &event);
102 XCloseDisplay(display);
108 void BC_Clipboard::run()
111 XClientMessageEvent *ptr;
113 #ifndef SINGLE_THREAD
114 int x_fd = ConnectionNumber(out_display);
119 #ifndef SINGLE_THREAD
120 // see bcwindowevents.C regarding XNextEvent
123 FD_SET(x_fd, &x_fds);
125 tv.tv_sec = 0; tv.tv_usec = 200000;
126 select(x_fd + 1, &x_fds, 0, 0, &tv);
127 XLockDisplay(out_display);
129 while(XPending(out_display))
132 //printf("BC_Clipboard::run 1\n");
133 XNextEvent(out_display, &event);
134 //printf("BC_Clipboard::run 2 %d\n", event.type);
137 BC_Display::lock_display("BC_Clipboard::run");
141 // Termination signal
143 ptr = (XClientMessageEvent*)&event;
144 if(ptr->message_type == completion_atom)
148 //printf("ClientMessage %x %x %d\n", ptr->message_type, ptr->data.l[0], primary_atom);
152 case SelectionRequest:
153 handle_selectionrequest((XSelectionRequestEvent*)&event);
157 if(data[0]) data[0][0] = 0;
158 if(data[1]) data[1][0] = 0;
161 #ifndef SINGLE_THREAD
163 XUnlockDisplay(out_display);
165 BC_Display::unlock_display();
170 void BC_Clipboard::handle_selectionrequest(XSelectionRequestEvent *request)
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);
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;
189 XSendEvent(out_display, request->requestor, 0, 0, &reply);
191 //printf("SelectionRequest\n");
194 int BC_Clipboard::handle_request_string(XSelectionRequestEvent *request)
196 char *data_ptr = (request->selection == primary ? data[0] : data[1]);
198 XChangeProperty(out_display,
204 (unsigned char*)data_ptr,
209 int BC_Clipboard::handle_request_targets(XSelectionRequestEvent *request)
215 XChangeProperty(out_display,
221 (unsigned char*)targets,
222 sizeof(targets)/sizeof(targets[0]));
223 //printf("BC_Clipboard::handle_request_targets\n");
227 int BC_Clipboard::to_clipboard(const char *data, long len, int clipboard_num)
229 //printf("BC_Clipboard::to_clipboard %d: %d '%*.*s'\n",clipboard_num,len,len,len,data);
230 if(clipboard_num == BC_PRIMARY_SELECTION)
232 XStoreBuffer(out_display, data, len, clipboard_num);
237 BC_Display::lock_display("BC_Clipboard::to_clipboard");
239 XLockDisplay(out_display);
242 // Store in local buffer
243 if(this->data[clipboard_num] && length[clipboard_num] != len)
245 delete [] this->data[clipboard_num];
246 this->data[clipboard_num] = 0;
249 if(!this->data[clipboard_num])
251 length[clipboard_num] = len;
252 this->data[clipboard_num] = new char[len + 1];
255 memcpy(this->data[clipboard_num], data, len);
256 this->data[clipboard_num][len] = 0;
258 if(clipboard_num == PRIMARY_SELECTION)
260 XSetSelectionOwner(out_display,
266 if(clipboard_num == SECONDARY_SELECTION)
268 XSetSelectionOwner(out_display,
279 BC_Display::unlock_display();
281 XUnlockDisplay(out_display);
286 int BC_Clipboard::from_clipboard(char *data, long maxlen, int clipboard_num)
291 if(clipboard_num == BC_PRIMARY_SELECTION)
295 data2 = XFetchBuffer(in_display, &len, clipboard_num);
296 for(i = 0; i < len && i < maxlen; i++)
310 BC_Display::lock_display("BC_Clipboard::from_clipboard");
312 XLockDisplay(in_display);
316 Atom type_return, pty;
318 unsigned long nitems, size, new_size;
321 pty = (clipboard_num == PRIMARY_SELECTION) ? primary : secondary;
322 /* a property of our window
323 for apps to put their
326 XConvertSelection(in_display,
327 clipboard_num == PRIMARY_SELECTION ? primary : secondary,
336 XNextEvent(in_display, &event);
337 }while(event.type != SelectionNotify && event.type != None);
339 if(event.type != None)
342 XGetWindowProperty(in_display,
343 in_win, pty, 0, 0, False, AnyPropertyType,
344 &type_return, &format, &nitems, &size,
345 (unsigned char**)&temp_data);
347 if(temp_data) XFree(temp_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);
357 if(type_return && temp_data)
359 strncpy(data, temp_data, maxlen);
365 if(temp_data) XFree(temp_data);
370 BC_Display::unlock_display();
372 XUnlockDisplay(in_display);
374 //int len = strlen(data);
375 //printf("BC_Clipboard::from_clipboard %d: %d '%*.*s'\n",clipboard_num,len,len,len,data);
379 long BC_Clipboard::clipboard_len(int clipboard_num)
382 if(clipboard_num == BC_PRIMARY_SELECTION)
387 data2 = XFetchBuffer(in_display, &len, clipboard_num);
396 BC_Display::lock_display("BC_Clipboard::clipboard_len");
398 XLockDisplay(in_display);
402 Atom type_return, pty;
404 unsigned long nitems, pty_size;
408 pty = (clipboard_num == PRIMARY_SELECTION) ? primary : secondary;
409 /* a property of our window
410 for apps to put their
412 XConvertSelection(in_display,
413 (clipboard_num == PRIMARY_SELECTION) ? primary : secondary,
414 strtype_atom, pty, in_win, CurrentTime);
418 XNextEvent(in_display, &event);
419 }while(event.type != SelectionNotify && event.type != None);
421 if(event.type != None)
424 XGetWindowProperty(in_display,
425 in_win, pty, 0, 0, False, AnyPropertyType,
426 &type_return, &format, &nitems, &pty_size,
427 (unsigned char**)&temp_data);
431 result = pty_size + 1;
442 BC_Display::unlock_display();
444 XUnlockDisplay(in_display);