1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-07 12:30:27 +00:00

Effective DisplayServer separation, rename X11 -> LinuxBSD

This commit is contained in:
Juan Linietsky
2020-03-03 10:36:29 -03:00
committed by Juan Linietsky
parent 4396e98834
commit f8a79a97c7
83 changed files with 1304 additions and 5378 deletions

23
platform/linuxbsd/SCsub Normal file
View File

@@ -0,0 +1,23 @@
#!/usr/bin/env python
Import('env')
from platform_methods import run_in_subprocess
import platform_linuxbsd_builders
common_x11 = [
"crash_handler_linuxbsd.cpp",
"os_linuxbsd.cpp",
"joypad_linux.cpp",
"context_gl_x11.cpp",
"detect_prime_x11.cpp",
"display_server_x11.cpp",
"vulkan_context_x11.cpp",
"key_mapping_x11.cpp",
]
prog = env.add_program('#bin/godot', ['godot_linuxbsd.cpp'] + common_x11)
if (env["debug_symbols"] == "full" or env["debug_symbols"] == "yes") and env["separate_debug_symbols"]:
env.AddPostAction(prog, run_in_subprocess(platform_linuxbsd_builders.make_debug_linuxbsd))

View File

@@ -0,0 +1,265 @@
/*************************************************************************/
/* context_gl_x11.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* 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 "context_gl_x11.h"
#ifdef X11_ENABLED
#if defined(OPENGL_ENABLED)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.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
typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLXContext, Bool, const int *);
struct ContextGL_X11_Private {
::GLXContext glx_context;
};
void ContextGL_X11::release_current() {
glXMakeCurrent(x11_display, None, NULL);
}
void ContextGL_X11::make_current() {
glXMakeCurrent(x11_display, x11_window, p->glx_context);
}
void ContextGL_X11::swap_buffers() {
glXSwapBuffers(x11_display, x11_window);
}
static bool ctxErrorOccurred = false;
static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) {
ctxErrorOccurred = true;
return 0;
}
static void set_class_hint(Display *p_display, Window p_window) {
XClassHint *classHint;
/* set the name and class hints for the window manager to use */
classHint = XAllocClassHint();
if (classHint) {
classHint->res_name = (char *)"Godot_Engine";
classHint->res_class = (char *)"Godot";
}
XSetClassHint(p_display, p_window, classHint);
XFree(classHint);
}
Error ContextGL_X11::initialize() {
//const char *extensions = glXQueryExtensionsString(x11_display, DefaultScreen(x11_display));
GLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (GLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((const GLubyte *)"glXCreateContextAttribsARB");
ERR_FAIL_COND_V(!glXCreateContextAttribsARB, ERR_UNCONFIGURED);
static int visual_attribs[] = {
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_DOUBLEBUFFER, true,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_DEPTH_SIZE, 24,
None
};
static int visual_attribs_layered[] = {
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_DOUBLEBUFFER, true,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_DEPTH_SIZE, 24,
None
};
int fbcount;
GLXFBConfig fbconfig = 0;
XVisualInfo *vi = NULL;
XSetWindowAttributes swa;
swa.event_mask = StructureNotifyMask;
swa.border_pixel = 0;
unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask;
if (OS::get_singleton()->is_layered_allowed()) {
GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs_layered, &fbcount);
ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
for (int i = 0; i < fbcount; i++) {
vi = (XVisualInfo *)glXGetVisualFromFBConfig(x11_display, fbc[i]);
if (!vi)
continue;
XRenderPictFormat *pict_format = XRenderFindVisualFormat(x11_display, vi->visual);
if (!pict_format) {
XFree(vi);
vi = NULL;
continue;
}
fbconfig = fbc[i];
if (pict_format->direct.alphaMask > 0) {
break;
}
}
XFree(fbc);
ERR_FAIL_COND_V(!fbconfig, ERR_UNCONFIGURED);
swa.background_pixmap = None;
swa.background_pixel = 0;
swa.border_pixmap = None;
valuemask |= CWBackPixel;
} else {
GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount);
ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
vi = glXGetVisualFromFBConfig(x11_display, fbc[0]);
fbconfig = fbc[0];
XFree(fbc);
}
int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&ctxErrorHandler);
switch (context_type) {
case GLES_2_0_COMPATIBLE: {
p->glx_context = glXCreateNewContext(x11_display, fbconfig, GLX_RGBA_TYPE, 0, true);
ERR_FAIL_COND_V(!p->glx_context, ERR_UNCONFIGURED);
} break;
}
swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone);
x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height, 0, vi->depth, InputOutput, vi->visual, valuemask, &swa);
XStoreName(x11_display, x11_window, "Godot Engine");
ERR_FAIL_COND_V(!x11_window, ERR_UNCONFIGURED);
set_class_hint(x11_display, x11_window);
XMapWindow(x11_display, x11_window);
XSync(x11_display, False);
XSetErrorHandler(oldHandler);
glXMakeCurrent(x11_display, x11_window, p->glx_context);
XFree(vi);
return OK;
}
int ContextGL_X11::get_window_width() {
XWindowAttributes xwa;
XGetWindowAttributes(x11_display, x11_window, &xwa);
return xwa.width;
}
int ContextGL_X11::get_window_height() {
XWindowAttributes xwa;
XGetWindowAttributes(x11_display, x11_window, &xwa);
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, ContextType p_context_type) :
x11_window(p_x11_window) {
default_video_mode = p_default_video_mode;
x11_display = p_x11_display;
context_type = p_context_type;
double_buffer = false;
direct_render = false;
glx_minor = glx_major = 0;
p = memnew(ContextGL_X11_Private);
p->glx_context = 0;
use_vsync = false;
}
ContextGL_X11::~ContextGL_X11() {
release_current();
glXDestroyContext(x11_display, p->glx_context);
memdelete(p);
}
#endif
#endif

View File

@@ -0,0 +1,81 @@
/*************************************************************************/
/* context_gl_x11.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* 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. */
/*************************************************************************/
#ifndef CONTEXT_GL_X11_H
#define CONTEXT_GL_X11_H
#ifdef X11_ENABLED
#if defined(OPENGL_ENABLED)
#include "core/os/os.h"
#include <X11/Xlib.h>
#include <X11/extensions/Xrender.h>
struct ContextGL_X11_Private;
class ContextGL_X11 {
public:
enum ContextType {
GLES_2_0_COMPATIBLE,
};
private:
ContextGL_X11_Private *p;
OS::VideoMode default_video_mode;
::Display *x11_display;
::Window &x11_window;
bool double_buffer;
bool direct_render;
int glx_minor, glx_major;
bool use_vsync;
ContextType context_type;
public:
void release_current();
void make_current();
void swap_buffers();
int get_window_width();
int get_window_height();
Error initialize();
void set_use_vsync(bool p_use);
bool is_using_vsync() const;
ContextGL_X11(::Display *p_x11_display, ::Window &p_x11_window, const OS::VideoMode &p_default_video_mode, ContextType p_context_type);
~ContextGL_X11();
};
#endif
#endif
#endif

View File

@@ -0,0 +1,149 @@
/*************************************************************************/
/* crash_handler_linuxbsd.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* 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 "crash_handler_linuxbsd.h"
#include "core/os/os.h"
#include "core/project_settings.h"
#include "main/main.h"
#ifdef DEBUG_ENABLED
#define CRASH_HANDLER_ENABLED 1
#endif
#ifdef CRASH_HANDLER_ENABLED
#include <cxxabi.h>
#include <dlfcn.h>
#include <execinfo.h>
#include <signal.h>
#include <stdlib.h>
static void handle_crash(int sig) {
if (OS::get_singleton() == NULL) {
abort();
}
void *bt_buffer[256];
size_t size = backtrace(bt_buffer, 256);
String _execpath = OS::get_singleton()->get_executable_path();
String msg;
const ProjectSettings *proj_settings = ProjectSettings::get_singleton();
if (proj_settings) {
msg = proj_settings->get("debug/settings/crash_handler/message");
}
// Dump the backtrace to stderr with a message to the user
fprintf(stderr, "%s: Program crashed with signal %d\n", __FUNCTION__, sig);
if (OS::get_singleton()->get_main_loop())
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH);
fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str());
char **strings = backtrace_symbols(bt_buffer, size);
if (strings) {
for (size_t i = 1; i < size; i++) {
char fname[1024];
Dl_info info;
snprintf(fname, 1024, "%s", strings[i]);
// Try to demangle the function name to provide a more readable one
if (dladdr(bt_buffer[i], &info) && info.dli_sname) {
if (info.dli_sname[0] == '_') {
int status;
char *demangled = abi::__cxa_demangle(info.dli_sname, NULL, 0, &status);
if (status == 0 && demangled) {
snprintf(fname, 1024, "%s", demangled);
}
if (demangled)
free(demangled);
}
}
List<String> args;
char str[1024];
snprintf(str, 1024, "%p", bt_buffer[i]);
args.push_back(str);
args.push_back("-e");
args.push_back(_execpath);
String output = "";
// Try to get the file/line number using addr2line
int ret;
Error err = OS::get_singleton()->execute(String("addr2line"), args, true, NULL, &output, &ret);
if (err == OK) {
output.erase(output.length() - 1, 1);
}
fprintf(stderr, "[%ld] %s (%ls)\n", (long int)i, fname, output.c_str());
}
free(strings);
}
fprintf(stderr, "-- END OF BACKTRACE --\n");
// Abort to pass the error to the OS
abort();
}
#endif
CrashHandler::CrashHandler() {
disabled = false;
}
CrashHandler::~CrashHandler() {
disable();
}
void CrashHandler::disable() {
if (disabled)
return;
#ifdef CRASH_HANDLER_ENABLED
signal(SIGSEGV, NULL);
signal(SIGFPE, NULL);
signal(SIGILL, NULL);
#endif
disabled = true;
}
void CrashHandler::initialize() {
#ifdef CRASH_HANDLER_ENABLED
signal(SIGSEGV, handle_crash);
signal(SIGFPE, handle_crash);
signal(SIGILL, handle_crash);
#endif
}

View File

@@ -0,0 +1,48 @@
/*************************************************************************/
/* crash_handler_linuxbsd.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* 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. */
/*************************************************************************/
#ifndef CRASH_HANDLER_X11_H
#define CRASH_HANDLER_X11_H
class CrashHandler {
bool disabled;
public:
void initialize();
void disable();
bool is_disabled() const { return disabled; };
CrashHandler();
~CrashHandler();
};
#endif // CRASH_HANDLER_X11_H

