Get rid of ctypes based loading of libglfw/libX11

This commit is contained in:
Kovid Goyal 2017-11-20 12:56:43 +05:30
parent b6be6ee1e7
commit cfc99baac4
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
6 changed files with 113 additions and 144 deletions

View File

@ -94,12 +94,13 @@ class Arg:
class Function:
def __init__(self, declaration):
def __init__(self, declaration, check_fail=True):
self.check_fail = check_fail
m = re.match(
r'(.+?)\s+(glfw[A-Z][a-zA-Z0-9]+)[(](.+)[)]$', declaration
)
if m is None:
raise SystemExit('Failed to parse ' + declaration)
raise SystemExit('Failed to parse ' + repr(declaration))
self.restype = m.group(1).strip()
self.name = m.group(2)
args = m.group(3).strip().split(',')
@ -121,9 +122,10 @@ class Function:
ans = '*(void **) (&{name}_impl) = dlsym(handle, "{name}");'.format(
name=self.name
)
ans += '\n if ({name}_impl == NULL) fail("Failed to load glfw function {name} with error: %s", dlerror());'.format(
name=self.name
)
if self.check_fail:
ans += '\n if ({name}_impl == NULL) fail("Failed to load glfw function {name} with error: %s", dlerror());'.format(
name=self.name
)
return ans
@ -138,6 +140,17 @@ def generate_wrappers(glfw_header, glfw_native_header):
if 'VkInstance' in decl:
continue
functions.append(Function(decl))
for line in '''\
void* glfwGetCocoaWindow(GLFWwindow* window)
uint32_t glfwGetCocoaMonitor(GLFWmonitor* monitor)
void* glfwGetX11Display(void)
int32_t glfwGetX11Window(GLFWwindow* window)
void glfwSetX11SelectionString(const char* string)
const char* glfwGetX11SelectionString(void)
'''.splitlines():
if line:
functions.append(Function(line.strip(), check_fail=False))
declarations = [f.declaration() for f in functions]
p = src.find(' * GLFW API tokens')
p = src.find('*/', p)

View File

@ -4,11 +4,10 @@
import os
import pwd
import ctypes
import sys
from collections import namedtuple
from .fast_data_types import set_boss as set_c_boss, handle_for_window_id
from .fast_data_types import set_boss as set_c_boss
appname = 'kitty'
version = (0, 5, 1)
@ -59,67 +58,4 @@ except KeyError:
print('Failed to read login shell from /etc/passwd for current user, falling back to /bin/sh', file=sys.stderr)
shell_path = '/bin/sh'
GLint = ctypes.c_int if ctypes.sizeof(ctypes.c_int) == 4 else ctypes.c_long
GLuint = ctypes.c_uint if ctypes.sizeof(ctypes.c_uint) == 4 else ctypes.c_ulong
GLfloat = ctypes.c_float
if ctypes.sizeof(GLfloat) != 4:
raise RuntimeError('float size is not 4')
if ctypes.sizeof(GLint) != 4:
raise RuntimeError('int size is not 4')
def get_glfw_lib_name():
try:
for line in open('/proc/self/maps'):
lib = line.split()[-1]
if '/libglfw.so' in lib:
return lib
except Exception as err:
try:
print(str(err), file=sys.stderr)
except Exception:
pass
return 'libglfw.so.3'
def glfw_lib():
ans = getattr(glfw_lib, 'ans', None)
if ans is None:
ans = glfw_lib.ans = ctypes.CDLL('libglfw.3.dylib' if isosx else get_glfw_lib_name())
return ans
def selection_clipboard_funcs():
ans = getattr(selection_clipboard_funcs, 'ans', None)
if ans is None:
lib = glfw_lib()
if hasattr(lib, 'glfwGetX11SelectionString'):
g = lib.glfwGetX11SelectionString
g.restype = ctypes.c_char_p
g.argtypes = []
s = lib.glfwSetX11SelectionString
s.restype = None
s.argtypes = [ctypes.c_char_p]
ans = g, s
else:
ans = None, None
selection_clipboard_funcs.ans = ans
return ans
def x11_window_id(window_id):
lib = glfw_lib()
lib.glfwGetX11Window.restype = ctypes.c_int32
lib.glfwGetX11Window.argtypes = [ctypes.c_void_p]
return lib.glfwGetX11Window(handle_for_window_id(window_id))
def x11_display():
lib = glfw_lib()
ans = lib.glfwGetX11Display
ans.restype = ctypes.c_void_p
ans.argtypes = []
return ans()
iswayland = not isosx and hasattr(glfw_lib(), 'glfwGetWaylandDisplay')
iswayland = False

12
kitty/glfw-wrapper.c generated
View File

