DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/gui/sdlmain_linux.cpp
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