368
platform/linuxbsd/detect.py Normal file
View File

@@ -0,0 +1,368 @@
import os
import platform
import sys
def is_active():
return True
def get_name():
return "LinuxBSD"
def can_build():
if (os.name != "posix" or sys.platform == "darwin"):
return False
# Check the minimal dependencies
x11_error = os.system("pkg-config --version > /dev/null")
if (x11_error):
return False
x11_error = os.system("pkg-config x11 --modversion > /dev/null ")
if (x11_error):
return False
x11_error = os.system("pkg-config xcursor --modversion > /dev/null ")
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
x11_error = os.system("pkg-config xrandr --modversion > /dev/null ")
if (x11_error):
print("xrandr not found.. x11 disabled.")
return False
x11_error = os.system("pkg-config xrender --modversion > /dev/null ")
if (x11_error):
print("xrender not found.. x11 disabled.")
return False
x11_error = os.system("pkg-config xi --modversion > /dev/null ")
if (x11_error):
print("xi not found.. Aborting.")
return False
return True
def get_opts():
from SCons.Variables import BoolVariable, EnumVariable
return [
BoolVariable('use_llvm', 'Use the LLVM compiler', False),
BoolVariable('use_lld', 'Use the LLD linker', False),
BoolVariable('use_thinlto', 'Use ThinLTO', False),
BoolVariable('use_static_cpp', 'Link libgcc and libstdc++ statically for better portability', False),
BoolVariable('use_coverage', 'Test Godot coverage', False),
BoolVariable('use_ubsan', 'Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)', False),
BoolVariable('use_asan', 'Use LLVM/GCC compiler address sanitizer (ASAN))', False),
BoolVariable('use_lsan', 'Use LLVM/GCC compiler leak sanitizer (LSAN))', False),
BoolVariable('use_tsan', 'Use LLVM/GCC compiler thread sanitizer (TSAN))', False),
BoolVariable('pulseaudio', 'Detect and use PulseAudio', True),
BoolVariable('udev', 'Use udev for gamepad connection callbacks', False),
EnumVariable('debug_symbols', 'Add debugging symbols to release builds', 'yes', ('yes', 'no', 'full')),
BoolVariable('separate_debug_symbols', 'Create a separate file containing debugging symbols', False),
BoolVariable('touch', 'Enable touch events', True),
BoolVariable('execinfo', 'Use libexecinfo on systems where glibc is not available', False),
]
def get_flags():
return []
def configure(env):
## Build type
if (env["target"] == "release"):
if (env["optimize"] == "speed"): #optimize for speed (default)
env.Prepend(CCFLAGS=['-O3'])
else: #optimize for size
env.Prepend(CCFLAGS=['-Os'])
if (env["debug_symbols"] == "yes"):
env.Prepend(CCFLAGS=['-g1'])
if (env["debug_symbols"] == "full"):
env.Prepend(CCFLAGS=['-g2'])
elif (env["target"] == "release_debug"):
if (env["optimize"] == "speed"): #optimize for speed (default)
env.Prepend(CCFLAGS=['-O2'])
else: #optimize for size
env.Prepend(CCFLAGS=['-Os'])
env.Prepend(CPPDEFINES=['DEBUG_ENABLED'])
if (env["debug_symbols"] == "yes"):
env.Prepend(CCFLAGS=['-g1'])
if (env["debug_symbols"] == "full"):
env.Prepend(CCFLAGS=['-g2'])
elif (env["target"] == "debug"):
env.Prepend(CCFLAGS=['-g3'])
env.Prepend(CPPDEFINES=['DEBUG_ENABLED', 'DEBUG_MEMORY_ENABLED'])
env.Append(LINKFLAGS=['-rdynamic'])
## Architecture
is64 = sys.maxsize > 2**32
if (env["bits"] == "default"):
env["bits"] = "64" if is64 else "32"
## Compiler configuration
if 'CXX' in env and 'clang' in os.path.basename(env['CXX']):
# Convenience check to enforce the use_llvm overrides when CXX is clang(++)
env['use_llvm'] = True
if env['use_llvm']:
if ('clang++' not in os.path.basename(env['CXX'])):
env["CC"] = "clang"
env["CXX"] = "clang++"
env["LINK"] = "clang++"
env.Append(CPPDEFINES=['TYPED_METHOD_BIND'])
env.extra_suffix = ".llvm" + env.extra_suffix
if env['use_lld']:
if env['use_llvm']:
env.Append(LINKFLAGS=['-fuse-ld=lld'])
if env['use_thinlto']:
# A convenience so you don't need to write use_lto too when using SCons
env['use_lto'] = True
else:
print("Using LLD with GCC is not supported yet, try compiling with 'use_llvm=yes'.")
sys.exit(255)
if env['use_coverage']:
env.Append(CCFLAGS=['-ftest-coverage', '-fprofile-arcs'])
env.Append(LINKFLAGS=['-ftest-coverage', '-fprofile-arcs'])
if env['use_ubsan'] or env['use_asan'] or env['use_lsan'] or env['use_tsan']:
env.extra_suffix += "s"
if env['use_ubsan']:
env.Append(CCFLAGS=['-fsanitize=undefined'])
env.Append(LINKFLAGS=['-fsanitize=undefined'])
if env['use_asan']:
env.Append(CCFLAGS=['-fsanitize=address'])
env.Append(LINKFLAGS=['-fsanitize=address'])
if env['use_lsan']:
env.Append(CCFLAGS=['-fsanitize=leak'])
env.Append(LINKFLAGS=['-fsanitize=leak'])
if env['use_tsan']:
env.Append(CCFLAGS=['-fsanitize=thread'])
env.Append(LINKFLAGS=['-fsanitize=thread'])
if env['use_lto']:
if not env['use_llvm'] and env.GetOption("num_jobs") > 1:
env.Append(CCFLAGS=['-flto'])
env.Append(LINKFLAGS=['-flto=' + str(env.GetOption("num_jobs"))])
else:
if env['use_lld'] and env['use_thinlto']:
env.Append(CCFLAGS=['-flto=thin'])
env.Append(LINKFLAGS=['-flto=thin'])
else:
env.Append(CCFLAGS=['-flto'])
env.Append(LINKFLAGS=['-flto'])
if not env['use_llvm']:
env['RANLIB'] = 'gcc-ranlib'
env['AR'] = 'gcc-ar'
env.Append(CCFLAGS=['-pipe'])
env.Append(LINKFLAGS=['-pipe'])
# -fpie and -no-pie is supported on GCC 6+ and Clang 4+, both below our
# minimal requirements.
env.Append(CCFLAGS=['-fpie'])
env.Append(LINKFLAGS=['-no-pie'])
## Dependencies
env.ParseConfig('pkg-config x11 --cflags --libs')
env.ParseConfig('pkg-config xcursor --cflags --libs')
env.ParseConfig('pkg-config xinerama --cflags --libs')
env.ParseConfig('pkg-config xrandr --cflags --libs')
env.ParseConfig('pkg-config xrender --cflags --libs')
env.ParseConfig('pkg-config xi --cflags --libs')
if (env['touch']):
env.Append(CPPDEFINES=['TOUCH_ENABLED'])
# FIXME: Check for existence of the libs before parsing their flags with pkg-config
# freetype depends on libpng and zlib, so bundling one of them while keeping others
# as shared libraries leads to weird issues
if env['builtin_freetype'] or env['builtin_libpng'] or env['builtin_zlib']:
env['builtin_freetype'] = True
env['builtin_libpng'] = True
env['builtin_zlib'] = True
if not env['builtin_freetype']:
env.ParseConfig('pkg-config freetype2 --cflags --libs')
if not env['builtin_libpng']:
env.ParseConfig('pkg-config libpng16 --cflags --libs')
if not env['builtin_bullet']:
# We need at least version 2.89
import subprocess
bullet_version = subprocess.check_output(['pkg-config', 'bullet', '--modversion']).strip()
if str(bullet_version) < "2.89":
# Abort as system bullet was requested but too old
print("Bullet: System version {0} does not match minimal requirements ({1}). Aborting.".format(bullet_version, "2.89"))
sys.exit(255)
env.ParseConfig('pkg-config bullet --cflags --libs')
if False: # not env['builtin_assimp']:
# FIXME: Add min version check
env.ParseConfig('pkg-config assimp --cflags --libs')
if not env['builtin_enet']:
env.ParseConfig('pkg-config libenet --cflags --libs')
if not env['builtin_squish']:
env.ParseConfig('pkg-config libsquish --cflags --libs')
if not env['builtin_zstd']:
env.ParseConfig('pkg-config libzstd --cflags --libs')
# Sound and video libraries
# Keep the order as it triggers chained dependencies (ogg needed by others, etc.)
if not env['builtin_libtheora']:
env['builtin_libogg'] = False # Needed to link against system libtheora
env['builtin_libvorbis'] = False # Needed to link against system libtheora
env.ParseConfig('pkg-config theora theoradec --cflags --libs')
else:
list_of_x86 = ['x86_64', 'x86', 'i386', 'i586']
if any(platform.machine() in s for s in list_of_x86):
env["x86_libtheora_opt_gcc"] = True
if not env['builtin_libvpx']:
env.ParseConfig('pkg-config vpx --cflags --libs')
if not env['builtin_libvorbis']:
env['builtin_libogg'] = False # Needed to link against system libvorbis
env.ParseConfig('pkg-config vorbis vorbisfile --cflags --libs')
if not env['builtin_opus']:
env['builtin_libogg'] = False # Needed to link against system opus
env.ParseConfig('pkg-config opus opusfile --cflags --libs')
if not env['builtin_libogg']:
env.ParseConfig('pkg-config ogg --cflags --libs')
if not env['builtin_libwebp']:
env.ParseConfig('pkg-config libwebp --cflags --libs')
if not env['builtin_mbedtls']:
# mbedTLS does not provide a pkgconfig config yet. See https://github.com/ARMmbed/mbedtls/issues/228
env.Append(LIBS=['mbedtls', 'mbedcrypto', 'mbedx509'])
if not env['builtin_wslay']:
env.ParseConfig('pkg-config libwslay --cflags --libs')
if not env['builtin_miniupnpc']:
# No pkgconfig file so far, hardcode default paths.
env.Prepend(CPPPATH=["/usr/include/miniupnpc"])
env.Append(LIBS=["miniupnpc"])
# On Linux wchar_t should be 32-bits
# 16-bit library shouldn't be required due to compiler optimisations
if not env['builtin_pcre2']:
env.ParseConfig('pkg-config libpcre2-32 --cflags --libs')
## Flags
if (os.system("pkg-config --exists alsa") == 0): # 0 means found
print("Enabling ALSA")
env.Append(CPPDEFINES=["ALSA_ENABLED", "ALSAMIDI_ENABLED"])
# Don't parse --cflags, we don't need to add /usr/include/alsa to include path
env.ParseConfig('pkg-config alsa --libs')
else:
print("ALSA libraries not found, disabling driver")
if env['pulseaudio']:
if (os.system("pkg-config --exists libpulse") == 0): # 0 means found
print("Enabling PulseAudio")
env.Append(CPPDEFINES=["PULSEAUDIO_ENABLED"])
env.ParseConfig('pkg-config --cflags --libs libpulse')
else:
print("PulseAudio development libraries not found, disabling driver")
if (platform.system() == "Linux"):
env.Append(CPPDEFINES=["JOYDEV_ENABLED"])
if env['udev']:
if (os.system("pkg-config --exists libudev") == 0): # 0 means found
print("Enabling udev support")
env.Append(CPPDEFINES=["UDEV_ENABLED"])
env.ParseConfig('pkg-config libudev --cflags --libs')
else:
print("libudev development libraries not found, disabling udev support")
# Linkflags below this line should typically stay the last ones
if not env['builtin_zlib']:
env.ParseConfig('pkg-config zlib --cflags --libs')
env.Prepend(CPPPATH=['#platform/linuxbsd'])
env.Append(CPPDEFINES=['X11_ENABLED', 'UNIX_ENABLED'])
env.Append(CPPDEFINES=['VULKAN_ENABLED'])
if not env['builtin_vulkan']:
env.ParseConfig('pkg-config vulkan --cflags --libs')
if not env['builtin_glslang']:
# No pkgconfig file for glslang so far
env.Append(LIBS=['glslang', 'SPIRV'])
#env.Append(CPPDEFINES=['OPENGL_ENABLED'])
env.Append(LIBS=['GL'])
env.Append(LIBS=['pthread'])
if (platform.system() == "Linux"):
env.Append(LIBS=['dl'])
if (platform.system().find("BSD") >= 0):
env["execinfo"] = True
if env["execinfo"]:
env.Append(LIBS=['execinfo'])
if not env['tools']:
import subprocess
import re
linker_version_str = subprocess.check_output([env.subst(env["LINK"]), '-Wl,--version']).decode("utf-8")
gnu_ld_version = re.search('^GNU ld [^$]*(\d+\.\d+)$', linker_version_str, re.MULTILINE)
if not gnu_ld_version:
print("Warning: Creating template binaries enabled for PCK embedding is currently only supported with GNU ld")
else:
if float(gnu_ld_version.group(1)) >= 2.30:
env.Append(LINKFLAGS=['-T', 'platform/linuxbsd/pck_embed.ld'])
else:
env.Append(LINKFLAGS=['-T', 'platform/linuxbsd/pck_embed.legacy.ld'])
## Cross-compilation
if (is64 and env["bits"] == "32"):
env.Append(CCFLAGS=['-m32'])
env.Append(LINKFLAGS=['-m32', '-L/usr/lib/i386-linux-gnu'])
elif (not is64 and env["bits"] == "64"):
env.Append(CCFLAGS=['-m64'])
env.Append(LINKFLAGS=['-m64', '-L/usr/lib/i686-linux-gnu'])
# Link those statically for portability
if env['use_static_cpp']:
env.Append(LINKFLAGS=['-static-libgcc', '-static-libstdc++'])

