diff options
-rw-r--r-- | README.md | 21 | ||||
-rw-r--r-- | core/bind/core_bind.cpp | 91 | ||||
-rw-r--r-- | core/bind/core_bind.h | 20 | ||||
-rw-r--r-- | core/os/os.h | 24 | ||||
-rw-r--r-- | demos/misc/window_management/control.gd | 116 | ||||
-rw-r--r-- | demos/misc/window_management/engine.cfg | 12 | ||||
-rw-r--r-- | demos/misc/window_management/icon.png | bin | 0 -> 3639 bytes | |||
-rw-r--r-- | demos/misc/window_management/icon.png.flags | 1 | ||||
-rw-r--r-- | demos/misc/window_management/window_management.scn | bin | 0 -> 4030 bytes | |||
-rw-r--r-- | main/main.cpp | 1 | ||||
-rw-r--r-- | platform/x11/detect.py | 10 | ||||
-rw-r--r-- | platform/x11/os_x11.cpp | 468 | ||||
-rw-r--r-- | platform/x11/os_x11.h | 29 |
13 files changed, 756 insertions, 37 deletions
@@ -1,3 +1,24 @@ +### x11-window-management branch + +#### New GDScript Methods for the OS Class: +* int OS.get_screen_count() +* int OS.get_screen() +* void OS.set_screen(int screen) +* Vector2 OS.get_screen_position(int screen=0) +* Vector2 OS.get_screen_size(int screen=0) +* Vector2 OS.get_window_position() +* void OS.set_window_position(Vector2 position) +* Vector2 OS.get_window_size() +* void OS.set_window_size(Vector2 size) +* void OS.set_fullscreen(bool enabled) +* bool OS.is_fullscreen() + +#### Demo +A demo/test is available at "demos/misc/window-management" + +#### Scons Commandline +'''scons p=x11 experimental_wm_api=yes''' + ![GODOT](/logo.png) ### The Engine diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 0c5d21b4f6..6919c70a5f 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -176,6 +176,76 @@ bool _OS::is_video_mode_fullscreen(int p_screen) const { } +#ifdef EXPERIMENTAL_WM_API +int _OS::get_screen_count() const { + return OS::get_singleton()->get_screen_count(); +} + +int _OS::get_screen() const { + return OS::get_singleton()->get_screen(); +} + +void _OS::set_screen(int p_screen) { + OS::get_singleton()->set_screen(p_screen); +} + +Point2 _OS::get_screen_position(int p_screen) const { + return OS::get_singleton()->get_screen_position(p_screen); +} + +Size2 _OS::get_screen_size(int p_screen) const { + return OS::get_singleton()->get_screen_size(p_screen); +} + +Point2 _OS::get_window_position() const { + return OS::get_singleton()->get_window_position(); +} + +void _OS::set_window_position(const Point2& p_position) { + OS::get_singleton()->set_window_position(p_position); +} + +Size2 _OS::get_window_size() const { + return OS::get_singleton()->get_window_size(); +} + +void _OS::set_window_size(const Size2& p_size) { + OS::get_singleton()->set_window_size(p_size); +} + +void _OS::set_fullscreen(bool p_enabled) { + OS::get_singleton()->set_fullscreen(p_enabled); +} + +bool _OS::is_fullscreen() const { + return OS::get_singleton()->is_fullscreen(); +} + +void _OS::set_resizable(bool p_enabled) { + OS::get_singleton()->set_resizable(p_enabled); +} + +bool _OS::is_resizable() const { + return OS::get_singleton()->is_resizable(); +} + +void _OS::set_minimized(bool p_enabled) { + OS::get_singleton()->set_minimized(p_enabled); +} + +bool _OS::is_minimized() const { + return OS::get_singleton()->is_minimized(); +} + +void _OS::set_maximized(bool p_enabled) { + OS::get_singleton()->set_maximized(p_enabled); +} + +bool _OS::is_maximized() const { + return OS::get_singleton()->is_maximized(); +} +#endif + void _OS::set_use_file_access_save_and_swap(bool p_enable) { FileAccess::set_backup_save(p_enable); @@ -186,7 +256,6 @@ bool _OS::is_video_mode_resizable(int p_screen) const { OS::VideoMode vm; vm = OS::get_singleton()->get_video_mode(p_screen); return vm.resizable; - } Array _OS::get_fullscreen_mode_list(int p_screen) const { @@ -632,6 +701,26 @@ void _OS::_bind_methods() { ObjectTypeDB::bind_method(_MD("is_video_mode_resizable","screen"),&_OS::is_video_mode_resizable,DEFVAL(0)); ObjectTypeDB::bind_method(_MD("get_fullscreen_mode_list","screen"),&_OS::get_fullscreen_mode_list,DEFVAL(0)); +#ifdef EXPERIMENTAL_WM_API + ObjectTypeDB::bind_method(_MD("get_screen_count"),&_OS::get_screen_count); + ObjectTypeDB::bind_method(_MD("get_screen"),&_OS::get_screen); + ObjectTypeDB::bind_method(_MD("set_screen"),&_OS::set_screen); + ObjectTypeDB::bind_method(_MD("get_screen_position"),&_OS::get_screen_position,DEFVAL(0)); + ObjectTypeDB::bind_method(_MD("get_screen_size"),&_OS::get_screen_size,DEFVAL(0)); + ObjectTypeDB::bind_method(_MD("get_window_position"),&_OS::get_window_position); + ObjectTypeDB::bind_method(_MD("set_window_position"),&_OS::set_window_position); + ObjectTypeDB::bind_method(_MD("get_window_size"),&_OS::get_window_size); + ObjectTypeDB::bind_method(_MD("set_window_size"),&_OS::set_window_size); + ObjectTypeDB::bind_method(_MD("set_fullscreen","enabled"),&_OS::set_fullscreen); + ObjectTypeDB::bind_method(_MD("is_fullscreen"),&_OS::is_fullscreen); + ObjectTypeDB::bind_method(_MD("set_resizable","enabled"),&_OS::set_resizable); + ObjectTypeDB::bind_method(_MD("is_resizable"),&_OS::is_resizable); + ObjectTypeDB::bind_method(_MD("set_minimized", "enabled"),&_OS::set_minimized); + ObjectTypeDB::bind_method(_MD("is_minimized"),&_OS::is_minimized); + ObjectTypeDB::bind_method(_MD("set_maximized", "enabled"),&_OS::set_maximized); + ObjectTypeDB::bind_method(_MD("is_maximized"),&_OS::is_maximized); +#endif + ObjectTypeDB::bind_method(_MD("set_iterations_per_second","iterations_per_second"),&_OS::set_iterations_per_second); ObjectTypeDB::bind_method(_MD("get_iterations_per_second"),&_OS::get_iterations_per_second); ObjectTypeDB::bind_method(_MD("set_target_fps","target_fps"),&_OS::set_target_fps); diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index 12a4ae86eb..b6f4f8eef4 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -108,6 +108,26 @@ public: bool is_video_mode_resizable(int p_screen=0) const; Array get_fullscreen_mode_list(int p_screen=0) const; +#ifdef EXPERIMENTAL_WM_API + virtual int get_screen_count() const; + virtual int get_screen() const; + virtual void set_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 Point2 get_window_position() const; + virtual void set_window_position(const Point2& p_position); + virtual Size2 get_window_size() const; + virtual void set_window_size(const Size2& p_size); + virtual void set_fullscreen(bool p_enabled); + virtual bool is_fullscreen() const; + virtual void set_resizable(bool p_enabled); + virtual bool is_resizable() const; + virtual void set_minimized(bool p_enabled); + virtual bool is_minimized() const; + virtual void set_maximized(bool p_enabled); + virtual bool is_maximized() const; +#endif + Error native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track); bool native_video_is_playing(); void native_video_pause(); diff --git a/core/os/os.h b/core/os/os.h index d4deff2f5e..c04a91e302 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -73,7 +73,7 @@ public: bool fullscreen; bool resizable; float get_aspect() const { return (float)width/(float)height; } - VideoMode(int p_width=640,int p_height=480,bool p_fullscreen=false, bool p_resizable = true) { width=p_width; height=p_height; fullscreen=p_fullscreen; resizable = p_resizable; } + VideoMode(int p_width=640,int p_height=480,bool p_fullscreen=false, bool p_resizable = true) {width=p_width; height=p_height; fullscreen=p_fullscreen; resizable = p_resizable; } }; protected: friend class Main; @@ -149,7 +149,27 @@ public: virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen=0)=0; virtual VideoMode get_video_mode(int p_screen=0) const=0; virtual void get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen=0) const=0; - + +#ifdef EXPERIMENTAL_WM_API + virtual int get_screen_count() const=0; + virtual int get_screen() const=0; + virtual void set_screen(int p_screen)=0; + virtual Point2 get_screen_position(int p_screen=0) const=0; + virtual Size2 get_screen_size(int p_screen=0) const=0; + virtual Point2 get_window_position() const=0; + virtual void set_window_position(const Point2& p_position)=0; + virtual Size2 get_window_size() const=0; + virtual void set_window_size(const Size2 p_size)=0; + virtual void set_fullscreen(bool p_enabled)=0; + virtual bool is_fullscreen() const=0; + virtual void set_resizable(bool p_enabled)=0; + virtual bool is_resizable() const=0; + virtual void set_minimized(bool p_enabled)=0; + virtual bool is_minimized() const=0; + virtual void set_maximized(bool p_enabled)=0; + virtual bool is_maximized() const=0; +#endif + virtual void set_iterations_per_second(int p_ips); virtual int get_iterations_per_second() const; diff --git a/demos/misc/window_management/control.gd b/demos/misc/window_management/control.gd new file mode 100644 index 0000000000..4929b1376c --- /dev/null +++ b/demos/misc/window_management/control.gd @@ -0,0 +1,116 @@ + +extends Control + +func _fixed_process(delta): + + var modetext = "Mode:\n" + + if(OS.is_fullscreen()): + modetext += "Fullscreen\n" + else: + modetext += "Windowed\n" + + if(!OS.is_resizable()): + modetext += "FixedSize\n" + + if(OS.is_minimized()): + modetext += "Minimized\n" + + if(OS.is_maximized()): + modetext += "Maximized\n" + + get_node("Label_Mode").set_text(modetext) + + get_node("Label_Position").set_text( str("Position:\n", OS.get_window_position() ) ) + + get_node("Label_Size").set_text(str("Size:\n", OS.get_window_size() ) ) + + get_node("Label_Screen_Count").set_text( str("Screen_Count:\n", OS.get_screen_count() ) ) + + get_node("Label_Screen_Current").set_text( str("Screen:\n", OS.get_screen() ) ) + + get_node("Label_Screen0_Resolution").set_text( str("Screen0 Resolution:\n", OS.get_screen_size() ) ) + + get_node("Label_Screen0_Position").set_text(str("Screen0 Position:\n",OS.get_screen_position() ) ) + + + if(OS.get_screen_count() > 1): + get_node("Button_Screen0").show() + get_node("Button_Screen1").show() + get_node("Label_Screen1_Resolution").show() + get_node("Label_Screen1_Position").show() + get_node("Label_Screen1_Resolution").set_text( str("Screen1 Resolution:\n", OS.get_screen_size(1) ) ) + get_node("Label_Screen1_Position").set_text( str("Screen1 Position:\n", OS.get_screen_position(1) ) ) + else: + get_node("Button_Screen0").hide() + get_node("Button_Screen1").hide() + get_node("Label_Screen1_Resolution").hide() + get_node("Label_Screen1_Position").hide() + + if( Input.is_action_pressed("ui_right")): + OS.set_screen(1) + + if( Input.is_action_pressed("ui_left")): + OS.set_screen(0) + + if( Input.is_action_pressed("ui_up")): + OS.set_fullscreen(true) + + if( Input.is_action_pressed("ui_down")): + OS.set_fullscreen(false) + + get_node("Button_Fullscreen").set_pressed( OS.is_fullscreen() ) + get_node("Button_FixedSize").set_pressed( !OS.is_resizable() ) + get_node("Button_Minimized").set_pressed( OS.is_minimized() ) + get_node("Button_Maximized").set_pressed( OS.is_maximized() ) + + +func _ready(): + set_fixed_process(true) + + +func _on_Button_MoveTo_pressed(): + OS.set_window_position( Vector2(100,100) ) + + +func _on_Button_Resize_pressed(): + OS.set_window_size( Vector2(1024,768) ) + + +func _on_Button_Screen0_pressed(): + OS.set_screen(0) + + +func _on_Button_Screen1_pressed(): + OS.set_screen(1) + + +func _on_Button_Fullscreen_pressed(): + if(OS.is_fullscreen()): + OS.set_fullscreen(false) + else: + OS.set_fullscreen(true) + + +func _on_Button_FixedSize_pressed(): + if(OS.is_resizable()): + OS.set_resizable(false) + else: + OS.set_resizable(true) + + +func _on_Button_Minimized_pressed(): + if(OS.is_minimized()): + OS.set_minimized(false) + else: + OS.set_minimized(true) + + +func _on_Button_Maximized_pressed(): + if(OS.is_maximized()): + OS.set_maximized(false) + else: + OS.set_maximized(true) + + + diff --git a/demos/misc/window_management/engine.cfg b/demos/misc/window_management/engine.cfg new file mode 100644 index 0000000000..6ce3d51aee --- /dev/null +++ b/demos/misc/window_management/engine.cfg @@ -0,0 +1,12 @@ +[application] + +name="window_management" +main_scene="res://window_management.scn" +icon="icon.png" + +[display] + +fullscreen=false +resizable=true +width=800 +height=600 diff --git a/demos/misc/window_management/icon.png b/demos/misc/window_management/icon.png Binary files differnew file mode 100644 index 0000000000..0c422e37b0 --- /dev/null +++ b/demos/misc/window_management/icon.png diff --git a/demos/misc/window_management/icon.png.flags b/demos/misc/window_management/icon.png.flags new file mode 100644 index 0000000000..5130fd1aab --- /dev/null +++ b/demos/misc/window_management/icon.png.flags @@ -0,0 +1 @@ +gen_mipmaps=false diff --git a/demos/misc/window_management/window_management.scn b/demos/misc/window_management/window_management.scn Binary files differnew file mode 100644 index 0000000000..baf03bdfd1 --- /dev/null +++ b/demos/misc/window_management/window_management.scn diff --git a/main/main.cpp b/main/main.cpp index f0e376a045..27d7d97e85 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -627,7 +627,6 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas } } - GLOBAL_DEF("display/width",video_mode.width); GLOBAL_DEF("display/height",video_mode.height); GLOBAL_DEF("display/fullscreen",video_mode.fullscreen); diff --git a/platform/x11/detect.py b/platform/x11/detect.py index 5171bc972d..6adba510e1 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -38,6 +38,11 @@ def can_build(): if (x11_error): print("xcursor not found.. x11 disabled.") return False + + x11_error=os.system("pkg-config xinerama --modversion > /dev/null ") + if (x11_error): + print("xinerama not found.. x11 disabled.") + return False return True # X11 enabled @@ -48,6 +53,7 @@ def get_opts(): ('use_llvm','Use llvm compiler','no'), ('use_sanitizer','Use llvm compiler sanitize address','no'), ('pulseaudio','Detect & Use pulseaudio','yes'), + ('experimental_wm_api', 'Use experimental window management API','no'), ] def get_flags(): @@ -153,3 +159,7 @@ def configure(env): env.Append( BUILDERS = { 'GLSL120GLES' : env.Builder(action = methods.build_gles2_headers, suffix = 'glsl.h',src_suffix = '.glsl') } ) #env.Append( BUILDERS = { 'HLSL9' : env.Builder(action = methods.build_hlsl_dx9_headers, suffix = 'hlsl.h',src_suffix = '.hlsl') } ) + if(env["experimental_wm_api"]=="yes"): + env.Append(CPPFLAGS=['-DEXPERIMENTAL_WM_API']) + env.ParseConfig('pkg-config xinerama --cflags --libs') + diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index a40af8d2a9..d711cea42e 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -36,6 +36,17 @@ #include "servers/physics/physics_server_sw.h" #include "X11/Xutil.h" +#ifdef EXPERIMENTAL_WM_API +#include "X11/Xatom.h" +#include "X11/extensions/Xinerama.h" +// ICCCM +#define WM_NormalState 1L // window normal state +#define WM_IconicState 3L // window minimized +// EWMH +#define _NET_WM_STATE_REMOVE 0L // remove/unset property +#define _NET_WM_STATE_ADD 1L // add/set property +#define _NET_WM_STATE_TOGGLE 2L // toggle property +#endif #include "main/main.h" @@ -56,7 +67,7 @@ #include <X11/Xatom.h> -#include "os/pc_joystick_map.h" +//#include "os/pc_joystick_map.h" #undef CursorShape @@ -117,10 +128,10 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi if (xim == NULL) { WARN_PRINT("XOpenIM failed"); - xim_style=NULL; + xim_style=0L; } else { ::XIMStyles *xim_styles=NULL; - xim_style=0; + xim_style=0L; char *imvalret=NULL; imvalret = XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL); if (imvalret != NULL || xim_styles == NULL) { @@ -128,7 +139,7 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi } if (xim_styles) { - xim_style = 0; + xim_style = 0L; for (int i=0;i<xim_styles->count_styles;i++) { if (xim_styles->supported_styles[i] == @@ -162,6 +173,7 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi // maybe contextgl wants to be in charge of creating the window //print_line("def videomode "+itos(current_videomode.width)+","+itos(current_videomode.height)); #if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED) + context_gl = memnew( ContextGL_X11( x11_display, x11_window,current_videomode, false ) ); context_gl->initialize(); @@ -179,9 +191,10 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi visual_server =memnew(VisualServerWrapMT(visual_server,get_render_thread_mode()==RENDER_SEPARATE_THREAD)); } +#ifndef EXPERIMENTAL_WM_API // borderless fullscreen window mode if (current_videomode.fullscreen) { - // needed for lxde/openbox, possibly others + // needed for lxde/openbox, possibly others Hints hints; Atom property; hints.flags = 2; @@ -210,7 +223,7 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureNotifyMask, &xev); } - // disable resizeable window + // disable resizable window if (!current_videomode.resizable) { XSizeHints *xsh; xsh = XAllocSizeHints(); @@ -226,7 +239,23 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi xsh->min_height = xwa.height; xsh->max_height = xwa.height; XSetWMNormalHints(x11_display, x11_window, xsh); + XFree(xsh); + } +#else + if (current_videomode.fullscreen) { + minimized = false; + maximized = false; + //set_wm_border(false); + set_wm_fullscreen(true); + } + if (!current_videomode.resizable) { + int screen = get_screen(); + Size2i screen_size = get_screen_size(screen); + set_window_size(screen_size); + set_resizable(false); } +#endif + AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton(); @@ -264,19 +293,20 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi XChangeWindowAttributes(x11_display, x11_window,CWEventMask,&new_attr); - XClassHint* classHint; + XClassHint* classHint; - /* set the titlebar name */ - XStoreName(x11_display, x11_window, "Godot"); + /* set the titlebar name */ + XStoreName(x11_display, x11_window, "Godot"); - /* set the name and class hints for the window manager to use */ - classHint = XAllocClassHint(); - if (classHint) { - classHint->res_name = "Godot"; - classHint->res_class = "Godot"; - } - XSetClassHint(x11_display, x11_window, classHint); - XFree(classHint); + /* set the name and class hints for the window manager to use */ + classHint = XAllocClassHint(); + if (classHint) { + char wmclass[] = "Godot"; + classHint->res_name = wmclass; + classHint->res_class = wmclass; + } + XSetClassHint(x11_display, x11_window, classHint); + XFree(classHint); wm_delete = XInternAtom(x11_display, "WM_DELETE_WINDOW", true); XSetWMProtocols(x11_display, x11_window, &wm_delete, 1); @@ -493,7 +523,6 @@ OS::MouseMode OS_X11::get_mouse_mode() const { int OS_X11::get_mouse_button_state() const { - return last_button_state; } @@ -520,6 +549,378 @@ void OS_X11::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) cons } +#ifdef EXPERIMENTAL_WM_API +#if 0 +// Just now not needed. Can be used for a possible OS.set_border(bool) method +void OS_X11::set_wm_border(bool p_enabled) { + // needed for lxde/openbox, possibly others + Hints hints; + Atom property; + hints.flags = 2; + hints.decorations = p_enabled ? 1L : 0L; + property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True); + XChangeProperty(x11_display, x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); + XMapRaised(x11_display, x11_window); + //XMoveResizeWindow(x11_display, x11_window, 0, 0, 800, 800); +} +#endif + +void OS_X11::set_wm_fullscreen(bool p_enabled) { + // Using EWMH -- Extened Window Manager Hints + XEvent xev; + Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False); + Atom wm_fullscreen = XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", False); + + memset(&xev, 0, sizeof(xev)); + xev.type = ClientMessage; + xev.xclient.window = x11_window; + xev.xclient.message_type = wm_state; + xev.xclient.format = 32; + xev.xclient.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; + xev.xclient.data.l[1] = wm_fullscreen; + xev.xclient.data.l[2] = 0; + + XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); +} + +int OS_X11::get_screen_count() const { + // Using Xinerama Extension + int event_base, error_base; + const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base); + if( !ext_okay ) return 0; + + int count; + XineramaScreenInfo* xsi = XineramaQueryScreens(x11_display, &count); + XFree(xsi); + return count; +} + +int OS_X11::get_screen() const { + int x,y; + Window child; + XTranslateCoordinates( x11_display, x11_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child); + + int count = get_screen_count(); + for(int i=0; i<count; i++) { + Point2i pos = get_screen_position(i); + Size2i size = get_screen_size(i); + if( (x >= pos.x && x <pos.x + size.width) && (y >= pos.y && y < pos.y + size.height) ) + return i; + } + return 0; +} + +void OS_X11::set_screen(int p_screen) { + int count = get_screen_count(); + if(p_screen >= count) return; + + if( current_videomode.fullscreen ) { + Point2i position = get_screen_position(p_screen); + Size2i size = get_screen_size(p_screen); + + XMoveResizeWindow(x11_display, x11_window, position.x, position.y, size.x, size.y); + } + else { + if( p_screen != get_screen() ) { + Point2i position = get_screen_position(p_screen); + XMoveWindow(x11_display, x11_window, position.x, position.y); + } + } +} + +Point2 OS_X11::get_screen_position(int p_screen) const { + // Using Xinerama Extension + int event_base, error_base; + const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base); + if( !ext_okay ) return Point2i(0,0); + + int count; + XineramaScreenInfo* xsi = XineramaQueryScreens(x11_display, &count); + if( p_screen >= count ) return Point2i(0,0); + + Point2i position = Point2i(xsi[p_screen].x_org, xsi[p_screen].y_org); + XFree(xsi); + return position; +} + +Size2 OS_X11::get_screen_size(int p_screen) const { + // Using Xinerama Extension + int event_base, error_base; + const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base); + if( !ext_okay ) return Size2i(0,0); + + int count; + XineramaScreenInfo* xsi = XineramaQueryScreens(x11_display, &count); + if( p_screen >= count ) return Size2i(0,0); + + Size2i size = Point2i(xsi[p_screen].width, xsi[p_screen].height); + XFree(xsi); + return size; +} + + +Point2 OS_X11::get_window_position() const { + int x,y; + Window child; + XTranslateCoordinates( x11_display, x11_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child); + + int screen = get_screen(); + Point2i screen_position = get_screen_position(screen); + + return Point2i(x-screen_position.x, y-screen_position.y); +} + +void OS_X11::set_window_position(const Point2& p_position) { + // Using EWMH -- Extended Window Manager Hints + // to get the size of the decoration + Atom property = XInternAtom(x11_display,"_NET_FRAME_EXTENTS", True); + Atom type; + int format; + unsigned long len; + unsigned long remaining; + unsigned char *data = NULL; + int result; + + result = XGetWindowProperty( + x11_display, + x11_window, + property, + 0, + 32, + False, + AnyPropertyType, + &type, + &format, + &len, + &remaining, + &data + ); + + long left = 0L; + long top = 0L; + + if( result == Success ) { + long *extends = (long *) data; + + left = extends[0]; + top = extends[2]; + + XFree(data); + } + + int screen = get_screen(); + Point2i screen_position = get_screen_position(screen); + + left -= screen_position.x; + top -= screen_position.y; + + XMoveWindow(x11_display,x11_window,p_position.x - left,p_position.y - top); +} + +Size2 OS_X11::get_window_size() const { + XWindowAttributes xwa; + XGetWindowAttributes(x11_display, x11_window, &xwa); + return Size2i(xwa.width, xwa.height); +} + +void OS_X11::set_window_size(const Size2 p_size) { + XResizeWindow(x11_display, x11_window, p_size.x, p_size.y); +} + +void OS_X11::set_fullscreen(bool p_enabled) { + +#if 0 + if(p_enabled && current_videomode.fullscreen) + return; + + if(!current_videomode.resizable) + set_resizable(true); + + if(p_enabled) { + window_data.size = get_window_size(); + window_data.position = get_window_position(); + + int screen = get_screen(); + Size2i size = get_screen_size(screen); + Point2i position = get_screen_position(screen); + + set_wm_border(false); + set_wm_fullscreen(true); + XMoveResizeWindow(x11_display, x11_window, position.x, position.y, size.x, size.y); + + current_videomode.fullscreen = True; + } else { + set_wm_fullscreen(false); + set_wm_border(true); + XMoveResizeWindow(x11_display, x11_window, + window_data.position.x, + window_data.position.y, + window_data.size.width, + window_data.size.height); + + current_videomode.fullscreen = False; + } +#endif + set_wm_fullscreen(p_enabled); + current_videomode.fullscreen = p_enabled; + + visual_server->init(); + +} + +bool OS_X11::is_fullscreen() const { + return current_videomode.fullscreen; +} + +void OS_X11::set_resizable(bool p_enabled) { + XSizeHints *xsh; + xsh = XAllocSizeHints(); + xsh->flags = p_enabled ? 0L : PMinSize | PMaxSize; + if(!p_enabled) { + XWindowAttributes xwa; + XGetWindowAttributes(x11_display,x11_window,&xwa); + xsh->min_width = xwa.width; + xsh->max_width = xwa.width; + xsh->min_height = xwa.height; + xsh->max_height = xwa.height; + } + XSetWMNormalHints(x11_display, x11_window, xsh); + XFree(xsh); + current_videomode.resizable = p_enabled; +} + +bool OS_X11::is_resizable() const { + return current_videomode.resizable; +} + +void OS_X11::set_minimized(bool p_enabled) { + // Using ICCCM -- Inter-Client Communication Conventions Manual + XEvent xev; + Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False); + + memset(&xev, 0, sizeof(xev)); + xev.type = ClientMessage; + xev.xclient.window = x11_window; + xev.xclient.message_type = wm_change; + xev.xclient.format = 32; + xev.xclient.data.l[0] = p_enabled ? WM_IconicState : WM_NormalState; + + XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); + + //XEvent xev; + Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False); + Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False); + + memset(&xev, 0, sizeof(xev)); + xev.type = ClientMessage; + xev.xclient.window = x11_window; + xev.xclient.message_type = wm_state; + xev.xclient.format = 32; + xev.xclient.data.l[0] = _NET_WM_STATE_ADD; + xev.xclient.data.l[1] = wm_hidden; + + XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); +} + +bool OS_X11::is_minimized() const { + // Using ICCCM -- Inter-Client Communication Conventions Manual + Atom property = XInternAtom(x11_display,"WM_STATE", True); + Atom type; + int format; + unsigned long len; + unsigned long remaining; + unsigned char *data = NULL; + + int result = XGetWindowProperty( + x11_display, + x11_window, + property, + 0, + 32, + False, + AnyPropertyType, + &type, + &format, + &len, + &remaining, + &data + ); + + if( result == Success ) { + long *state = (long *) data; + if( state[0] == WM_IconicState ) + return true; + } + return false; +} + +void OS_X11::set_maximized(bool p_enabled) { + // Using EWMH -- Extended Window Manager Hints + XEvent xev; + Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False); + Atom wm_max_horz = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False); + Atom wm_max_vert = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_VERT", False); + + memset(&xev, 0, sizeof(xev)); + xev.type = ClientMessage; + xev.xclient.window = x11_window; + xev.xclient.message_type = wm_state; + xev.xclient.format = 32; + xev.xclient.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; + xev.xclient.data.l[1] = wm_max_horz; + xev.xclient.data.l[2] = wm_max_vert; + + XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); + + maximized = p_enabled; +} + +bool OS_X11::is_maximized() const { + // Using EWMH -- Extended Window Manager Hints + Atom property = XInternAtom(x11_display,"_NET_WM_STATE",False ); + Atom type; + int format; + unsigned long len; + unsigned long remaining; + unsigned char *data = NULL; + + int result = XGetWindowProperty( + x11_display, + x11_window, + property, + 0, + 1024, + False, + XA_ATOM, + &type, + &format, + &len, + &remaining, + &data + ); + + if(result == Success) { + Atom *atoms = (Atom*) data; + Atom wm_max_horz = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False); + Atom wm_max_vert = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_VERT", False); + bool found_wm_max_horz = false; + bool found_wm_max_vert = false; + + for( unsigned int i=0; i < len; i++ ) { + if( atoms[i] == wm_max_horz ) + found_wm_max_horz = true; + if( atoms[i] == wm_max_vert ) + found_wm_max_vert = true; + + if( found_wm_max_horz && found_wm_max_vert ) + return true; + } + XFree(atoms); + } + + return false; +} +#endif InputModifierState OS_X11::get_key_modifier_state(unsigned int p_x11_state) { @@ -594,11 +995,9 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) { KeySym keysym_keycode=0; // keysym used to find a keycode KeySym keysym_unicode=0; // keysym used to find unicode - int nbytes=0; // bytes the string takes - // XLookupString returns keysyms usable as nice scancodes/ char str[256+1]; - nbytes=XLookupString(xkeyevent, str, 256, &keysym_keycode, NULL); + XLookupString(xkeyevent, str, 256, &keysym_keycode, NULL); // Meanwhile, XLookupString returns keysyms useful for unicode. @@ -695,7 +1094,7 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) { ::Time tresh=ABS(peek_event.xkey.time-xkeyevent->time); if (peek_event.type == KeyPress && tresh<5 ) { KeySym rk; - nbytes=XLookupString((XKeyEvent*)&peek_event, str, 256, &rk, NULL); + XLookupString((XKeyEvent*)&peek_event, str, 256, &rk, NULL); if (rk==keysym_keycode) { XEvent event; XNextEvent(x11_display, &event); //erase next event @@ -759,13 +1158,16 @@ void OS_X11::process_xevents() { break; case VisibilityNotify: { - XVisibilityEvent * visibility = (XVisibilityEvent *)&event; minimized = (visibility->state == VisibilityFullyObscured); - } break; - case FocusIn: + case FocusIn: + minimized = false; + if(current_videomode.fullscreen) { + set_wm_fullscreen(true); + visual_server->init(); + } main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN); if (mouse_mode==MOUSE_MODE_CAPTURED) { XGrabPointer(x11_display, x11_window, True, @@ -776,6 +1178,11 @@ void OS_X11::process_xevents() { break; case FocusOut: + if(current_videomode.fullscreen) { + set_wm_fullscreen(false); + set_minimized(true); + visual_server->init(); + } main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT); if (mouse_mode==MOUSE_MODE_CAPTURED) { //dear X11, I try, I really try, but you never work, you do whathever you want. @@ -856,7 +1263,7 @@ void OS_X11::process_xevents() { if (mouse_mode==MOUSE_MODE_CAPTURED) { #if 1 - Vector2 c = Point2i(current_videomode.width/2,current_videomode.height/2); + //Vector2 c = Point2i(current_videomode.width/2,current_videomode.height/2); if (pos==Point2i(current_videomode.width/2,current_videomode.height/2)) { //this sucks, it's a hack, etc and is a little inaccurate, etc. //but nothing I can do, X11 sucks. @@ -865,9 +1272,9 @@ void OS_X11::process_xevents() { break; } - Point2i ncenter = pos; + Point2i new_center = pos; pos = last_mouse_pos + ( pos-center ); - center=ncenter; + center=new_center; do_mouse_warp=true; #else //Dear X11, thanks for making my life miserable @@ -1354,6 +1761,7 @@ void OS_X11::process_joysticks() { #endif }; + void OS_X11::set_cursor_shape(CursorShape p_shape) { ERR_FAIL_INDEX(p_shape,CURSOR_MAX); @@ -1466,8 +1874,6 @@ OS_X11::OS_X11() { #endif minimized = false; - xim_style=NULL; + xim_style=0L; mouse_mode=MOUSE_MODE_VISIBLE; - - }; diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index dd2476ec1b..b47c5db069 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -159,6 +159,11 @@ class OS_X11 : public OS_Unix { int joystick_count; Joystick joysticks[JOYSTICKS_MAX]; +#ifdef EXPERIMENTAL_WM_API + bool maximized; + //void set_wm_border(bool p_enabled); + void set_wm_fullscreen(bool p_enabled); +#endif protected: @@ -166,8 +171,8 @@ protected: virtual const char * get_video_driver_name(int p_driver) const; virtual VideoMode get_default_video_mode() const; - virtual int get_audio_driver_count() const; - virtual const char * get_audio_driver_name(int p_driver) const; + virtual int get_audio_driver_count() const; + virtual const char * get_audio_driver_name(int p_driver) const; virtual void initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver); virtual void finalize(); @@ -178,6 +183,7 @@ protected: void process_joysticks(); void close_joystick(int p_id = -1); + public: virtual String get_name(); @@ -213,6 +219,25 @@ public: virtual VideoMode get_video_mode(int p_screen=0) const; virtual void get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen=0) const; +#ifdef EXPERIMENTAL_WM_API + virtual int get_screen_count() const; + virtual int get_screen() const; + virtual void set_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 Point2 get_window_position() const; + virtual void set_window_position(const Point2& p_position); + virtual Size2 get_window_size() const; + virtual void set_window_size(const Size2 p_size); + virtual void set_fullscreen(bool p_enabled); + virtual bool is_fullscreen() const; + virtual void set_resizable(bool p_enabled); + virtual bool is_resizable() const; + virtual void set_minimized(bool p_enabled); + virtual bool is_minimized() const; + virtual void set_maximized(bool p_enabled); + virtual bool is_maximized() const; +#endif virtual void move_window_to_foreground(); void run(); |