00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "global.hpp"
00019
00020 #include "clipboard.hpp"
00021 #include <algorithm>
00022
00023 #if defined(_X11) && !defined(__APPLE__)
00024
00025 #define CLIPBOARD_FUNCS_DEFINED
00026
00027
00028 #include "SDL_syswm.h"
00029
00030 #include <unistd.h>
00031
00032
00033
00034
00035
00036
00037 class XHelper
00038 {
00039 private:
00040 XHelper() :
00041 wmInf_(),
00042 acquireCount_(0)
00043 {
00044 acquire();
00045
00046
00047 const char* atoms[] = {
00048 "CLIPBOARD",
00049 "TEXT",
00050 "COMPOUND_TEXT",
00051 "UTF8_STRING",
00052 "WESNOTH_PASTE",
00053 "TARGETS"
00054 };
00055
00056 XInternAtoms(dpy(), const_cast<char**>(reinterpret_cast<const char**>(atoms)), 6, false, atomTable_);
00057
00058 release();
00059 }
00060
00061 static XHelper* s_instance_;
00062
00063 SDL_SysWMinfo wmInf_;
00064
00065 Atom atomTable_[6];
00066 int acquireCount_;
00067 public:
00068 static XHelper* instance()
00069 {
00070 if (!s_instance_)
00071 s_instance_ = new XHelper;
00072 return s_instance_;
00073 }
00074
00075
00076 Atom XA_CLIPBOARD() const
00077 {
00078 return atomTable_[0];
00079 }
00080
00081 Atom XA_TEXT() const
00082 {
00083 return atomTable_[1];
00084 }
00085
00086 Atom XA_COMPOUND_TEXT() const
00087 {
00088 return atomTable_[2];
00089 }
00090
00091 Atom UTF8_STRING() const
00092 {
00093 return atomTable_[3];
00094 }
00095
00096 Atom WES_PASTE() const
00097 {
00098 return atomTable_[4];
00099 }
00100
00101 Atom XA_TARGETS() const
00102 {
00103 return atomTable_[5];
00104 }
00105
00106 Display* dpy() const
00107 {
00108 return wmInf_.info.x11.display;
00109 }
00110
00111 Window window() const
00112 {
00113 return wmInf_.info.x11.window;
00114 }
00115
00116 void acquire()
00117 {
00118 ++acquireCount_;
00119 if (acquireCount_ == 1) {
00120 SDL_VERSION (&wmInf_.version);
00121 SDL_GetWMInfo(&wmInf_);
00122
00123 wmInf_.info.x11.lock_func();
00124 }
00125 }
00126
00127 void release()
00128 {
00129 --acquireCount_;
00130 if (acquireCount_ == 0)
00131 wmInf_.info.x11.unlock_func();
00132 }
00133 };
00134
00135 XHelper* XHelper::s_instance_ = 0;
00136
00137 class UseX
00138 {
00139 public:
00140 UseX()
00141 {
00142 XHelper::instance()->acquire();
00143 }
00144
00145 ~UseX()
00146 {
00147 XHelper::instance()->release();
00148 }
00149
00150 XHelper* operator->()
00151 {
00152 return XHelper::instance();
00153 }
00154 };
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180 static std::string clipboard_string;
00181
00182
00183
00184
00185
00186
00187 static std::string primary_string;
00188
00189 void handle_system_event(const SDL_Event& event)
00190 {
00191 XEvent& xev = event.syswm.msg->event.xevent;
00192 if (xev.type == SelectionRequest) {
00193 UseX x11;
00194
00195
00196
00197 if ((xev.xselectionrequest.owner == x11->window()) &&
00198 ((xev.xselectionrequest.selection == XA_PRIMARY) ||
00199 (xev.xselectionrequest.selection == x11->XA_CLIPBOARD()))) {
00200 XEvent responseEvent;
00201 responseEvent.xselection.type = SelectionNotify;
00202 responseEvent.xselection.display = x11->dpy();
00203 responseEvent.xselection.requestor = xev.xselectionrequest.requestor;
00204 responseEvent.xselection.selection = xev.xselectionrequest.selection;
00205 responseEvent.xselection.target = xev.xselectionrequest.target;
00206 responseEvent.xselection.property = None;
00207 responseEvent.xselection.time = xev.xselectionrequest.time;
00208
00209
00210
00211
00212
00213 if (xev.xselectionrequest.target == x11->XA_TARGETS()) {
00214 responseEvent.xselection.property = xev.xselectionrequest.property;
00215
00216 Atom supported[] = {
00217 x11->XA_TEXT(),
00218 x11->XA_COMPOUND_TEXT(),
00219 x11->UTF8_STRING(),
00220 x11->XA_TARGETS()
00221 };
00222
00223 XChangeProperty(x11->dpy(), responseEvent.xselection.requestor,
00224 xev.xselectionrequest.property, XA_ATOM, 32, PropModeReplace,
00225 const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(supported)), 4);
00226 }
00227
00228
00229
00230
00231 if (xev.xselectionrequest.target == x11->XA_TEXT()
00232 || xev.xselectionrequest.target == x11->XA_COMPOUND_TEXT()
00233 || xev.xselectionrequest.target == x11->UTF8_STRING()) {
00234
00235 responseEvent.xselection.property = xev.xselectionrequest.property;
00236
00237 std::string& selection = (xev.xselectionrequest.selection == XA_PRIMARY) ?
00238 primary_string : clipboard_string;
00239
00240 XChangeProperty(x11->dpy(), responseEvent.xselection.requestor,
00241 xev.xselectionrequest.property,
00242 xev.xselectionrequest.target, 8, PropModeReplace,
00243 reinterpret_cast<const unsigned char*>(selection.c_str()), selection.length());
00244 }
00245
00246 XSendEvent(x11->dpy(), xev.xselectionrequest.requestor, False, NoEventMask,
00247 &responseEvent);
00248 }
00249 }
00250
00251 if (xev.type == SelectionClear) {
00252
00253 UseX x11;
00254
00255 if(xev.xselectionclear.selection == x11->XA_CLIPBOARD()) {
00256 clipboard_string.clear();
00257 } else if(xev.xselectionclear.selection == XA_PRIMARY) {
00258 primary_string.clear();
00259 }
00260 }
00261 }
00262
00263 void copy_to_clipboard(const std::string& text, const bool mouse)
00264 {
00265 if (text.empty()) {
00266 return;
00267 }
00268
00269 UseX x11;
00270
00271 if(mouse) {
00272 primary_string = text;
00273 XSetSelectionOwner(x11->dpy(), XA_PRIMARY, x11->window(), CurrentTime);
00274 } else {
00275 clipboard_string = text;
00276 XSetSelectionOwner(x11->dpy(), x11->XA_CLIPBOARD(), x11->window(), CurrentTime);
00277 }
00278 }
00279
00280
00281
00282
00283
00284 static bool try_grab_target(Atom source, Atom target, std::string& ret)
00285 {
00286 UseX x11;
00287
00288
00289 XDeleteProperty(x11->dpy(), x11->window(), x11->WES_PASTE());
00290 XSync (x11->dpy(), False);
00291
00292
00293
00294
00295 XConvertSelection(x11->dpy(), source, target,
00296 x11->WES_PASTE(), x11->window(), CurrentTime);
00297
00298
00299 for (int attempt = 0; attempt < 15; attempt++) {
00300 if (XPending(x11->dpy())) {
00301 XEvent selectNotify;
00302 while (XCheckTypedWindowEvent(x11->dpy(), x11->window(), SelectionNotify, &selectNotify)) {
00303 if (selectNotify.xselection.property == None)
00304
00305 return false;
00306 else if (selectNotify.xselection.property == x11->WES_PASTE() &&
00307 selectNotify.xselection.target == target) {
00308
00309 unsigned long length = 0;
00310 unsigned char* data;
00311
00312
00313 Atom typeRet;
00314 int formatRet;
00315 unsigned long remaining;
00316
00317
00318
00319
00320 XGetWindowProperty(x11->dpy(), x11->window(),
00321 selectNotify.xselection.property,
00322 0, 65535/4, True, target,
00323 &typeRet, &formatRet, &length, &remaining, &data);
00324
00325 if (data && length) {
00326 ret = reinterpret_cast<char*>(data);
00327 XFree(data);
00328 return true;
00329 } else {
00330 return false;
00331 }
00332 }
00333 }
00334 }
00335
00336 usleep(10000);
00337 }
00338
00339
00340 return false;
00341 }
00342
00343 std::string copy_from_clipboard(const bool mouse)
00344 {
00345
00346 if(mouse && !primary_string.empty()) {
00347 return primary_string;
00348 }
00349 if (!mouse && !clipboard_string.empty()) {
00350 return clipboard_string;
00351 }
00352
00353 UseX x11;
00354
00355 std::string ret;
00356 const Atom& source = mouse ? XA_PRIMARY : x11->XA_CLIPBOARD();
00357
00358 if (try_grab_target(source, x11->UTF8_STRING(), ret))
00359 return ret;
00360
00361 if (try_grab_target(source, x11->XA_COMPOUND_TEXT(), ret))
00362 return ret;
00363
00364 if (try_grab_target(source, x11->XA_TEXT(), ret))
00365 return ret;
00366
00367 if (try_grab_target(source, XA_STRING, ret))
00368 return ret;
00369
00370
00371 return "";
00372 }
00373
00374 #endif
00375 #ifdef _WIN32
00376 #include <windows.h>
00377 #define CLIPBOARD_FUNCS_DEFINED
00378
00379 void handle_system_event(const SDL_Event& )
00380 {}
00381
00382 void copy_to_clipboard(const std::string& text, const bool)
00383 {
00384 if(text.empty())
00385 return;
00386 if(!OpenClipboard(NULL))
00387 return;
00388 EmptyClipboard();
00389
00390
00391 std::string str;
00392 str.reserve(text.size());
00393 std::string::const_iterator last = text.begin();
00394 while(last != text.end()) {
00395 if(*last != '\n') {
00396 str.push_back(*last);
00397 } else {
00398 str.append("\r\n");
00399 }
00400 ++last;
00401 }
00402
00403 const HGLOBAL hglb = GlobalAlloc(GMEM_MOVEABLE, (str.size() + 1) * sizeof(TCHAR));
00404 if(hglb == NULL) {
00405 CloseClipboard();
00406 return;
00407 }
00408 char* const buffer = reinterpret_cast<char* const>(GlobalLock(hglb));
00409 strcpy(buffer, str.c_str());
00410 GlobalUnlock(hglb);
00411 SetClipboardData(CF_TEXT, hglb);
00412 CloseClipboard();
00413 }
00414
00415 std::string copy_from_clipboard(const bool)
00416 {
00417 if(!IsClipboardFormatAvailable(CF_TEXT))
00418 return "";
00419 if(!OpenClipboard(NULL))
00420 return "";
00421
00422 HGLOBAL hglb = GetClipboardData(CF_TEXT);
00423 if(hglb == NULL) {
00424 CloseClipboard();
00425 return "";
00426 }
00427 char const * buffer = reinterpret_cast<char*>(GlobalLock(hglb));
00428 if(buffer == NULL) {
00429 CloseClipboard();
00430 return "";
00431 }
00432
00433
00434 std::string str(buffer);
00435 str.erase(std::remove(str.begin(),str.end(),'\r'),str.end());
00436
00437 GlobalUnlock(hglb);
00438 CloseClipboard();
00439 return str;
00440 }
00441
00442 #endif
00443
00444 #ifdef __BEOS__
00445 #include <Clipboard.h>
00446 #define CLIPBOARD_FUNCS_DEFINED
00447
00448 void copy_to_clipboard(const std::string& text, const bool)
00449 {
00450 BMessage *clip;
00451 if (be_clipboard->Lock())
00452 {
00453 be_clipboard->Clear();
00454 if ((clip = be_clipboard->Data()))
00455 {
00456 clip->AddData("text/plain", B_MIME_TYPE, text.c_str(), text.size()+1);
00457 be_clipboard->Commit();
00458 }
00459 be_clipboard->Unlock();
00460 }
00461 }
00462
00463 std::string copy_from_clipboard(const bool)
00464 {
00465 const char* data;
00466 ssize_t size;
00467 BMessage *clip = NULL;
00468 if (be_clipboard->Lock())
00469 {
00470 clip = be_clipboard->Data();
00471 be_clipboard->Unlock();
00472 }
00473 if (clip != NULL && clip->FindData("text/plain", B_MIME_TYPE, (const void**)&data, &size) == B_OK)
00474 return (const char*)data;
00475 else
00476 return "";
00477 }
00478 #endif
00479
00480 #ifdef __APPLE__
00481 #define CLIPBOARD_FUNCS_DEFINED
00482
00483 #include <Carbon/Carbon.h>
00484
00485 void copy_to_clipboard(const std::string& text, const bool)
00486 {
00487 std::string new_str;
00488 new_str.reserve(text.size());
00489 for (unsigned int i = 0; i < text.size(); ++i)
00490 {
00491 if (text[i] == '\n')
00492 {
00493 new_str.push_back('\r');
00494 } else {
00495 new_str.push_back(text[i]);
00496 }
00497 }
00498 OSStatus err = noErr;
00499 PasteboardRef clipboard;
00500 PasteboardSyncFlags syncFlags;
00501 CFDataRef textData = NULL;
00502 err = PasteboardCreate(kPasteboardClipboard, &clipboard);
00503 if (err != noErr) return;
00504 err = PasteboardClear(clipboard);
00505 if (err != noErr) return;
00506 syncFlags = PasteboardSynchronize(clipboard);
00507 if ((syncFlags&kPasteboardModified) && !(syncFlags&kPasteboardClientIsOwner)) return;
00508 textData = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)new_str.c_str(), text.size());
00509 PasteboardPutItemFlavor(clipboard, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), textData, 0);
00510 }
00511
00512 std::string copy_from_clipboard(const bool)
00513 {
00514 OSStatus err = noErr;
00515 PasteboardRef clipboard;
00516 PasteboardSyncFlags syncFlags;
00517 ItemCount count;
00518 err = PasteboardCreate(kPasteboardClipboard, &clipboard);
00519 if (err != noErr) return "";
00520 syncFlags = PasteboardSynchronize(clipboard);
00521 if (syncFlags&kPasteboardModified) return "";
00522 err = PasteboardGetItemCount(clipboard, &count);
00523 if (err != noErr) return "";
00524 for (UInt32 k = 1; k <= count; k++) {
00525 PasteboardItemID itemID;
00526 CFArrayRef flavorTypeArray;
00527 CFIndex flavorCount;
00528 err = PasteboardGetItemIdentifier(clipboard, k, &itemID);
00529 if (err != noErr) return "";
00530 err = PasteboardCopyItemFlavors(clipboard, itemID, &flavorTypeArray);
00531 if (err != noErr) return "";
00532 flavorCount = CFArrayGetCount(flavorTypeArray);
00533 for (CFIndex j = 0; j < flavorCount; j++) {
00534 CFStringRef flavorType;
00535 CFDataRef flavorData;
00536 CFIndex flavorDataSize;
00537 flavorType = (CFStringRef)CFArrayGetValueAtIndex(flavorTypeArray, j);
00538 if (UTTypeConformsTo(flavorType, CFSTR("public.utf8-plain-text"))) {
00539 err = PasteboardCopyItemFlavorData(clipboard, itemID, flavorType, &flavorData);
00540 if (err != noErr) {
00541 CFRelease(flavorTypeArray);
00542 return "";
00543 }
00544 flavorDataSize = CFDataGetLength(flavorData);
00545 std::string str;
00546 str.reserve(flavorDataSize);
00547 str.resize(flavorDataSize);
00548 CFDataGetBytes(flavorData, CFRangeMake(0, flavorDataSize), (UInt8 *)str.data());
00549 for (unsigned int i = 0; i < str.size(); ++i) {
00550 if (str[i] == '\r') str[i] = '\n';
00551 }
00552 return str;
00553 }
00554 }
00555 }
00556 return "";
00557 }
00558
00559 void handle_system_event(const SDL_Event& )
00560 {
00561 }
00562
00563 #endif
00564
00565 #ifndef CLIPBOARD_FUNCS_DEFINED
00566
00567 void copy_to_clipboard(const std::string& , const bool)
00568 {
00569 }
00570
00571 std::string copy_from_clipboard(const bool)
00572 {
00573 return "";
00574 }
00575
00576 void handle_system_event(const SDL_Event& )
00577 {
00578 }
00579
00580 #endif
00581