View File

@@ -0,0 +1,238 @@
/*************************************************************************/
/* detect_prime_x11.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* 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. */
/*************************************************************************/
#ifdef X11_ENABLED
#if defined(OPENGL_ENABLED)
#include "detect_prime.h"
#include "core/print_string.h"
#include "core/ustring.h"
#include <stdlib.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLXContext, Bool, const int *);
struct vendor {
const char *glxvendor;
int priority;
};
vendor vendormap[] = {
{ "Advanced Micro Devices, Inc.", 30 },
{ "NVIDIA Corporation", 30 },
{ "X.Org", 30 },
{ "Intel Open Source Technology Center", 20 },
{ "Intel", 20 },
{ "nouveau", 10 },
{ "Mesa Project", 0 },
{ NULL, 0 }
};
// Runs inside a child. Exiting will not quit the engine.
void create_context() {
Display *x11_display = XOpenDisplay(NULL);
Window x11_window;
GLXContext glx_context;
GLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (GLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((const GLubyte *)"glXCreateContextAttribsARB");
static int visual_attribs[] = {
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_DOUBLEBUFFER, true,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_DEPTH_SIZE, 24,
None
};
int fbcount;
GLXFBConfig fbconfig = 0;
XVisualInfo *vi = NULL;
XSetWindowAttributes swa;
swa.event_mask = StructureNotifyMask;
swa.border_pixel = 0;
unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask;
GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount);
if (!fbc)
exit(1);
vi = glXGetVisualFromFBConfig(x11_display, fbc[0]);
fbconfig = fbc[0];
static int context_attribs[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 3,
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
None
};
glx_context = glXCreateContextAttribsARB(x11_display, fbconfig, NULL, true, context_attribs);
swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone);
x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, 10, 10, 0, vi->depth, InputOutput, vi->visual, valuemask, &swa);
if (!x11_window)
exit(1);
glXMakeCurrent(x11_display, x11_window, glx_context);
XFree(vi);
}
int detect_prime() {
pid_t p;
int priorities[2];
String vendors[2];
String renderers[2];
vendors[0] = "Unknown";
vendors[1] = "Unknown";
renderers[0] = "Unknown";
renderers[1] = "Unknown";
for (int i = 0; i < 2; ++i) {
int fdset[2];
if (pipe(fdset) == -1) {
print_verbose("Failed to pipe(), using default GPU");
return 0;
}
// Fork so the driver initialization can crash without taking down the engine.
p = fork();
if (p > 0) {
// Main thread
int stat_loc = 0;
char string[201];
string[200] = '\0';
close(fdset[1]);
waitpid(p, &stat_loc, 0);
if (!stat_loc) {
// No need to do anything complicated here. Anything less than
// PIPE_BUF will be delivered in one read() call.
// Leave it 'Unknown' otherwise.
if (read(fdset[0], string, sizeof(string) - 1) > 0) {
vendors[i] = string;
renderers[i] = string + strlen(string) + 1;
}
}
close(fdset[0]);
} else {
// In child, exit() here will not quit the engine.
char string[201];
close(fdset[0]);
if (i) setenv("DRI_PRIME", "1", 1);
create_context();
const char *vendor = (const char *)glGetString(GL_VENDOR);
const char *renderer = (const char *)glGetString(GL_RENDERER);
unsigned int vendor_len = strlen(vendor) + 1;
unsigned int renderer_len = strlen(renderer) + 1;
if (vendor_len + renderer_len >= sizeof(string)) {
renderer_len = 200 - vendor_len;
}
memcpy(&string, vendor, vendor_len);
memcpy(&string[vendor_len], renderer, renderer_len);
if (write(fdset[1], string, vendor_len + renderer_len) == -1) {
print_verbose("Couldn't write vendor/renderer string.");
}
close(fdset[1]);
exit(0);
}
}
int preferred = 0;
int priority = 0;
if (vendors[0] == vendors[1]) {
print_verbose("Only one GPU found, using default.");
return 0;
}
for (int i = 1; i >= 0; --i) {
vendor *v = vendormap;
while (v->glxvendor) {
if (v->glxvendor == vendors[i]) {
priorities[i] = v->priority;
if (v->priority >= priority) {
priority = v->priority;
preferred = i;
}
}
++v;
}
}
print_verbose("Found renderers:");
for (int i = 0; i < 2; ++i) {
print_verbose("Renderer " + itos(i) + ": " + renderers[i] + " with priority: " + itos(priorities[i]));
}
print_verbose("Using renderer: " + renderers[preferred]);
return preferred;
}
#endif
#endif

