00001
00032 #if LL_SDL
00033
00034 #include "linden_common.h"
00035
00036 #include "llwindowsdl.h"
00037 #include "llkeyboardsdl.h"
00038 #include "llerror.h"
00039 #include "llgl.h"
00040 #include "llstring.h"
00041 #include "lldir.h"
00042 #include "llfindlocale.h"
00043
00044 #include "llglheaders.h"
00045
00046 #include "indra_constants.h"
00047
00048 #if LL_GTK
00049 extern "C" {
00050 # include "gtk/gtk.h"
00051 }
00052 #include <locale.h>
00053 #endif // LL_GTK
00054
00055 extern "C" {
00056 # include "fontconfig/fontconfig.h"
00057 }
00058
00059 #if LL_LINUX || LL_SOLARIS
00060
00061
00062 # include <unistd.h>
00063 # include <sys/types.h>
00064 # include <sys/wait.h>
00065 #endif // LL_LINUX || LL_SOLARIS
00066
00067 extern BOOL gDebugWindowProc;
00068
00069 const S32 MAX_NUM_RESOLUTIONS = 32;
00070
00071
00072
00073
00074
00075 #if LL_X11
00076 # include <X11/Xutil.h>
00077 #endif //LL_X11
00078
00079
00080
00081
00082
00083 static LLWindowSDL *gWindowImplementation = NULL;
00084
00085 static BOOL was_fullscreen = FALSE;
00086
00087
00088 void maybe_lock_display(void)
00089 {
00090 if (gWindowImplementation && gWindowImplementation->Lock_Display) {
00091 gWindowImplementation->Lock_Display();
00092 }
00093 }
00094
00095
00096 void maybe_unlock_display(void)
00097 {
00098 if (gWindowImplementation && gWindowImplementation->Unlock_Display) {
00099 gWindowImplementation->Unlock_Display();
00100 }
00101 }
00102
00103
00104 #if LL_GTK
00105
00106 BOOL ll_try_gtk_init(void)
00107 {
00108 static BOOL done_gtk_diag = FALSE;
00109 static BOOL gtk_is_good = FALSE;
00110 static BOOL done_setlocale = FALSE;
00111 static BOOL tried_gtk_init = FALSE;
00112
00113 if (!done_setlocale)
00114 {
00115 llinfos << "Starting GTK Initialization." << llendl;
00116 maybe_lock_display();
00117 gtk_disable_setlocale();
00118 maybe_unlock_display();
00119 done_setlocale = TRUE;
00120 }
00121
00122 if (!tried_gtk_init)
00123 {
00124 tried_gtk_init = TRUE;
00125 #if LL_GSTREAMER_ENABLED
00126 if (!g_thread_supported ()) g_thread_init (NULL);
00127 #endif // LL_GSTREAMER_ENABLED
00128 maybe_lock_display();
00129 gtk_is_good = gtk_init_check(NULL, NULL);
00130 maybe_unlock_display();
00131 if (!gtk_is_good)
00132 llwarns << "GTK Initialization failed." << llendl;
00133 }
00134
00135 if (gtk_is_good && !done_gtk_diag)
00136 {
00137 llinfos << "GTK Initialized." << llendl;
00138 llinfos << "- Compiled against GTK version "
00139 << GTK_MAJOR_VERSION << "."
00140 << GTK_MINOR_VERSION << "."
00141 << GTK_MICRO_VERSION << llendl;
00142 llinfos << "- Running against GTK version "
00143 << gtk_major_version << "."
00144 << gtk_minor_version << "."
00145 << gtk_micro_version << llendl;
00146 maybe_lock_display();
00147 const gchar* gtk_warning = gtk_check_version(
00148 GTK_MAJOR_VERSION,
00149 GTK_MINOR_VERSION,
00150 GTK_MICRO_VERSION);
00151 maybe_unlock_display();
00152 if (gtk_warning)
00153 {
00154 llwarns << "- GTK COMPATIBILITY WARNING: " <<
00155 gtk_warning << llendl;
00156 gtk_is_good = FALSE;
00157 }
00158
00159 done_gtk_diag = TRUE;
00160 }
00161
00162 return gtk_is_good;
00163 }
00164 #endif // LL_GTK
00165
00166
00167 #if LL_X11
00168 Window get_SDL_XWindowID(void)
00169 {
00170 if (gWindowImplementation) {
00171 return gWindowImplementation->mSDL_XWindowID;
00172 }
00173 return None;
00174 }
00175
00176 Display* get_SDL_Display(void)
00177 {
00178 if (gWindowImplementation) {
00179 return gWindowImplementation->mSDL_Display;
00180 }
00181 return NULL;
00182 }
00183 #endif // LL_X11
00184
00185
00186 BOOL check_for_card(const char* RENDERER, const char* bad_card)
00187 {
00188 if (!strncasecmp(RENDERER, bad_card, strlen(bad_card)))
00189 {
00190 char buffer[1024];
00191 snprintf(buffer, sizeof(buffer),
00192 "Your video card appears to be a %s, which Second Life does not support.\n"
00193 "\n"
00194 "Second Life requires a video card with 32 Mb of memory or more, as well as\n"
00195 "multitexture support. We explicitly support nVidia GeForce 2 or better, \n"
00196 "and ATI Radeon 8500 or better.\n"
00197 "\n"
00198 "If you own a supported card and continue to receive this message, try \n"
00199 "updating to the latest video card drivers. Otherwise look in the\n"
00200 "secondlife.com support section or e-mail technical support\n"
00201 "\n"
00202 "You can try to run Second Life, but it will probably crash or run\n"
00203 "very slowly. Try anyway?",
00204 bad_card);
00205 S32 button = OSMessageBox(buffer, "Unsupported video card", OSMB_YESNO);
00206 if (OSBTN_YES == button)
00207 {
00208 return FALSE;
00209 }
00210 else
00211 {
00212 return TRUE;
00213 }
00214 }
00215
00216 return FALSE;
00217 }
00218
00219
00220
00221
00222 LLWindowSDL::LLWindowSDL(char *title, S32 x, S32 y, S32 width,
00223 S32 height, U32 flags,
00224 BOOL fullscreen, BOOL clearBg,
00225 BOOL disable_vsync, BOOL use_gl,
00226 BOOL ignore_pixel_depth, U32 fsaa_samples)
00227 : LLWindow(fullscreen, flags), mGamma(1.0f)
00228 {
00229
00230 gKeyboard = new LLKeyboardSDL();
00231
00232
00233
00234 mWindow = NULL;
00235 mCursorDecoupled = FALSE;
00236 mCursorLastEventDeltaX = 0;
00237 mCursorLastEventDeltaY = 0;
00238 mCursorIgnoreNextDelta = FALSE;
00239 mNeedsResize = FALSE;
00240 mOverrideAspectRatio = 0.f;
00241 mGrabbyKeyFlags = 0;
00242 mReallyCapturedCount = 0;
00243 mHaveInputFocus = -1;
00244 mIsMinimized = -1;
00245 mFSAASamples = fsaa_samples;
00246
00247 #if LL_X11
00248 mSDL_XWindowID = None;
00249 mSDL_Display = NULL;
00250 #endif // LL_X11
00251
00252 #if LL_GTK
00253
00254
00255
00256
00257 ll_try_gtk_init();
00258 #endif // LL_GTK
00259
00260
00261 mOriginalAspectRatio = 1024.0 / 768.0;
00262
00263 if (!title)
00264 title = "SDL Window";
00265
00266
00267 mWindowTitle = new char[strlen(title) + 1];
00268 if(mWindowTitle == NULL)
00269 {
00270 llwarns << "Memory allocation failure" << llendl;
00271 return;
00272 }
00273
00274 strcpy(mWindowTitle, title);
00275
00276 if(createContext(x, y, width, height, 32, fullscreen, disable_vsync))
00277 {
00278 gGLManager.initGL();
00279
00280
00281 initCursors();
00282 setCursor( UI_CURSOR_ARROW );
00283 }
00284
00285 stop_glerror();
00286
00287
00288 gWindowImplementation = this;
00289
00290 #if LL_X11
00291 mFlashing = FALSE;
00292 #endif // LL_X11
00293 }
00294
00295 static SDL_Surface *Load_BMP_Resource(const char *basename)
00296 {
00297 const int PATH_BUFFER_SIZE=1000;
00298 char path_buffer[PATH_BUFFER_SIZE];
00299
00300
00301 snprintf(path_buffer, PATH_BUFFER_SIZE-1, "%s%sres-sdl%s%s",
00302 gDirUtilp->getAppRODataDir().c_str(),
00303 gDirUtilp->getDirDelimiter().c_str(),
00304 gDirUtilp->getDirDelimiter().c_str(),
00305 basename);
00306 path_buffer[PATH_BUFFER_SIZE-1] = '\0';
00307
00308 return SDL_LoadBMP(path_buffer);
00309 }
00310
00311 #if LL_X11
00312
00313
00314
00315
00316 static int x11_detect_VRAM_kb_fp(FILE *fp, const char *prefix_str)
00317 {
00318 const int line_buf_size = 1000;
00319 char line_buf[line_buf_size];
00320 while (fgets(line_buf, line_buf_size, fp))
00321 {
00322
00323
00324
00325
00326
00327
00328 const char *part1_template = prefix_str;
00329 const char part2_template[] = " kB";
00330 char *part1 = strstr(line_buf, part1_template);
00331 if (part1)
00332 {
00333 part1 = &part1[strlen(part1_template)];
00334 char *part2 = strstr(part1, part2_template);
00335 if (part2)
00336 {
00337
00338
00339
00340 int rtn = 0;
00341 for (; part1 < part2; ++part1)
00342 {
00343 if (*part1 < '0' || *part1 > '9')
00344 {
00345
00346 rtn = 0;
00347 break;
00348 }
00349 rtn *= 10;
00350 rtn += (*part1) - '0';
00351 }
00352 if (rtn > 0)
00353 {
00354
00355 return rtn;
00356 }
00357 }
00358 }
00359 }
00360 return 0;
00361 }
00362
00363 static int x11_detect_VRAM_kb()
00364 {
00365 #if LL_SOLARIS
00366 #error Can this be done without an explicit architecture test, ie a test FOR xorg? Was followed by: && defined(__sparc)
00367
00368
00369 return(0);
00370 #else
00371
00372 std::string x_log_location("/var/log/");
00373 std::string fname;
00374 int rtn = 0;
00375 int display_num = 0;
00376 FILE *fp;
00377 char *display_env = getenv("DISPLAY");
00378
00379 if (display_env[0] == ':' &&
00380 display_env[1] >= '0' && display_env[1] <= '9')
00381 {
00382 display_num = display_env[1] - '0';
00383 }
00384
00385
00386
00387
00388
00389 fname = x_log_location;
00390 fname += "Xorg.";
00391 fname += ('0' + display_num);
00392 fname += ".log";
00393 fp = fopen(fname.c_str(), "r");
00394 if (fp)
00395 {
00396 llinfos << "Looking in " << fname
00397 << " for VRAM info..." << llendl;
00398 rtn = x11_detect_VRAM_kb_fp(fp, ": VideoRAM: ");
00399 fclose(fp);
00400 if (0 == rtn)
00401 {
00402 fp = fopen(fname.c_str(), "r");
00403 if (fp)
00404 {
00405 rtn = x11_detect_VRAM_kb_fp(fp, ": Memory: ");
00406 fclose(fp);
00407 }
00408 }
00409 }
00410 else
00411 {
00412 llinfos << "Could not open " << fname
00413 << " - skipped." << llendl;
00414
00415 fname = x_log_location;
00416 fname += "XFree86.";
00417 fname += ('0' + display_num);
00418 fname += ".log";
00419 fp = fopen(fname.c_str(), "r");
00420 if (fp)
00421 {
00422 llinfos << "Looking in " << fname
00423 << " for VRAM info..." << llendl;
00424 rtn = x11_detect_VRAM_kb_fp(fp, ": VideoRAM: ");
00425 fclose(fp);
00426 if (0 == rtn)
00427 {
00428 fp = fopen(fname.c_str(), "r");
00429 if (fp)
00430 {
00431 rtn = x11_detect_VRAM_kb_fp(fp, ": Memory: ");
00432 fclose(fp);
00433 }
00434 }
00435 }
00436 else
00437 {
00438 llinfos << "Could not open " << fname
00439 << " - skipped." << llendl;
00440 }
00441 }
00442 return rtn;
00443 #endif // LL_SOLARIS
00444 }
00445 #endif // LL_X11
00446
00447 BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync)
00448 {
00449
00450
00451
00452 llinfos << "createContext, fullscreen=" << fullscreen <<
00453 " size=" << width << "x" << height << llendl;
00454
00455
00456 mGrabbyKeyFlags = 0;
00457 mReallyCapturedCount = 0;
00458
00459 if (SDL_Init(SDL_INIT_VIDEO) < 0)
00460 {
00461 llinfos << "sdl_init() failed! " << SDL_GetError() << llendl;
00462 setupFailure("window creation error", "error", OSMB_OK);
00463 return false;
00464 }
00465
00466 SDL_version c_sdl_version;
00467 SDL_VERSION(&c_sdl_version);
00468 llinfos << "Compiled against SDL "
00469 << int(c_sdl_version.major) << "."
00470 << int(c_sdl_version.minor) << "."
00471 << int(c_sdl_version.patch) << llendl;
00472 const SDL_version *r_sdl_version;
00473 r_sdl_version = SDL_Linked_Version();
00474 llinfos << " Running against SDL "
00475 << int(r_sdl_version->major) << "."
00476 << int(r_sdl_version->minor) << "."
00477 << int(r_sdl_version->patch) << llendl;
00478
00479 const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo( );
00480 if (!videoInfo)
00481 {
00482 llinfos << "SDL_GetVideoInfo() failed! " << SDL_GetError() << llendl;
00483 setupFailure("Window creation error", "Error", OSMB_OK);
00484 return FALSE;
00485 }
00486
00487 SDL_EnableUNICODE(1);
00488 SDL_WM_SetCaption(mWindowTitle, mWindowTitle);
00489
00490
00491 SDL_Surface *bmpsurface;
00492 bmpsurface = Load_BMP_Resource("ll_icon.BMP");
00493 if (bmpsurface)
00494 {
00495
00496 SDL_SetColorKey(bmpsurface,
00497 SDL_SRCCOLORKEY,
00498 SDL_MapRGB(bmpsurface->format, 0,0,0) );
00499 SDL_WM_SetIcon(bmpsurface, NULL);
00500
00501
00502 SDL_FreeSurface(bmpsurface);
00503 bmpsurface = NULL;
00504 }
00505
00506
00507
00508
00509
00510 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
00511 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,8);
00512 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
00513 #if !LL_SOLARIS
00514 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, (bits <= 16) ? 16 : 24);
00515
00516 if (!getenv("LL_GL_NO_STENCIL"))
00517 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
00518 #else
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
00533 #endif
00534 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, (bits <= 16) ? 1 : 8);
00535
00536
00537
00538 mFullscreen = fullscreen;
00539 was_fullscreen = fullscreen;
00540
00541 int sdlflags = SDL_OPENGL | SDL_RESIZABLE | SDL_ANYFORMAT;
00542
00543 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
00544
00545 if (mFSAASamples > 0)
00546 {
00547 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
00548 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, mFSAASamples);
00549 }
00550
00551 mSDLFlags = sdlflags;
00552
00553 if (mFullscreen)
00554 {
00555 llinfos << "createContext: setting up fullscreen " << width << "x" << height << llendl;
00556
00557
00558 if((width == 0) || (height == 0))
00559 {
00560
00561
00562
00563 S32 resolutionCount = 0;
00564 LLWindowResolution *resolutionList = getSupportedResolutions(resolutionCount);
00565
00566 if(resolutionList != NULL)
00567 {
00568 F32 closestAspect = 0;
00569 U32 closestHeight = 0;
00570 U32 closestWidth = 0;
00571 int i;
00572
00573 llinfos << "createContext: searching for a display mode, original aspect is " << mOriginalAspectRatio << llendl;
00574
00575 for(i=0; i < resolutionCount; i++)
00576 {
00577 F32 aspect = (F32)resolutionList[i].mWidth / (F32)resolutionList[i].mHeight;
00578
00579 llinfos << "createContext: width " << resolutionList[i].mWidth << " height " << resolutionList[i].mHeight << " aspect " << aspect << llendl;
00580
00581 if( (resolutionList[i].mHeight >= 700) && (resolutionList[i].mHeight <= 800) &&
00582 (fabs(aspect - mOriginalAspectRatio) < fabs(closestAspect - mOriginalAspectRatio)))
00583 {
00584 llinfos << " (new closest mode) " << llendl;
00585
00586
00587 closestWidth = resolutionList[i].mWidth;
00588 closestHeight = resolutionList[i].mHeight;
00589 closestAspect = aspect;
00590 }
00591 }
00592
00593 width = closestWidth;
00594 height = closestHeight;
00595 }
00596 }
00597
00598 if((width == 0) || (height == 0))
00599 {
00600
00601 width = 1024;
00602 height = 768;
00603 }
00604
00605 mWindow = SDL_SetVideoMode(width, height, bits, sdlflags | SDL_FULLSCREEN);
00606 if (!mWindow && bits > 16)
00607 {
00608 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
00609 mWindow = SDL_SetVideoMode(width, height, bits, sdlflags | SDL_FULLSCREEN);
00610 }
00611
00612 if (mWindow)
00613 {
00614 mFullscreen = TRUE;
00615 was_fullscreen = TRUE;
00616 mFullscreenWidth = mWindow->w;
00617 mFullscreenHeight = mWindow->h;
00618 mFullscreenBits = mWindow->format->BitsPerPixel;
00619 mFullscreenRefresh = -1;
00620
00621 llinfos << "Running at " << mFullscreenWidth
00622 << "x" << mFullscreenHeight
00623 << "x" << mFullscreenBits
00624 << " @ " << mFullscreenRefresh
00625 << llendl;
00626 }
00627 else
00628 {
00629 llwarns << "createContext: fullscreen creation failure. SDL: " << SDL_GetError() << llendl;
00630
00631 mFullscreen = FALSE;
00632 was_fullscreen = FALSE;
00633 mFullscreenWidth = -1;
00634 mFullscreenHeight = -1;
00635 mFullscreenBits = -1;
00636 mFullscreenRefresh = -1;
00637
00638 char error[256];
00639 snprintf(error, sizeof(error), "Unable to run fullscreen at %d x %d.\nRunning in window.", width, height);
00640 OSMessageBox(error, "Error", OSMB_OK);
00641 }
00642 }
00643
00644 if(!mFullscreen && (mWindow == NULL))
00645 {
00646 if (width == 0)
00647 width = 1024;
00648 if (height == 0)
00649 width = 768;
00650
00651 llinfos << "createContext: creating window " << width << "x" << height << "x" << bits << llendl;
00652 mWindow = SDL_SetVideoMode(width, height, bits, sdlflags);
00653 if (!mWindow && bits > 16)
00654 {
00655 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
00656 mWindow = SDL_SetVideoMode(width, height, bits, sdlflags);
00657 }
00658
00659 if (!mWindow)
00660 {
00661 llwarns << "createContext: window creation failure. SDL: " << SDL_GetError() << llendl;
00662 setupFailure("Window creation error", "Error", OSMB_OK);
00663 return FALSE;
00664 }
00665 } else if (!mFullscreen && (mWindow != NULL))
00666 {
00667 llinfos << "createContext: SKIPPING - !fullscreen, but +mWindow " << width << "x" << height << "x" << bits << llendl;
00668 }
00669
00670
00671 # if LL_X11
00672 gGLManager.mVRAM = x11_detect_VRAM_kb() / 1024;
00673 if (gGLManager.mVRAM != 0)
00674 {
00675 llinfos << "X11 log-parser detected " << gGLManager.mVRAM << "MB VRAM." << llendl;
00676 } else
00677 # endif // LL_X11
00678 {
00679
00680
00681
00682 gGLManager.mVRAM = videoInfo->video_mem / 1024;
00683 if (gGLManager.mVRAM != 0)
00684 {
00685 llinfos << "SDL detected " << gGLManager.mVRAM << "MB VRAM." << llendl;
00686 }
00687 }
00688
00689
00690
00691
00692
00693
00694 GLint depthBits, stencilBits, redBits, greenBits, blueBits, alphaBits;
00695
00696 glGetIntegerv(GL_RED_BITS, &redBits);
00697 glGetIntegerv(GL_GREEN_BITS, &greenBits);
00698 glGetIntegerv(GL_BLUE_BITS, &blueBits);
00699 glGetIntegerv(GL_ALPHA_BITS, &alphaBits);
00700 glGetIntegerv(GL_DEPTH_BITS, &depthBits);
00701 glGetIntegerv(GL_STENCIL_BITS, &stencilBits);
00702
00703 llinfos << "GL buffer:" << llendl
00704 llinfos << " Red Bits " << S32(redBits) << llendl
00705 llinfos << " Green Bits " << S32(greenBits) << llendl
00706 llinfos << " Blue Bits " << S32(blueBits) << llendl
00707 llinfos << " Alpha Bits " << S32(alphaBits) << llendl
00708 llinfos << " Depth Bits " << S32(depthBits) << llendl
00709 llinfos << " Stencil Bits " << S32(stencilBits) << llendl;
00710
00711 GLint colorBits = redBits + greenBits + blueBits + alphaBits;
00712
00713
00714
00715 #if LL_SOLARIS
00716 #error && defined(__sparc)
00717 if(colorBits < 24)
00718 #else
00719 if (colorBits < 32)
00720 #endif
00721 {
00722 close();
00723 setupFailure(
00724 #if LL_SOLARIS
00725 #error && defined(__sparc)
00726 "Second Life requires at least 24-bit color on SPARC to run in a window.\n"
00727 "Please use fbconfig to set your default color depth to 24 bits.\n"
00728 "You may also need to adjust the X11 setting in SMF. To do so use\n"
00729 " 'svccfg -s svc:/application/x11/x11-server setprop options/default_depth=24'\n"
00730 #else
00731 "Second Life requires True Color (32-bit) to run in a window.\n"
00732 "Please go to Control Panels -> Display -> Settings and\n"
00733 "set the screen to 32-bit color.\n"
00734 #endif
00735 "Alternately, if you choose to run fullscreen, Second Life\n"
00736 "will automatically adjust the screen each time it runs.",
00737 "Error",
00738 OSMB_OK);
00739 return FALSE;
00740 }
00741
00742 #if 0 // *FIX: we're going to brave it for now...
00743 if (alphaBits < 8)
00744 {
00745 close();
00746 setupFailure(
00747 "Second Life is unable to run because it can't get an 8 bit alpha\n"
00748 "channel. Usually this is due to video card driver issues.\n"
00749 "Please make sure you have the latest video card drivers installed.\n"
00750 "Also be sure your monitor is set to True Color (32-bit) in\n"
00751 "Control Panels -> Display -> Settings.\n"
00752 "If you continue to receive this message, contact customer service.",
00753 "Error",
00754 OSMB_OK);
00755 return FALSE;
00756 }
00757 #endif
00758
00759 #if LL_X11
00760 init_x11clipboard();
00761 #endif // LL_X11
00762
00763
00764 glDisable(GL_MULTISAMPLE_ARB);
00765
00766
00767 if (-1 == SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,
00768 SDL_DEFAULT_REPEAT_INTERVAL))
00769 llwarns << "Couldn't enable key-repeat: " << SDL_GetError() <<llendl;
00770
00771
00772 return TRUE;
00773 }
00774
00775
00776
00777 BOOL LLWindowSDL::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp)
00778 {
00779 const BOOL needsRebuild = TRUE;
00780 BOOL result = true;
00781
00782 llinfos << "switchContext, fullscreen=" << fullscreen << llendl;
00783 stop_glerror();
00784 if(needsRebuild)
00785 {
00786 destroyContext();
00787 result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, disable_vsync);
00788 if (result)
00789 {
00790 gGLManager.initGL();
00791
00792
00793 initCursors();
00794 setCursor( UI_CURSOR_ARROW );
00795 }
00796 }
00797
00798 stop_glerror();
00799
00800 return result;
00801 }
00802
00803 void LLWindowSDL::destroyContext()
00804 {
00805 llinfos << "destroyContext begins" << llendl;
00806 #if LL_X11
00807 quit_x11clipboard();
00808 #endif // LL_X11
00809
00810
00811 llinfos << "shutdownGL begins" << llendl;
00812 gGLManager.shutdownGL();
00813 llinfos << "SDL_QuitSS/VID begins" << llendl;
00814 SDL_QuitSubSystem(SDL_INIT_VIDEO);
00815
00816 mWindow = NULL;
00817 }
00818
00819 LLWindowSDL::~LLWindowSDL()
00820 {
00821 quitCursors();
00822 destroyContext();
00823
00824 if(mSupportedResolutions != NULL)
00825 {
00826 delete []mSupportedResolutions;
00827 }
00828
00829 delete[] mWindowTitle;
00830
00831 gWindowImplementation = NULL;
00832 }
00833
00834
00835 void LLWindowSDL::show()
00836 {
00837
00838 }
00839
00840 void LLWindowSDL::hide()
00841 {
00842
00843 }
00844
00845 void LLWindowSDL::minimize()
00846 {
00847
00848 }
00849
00850 void LLWindowSDL::restore()
00851 {
00852
00853 }
00854
00855
00856
00857
00858 void LLWindowSDL::close()
00859 {
00860
00861
00862
00863
00864
00865
00866
00867 setMouseClipping(FALSE);
00868 showCursor();
00869
00870 destroyContext();
00871 }
00872
00873 BOOL LLWindowSDL::isValid()
00874 {
00875 return (mWindow != NULL);
00876 }
00877
00878 BOOL LLWindowSDL::getVisible()
00879 {
00880 BOOL result = FALSE;
00881
00882
00883
00884 if (mWindow)
00885 {
00886 result = TRUE;
00887 }
00888
00889 return(result);
00890 }
00891
00892 BOOL LLWindowSDL::getMinimized()
00893 {
00894 BOOL result = FALSE;
00895
00896 if (mWindow && (1 == mIsMinimized))
00897 {
00898 result = TRUE;
00899 }
00900 return(result);
00901 }
00902
00903 BOOL LLWindowSDL::getMaximized()
00904 {
00905 BOOL result = FALSE;
00906
00907 if (mWindow)
00908 {
00909
00910 }
00911
00912 return(result);
00913 }
00914
00915 BOOL LLWindowSDL::maximize()
00916 {
00917
00918 return FALSE;
00919 }
00920
00921 BOOL LLWindowSDL::getFullscreen()
00922 {
00923 return mFullscreen;
00924 }
00925
00926 BOOL LLWindowSDL::getPosition(LLCoordScreen *position)
00927 {
00928
00929 position->mX = 0;
00930 position->mY = 0;
00931 return TRUE;
00932 }
00933
00934 BOOL LLWindowSDL::getSize(LLCoordScreen *size)
00935 {
00936 if (mWindow)
00937 {
00938 size->mX = mWindow->w;
00939 size->mY = mWindow->h;
00940 return (TRUE);
00941 }
00942
00943 llwarns << "LLWindowSDL::getPosition(): no window and not fullscreen!" << llendl;
00944 return (FALSE);
00945 }
00946
00947 BOOL LLWindowSDL::getSize(LLCoordWindow *size)
00948 {
00949 if (mWindow)
00950 {
00951 size->mX = mWindow->w;
00952 size->mY = mWindow->h;
00953 return (TRUE);
00954 }
00955
00956 llwarns << "LLWindowSDL::getPosition(): no window and not fullscreen!" << llendl;
00957 return (FALSE);
00958 }
00959
00960 BOOL LLWindowSDL::setPosition(const LLCoordScreen position)
00961 {
00962 if(mWindow)
00963 {
00964
00965
00966 }
00967
00968 return TRUE;
00969 }
00970
00971 BOOL LLWindowSDL::setSize(const LLCoordScreen size)
00972 {
00973 if(mWindow)
00974 {
00975
00976
00977 }
00978
00979 return TRUE;
00980 }
00981
00982 void LLWindowSDL::swapBuffers()
00983 {
00984 if (mWindow)
00985 SDL_GL_SwapBuffers();
00986 }
00987
00988 U32 LLWindowSDL::getFSAASamples()
00989 {
00990 return mFSAASamples;
00991 }
00992
00993 void LLWindowSDL::setFSAASamples(const U32 samples)
00994 {
00995 mFSAASamples = samples;
00996 }
00997
00998 F32 LLWindowSDL::getGamma()
00999 {
01000 return 1/mGamma;
01001 }
01002
01003 BOOL LLWindowSDL::restoreGamma()
01004 {
01005
01006 SDL_SetGamma(1.0f, 1.0f, 1.0f);
01007 return true;
01008 }
01009
01010 BOOL LLWindowSDL::setGamma(const F32 gamma)
01011 {
01012 mGamma = gamma;
01013 if (mGamma == 0) mGamma = 0.1f;
01014 mGamma = 1/mGamma;
01015 SDL_SetGamma(mGamma, mGamma, mGamma);
01016 return true;
01017 }
01018
01019 BOOL LLWindowSDL::isCursorHidden()
01020 {
01021 return mCursorHidden;
01022 }
01023
01024
01025
01026
01027 void LLWindowSDL::setMouseClipping( BOOL b )
01028 {
01029
01030
01031 mIsMouseClipping = b;
01032
01033 adjustCursorDecouple();
01034 }
01035
01036 BOOL LLWindowSDL::setCursorPosition(const LLCoordWindow position)
01037 {
01038 BOOL result = TRUE;
01039 LLCoordScreen screen_pos;
01040
01041 if (!convertCoords(position, &screen_pos))
01042 {
01043 return FALSE;
01044 }
01045
01046
01047
01048 SDL_WarpMouse(screen_pos.mX, screen_pos.mY);
01049
01050
01051 adjustCursorDecouple(true);
01052
01053 return result;
01054 }
01055
01056 BOOL LLWindowSDL::getCursorPosition(LLCoordWindow *position)
01057 {
01058
01059 LLCoordScreen screen_pos;
01060
01061
01062 int x, y;
01063 SDL_GetMouseState(&x, &y);
01064
01065 screen_pos.mX = x;
01066 screen_pos.mY = y;
01067
01068 return convertCoords(screen_pos, position);
01069 }
01070
01071 void LLWindowSDL::adjustCursorDecouple(bool warpingMouse)
01072 {
01073 if(mIsMouseClipping && mCursorHidden)
01074 {
01075 if(warpingMouse)
01076 {
01077
01078 if(!mCursorDecoupled)
01079 {
01080
01081
01082 mCursorDecoupled = true;
01083 mCursorIgnoreNextDelta = TRUE;
01084 }
01085 }
01086 }
01087 else
01088 {
01089
01090 if(mCursorDecoupled)
01091 {
01092
01093
01094 mCursorDecoupled = false;
01095 }
01096 }
01097 }
01098
01099 F32 LLWindowSDL::getNativeAspectRatio()
01100 {
01101 #if 0
01102
01103
01104
01105 S32 num_resolutions;
01106 LLWindowResolution* resolutions = getSupportedResolutions(num_resolutions);
01107
01108
01109 return ((F32)resolutions[num_resolutions - 1].mWidth / (F32)resolutions[num_resolutions - 1].mHeight);
01110
01111 #endif
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130 if (mOverrideAspectRatio > 0.f)
01131 {
01132 return mOverrideAspectRatio;
01133 }
01134
01135 return mOriginalAspectRatio;
01136 }
01137
01138 F32 LLWindowSDL::getPixelAspectRatio()
01139 {
01140 F32 pixel_aspect = 1.f;
01141 if (getFullscreen())
01142 {
01143 LLCoordScreen screen_size;
01144 if (getSize(&screen_size))
01145 {
01146 pixel_aspect = getNativeAspectRatio() * (F32)screen_size.mY / (F32)screen_size.mX;
01147 }
01148 }
01149
01150 return pixel_aspect;
01151 }
01152
01153
01154
01155
01156
01157 static LLCoordScreen old_size;
01158 static BOOL old_fullscreen;
01159 void LLWindowSDL::beforeDialog()
01160 {
01161 llinfos << "LLWindowSDL::beforeDialog()" << llendl;
01162
01163 if (SDLReallyCaptureInput(FALSE)
01164 && getSize(&old_size))
01165 {
01166 old_fullscreen = was_fullscreen;
01167
01168 if (old_fullscreen)
01169 {
01170
01171
01172 }
01173 }
01174
01175 #if LL_X11
01176 if (mSDL_Display)
01177 {
01178
01179
01180 maybe_lock_display();
01181 XSync(mSDL_Display, False);
01182 maybe_unlock_display();
01183 }
01184 #endif // LL_X11
01185
01186 #if LL_GTK
01187
01188
01189 ll_try_gtk_init();
01190 #endif // LL_GTK
01191
01192 maybe_lock_display();
01193 }
01194
01195 void LLWindowSDL::afterDialog()
01196 {
01197 llinfos << "LLWindowSDL::afterDialog()" << llendl;
01198
01199 maybe_unlock_display();
01200
01201 if (old_fullscreen && !was_fullscreen)
01202 {
01203
01204
01205 }
01206
01207
01208 }
01209
01210
01211 S32 LLWindowSDL::stat(const char* file_name, struct stat* stat_info)
01212 {
01213 return ::stat( file_name, stat_info );
01214 }
01215
01216 #if LL_X11
01217
01218 void LLWindowSDL::x11_set_urgent(BOOL urgent)
01219 {
01220 if (mSDL_Display && !mFullscreen)
01221 {
01222 XWMHints *wm_hints;
01223
01224 llinfos << "X11 hint for urgency, " << urgent << llendl;
01225
01226 maybe_lock_display();
01227 wm_hints = XGetWMHints(mSDL_Display, mSDL_XWindowID);
01228 if (!wm_hints)
01229 wm_hints = XAllocWMHints();
01230
01231 if (urgent)
01232 wm_hints->flags |= XUrgencyHint;
01233 else
01234 wm_hints->flags &= ~XUrgencyHint;
01235
01236 XSetWMHints(mSDL_Display, mSDL_XWindowID, wm_hints);
01237 XFree(wm_hints);
01238 XSync(mSDL_Display, False);
01239 maybe_unlock_display();
01240 }
01241 }
01242 #endif // LL_X11
01243
01244 void LLWindowSDL::flashIcon(F32 seconds)
01245 {
01246 #if !LL_X11
01247 llinfos << "Stub LLWindowSDL::flashIcon(" << seconds << ")" << llendl;
01248 #else
01249 llinfos << "X11 LLWindowSDL::flashIcon(" << seconds << ")" << llendl;
01250
01251 F32 remaining_time = mFlashTimer.getRemainingTimeF32();
01252 if (remaining_time < seconds)
01253 remaining_time = seconds;
01254 mFlashTimer.reset();
01255 mFlashTimer.setTimerExpirySec(remaining_time);
01256
01257 x11_set_urgent(TRUE);
01258 mFlashing = TRUE;
01259 #endif // LL_X11
01260 }
01261
01262 #if LL_X11
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272 typedef Atom x11clipboard_type;
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286 static x11clipboard_type get_x11_readwrite_clipboard_type(void)
01287 {
01288 return XInternAtom(get_SDL_Display(), "CLIPBOARD", False);
01289 }
01290
01291 static x11clipboard_type get_x11_write_clipboard_type(void)
01292 {
01293 return XA_PRIMARY;
01294 }
01295
01296
01297
01298
01299 static x11clipboard_type get_x11_cutbuffer_clipboard_type(void)
01300 {
01301 return XInternAtom(get_SDL_Display(), "SECONDLIFE_CUTBUFFER", False);
01302 }
01303
01304
01305 static Atom get_x11_targets_atom(void)
01306 {
01307 return XInternAtom(get_SDL_Display(), "TARGETS", False);
01308 }
01309
01310 static Atom get_x11_text_atom(void)
01311 {
01312 return XInternAtom(get_SDL_Display(), "TEXT", False);
01313 }
01314
01315
01316
01317
01318
01319 #define SDLCLIPTYPE(A, B, C, D) (int)(((A)<<24)|((B)<<16)|((C)<<8)|((D)<<0))
01320 #define FORMAT_PREFIX "SECONDLIFE_x11clipboard_0x"
01321
01322 static
01323 x11clipboard_type convert_format(int type)
01324 {
01325 if (!gWindowImplementation)
01326 {
01327 llwarns << "!gWindowImplementation in convert_format()"
01328 << llendl;
01329 return XA_STRING;
01330 }
01331
01332 switch (type)
01333 {
01334 case SDLCLIPTYPE('T', 'E', 'X', 'T'):
01335
01336 return XA_STRING;
01337 case SDLCLIPTYPE('U', 'T', 'F', '8'):
01338
01339 return XInternAtom(gWindowImplementation->mSDL_Display,
01340 "UTF8_STRING", False);
01341 default:
01342 {
01343
01344
01345 char format[sizeof(FORMAT_PREFIX)+8+1];
01346
01347 snprintf(format, sizeof(format), "%s%08lx", FORMAT_PREFIX, (unsigned long)type);
01348 return XInternAtom(gWindowImplementation->mSDL_Display,
01349 format, False);
01350 }
01351 }
01352 }
01353
01354
01355
01356 static int
01357 convert_data(int type, char *dst, const char *src, int srclen)
01358 {
01359 int dstlen;
01360
01361 dstlen = 0;
01362 switch (type)
01363 {
01364 case SDLCLIPTYPE('T', 'E', 'X', 'T'):
01365 case SDLCLIPTYPE('U', 'T', 'F', '8'):
01366 if (src == NULL)
01367 {
01368 break;
01369 }
01370 if ( srclen == 0 )
01371 srclen = strlen(src);
01372
01373 dstlen = srclen + 1;
01374
01375 if ( dst )
01376 {
01377 memcpy(dst, src, srclen);
01378 dst[srclen] = '\0';
01379 }
01380 break;
01381
01382 default:
01383 llwarns << "convert_data: Unknown medium type" << llendl;
01384 break;
01385 }
01386 return(dstlen);
01387 }
01388
01389
01390
01391
01392 static int
01393 convert_x11clipboard(int type, char *dst, const char *src, int srclen)
01394 {
01395 int dstlen;
01396
01397 dstlen = 0;
01398 switch (type)
01399 {
01400 case SDLCLIPTYPE('U', 'T', 'F', '8'):
01401 case SDLCLIPTYPE('T', 'E', 'X', 'T'):
01402 if (src == NULL)
01403 {
01404 break;
01405 }
01406 if ( srclen == 0 )
01407 srclen = strlen(src);
01408
01409 dstlen = srclen + 1;
01410
01411 if ( dst )
01412 {
01413 memcpy(dst, src, srclen);
01414 dst[srclen] = '\0';
01415 }
01416 break;
01417
01418 default:
01419 llwarns << "convert_x11clipboard: Unknown medium type" << llendl;
01420 break;
01421 }
01422 return dstlen;
01423 }
01424
01425 int
01426 LLWindowSDL::is_empty_x11clipboard(void)
01427 {
01428 int retval;
01429
01430 maybe_lock_display();
01431 retval = ( XGetSelectionOwner(mSDL_Display, get_x11_readwrite_clipboard_type()) == None );
01432 maybe_unlock_display();
01433
01434 return(retval);
01435 }
01436
01437 void
01438 LLWindowSDL::put_x11clipboard(int type, int srclen, const char *src)
01439 {
01440 x11clipboard_type format;
01441 int dstlen;
01442 char *dst;
01443
01444 format = convert_format(type);
01445 dstlen = convert_data(type, NULL, src, srclen);
01446
01447 dst = (char *)malloc(dstlen);
01448 if ( dst != NULL )
01449 {
01450 maybe_lock_display();
01451 Window root = DefaultRootWindow(mSDL_Display);
01452 convert_data(type, dst, src, srclen);
01453
01454
01455
01456 if (type == SDLCLIPTYPE('T','E','X','T'))
01457 {
01458
01459 llinfos << "X11: Populating cutbuffer." <<llendl;
01460 XChangeProperty(mSDL_Display, root,
01461 XA_CUT_BUFFER0, XA_STRING, 8, PropModeReplace,
01462 (unsigned char*)dst, dstlen-1);
01463 } else {
01464
01465
01466
01467 }
01468
01469 XChangeProperty(mSDL_Display, root,
01470 get_x11_cutbuffer_clipboard_type(), format, 8, PropModeReplace,
01471 (unsigned char*)dst, dstlen-1);
01472 free(dst);
01473
01474
01475 XSetSelectionOwner(mSDL_Display, get_x11_readwrite_clipboard_type(),
01476 mSDL_XWindowID, CurrentTime);
01477 XSetSelectionOwner(mSDL_Display, get_x11_write_clipboard_type(),
01478 mSDL_XWindowID, CurrentTime);
01479
01480 maybe_unlock_display();
01481 }
01482 }
01483
01484 void
01485 LLWindowSDL::get_x11clipboard(int type, int *dstlen, char **dst)
01486 {
01487 x11clipboard_type format;
01488
01489 *dstlen = 0;
01490 format = convert_format(type);
01491
01492 Window owner;
01493 Atom selection;
01494 Atom seln_type;
01495 int seln_format;
01496 unsigned long nbytes;
01497 unsigned long overflow;
01498 char *src;
01499
01500 maybe_lock_display();
01501 owner = XGetSelectionOwner(mSDL_Display, get_x11_readwrite_clipboard_type());
01502 maybe_unlock_display();
01503 if (owner == None)
01504 {
01505
01506 owner = DefaultRootWindow(mSDL_Display);
01507 selection = XA_CUT_BUFFER0;
01508 } else if (owner == mSDL_XWindowID)
01509 {
01510
01511 owner = DefaultRootWindow(mSDL_Display);
01512 selection = get_x11_cutbuffer_clipboard_type();
01513 }
01514 else
01515 {
01516
01517 int selection_response = 0;
01518 SDL_Event event;
01519
01520 owner = mSDL_XWindowID;
01521 maybe_lock_display();
01522 selection = XInternAtom(mSDL_Display, "SDL_SELECTION", False);
01523 XConvertSelection(mSDL_Display, get_x11_readwrite_clipboard_type(), format,
01524 selection, owner, CurrentTime);
01525 maybe_unlock_display();
01526 llinfos << "X11: Waiting for clipboard to arrive." <<llendl;
01527 while ( ! selection_response )
01528 {
01529
01530
01531 SDL_PumpEvents();
01532 if (1 == SDL_PeepEvents(&event, 1, SDL_GETEVENT,
01533 SDL_SYSWMEVENTMASK) )
01534 {
01535 if ( event.type == SDL_SYSWMEVENT )
01536 {
01537 XEvent xevent =
01538 event.syswm.msg->event.xevent;
01539
01540 if ( (xevent.type == SelectionNotify)&&
01541 (xevent.xselection.requestor == owner) )
01542 selection_response = 1;
01543 }
01544 } else {
01545 llinfos << "X11: Waiting for SYSWM event..." << llendl;
01546 }
01547 }
01548 llinfos << "X11: Clipboard arrived." <<llendl;
01549 }
01550
01551 maybe_lock_display();
01552 if ( XGetWindowProperty(mSDL_Display, owner, selection, 0, INT_MAX/4,
01553 False, format, &seln_type, &seln_format,
01554 &nbytes, &overflow, (unsigned char **)&src) == Success )
01555 {
01556 if ( seln_type == format )
01557 {
01558 *dstlen = convert_x11clipboard(type, NULL, src, nbytes);
01559 *dst = (char *)realloc(*dst, *dstlen);
01560 if ( *dst == NULL )
01561 *dstlen = 0;
01562 else
01563 convert_x11clipboard(type, *dst, src, nbytes);
01564 }
01565 XFree(src);
01566 }
01567 maybe_unlock_display();
01568 }
01569
01570 int clipboard_filter_callback(const SDL_Event *event)
01571 {
01572
01573 if ( event->type != SDL_SYSWMEVENT )
01574 {
01575 return(1);
01576 }
01577
01578
01579 switch (event->syswm.msg->event.xevent.type) {
01580
01581 case SelectionRequest: {
01582 XSelectionRequestEvent *req;
01583 XEvent sevent;
01584 int seln_format;
01585 unsigned long nbytes;
01586 unsigned long overflow;
01587 unsigned char *seln_data;
01588
01589 req = &event->syswm.msg->event.xevent.xselectionrequest;
01590 sevent.xselection.type = SelectionNotify;
01591 sevent.xselection.display = req->display;
01592 sevent.xselection.selection = req->selection;
01593 sevent.xselection.target = None;
01594 sevent.xselection.property = None;
01595 sevent.xselection.requestor = req->requestor;
01596 sevent.xselection.time = req->time;
01597 if ( XGetWindowProperty(get_SDL_Display(), DefaultRootWindow(get_SDL_Display()),
01598 get_x11_cutbuffer_clipboard_type(), 0, INT_MAX/4, False, req->target,
01599 &sevent.xselection.target, &seln_format,
01600 &nbytes, &overflow, &seln_data) == Success )
01601 {
01602 if ( sevent.xselection.target == req->target)
01603 {
01604 if ( sevent.xselection.target == XA_STRING ||
01605 sevent.xselection.target ==
01606 convert_format(SDLCLIPTYPE('U','T','F','8')) )
01607 {
01608 if ( seln_data[nbytes-1] == '\0' )
01609 --nbytes;
01610 }
01611 XChangeProperty(get_SDL_Display(), req->requestor, req->property,
01612 req->target, seln_format, PropModeReplace,
01613 seln_data, nbytes);
01614 sevent.xselection.property = req->property;
01615 } else if (get_x11_targets_atom() == req->target) {
01616
01617 const int num_supported = 3;
01618 Atom supported[num_supported] = {
01619 XA_STRING,
01620 get_x11_text_atom(),
01621 get_x11_targets_atom()
01622 };
01623 supported[0] = sevent.xselection.target;
01624 XChangeProperty(get_SDL_Display(), req->requestor,
01625 req->property, XA_ATOM, 32, PropModeReplace,
01626 (unsigned char*)supported,
01627 num_supported);
01628 sevent.xselection.property = req->property;
01629 llinfos << "Clipboard: An app asked us what selections format we offer." << llendl;
01630 } else {
01631 llinfos << "Clipboard: An app requested an unsupported selection format " << req->target << ", we have " << sevent.xselection.target << llendl;
01632 sevent.xselection.target = None;
01633 }
01634 XFree(seln_data);
01635 }
01636 int sendret =
01637 XSendEvent(get_SDL_Display(),req->requestor,False,0,&sevent);
01638 if ((sendret==BadValue) || (sendret==BadWindow))
01639 llwarns << "Clipboard SendEvent failed" << llendl;
01640 XSync(get_SDL_Display(), False);
01641 }
01642 break;
01643 }
01644
01645
01646 return(1);
01647 }
01648
01649 int
01650 LLWindowSDL::init_x11clipboard(void)
01651 {
01652 SDL_SysWMinfo info;
01653 int retval;
01654
01655
01656 retval = -1;
01657 SDL_SetError("SDL is not running on known window manager");
01658
01659 SDL_VERSION(&info.version);
01660 if ( SDL_GetWMInfo(&info) )
01661 {
01662
01663 if ( info.subsystem == SDL_SYSWM_X11 )
01664 {
01665 mSDL_Display = info.info.x11.display;
01666 mSDL_XWindowID = info.info.x11.wmwindow;
01667 Lock_Display = info.info.x11.lock_func;
01668 Unlock_Display = info.info.x11.unlock_func;
01669
01670
01671 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
01672 SDL_SetEventFilter(clipboard_filter_callback);
01673
01674 retval = 0;
01675 }
01676 else
01677 {
01678 SDL_SetError("SDL is not running on X11");
01679 }
01680 }
01681 return(retval);
01682 }
01683
01684 void
01685 LLWindowSDL::quit_x11clipboard(void)
01686 {
01687 mSDL_Display = NULL;
01688 mSDL_XWindowID = None;
01689 Lock_Display = NULL;
01690 Unlock_Display = NULL;
01691
01692 SDL_SetEventFilter(NULL);
01693 }
01694
01695
01696
01697 BOOL LLWindowSDL::isClipboardTextAvailable()
01698 {
01699 return !is_empty_x11clipboard();
01700 }
01701
01702 BOOL LLWindowSDL::pasteTextFromClipboard(LLWString &dst)
01703 {
01704 int cliplen;
01705 char *cliptext = NULL;
01706 get_x11clipboard(SDLCLIPTYPE('U','T','F','8'), &cliplen, &cliptext);
01707 if (cliptext)
01708 {
01709 llinfos << "X11: Got UTF8 clipboard text." << llendl;
01710
01711
01712 std::string clip_str(cliptext);
01713
01714
01715
01716 dst = utf8str_to_wstring(clip_str);
01717
01718
01719
01720
01721
01722 free(cliptext);
01723 return TRUE;
01724 }
01725 get_x11clipboard(SDLCLIPTYPE('T','E','X','T'), &cliplen, &cliptext);
01726 if (cliptext)
01727 {
01728 llinfos << "X11: Got ISO 8859-1 clipboard text." << llendl;
01729 std::string clip_str(cliptext);
01730 std::string utf8_str = rawstr_to_utf8(clip_str);
01731 dst = utf8str_to_wstring(utf8_str);
01732 free(cliptext);
01733 }
01734 return FALSE;
01735 }
01736
01737 BOOL LLWindowSDL::copyTextToClipboard(const LLWString &s)
01738 {
01739 std::string utf8text = wstring_to_utf8str(s);
01740 const char* cstr = utf8text.c_str();
01741 if (cstr == NULL)
01742 {
01743 return FALSE;
01744 }
01745 int cstrlen = strlen(cstr);
01746 int i;
01747 for (i=0; i<cstrlen; ++i)
01748 {
01749 if (0x80 & (unsigned char)cstr[i])
01750 {
01751
01752 llinfos << "X11: UTF8 copyTextToClipboard" << llendl;
01753 put_x11clipboard(SDLCLIPTYPE('U','T','F','8'), cstrlen, cstr);
01754 return TRUE;
01755 }
01756 }
01757
01758 llinfos << "X11: ISO 8859-1 copyTextToClipboard" << llendl;
01759 put_x11clipboard(SDLCLIPTYPE('T','E','X','T'), cstrlen, cstr);
01760 return TRUE;
01761 }
01762 #else
01763
01764 BOOL LLWindowSDL::isClipboardTextAvailable()
01765 {
01766 return FALSE;
01767 }
01768
01769 BOOL LLWindowSDL::pasteTextFromClipboard(LLWString &dst)
01770 {
01771 return FALSE;
01772 }
01773
01774 BOOL LLWindowSDL::copyTextToClipboard(const LLWString &s)
01775 {
01776 return FALSE;
01777 }
01778 #endif // LL_X11
01779
01780 BOOL LLWindowSDL::sendEmail(const char* address, const char* subject, const char* body_text,
01781 const char* attachment, const char* attachment_displayed_name )
01782 {
01783
01784
01785 return FALSE;
01786 }
01787
01788
01789 LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_resolutions)
01790 {
01791 if (!mSupportedResolutions)
01792 {
01793 mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS];
01794 mNumSupportedResolutions = 0;
01795
01796 SDL_Rect **modes = SDL_ListModes(NULL, SDL_OPENGL | SDL_FULLSCREEN);
01797 if ( (modes != NULL) && (modes != ((SDL_Rect **) -1)) )
01798 {
01799 int count = 0;
01800 while (*modes)
01801 {
01802 modes++;
01803 count++;
01804 }
01805
01806 while (count--)
01807 {
01808 modes--;
01809 SDL_Rect *r = *modes;
01810 int w = r->w;
01811 int h = r->h;
01812 if ((w >= 800) && (h >= 600))
01813 {
01814
01815 if ( (mNumSupportedResolutions == 0) ||
01816 ((mSupportedResolutions[mNumSupportedResolutions-1].mWidth != w) &&
01817 (mSupportedResolutions[mNumSupportedResolutions-1].mHeight != h)) )
01818 {
01819 mSupportedResolutions[mNumSupportedResolutions].mWidth = w;
01820 mSupportedResolutions[mNumSupportedResolutions].mHeight = h;
01821 mNumSupportedResolutions++;
01822 }
01823 }
01824 }
01825 }
01826 }
01827
01828 num_resolutions = mNumSupportedResolutions;
01829 return mSupportedResolutions;
01830 }
01831
01832 BOOL LLWindowSDL::convertCoords(LLCoordGL from, LLCoordWindow *to)
01833 {
01834 if (!to)
01835 return FALSE;
01836
01837 to->mX = from.mX;
01838 to->mY = mWindow->h - from.mY - 1;
01839
01840 return TRUE;
01841 }
01842
01843 BOOL LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordGL* to)
01844 {
01845 if (!to)
01846 return FALSE;
01847
01848 to->mX = from.mX;
01849 to->mY = mWindow->h - from.mY - 1;
01850
01851 return TRUE;
01852 }
01853
01854 BOOL LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordWindow* to)
01855 {
01856 if (!to)
01857 return FALSE;
01858
01859
01860 to->mX = from.mX;
01861 to->mY = from.mY;
01862 return (TRUE);
01863 }
01864
01865 BOOL LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordScreen *to)
01866 {
01867 if (!to)
01868 return FALSE;
01869
01870
01871 to->mX = from.mX;
01872 to->mY = from.mY;
01873 return (TRUE);
01874 }
01875
01876 BOOL LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordGL *to)
01877 {
01878 LLCoordWindow window_coord;
01879
01880 return(convertCoords(from, &window_coord) && convertCoords(window_coord, to));
01881 }
01882
01883 BOOL LLWindowSDL::convertCoords(LLCoordGL from, LLCoordScreen *to)
01884 {
01885 LLCoordWindow window_coord;
01886
01887 return(convertCoords(from, &window_coord) && convertCoords(window_coord, to));
01888 }
01889
01890
01891
01892
01893 void LLWindowSDL::setupFailure(const char* text, const char* caption, U32 type)
01894 {
01895 destroyContext();
01896
01897 OSMessageBox(text, caption, type);
01898 }
01899
01900 BOOL LLWindowSDL::SDLReallyCaptureInput(BOOL capture)
01901 {
01902
01903
01904
01905 if (capture)
01906 mReallyCapturedCount = 1;
01907 else
01908 mReallyCapturedCount = 0;
01909
01910 SDL_GrabMode wantmode, newmode;
01911 if (mReallyCapturedCount <= 0)
01912 {
01913 wantmode = SDL_GRAB_OFF;
01914 } else
01915 {
01916 wantmode = SDL_GRAB_ON;
01917 }
01918
01919 if (mReallyCapturedCount < 0)
01920 {
01921 mReallyCapturedCount = 0;
01922 llwarns << "ReallyCapture count was < 0" << llendl;
01923 }
01924
01925 if (!mFullscreen)
01926 {
01927 #if LL_X11
01928 if (mSDL_Display)
01929 {
01930
01931
01932
01933
01934
01935
01936
01937
01938
01939 int result;
01940 if (wantmode == SDL_GRAB_ON)
01941 {
01942
01943
01944 maybe_lock_display();
01945 result = XGrabPointer(mSDL_Display, mSDL_XWindowID,
01946 True, 0, GrabModeAsync,
01947 GrabModeAsync,
01948 None, None, CurrentTime);
01949 maybe_unlock_display();
01950 if (GrabSuccess == result)
01951 newmode = SDL_GRAB_ON;
01952 else
01953 newmode = SDL_GRAB_OFF;
01954 } else if (wantmode == SDL_GRAB_OFF)
01955 {
01956
01957 newmode = SDL_GRAB_OFF;
01958
01959
01960 maybe_lock_display();
01961 XUngrabPointer(mSDL_Display, CurrentTime);
01962
01963 XSync(mSDL_Display, False);
01964 maybe_unlock_display();
01965 } else
01966 {
01967 newmode = SDL_GRAB_QUERY;
01968 }
01969 } else
01970 newmode = wantmode;
01971 #endif // LL_X11
01972 } else {
01973
01974 newmode = wantmode;
01975 }
01976
01977
01978 return (capture && SDL_GRAB_ON==newmode) ||
01979 (!capture && SDL_GRAB_OFF==newmode);
01980 }
01981
01982 U32 LLWindowSDL::SDLCheckGrabbyKeys(SDLKey keysym, BOOL gain)
01983 {
01984
01985
01986
01987
01988
01989
01990
01991
01992
01993
01994
01995
01996
01997 U32 mask = 0;
01998 switch (keysym)
01999 {
02000 case SDLK_LALT:
02001 mask = 1U << 0; break;
02002 case SDLK_LCTRL:
02003 mask = 1U << 1; break;
02004 case SDLK_RCTRL:
02005 mask = 1U << 2; break;
02006 default:
02007 break;
02008 }
02009
02010 if (gain)
02011 mGrabbyKeyFlags |= mask;
02012 else
02013 mGrabbyKeyFlags &= ~mask;
02014
02015
02016
02017
02018 return mGrabbyKeyFlags;
02019 }
02020
02021 void LLWindowSDL::gatherInput()
02022 {
02023 const Uint32 CLICK_THRESHOLD = 300;
02024 static int leftClick = 0;
02025 static int rightClick = 0;
02026 static Uint32 lastLeftDown = 0;
02027 static Uint32 lastRightDown = 0;
02028 SDL_Event event;
02029
02030 #if LL_GTK && LL_LLMOZLIB_ENABLED
02031
02032 if (ll_try_gtk_init())
02033 {
02034
02035
02036
02037
02038 static std::string saved_locale;
02039 saved_locale = ll_safe_string(setlocale(LC_ALL, NULL));
02040
02041
02042
02043 static LLTimer pump_timer;
02044 pump_timer.reset();
02045 pump_timer.setTimerExpirySec(1.0f / 15.0f);
02046 do {
02047
02048 gtk_main_iteration_do(0);
02049 } while (gtk_events_pending() &&
02050 !pump_timer.hasExpired());
02051
02052 setlocale(LC_ALL, saved_locale.c_str() );
02053 }
02054 #endif // LL_GTK && LL_LLMOZLIB_ENABLED
02055
02056
02057 while (SDL_PollEvent(&event))
02058 {
02059 switch (event.type)
02060 {
02061 case SDL_MOUSEMOTION:
02062 {
02063 LLCoordWindow winCoord(event.button.x, event.button.y);
02064 LLCoordGL openGlCoord;
02065 convertCoords(winCoord, &openGlCoord);
02066 MASK mask = gKeyboard->currentMask(TRUE);
02067 mCallbacks->handleMouseMove(this, openGlCoord, mask);
02068 break;
02069 }
02070
02071 case SDL_KEYDOWN:
02072 gKeyboard->handleKeyDown(event.key.keysym.sym, event.key.keysym.mod);
02073
02074 if (SDLCheckGrabbyKeys(event.key.keysym.sym, TRUE) != 0)
02075 SDLReallyCaptureInput(TRUE);
02076
02077 if (event.key.keysym.unicode)
02078 {
02079 handleUnicodeUTF16(event.key.keysym.unicode,
02080 gKeyboard->currentMask(FALSE));
02081 }
02082 break;
02083
02084 case SDL_KEYUP:
02085 if (SDLCheckGrabbyKeys(event.key.keysym.sym, FALSE) == 0)
02086 SDLReallyCaptureInput(FALSE);
02087
02088 gKeyboard->handleKeyUp(event.key.keysym.sym, event.key.keysym.mod);
02089 break;
02090
02091 case SDL_MOUSEBUTTONDOWN:
02092 {
02093 bool isDoubleClick = false;
02094 LLCoordWindow winCoord(event.button.x, event.button.y);
02095 LLCoordGL openGlCoord;
02096 convertCoords(winCoord, &openGlCoord);
02097 MASK mask = gKeyboard->currentMask(TRUE);
02098
02099 if (event.button.button == SDL_BUTTON_LEFT)
02100 {
02101 Uint32 now = SDL_GetTicks();
02102 if ((now - lastLeftDown) > CLICK_THRESHOLD)
02103 leftClick = 1;
02104 else
02105 {
02106 if (++leftClick >= 2)
02107 {
02108 leftClick = 0;
02109 isDoubleClick = true;
02110 }
02111 }
02112 lastLeftDown = now;
02113 }
02114 else if (event.button.button == SDL_BUTTON_RIGHT)
02115 {
02116 Uint32 now = SDL_GetTicks();
02117 if ((now - lastRightDown) > CLICK_THRESHOLD)
02118 rightClick = 1;
02119 else
02120 {
02121 if (++rightClick >= 2)
02122 {
02123 rightClick = 0;
02124 isDoubleClick = true;
02125 }
02126 }
02127 lastRightDown = now;
02128 }
02129
02130 if (event.button.button == SDL_BUTTON_LEFT)
02131 {
02132 if (isDoubleClick)
02133 mCallbacks->handleDoubleClick(this, openGlCoord, mask);
02134 else
02135 mCallbacks->handleMouseDown(this, openGlCoord, mask);
02136 }
02137
02138 else if (event.button.button == SDL_BUTTON_RIGHT)
02139 {
02140
02141 mCallbacks->handleRightMouseDown(this, openGlCoord, mask);
02142 }
02143
02144 else if (event.button.button == SDL_BUTTON_MIDDLE)
02145 {
02146 mCallbacks->handleMiddleMouseDown(this, openGlCoord, mask);
02147 }
02148 else if (event.button.button == 4)
02149 mCallbacks->handleScrollWheel(this, -1);
02150 else if (event.button.button == 5)
02151 mCallbacks->handleScrollWheel(this, 1);
02152
02153 break;
02154 }
02155
02156 case SDL_MOUSEBUTTONUP:
02157 {
02158 LLCoordWindow winCoord(event.button.x, event.button.y);
02159 LLCoordGL openGlCoord;
02160 convertCoords(winCoord, &openGlCoord);
02161 MASK mask = gKeyboard->currentMask(TRUE);
02162
02163 if (event.button.button == SDL_BUTTON_LEFT)
02164 mCallbacks->handleMouseUp(this, openGlCoord, mask);
02165 else if (event.button.button == SDL_BUTTON_RIGHT)
02166 mCallbacks->handleRightMouseUp(this, openGlCoord, mask);
02167 else if (event.button.button == SDL_BUTTON_MIDDLE)
02168 {
02169 mCallbacks->handleMiddleMouseUp(this, openGlCoord, mask);
02170 }
02171
02172
02173 break;
02174 }
02175
02176 case SDL_VIDEOEXPOSE:
02177 mCallbacks->handlePaint(this, 0, 0, mWindow->w, mWindow->h);
02178 break;
02179
02180 case SDL_VIDEORESIZE:
02181 llinfos << "Handling a resize event: " << event.resize.w <<
02182 "x" << event.resize.h << llendl;
02183
02184
02185 mWindow = SDL_SetVideoMode(event.resize.w, event.resize.h, 32, mSDLFlags);
02186 if (!mWindow)
02187 {
02188
02189 llinfos << "Could not recreate context after resize! Quitting..." << llendl;
02190 if(mCallbacks->handleCloseRequest(this))
02191 {
02192
02193 mCallbacks->handleQuit(this);
02194
02195 }
02196 break;
02197 }
02198
02199 mCallbacks->handleResize(this, event.resize.w, event.resize.h );
02200 break;
02201
02202 case SDL_ACTIVEEVENT:
02203 if (event.active.state & SDL_APPINPUTFOCUS)
02204 {
02205
02206
02207
02208
02209
02210
02211
02212 if (event.active.gain != mHaveInputFocus)
02213 {
02214 if (event.active.gain)
02215 mCallbacks->handleFocus(this);
02216 else
02217 mCallbacks->handleFocusLost(this);
02218
02219 mHaveInputFocus = !!event.active.gain;
02220 }
02221 }
02222 if (event.active.state & SDL_APPACTIVE)
02223 {
02224
02225 if ((!event.active.gain) != mIsMinimized)
02226 {
02227 mCallbacks->handleActivate(this, !!event.active.gain);
02228 llinfos << "SDL deiconification state switched to " << BOOL(event.active.gain) << llendl;
02229
02230 mIsMinimized = (!event.active.gain);
02231 }
02232 else
02233 {
02234 llinfos << "Ignored bogus redundant SDL deiconification state switch to " << BOOL(event.active.gain) << llendl;
02235 }
02236 }
02237 break;
02238
02239 case SDL_QUIT:
02240 if(mCallbacks->handleCloseRequest(this))
02241 {
02242
02243 mCallbacks->handleQuit(this);
02244
02245 }
02246 break;
02247 default:
02248
02249 break;
02250 }
02251 }
02252
02253 #if LL_X11
02254
02255
02256 if (mFlashing && mFlashTimer.hasExpired())
02257 {
02258 x11_set_urgent(FALSE);
02259 mFlashing = FALSE;
02260 }
02261 #endif // LL_X11
02262 }
02263
02264 static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty)
02265 {
02266 SDL_Cursor *sdlcursor = NULL;
02267 SDL_Surface *bmpsurface;
02268
02269
02270 bmpsurface = Load_BMP_Resource(filename);
02271 if (bmpsurface && bmpsurface->w%8==0)
02272 {
02273 SDL_Surface *cursurface;
02274 lldebugs << "Loaded cursor file " << filename << " "
02275 << bmpsurface->w << "x" << bmpsurface->h << llendl;
02276 cursurface = SDL_CreateRGBSurface (SDL_SWSURFACE,
02277 bmpsurface->w,
02278 bmpsurface->h,
02279 32,
02280 SDL_SwapLE32(0xFFU),
02281 SDL_SwapLE32(0xFF00U),
02282 SDL_SwapLE32(0xFF0000U),
02283 SDL_SwapLE32(0xFF000000U));
02284 SDL_FillRect(cursurface, NULL, SDL_SwapLE32(0x00000000U));
02285
02286
02287
02288 if (0 == SDL_BlitSurface(bmpsurface, NULL,
02289 cursurface, NULL))
02290 {
02291
02292 const int bitmap_bytes = (cursurface->w * cursurface->h) / 8;
02293 unsigned char *cursor_data = new unsigned char[bitmap_bytes];
02294 unsigned char *cursor_mask = new unsigned char[bitmap_bytes];
02295 memset(cursor_data, 0, bitmap_bytes);
02296 memset(cursor_mask, 0, bitmap_bytes);
02297 int i,j;
02298
02299
02300
02301 for (i=0; i<cursurface->h; ++i) {
02302 for (j=0; j<cursurface->w; ++j) {
02303 U8 *pixelp =
02304 ((U8*)cursurface->pixels)
02305 + cursurface->pitch * i
02306 + j*cursurface->format->BytesPerPixel;
02307 U8 srcred = pixelp[0];
02308 U8 srcgreen = pixelp[1];
02309 U8 srcblue = pixelp[2];
02310 BOOL mask_bit = (srcred != 200)
02311 || (srcgreen != 200)
02312 || (srcblue != 200);
02313 BOOL data_bit = mask_bit && (srcgreen <= 80);
02314 unsigned char bit_offset = (cursurface->w/8) * i
02315 + j/8;
02316 cursor_data[bit_offset] |= (data_bit) << (7 - (j&7));
02317 cursor_mask[bit_offset] |= (mask_bit) << (7 - (j&7));
02318 }
02319 }
02320 sdlcursor = SDL_CreateCursor((Uint8*)cursor_data,
02321 (Uint8*)cursor_mask,
02322 cursurface->w, cursurface->h,
02323 hotx, hoty);
02324 delete[] cursor_data;
02325 delete[] cursor_mask;
02326 } else {
02327 llwarns << "CURSOR BLIT FAILURE, cursurface: " << cursurface << llendl;
02328 }
02329 SDL_FreeSurface(cursurface);
02330 SDL_FreeSurface(bmpsurface);
02331 } else {
02332 llwarns << "CURSOR LOAD FAILURE " << filename << llendl;
02333 }
02334
02335 return sdlcursor;
02336 }
02337
02338 void LLWindowSDL::setCursor(ECursorType cursor)
02339 {
02340 if (mCurrentCursor != cursor)
02341 {
02342 if (cursor < UI_CURSOR_COUNT)
02343 {
02344 SDL_Cursor *sdlcursor = mSDLCursors[cursor];
02345
02346
02347 if (!sdlcursor && mSDLCursors[UI_CURSOR_ARROW])
02348 sdlcursor = mSDLCursors[UI_CURSOR_ARROW];
02349 if (sdlcursor)
02350 SDL_SetCursor(sdlcursor);
02351 } else {
02352 llwarns << "Tried to set invalid cursor number " << cursor << llendl;
02353 }
02354 mCurrentCursor = cursor;
02355 }
02356 }
02357
02358 ECursorType LLWindowSDL::getCursor()
02359 {
02360 return mCurrentCursor;
02361 }
02362
02363 void LLWindowSDL::initCursors()
02364 {
02365 int i;
02366
02367 for (i=0; i<UI_CURSOR_COUNT; ++i)
02368 {
02369 mSDLCursors[i] = NULL;
02370 }
02371
02372
02373
02374
02375 mSDLCursors[UI_CURSOR_ARROW] = makeSDLCursorFromBMP("llarrow.BMP",0,0);
02376 mSDLCursors[UI_CURSOR_WAIT] = makeSDLCursorFromBMP("wait.BMP",12,15);
02377 mSDLCursors[UI_CURSOR_HAND] = makeSDLCursorFromBMP("hand.BMP",7,10);
02378 mSDLCursors[UI_CURSOR_IBEAM] = makeSDLCursorFromBMP("ibeam.BMP",15,16);
02379 mSDLCursors[UI_CURSOR_CROSS] = makeSDLCursorFromBMP("cross.BMP",16,14);
02380 mSDLCursors[UI_CURSOR_SIZENWSE] = makeSDLCursorFromBMP("sizenwse.BMP",14,17);
02381 mSDLCursors[UI_CURSOR_SIZENESW] = makeSDLCursorFromBMP("sizenesw.BMP",17,17);
02382 mSDLCursors[UI_CURSOR_SIZEWE] = makeSDLCursorFromBMP("sizewe.BMP",16,14);
02383 mSDLCursors[UI_CURSOR_SIZENS] = makeSDLCursorFromBMP("sizens.BMP",17,16);
02384 mSDLCursors[UI_CURSOR_NO] = makeSDLCursorFromBMP("llno.BMP",8,8);
02385 mSDLCursors[UI_CURSOR_WORKING] = makeSDLCursorFromBMP("working.BMP",12,15);
02386 mSDLCursors[UI_CURSOR_TOOLGRAB] = makeSDLCursorFromBMP("lltoolgrab.BMP",2,13);
02387 mSDLCursors[UI_CURSOR_TOOLLAND] = makeSDLCursorFromBMP("lltoolland.BMP",1,6);
02388 mSDLCursors[UI_CURSOR_TOOLFOCUS] = makeSDLCursorFromBMP("lltoolfocus.BMP",8,5);
02389 mSDLCursors[UI_CURSOR_TOOLCREATE] = makeSDLCursorFromBMP("lltoolcreate.BMP",7,7);
02390 mSDLCursors[UI_CURSOR_ARROWDRAG] = makeSDLCursorFromBMP("arrowdrag.BMP",0,0);
02391 mSDLCursors[UI_CURSOR_ARROWCOPY] = makeSDLCursorFromBMP("arrowcop.BMP",0,0);
02392 mSDLCursors[UI_CURSOR_ARROWDRAGMULTI] = makeSDLCursorFromBMP("llarrowdragmulti.BMP",0,0);
02393 mSDLCursors[UI_CURSOR_ARROWCOPYMULTI] = makeSDLCursorFromBMP("arrowcopmulti.BMP",0,0);
02394 mSDLCursors[UI_CURSOR_NOLOCKED] = makeSDLCursorFromBMP("llnolocked.BMP",8,8);
02395 mSDLCursors[UI_CURSOR_ARROWLOCKED] = makeSDLCursorFromBMP("llarrowlocked.BMP",0,0);
02396 mSDLCursors[UI_CURSOR_GRABLOCKED] = makeSDLCursorFromBMP("llgrablocked.BMP",2,13);
02397 mSDLCursors[UI_CURSOR_TOOLTRANSLATE] = makeSDLCursorFromBMP("lltooltranslate.BMP",0,0);
02398 mSDLCursors[UI_CURSOR_TOOLROTATE] = makeSDLCursorFromBMP("lltoolrotate.BMP",0,0);
02399 mSDLCursors[UI_CURSOR_TOOLSCALE] = makeSDLCursorFromBMP("lltoolscale.BMP",0,0);
02400 mSDLCursors[UI_CURSOR_TOOLCAMERA] = makeSDLCursorFromBMP("lltoolcamera.BMP",7,5);
02401 mSDLCursors[UI_CURSOR_TOOLPAN] = makeSDLCursorFromBMP("lltoolpan.BMP",7,5);
02402 mSDLCursors[UI_CURSOR_TOOLZOOMIN] = makeSDLCursorFromBMP("lltoolzoomin.BMP",7,5);
02403 mSDLCursors[UI_CURSOR_TOOLPICKOBJECT3] = makeSDLCursorFromBMP("toolpickobject3.BMP",0,0);
02404 mSDLCursors[UI_CURSOR_TOOLSIT] = makeSDLCursorFromBMP("toolsit.BMP",0,0);
02405 mSDLCursors[UI_CURSOR_TOOLBUY] = makeSDLCursorFromBMP("toolbuy.BMP",0,0);
02406 mSDLCursors[UI_CURSOR_TOOLPAY] = makeSDLCursorFromBMP("toolpay.BMP",0,0);
02407 mSDLCursors[UI_CURSOR_TOOLOPEN] = makeSDLCursorFromBMP("toolopen.BMP",0,0);
02408 mSDLCursors[UI_CURSOR_TOOLPLAY] = makeSDLCursorFromBMP("toolplay.BMP",0,0);
02409 mSDLCursors[UI_CURSOR_TOOLPAUSE] = makeSDLCursorFromBMP("toolpause.BMP",0,0);
02410 mSDLCursors[UI_CURSOR_TOOLMEDIAOPEN] = makeSDLCursorFromBMP("toolmediaopen.BMP",0,0);
02411 mSDLCursors[UI_CURSOR_PIPETTE] = makeSDLCursorFromBMP("lltoolpipette.BMP",2,28);
02412 }
02413
02414 void LLWindowSDL::quitCursors()
02415 {
02416 int i;
02417 if (mWindow)
02418 {
02419 for (i=0; i<UI_CURSOR_COUNT; ++i)
02420 {
02421 if (mSDLCursors[i])
02422 {
02423 SDL_FreeCursor(mSDLCursors[i]);
02424 mSDLCursors[i] = NULL;
02425 }
02426 }
02427 } else {
02428
02429
02430 llinfos << "Skipping quitCursors: mWindow already gone." << llendl;
02431 for (i=0; i<UI_CURSOR_COUNT; ++i)
02432 mSDLCursors[i] = NULL;
02433 }
02434 }
02435
02436 void LLWindowSDL::captureMouse()
02437 {
02438
02439
02440
02441
02442
02443
02444
02445 }
02446
02447 void LLWindowSDL::releaseMouse()
02448 {
02449
02450
02451
02452 }
02453
02454 void LLWindowSDL::hideCursor()
02455 {
02456 if(!mCursorHidden)
02457 {
02458
02459 mCursorHidden = TRUE;
02460 mHideCursorPermanent = TRUE;
02461 SDL_ShowCursor(0);
02462 }
02463 else
02464 {
02465
02466 }
02467
02468 adjustCursorDecouple();
02469 }
02470
02471 void LLWindowSDL::showCursor()
02472 {
02473 if(mCursorHidden)
02474 {
02475
02476 mCursorHidden = FALSE;
02477 mHideCursorPermanent = FALSE;
02478 SDL_ShowCursor(1);
02479 }
02480 else
02481 {
02482
02483 }
02484
02485 adjustCursorDecouple();
02486 }
02487
02488 void LLWindowSDL::showCursorFromMouseMove()
02489 {
02490 if (!mHideCursorPermanent)
02491 {
02492 showCursor();
02493 }
02494 }
02495
02496 void LLWindowSDL::hideCursorUntilMouseMove()
02497 {
02498 if (!mHideCursorPermanent)
02499 {
02500 hideCursor();
02501 mHideCursorPermanent = FALSE;
02502 }
02503 }
02504
02505
02506
02507
02508
02509
02510
02511 LLSplashScreenSDL::LLSplashScreenSDL()
02512 {
02513 }
02514
02515 LLSplashScreenSDL::~LLSplashScreenSDL()
02516 {
02517 }
02518
02519 void LLSplashScreenSDL::showImpl()
02520 {
02521 }
02522
02523 void LLSplashScreenSDL::updateImpl(const char* mesg)
02524 {
02525 }
02526
02527 void LLSplashScreenSDL::hideImpl()
02528 {
02529 }
02530
02531
02532
02533 #if LL_GTK
02534 static void response_callback (GtkDialog *dialog,
02535 gint arg1,
02536 gpointer user_data)
02537 {
02538 gint *response = (gint*)user_data;
02539 *response = arg1;
02540 gtk_widget_destroy(GTK_WIDGET(dialog));
02541 gtk_main_quit();
02542 }
02543
02544 S32 OSMessageBoxSDL(const char* text, const char* caption, U32 type)
02545 {
02546 S32 rtn = OSBTN_CANCEL;
02547
02548 ll_try_gtk_init();
02549
02550 if(gWindowImplementation != NULL)
02551 gWindowImplementation->beforeDialog();
02552
02553 if (ll_try_gtk_init()
02554
02555 && ((NULL==gWindowImplementation) || (!was_fullscreen))
02556 )
02557 {
02558 GtkWidget *win = NULL;
02559
02560 llinfos << "Creating a dialog because we're in windowed mode and GTK is happy." << llendl;
02561
02562 GtkDialogFlags flags = GTK_DIALOG_MODAL;
02563 GtkMessageType messagetype;
02564 GtkButtonsType buttons;
02565 switch (type)
02566 {
02567 default:
02568 case OSMB_OK:
02569 messagetype = GTK_MESSAGE_WARNING;
02570 buttons = GTK_BUTTONS_OK;
02571 break;
02572 case OSMB_OKCANCEL:
02573 messagetype = GTK_MESSAGE_QUESTION;
02574 buttons = GTK_BUTTONS_OK_CANCEL;
02575 break;
02576 case OSMB_YESNO:
02577 messagetype = GTK_MESSAGE_QUESTION;
02578 buttons = GTK_BUTTONS_YES_NO;
02579 break;
02580 }
02581 win = gtk_message_dialog_new(NULL,
02582 flags, messagetype, buttons,
02583 text);
02584
02585 # if LL_X11
02586
02587
02588
02589 if (gWindowImplementation &&
02590 gWindowImplementation->mSDL_XWindowID != None)
02591 {
02592 gtk_widget_realize(GTK_WIDGET(win));
02593 GdkWindow *gdkwin = gdk_window_foreign_new(gWindowImplementation->mSDL_XWindowID);
02594 gdk_window_set_transient_for(GTK_WIDGET(win)->window,
02595 gdkwin);
02596 }
02597 # endif //LL_X11
02598
02599 gtk_window_set_position(GTK_WINDOW(win),
02600 GTK_WIN_POS_CENTER_ON_PARENT);
02601
02602 gtk_window_set_type_hint(GTK_WINDOW(win),
02603 GDK_WINDOW_TYPE_HINT_DIALOG);
02604
02605 if (caption)
02606 gtk_window_set_title(GTK_WINDOW(win), caption);
02607
02608 gint response = GTK_RESPONSE_NONE;
02609 g_signal_connect (win,
02610 "response",
02611 G_CALLBACK (response_callback),
02612 &response);
02613
02614
02615
02616
02617 gtk_widget_show_all (win);
02618 gtk_main();
02619
02620
02621 switch (response)
02622 {
02623 case GTK_RESPONSE_OK: rtn = OSBTN_OK; break;
02624 case GTK_RESPONSE_YES: rtn = OSBTN_YES; break;
02625 case GTK_RESPONSE_NO: rtn = OSBTN_NO; break;
02626 case GTK_RESPONSE_APPLY: rtn = OSBTN_OK; break;
02627 case GTK_RESPONSE_NONE:
02628 case GTK_RESPONSE_CANCEL:
02629 case GTK_RESPONSE_CLOSE:
02630 case GTK_RESPONSE_DELETE_EVENT:
02631 default: rtn = OSBTN_CANCEL;
02632 }
02633 }
02634 else
02635 {
02636 llinfos << "MSGBOX: " << caption << ": " << text << llendl;
02637 llinfos << "Skipping dialog because we're in fullscreen mode or GTK is not happy." << llendl;
02638 rtn = OSBTN_OK;
02639 }
02640
02641 if(gWindowImplementation != NULL)
02642 gWindowImplementation->afterDialog();
02643
02644 return rtn;
02645 }
02646
02647 static void color_changed_callback(GtkWidget *widget,
02648 gpointer user_data)
02649 {
02650 GtkColorSelection *colorsel = GTK_COLOR_SELECTION(widget);
02651 GdkColor *colorp = (GdkColor*)user_data;
02652
02653 gtk_color_selection_get_current_color(colorsel, colorp);
02654 }
02655
02656 BOOL LLWindowSDL::dialog_color_picker ( F32 *r, F32 *g, F32 *b)
02657 {
02658 BOOL rtn = FALSE;
02659
02660 beforeDialog();
02661
02662 if (ll_try_gtk_init()
02663
02664 && !was_fullscreen
02665 )
02666 {
02667 GtkWidget *win = NULL;
02668
02669 win = gtk_color_selection_dialog_new(NULL);
02670
02671 # if LL_X11
02672
02673
02674
02675 if (mSDL_XWindowID != None)
02676 {
02677 gtk_widget_realize(GTK_WIDGET(win));
02678 GdkWindow *gdkwin = gdk_window_foreign_new(mSDL_XWindowID);
02679 gdk_window_set_transient_for(GTK_WIDGET(win)->window,
02680 gdkwin);
02681 }
02682 # endif //LL_X11
02683
02684 GtkColorSelection *colorsel = GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG(win)->colorsel);
02685
02686 GdkColor color, orig_color;
02687 orig_color.red = guint16(65535 * *r);
02688 orig_color.green= guint16(65535 * *g);
02689 orig_color.blue = guint16(65535 * *b);
02690 color = orig_color;
02691
02692 gtk_color_selection_set_previous_color (colorsel, &color);
02693 gtk_color_selection_set_current_color (colorsel, &color);
02694 gtk_color_selection_set_has_palette (colorsel, TRUE);
02695 gtk_color_selection_set_has_opacity_control(colorsel, FALSE);
02696
02697 gint response = GTK_RESPONSE_NONE;
02698 g_signal_connect (win,
02699 "response",
02700 G_CALLBACK (response_callback),
02701 &response);
02702
02703 g_signal_connect (G_OBJECT (colorsel), "color_changed",
02704 G_CALLBACK (color_changed_callback),
02705 &color);
02706
02707 gtk_window_set_modal(GTK_WINDOW(win), TRUE);
02708 gtk_widget_show_all(win);
02709
02710 gtk_widget_hide(GTK_COLOR_SELECTION_DIALOG(win)->help_button);
02711 gtk_main();
02712
02713 if (response == GTK_RESPONSE_OK &&
02714 (orig_color.red != color.red
02715 || orig_color.green != color.green
02716 || orig_color.blue != color.blue) )
02717 {
02718 *r = color.red / 65535.0f;
02719 *g = color.green / 65535.0f;
02720 *b = color.blue / 65535.0f;
02721 rtn = TRUE;
02722 }
02723 }
02724
02725 afterDialog();
02726
02727 return rtn;
02728 }
02729 #else
02730 S32 OSMessageBoxSDL(const char* text, const char* caption, U32 type)
02731 {
02732 llinfos << "MSGBOX: " << caption << ": " << text << llendl;
02733 return 0;
02734 }
02735
02736 BOOL LLWindowSDL::dialog_color_picker ( F32 *r, F32 *g, F32 *b)
02737 {
02738 return (FALSE);
02739 }
02740 #endif // LL_GTK
02741
02742
02743
02744 void spawn_web_browser(const char* escaped_url)
02745 {
02746 llinfos << "spawn_web_browser: " << escaped_url << llendl;
02747
02748 #if LL_LINUX || LL_SOLARIS
02749 # if LL_X11
02750 if (gWindowImplementation && gWindowImplementation->mSDL_Display)
02751 {
02752 maybe_lock_display();
02753
02754 XSync(gWindowImplementation->mSDL_Display, False);
02755 maybe_unlock_display();
02756 }
02757 # endif // LL_X11
02758
02759 std::string cmd;
02760 cmd = gDirUtilp->getAppRODataDir();
02761 cmd += gDirUtilp->getDirDelimiter();
02762 cmd += "launch_url.sh";
02763 char* const argv[] = {(char*)cmd.c_str(), (char*)escaped_url, NULL};
02764
02765 fflush(NULL);
02766 pid_t pid = fork();
02767 if (pid == 0)
02768 {
02769
02770
02771 close(0);
02772 close(1);
02773 close(2);
02774
02775 execv(cmd.c_str(), argv);
02776
02777 llwarns << "execv failure when trying to start " << cmd << llendl;
02778 _exit(1);
02779 } else {
02780 if (pid > 0)
02781 {
02782
02783 int childExitStatus;
02784 waitpid(pid, &childExitStatus, 0);
02785 } else {
02786 llwarns << "fork failure." << llendl;
02787 }
02788 }
02789 #endif // LL_LINUX || LL_SOLARIS
02790
02791 llinfos << "spawn_web_browser returning." << llendl;
02792 }
02793
02794
02795 void *LLWindowSDL::getPlatformWindow()
02796 {
02797 #if LL_GTK && LL_LLMOZLIB_ENABLED
02798 if (ll_try_gtk_init())
02799 {
02800 maybe_lock_display();
02801
02802 GtkWidget *owin = gtk_window_new(GTK_WINDOW_POPUP);
02803
02804
02805
02806
02807
02808 GtkWidget *rtnw = gtk_layout_new(NULL, NULL);
02809 gtk_container_add(GTK_CONTAINER(owin), rtnw);
02810 gtk_widget_realize(rtnw);
02811 GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(rtnw), GTK_NO_WINDOW);
02812
02813 maybe_unlock_display();
02814
02815 return rtnw;
02816 }
02817 #endif // LL_GTK && LL_LLMOZLIB_ENABLED
02818
02819 return NULL;
02820 }
02821
02822 void LLWindowSDL::bringToFront()
02823 {
02824
02825
02826 llinfos << "bringToFront" << llendl;
02827 #if LL_X11
02828 if (mSDL_Display && !mFullscreen)
02829 {
02830 maybe_lock_display();
02831 XRaiseWindow(mSDL_Display, mSDL_XWindowID);
02832 XSync(mSDL_Display, False);
02833 maybe_unlock_display();
02834 }
02835 #endif // LL_X11
02836 }
02837
02838
02839 std::string LLWindowSDL::getFontListSans()
02840 {
02841
02842
02843 std::string final_fallback("/usr/share/fonts/truetype/kochi/kochi-gothic.ttf");
02844
02845
02846
02847
02848 std::string sort_order("slant=0:index=0:weight=80:spacing=0");
02849
02850
02851
02852
02853
02854
02855 const bool elide_unicode_coverage = true;
02856 std::string rtn;
02857 FcFontSet *fs = NULL;
02858 FcPattern *sortpat = NULL;
02859 int font_count = 0;
02860
02861 llinfos << "Getting system font list from FontConfig..." << llendl;
02862
02863
02864
02865
02866
02867
02868 FL_Locale *locale = NULL;
02869 FL_Success success = FL_FindLocale(&locale, FL_MESSAGES);
02870 if (success != 0)
02871 {
02872 if (success >= 2 && locale->lang)
02873 {
02874 llinfos << "Preferring fonts of language: "
02875 << locale->lang
02876 << llendl;
02877 sort_order = "lang=" + std::string(locale->lang) + ":"
02878 + sort_order;
02879 }
02880 FL_FreeLocale(&locale);
02881 }
02882
02883 if (!FcInit())
02884 {
02885 llwarns << "FontConfig failed to initialize." << llendl;
02886 return final_fallback;
02887 }
02888
02889 sortpat = FcNameParse((FcChar8*) sort_order.c_str());
02890 if (sortpat)
02891 {
02892
02893 fs = FcFontSort(NULL, sortpat, elide_unicode_coverage,
02894 NULL, NULL);
02895 FcPatternDestroy(sortpat);
02896 }
02897
02898 if (fs)
02899 {
02900
02901
02902 int i;
02903 for (i=0; i<fs->nfont; ++i)
02904 {
02905 FcChar8 *filename;
02906 if (FcResultMatch == FcPatternGetString(fs->fonts[i],
02907 FC_FILE, 0,
02908 &filename)
02909 && filename)
02910 {
02911 rtn += std::string((const char*)filename)+";";
02912 ++font_count;
02913 }
02914 }
02915 FcFontSetDestroy (fs);
02916 }
02917
02918 lldebugs << "Using font list: " << rtn << llendl;
02919 llinfos << "Using " << font_count << " system font(s)." << llendl;
02920
02921 return rtn + final_fallback;
02922 }
02923
02924 #endif // LL_SDL