Browse Source

x11: Implemented dpi detection

depends on XRandR.
Had to dynamically load `XRRGetMonitors` as Ubuntu 12.04 doesn't have it.
Also removed libudev from travis install list.
Andreas Haas 9 years ago
parent
commit
18c941bbec
4 changed files with 85 additions and 2 deletions
  1. 1 1
      .travis.yml
  2. 7 1
      platform/x11/detect.py
  3. 58 0
      platform/x11/os_x11.cpp
  4. 19 0
      platform/x11/os_x11.h

+ 1 - 1
.travis.yml

@@ -54,7 +54,7 @@ addons:
       - libglu1-mesa-dev
       - libssl-dev
       - libxinerama-dev
-      - libudev-dev
+      - libxrandr-dev
 
       # For cross-compiling to Windows.
       - binutils-mingw-w64-i686

+ 7 - 1
platform/x11/detect.py

@@ -45,6 +45,11 @@ def can_build():
 		print("xinerama not found.. x11 disabled.")
 		return False
 
+	x11_error=os.system("pkg-config xrandr --modversion > /dev/null ")
+	if (x11_error):
+			print("xrandr not found.. x11 disabled.")
+			return False
+
 
 	return True # X11 enabled
 
@@ -132,6 +137,7 @@ def configure(env):
 	env.ParseConfig('pkg-config x11 --cflags --libs')
 	env.ParseConfig('pkg-config xinerama --cflags --libs')
 	env.ParseConfig('pkg-config xcursor --cflags --libs')
+	env.ParseConfig('pkg-config xrandr --cflags --libs')
 
 	if (env["openssl"]=="yes"):
 		env.ParseConfig('pkg-config openssl --cflags --libs')
@@ -179,7 +185,7 @@ def configure(env):
 			print("PulseAudio development libraries not found, disabling driver")
 
 	env.Append(CPPFLAGS=['-DX11_ENABLED','-DUNIX_ENABLED','-DGLES2_ENABLED','-DGLES_OVER_GL'])
-	env.Append(LIBS=['GL', 'GLU', 'pthread', 'z'])
+	env.Append(LIBS=['GL', 'GLU', 'pthread', 'z', 'dl'])
 	#env.Append(CPPFLAGS=['-DMPC_FIXED_POINT'])
 
 #host compiler is default..

+ 58 - 0
platform/x11/os_x11.cpp

@@ -57,6 +57,7 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <dlfcn.h>
 
 //stupid linux.h
 #ifdef KEY_TAB
@@ -117,6 +118,19 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
 	char * modifiers = XSetLocaleModifiers ("@im=none");
 	ERR_FAIL_COND( modifiers == NULL );
 
+	const char* err;
+	xrr_get_monitors = NULL;
+	xrandr_handle = dlopen("libXrandr.so", RTLD_LAZY);
+	err = dlerror();
+	if (!xrandr_handle) {
+		fprintf(stderr, "could not load libXrandr.so, dpi detection disabled. Error: %s\n", err);
+	}
+	else {
+		xrr_get_monitors = (xrr_get_monitors_t) dlsym(xrandr_handle, "XRRGetMonitors");
+		if (!xrr_get_monitors)
+			fprintf(stderr, "could not find symbol XRRGetMonitors, dpi detection will only work on the first screen\nError: %s\n", err);
+	}
+
 	xim = XOpenIM (x11_display, NULL, NULL, NULL);
 
 
@@ -480,6 +494,9 @@ void OS_X11::finalize() {
 	physics_2d_server->finish();
 	memdelete(physics_2d_server);
 
+	if (xrandr_handle)
+		dlclose(xrandr_handle);
+
 	XUnmapWindow( x11_display, x11_window );
 	XDestroyWindow( x11_display, x11_window );
 
@@ -722,6 +739,47 @@ Size2 OS_X11::get_screen_size(int p_screen) const {
 	return size;
 }
 
+int OS_X11::get_screen_dpi(int p_screen) const {
+
+	//invalid screen?
+	ERR_FAIL_INDEX_V(p_screen, get_screen_count(), 0);
+
+	//Get physical monitor Dimensions through XRandR and calculate dpi
+	int event_base, error_base;
+	const Bool ext_okay = XRRQueryExtension(x11_display,&event_base, &error_base);
+
+	Size2 sc = get_screen_size(p_screen);
+	if (ext_okay) {
+		int count = 0;
+		if (xrr_get_monitors) {
+			xrr_monitor_info *monitors = xrr_get_monitors(x11_display, x11_window, true, &count);
+			if (p_screen < count) {
+				double xdpi = sc.width  / (double) monitors[p_screen].mwidth  * 25.4;
+				double ydpi = sc.height / (double) monitors[p_screen].mheight * 25.4;
+				return (xdpi + ydpi) / 2;
+			}
+		}
+		else if (p_screen == 0) {
+			XRRScreenSize *sizes = XRRSizes(x11_display, 0, &count);
+			if (sizes) {
+				double xdpi = sc.width  / (double) sizes[0].mwidth  * 25.4;
+				double ydpi = sc.height / (double) sizes[0].mheight * 25.4;
+				return (xdpi + ydpi) / 2;
+			}
+		}
+	}
+
+	int width_mm  = DisplayWidthMM(x11_display, p_screen);
+	int height_mm = DisplayHeightMM(x11_display, p_screen);
+	double xdpi = (width_mm  ? sc.width  / (double) width_mm  * 25.4 : 0);
+	double ydpi = (height_mm ? sc.height / (double) height_mm * 25.4 : 0);
+	if (xdpi || xdpi)
+		return  (xdpi + ydpi)/(xdpi && ydpi ? 2 : 1);
+
+	//could not get dpi
+	return 96;
+}
+
 Point2 OS_X11::get_window_position() const {
 	int x,y;
 	Window child;

+ 19 - 0
platform/x11/os_x11.h

@@ -52,6 +52,7 @@
 #include <X11/keysym.h>
 #include <X11/Xlib.h>
 #include <X11/Xcursor/Xcursor.h>
+#include <X11/extensions/Xrandr.h>
 
 // Hints for X11 fullscreen
 typedef struct {
@@ -62,6 +63,20 @@ typedef struct {
 	unsigned long status;
 } Hints;
 
+typedef struct _xrr_monitor_info {
+    Atom name;
+    Bool primary;
+    Bool automatic;
+    int noutput;
+    int x;
+    int y;
+    int width;
+    int height;
+    int mwidth;
+    int mheight;
+    RROutput *outputs;
+} xrr_monitor_info;
+
 #undef CursorShape
 /**
 	@author Juan Linietsky <[email protected]>
@@ -162,6 +177,9 @@ class OS_X11 : public OS_Unix {
 	//void set_wm_border(bool p_enabled);
 	void set_wm_fullscreen(bool p_enabled);
 
+	typedef xrr_monitor_info* (*xrr_get_monitors_t)(Display *dpy, Window window, Bool get_active, int *nmonitors);
+	xrr_get_monitors_t xrr_get_monitors;
+	void *xrandr_handle;
 
 protected:
 
@@ -219,6 +237,7 @@ public:
 	virtual void set_current_screen(int p_screen);
 	virtual Point2 get_screen_position(int p_screen=0) const;
 	virtual Size2 get_screen_size(int p_screen=0) const;
+	virtual int get_screen_dpi(int p_screen=0) const;
 	virtual Point2 get_window_position() const;
 	virtual void set_window_position(const Point2& p_position);
 	virtual Size2 get_window_size() const;