View File

@@ -0,0 +1,37 @@
/*************************************************************************/
/* detect_prime_x11.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* 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. */
/*************************************************************************/
#ifdef X11_ENABLED
#if defined(OPENGL_ENABLED)
int detect_prime();
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,323 @@
/*************************************************************************/
/* display_server_x11.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* 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. */
/*************************************************************************/
#ifndef DISPLAY_SERVER_X11_H
#define DISPLAY_SERVER_X11_H
#ifdef X11_ENABLED
#include "servers/display_server.h"
#include "core/input/input.h"
#include "drivers/alsa/audio_driver_alsa.h"
#include "drivers/alsamidi/midi_driver_alsamidi.h"
#include "drivers/pulseaudio/audio_driver_pulseaudio.h"
#include "drivers/unix/os_unix.h"
#include "joypad_linux.h"
#include "servers/audio_server.h"
#include "servers/visual/rasterizer.h"
#include "servers/visual_server.h"
#if defined(OPENGL_ENABLED)
#include "context_gl_x11.h"
#endif
#if defined(VULKAN_ENABLED)
#include "drivers/vulkan/rendering_device_vulkan.h"
#include "platform/linuxbsd/vulkan_context_x11.h"
#endif
#include <X11/Xcursor/Xcursor.h>
#include <X11/Xlib.h>
#include <X11/extensions/XInput2.h>
#include <X11/extensions/Xrandr.h>
#include <X11/keysym.h>
// Hints for X11 fullscreen
typedef struct {
unsigned long flags;
unsigned long functions;
unsigned long decorations;
long inputMode;
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
class DisplayServerX11 : public DisplayServer {
//No need to register, it's platform-specific and nothing is added
//GDCLASS(DisplayServerX11, DisplayServer)
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 xdnd_aware;
Atom requested;
int xdnd_version;
#if defined(OPENGL_ENABLED)
ContextGL_X11 *context_gles2;
#endif
#if defined(VULKAN_ENABLED)
VulkanContextX11 *context_vulkan;
RenderingDeviceVulkan *rendering_device_vulkan;
#endif
struct WindowData {
Window x11_window;
::XIC xic;
#if defined(VULKAN_ENABLED)
int vulkan_window;
#endif
Size2i min_size;
Size2i max_size;
Size2i size;
Size2i im_position;
bool im_active = false;
//better to guess on the fly, given WM can change it
//WindowMode mode;
bool fullscreen = false; //OS can't exit from this mode
bool on_top = false;
bool borderless = false;
bool resize_disabled = false;
Vector2i last_position_before_fs;
};
Map<WindowID, WindowData> windows;
WindowID window_id_counter = MAIN_WINDOW_ID;
WindowID _create_window(WindowMode p_mode, const Vector2i &p_resolution);
String internal_clipboard;
Window xdnd_source_window;
::Display *x11_display;
char *xmbstring;
int xmblen;
unsigned long last_timestamp;
::Time last_keyrelease_time;
::XIM xim;
::XIMStyle xim_style;
static void _xim_destroy_callback(::XIM im, ::XPointer client_data,
::XPointer call_data);
Point2i last_mouse_pos;
bool last_mouse_pos_valid;
Point2i last_click_pos;
uint64_t last_click_ms;
int last_click_button_index;
uint32_t last_button_state;
struct {
int opcode;
Vector<int> touch_devices;
Map<int, Vector2> absolute_devices;
Map<int, Vector3> pen_devices;
XIEventMask all_event_mask;
Map<int, Vector2> state;
double pressure;
Vector2 tilt;
Vector2 mouse_pos_to_filter;
Vector2 relative_motion;
Vector2 raw_pos;
Vector2 old_raw_pos;
::Time last_relative_time;
} xi;
bool _refresh_device_info();
unsigned int _get_mouse_button_state(unsigned int p_x11_button, int p_x11_type);
void _get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state);
void _flush_mouse_motion();
MouseMode mouse_mode;
Point2i center;
void _handle_key_event(WindowID p_window, XKeyEvent *p_event, bool p_echo = false);
bool force_quit;
bool minimized;
bool window_has_focus;
bool do_mouse_warp;
const char *cursor_theme;
int cursor_size;
XcursorImage *img[CURSOR_MAX];
Cursor cursors[CURSOR_MAX];
Cursor null_cursor;
CursorShape current_cursor;
Map<CursorShape, Vector<Variant>> cursors_cache;
bool layered_window;
String rendering_driver;
bool window_focused;
//void set_wm_border(bool p_enabled);
void set_wm_fullscreen(bool p_enabled);
void set_wm_above(bool p_enabled);
typedef xrr_monitor_info *(*xrr_get_monitors_t)(Display *dpy, Window window, Bool get_active, int *nmonitors);
typedef void (*xrr_free_monitors_t)(xrr_monitor_info *monitors);
xrr_get_monitors_t xrr_get_monitors;
xrr_free_monitors_t xrr_free_monitors;
void *xrandr_handle;
Bool xrandr_ext_ok;
struct Property {
unsigned char *data;
int format, nitems;
Atom type;
};
static Property _read_property(Display *p_display, Window p_window, Atom p_property);
void _update_real_mouse_position(const WindowData &wd);
void _set_wm_fullscreen(WindowID p_window, bool p_enabled);
void _set_wm_maximized(WindowID p_window, bool p_enabled);
void _update_context(WindowData &wd);
Context context = CONTEXT_ENGINE;
protected:
void _window_changed(XEvent *event);
public:
virtual bool has_feature(Feature p_feature) const;
virtual String get_name() const;
virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
virtual void mouse_set_mode(MouseMode p_mode);
virtual MouseMode mouse_get_mode() const;
virtual void mouse_warp_to_position(const Point2i &p_to);
virtual Point2i mouse_get_position() const;
virtual int mouse_get_button_state() const;
virtual void clipboard_set(const String &p_text);
virtual String clipboard_get() const;
virtual int get_screen_count() const;
virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
virtual Vector<int> get_window_list() const;
virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
virtual void delete_sub_window(WindowID p_id);
virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID);
virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const;
virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID);
virtual Point2i window_get_position(WindowID p_window = MAIN_WINDOW_ID) const;
virtual void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID);
virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const;
virtual void window_set_min_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
virtual Size2i window_get_min_size(WindowID p_window = MAIN_WINDOW_ID) const;
virtual void window_set_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
virtual Size2i window_get_size(WindowID p_window = MAIN_WINDOW_ID) const;
virtual Size2i window_get_real_size(WindowID p_window = MAIN_WINDOW_ID) const;
virtual void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID);
virtual WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const;
virtual bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const;
virtual void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID);
virtual bool window_get_flag(WindowFlags p_flag, WindowID p_window = MAIN_WINDOW_ID) const;
virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID);
virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID);
virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const;
virtual bool can_any_window_draw() const;
virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID);
virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID);
virtual void cursor_set_shape(CursorShape p_shape);
virtual CursorShape cursor_get_shape() const;
virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
virtual LatinKeyboardVariant get_latin_keyboard_variant() const;
virtual void process_events();
virtual void release_rendering_thread();
virtual void make_rendering_thread();
virtual void swap_buffers();
virtual void set_context(Context p_context);
virtual void set_native_icon(const String &p_filename);
virtual void set_icon(const Ref<Image> &p_icon);
static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
static Vector<String> get_rendering_drivers_func();
static void register_x11_driver();
DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
~DisplayServerX11();
};
#endif // X11 enabled
#endif // DISPLAY_SERVER_X11_H

