1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291 |
- /*************************************************************************/
- /* os_x11.cpp */
- /*************************************************************************/
- /* This file is part of: */
- /* GODOT ENGINE */
- /* http://www.godotengine.org */
- /*************************************************************************/
- /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
- /* */
- /* Permission is hereby granted, free of charge, to any person obtaining */
- /* a copy of this software and associated documentation files (the */
- /* "Software"), to deal in the Software without restriction, including */
- /* without limitation the rights to use, copy, modify, merge, publish, */
- /* distribute, sublicense, and/or sell copies of the Software, and to */
- /* permit persons to whom the Software is furnished to do so, subject to */
- /* the following conditions: */
- /* */
- /* The above copyright notice and this permission notice shall be */
- /* included in all copies or substantial portions of the Software. */
- /* */
- /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
- /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
- /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
- /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
- /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
- /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
- /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
- /*************************************************************************/
- #include "servers/visual/visual_server_raster.h"
- #include "drivers/gles2/rasterizer_gles2.h"
- #include "drivers/gles1/rasterizer_gles1.h"
- #include "os_x11.h"
- #include "key_mapping_x11.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include "print_string.h"
- #include "servers/physics/physics_server_sw.h"
- #include "X11/Xutil.h"
- #include "main/main.h"
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <linux/joystick.h>
- //stupid linux.h
- #ifdef KEY_TAB
- #undef KEY_TAB
- #endif
- #include <X11/Xatom.h>
- #include "os/pc_joystick_map.h"
- #undef CursorShape
- int OS_X11::get_video_driver_count() const {
- return 2;
- }
- const char * OS_X11::get_video_driver_name(int p_driver) const {
- return p_driver==0?"GLES2":"GLES1";
- }
- OS::VideoMode OS_X11::get_default_video_mode() const {
- return OS::VideoMode(800,600,false);
- }
- void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
- last_button_state=0;
- dpad_last[0]=0;
- dpad_last[1]=0;
- xmbstring=NULL;
- event_id=0;
- x11_window=0;
- last_click_ms=0;
- args=OS::get_singleton()->get_cmdline_args();
- current_videomode=p_desired;
- main_loop=NULL;
- last_timestamp=0;
- last_mouse_pos_valid=false;
- last_keyrelease_time=0;
- if (get_render_thread_mode()==RENDER_SEPARATE_THREAD) {
- XInitThreads();
- }
-
- /** XLIB INITIALIZATION **/
- x11_display = XOpenDisplay(NULL);
-
- char * modifiers = XSetLocaleModifiers ("@im=none");
- ERR_FAIL_COND( modifiers == NULL );
-
- xim = XOpenIM (x11_display, NULL, NULL, NULL);
-
- if (xim == NULL) {
- WARN_PRINT("XOpenIM failed");
- xim_style=NULL;
- } else {
- ::XIMStyles *xim_styles=NULL;
- xim_style=0;
- char *imvalret=NULL;
- imvalret = XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL);
- if (imvalret != NULL || xim_styles == NULL) {
- fprintf (stderr, "Input method doesn't support any styles\n");
- }
-
- if (xim_styles) {
- xim_style = 0;
- for (int i=0;i<xim_styles->count_styles;i++) {
-
- if (xim_styles->supported_styles[i] ==
- (XIMPreeditNothing | XIMStatusNothing)) {
-
- xim_style = xim_styles->supported_styles[i];
- break;
- }
- }
-
- XFree (xim_styles);
- }
- }
- /*
- char* windowid = getenv("GODOT_WINDOWID");
- if (windowid) {
- //freopen("/home/punto/stdout", "w", stdout);
- //reopen("/home/punto/stderr", "w", stderr);
- x11_window = atol(windowid);
- XWindowAttributes xwa;
- XGetWindowAttributes(x11_display,x11_window,&xwa);
- current_videomode.width = xwa.width;
- current_videomode.height = xwa.height;
- };
- */
- // 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();
- if (p_video_driver == 0) {
- rasterizer = memnew( RasterizerGLES2 );
- } else {
- rasterizer = memnew( RasterizerGLES1 );
- };
- #endif
- visual_server = memnew( VisualServerRaster(rasterizer) );
- if (get_render_thread_mode()!=RENDER_THREAD_UNSAFE) {
- visual_server =memnew(VisualServerWrapMT(visual_server,get_render_thread_mode()==RENDER_SEPARATE_THREAD));
- }
- AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
- if (AudioDriverManagerSW::get_driver(p_audio_driver)->init()!=OK) {
- ERR_PRINT("Initializing audio failed.");
- }
- sample_manager = memnew( SampleManagerMallocSW );
- audio_server = memnew( AudioServerSW(sample_manager) );
- audio_server->init();
- spatial_sound_server = memnew( SpatialSoundServerSW );
- spatial_sound_server->init();
- spatial_sound_2d_server = memnew( SpatialSound2DServerSW );
- spatial_sound_2d_server->init();
-
- ERR_FAIL_COND(!visual_server);
- ERR_FAIL_COND(x11_window==0);
- XSetWindowAttributes new_attr;
- new_attr.event_mask=KeyPressMask | KeyReleaseMask | ButtonPressMask |
- ButtonReleaseMask | EnterWindowMask |
- LeaveWindowMask | PointerMotionMask |
- Button1MotionMask |
- Button2MotionMask | Button3MotionMask |
- Button4MotionMask | Button5MotionMask |
- ButtonMotionMask | KeymapStateMask |
- ExposureMask | VisibilityChangeMask |
- StructureNotifyMask |
- SubstructureNotifyMask | SubstructureRedirectMask |
- FocusChangeMask | PropertyChangeMask |
- ColormapChangeMask | OwnerGrabButtonMask;
- XChangeWindowAttributes(x11_display, x11_window,CWEventMask,&new_attr);
-
- wm_delete = XInternAtom(x11_display, "WM_DELETE_WINDOW", true);
- XSetWMProtocols(x11_display, x11_window, &wm_delete, 1);
-
- if (xim && xim_style) {
-
- xic = XCreateIC (xim,XNInputStyle, xim_style,XNClientWindow,x11_window,XNFocusWindow, x11_window, (char*)NULL);
- } else {
-
- xic=NULL;
- WARN_PRINT("XCreateIC couldn't create xic");
- }
- XcursorSetTheme(x11_display,"default");
- cursor_size = XcursorGetDefaultSize(x11_display);
- cursor_theme = XcursorGetTheme(x11_display);
- if (!cursor_theme) {
- print_line("not found theme");
- cursor_theme="default";
- }
- for(int i=0;i<CURSOR_MAX;i++) {
- cursors[i]=None;
- }
- current_cursor=CURSOR_ARROW;
- if (cursor_theme) {
- //print_line("cursor theme: "+String(cursor_theme));
- for(int i=0;i<CURSOR_MAX;i++) {
- static const char *cursor_file[]={
- "left_ptr",
- "xterm",
- "hand2",
- "cross",
- "watch",
- "left_ptr_watch",
- "fleur",
- "hand1",
- "X_cursor",
- "sb_v_double_arrow",
- "sb_h_double_arrow",
- "size_bdiag",
- "size_fdiag",
- "hand1",
- "sb_v_double_arrow",
- "sb_h_double_arrow",
- "question_arrow"
- };
- XcursorImage *img = XcursorLibraryLoadImage(cursor_file[i],cursor_theme,cursor_size);
- if (img) {
- cursors[i]=XcursorImageLoadCursor(x11_display,img);
- //print_line("found cursor: "+String(cursor_file[i])+" id "+itos(cursors[i]));
- } else {
- if (OS::is_stdout_verbose())
- print_line("failed cursor: "+String(cursor_file[i]));
- }
- }
- }
- {
- Pixmap cursormask;
- XGCValues xgc;
- GC gc;
- XColor col;
- Cursor cursor;
- cursormask = XCreatePixmap(x11_display, RootWindow(x11_display,DefaultScreen(x11_display)), 1, 1, 1);
- xgc.function = GXclear;
- gc = XCreateGC(x11_display, cursormask, GCFunction, &xgc);
- XFillRectangle(x11_display, cursormask, gc, 0, 0, 1, 1);
- col.pixel = 0;
- col.red = 0;
- col.flags = 4;
- cursor = XCreatePixmapCursor(x11_display,
- cursormask, cursormask,
- &col, &col, 0, 0);
- XFreePixmap(x11_display, cursormask);
- XFreeGC(x11_display, gc);
- if (cursor == None)
- {
- ERR_PRINT("FAILED CREATING CURSOR");
- }
- null_cursor=cursor;
- }
- set_cursor_shape(CURSOR_BUSY);
- visual_server->init();
- //
- physics_server = memnew( PhysicsServerSW );
- physics_server->init();
- physics_2d_server = memnew( Physics2DServerSW );
- physics_2d_server->init();
- input = memnew( InputDefault );
- probe_joystick();
- _ensure_data_dir();
- net_wm_icon = XInternAtom(x11_display, "_NET_WM_ICON", False);
- //printf("got map notify\n");
-
- }
- void OS_X11::finalize() {
- if(main_loop)
- memdelete(main_loop);
- main_loop=NULL;
- spatial_sound_server->finish();
- memdelete(spatial_sound_server);
- spatial_sound_2d_server->finish();
- memdelete(spatial_sound_2d_server);
- //if (debugger_connection_console) {
- // memdelete(debugger_connection_console);
- //}
- audio_server->finish();
- memdelete(audio_server);
- memdelete(sample_manager);
- visual_server->finish();
- memdelete(visual_server);
- memdelete(rasterizer);
-
- physics_server->finish();
- memdelete(physics_server);
- physics_2d_server->finish();
- memdelete(physics_2d_server);
- memdelete(input);
- #if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
- memdelete(context_gl);
- #endif
-
- XCloseDisplay(x11_display);
- if (xmbstring)
- memfree(xmbstring);
-
- args.clear();
- }
- void OS_X11::set_mouse_mode(MouseMode p_mode) {
- print_line("WUTF "+itos(p_mode)+" old "+itos(mouse_mode));
- if (p_mode==mouse_mode)
- return;
- if (mouse_mode==MOUSE_MODE_CAPTURED)
- XUngrabPointer(x11_display, CurrentTime);
- if (mouse_mode!=MOUSE_MODE_VISIBLE && p_mode==MOUSE_MODE_VISIBLE)
- XUndefineCursor(x11_display,x11_window);
- if (p_mode!=MOUSE_MODE_VISIBLE && mouse_mode==MOUSE_MODE_VISIBLE) {
- XDefineCursor(x11_display,x11_window,null_cursor);
- }
- mouse_mode=p_mode;
- if (mouse_mode==MOUSE_MODE_CAPTURED) {
- if (XGrabPointer(x11_display, x11_window, True,
- ButtonPressMask | ButtonReleaseMask |
- PointerMotionMask, GrabModeAsync, GrabModeAsync,
- x11_window, None, CurrentTime) !=
- GrabSuccess) {
- ERR_PRINT("NO GRAB");
- }
- center.x = current_videomode.width/2;
- center.y = current_videomode.height/2;
- XWarpPointer(x11_display, None, x11_window,
- 0,0,0,0, (int)center.x, (int)center.y);
- }
- }
- OS::MouseMode OS_X11::get_mouse_mode() const {
- return mouse_mode;
- }
- int OS_X11::get_mouse_button_state() const {
- return last_button_state;
- }
- Point2 OS_X11::get_mouse_pos() const {
- return last_mouse_pos;
- }
- void OS_X11::set_window_title(const String& p_title) {
- XStoreName(x11_display,x11_window,p_title.utf8().get_data());
- }
- void OS_X11::set_video_mode(const VideoMode& p_video_mode,int p_screen) {
- }
- OS::VideoMode OS_X11::get_video_mode(int p_screen) const {
- return current_videomode;
- }
- void OS_X11::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) const {
- }
- InputModifierState OS_X11::get_key_modifier_state(unsigned int p_x11_state) {
-
- InputModifierState state;
-
- state.shift = (p_x11_state&ShiftMask);
- state.control = (p_x11_state&ControlMask);
- state.alt = (p_x11_state&Mod1Mask /*|| p_x11_state&Mod5Mask*/); //altgr should not count as alt
- state.meta = (p_x11_state&Mod4Mask);
-
- return state;
- }
- unsigned int OS_X11::get_mouse_button_state(unsigned int p_x11_state) {
- unsigned int state=0;
-
- if (p_x11_state&Button1Mask) {
-
- state|=1<<0;
- }
- if (p_x11_state&Button3Mask) {
-
- state|=1<<1;
- }
- if (p_x11_state&Button2Mask) {
-
- state|=1<<2;
- }
-
- if (p_x11_state&Button4Mask) {
-
- state|=1<<3;
- }
- if (p_x11_state&Button5Mask) {
-
- state|=1<<4;
- }
- last_button_state=state;
- return state;
- }
-
- void OS_X11::handle_key_event(XKeyEvent *p_event) {
-
- // X11 functions don't know what const is
- XKeyEvent *xkeyevent = p_event;
-
- // This code was pretty difficult to write.
- // The docs stink and every toolkit seems to
- // do it in a different way.
-
- /* Phase 1, obtain a proper keysym */
-
- // This was also very difficult to figure out.
- // You'd expect you could just use Keysym provided by
- // XKeycodeToKeysym to obtain internationalized
- // input.. WRONG!!
- // you must use XLookupString (???) which not only wastes
- // cycles generating an unnecesary string, but also
- // still works in half the cases. (won't handle deadkeys)
- // For more complex input methods (deadkeys and more advanced)
- // you have to use XmbLookupString (??).
- // So.. then you have to chosse which of both results
- // you want to keep.
- // This is a real bizarreness and cpu waster.
-
- 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);
-
- // Meanwhile, XLookupString returns keysyms useful for unicode.
-
-
- if (!xmbstring) {
- // keep a temporary buffer for the string
- xmbstring=(char*)memalloc(sizeof(char)*8);
- xmblen=8;
- }
-
- if (xkeyevent->type == KeyPress && xic) {
- Status status;
- do {
-
- int mnbytes = XmbLookupString (xic, xkeyevent, xmbstring, xmblen - 1, &keysym_unicode, &status);
- xmbstring[mnbytes] = '\0';
- if (status == XBufferOverflow) {
- xmblen = mnbytes + 1;
- xmbstring = (char*)memrealloc (xmbstring, xmblen);
- }
- } while (status == XBufferOverflow);
- }
-
- /* Phase 2, obtain a pigui keycode from the keysym */
-
- // KeyMappingX11 just translated the X11 keysym to a PIGUI
- // keysym, so it works in all platforms the same.
- unsigned int keycode = KeyMappingX11::get_keycode(keysym_keycode);
-
- /* Phase 3, obtain an unicode character from the keysym */
-
- // KeyMappingX11 also translates keysym to unicode.
- // It does a binary search on a table to translate
- // most properly.
- //print_line("keysym_unicode: "+rtos(keysym_unicode));
- unsigned int unicode = keysym_unicode>0? KeyMappingX11::get_unicode_from_keysym(keysym_unicode):0;
-
- /* Phase 4, determine if event must be filtered */
-
- // This seems to be a side-effect of using XIM.
- // XEventFilter looks like a core X11 funciton,
- // but it's actually just used to see if we must
- // ignore a deadkey, or events XIM determines
- // must not reach the actual gui.
- // Guess it was a design problem of the extension
- bool keypress = xkeyevent->type == KeyPress;
-
- if (xkeyevent->type == KeyPress && xic) {
- if (XFilterEvent((XEvent*)xkeyevent, x11_window))
- return;
- }
-
- if (keycode==0 && unicode==0)
- return;
- /* Phase 5, determine modifier mask */
-
- // No problems here, except I had no way to
- // know Mod1 was ALT and Mod4 was META (applekey/winkey)
- // just tried Mods until i found them.
- //print_line("mod1: "+itos(xkeyevent->state&Mod1Mask)+" mod 5: "+itos(xkeyevent->state&Mod5Mask));
-
- InputModifierState state = get_key_modifier_state(xkeyevent->state);
-
- /* Phase 6, determine echo character */
-
- // Echo characters in X11 are a keyrelease and a keypress
- // one after the other with the (almot) same timestamp.
- // To detect them, i use XPeekEvent and check that their
- // difference in time is below a treshold.
-
- bool echo=false;
-
- if (xkeyevent->type == KeyPress) {
-
- // saved the time of the last keyrelease to see
- // if it's the same as this keypress.
- if (xkeyevent->time==last_keyrelease_time)
- echo=true;
- } else {
-
- // make sure there are events pending,
- // so this call won't block.
- if (XPending(x11_display)>0) {
- XEvent peek_event;
- XPeekEvent(x11_display, &peek_event);
-
- // I'm using a treshold of 5 msecs,
- // since sometimes there seems to be a little
- // jitter. I'm still not convinced that all this approach
- // is correct, but the xorg developers are
- // not very helpful today.
-
- ::Time tresh=ABS(peek_event.xkey.time-xkeyevent->time);
- if (peek_event.type == KeyPress && tresh<5 )
- echo=true;
-
- // use the time from peek_event so it always works
- last_keyrelease_time=peek_event.xkey.time;
- } else {
- last_keyrelease_time=xkeyevent->time;
- }
-
- // save the time to check for echo when keypress happens
-
- }
-
-
- /* Phase 7, send event to Window */
-
- InputEvent event;
- event.ID=++event_id;
- event.type = InputEvent::KEY;
- event.device=0;
- event.key.mod=state;
- event.key.pressed=keypress;
- if (keycode>='a' && keycode<='z')
- keycode-='a'-'A';
- event.key.scancode=keycode;
- event.key.unicode=unicode;
- event.key.echo=echo;
- if (event.key.scancode==KEY_BACKTAB) {
- //make it consistent accross platforms.
- event.key.scancode=KEY_TAB;
- event.key.mod.shift=true;
- }
- //printf("key: %x\n",event.key.scancode);
- input->parse_input_event( event);
-
- }
- void OS_X11::process_xevents() {
- //printf("checking events %i\n", XPending(x11_display));
- bool do_mouse_warp=false;
- while (XPending(x11_display) > 0) {
- XEvent event;
- XNextEvent(x11_display, &event);
- switch (event.type) {
- case Expose:
- Main::force_redraw();
- break;
- case NoExpose:
- minimized = true;
- break;
- case VisibilityNotify: {
- XVisibilityEvent * visibility = (XVisibilityEvent *)&event;
- minimized = (visibility->state == VisibilityFullyObscured);
- } break;
- case FocusIn:
- main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
- if (mouse_mode==MOUSE_MODE_CAPTURED) {
- XGrabPointer(x11_display, x11_window, True,
- ButtonPressMask | ButtonReleaseMask |
- PointerMotionMask, GrabModeAsync, GrabModeAsync,
- x11_window, None, CurrentTime);
- }
- break;
- case FocusOut:
- 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.
- XUngrabPointer(x11_display, CurrentTime);
- }
- break;
- case ConfigureNotify:
- /* call resizeGLScene only if our window-size changed */
-
- if ((event.xconfigure.width == current_videomode.width) &&
- (event.xconfigure.height == current_videomode.height))
- break;
-
- current_videomode.width=event.xconfigure.width;
- current_videomode.height=event.xconfigure.height;
- break;
- case ButtonPress:
- case ButtonRelease: {
-
- /* exit in case of a mouse button press */
- last_timestamp=event.xbutton.time;
- if (mouse_mode==MOUSE_MODE_CAPTURED) {
- event.xbutton.x=last_mouse_pos.x;
- event.xbutton.y=last_mouse_pos.y;
- }
-
- InputEvent mouse_event;
- mouse_event.ID=++event_id;
- mouse_event.type = InputEvent::MOUSE_BUTTON;
- mouse_event.device=0;
- mouse_event.mouse_button.mod = get_key_modifier_state(event.xbutton.state);
- mouse_event.mouse_button.button_mask = get_mouse_button_state(event.xbutton.state);
- mouse_event.mouse_button.x=event.xbutton.x;
- mouse_event.mouse_button.y=event.xbutton.y;
- mouse_event.mouse_button.global_x=event.xbutton.x;
- mouse_event.mouse_button.global_y=event.xbutton.y;
- mouse_event.mouse_button.button_index=event.xbutton.button;
- if (mouse_event.mouse_button.button_index==2)
- mouse_event.mouse_button.button_index=3;
- else if (mouse_event.mouse_button.button_index==3)
- mouse_event.mouse_button.button_index=2;
-
- mouse_event.mouse_button.pressed=(event.type==ButtonPress);
- if (event.type==ButtonPress && event.xbutton.button==1) {
-
- uint64_t diff = get_ticks_usec()/1000 - last_click_ms;
- if (diff<400 && Point2(last_click_pos).distance_to(Point2(event.xbutton.x,event.xbutton.y))<5) {
-
- last_click_ms=0;
- last_click_pos = Point2(-100,-100);
- mouse_event.mouse_button.doubleclick=true;
- mouse_event.ID=++event_id;
-
- } else {
- last_click_ms+=diff;
- last_click_pos = Point2(event.xbutton.x,event.xbutton.y);
- }
- }
- input->parse_input_event( mouse_event);
-
- } break;
- case MotionNotify: {
-
-
- last_timestamp=event.xmotion.time;
-
- // Motion is also simple.
- // A little hack is in order
- // to be able to send relative motion events.
-
- Point2i pos( event.xmotion.x, event.xmotion.y );
- if (mouse_mode==MOUSE_MODE_CAPTURED) {
- #if 1
- 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.
- center=pos;
- break;
- }
- Point2i ncenter = pos;
- pos = last_mouse_pos + ( pos-center );
- center=ncenter;
- do_mouse_warp=true;
- #else
- //Dear X11, thanks for making my life miserable
- center.x = current_videomode.width/2;
- center.y = current_videomode.height/2;
- pos = last_mouse_pos + ( pos-center );
- if (pos==last_mouse_pos)
- break;
- XWarpPointer(x11_display, None, x11_window,
- 0,0,0,0, (int)center.x, (int)center.y);
- #endif
- }
-
- if (!last_mouse_pos_valid) {
-
- last_mouse_pos=pos;
- last_mouse_pos_valid=true;
- }
-
- Point2i rel = pos - last_mouse_pos;
-
- InputEvent motion_event;
- motion_event.ID=++event_id;
- motion_event.type=InputEvent::MOUSE_MOTION;
- motion_event.device=0;
-
- motion_event.mouse_motion.mod = get_key_modifier_state(event.xmotion.state);
- motion_event.mouse_motion.button_mask = get_mouse_button_state(event.xmotion.state);
- motion_event.mouse_motion.x=pos.x;
- motion_event.mouse_motion.y=pos.y;
- input->set_mouse_pos(pos);
- motion_event.mouse_motion.global_x=pos.x;
- motion_event.mouse_motion.global_y=pos.y;
- motion_event.mouse_motion.speed_x=input->get_mouse_speed().x;
- motion_event.mouse_motion.speed_y=input->get_mouse_speed().y;
- motion_event.mouse_motion.relative_x=rel.x;
- motion_event.mouse_motion.relative_y=rel.y;
-
- last_mouse_pos=pos;
-
- input->parse_input_event( motion_event);
-
- } break;
- case KeyPress:
- case KeyRelease: {
- last_timestamp=event.xkey.time;
-
- // key event is a little complex, so
- // it will be handled in it's own function.
- handle_key_event( (XKeyEvent*)&event );
- } break;
- case SelectionRequest: {
- XSelectionRequestEvent *req;
- XEvent e, respond;
- e = event;
- req=&(e.xselectionrequest);
- if (req->target == XA_STRING || req->target == XInternAtom(x11_display, "COMPOUND_TEXT", 0) ||
- req->target == XInternAtom(x11_display, "UTF8_STRING", 0))
- {
- CharString clip = OS::get_clipboard().utf8();
- XChangeProperty (x11_display,
- req->requestor,
- req->property,
- req->target,
- 8,
- PropModeReplace,
- (unsigned char*)clip.get_data(),
- clip.length());
- respond.xselection.property=req->property;
- } else if (req->target == XInternAtom(x11_display, "TARGETS", 0)) {
- Atom data[2];
- data[0] = XInternAtom(x11_display, "UTF8_STRING", 0);
- data[1] = XA_STRING;
- XChangeProperty (x11_display, req->requestor, req->property, req->target,
- 8, PropModeReplace, (unsigned char *) &data,
- sizeof (data));
- respond.xselection.property=req->property;
- } else {
- printf ("No String %x\n",
- (int)req->target);
- respond.xselection.property= None;
- }
- respond.xselection.type= SelectionNotify;
- respond.xselection.display= req->display;
- respond.xselection.requestor= req->requestor;
- respond.xselection.selection=req->selection;
- respond.xselection.target= req->target;
- respond.xselection.time = req->time;
- XSendEvent (x11_display, req->requestor,0,0,&respond);
- XFlush (x11_display);
- } break;
- case ClientMessage:
-
- if ((unsigned int)event.xclient.data.l[0]==(unsigned int)wm_delete)
- main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
- break;
- default:
- break;
- }
- }
-
- XFlush(x11_display);
- if (do_mouse_warp) {
- XWarpPointer(x11_display, None, x11_window,
- 0,0,0,0, (int)current_videomode.width/2, (int)current_videomode.height/2);
- }
- }
- MainLoop *OS_X11::get_main_loop() const {
- return main_loop;
- }
- void OS_X11::delete_main_loop() {
- if (main_loop)
- memdelete(main_loop);
- main_loop=NULL;
- }
- void OS_X11::set_main_loop( MainLoop * p_main_loop ) {
- main_loop=p_main_loop;
- input->set_main_loop(p_main_loop);
- }
- bool OS_X11::can_draw() const {
- return !minimized;
- };
- void OS_X11::set_clipboard(const String& p_text) {
- OS::set_clipboard(p_text);
- XSetSelectionOwner(x11_display, XA_PRIMARY, x11_window, CurrentTime);
- XSetSelectionOwner(x11_display, XInternAtom(x11_display, "CLIPBOARD", 0), x11_window, CurrentTime);
- };
- static String _get_clipboard(Atom p_source, Window x11_window, ::Display* x11_display, String p_internal_clipboard) {
- String ret;
- Atom type;
- Atom selection = XA_PRIMARY;
- int format, result;
- unsigned long len, bytes_left, dummy;
- unsigned char *data;
- Window Sown = XGetSelectionOwner (x11_display, p_source);
- if (Sown == x11_window) {
- printf("returning internal clipboard\n");
- return p_internal_clipboard;
- };
- if (Sown != None) {
- XConvertSelection (x11_display, p_source, XA_STRING, selection,
- x11_window, CurrentTime);
- XFlush (x11_display);
- while (true) {
- XEvent event;
- XNextEvent(x11_display, &event);
- if (event.type == SelectionNotify && event.xselection.requestor == x11_window) {
- break;
- };
- };
- //
- // Do not get any data, see how much data is there
- //
- XGetWindowProperty (x11_display, x11_window,
- selection, // Tricky..
- 0, 0, // offset - len
- 0, // Delete 0==FALSE
- AnyPropertyType, //flag
- &type, // return type
- &format, // return format
- &len, &bytes_left, //that
- &data);
- // DATA is There
- if (bytes_left > 0)
- {
- result = XGetWindowProperty (x11_display, x11_window,
- selection, 0,bytes_left,0,
- AnyPropertyType, &type,&format,
- &len, &dummy, &data);
- if (result == Success) {
- ret.parse_utf8((const char*)data);
- } else printf ("FAIL\n");
- XFree (data);
- }
- }
- return ret;
- };
- String OS_X11::get_clipboard() const {
- String ret;
- ret = _get_clipboard(XInternAtom(x11_display, "CLIPBOARD", 0), x11_window, x11_display, OS::get_clipboard());
- if (ret == "") {
- ret = _get_clipboard(XA_PRIMARY, x11_window, x11_display, OS::get_clipboard());
- };
- return ret;
- };
- String OS_X11::get_name() {
- return "X11";
- }
- void OS_X11::close_joystick(int p_id) {
- if (p_id == -1) {
- for (int i=0; i<JOYSTICKS_MAX; i++) {
- close_joystick(i);
- };
- return;
- };
- if (joysticks[p_id].fd != -1) {
- close(joysticks[p_id].fd);
- joysticks[p_id].fd = -1;
- };
- };
- void OS_X11::probe_joystick(int p_id) {
- if (p_id == -1) {
- for (int i=0; i<JOYSTICKS_MAX; i++) {
- probe_joystick(i);
- };
- return;
- };
- close_joystick(p_id);
- const char *joy_names[] = {
- "/dev/input/js%d",
- "/dev/js%d",
- NULL
- };
- int i=0;
- while(joy_names[i]) {
- char fname[64];
- sprintf(fname, joy_names[i], p_id);
- int fd = open(fname, O_RDONLY);
- if (fd != -1) {
- fcntl( fd, F_SETFL, O_NONBLOCK );
- joysticks[p_id] = Joystick(); // this will reset the axis array
- joysticks[p_id].fd = fd;
- break; // don't try the next name
- };
- ++i;
- };
- };
- void OS_X11::move_window_to_foreground() {
- XRaiseWindow(x11_display,x11_window);
- }
- void OS_X11::process_joysticks() {
- int bytes;
- js_event events[32];
- InputEvent ievent;
- for (int i=0; i<JOYSTICKS_MAX; i++) {
- if (joysticks[i].fd == -1)
- continue;
- ievent.device = i;
- while ( (bytes = read(joysticks[i].fd, &events, sizeof(events))) > 0) {
- int ev_count = bytes / sizeof(js_event);
- for (int j=0; j<ev_count; j++) {
- js_event& event = events[j];
- //printf("got event on joystick %i, %i, %i, %i, %i\n", i, joysticks[i].fd, event.type, event.number, event.value);
- if (event.type & JS_EVENT_INIT)
- continue;
- switch (event.type & ~JS_EVENT_INIT) {
- case JS_EVENT_AXIS:
- if (joysticks[i].last_axis[event.number] != event.value) {
- if (event.number==5 || event.number==6) {
- int axis=event.number-5;
- int val = event.value;
- if (val<0)
- val=-1;
- if (val>0)
- val=+1;
- InputEvent ev;
- ev.type = InputEvent::JOYSTICK_BUTTON;
- ev.ID = ++event_id;
- if (val!=dpad_last[axis]) {
- int prev_val = dpad_last[axis];
- if (prev_val!=0) {
- ev.joy_button.pressed=false;
- ev.joy_button.pressure=0.0;
- if (event.number==5)
- ev.joy_button.button_index=JOY_DPAD_LEFT+(prev_val+1)/2;
- if (event.number==6)
- ev.joy_button.button_index=JOY_DPAD_UP+(prev_val+1)/2;
- input->parse_input_event( ev );
- }
- }
- if (val!=0) {
- ev.joy_button.pressed=true;
- ev.joy_button.pressure=1.0;
- if (event.number==5)
- ev.joy_button.button_index=JOY_DPAD_LEFT+(val+1)/2;
- if (event.number==6)
- ev.joy_button.button_index=JOY_DPAD_UP+(val+1)/2;
- input->parse_input_event( ev );
- }
- dpad_last[axis]=val;
- }
- //print_line("ev: "+itos(event.number)+" val: "+ rtos((float)event.value / (float)MAX_JOY_AXIS));
- if (event.number >= JOY_AXIS_MAX)
- break;
- //ERR_FAIL_COND(event.number >= JOY_AXIS_MAX);
- ievent.type = InputEvent::JOYSTICK_MOTION;
- ievent.ID = ++event_id;
- ievent.joy_motion.axis = _pc_joystick_get_native_axis(event.number);
- ievent.joy_motion.axis_value = (float)event.value / (float)MAX_JOY_AXIS;
- joysticks[i].last_axis[event.number] = event.value;
- input->parse_input_event( ievent );
- };
- break;
- case JS_EVENT_BUTTON:
- ievent.type = InputEvent::JOYSTICK_BUTTON;
- ievent.ID = ++event_id;
- ievent.joy_button.button_index = _pc_joystick_get_native_button(event.number);
- ievent.joy_button.pressed = event.value;
- input->parse_input_event( ievent );
- break;
- };
- };
- };
- };
- };
- void OS_X11::set_cursor_shape(CursorShape p_shape) {
- ERR_FAIL_INDEX(p_shape,CURSOR_MAX);
- if (p_shape==current_cursor)
- return;
- if (mouse_mode==MOUSE_MODE_VISIBLE) {
- if (cursors[p_shape]!=None)
- XDefineCursor(x11_display,x11_window,cursors[p_shape]);
- else if (cursors[CURSOR_ARROW]!=None)
- XDefineCursor(x11_display,x11_window,cursors[CURSOR_ARROW]);
- }
- current_cursor=p_shape;
- }
- void OS_X11::release_rendering_thread() {
- context_gl->release_current();
- }
- void OS_X11::make_rendering_thread() {
- context_gl->make_current();
- }
- void OS_X11::swap_buffers() {
- context_gl->swap_buffers();
- }
- void OS_X11::set_icon(const Image& p_icon) {
- if (!p_icon.empty()) {
- Image img=p_icon;
- img.convert(Image::FORMAT_RGBA);
- int w = img.get_width();
- int h = img.get_height();
- // We're using long to have wordsize (32Bit build -> 32 Bits, 64 Bit build -> 64 Bits
- Vector<long> pd;
- pd.resize(2+w*h);
- print_line("***** SET ICON ***** "+itos(w)+" "+itos(h));
- pd[0]=w;
- pd[1]=h;
- DVector<uint8_t>::Read r = img.get_data().read();
- long * wr = &pd[2];
- uint8_t const * pr = r.ptr();
- for(int i=0;i<w*h;i++) {
- long v=0;
- // A R G B
- v|=pr[3] << 24 | pr[0] << 16 | pr[1] << 8 | pr[2];
- *wr++=v;
- pr += 4;
- }
- XChangeProperty(x11_display, x11_window, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, (unsigned char*) pd.ptr(), pd.size());
- } else {
- XDeleteProperty(x11_display, x11_window, net_wm_icon);
- }
- XFlush(x11_display);
- }
- void OS_X11::run() {
- force_quit = false;
-
- if (!main_loop)
- return;
-
- main_loop->init();
-
- // uint64_t last_ticks=get_ticks_usec();
-
- // int frames=0;
- // uint64_t frame=0;
-
- while (!force_quit) {
-
- process_xevents(); // get rid of pending events
- process_joysticks();
- if (Main::iteration()==true)
- break;
- };
-
- main_loop->finish();
- }
- OS_X11::OS_X11() {
- #ifdef RTAUDIO_ENABLED
- AudioDriverManagerSW::add_driver(&driver_rtaudio);
- #endif
- #ifdef ALSA_ENABLED
- AudioDriverManagerSW::add_driver(&driver_alsa);
- #endif
- minimized = false;
- xim_style=NULL;
- mouse_mode=MOUSE_MODE_VISIBLE;
- };
|