diff options
author | Armin Weatherwax | 2009-06-08 11:10:27 +0200 |
---|---|---|
committer | McCabe Maxsted | 2009-09-04 11:34:24 -0700 |
commit | 3f0082a9dda60432b8b759e09f19b495d9d5275c (patch) | |
tree | 989f5e10f9b9891ec7718b5ee2406582b6c0e352 /linden/indra/llwindow/llwindowsdl.cpp | |
parent | Rebranded startup loading page to Imprudence (diff) | |
download | meta-impy-3f0082a9dda60432b8b759e09f19b495d9d5275c.zip meta-impy-3f0082a9dda60432b8b759e09f19b495d9d5275c.tar.gz meta-impy-3f0082a9dda60432b8b759e09f19b495d9d5275c.tar.bz2 meta-impy-3f0082a9dda60432b8b759e09f19b495d9d5275c.tar.xz |
Linux middle mouse button paste/primary selection support and gtk clipboard handler (fixes crashbug using synergy mouse-keyboard-clipboard-sharing over lan)
modified: linden/doc/contributions.txt
modified: linden/indra/llui/llclipboard.cpp
modified: linden/indra/llui/llclipboard.h
modified: linden/indra/llui/llfloater.cpp
modified: linden/indra/llui/llfloater.h
modified: linden/indra/llui/lllineeditor.cpp
modified: linden/indra/llui/lllineeditor.h
modified: linden/indra/llui/lltexteditor.cpp
modified: linden/indra/llui/lltexteditor.h
modified: linden/indra/llui/llview.cpp
modified: linden/indra/llui/llview.h
modified: linden/indra/llwindow/CMakeLists.txt
new file: linden/indra/llwindow/llmousehandler.cpp
modified: linden/indra/llwindow/llmousehandler.h
modified: linden/indra/llwindow/llwindow.cpp
modified: linden/indra/llwindow/llwindow.h
modified: linden/indra/llwindow/llwindowsdl.cpp
modified: linden/indra/llwindow/llwindowsdl.h
modified: linden/indra/newview/lltool.cpp
modified: linden/indra/newview/lltool.h
modified: linden/indra/newview/llviewertexteditor.cpp
modified: linden/indra/newview/llviewertexteditor.h
modified: linden/indra/newview/llviewerwindow.cpp
modified: linden/indra/newview/llviewerwindow.h
(cherry picked from commit 594f4830922f4294dda432fa748935adffaeed8f)
Diffstat (limited to 'linden/indra/llwindow/llwindowsdl.cpp')
-rw-r--r-- | linden/indra/llwindow/llwindowsdl.cpp | 570 |
1 files changed, 100 insertions, 470 deletions
diff --git a/linden/indra/llwindow/llwindowsdl.cpp b/linden/indra/llwindow/llwindowsdl.cpp index 8111aaf..5209e6f 100644 --- a/linden/indra/llwindow/llwindowsdl.cpp +++ b/linden/indra/llwindow/llwindowsdl.cpp | |||
@@ -188,11 +188,12 @@ Display* LLWindowSDL::get_SDL_Display(void) | |||
188 | 188 | ||
189 | 189 | ||
190 | LLWindowSDL::LLWindowSDL(const std::string& title, S32 x, S32 y, S32 width, | 190 | LLWindowSDL::LLWindowSDL(const std::string& title, S32 x, S32 y, S32 width, |
191 | S32 height, U32 flags, | 191 | S32 height, U32 flags, |
192 | BOOL fullscreen, BOOL clearBg, | 192 | BOOL fullscreen, BOOL clearBg, |
193 | BOOL disable_vsync, BOOL use_gl, | 193 | BOOL disable_vsync, BOOL use_gl, |
194 | BOOL ignore_pixel_depth, U32 fsaa_samples) | 194 | BOOL ignore_pixel_depth, U32 fsaa_samples) |
195 | : LLWindow(fullscreen, flags), mGamma(1.0f) | 195 | : LLWindow(fullscreen, flags), Lock_Display(NULL), |
196 | Unlock_Display(NULL), mGamma(1.0f) | ||
196 | { | 197 | { |
197 | // Initialize the keyboard | 198 | // Initialize the keyboard |
198 | gKeyboard = new LLKeyboardSDL(); | 199 | gKeyboard = new LLKeyboardSDL(); |
@@ -717,9 +718,33 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B | |||
717 | #endif | 718 | #endif |
718 | 719 | ||
719 | #if LL_X11 | 720 | #if LL_X11 |
720 | init_x11clipboard(); | 721 | /* Grab the window manager specific information */ |
722 | SDL_SysWMinfo info; | ||
723 | SDL_VERSION(&info.version); | ||
724 | if ( SDL_GetWMInfo(&info) ) | ||
725 | { | ||
726 | /* Save the information for later use */ | ||
727 | if ( info.subsystem == SDL_SYSWM_X11 ) | ||
728 | { | ||
729 | mSDL_Display = info.info.x11.display; | ||
730 | mSDL_XWindowID = info.info.x11.wmwindow; | ||
731 | Lock_Display = info.info.x11.lock_func; | ||
732 | Unlock_Display = info.info.x11.unlock_func; | ||
733 | } | ||
734 | else | ||
735 | { | ||
736 | llwarns << "We're not running under X11? Wild." | ||
737 | << llendl; | ||
738 | } | ||
739 | } | ||
740 | else | ||
741 | { | ||
742 | llwarns << "We're not running under any known WM. Wild." | ||
743 | << llendl; | ||
744 | } | ||
721 | #endif // LL_X11 | 745 | #endif // LL_X11 |
722 | 746 | ||
747 | |||
723 | //make sure multisampling is disabled by default | 748 | //make sure multisampling is disabled by default |
724 | glDisable(GL_MULTISAMPLE_ARB); | 749 | glDisable(GL_MULTISAMPLE_ARB); |
725 | 750 | ||
@@ -763,8 +788,12 @@ BOOL LLWindowSDL::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL | |||
763 | void LLWindowSDL::destroyContext() | 788 | void LLWindowSDL::destroyContext() |
764 | { | 789 | { |
765 | llinfos << "destroyContext begins" << llendl; | 790 | llinfos << "destroyContext begins" << llendl; |
791 | |||
766 | #if LL_X11 | 792 | #if LL_X11 |
767 | quit_x11clipboard(); | 793 | mSDL_Display = NULL; |
794 | mSDL_XWindowID = None; | ||
795 | Lock_Display = NULL; | ||
796 | Unlock_Display = NULL; | ||
768 | #endif // LL_X11 | 797 | #endif // LL_X11 |
769 | 798 | ||
770 | // Clean up remaining GL state before blowing away window | 799 | // Clean up remaining GL state before blowing away window |
@@ -1212,523 +1241,125 @@ void LLWindowSDL::flashIcon(F32 seconds) | |||
1212 | #endif // LL_X11 | 1241 | #endif // LL_X11 |
1213 | } | 1242 | } |
1214 | 1243 | ||
1215 | #if LL_X11 | 1244 | #if LL_GTK |
1216 | /* Lots of low-level X11 stuff to handle X11 copy-and-paste */ | 1245 | BOOL LLWindowSDL::isClipboardTextAvailable() |
1217 | |||
1218 | /* Our X11 clipboard support is a bit bizarre in various | ||
1219 | organically-grown ways. Ideally it should be fixed to do | ||
1220 | real string-type negotiation (this would make pasting to | ||
1221 | xterm faster and pasting to UTF-8 emacs work properly), but | ||
1222 | right now it has the rare and desirable trait of being | ||
1223 | generally stable and working. */ | ||
1224 | |||
1225 | typedef Atom x11clipboard_type; | ||
1226 | |||
1227 | /* PRIMARY and CLIPBOARD are the two main kinds of | ||
1228 | X11 clipboard. A third are the CUT_BUFFERs which an | ||
1229 | obsolete holdover from X10 days and use a quite orthogonal | ||
1230 | mechanism. CLIPBOARD is the type whose design most | ||
1231 | closely matches SL's own win32-alike explicit copy-and-paste | ||
1232 | paradigm. | ||
1233 | |||
1234 | Pragmatically we support all three to varying degrees. When | ||
1235 | we paste into SL, it is strictly from CLIPBOARD. When we copy, | ||
1236 | we support (to as full an extent as the clipboard content type | ||
1237 | allows) CLIPBOARD, PRIMARY, and CUT_BUFFER0. | ||
1238 | */ | ||
1239 | static x11clipboard_type get_x11_readwrite_clipboard_type(void) | ||
1240 | { | ||
1241 | return XInternAtom(LLWindowSDL::get_SDL_Display(), "CLIPBOARD", False); | ||
1242 | } | ||
1243 | |||
1244 | static x11clipboard_type get_x11_write_clipboard_type(void) | ||
1245 | { | ||
1246 | return XA_PRIMARY; | ||
1247 | } | ||
1248 | |||
1249 | /* This is where our own private cutbuffer goes - we don't use | ||
1250 | a regular cutbuffer (XA_CUT_BUFFER0 etc) for intermediate | ||
1251 | storage because their use isn't really defined for holding UTF8. */ | ||
1252 | static x11clipboard_type get_x11_cutbuffer_clipboard_type(void) | ||
1253 | { | ||
1254 | return XInternAtom(LLWindowSDL::get_SDL_Display(), "SECONDLIFE_CUTBUFFER", False); | ||
1255 | } | ||
1256 | |||
1257 | /* Some X11 atom-generators */ | ||
1258 | static Atom get_x11_targets_atom(void) | ||
1259 | { | ||
1260 | return XInternAtom(LLWindowSDL::get_SDL_Display(), "TARGETS", False); | ||
1261 | } | ||
1262 | |||
1263 | static Atom get_x11_text_atom(void) | ||
1264 | { | ||
1265 | return XInternAtom(LLWindowSDL::get_SDL_Display(), "TEXT", False); | ||
1266 | } | ||
1267 | |||
1268 | /* These defines, and convert_data/convert_x11clipboard, | ||
1269 | mostly exist to support non-text or unusually-encoded | ||
1270 | clipboard data, which we don't really have a need for at | ||
1271 | the moment. */ | ||
1272 | #define SDLCLIPTYPE(A, B, C, D) (int)(((A)<<24)|((B)<<16)|((C)<<8)|((D)<<0)) | ||
1273 | #define FORMAT_PREFIX "SECONDLIFE_x11clipboard_0x" | ||
1274 | |||
1275 | static | ||
1276 | x11clipboard_type convert_format(int type) | ||
1277 | { | 1246 | { |
1278 | if (!gWindowImplementation) | 1247 | if (ll_try_gtk_init()) |
1279 | { | 1248 | { |
1280 | llwarns << "!gWindowImplementation in convert_format()" | 1249 | GtkClipboard * const clipboard = |
1281 | << llendl; | 1250 | gtk_clipboard_get(GDK_NONE); |
1282 | return XA_STRING; | 1251 | return gtk_clipboard_wait_is_text_available(clipboard) ? |
1283 | } | 1252 | TRUE : FALSE; |
1284 | |||
1285 | switch (type) | ||
1286 | { | ||
1287 | case SDLCLIPTYPE('T', 'E', 'X', 'T'): | ||
1288 | // old-style X11 clipboard, strictly only ISO 8859-1 encoding | ||
1289 | return XA_STRING; | ||
1290 | case SDLCLIPTYPE('U', 'T', 'F', '8'): | ||
1291 | // newer de-facto UTF8 clipboard atom | ||
1292 | return XInternAtom(gWindowImplementation->mSDL_Display, | ||
1293 | "UTF8_STRING", False); | ||
1294 | default: | ||
1295 | { | ||
1296 | /* completely arbitrary clipboard types... we don't actually use | ||
1297 | these right now, and support is skeletal. */ | ||
1298 | char format[sizeof(FORMAT_PREFIX)+8+1]; /* Flawfinder: ignore */ | ||
1299 | |||
1300 | snprintf(format, sizeof(format), "%s%08lx", FORMAT_PREFIX, (unsigned long)type); | ||
1301 | return XInternAtom(gWindowImplementation->mSDL_Display, | ||
1302 | format, False); | ||
1303 | } | 1253 | } |
1304 | } | 1254 | return FALSE; // failure |
1305 | } | 1255 | } |
1306 | 1256 | ||
1307 | /* convert platform string to x11 clipboard format. for our | 1257 | BOOL LLWindowSDL::pasteTextFromClipboard(LLWString &text) |
1308 | purposes this is pretty trivial right now. */ | ||
1309 | static int | ||
1310 | convert_data(int type, char *dst, const char *src, int srclen) | ||
1311 | { | 1258 | { |
1312 | int dstlen; | 1259 | if (ll_try_gtk_init()) |
1313 | |||
1314 | dstlen = 0; | ||
1315 | switch (type) | ||
1316 | { | 1260 | { |
1317 | case SDLCLIPTYPE('T', 'E', 'X', 'T'): | 1261 | GtkClipboard * const clipboard = |
1318 | case SDLCLIPTYPE('U', 'T', 'F', '8'): | 1262 | gtk_clipboard_get(GDK_NONE); |
1319 | if (src == NULL) | 1263 | gchar * const data = gtk_clipboard_wait_for_text(clipboard); |
1320 | { | 1264 | if (data) |
1321 | break; | ||
1322 | } | ||
1323 | if ( srclen == 0 ) | ||
1324 | srclen = strlen(src); /* Flawfinder: ignore */ | ||
1325 | |||
1326 | dstlen = srclen + 1; | ||
1327 | |||
1328 | if ( dst ) // assume caller made it big enough by asking us | ||
1329 | { | 1265 | { |
1330 | memcpy(dst, src, srclen); /* Flawfinder: ignore */ | 1266 | text = LLWString(utf8str_to_wstring(data)); |
1331 | dst[srclen] = '\0'; | 1267 | g_free(data); |
1268 | return TRUE; | ||
1332 | } | 1269 | } |
1333 | break; | ||
1334 | |||
1335 | default: | ||
1336 | llwarns << "convert_data: Unknown medium type" << llendl; | ||
1337 | break; | ||
1338 | } | 1270 | } |
1339 | return(dstlen); | 1271 | return FALSE; // failure |
1340 | } | 1272 | } |
1341 | 1273 | ||
1342 | /* Convert x11clipboard data to platform string. This too is | 1274 | BOOL LLWindowSDL::copyTextToClipboard(const LLWString &text) |
1343 | pretty trivial for our needs right now, and just about identical | ||
1344 | to above. */ | ||
1345 | static int | ||
1346 | convert_x11clipboard(int type, char *dst, const char *src, int srclen) | ||
1347 | { | 1275 | { |
1348 | int dstlen; | 1276 | if (ll_try_gtk_init()) |
1349 | |||
1350 | dstlen = 0; | ||
1351 | switch (type) | ||
1352 | { | 1277 | { |
1353 | case SDLCLIPTYPE('U', 'T', 'F', '8'): | 1278 | const std::string utf8 = wstring_to_utf8str(text); |
1354 | case SDLCLIPTYPE('T', 'E', 'X', 'T'): | 1279 | GtkClipboard * const clipboard = |
1355 | if (src == NULL) | 1280 | gtk_clipboard_get(GDK_NONE); |
1356 | { | 1281 | gtk_clipboard_set_text(clipboard, utf8.c_str(), utf8.length()); |
1357 | break; | 1282 | return TRUE; |
1358 | } | ||
1359 | if ( srclen == 0 ) | ||
1360 | srclen = strlen(src); /* Flawfinder: ignore */ | ||
1361 | |||
1362 | dstlen = srclen + 1; | ||
1363 | |||
1364 | if ( dst ) // assume caller made it big enough by asking us | ||
1365 | { | ||
1366 | memcpy(dst, src, srclen); /* Flawfinder: ignore */ | ||
1367 | dst[srclen] = '\0'; | ||
1368 | } | ||
1369 | break; | ||
1370 | |||
1371 | default: | ||
1372 | llwarns << "convert_x11clipboard: Unknown medium type" << llendl; | ||
1373 | break; | ||
1374 | } | 1283 | } |
1375 | return dstlen; | 1284 | return FALSE; // failure |
1376 | } | ||
1377 | |||
1378 | int | ||
1379 | LLWindowSDL::is_empty_x11clipboard(void) | ||
1380 | { | ||
1381 | int retval; | ||
1382 | |||
1383 | maybe_lock_display(); | ||
1384 | retval = ( XGetSelectionOwner(mSDL_Display, get_x11_readwrite_clipboard_type()) == None ); | ||
1385 | maybe_unlock_display(); | ||
1386 | |||
1387 | return(retval); | ||
1388 | } | 1285 | } |
1389 | 1286 | ||
1390 | void | 1287 | BOOL LLWindowSDL::isPrimaryTextAvailable() |
1391 | LLWindowSDL::put_x11clipboard(int type, int srclen, const char *src) | ||
1392 | { | 1288 | { |
1393 | x11clipboard_type format; | 1289 | if (ll_try_gtk_init()) |
1394 | int dstlen; | ||
1395 | char *dst; | ||
1396 | |||
1397 | format = convert_format(type); | ||
1398 | dstlen = convert_data(type, NULL, src, srclen); | ||
1399 | |||
1400 | dst = (char *)malloc(dstlen); | ||
1401 | if ( dst != NULL ) | ||
1402 | { | 1290 | { |
1403 | maybe_lock_display(); | 1291 | GtkClipboard * const clipboard = |
1404 | Window root = DefaultRootWindow(mSDL_Display); | 1292 | gtk_clipboard_get(GDK_SELECTION_PRIMARY); |
1405 | convert_data(type, dst, src, srclen); | 1293 | return gtk_clipboard_wait_is_text_available(clipboard) ? |
1406 | // Cutbuffers are only allowed to have STRING atom types, | 1294 | TRUE : FALSE; |
1407 | // but Emacs puts UTF8 inside them anyway. We cautiously | ||
1408 | // don't. | ||
1409 | if (type == SDLCLIPTYPE('T','E','X','T')) | ||
1410 | { | ||
1411 | // dstlen-1 so we don't include the trailing \0 | ||
1412 | llinfos << "X11: Populating cutbuffer." <<llendl; | ||
1413 | XChangeProperty(mSDL_Display, root, | ||
1414 | XA_CUT_BUFFER0, XA_STRING, 8, PropModeReplace, | ||
1415 | (unsigned char*)dst, dstlen-1); | ||
1416 | } else { | ||
1417 | // Should we clear the cutbuffer if we can't put the selection in | ||
1418 | // it because it's a UTF8 selection? Eh, no great reason I think. | ||
1419 | //XDeleteProperty(SDL_Display, root, XA_CUT_BUFFER0); | ||
1420 | } | ||
1421 | // Private cutbuffer of an appropriate type. | ||
1422 | XChangeProperty(mSDL_Display, root, | ||
1423 | get_x11_cutbuffer_clipboard_type(), format, 8, PropModeReplace, | ||
1424 | (unsigned char*)dst, dstlen-1); | ||
1425 | free(dst); | ||
1426 | |||
1427 | /* Claim ownership of both PRIMARY and CLIPBOARD */ | ||
1428 | XSetSelectionOwner(mSDL_Display, get_x11_readwrite_clipboard_type(), | ||
1429 | mSDL_XWindowID, CurrentTime); | ||
1430 | XSetSelectionOwner(mSDL_Display, get_x11_write_clipboard_type(), | ||
1431 | mSDL_XWindowID, CurrentTime); | ||
1432 | |||
1433 | maybe_unlock_display(); | ||
1434 | } | 1295 | } |
1296 | return FALSE; // failure | ||
1435 | } | 1297 | } |
1436 | 1298 | ||
1437 | void | 1299 | BOOL LLWindowSDL::pasteTextFromPrimary(LLWString &text) |
1438 | LLWindowSDL::get_x11clipboard(int type, int *dstlen, char **dst) | ||
1439 | { | 1300 | { |
1440 | x11clipboard_type format; | 1301 | if (ll_try_gtk_init()) |
1441 | |||
1442 | *dstlen = 0; | ||
1443 | format = convert_format(type); | ||
1444 | |||
1445 | Window owner; | ||
1446 | Atom selection; | ||
1447 | Atom seln_type; | ||
1448 | int seln_format; | ||
1449 | unsigned long nbytes; | ||
1450 | unsigned long overflow; | ||
1451 | char *src; | ||
1452 | |||
1453 | maybe_lock_display(); | ||
1454 | owner = XGetSelectionOwner(mSDL_Display, get_x11_readwrite_clipboard_type()); | ||
1455 | maybe_unlock_display(); | ||
1456 | if (owner == None) | ||
1457 | { | ||
1458 | // Fall right back to ancient X10 cut-buffers | ||
1459 | owner = DefaultRootWindow(mSDL_Display); | ||
1460 | selection = XA_CUT_BUFFER0; | ||
1461 | } else if (owner == mSDL_XWindowID) | ||
1462 | { | ||
1463 | // Use our own uncooked opaque string property | ||
1464 | owner = DefaultRootWindow(mSDL_Display); | ||
1465 | selection = get_x11_cutbuffer_clipboard_type(); | ||
1466 | } | ||
1467 | else | ||
1468 | { | ||
1469 | // Use full-on X11-style clipboard negotiation with the owning app | ||
1470 | int selection_response = 0; | ||
1471 | SDL_Event event; | ||
1472 | |||
1473 | owner = mSDL_XWindowID; | ||
1474 | maybe_lock_display(); | ||
1475 | selection = XInternAtom(mSDL_Display, "SDL_SELECTION", False); | ||
1476 | XConvertSelection(mSDL_Display, get_x11_readwrite_clipboard_type(), format, | ||
1477 | selection, owner, CurrentTime); | ||
1478 | maybe_unlock_display(); | ||
1479 | llinfos << "X11: Waiting for clipboard to arrive." <<llendl; | ||
1480 | while ( ! selection_response ) | ||
1481 | { | ||
1482 | // Only look for SYSWMEVENTs, or we may lose keypresses | ||
1483 | // etc. | ||
1484 | SDL_PumpEvents(); | ||
1485 | if (1 == SDL_PeepEvents(&event, 1, SDL_GETEVENT, | ||
1486 | SDL_SYSWMEVENTMASK) ) | ||
1487 | { | ||
1488 | if ( event.type == SDL_SYSWMEVENT ) | ||
1489 | { | ||
1490 | XEvent xevent = | ||
1491 | event.syswm.msg->event.xevent; | ||
1492 | |||
1493 | if ( (xevent.type == SelectionNotify)&& | ||
1494 | (xevent.xselection.requestor == owner) ) | ||
1495 | selection_response = 1; | ||
1496 | } | ||
1497 | } else { | ||
1498 | llinfos << "X11: Waiting for SYSWM event..." << llendl; | ||
1499 | } | ||
1500 | } | ||
1501 | llinfos << "X11: Clipboard arrived." <<llendl; | ||
1502 | } | ||
1503 | |||
1504 | maybe_lock_display(); | ||
1505 | if ( XGetWindowProperty(mSDL_Display, owner, selection, 0, INT_MAX/4, | ||
1506 | False, format, &seln_type, &seln_format, | ||
1507 | &nbytes, &overflow, (unsigned char **)&src) == Success ) | ||
1508 | { | 1302 | { |
1509 | if ( seln_type == format ) | 1303 | GtkClipboard * const clipboard = |
1510 | { | 1304 | gtk_clipboard_get(GDK_SELECTION_PRIMARY); |
1511 | *dstlen = convert_x11clipboard(type, NULL, src, nbytes); | 1305 | gchar * const data = gtk_clipboard_wait_for_text(clipboard); |
1512 | *dst = (char *)realloc(*dst, *dstlen); | 1306 | if (data) |
1513 | if ( *dst == NULL ) | ||
1514 | *dstlen = 0; | ||
1515 | else | ||
1516 | convert_x11clipboard(type, *dst, src, nbytes); | ||
1517 | } | ||
1518 | XFree(src); | ||
1519 | } | ||
1520 | maybe_unlock_display(); | ||
1521 | } | ||
1522 | |||
1523 | int clipboard_filter_callback(const SDL_Event *event) | ||
1524 | { | ||
1525 | /* Post all non-window manager specific events */ | ||
1526 | if ( event->type != SDL_SYSWMEVENT ) | ||
1527 | { | ||
1528 | return(1); | ||
1529 | } | ||
1530 | |||
1531 | /* Handle window-manager specific clipboard events */ | ||
1532 | switch (event->syswm.msg->event.xevent.type) { | ||
1533 | /* Copy the selection from SECONDLIFE_CUTBUFFER to the requested property */ | ||
1534 | case SelectionRequest: { | ||
1535 | XSelectionRequestEvent *req; | ||
1536 | XEvent sevent; | ||
1537 | int seln_format; | ||
1538 | unsigned long nbytes; | ||
1539 | unsigned long overflow; | ||
1540 | unsigned char *seln_data; | ||
1541 | |||
1542 | req = &event->syswm.msg->event.xevent.xselectionrequest; | ||
1543 | sevent.xselection.type = SelectionNotify; | ||
1544 | sevent.xselection.display = req->display; | ||
1545 | sevent.xselection.selection = req->selection; | ||
1546 | sevent.xselection.target = None; | ||
1547 | sevent.xselection.property = None; | ||
1548 | sevent.xselection.requestor = req->requestor; | ||
1549 | sevent.xselection.time = req->time; | ||
1550 | if ( XGetWindowProperty(LLWindowSDL::get_SDL_Display(), DefaultRootWindow(LLWindowSDL::get_SDL_Display()), | ||
1551 | get_x11_cutbuffer_clipboard_type(), 0, INT_MAX/4, False, req->target, | ||
1552 | &sevent.xselection.target, &seln_format, | ||
1553 | &nbytes, &overflow, &seln_data) == Success ) | ||
1554 | { | 1307 | { |
1555 | if ( sevent.xselection.target == req->target) | 1308 | text = LLWString(utf8str_to_wstring(data)); |
1556 | { | 1309 | g_free(data); |
1557 | if ( sevent.xselection.target == XA_STRING || | 1310 | return TRUE; |
1558 | sevent.xselection.target == | ||
1559 | convert_format(SDLCLIPTYPE('U','T','F','8')) ) | ||
1560 | { | ||
1561 | if ( seln_data[nbytes-1] == '\0' ) | ||
1562 | --nbytes; | ||
1563 | } | ||
1564 | XChangeProperty(LLWindowSDL::get_SDL_Display(), req->requestor, req->property, | ||
1565 | req->target, seln_format, PropModeReplace, | ||
1566 | seln_data, nbytes); | ||
1567 | sevent.xselection.property = req->property; | ||
1568 | } else if (get_x11_targets_atom() == req->target) { | ||
1569 | /* only advertise what we currently support */ | ||
1570 | const int num_supported = 3; | ||
1571 | Atom supported[num_supported] = { | ||
1572 | XA_STRING, // will be over-written below | ||
1573 | get_x11_text_atom(), | ||
1574 | get_x11_targets_atom() | ||
1575 | }; | ||
1576 | supported[0] = sevent.xselection.target; | ||
1577 | XChangeProperty(LLWindowSDL::get_SDL_Display(), req->requestor, | ||
1578 | req->property, XA_ATOM, 32, PropModeReplace, | ||
1579 | (unsigned char*)supported, | ||
1580 | num_supported); | ||
1581 | sevent.xselection.property = req->property; | ||
1582 | llinfos << "Clipboard: An app asked us what selections format we offer." << llendl; | ||
1583 | } else { | ||
1584 | llinfos << "Clipboard: An app requested an unsupported selection format " << req->target << ", we have " << sevent.xselection.target << llendl; | ||
1585 | sevent.xselection.target = None; | ||
1586 | } | ||
1587 | XFree(seln_data); | ||
1588 | } | 1311 | } |
1589 | int sendret = | ||
1590 | XSendEvent(LLWindowSDL::get_SDL_Display(),req->requestor,False,0,&sevent); | ||
1591 | if ((sendret==BadValue) || (sendret==BadWindow)) | ||
1592 | llwarns << "Clipboard SendEvent failed" << llendl; | ||
1593 | XSync(LLWindowSDL::get_SDL_Display(), False); | ||
1594 | } | ||
1595 | break; | ||
1596 | } | 1312 | } |
1597 | 1313 | return FALSE; // failure | |
1598 | /* Post the event for X11 clipboard reading above */ | ||
1599 | return(1); | ||
1600 | } | 1314 | } |
1601 | 1315 | ||
1602 | int | 1316 | BOOL LLWindowSDL::copyTextToPrimary(const LLWString &text) |
1603 | LLWindowSDL::init_x11clipboard(void) | ||
1604 | { | 1317 | { |
1605 | SDL_SysWMinfo info; | 1318 | if (ll_try_gtk_init()) |
1606 | int retval; | ||
1607 | |||
1608 | /* Grab the window manager specific information */ | ||
1609 | retval = -1; | ||
1610 | SDL_SetError("SDL is not running on known window manager"); | ||
1611 | |||
1612 | SDL_VERSION(&info.version); | ||
1613 | if ( SDL_GetWMInfo(&info) ) | ||
1614 | { | 1319 | { |
1615 | /* Save the information for later use */ | 1320 | const std::string utf8 = wstring_to_utf8str(text); |
1616 | if ( info.subsystem == SDL_SYSWM_X11 ) | 1321 | GtkClipboard * const clipboard = |
1617 | { | 1322 | gtk_clipboard_get(GDK_SELECTION_PRIMARY); |
1618 | mSDL_Display = info.info.x11.display; | 1323 | gtk_clipboard_set_text(clipboard, utf8.c_str(), utf8.length()); |
1619 | mSDL_XWindowID = info.info.x11.wmwindow; | 1324 | return TRUE; |
1620 | Lock_Display = info.info.x11.lock_func; | ||
1621 | Unlock_Display = info.info.x11.unlock_func; | ||
1622 | |||
1623 | /* Enable the special window hook events */ | ||
1624 | SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE); | ||
1625 | SDL_SetEventFilter(clipboard_filter_callback); | ||
1626 | |||
1627 | retval = 0; | ||
1628 | } | ||
1629 | else | ||
1630 | { | ||
1631 | SDL_SetError("SDL is not running on X11"); | ||
1632 | } | ||
1633 | } | 1325 | } |
1634 | return(retval); | 1326 | return FALSE; // failure |
1635 | } | ||
1636 | |||
1637 | void | ||
1638 | LLWindowSDL::quit_x11clipboard(void) | ||
1639 | { | ||
1640 | mSDL_Display = NULL; | ||
1641 | mSDL_XWindowID = None; | ||
1642 | Lock_Display = NULL; | ||
1643 | Unlock_Display = NULL; | ||
1644 | |||
1645 | SDL_SetEventFilter(NULL); // Stop custom event filtering | ||
1646 | } | 1327 | } |
1647 | 1328 | ||
1648 | /************************************************/ | 1329 | #else |
1649 | 1330 | ||
1650 | BOOL LLWindowSDL::isClipboardTextAvailable() | 1331 | BOOL LLWindowSDL::isClipboardTextAvailable() |
1651 | { | 1332 | { |
1652 | return !is_empty_x11clipboard(); | 1333 | return FALSE; // unsupported |
1653 | } | 1334 | } |
1654 | 1335 | ||
1655 | BOOL LLWindowSDL::pasteTextFromClipboard(LLWString &dst) | 1336 | BOOL LLWindowSDL::pasteTextFromClipboard(LLWString &dst) |
1656 | { | 1337 | { |
1657 | int cliplen; // seems 1 or 2 bytes longer than expected | 1338 | return FALSE; // unsupported |
1658 | char *cliptext = NULL; | ||
1659 | get_x11clipboard(SDLCLIPTYPE('U','T','F','8'), &cliplen, &cliptext); | ||
1660 | if (cliptext) | ||
1661 | { | ||
1662 | llinfos << "X11: Got UTF8 clipboard text." << llendl; | ||
1663 | // at some future time we can use cliplen instead of relying on \0, | ||
1664 | // if we ever grok non-ascii, non-utf8 encodings on the clipboard. | ||
1665 | std::string clip_str(cliptext); | ||
1666 | // we can't necessarily trust the incoming text to be valid UTF-8, | ||
1667 | // but utf8str_to_wstring() seems to do an appropriate level of | ||
1668 | // validation for avoiding over-reads. | ||
1669 | dst = utf8str_to_wstring(clip_str); | ||
1670 | /*llinfos << "X11 pasteTextFromClipboard: cliplen=" << cliplen << | ||
1671 | " strlen(cliptext)=" << strlen(cliptext) << | ||
1672 | " clip_str.length()=" << clip_str.length() << | ||
1673 | " dst.length()=" << dst.length() << | ||
1674 | llendl;*/ | ||
1675 | free(cliptext); | ||
1676 | return TRUE; // success | ||
1677 | } | ||
1678 | get_x11clipboard(SDLCLIPTYPE('T','E','X','T'), &cliplen, &cliptext); | ||
1679 | if (cliptext) | ||
1680 | { | ||
1681 | llinfos << "X11: Got ISO 8859-1 clipboard text." << llendl; | ||
1682 | std::string clip_str(cliptext); | ||
1683 | std::string utf8_str = rawstr_to_utf8(clip_str); | ||
1684 | dst = utf8str_to_wstring(utf8_str); | ||
1685 | free(cliptext); | ||
1686 | } | ||
1687 | return FALSE; // failure | ||
1688 | } | 1339 | } |
1340 | |||
1689 | 1341 | ||
1690 | BOOL LLWindowSDL::copyTextToClipboard(const LLWString &s) | 1342 | BOOL LLWindowSDL::copyTextToClipboard(const LLWString &s) |
1691 | { | 1343 | { |
1692 | std::string utf8text = wstring_to_utf8str(s); | 1344 | return FALSE; // unsupported |
1693 | const char* cstr = utf8text.c_str(); | ||
1694 | if (cstr == NULL) | ||
1695 | { | ||
1696 | return FALSE; | ||
1697 | } | ||
1698 | int cstrlen = strlen(cstr); /* Flawfinder: ignore */ | ||
1699 | int i; | ||
1700 | for (i=0; i<cstrlen; ++i) | ||
1701 | { | ||
1702 | if (0x80 & (unsigned char)cstr[i]) | ||
1703 | { | ||
1704 | // Found an 8-bit character; use new-style UTF8 clipboard | ||
1705 | llinfos << "X11: UTF8 copyTextToClipboard" << llendl; | ||
1706 | put_x11clipboard(SDLCLIPTYPE('U','T','F','8'), cstrlen, cstr); | ||
1707 | return TRUE; | ||
1708 | } | ||
1709 | } | ||
1710 | // Didn't find any 8-bit characters; use old-style ISO 8859-1 clipboard | ||
1711 | llinfos << "X11: ISO 8859-1 copyTextToClipboard" << llendl; | ||
1712 | put_x11clipboard(SDLCLIPTYPE('T','E','X','T'), cstrlen, cstr); | ||
1713 | return TRUE; | ||
1714 | } | 1345 | } |
1715 | #else | ||
1716 | 1346 | ||
1717 | BOOL LLWindowSDL::isClipboardTextAvailable() | 1347 | BOOL LLWindowSDL::isPrimaryTextAvailable() |
1718 | { | 1348 | { |
1719 | return FALSE; // unsupported | 1349 | return FALSE; // unsupported |
1720 | } | 1350 | } |
1721 | 1351 | ||
1722 | BOOL LLWindowSDL::pasteTextFromClipboard(LLWString &dst) | 1352 | BOOL LLWindowSDL::pasteTextFromPrimary(LLWString &dst) |
1723 | { | 1353 | { |
1724 | return FALSE; // unsupported | 1354 | return FALSE; // unsupported |
1725 | } | 1355 | } |
1726 | 1356 | ||
1727 | BOOL LLWindowSDL::copyTextToClipboard(const LLWString &s) | 1357 | BOOL LLWindowSDL::copyTextToPrimary(const LLWString &s) |
1728 | { | 1358 | { |
1729 | return FALSE; // unsupported | 1359 | return FALSE; // unsupported |
1730 | } | 1360 | } |
1731 | #endif // LL_X11 | 1361 | |
1362 | #endif // LL_GTK | ||
1732 | 1363 | ||
1733 | LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_resolutions) | 1364 | LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_resolutions) |
1734 | { | 1365 | { |
@@ -2538,8 +2169,7 @@ S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 typ | |||
2538 | buttons = GTK_BUTTONS_YES_NO; | 2169 | buttons = GTK_BUTTONS_YES_NO; |
2539 | break; | 2170 | break; |
2540 | } | 2171 | } |
2541 | win = gtk_message_dialog_new(NULL, flags, messagetype, buttons, "%s", | 2172 | win = gtk_message_dialog_new(NULL,flags, messagetype, buttons, "%s", text.c_str()); |
2542 | text.c_str()); | ||
2543 | 2173 | ||
2544 | # if LL_X11 | 2174 | # if LL_X11 |
2545 | // Make GTK tell the window manager to associate this | 2175 | // Make GTK tell the window manager to associate this |