View File

@@ -0,0 +1,169 @@
/*************************************************************************/
/* export.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* 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 "export.h"
#include "core/os/file_access.h"
#include "editor/editor_export.h"
#include "platform/linuxbsd/logo.gen.h"
#include "scene/resources/texture.h"
static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size);
void register_linuxbsd_exporter() {
Ref<EditorExportPlatformPC> platform;
platform.instance();
Ref<Image> img = memnew(Image(_linuxbsd_logo));
Ref<ImageTexture> logo;
logo.instance();
logo->create_from_image(img);
platform->set_logo(logo);
platform->set_name("Linux/X11");
platform->set_extension("x86");
platform->set_extension("x86_64", "binary_format/64_bits");
platform->set_release_32("linux_x11_32_release");
platform->set_debug_32("linux_x11_32_debug");
platform->set_release_64("linux_x11_64_release");
platform->set_debug_64("linux_x11_64_debug");
platform->set_os_name("X11");
platform->set_chmod_flags(0755);
platform->set_fixup_embedded_pck_func(&fixup_embedded_pck);
EditorExport::get_singleton()->add_export_platform(platform);
}
static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) {
// Patch the header of the "pck" section in the ELF file so that it corresponds to the embedded data
FileAccess *f = FileAccess::open(p_path, FileAccess::READ_WRITE);
if (!f) {
return ERR_CANT_OPEN;
}
// Read and check ELF magic number
{
uint32_t magic = f->get_32();
if (magic != 0x464c457f) { // 0x7F + "ELF"
f->close();
return ERR_FILE_CORRUPT;
}
}
// Read program architecture bits from class field
int bits = f->get_8() * 32;
if (bits == 32 && p_embedded_size >= 0x100000000) {
f->close();
ERR_FAIL_V_MSG(ERR_INVALID_DATA, "32-bit executables cannot have embedded data >= 4 GiB.");
}
// Get info about the section header table
int64_t section_table_pos;
int64_t section_header_size;
if (bits == 32) {
section_header_size = 40;
f->seek(0x20);
section_table_pos = f->get_32();
f->seek(0x30);
} else { // 64
section_header_size = 64;
f->seek(0x28);
section_table_pos = f->get_64();
f->seek(0x3c);
}
int num_sections = f->get_16();
int string_section_idx = f->get_16();
// Load the strings table
uint8_t *strings;
{
// Jump to the strings section header
f->seek(section_table_pos + string_section_idx * section_header_size);
// Read strings data size and offset
int64_t string_data_pos;
int64_t string_data_size;
if (bits == 32) {
f->seek(f->get_position() + 0x10);
string_data_pos = f->get_32();
string_data_size = f->get_32();
} else { // 64
f->seek(f->get_position() + 0x18);
string_data_pos = f->get_64();
string_data_size = f->get_64();
}
// Read strings data
f->seek(string_data_pos);
strings = (uint8_t *)memalloc(string_data_size);
if (!strings) {
f->close();
return ERR_OUT_OF_MEMORY;
}
f->get_buffer(strings, string_data_size);
}
// Search for the "pck" section
bool found = false;
for (int i = 0; i < num_sections; ++i) {
int64_t section_header_pos = section_table_pos + i * section_header_size;
f->seek(section_header_pos);
uint32_t name_offset = f->get_32();
if (strcmp((char *)strings + name_offset, "pck") == 0) {
// "pck" section found, let's patch!
if (bits == 32) {
f->seek(section_header_pos + 0x10);
f->store_32(p_embedded_start);
f->store_32(p_embedded_size);
} else { // 64
f->seek(section_header_pos + 0x18);
f->store_64(p_embedded_start);
f->store_64(p_embedded_size);
}
found = true;
break;
}
}
memfree(strings);
f->close();
return found ? OK : ERR_FILE_CORRUPT;
}

View File

@@ -0,0 +1,36 @@
/*************************************************************************/
/* export.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* 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. */
/*************************************************************************/
#ifndef LINUXBSD_EXPORT_H
#define LINUXBSD_EXPORT_H
void register_linuxbsd_exporter();
#endif // LINUXBSD_EXPORT_H

View File

