From e558880e8f48860b051e3c116dbb8647fe3fe575 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 18 Oct 2017 12:46:32 +0530 Subject: [PATCH] Load glfw primary selection functions dynamically Allows kitty to run on wayland. Also dont try to set the window icon on wayland. --- kitty/constants.py | 44 ++++++++++++++++++++++++++++++++++++++++ kitty/data-types.c | 2 -- kitty/main.py | 5 +++-- kitty/utils.py | 47 +++++++++++++++++++++++-------------------- kitty/x11.c | 50 ---------------------------------------------- 5 files changed, 72 insertions(+), 76 deletions(-) delete mode 100644 kitty/x11.c diff --git a/kitty/constants.py b/kitty/constants.py index fcbd65e7a..f486160ce 100644 --- a/kitty/constants.py +++ b/kitty/constants.py @@ -75,3 +75,47 @@ 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/{}/maps'.format(os.getpid())): + 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 + + +iswayland = False +if not isosx: + iswayland = selection_clipboard_funcs()[0] is None diff --git a/kitty/data-types.c b/kitty/data-types.c index ccc945d26..2bc538c09 100644 --- a/kitty/data-types.c +++ b/kitty/data-types.c @@ -139,7 +139,6 @@ extern bool init_keys(PyObject *module); extern bool init_graphics(PyObject *module); extern bool init_shaders(PyObject *module); extern bool init_shaders_debug(PyObject *module); -extern bool init_x11_funcs(PyObject *module); #ifdef __APPLE__ extern int init_CoreText(PyObject *); extern bool init_cocoa(PyObject *module); @@ -181,7 +180,6 @@ PyInit_fast_data_types(void) { if (!init_Face(m)) return NULL; if (!init_freetype_library(m)) return NULL; if (!init_fontconfig_library(m)) return NULL; - if (!init_x11_funcs(m)) return NULL; #endif #define OOF(n) #n, offsetof(Cell, n) diff --git a/kitty/main.py b/kitty/main.py index 64e4721f1..ae7147659 100644 --- a/kitty/main.py +++ b/kitty/main.py @@ -14,7 +14,8 @@ from .config import ( cached_values, load_cached_values, load_config, save_cached_values ) from .constants import ( - appname, config_dir, isosx, logo_data_file, str_version, viewport_size + appname, config_dir, isosx, iswayland, logo_data_file, str_version, + viewport_size ) from .fast_data_types import ( GL_VERSION_REQUIRED, GLFW_CONTEXT_VERSION_MAJOR, @@ -183,7 +184,7 @@ def run_app(opts, args): cocoa_create_global_menu() if opts.macos_hide_titlebar: cocoa_make_window_resizable(window.cocoa_window_id()) - else: + elif not iswayland: # no window icons on wayland with open(logo_data_file, 'rb') as f: window.set_icon(f.read(), 256, 256) set_logical_dpi(*get_logical_dpi()) diff --git a/kitty/utils.py b/kitty/utils.py index c46e4f61c..35699ba35 100644 --- a/kitty/utils.py +++ b/kitty/utils.py @@ -12,8 +12,11 @@ from contextlib import contextmanager from functools import lru_cache from time import monotonic -from .constants import isosx -from .fast_data_types import glfw_get_physical_dpi, wcwidth as wcwidth_impl, redirect_std_streams, GLSL_VERSION +from .constants import isosx, iswayland, selection_clipboard_funcs +from .fast_data_types import ( + GLSL_VERSION, glfw_get_physical_dpi, redirect_std_streams, + wcwidth as wcwidth_impl +) from .rgb import Color, to_color BASE = os.path.dirname(os.path.abspath(__file__)) @@ -118,8 +121,8 @@ def x11_dpi(): def get_logical_dpi(): if not hasattr(get_logical_dpi, 'ans'): - if isosx: - # TODO: Investigate if this needs a different implementation on OS X + if isosx or iswayland: + # TODO: Investigate if this needs a different implementation on OS X or Wayland get_logical_dpi.ans = glfw_get_physical_dpi() else: # See https://github.com/glfw/glfw/issues/1019 for why we cant use @@ -160,17 +163,31 @@ def parse_color_set(raw): continue +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=open(os.devnull, 'wb'), stderr=subprocess.STDOUT) + p.stdin.write(text), p.stdin.close() + p.wait() + else: + s(text) + + def get_primary_selection(): if isosx: return '' # There is no primary selection on OS X - try: - from .fast_data_types import get_selection_x11 - ans = (get_selection_x11() or b'').decode('utf-8', 'replace') - except ImportError: + g = selection_clipboard_funcs()[0] + if g is None: ans = subprocess.check_output(['xsel', '-p'], stderr=open(os.devnull, 'wb'), stdin=open(os.devnull, 'rb')).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 @@ -188,20 +205,6 @@ def base64_encode( return ans -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') - try: - from .fast_data_types import set_selection_x11 - set_selection_x11(text) - except ImportError: - p = subprocess.Popen(['xsel', '-i', '-p'], stdin=subprocess.PIPE, stdout=open(os.devnull, 'wb'), stderr=subprocess.STDOUT) - p.stdin.write(text), p.stdin.close() - p.wait() - - def open_url(url, program='default'): if program == 'default': cmd = ['open'] if isosx else ['xdg-open'] diff --git a/kitty/x11.c b/kitty/x11.c deleted file mode 100644 index 46acdd34b..000000000 --- a/kitty/x11.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * x11.c - * Copyright (C) 2017 Kovid Goyal - * - * Distributed under terms of the GPL3 license. - */ - -#include -#include -#include -#if GLFW_VERSION_MAJOR > 3 || (GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR > 2) -#define HAS_X11_SELECTION -#endif - -#ifdef HAS_X11_SELECTION -#define GLFW_EXPOSE_NATIVE_X11 -#include - -static PyObject* -get_selection_x11(PyObject *self) { - (void)(self); - return Py_BuildValue("y", glfwGetX11SelectionString()); -} - -static PyObject* -set_selection_x11(PyObject *self, PyObject *args) { - (void)(self); - const char *data; - if (!PyArg_ParseTuple(args, "y", &data)) return NULL; - glfwSetX11SelectionString(data); - Py_RETURN_NONE; -} - -static PyMethodDef sel_methods[] = { - {"get_selection_x11", (PyCFunction)get_selection_x11, METH_NOARGS, ""}, - {"set_selection_x11", (PyCFunction)set_selection_x11, METH_VARARGS, ""}, - {NULL, NULL, 0, NULL} /* Sentinel */ -}; - - -#endif - -bool -init_x11_funcs(PyObject *module) { - (void)(module); -#ifdef HAS_X11_SELECTION - if (PyModule_AddFunctions(module, sel_methods) != 0) return false; -#endif - return true; -}