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