@@ -0,0 +1,67 @@
/*************************************************************************/
/* godot_linuxbsd.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* 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 <limits.h>
#include <locale.h>
#include <stdlib.h>
#include <unistd.h>
#include "main/main.h"
#include "os_linuxbsd.h"
int main(int argc, char *argv[]) {
OS_LinuxBSD os;
setlocale(LC_CTYPE, "");
char *cwd = (char *)malloc(PATH_MAX);
ERR_FAIL_COND_V(!cwd, ERR_OUT_OF_MEMORY);
char *ret = getcwd(cwd, PATH_MAX);
Error err = Main::setup(argv[0], argc - 1, &argv[1]);
if (err != OK) {
free(cwd);
return 255;
}
if (Main::start())
os.run(); // it is actually the OS that decides how to run
Main::cleanup();
if (ret) { // Previous getcwd was successful
if (chdir(cwd) != 0) {
ERR_PRINT("Couldn't return to previous working directory.");
}
}
free(cwd);
return os.get_exit_code();
}

View File

@@ -0,0 +1,554 @@
/*************************************************************************/
/* joypad_linux.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* 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. */
/*************************************************************************/
#ifdef JOYDEV_ENABLED
#include "joypad_linux.h"
#include <errno.h>
#include <fcntl.h>
#include <linux/input.h>
#include <unistd.h>
#ifdef UDEV_ENABLED
#include <libudev.h>
#endif
#define LONG_BITS (sizeof(long) * 8)
#define test_bit(nr, addr) (((1UL << ((nr) % LONG_BITS)) & ((addr)[(nr) / LONG_BITS])) != 0)
#define NBITS(x) ((((x)-1) / LONG_BITS) + 1)
#ifdef UDEV_ENABLED
static const char *ignore_str = "/dev/input/js";
#endif
JoypadLinux::Joypad::Joypad() {
fd = -1;
dpad = 0;
devpath = "";
for (int i = 0; i < MAX_ABS; i++) {
abs_info[i] = NULL;
}
}
JoypadLinux::Joypad::~Joypad() {
for (int i = 0; i < MAX_ABS; i++) {
if (abs_info[i]) {
memdelete(abs_info[i]);
}
}
}
void JoypadLinux::Joypad::reset() {
dpad = 0;
fd = -1;
Input::JoyAxis jx;
jx.min = -1;
jx.value = 0.0f;
for (int i = 0; i < MAX_ABS; i++) {
abs_map[i] = -1;
curr_axis[i] = jx;
}
}
JoypadLinux::JoypadLinux(Input *in) {
exit_udev = false;
input = in;
joy_thread = Thread::create(joy_thread_func, this);
}
JoypadLinux::~JoypadLinux() {
exit_udev = true;
Thread::wait_to_finish(joy_thread);
memdelete(joy_thread);
close_joypad();
}
void JoypadLinux::joy_thread_func(void *p_user) {
if (p_user) {
JoypadLinux *joy = (JoypadLinux *)p_user;
joy->run_joypad_thread();
}
}
void JoypadLinux::run_joypad_thread() {
#ifdef UDEV_ENABLED
udev *_udev = udev_new();
ERR_FAIL_COND(!_udev);
enumerate_joypads(_udev);
monitor_joypads(_udev);
udev_unref(_udev);
#else
monitor_joypads();
#endif
}
#ifdef UDEV_ENABLED
void JoypadLinux::enumerate_joypads(udev *p_udev) {
udev_enumerate *enumerate;
udev_list_entry *devices, *dev_list_entry;
udev_device *dev;
enumerate = udev_enumerate_new(p_udev);
udev_enumerate_add_match_subsystem(enumerate, "input");
udev_enumerate_scan_devices(enumerate);
devices = udev_enumerate_get_list_entry(enumerate);
udev_list_entry_foreach(dev_list_entry, devices) {
const char *path = udev_list_entry_get_name(dev_list_entry);
dev = udev_device_new_from_syspath(p_udev, path);
const char *devnode = udev_device_get_devnode(dev);
if (devnode) {
String devnode_str = devnode;
if (devnode_str.find(ignore_str) == -1) {
MutexLock lock(joy_mutex);
open_joypad(devnode);
}
}
udev_device_unref(dev);
}
udev_enumerate_unref(enumerate);
}
void JoypadLinux::monitor_joypads(udev *p_udev) {
udev_device *dev = NULL;
udev_monitor *mon = udev_monitor_new_from_netlink(p_udev, "udev");
udev_monitor_filter_add_match_subsystem_devtype(mon, "input", NULL);
udev_monitor_enable_receiving(mon);
int fd = udev_monitor_get_fd(mon);
while (!exit_udev) {
fd_set fds;
struct timeval tv;
int ret;
FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = 0;
tv.tv_usec = 0;
ret = select(fd + 1, &fds, NULL, NULL, &tv);
/* Check if our file descriptor has received data. */
if (ret > 0 && FD_ISSET(fd, &fds)) {
/* Make the call to receive the device.
select() ensured that this will not block. */
dev = udev_monitor_receive_device(mon);
if (dev && udev_device_get_devnode(dev) != 0) {
MutexLock lock(joy_mutex);
String action = udev_device_get_action(dev);
const char *devnode = udev_device_get_devnode(dev);
if (devnode) {
String devnode_str = devnode;
if (devnode_str.find(ignore_str) == -1) {
if (action == "add")
open_joypad(devnode);
else if (String(action) == "remove")
close_joypad(get_joy_from_path(devnode));
}
}
udev_device_unref(dev);
}
}
usleep(50000);
}
udev_monitor_unref(mon);
}
#endif
void JoypadLinux::monitor_joypads() {
while (!exit_udev) {
{
MutexLock lock(joy_mutex);
for (int i = 0; i < 32; i++) {
char fname[64];
sprintf(fname, "/dev/input/event%d", i);
if (attached_devices.find(fname) == -1) {
open_joypad(fname);
}
}
}
usleep(1000000); // 1s
}
}
int JoypadLinux::get_joy_from_path(String p_path) const {
for (int i = 0; i < JOYPADS_MAX; i++) {
if (joypads[i].devpath == p_path) {
return i;
}
}
return -2;
}
void JoypadLinux::close_joypad(int p_id) {
if (p_id == -1) {
for (int i = 0; i < JOYPADS_MAX; i++) {
close_joypad(i);
};
return;
} else if (p_id < 0)
return;
Joypad &joy = joypads[p_id];
if (joy.fd != -1) {
close(joy.fd);
joy.fd = -1;
attached_devices.remove(attached_devices.find(joy.devpath));
input->joy_connection_changed(p_id, false, "");
};
}
static String _hex_str(uint8_t p_byte) {
static const char *dict = "0123456789abcdef";
char ret[3];
ret[2] = 0;
ret[0] = dict[p_byte >> 4];
ret[1] = dict[p_byte & 0xF];
return ret;
}
void JoypadLinux::setup_joypad_properties(int p_id) {
Joypad *joy = &joypads[p_id];
unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
int num_buttons = 0;
int num_axes = 0;
if ((ioctl(joy->fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
(ioctl(joy->fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) {
return;
}
for (int i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
if (test_bit(i, keybit)) {
joy->key_map[i] = num_buttons++;
}
}
for (int i = BTN_MISC; i < BTN_JOYSTICK; ++i) {
if (test_bit(i, keybit)) {
joy->key_map[i] = num_buttons++;
}
}
for (int i = 0; i < ABS_MISC; ++i) {
/* Skip hats */
if (i == ABS_HAT0X) {
i = ABS_HAT3Y;
continue;
}
if (test_bit(i, absbit)) {
joy->abs_map[i] = num_axes++;
joy->abs_info[i] = memnew(input_absinfo);
if (ioctl(joy->fd, EVIOCGABS(i), joy->abs_info[i]) < 0) {
memdelete(joy->abs_info[i]);
joy->abs_info[i] = NULL;
}
}
}
joy->force_feedback = false;
joy->ff_effect_timestamp = 0;
unsigned long ffbit[NBITS(FF_CNT)];
if (ioctl(joy->fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) != -1) {
if (test_bit(FF_RUMBLE, ffbit)) {
joy->force_feedback = true;
}
}
}
void JoypadLinux::open_joypad(const char *p_path) {
int joy_num = input->get_unused_joy_id();
int fd = open(p_path, O_RDWR | O_NONBLOCK);
if (fd != -1 && joy_num != -1) {
unsigned long evbit[NBITS(EV_MAX)] = { 0 };
unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
// add to attached devices so we don't try to open it again
attached_devices.push_back(String(p_path));
if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
(ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
(ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) {
close(fd);
return;
}
//check if the device supports basic gamepad events, prevents certain keyboards from
//being detected as joypads
if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
(test_bit(ABS_X, absbit) || test_bit(ABS_Y, absbit) || test_bit(ABS_HAT0X, absbit) ||
test_bit(ABS_GAS, absbit) || test_bit(ABS_RUDDER, absbit)) &&
(test_bit(BTN_A, keybit) || test_bit(BTN_THUMBL, keybit) ||
test_bit(BTN_TRIGGER, keybit) || test_bit(BTN_1, keybit))) &&
!(test_bit(EV_ABS, evbit) &&
test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit) &&
test_bit(ABS_RX, absbit) && test_bit(ABS_RY, absbit))) {
close(fd);
return;
}
char uid[128];
char namebuf[128];
String name = "";
input_id inpid;
if (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) >= 0) {
name = namebuf;
}
if (ioctl(fd, EVIOCGID, &inpid) < 0) {
close(fd);
return;
}
joypads[joy_num].reset();
Joypad &joy = joypads[joy_num];
joy.fd = fd;
joy.devpath = String(p_path);
setup_joypad_properties(joy_num);
sprintf(uid, "%04x%04x", BSWAP16(inpid.bustype), 0);
if (inpid.vendor && inpid.product && inpid.version) {
uint16_t vendor = BSWAP16(inpid.vendor);
uint16_t product = BSWAP16(inpid.product);
uint16_t version = BSWAP16(inpid.version);
sprintf(uid + String(uid).length(), "%04x%04x%04x%04x%04x%04x", vendor, 0, product, 0, version, 0);
input->joy_connection_changed(joy_num, true, name, uid);
} else {
String uidname = uid;
int uidlen = MIN(name.length(), 11);
for (int i = 0; i < uidlen; i++) {
uidname = uidname + _hex_str(name[i]);
}
uidname += "00";
input->joy_connection_changed(joy_num, true, name, uidname);
}
}
}
void JoypadLinux::joypad_vibration_start(int p_id, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp) {
Joypad &joy = joypads[p_id];
if (!joy.force_feedback || joy.fd == -1 || p_weak_magnitude < 0.f || p_weak_magnitude > 1.f || p_strong_magnitude < 0.f || p_strong_magnitude > 1.f) {
return;
}
if (joy.ff_effect_id != -1) {
joypad_vibration_stop(p_id, p_timestamp);
}
struct ff_effect effect;
effect.type = FF_RUMBLE;
effect.id = -1;
effect.u.rumble.weak_magnitude = floor(p_weak_magnitude * (float)0xffff);
effect.u.rumble.strong_magnitude = floor(p_strong_magnitude * (float)0xffff);
effect.replay.length = floor(p_duration * 1000);
effect.replay.delay = 0;
if (ioctl(joy.fd, EVIOCSFF, &effect) < 0) {
return;
}
struct input_event play;
play.type = EV_FF;
play.code = effect.id;
play.value = 1;
if (write(joy.fd, (const void *)&play, sizeof(play)) == -1) {
print_verbose("Couldn't write to Joypad device.");
}
joy.ff_effect_id = effect.id;
joy.ff_effect_timestamp = p_timestamp;
}
void JoypadLinux::joypad_vibration_stop(int p_id, uint64_t p_timestamp) {
Joypad &joy = joypads[p_id];
if (!joy.force_feedback || joy.fd == -1 || joy.ff_effect_id == -1) {
return;
}
if (ioctl(joy.fd, EVIOCRMFF, joy.ff_effect_id) < 0) {
return;
}
joy.ff_effect_id = -1;
joy.ff_effect_timestamp = p_timestamp;
}
Input::JoyAxis JoypadLinux::axis_correct(const input_absinfo *p_abs, int p_value) const {
int min = p_abs->minimum;
int max = p_abs->maximum;
Input::JoyAxis jx;
if (min < 0) {
jx.min = -1;
if (p_value < 0) {
jx.value = (float)-p_value / min;
} else {
jx.value = (float)p_value / max;
}
} else if (min == 0) {
jx.min = 0;
jx.value = 0.0f + (float)p_value / max;
}
return jx;
}
void JoypadLinux::process_joypads() {
if (joy_mutex.try_lock() != OK) {
return;
}
for (int i = 0; i < JOYPADS_MAX; i++) {
if (joypads[i].fd == -1) continue;
input_event events[32];
Joypad *joy = &joypads[i];
int len;
while ((len = read(joy->fd, events, (sizeof events))) > 0) {
len /= sizeof(events[0]);
for (int j = 0; j < len; j++) {
input_event &ev = events[j];
// ev may be tainted and out of MAX_KEY range, which will cause
// joy->key_map[ev.code] to crash
if (ev.code >= MAX_KEY)
return;
switch (ev.type) {
case EV_KEY:
input->joy_button(i, joy->key_map[ev.code], ev.value);
break;
case EV_ABS:
switch (ev.code) {
case ABS_HAT0X:
if (ev.value != 0) {
if (ev.value < 0)
joy->dpad |= Input::HAT_MASK_LEFT;
else
joy->dpad |= Input::HAT_MASK_RIGHT;
} else
joy->dpad &= ~(Input::HAT_MASK_LEFT | Input::HAT_MASK_RIGHT);
input->joy_hat(i, joy->dpad);
break;
case ABS_HAT0Y:
if (ev.value != 0) {
if (ev.value < 0)
joy->dpad |= Input::HAT_MASK_UP;
else
joy->dpad |= Input::HAT_MASK_DOWN;
} else
joy->dpad &= ~(Input::HAT_MASK_UP | Input::HAT_MASK_DOWN);
input->joy_hat(i, joy->dpad);
break;
default:
if (ev.code >= MAX_ABS)
return;
if (joy->abs_map[ev.code] != -1 && joy->abs_info[ev.code]) {
Input::JoyAxis value = axis_correct(joy->abs_info[ev.code], ev.value);
joy->curr_axis[joy->abs_map[ev.code]] = value;
}
break;
}
break;
}
}
}
for (int j = 0; j < MAX_ABS; j++) {
int index = joy->abs_map[j];
if (index != -1) {
input->joy_axis(i, index, joy->curr_axis[index]);
}
}
if (len == 0 || (len < 0 && errno != EAGAIN)) {
close_joypad(i);
};
if (joy->force_feedback) {
uint64_t timestamp = input->get_joy_vibration_timestamp(i);
if (timestamp > joy->ff_effect_timestamp) {
Vector2 strength = input->get_joy_vibration_strength(i);
float duration = input->get_joy_vibration_duration(i);
if (strength.x == 0 && strength.y == 0) {
joypad_vibration_stop(i, timestamp);
} else {
joypad_vibration_start(i, strength.x, strength.y, duration, timestamp);
}
}
}
}
joy_mutex.unlock();
}
#endif

View File

@@ -0,0 +1,102 @@
/*************************************************************************/
/* joypad_linux.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* 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. */
/*************************************************************************/
//author: Andreas Haas <hondres, liugam3@gmail.com>
#ifndef JOYPAD_LINUX_H
#define JOYPAD_LINUX_H
#ifdef JOYDEV_ENABLED
#include "core/input/input.h"
#include "core/os/mutex.h"
#include "core/os/thread.h"
struct input_absinfo;
class JoypadLinux {
public:
JoypadLinux(Input *in);
~JoypadLinux();
void process_joypads();
private:
enum {
JOYPADS_MAX = 16,
MAX_ABS = 63,
MAX_KEY = 767, // Hack because <linux/input.h> can't be included here
};
struct Joypad {
Input::JoyAxis curr_axis[MAX_ABS];
int key_map[MAX_KEY];
int abs_map[MAX_ABS];
int dpad;
int fd;
String devpath;
input_absinfo *abs_info[MAX_ABS];
bool force_feedback;
int ff_effect_id;
uint64_t ff_effect_timestamp;
Joypad();
~Joypad();
void reset();
};
bool exit_udev;
Mutex joy_mutex;
Thread *joy_thread;
Input *input;
Joypad joypads[JOYPADS_MAX];
Vector<String> attached_devices;
static void joy_thread_func(void *p_user);
int get_joy_from_path(String p_path) const;
void setup_joypad_properties(int p_id);
void close_joypad(int p_id = -1);
#ifdef UDEV_ENABLED
void enumerate_joypads(struct udev *p_udev);
void monitor_joypads(struct udev *p_udev);
#endif
void monitor_joypads();
void run_joypad_thread();
void open_joypad(const char *p_path);
void joypad_vibration_start(int p_id, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp);
void joypad_vibration_stop(int p_id, uint64_t p_timestamp);
Input::JoyAxis axis_correct(const input_absinfo *p_abs, int p_value) const;
};
#endif
#endif // JOYPAD_LINUX_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,54 @@
/*************************************************************************/
/* key_mapping_x11.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* 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. */
/*************************************************************************/
#ifndef KEY_MAPPING_X11_H
#define KEY_MAPPING_X11_H
#include <X11/XF86keysym.h>
#include <X11/Xlib.h>
#define XK_MISCELLANY
#define XK_LATIN1
#define XK_XKB_KEYS
#include <X11/keysymdef.h>
#include "core/os/keyboard.h"
class KeyMappingX11 {
KeyMappingX11(){};
public:
static unsigned int get_keycode(KeySym p_keysym);
static unsigned int get_scancode(unsigned int p_code);
static KeySym get_keysym(unsigned int p_code);
static unsigned int get_unicode_from_keysym(KeySym p_keysym);
static KeySym get_keysym_from_unicode(unsigned int p_unicode);
};
#endif

BIN
platform/linuxbsd/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,381 @@
/*************************************************************************/
/* os_linuxbsd.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* 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 "os_linuxbsd.h"
#include "core/os/dir_access.h"
#include "core/print_string.h"
#include "errno.h"
#ifdef HAVE_MNTENT
#include <mntent.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "main/main.h"
#ifdef X11_ENABLED
#include "display_server_x11.h"
#endif
void OS_LinuxBSD::initialize() {
crash_handler.initialize();
OS_Unix::initialize_core();
}
void OS_LinuxBSD::initialize_joypads() {
#ifdef JOYDEV_ENABLED
joypad = memnew(JoypadLinux(Input::get_singleton()));
#endif
}
String OS_LinuxBSD::get_unique_id() const {
static String machine_id;
if (machine_id.empty()) {
if (FileAccess *f = FileAccess::open("/etc/machine-id", FileAccess::READ)) {
while (machine_id.empty() && !f->eof_reached()) {
machine_id = f->get_line().strip_edges();
}
f->close();
memdelete(f);
}
}
return machine_id;
}
void OS_LinuxBSD::finalize() {
if (main_loop)
memdelete(main_loop);
main_loop = NULL;
#ifdef ALSAMIDI_ENABLED
driver_alsamidi.close();
#endif
#ifdef JOYDEV_ENABLED
memdelete(joypad);
#endif
}
MainLoop *OS_LinuxBSD::get_main_loop() const {
return main_loop;
}
void OS_LinuxBSD::delete_main_loop() {
if (main_loop)
memdelete(main_loop);
main_loop = NULL;
}
void OS_LinuxBSD::set_main_loop(MainLoop *p_main_loop) {
main_loop = p_main_loop;
}
String OS_LinuxBSD::get_name() const {
#ifdef __linux__
return "Linux";
#elif defined(__FreeBSD__)
return "FreeBSD";
#elif defined(__NetBSD__)
return "NetBSD";
#else
return "BSD";
#endif
}
Error OS_LinuxBSD::shell_open(String p_uri) {
Error ok;
List<String> args;
args.push_back(p_uri);
ok = execute("xdg-open", args, false);
if (ok == OK)
return OK;
ok = execute("gnome-open", args, false);
if (ok == OK)
return OK;
ok = execute("kde-open", args, false);
return ok;
}
bool OS_LinuxBSD::_check_internal_feature_support(const String &p_feature) {
return p_feature == "pc";
}
String OS_LinuxBSD::get_config_path() const {
if (has_environment("XDG_CONFIG_HOME")) {
return get_environment("XDG_CONFIG_HOME");
} else if (has_environment("HOME")) {
return get_environment("HOME").plus_file(".config");
} else {
return ".";
}
}
String OS_LinuxBSD::get_data_path() const {
if (has_environment("XDG_DATA_HOME")) {
return get_environment("XDG_DATA_HOME");
} else if (has_environment("HOME")) {
return get_environment("HOME").plus_file(".local/share");
} else {
return get_config_path();
}
}
String OS_LinuxBSD::get_cache_path() const {
if (has_environment("XDG_CACHE_HOME")) {
return get_environment("XDG_CACHE_HOME");
} else if (has_environment("HOME")) {
return get_environment("HOME").plus_file(".cache");
} else {
return get_config_path();
}
}
String OS_LinuxBSD::get_system_dir(SystemDir p_dir) const {
String xdgparam;
switch (p_dir) {
case SYSTEM_DIR_DESKTOP: {
xdgparam = "DESKTOP";
} break;
case SYSTEM_DIR_DCIM: {
xdgparam = "PICTURES";
} break;
case SYSTEM_DIR_DOCUMENTS: {
xdgparam = "DOCUMENTS";
} break;
case SYSTEM_DIR_DOWNLOADS: {
xdgparam = "DOWNLOAD";
} break;
case SYSTEM_DIR_MOVIES: {
xdgparam = "VIDEOS";
} break;
case SYSTEM_DIR_MUSIC: {
xdgparam = "MUSIC";
} break;
case SYSTEM_DIR_PICTURES: {
xdgparam = "PICTURES";
} break;
case SYSTEM_DIR_RINGTONES: {
xdgparam = "MUSIC";
} break;
}
String pipe;
List<String> arg;
arg.push_back(xdgparam);
Error err = const_cast<OS_LinuxBSD *>(this)->execute("xdg-user-dir", arg, true, NULL, &pipe);
if (err != OK)
return ".";
return pipe.strip_edges();
}
void OS_LinuxBSD::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) {
DisplayServer::get_singleton()->process_events(); // get rid of pending events
#ifdef JOYDEV_ENABLED
joypad->process_joypads();
#endif
if (Main::iteration())
break;
};
main_loop->finish();
}
void OS_LinuxBSD::disable_crash_handler() {
crash_handler.disable();
}
bool OS_LinuxBSD::is_disable_crash_handler() const {
return crash_handler.is_disabled();
}
static String get_mountpoint(const String &p_path) {
struct stat s;
if (stat(p_path.utf8().get_data(), &s)) {
return "";
}
#ifdef HAVE_MNTENT
dev_t dev = s.st_dev;
FILE *fd = setmntent("/proc/mounts", "r");
if (!fd) {
return "";
}
struct mntent mnt;
char buf[1024];
size_t buflen = 1024;
while (getmntent_r(fd, &mnt, buf, buflen)) {
if (!stat(mnt.mnt_dir, &s) && s.st_dev == dev) {
endmntent(fd);
return String(mnt.mnt_dir);
}
}
endmntent(fd);
#endif
return "";
}
Error OS_LinuxBSD::move_to_trash(const String &p_path) {
String trash_can = "";
String mnt = get_mountpoint(p_path);
// If there is a directory "[Mountpoint]/.Trash-[UID]/files", use it as the trash can.
if (mnt != "") {
String path(mnt + "/.Trash-" + itos(getuid()) + "/files");
struct stat s;
if (!stat(path.utf8().get_data(), &s)) {
trash_can = path;
}
}
// Otherwise, if ${XDG_DATA_HOME} is defined, use "${XDG_DATA_HOME}/Trash/files" as the trash can.
if (trash_can == "") {
char *dhome = getenv("XDG_DATA_HOME");
if (dhome) {
trash_can = String(dhome) + "/Trash/files";
}
}
// Otherwise, if ${HOME} is defined, use "${HOME}/.local/share/Trash/files" as the trash can.
if (trash_can == "") {
char *home = getenv("HOME");
if (home) {
trash_can = String(home) + "/.local/share/Trash/files";
}
}
// Issue an error if none of the previous locations is appropriate for the trash can.
if (trash_can == "") {
ERR_PRINT("move_to_trash: Could not determine the trash can location");
return FAILED;
}
// Create needed directories for decided trash can location.
DirAccess *dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
Error err = dir_access->make_dir_recursive(trash_can);
memdelete(dir_access);
// Issue an error if trash can is not created proprely.
if (err != OK) {
ERR_PRINT("move_to_trash: Could not create the trash can \"" + trash_can + "\"");
return err;
}
// The trash can is successfully created, now move the given resource to it.
// Do not use DirAccess:rename() because it can't move files across multiple mountpoints.
List<String> mv_args;
mv_args.push_back(p_path);
mv_args.push_back(trash_can);
int retval;
err = execute("mv", mv_args, true, NULL, NULL, &retval);
// Issue an error if "mv" failed to move the given resource to the trash can.
if (err != OK || retval != 0) {
ERR_PRINT("move_to_trash: Could not move the resource \"" + p_path + "\" to the trash can \"" + trash_can + "\"");
return FAILED;
}
return OK;
}
OS_LinuxBSD::OS_LinuxBSD() {
main_loop = NULL;
force_quit = false;
#ifdef PULSEAUDIO_ENABLED
AudioDriverManager::add_driver(&driver_pulseaudio);
#endif
#ifdef ALSA_ENABLED
AudioDriverManager::add_driver(&driver_alsa);
#endif
#ifdef X11_ENABLED
DisplayServerX11::register_x11_driver();
#endif
}

View File

@@ -0,0 +1,106 @@
/*************************************************************************/
/* os_linuxbsd.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* 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. */
/*************************************************************************/
#ifndef OS_LINUXBSD_H
#define OS_LINUXBSD_H
#include "core/input/input.h"
#include "crash_handler_linuxbsd.h"
#include "drivers/alsa/audio_driver_alsa.h"
#include "drivers/alsamidi/midi_driver_alsamidi.h"
#include "drivers/pulseaudio/audio_driver_pulseaudio.h"
#include "drivers/unix/os_unix.h"
#include "joypad_linux.h"
#include "servers/audio_server.h"
#include "servers/visual/rasterizer.h"
#include "servers/visual_server.h"
class OS_LinuxBSD : public OS_Unix {
virtual void delete_main_loop();
bool force_quit;
#ifdef JOYDEV_ENABLED
JoypadLinux *joypad;
#endif
#ifdef ALSA_ENABLED
AudioDriverALSA driver_alsa;
#endif
#ifdef ALSAMIDI_ENABLED
MIDIDriverALSAMidi driver_alsamidi;
#endif
#ifdef PULSEAUDIO_ENABLED
AudioDriverPulseAudio driver_pulseaudio;
#endif
CrashHandler crash_handler;
MainLoop *main_loop;
protected:
virtual void initialize();
virtual void finalize();
virtual void initialize_joypads();
virtual void set_main_loop(MainLoop *p_main_loop);
public:
virtual String get_name() const;
virtual MainLoop *get_main_loop() const;
virtual String get_config_path() const;
virtual String get_data_path() const;
virtual String get_cache_path() const;
virtual String get_system_dir(SystemDir p_dir) const;
virtual Error shell_open(String p_uri);
virtual String get_unique_id() const;
virtual bool _check_internal_feature_support(const String &p_feature);
void run();
void disable_crash_handler();
bool is_disable_crash_handler() const;
virtual Error move_to_trash(const String &p_path);
OS_LinuxBSD();
};
#endif

View File

@@ -0,0 +1,10 @@
SECTIONS
{
/* Add a zero-sized section; the exporter will patch it to enclose the data appended to the executable (embedded PCK) */
pck 0 (INFO) :
{
/* binutils >= 2.30 allow it being zero-sized, but needs something between the braces to keep the section */
. = ALIGN(8);
}
}
INSERT AFTER .rodata;

View File

@@ -0,0 +1,10 @@
SECTIONS
{
/* The exporter will patch this section to enclose the data appended to the executable (embedded PCK) */
pck 0 (INFO) : AT ( ADDR (.rodata) + SIZEOF (.rodata) )
{
/* binutils < 2.30 need some actual content for the linker not to discard the section */
BYTE(0);
}
}
INSERT AFTER .rodata;

View File

@@ -0,0 +1,39 @@
/*************************************************************************/
/* platform_config.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* 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. */
/*************************************************************************/
#ifdef __linux__
#include <alloca.h>
#endif
#if defined(__FreeBSD__) || defined(__OpenBSD__)
#include <stdlib.h>
#define PTHREAD_BSD_SET_NAME
#endif
#define GLES2_INCLUDE_H "thirdparty/glad/glad/glad.h"

View File

@@ -0,0 +1,17 @@
"""Functions used to generate source files during build time
All such functions are invoked in a subprocess on Windows to prevent build flakiness.
"""
import os
from platform_methods import subprocess_main
def make_debug_linuxbsd(target, source, env):
os.system('objcopy --only-keep-debug {0} {0}.debugsymbols'.format(target[0]))
os.system('strip --strip-debug --strip-unneeded {0}'.format(target[0]))
os.system('objcopy --add-gnu-debuglink={0}.debugsymbols {0}'.format(target[0]))
if __name__ == '__main__':
subprocess_main(globals())

View File

@@ -0,0 +1,57 @@
/*************************************************************************/
/* vulkan_context_x11.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* 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 "vulkan_context_x11.h"
#include <vulkan/vulkan_xlib.h>
const char *VulkanContextX11::_get_platform_surface_extension() const {
return VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
}
int VulkanContextX11::window_create(::Window p_window, Display *p_display, int p_width, int p_height) {
VkXlibSurfaceCreateInfoKHR createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
createInfo.pNext = NULL;
createInfo.flags = 0;
createInfo.dpy = p_display;
createInfo.window = p_window;
VkSurfaceKHR surface;
VkResult err = vkCreateXlibSurfaceKHR(_get_instance(), &createInfo, NULL, &surface);
ERR_FAIL_COND_V(err, -1);
return _window_create(surface, p_width, p_height);
}
VulkanContextX11::VulkanContextX11() {
}
VulkanContextX11::~VulkanContextX11() {
}

View File

@@ -0,0 +1,48 @@
/*************************************************************************/
/* vulkan_context_x11.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* 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. */
/*************************************************************************/
#ifndef VULKAN_DEVICE_X11_H
#define VULKAN_DEVICE_X11_H
#include "drivers/vulkan/vulkan_context.h"
#include <X11/Xlib.h>
class VulkanContextX11 : public VulkanContext {
virtual const char *_get_platform_surface_extension() const;
public:
int window_create(::Window p_window, Display *p_display, int p_width, int p_height);
VulkanContextX11();
~VulkanContextX11();
};
#endif // VULKAN_DEVICE_X11_H