summaryrefslogtreecommitdiff
path: root/platform/x11
diff options
context:
space:
mode:
Diffstat (limited to 'platform/x11')
-rw-r--r--platform/x11/context_gl_x11.cpp38
-rw-r--r--platform/x11/context_gl_x11.h4
-rw-r--r--platform/x11/detect.py4
-rw-r--r--platform/x11/os_x11.cpp179
-rw-r--r--platform/x11/os_x11.h15
5 files changed, 238 insertions, 2 deletions
diff --git a/platform/x11/context_gl_x11.cpp b/platform/x11/context_gl_x11.cpp
index 9f987e1376..cd325dfc99 100644
--- a/platform/x11/context_gl_x11.cpp
+++ b/platform/x11/context_gl_x11.cpp
@@ -34,7 +34,9 @@
#include <unistd.h>
#include <stdlib.h>
+#define GLX_GLXEXT_PROTOTYPES
#include <GL/glx.h>
+#include <GL/glxext.h>
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
@@ -176,6 +178,41 @@ int ContextGL_X11::get_window_height() {
return xwa.height;
}
+void ContextGL_X11::set_use_vsync(bool p_use) {
+ static bool setup = false;
+ static PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT = NULL;
+ static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalMESA = NULL;
+ static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = NULL;
+
+ if (!setup) {
+ setup = true;
+ String extensions = glXQueryExtensionsString(x11_display, DefaultScreen(x11_display));
+ if (extensions.find("GLX_EXT_swap_control") != -1)
+ glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) glXGetProcAddressARB((const GLubyte*)"glXSwapIntervalEXT");
+ if (extensions.find("GLX_MESA_swap_control") != -1)
+ glXSwapIntervalMESA = (PFNGLXSWAPINTERVALSGIPROC) glXGetProcAddressARB((const GLubyte*)"glXSwapIntervalMESA");
+ if (extensions.find("GLX_SGI_swap_control") != -1)
+ glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC) glXGetProcAddressARB((const GLubyte*)"glXSwapIntervalSGI");
+ }
+ int val = p_use ? 1:0;
+ if (glXSwapIntervalMESA) {
+ glXSwapIntervalMESA(val);
+ }
+ else if (glXSwapIntervalSGI) {
+ glXSwapIntervalSGI(val);
+ }
+ else if (glXSwapIntervalEXT) {
+ GLXDrawable drawable = glXGetCurrentDrawable();
+ glXSwapIntervalEXT(x11_display, drawable, val);
+ }
+ else return;
+ use_vsync = p_use;
+}
+bool ContextGL_X11::is_using_vsync() const {
+
+ return use_vsync;
+}
+
ContextGL_X11::ContextGL_X11(::Display *p_x11_display,::Window &p_x11_window,const OS::VideoMode& p_default_video_mode,bool p_opengl_3_context) : x11_window(p_x11_window) {
@@ -189,6 +226,7 @@ ContextGL_X11::ContextGL_X11(::Display *p_x11_display,::Window &p_x11_window,con
glx_minor=glx_major=0;
p = memnew( ContextGL_X11_Private );
p->glx_context=0;
+ use_vsync=false;
}
diff --git a/platform/x11/context_gl_x11.h b/platform/x11/context_gl_x11.h
index c77fb3e333..4474542c0b 100644
--- a/platform/x11/context_gl_x11.h
+++ b/platform/x11/context_gl_x11.h
@@ -55,6 +55,7 @@ class ContextGL_X11 : public ContextGL {
bool direct_render;
int glx_minor,glx_major;
bool opengl_3_context;
+ bool use_vsync;
public:
virtual void release_current();
@@ -65,6 +66,9 @@ public:
virtual Error initialize();
+ virtual void set_use_vsync(bool p_use);
+ virtual bool is_using_vsync() const;
+
ContextGL_X11(::Display *p_x11_display,::Window &p_x11_window,const OS::VideoMode& p_default_video_mode,bool p_opengl_3_context);
~ContextGL_X11();
diff --git a/platform/x11/detect.py b/platform/x11/detect.py
index 6b3f7147ef..5a43bf9323 100644
--- a/platform/x11/detect.py
+++ b/platform/x11/detect.py
@@ -143,8 +143,8 @@ def configure(env):
if (env["freetype"]!="no"):
env.Append(CCFLAGS=['-DFREETYPE_ENABLED'])
if (env["freetype"]=="builtin"):
- env.Append(CPPPATH=['#tools/freetype'])
- env.Append(CPPPATH=['#tools/freetype/freetype/include'])
+ env.Append(CPPPATH=['#drivers/freetype'])
+ env.Append(CPPPATH=['#drivers/freetype/freetype/include'])
env.Append(CPPFLAGS=['-DOPENGL_ENABLED','-DGLEW_ENABLED'])
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index 4d7532d637..b089436a17 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -105,6 +105,7 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
last_timestamp=0;
last_mouse_pos_valid=false;
last_keyrelease_time=0;
+ xdnd_version = 0;
if (get_render_thread_mode()==RENDER_SEPARATE_THREAD) {
XInitThreads();
@@ -415,6 +416,19 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
}
set_cursor_shape(CURSOR_BUSY);
+ //Set Xdnd (drag & drop) support
+ Atom XdndAware = XInternAtom(x11_display, "XdndAware", False);
+ Atom version=5;
+ XChangeProperty(x11_display, x11_window, XdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char*)&version, 1);
+
+ xdnd_enter = XInternAtom(x11_display, "XdndEnter", False);
+ xdnd_position = XInternAtom(x11_display, "XdndPosition", False);
+ xdnd_status = XInternAtom(x11_display, "XdndStatus", False);
+ xdnd_action_copy = XInternAtom(x11_display, "XdndActionCopy", False);
+ xdnd_drop = XInternAtom(x11_display, "XdndDrop", False);
+ xdnd_finished = XInternAtom(x11_display, "XdndFinished", False);
+ xdnd_selection = XInternAtom(x11_display, "XdndSelection", False);
+ requested = None;
visual_server->init();
//
@@ -1166,6 +1180,72 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
input->parse_input_event( event);
}
+struct Property
+{
+ unsigned char *data;
+ int format, nitems;
+ Atom type;
+};
+
+static Property read_property(Display* p_display, Window p_window, Atom p_property) {
+
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems;
+ unsigned long bytes_after;
+ unsigned char *ret=0;
+
+ int read_bytes = 1024;
+
+ //Keep trying to read the property until there are no
+ //bytes unread.
+ do
+ {
+ if(ret != 0)
+ XFree(ret);
+
+ XGetWindowProperty(p_display, p_window, p_property, 0, read_bytes, False, AnyPropertyType,
+ &actual_type, &actual_format, &nitems, &bytes_after,
+ &ret);
+
+ read_bytes *= 2;
+
+ }while(bytes_after != 0);
+
+ Property p = {ret, actual_format, nitems, actual_type};
+
+ return p;
+}
+
+static Atom pick_target_from_list(Display* p_display, Atom *p_list, int p_count) {
+
+ static const char* target_type = "text/uri-list";
+
+ for (int i = 0; i < p_count; i++) {
+
+ Atom atom = p_list[i];
+
+ if (atom != None && String(XGetAtomName(p_display, atom)) == target_type)
+ return atom;
+ }
+ return None;
+}
+
+static Atom pick_target_from_atoms(Display* p_disp, Atom p_t1, Atom p_t2, Atom p_t3) {
+
+ static const char* target_type = "text/uri-list";
+ if (p_t1 != None && String(XGetAtomName(p_disp, p_t1)) == target_type)
+ return p_t1;
+
+ if (p_t2 != None && String(XGetAtomName(p_disp, p_t2)) == target_type)
+ return p_t2;
+
+ if (p_t3 != None && String(XGetAtomName(p_disp, p_t3)) == target_type)
+ return p_t3;
+
+ return None;
+}
+
void OS_X11::process_xevents() {
//printf("checking events %i\n", XPending(x11_display));
@@ -1456,11 +1536,96 @@ void OS_X11::process_xevents() {
XFlush (x11_display);
} break;
+ case SelectionNotify:
+
+ if (event.xselection.target == requested) {
+
+ Property p = read_property(x11_display, x11_window, XInternAtom(x11_display, "PRIMARY", 0));
+
+ Vector<String> files = String((char *)p.data).split("\n", false);
+ for (int i = 0; i < files.size(); i++) {
+ files[i] = files[i].replace("file://", "").replace("%20", " ").strip_escapes();
+ }
+ main_loop->drop_files(files);
+
+ //Reply that all is well.
+ XClientMessageEvent m;
+ memset(&m, sizeof(m), 0);
+ m.type = ClientMessage;
+ m.display = x11_display;
+ m.window = xdnd_source_window;
+ m.message_type = xdnd_finished;
+ m.format=32;
+ m.data.l[0] = x11_window;
+ m.data.l[1] = 1;
+ m.data.l[2] = xdnd_action_copy; //We only ever copy.
+
+ XSendEvent(x11_display, xdnd_source_window, False, NoEventMask, (XEvent*)&m);
+ }
+ break;
case ClientMessage:
if ((unsigned int)event.xclient.data.l[0]==(unsigned int)wm_delete)
main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
+
+ else if ((unsigned int)event.xclient.message_type == (unsigned int)xdnd_enter) {
+
+ //File(s) have been dragged over the window, check for supported target (text/uri-list)
+ xdnd_version = ( event.xclient.data.l[1] >> 24);
+ Window source = event.xclient.data.l[0];
+ bool more_than_3 = event.xclient.data.l[1] & 1;
+ if (more_than_3) {
+ Property p = read_property(x11_display, source, XInternAtom(x11_display, "XdndTypeList", False));
+ requested = pick_target_from_list(x11_display, (Atom*)p.data, p.nitems);
+ }
+ else
+ requested = pick_target_from_atoms(x11_display, event.xclient.data.l[2],event.xclient.data.l[3], event.xclient.data.l[4]);
+ }
+ else if ((unsigned int)event.xclient.message_type == (unsigned int )xdnd_position) {
+
+ //xdnd position event, reply with an XDND status message
+ //just depending on type of data for now
+ XClientMessageEvent m;
+ memset(&m, sizeof(m), 0);
+ m.type = ClientMessage;
+ m.display = event.xclient.display;
+ m.window = event.xclient.data.l[0];
+ m.message_type = xdnd_status;
+ m.format=32;
+ m.data.l[0] = x11_window;
+ m.data.l[1] = (requested != None);
+ m.data.l[2] = 0; //empty rectangle
+ m.data.l[3] = 0;
+ m.data.l[4] = xdnd_action_copy;
+
+ XSendEvent(x11_display, event.xclient.data.l[0], False, NoEventMask, (XEvent*)&m);
+ XFlush(x11_display);
+ }
+ else if ((unsigned int)event.xclient.message_type == (unsigned int)xdnd_drop) {
+
+ if (requested != None) {
+ xdnd_source_window = event.xclient.data.l[0];
+ if(xdnd_version >= 1)
+ XConvertSelection(x11_display, xdnd_selection, requested, XInternAtom(x11_display, "PRIMARY", 0), x11_window, event.xclient.data.l[2]);
+ else
+ XConvertSelection(x11_display, xdnd_selection, requested, XInternAtom(x11_display, "PRIMARY", 0), x11_window, CurrentTime);
+ }
+ else {
+ //Reply that we're not interested.
+ XClientMessageEvent m;
+ memset(&m, sizeof(m), 0);
+ m.type = ClientMessage;
+ m.display = event.xclient.display;
+ m.window = event.xclient.data.l[0];
+ m.message_type = xdnd_finished;
+ m.format=32;
+ m.data.l[0] = x11_window;
+ m.data.l[1] = 0;
+ m.data.l[2] = None; //Failed.
+ XSendEvent(x11_display, event.xclient.data.l[0], False, NoEventMask, (XEvent*)&m);
+ }
+ }
break;
default:
break;
@@ -1787,6 +1952,20 @@ String OS_X11::get_joy_guid(int p_device) const {
return input->get_joy_guid_remapped(p_device);
}
+void OS_X11::set_use_vsync(bool p_enable) {
+ if (context_gl)
+ return context_gl->set_use_vsync(p_enable);
+}
+
+bool OS_X11::is_vsnc_enabled() const {
+
+ if (context_gl)
+ return context_gl->is_using_vsync();
+
+ return true;
+}
+
+
void OS_X11::set_context(int p_context) {
XClassHint* classHint = NULL;
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
index d9a5b1688c..311f26d4d3 100644
--- a/platform/x11/os_x11.h
+++ b/platform/x11/os_x11.h
@@ -70,6 +70,17 @@ typedef struct {
class OS_X11 : public OS_Unix {
Atom wm_delete;
+ Atom xdnd_enter;
+ Atom xdnd_position;
+ Atom xdnd_status;
+ Atom xdnd_action_copy;
+ Atom xdnd_drop;
+ Atom xdnd_finished;
+ Atom xdnd_selection;
+ Atom requested;
+
+ int xdnd_version;
+
#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
ContextGL_X11 *context_gl;
#endif
@@ -78,6 +89,7 @@ class OS_X11 : public OS_Unix {
VideoMode current_videomode;
List<String> args;
Window x11_window;
+ Window xdnd_source_window;
MainLoop *main_loop;
::Display* x11_display;
char *xmbstring;
@@ -228,6 +240,9 @@ public:
virtual void set_context(int p_context);
+ virtual void set_use_vsync(bool p_enable);
+ virtual bool is_vsnc_enabled() const;
+
void run();
OS_X11();