@ -341,6 +341,18 @@ load_glfw(const char* path) {
*(void **) (&glfwGetRequiredInstanceExtensions_impl) = dlsym(handle, "glfwGetRequiredInstanceExtensions");
if (glfwGetRequiredInstanceExtensions_impl == NULL) fail("Failed to load glfw function glfwGetRequiredInstanceExtensions with error: %s", dlerror());
*(void **) (&glfwGetCocoaWindow_impl) = dlsym(handle, "glfwGetCocoaWindow");
*(void **) (&glfwGetCocoaMonitor_impl) = dlsym(handle, "glfwGetCocoaMonitor");
*(void **) (&glfwGetX11Display_impl) = dlsym(handle, "glfwGetX11Display");
*(void **) (&glfwGetX11Window_impl) = dlsym(handle, "glfwGetX11Window");
*(void **) (&glfwSetX11SelectionString_impl) = dlsym(handle, "glfwSetX11SelectionString");
*(void **) (&glfwGetX11SelectionString_impl) = dlsym(handle, "glfwGetX11SelectionString");
return NULL;
}

24
kitty/glfw-wrapper.h generated
View File

@ -1783,4 +1783,28 @@ typedef const char** (*glfwGetRequiredInstanceExtensions_func)(uint32_t*);
glfwGetRequiredInstanceExtensions_func glfwGetRequiredInstanceExtensions_impl;
#define glfwGetRequiredInstanceExtensions glfwGetRequiredInstanceExtensions_impl
typedef void* (*glfwGetCocoaWindow_func)(GLFWwindow*);
glfwGetCocoaWindow_func glfwGetCocoaWindow_impl;
#define glfwGetCocoaWindow glfwGetCocoaWindow_impl
typedef uint32_t (*glfwGetCocoaMonitor_func)(GLFWmonitor*);
glfwGetCocoaMonitor_func glfwGetCocoaMonitor_impl;
#define glfwGetCocoaMonitor glfwGetCocoaMonitor_impl
typedef void* (*glfwGetX11Display_func)();
glfwGetX11Display_func glfwGetX11Display_impl;
#define glfwGetX11Display glfwGetX11Display_impl
typedef int32_t (*glfwGetX11Window_func)(GLFWwindow*);
glfwGetX11Window_func glfwGetX11Window_impl;
#define glfwGetX11Window glfwGetX11Window_impl
typedef void (*glfwSetX11SelectionString_func)(const char*);
glfwSetX11SelectionString_func glfwSetX11SelectionString_impl;
#define glfwSetX11SelectionString glfwSetX11SelectionString_impl
typedef const char* (*glfwGetX11SelectionString_func)();
glfwGetX11SelectionString_func glfwGetX11SelectionString_impl;
#define glfwGetX11SelectionString glfwGetX11SelectionString_impl
const char* load_glfw(const char* path);

View File

