DOSBox-X
|
00001 00002 #include "config.h" 00003 00004 #ifdef LINUX 00005 #include "logging.h" 00006 #include "keymap.h" 00007 #include "SDL.h" 00008 #include "SDL_version.h" 00009 #include "SDL_syswm.h" 00010 #include "sdlmain.h" 00011 00012 #if C_X11 00013 # if C_X11_XKB 00014 # include <X11/XKBlib.h> 00015 # endif 00016 # if C_X11_EXT_XKBRULES 00017 # include <X11/extensions/XKBrules.h> 00018 # endif 00019 #endif 00020 00021 void UpdateWindowDimensions(Bitu width, Bitu height); 00022 void UpdateWindowMaximized(bool flag); 00023 00024 #if C_X11_XRANDR 00025 #include <X11/extensions/Xrandr.h> 00026 #endif 00027 00028 /* The XRandR extension may or may not be there */ 00029 #if C_X11_XRANDR 00030 bool X11_XRR_avail = false; 00031 bool X11_XRR_checked = false; 00032 00033 bool X11_XRR_check(Display *display) { 00034 if (!X11_XRR_checked) { 00035 X11_XRR_checked = true; 00036 00037 int major=0,minor=0,err=0; 00038 00039 if (XQueryExtension(display,"RANDR",&major,&minor,&err) && major != 0) 00040 X11_XRR_avail = true; 00041 else 00042 X11_XRR_avail = false; 00043 00044 LOG_MSG("X11 extension XRANDR is %s",X11_XRR_avail ? "available" : "not available"); 00045 } 00046 00047 return X11_XRR_avail; 00048 } 00049 #endif 00050 00051 #if !defined(C_SDL2) 00052 extern "C" void SDL1_hax_X11_jpfix(int ro_scan,int yen_scan); 00053 #endif 00054 00055 #if 1 00056 # define _NET_WM_STATE_REMOVE 0 // remove/unset property 00057 # define _NET_WM_STATE_ADD 1 // add/set property 00058 # define _NET_WM_STATE_TOGGLE 2 // toggle property 00059 #endif 00060 00061 void LinuxX11_OnTop(bool f) { 00062 (void)f; 00063 00064 SDL_SysWMinfo wminfo; 00065 memset(&wminfo,0,sizeof(wminfo)); 00066 SDL_VERSION(&wminfo.version); 00067 00068 #if defined(C_SDL2) 00069 SDL_Window* GFX_GetSDLWindow(void); 00070 00071 if (SDL_GetWindowWMInfo(GFX_GetSDLWindow(),&wminfo) >= 0) { 00072 # if C_X11 00073 if (wminfo.subsystem == SDL_SYSWM_X11 && wminfo.info.x11.display != NULL) { 00074 Atom wmStateAbove = XInternAtom(wminfo.info.x11.display, "_NET_WM_STATE_ABOVE", 1); 00075 if (wmStateAbove == None) return; 00076 00077 Atom wmNetWmState = XInternAtom(wminfo.info.x11.display, "_NET_WM_STATE", 1); 00078 if (wmNetWmState == None) return; 00079 00080 XClientMessageEvent xclient; 00081 memset(&xclient,0,sizeof(xclient)); 00082 00083 xclient.type = ClientMessage; 00084 xclient.window = wminfo.info.x11.window; 00085 xclient.message_type = wmNetWmState; 00086 xclient.format = 32; 00087 xclient.data.l[0] = f ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; 00088 xclient.data.l[1] = (long int)wmStateAbove; 00089 xclient.data.l[2] = 0; 00090 xclient.data.l[3] = 0; 00091 xclient.data.l[4] = 0; 00092 00093 XSendEvent( 00094 wminfo.info.x11.display, 00095 DefaultRootWindow(wminfo.info.x11.display), 00096 False, 00097 SubstructureRedirectMask | SubstructureNotifyMask, 00098 (XEvent *)&xclient ); 00099 } 00100 # endif 00101 } 00102 #else 00103 if (SDL_GetWMInfo(&wminfo) >= 0) { 00104 # if C_X11 00105 if (wminfo.subsystem == SDL_SYSWM_X11 && wminfo.info.x11.display != NULL) { 00106 Atom wmStateAbove = XInternAtom(wminfo.info.x11.display, "_NET_WM_STATE_ABOVE", 1); 00107 if (wmStateAbove == None) return; 00108 00109 Atom wmNetWmState = XInternAtom(wminfo.info.x11.display, "_NET_WM_STATE", 1); 00110 if (wmNetWmState == None) return; 00111 00112 XClientMessageEvent xclient; 00113 memset(&xclient,0,sizeof(xclient)); 00114 00115 xclient.type = ClientMessage; 00116 xclient.window = wminfo.info.x11.wmwindow; 00117 xclient.message_type = wmNetWmState; 00118 xclient.format = 32; 00119 xclient.data.l[0] = f ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; 00120 xclient.data.l[1] = (long int)wmStateAbove; 00121 xclient.data.l[2] = 0; 00122 xclient.data.l[3] = 0; 00123 xclient.data.l[4] = 0; 00124 00125 XSendEvent( 00126 wminfo.info.x11.display, 00127 DefaultRootWindow(wminfo.info.x11.display), 00128 False, 00129 SubstructureRedirectMask | SubstructureNotifyMask, 00130 (XEvent *)&xclient ); 00131 } 00132 # endif 00133 } 00134 #endif 00135 } 00136 00137 char *LinuxX11_KeySymName(Uint32 x) { 00138 (void)x; 00139 00140 SDL_SysWMinfo wminfo; 00141 memset(&wminfo,0,sizeof(wminfo)); 00142 SDL_VERSION(&wminfo.version); 00143 00144 #if defined(C_SDL2) 00145 SDL_Window* GFX_GetSDLWindow(void); 00146 00147 if (SDL_GetWindowWMInfo(GFX_GetSDLWindow(),&wminfo) >= 0) { 00148 # if C_X11 00149 if (wminfo.subsystem == SDL_SYSWM_X11 && wminfo.info.x11.display != NULL) { 00150 return XKeysymToString(x); 00151 } 00152 # endif 00153 } 00154 #else 00155 if (SDL_GetWMInfo(&wminfo) >= 0) { 00156 # if C_X11 00157 if (wminfo.subsystem == SDL_SYSWM_X11 && wminfo.info.x11.display != NULL) { 00158 return XKeysymToString(x); 00159 } 00160 # endif 00161 } 00162 #endif 00163 00164 return NULL; 00165 } 00166 00167 void Linux_JPXKBFix(void) { 00168 #if !defined(C_SDL2) 00169 SDL_SysWMinfo wminfo; 00170 memset(&wminfo,0,sizeof(wminfo)); 00171 SDL_VERSION(&wminfo.version); 00172 if (SDL_GetWMInfo(&wminfo) >= 0) { 00173 # if C_X11 00174 # if C_X11_XKB 00175 if (wminfo.subsystem == SDL_SYSWM_X11 && wminfo.info.x11.display != NULL) { 00176 /* detect xkbmap with Ro and Yen keys mapped to \, determine the scan codes, 00177 * and then hack the SDL 1.x X11 driver to handle it. 00178 * 00179 * Never assume specific scan codes, even though on my system the scan codes 00180 * are 97 (Yen) and 132 (Ro) both mapped to \ backslash. 00181 * 00182 * We can use the index to look for keysyms that mention backslash and underscore (Ro) 00183 * or backslash and bar (Yen) */ 00184 /* TODO: If xkbmap actually maps these keys properly, how can we tell? */ 00185 int ro=-1,yen=-1; 00186 unsigned int i,j; 00187 KeySym sym[4]; 00188 00189 for (i=0;i < 256;i++) { 00190 for (j=0;j < 4;j++) 00191 sym[j] = XKeycodeToKeysym(wminfo.info.x11.display,(KeyCode)i,(int)j); 00192 00193 if (sym[0] == '\\') { 00194 if (sym[1] == '_') { /* shift + backslash == _ means we found Ro */ 00195 if (ro < 0) ro = (int)i; 00196 } 00197 else if (sym[1] == '|') { /* shift + backslash == | means we found Yen */ 00198 if (yen < 0) yen = (int)i; 00199 } 00200 } 00201 } 00202 00203 LOG_MSG("JP Linux/X11 fix: Found Ro=%d Yen=%d",ro,yen); 00204 00205 SDL1_hax_X11_jpfix(ro,yen); 00206 } 00207 # endif 00208 # endif 00209 } 00210 #endif 00211 } 00212 00213 unsigned int Linux_GetKeyboardLayout(void) { 00214 unsigned int ret = DKM_US; 00215 00216 SDL_SysWMinfo wminfo; 00217 memset(&wminfo,0,sizeof(wminfo)); 00218 SDL_VERSION(&wminfo.version); 00219 00220 #if defined(C_SDL2) 00221 SDL_Window* GFX_GetSDLWindow(void); 00222 00223 if (SDL_GetWindowWMInfo(GFX_GetSDLWindow(),&wminfo) >= 0) { 00224 # if C_X11 00225 # if C_X11_XKB 00226 # if C_X11_EXT_XKBRULES 00227 if (wminfo.subsystem == SDL_SYSWM_X11 && wminfo.info.x11.display != NULL) { 00228 XkbRF_VarDefsRec vd = {0}; 00229 XkbStateRec state = {0}; 00230 00231 XkbGetState(wminfo.info.x11.display, XkbUseCoreKbd, &state); 00232 00233 XkbDescPtr desc = XkbGetKeyboard(wminfo.info.x11.display, XkbAllComponentsMask, XkbUseCoreKbd); 00234 char *group = desc ? XGetAtomName(wminfo.info.x11.display, desc->names->groups[state.group]) : NULL; 00235 00236 if (group != NULL) LOG_MSG("Current X11 keyboard layout (full name) is: '%s'\n",group); 00237 00238 /* FIXME: Does this allocate anything? Do I need to free it? I am concerned about memory leaks --J.C. */ 00239 XkbRF_GetNamesProp(wminfo.info.x11.display, NULL, &vd); 00240 00241 char *tok = vd.layout ? strtok(vd.layout, ",") : NULL; 00242 00243 if (tok != NULL) { 00244 for (int i = 0; i < state.group; i++) { 00245 tok = strtok(NULL, ","); 00246 if (tok == NULL) break; 00247 } 00248 if (tok != NULL) { 00249 LOG_MSG("Current X11 keyboard layout (token) is: '%s'\n",tok); 00250 00251 if (!strcmp(tok,"us")) 00252 ret = DKM_US; 00253 else if (!strcmp(tok,"jp")) 00254 ret = DKM_JPN; 00255 else if (!strcmp(tok,"de")) 00256 ret = DKM_DEU; 00257 } 00258 } 00259 00260 if (group) XFree(group); 00261 if (desc) XFree(desc); 00262 } 00263 # endif 00264 # endif 00265 # endif 00266 } 00267 #else 00268 if (SDL_GetWMInfo(&wminfo) >= 0) { 00269 # if C_X11 00270 # if C_X11_XKB 00271 # if C_X11_EXT_XKBRULES 00272 if (wminfo.subsystem == SDL_SYSWM_X11 && wminfo.info.x11.display != NULL) { 00273 XkbRF_VarDefsRec vd = {0}; 00274 XkbStateRec state = {0}; 00275 00276 XkbGetState(wminfo.info.x11.display, XkbUseCoreKbd, &state); 00277 00278 XkbDescPtr desc = XkbGetKeyboard(wminfo.info.x11.display, XkbAllComponentsMask, XkbUseCoreKbd); 00279 char *group = desc ? XGetAtomName(wminfo.info.x11.display, desc->names->groups[state.group]) : NULL; 00280 00281 if (group != NULL) LOG_MSG("Current X11 keyboard layout (full name) is: '%s'\n",group); 00282 00283 /* FIXME: Does this allocate anything? Do I need to free it? I am concerned about memory leaks --J.C. */ 00284 XkbRF_GetNamesProp(wminfo.info.x11.display, NULL, &vd); 00285 00286 char *tok = vd.layout ? strtok(vd.layout, ",") : NULL; 00287 00288 if (tok != NULL) { 00289 for (int i = 0; i < state.group; i++) { 00290 tok = strtok(NULL, ","); 00291 if (tok == NULL) break; 00292 } 00293 if (tok != NULL) { 00294 LOG_MSG("Current X11 keyboard layout (token) is: '%s'\n",tok); 00295 00296 if (!strcmp(tok,"us")) 00297 ret = DKM_US; 00298 else if (!strcmp(tok,"jp")) 00299 ret = DKM_JPN; 00300 else if (!strcmp(tok,"de")) 00301 ret = DKM_DEU; 00302 } 00303 } 00304 00305 if (group) XFree(group); 00306 if (desc) XFree(desc); 00307 } 00308 # endif 00309 # endif 00310 # endif 00311 } 00312 #endif 00313 00314 return ret; 00315 } 00316 00317 void UpdateWindowDimensions_Linux(void) { 00318 SDL_SysWMinfo wminfo; 00319 memset(&wminfo,0,sizeof(wminfo)); 00320 SDL_VERSION(&wminfo.version); 00321 00322 #if defined(C_SDL2) 00323 SDL_Window* GFX_GetSDLWindow(void); 00324 00325 if (SDL_GetWindowWMInfo(GFX_GetSDLWindow(),&wminfo) >= 0) { 00326 # if C_X11 00327 if (wminfo.subsystem == SDL_SYSWM_X11 && wminfo.info.x11.display != NULL) { 00328 XWindowAttributes attr; 00329 bool maximized = false; 00330 00331 memset(&attr,0,sizeof(attr)); 00332 XGetWindowAttributes(wminfo.info.x11.display, wminfo.info.x11.window, &attr); 00333 00334 /* we also want to ask X11 if the various atoms have been set by the window manager 00335 * to signal that our window has been maximized. generally when the window has been 00336 * maximized, SDL video mode setting has no effect on the dimensions of the window 00337 * when it's been maximized so it helps to know in order to make better choices */ 00338 if (GFX_IsFullscreen()) { 00339 } 00340 else { 00341 Atom atomWmState = XInternAtom(wminfo.info.x11.display, "_NET_WM_STATE", False); 00342 Atom atomMaxVert = XInternAtom(wminfo.info.x11.display, "_NET_WM_STATE_MAXIMIZED_VERT", False); 00343 Atom atomMaxHorz = XInternAtom(wminfo.info.x11.display, "_NET_WM_STATE_MAXIMIZED_HORZ", False); 00344 00345 unsigned long nItem = 0, bytesAfter = 0; 00346 unsigned char *properties = NULL; 00347 Atom type = None; 00348 int format = 0; 00349 00350 XGetWindowProperty(wminfo.info.x11.display, wminfo.info.x11.window, 00351 /*atom to query*/atomWmState,/*offset*/0,/*length*/16384,/*delete*/False, 00352 /*request type*/AnyPropertyType, 00353 /*returns...*/&type,&format,&nItem,&bytesAfter,&properties); 00354 00355 if (properties != NULL) { 00356 if (format == 32) { /* it usually is */ 00357 for (unsigned long i=0;i < nItem;i++) { 00358 uint32_t val = ((uint32_t*)properties)[i]; 00359 00360 if ((Atom)val == atomMaxVert || (Atom)val == atomMaxHorz) 00361 maximized = true; 00362 } 00363 } 00364 00365 XFree(properties); 00366 } 00367 } 00368 00369 LOG_MSG("X11 main window is %u x %u maximized=%u",attr.width, attr.height, maximized); 00370 00371 UpdateWindowDimensions((unsigned int)attr.width, (unsigned int)attr.height); 00372 UpdateWindowMaximized(maximized); 00373 } 00374 # endif 00375 } 00376 #else 00377 if (SDL_GetWMInfo(&wminfo) >= 0) { 00378 # if C_X11 00379 if (wminfo.subsystem == SDL_SYSWM_X11 && wminfo.info.x11.display != NULL) { 00380 XWindowAttributes attr; 00381 bool maximized = false; 00382 00383 memset(&attr,0,sizeof(attr)); 00384 XGetWindowAttributes(wminfo.info.x11.display, GFX_IsFullscreen() ? wminfo.info.x11.fswindow : wminfo.info.x11.wmwindow, &attr); 00385 00386 /* we also want to ask X11 if the various atoms have been set by the window manager 00387 * to signal that our window has been maximized. generally when the window has been 00388 * maximized, SDL video mode setting has no effect on the dimensions of the window 00389 * when it's been maximized so it helps to know in order to make better choices */ 00390 if (GFX_IsFullscreen()) { 00391 } 00392 else { 00393 Atom atomWmState = XInternAtom(wminfo.info.x11.display, "_NET_WM_STATE", False); 00394 Atom atomMaxVert = XInternAtom(wminfo.info.x11.display, "_NET_WM_STATE_MAXIMIZED_VERT", False); 00395 Atom atomMaxHorz = XInternAtom(wminfo.info.x11.display, "_NET_WM_STATE_MAXIMIZED_HORZ", False); 00396 00397 unsigned long nItem = 0, bytesAfter = 0; 00398 unsigned char *properties = NULL; 00399 Atom type = None; 00400 int format = 0; 00401 00402 XGetWindowProperty(wminfo.info.x11.display, wminfo.info.x11.wmwindow, 00403 /*atom to query*/atomWmState,/*offset*/0,/*length*/16384,/*delete*/False, 00404 /*request type*/AnyPropertyType, 00405 /*returns...*/&type,&format,&nItem,&bytesAfter,&properties); 00406 00407 if (properties != NULL) { 00408 if (format == 32) { /* it usually is */ 00409 for (unsigned long i=0;i < nItem;i++) { 00410 uint32_t val = ((uint32_t*)properties)[i]; 00411 00412 if ((Atom)val == atomMaxVert || (Atom)val == atomMaxHorz) 00413 maximized = true; 00414 } 00415 } 00416 00417 XFree(properties); 00418 } 00419 } 00420 00421 LOG_MSG("X11 main window is %u x %u maximized=%u",attr.width, attr.height, maximized); 00422 00423 UpdateWindowDimensions((unsigned int)attr.width, (unsigned int)attr.height); 00424 UpdateWindowMaximized(maximized); 00425 } 00426 # endif 00427 } 00428 #endif 00429 } 00430 00431 #if C_X11 00432 /* Retrieve screen size/dimensions/DPI using XRandR */ 00433 static bool Linux_TryXRandrGetDPI(ScreenSizeInfo &info,Display *display,Window window) { 00434 bool result = false; 00435 # if C_X11_XRANDR 00436 XRRScreenResources *xr_screen; 00437 XWindowAttributes attr; 00438 int x = 0, y = 0; 00439 Window child; 00440 00441 /* do not use XRandR if the X11 server does not support it */ 00442 if (!X11_XRR_check(display)) 00443 return false; 00444 00445 memset(&attr,0,sizeof(attr)); 00446 XGetWindowAttributes(display, window, &attr); 00447 XTranslateCoordinates(display, window, DefaultRootWindow(display), 0, 0, &x, &y, &child ); 00448 00449 attr.x = x - attr.x; 00450 attr.y = y - attr.y; 00451 00452 if ((xr_screen=XRRGetScreenResources(display, DefaultRootWindow(display))) != NULL) { 00453 /* Look for a valid CRTC, don't assume the first is valid (as the StackOverflow example does) */ 00454 for (int c=0;c < xr_screen->ncrtc;c++) { 00455 XRRCrtcInfo *chk = XRRGetCrtcInfo(display, xr_screen, xr_screen->crtcs[c]); 00456 if (chk == NULL) continue; 00457 if (chk->width == 0 || chk->height == 0) continue; 00458 00459 LOG_MSG("XRandR CRTC %u: pos=(%d,%d) size=(%d,%d) outputs=%d", 00460 c,chk->x,chk->y,chk->width,chk->height,chk->noutput); 00461 00462 /* match our window position to the display, use the center */ 00463 int match_x = attr.x + (attr.width / 2); 00464 int match_y = attr.y + (attr.height / 2); 00465 00466 if (match_x >= chk->x && match_x < (chk->x+(int)chk->width) && 00467 match_y >= chk->y && match_y < (chk->y+(int)chk->height)) { 00468 LOG_MSG("Our window lies on this CRTC display (window pos=(%d,%d) size=(%d,%d) match=(%d,%d)).", 00469 attr.x,attr.y, 00470 attr.width,attr.height, 00471 match_x,match_y); 00472 00473 if (chk->noutput > 0) { 00474 for (int o=0;o < chk->noutput;o++) { 00475 XRROutputInfo *ochk = XRRGetOutputInfo(display, xr_screen, chk->outputs[o]); 00476 if (ochk == NULL) continue; 00477 00478 std::string oname; 00479 00480 if (ochk->nameLen > 0 && ochk->name != NULL) 00481 oname = std::string(ochk->name,(size_t)ochk->nameLen); 00482 00483 LOG_MSG(" Goes to output %u: name='%s' size_mm=(%lu x %lu)", 00484 o,oname.c_str(),ochk->mm_width,ochk->mm_height); 00485 00486 if (true/*TODO: Any decision making?*/) { 00487 o = chk->noutput; /* short circuit the for loop */ 00488 c = xr_screen->ncrtc; /* and the other */ 00489 result = true; 00490 00491 /* choose this combo to determine screen size, and dimensions */ 00492 info.method = METHOD_XRANDR; 00493 00494 info.screen_position_pixels.x = chk->x; 00495 info.screen_position_pixels.y = chk->y; 00496 00497 info.screen_dimensions_pixels.width = chk->width; 00498 info.screen_dimensions_pixels.height = chk->height; 00499 00500 info.screen_dimensions_mm.width = ochk->mm_width; 00501 info.screen_dimensions_mm.height = ochk->mm_height; 00502 00503 if (info.screen_dimensions_mm.width > 0) 00504 info.screen_dpi.width = 00505 ((((double)info.screen_dimensions_pixels.width) * 25.4) / 00506 ((double)info.screen_dimensions_mm.width)); 00507 00508 if (info.screen_dimensions_mm.height > 0) 00509 info.screen_dpi.height = 00510 ((((double)info.screen_dimensions_pixels.height) * 25.4) / 00511 ((double)info.screen_dimensions_mm.height)); 00512 } 00513 00514 XRRFreeOutputInfo(ochk); 00515 ochk = NULL; 00516 } 00517 } 00518 } 00519 00520 XRRFreeCrtcInfo(chk); 00521 chk = NULL; 00522 } 00523 00524 XRRFreeScreenResources(xr_screen); 00525 xr_screen = NULL; 00526 } 00527 #else 00528 (void)info; //UNUSED 00529 (void)display; //UNUSED 00530 (void)window; //UNUSED 00531 # endif 00532 00533 return result; 00534 } 00535 #endif 00536 00537 void Linux_GetWindowDPI(ScreenSizeInfo &info) { 00538 info.clear(); 00539 00540 SDL_SysWMinfo wminfo; 00541 memset(&wminfo,0,sizeof(wminfo)); 00542 SDL_VERSION(&wminfo.version); 00543 00544 #if defined(C_SDL2) 00545 SDL_Window* GFX_GetSDLWindow(void); 00546 00547 if (SDL_GetWindowWMInfo(GFX_GetSDLWindow(),&wminfo) >= 0) { 00548 # if C_X11 00549 if (wminfo.subsystem == SDL_SYSWM_X11 && wminfo.info.x11.display != NULL) { 00550 if (Linux_TryXRandrGetDPI(info,wminfo.info.x11.display,wminfo.info.x11.window)) { 00551 /* got it */ 00552 } 00553 else { 00554 /* fallback to X11 method, which may not return accurate info on modern systems */ 00555 Window rootWindow = DefaultRootWindow(wminfo.info.x11.display); 00556 if (rootWindow != 0) { 00557 int screen = 0; 00558 00559 info.method = METHOD_X11; 00560 00561 /* found on StackOverflow */ 00562 00563 /* 00564 * there are 2.54 centimeters to an inch; so there are 25.4 millimeters. 00565 * 00566 * dpi = N pixels / (M millimeters / (25.4 millimeters / 1 inch)) 00567 * = N pixels / (M inch / 25.4) 00568 * = N * 25.4 pixels / M inch 00569 */ 00570 info.screen_dimensions_pixels.width = DisplayWidth( wminfo.info.x11.display,screen); 00571 info.screen_dimensions_pixels.height = DisplayHeight( wminfo.info.x11.display,screen); 00572 00573 info.screen_dimensions_mm.width = DisplayWidthMM( wminfo.info.x11.display,screen); 00574 info.screen_dimensions_mm.height = DisplayHeightMM(wminfo.info.x11.display,screen); 00575 00576 if (info.screen_dimensions_mm.width > 0) 00577 info.screen_dpi.width = 00578 ((((double)info.screen_dimensions_pixels.width) * 25.4) / 00579 ((double)info.screen_dimensions_mm.width)); 00580 00581 if (info.screen_dimensions_mm.height > 0) 00582 info.screen_dpi.height = 00583 ((((double)info.screen_dimensions_pixels.height) * 25.4) / 00584 ((double)info.screen_dimensions_mm.height)); 00585 } 00586 } 00587 } 00588 # endif 00589 } 00590 #else 00591 if (SDL_GetWMInfo(&wminfo) >= 0) { 00592 # if C_X11 00593 if (wminfo.subsystem == SDL_SYSWM_X11 && wminfo.info.x11.display != NULL) { 00594 if (Linux_TryXRandrGetDPI(info,wminfo.info.x11.display,GFX_IsFullscreen() ? wminfo.info.x11.fswindow : wminfo.info.x11.wmwindow)) { 00595 /* got it */ 00596 } 00597 else { 00598 /* fallback to X11 method, which may not return accurate info on modern systems */ 00599 Window rootWindow = DefaultRootWindow(wminfo.info.x11.display); 00600 if (rootWindow != 0) { 00601 int screen = 0; 00602 00603 info.method = METHOD_X11; 00604 00605 /* found on StackOverflow */ 00606 00607 /* 00608 * there are 2.54 centimeters to an inch; so there are 25.4 millimeters. 00609 * 00610 * dpi = N pixels / (M millimeters / (25.4 millimeters / 1 inch)) 00611 * = N pixels / (M inch / 25.4) 00612 * = N * 25.4 pixels / M inch 00613 */ 00614 info.screen_dimensions_pixels.width = DisplayWidth( wminfo.info.x11.display,screen); 00615 info.screen_dimensions_pixels.height = DisplayHeight( wminfo.info.x11.display,screen); 00616 00617 info.screen_dimensions_mm.width = DisplayWidthMM( wminfo.info.x11.display,screen); 00618 info.screen_dimensions_mm.height = DisplayHeightMM(wminfo.info.x11.display,screen); 00619 00620 if (info.screen_dimensions_mm.width > 0) 00621 info.screen_dpi.width = 00622 ((((double)info.screen_dimensions_pixels.width) * 25.4) / 00623 ((double)info.screen_dimensions_mm.width)); 00624 00625 if (info.screen_dimensions_mm.height > 0) 00626 info.screen_dpi.height = 00627 ((((double)info.screen_dimensions_pixels.height) * 25.4) / 00628 ((double)info.screen_dimensions_mm.height)); 00629 } 00630 } 00631 } 00632 # endif 00633 } 00634 #endif 00635 } 00636 00637 void Linux_GetDesktopResolution(int *width,int *height) { 00638 /* We're most likely running on an X-windows desktop (through SDL). */ 00639 SDL_SysWMinfo wminfo; 00640 memset(&wminfo,0,sizeof(wminfo)); 00641 SDL_VERSION(&wminfo.version); 00642 00643 #if defined(C_SDL2) 00644 SDL_Window* GFX_GetSDLWindow(void); 00645 00646 if (SDL_GetWindowWMInfo(GFX_GetSDLWindow(),&wminfo) >= 0) { 00647 # if C_X11 00648 if (wminfo.subsystem == SDL_SYSWM_X11 && wminfo.info.x11.display != NULL) { 00649 LOG_MSG("GetDesktopResolution reading X11 desktop resolution"); 00650 00651 Window rootWindow = DefaultRootWindow(wminfo.info.x11.display); 00652 if (rootWindow != 0) { 00653 XWindowAttributes rootWinAttr; 00654 00655 memset(&rootWinAttr,0,sizeof(rootWinAttr)); 00656 XGetWindowAttributes(wminfo.info.x11.display,rootWindow,&rootWinAttr); 00657 LOG_MSG("Root window (ID %lu) is %lu x %lu",(unsigned long)rootWindow,(unsigned long)rootWinAttr.width,(unsigned long)rootWinAttr.height); 00658 00659 if (rootWinAttr.width > 0 && rootWinAttr.height > 0) { 00660 *width = (int)rootWinAttr.width; 00661 *height = (int)rootWinAttr.height; 00662 } 00663 else { 00664 *width = 1024; // guess 00665 *height = 768; 00666 } 00667 } 00668 else { 00669 *width = 1024; // guess 00670 *height = 768; 00671 } 00672 } 00673 else 00674 # endif 00675 { 00676 *width = 1024; // guess 00677 *height = 768; 00678 } 00679 } 00680 else { 00681 *width = 1024; // guess 00682 *height = 768; 00683 } 00684 #else 00685 if (SDL_GetWMInfo(&wminfo) >= 0) { 00686 # if C_X11 00687 if (wminfo.subsystem == SDL_SYSWM_X11 && wminfo.info.x11.display != NULL) { 00688 LOG_MSG("GetDesktopResolution reading X11 desktop resolution"); 00689 00690 Window rootWindow = DefaultRootWindow(wminfo.info.x11.display); 00691 if (rootWindow != 0) { 00692 XWindowAttributes rootWinAttr; 00693 00694 memset(&rootWinAttr,0,sizeof(rootWinAttr)); 00695 XGetWindowAttributes(wminfo.info.x11.display,rootWindow,&rootWinAttr); 00696 LOG_MSG("Root window (ID %lu) is %lu x %lu",(unsigned long)rootWindow,(unsigned long)rootWinAttr.width,(unsigned long)rootWinAttr.height); 00697 00698 if (rootWinAttr.width > 0 && rootWinAttr.height > 0) { 00699 *width = (int)rootWinAttr.width; 00700 *height = (int)rootWinAttr.height; 00701 } 00702 else { 00703 *width = 1024; // guess 00704 *height = 768; 00705 } 00706 } 00707 else { 00708 *width = 1024; // guess 00709 *height = 768; 00710 } 00711 } 00712 else 00713 # endif 00714 { 00715 *width = 1024; // guess 00716 *height = 768; 00717 } 00718 } 00719 else { 00720 *width = 1024; // guess 00721 *height = 768; 00722 } 00723 #endif 00724 } 00725 #endif 00726