@ -537,6 +537,45 @@ primary_monitor_content_scale(PyObject UNUSED *self) {
return Py_BuildValue("ff", xscale, yscale);
}
static PyObject*
x11_display(PyObject UNUSED *self) {
if (glfwGetX11Display) {
return PyLong_FromVoidPtr(glfwGetX11Display());
} else fprintf(stderr, "Failed to load glfwGetX11Display\n");
Py_RETURN_NONE;
}
static PyObject*
x11_window_id(PyObject UNUSED *self, PyObject *os_wid) {
if (glfwGetX11Window) {
id_type os_window_id = PyLong_AsUnsignedLongLong(os_wid);
for (size_t i = 0; i < global_state.num_os_windows; i++) {
OSWindow *w = global_state.os_windows + i;
if (w->id == os_window_id) return Py_BuildValue("l", (long)glfwGetX11Window(w->handle));
}
}
else { PyErr_SetString(PyExc_RuntimeError, "Failed to load glfwGetX11Window"); return NULL; }
PyErr_SetString(PyExc_ValueError, "No OSWindow with the specified id found");
return NULL;
}
static PyObject*
get_primary_selection(PyObject UNUSED *self) {
if (glfwGetX11SelectionString) {
return Py_BuildValue("y", glfwGetX11SelectionString());
} else fprintf(stderr, "Failed to load glfwGetX11SelectionString\n");
Py_RETURN_NONE;
}
static PyObject*
set_primary_selection(PyObject UNUSED *self, PyObject *args) {
char *text;
if (!PyArg_ParseTuple(args, "s", &text)) return NULL;
if (glfwSetX11SelectionString) glfwSetX11SelectionString(text);
else fprintf(stderr, "Failed to load glfwSetX11SelectionString\n");
Py_RETURN_NONE;
}
static PyObject*
os_window_should_close(PyObject UNUSED *self, PyObject *args) {
int q = -1001;
@ -584,6 +623,10 @@ static PyMethodDef module_methods[] = {
METHODB(glfw_window_hint, METH_VARARGS),
METHODB(os_window_should_close, METH_VARARGS),
METHODB(os_window_swap_buffers, METH_VARARGS),
METHODB(get_primary_selection, METH_NOARGS),
METHODB(x11_display, METH_NOARGS),
METHODB(x11_window_id, METH_O),
METHODB(set_primary_selection, METH_VARARGS),
{"glfw_init", (PyCFunction)glfw_init, METH_VARARGS, ""},
{"glfw_terminate", (PyCFunction)glfw_terminate, METH_NOARGS, ""},
{"glfw_wait_events", (PyCFunction)glfw_wait_events, METH_VARARGS, ""},

View File

@ -17,13 +17,10 @@ from contextlib import contextmanager
from functools import lru_cache
from time import monotonic
from .constants import (
appname, isosx, iswayland, selection_clipboard_funcs, x11_display,
x11_window_id
)
from .constants import appname, isosx, iswayland
from .fast_data_types import (
GLSL_VERSION, glfw_get_physical_dpi, glfw_primary_monitor_content_scale,
redirect_std_streams, wcwidth as wcwidth_impl
redirect_std_streams, wcwidth as wcwidth_impl, x11_display, x11_window_id
)
from .rgb import Color, to_color
@ -75,43 +72,6 @@ def sanitize_title(x):
return re.sub(r'\s+', ' ', re.sub(r'[\0-\x19]', '', x))
@lru_cache()
def load_libx11():
import ctypes
from ctypes.util import find_library
libx11 = ctypes.CDLL(find_library('X11'))
def cdef(name, restype, *argtypes):
f = getattr(libx11, name)
if restype is not None:
f.restype = restype
if argtypes:
f.argtypes = argtypes
return f
return cdef('XResourceManagerString', ctypes.c_char_p, ctypes.c_void_p)
def parse_xrdb(raw):
q = 'Xft.dpi:\t'
for line in raw.decode('utf-8', 'replace').splitlines():
if line.startswith(q):
return float(line[len(q):])
def x11_dpi():
if iswayland:
return
XResourceManagerString = load_libx11()
display = x11_display()
if display:
try:
raw = XResourceManagerString(display)
return parse_xrdb(raw)
except Exception:
pass
def get_logical_dpi(override_dpi=None):
# See https://github.com/glfw/glfw/issues/1019 for why we cant use
# glfw_get_physical_dpi()
@ -122,14 +82,8 @@ def get_logical_dpi(override_dpi=None):
# TODO: Investigate if this needs a different implementation on OS X
get_logical_dpi.ans = glfw_get_physical_dpi()
else:
try:
xscale, yscale = glfw_primary_monitor_content_scale()
except NotImplementedError: # glfw < 3.3
xdpi = ydpi = x11_dpi()
if xdpi is None:
xdpi, ydpi = glfw_get_physical_dpi()
else:
xdpi, ydpi = xscale * 96.0, yscale * 96.0
xscale, yscale = glfw_primary_monitor_content_scale()
xdpi, ydpi = xscale * 96.0, yscale * 96.0
get_logical_dpi.ans = xdpi, ydpi
return get_logical_dpi.ans
@ -163,32 +117,19 @@ def parse_color_set(raw):
def set_primary_selection(text):
if isosx:
return # There is no primary selection on OS X
if isinstance(text, str):
text = text.encode('utf-8')
s = selection_clipboard_funcs()[1]
if s is None:
p = subprocess.Popen(['xsel', '-i', '-p'], stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
p.stdin.write(text), p.stdin.close()
p.wait()
else:
s(text)
if isosx or iswayland:
return # There is no primary selection
if isinstance(text, bytes):
text = text.decode('utf-8')
from kitty.fast_data_types import set_primary_selection
set_primary_selection(text)
def get_primary_selection():
if isosx:
return '' # There is no primary selection on OS X
g = selection_clipboard_funcs()[0]
if g is None:
# We cannot use check_output as we set a SIGCHLD handler to reap zombies
ans = subprocess.Popen(['xsel', '-p'], stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE).stdout.read().decode('utf-8')
if ans:
# Without this for some reason repeated pastes dont work
set_primary_selection(ans)
else:
ans = (g() or b'').decode('utf-8', 'replace')
return ans
if isosx or iswayland:
return '' # There is no primary selection
from kitty.fast_data_types import get_primary_selection
return (get_primary_selection() or b'').decode('utf-8', 'replace')
def base64_encode(