Work on migrating the code needed for application startup

This commit is contained in:
Kovid Goyal 2017-11-14 20:32:34 +05:30
parent eecd0c8d9a
commit e11a50ae83
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
9 changed files with 84 additions and 128 deletions

View File

@ -8,7 +8,7 @@ import ctypes
import sys
from collections import namedtuple
from .fast_data_types import set_boss as set_c_boss
from .fast_data_types import set_boss as set_c_boss, handle_for_window_id
appname = 'kitty'
version = (0, 5, 1)
@ -37,18 +37,6 @@ del _get_config_dir
defconf = os.path.join(config_dir, 'kitty.conf')
class ViewportSize:
__slots__ = ('width', 'height', 'x_ratio', 'y_ratio')
def __init__(self):
self.width = self.height = 1024
self.x_ratio = self.y_ratio = 1.0
def __repr__(self):
return '(width={}, height={}, x_ratio={}, y_ratio={})'.format(self.width, self.height, self.x_ratio, self.y_ratio)
def get_boss():
return get_boss.boss
@ -62,8 +50,6 @@ def wakeup():
get_boss.boss.child_monitor.wakeup()
viewport_size = ViewportSize()
cell_size = ViewportSize()
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
terminfo_dir = os.path.join(base_dir, 'terminfo')
logo_data_file = os.path.join(base_dir, 'logo', 'kitty.rgba')
@ -121,11 +107,11 @@ def selection_clipboard_funcs():
return ans
def x11_window_id(window):
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(window.window_id())
return lib.glfwGetX11Window(handle_for_window_id(window_id))
def x11_display():

View File

@ -14,6 +14,9 @@
#include <pthread.h>
#define PY_SSIZE_T_CLEAN
#include <Python.h>
// Required minimum OpenGL version
#define OPENGL_REQUIRED_VERSION_MAJOR 3
#define OPENGL_REQUIRED_VERSION_MINOR 3
#define UNUSED __attribute__ ((unused))
#define EXPORTED __attribute__ ((visibility ("default")))
#define LIKELY(x) __builtin_expect (!!(x), 1)

View File

@ -16,10 +16,7 @@
static char glbuf[4096];
// GL setup and error handling {{{
// Required minimum OpenGL version
#define REQUIRED_VERSION_MAJOR 3
#define REQUIRED_VERSION_MINOR 3
#define GLSL_VERSION (REQUIRED_VERSION_MAJOR * 100 + REQUIRED_VERSION_MINOR * 10)
#define GLSL_VERSION (OPENGL_REQUIRED_VERSION_MAJOR * 100 + OPENGL_REQUIRED_VERSION_MINOR * 10)
static void
check_for_gl_error(const char *name, void UNUSED *funcptr, int UNUSED len_args, ...) {
@ -47,11 +44,9 @@ check_for_gl_error(const char *name, void UNUSED *funcptr, int UNUSED len_args,
}
}
static PyObject*
gl_init(PyObject UNUSED *self, PyObject *args) {
int is_wayland, debug;
if (!PyArg_ParseTuple(args, "pp", &is_wayland, &debug)) return NULL;
if (!init_glad((GLADloadproc) glfwGetProcAddress, debug)) {
void
gl_init() {
if (!init_glad((GLADloadproc) glfwGetProcAddress, global_state.debug_gl)) {
fatal("Loading the OpenGL library failed");
}
glad_set_post_callback(check_for_gl_error);
@ -62,7 +57,6 @@ gl_init(PyObject UNUSED *self, PyObject *args) {
ARB_TEST(texture_storage);
#undef ARB_TEST
glEnable(GL_BLEND);
Py_RETURN_NONE;
}
void

View File

@ -157,6 +157,15 @@ set_mouse_cursor(MouseShape type) {
}
}
static GLFWimage logo = {0};
static PyObject*
set_default_window_icon(PyObject UNUSED *self, PyObject *args) {
Py_ssize_t sz;
if(!PyArg_ParseTuple(args, "s#ii", &(logo.pixels), &sz, &(logo.width), &(logo.height))) return NULL;
Py_RETURN_NONE;
}
static PyObject*
create_new_os_window(PyObject UNUSED *self, PyObject *args) {
int width, height;
@ -164,11 +173,24 @@ create_new_os_window(PyObject UNUSED *self, PyObject *args) {
if (!PyArg_ParseTuple(args, "iis", &width, &height, &title)) return NULL;
if (standard_cursor == NULL) {
// The first window to be created
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, OPENGL_REQUIRED_VERSION_MAJOR);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, OPENGL_REQUIRED_VERSION_MINOR);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, true);
glfwWindowHint(GLFW_SAMPLES, 0);
glfwSwapInterval(0); // a value of 1 makes mouse selection laggy
#ifdef __APPLE__
if (OPT(macos_hide_titlebar)) glfwWindowHint(GLFW_DECORATED, False)
// OS X cannot handle 16bit stencil buffers
glfwWindowHint(GLFW_STENCIL_BITS, 8)
#else
#endif
standard_cursor = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
click_cursor = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
arrow_cursor = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
if (standard_cursor == NULL || click_cursor == NULL || arrow_cursor == NULL) {
Py_CLEAR(self); PyErr_SetString(PyExc_ValueError, "Failed to create standard mouse cursors"); return NULL; }
PyErr_SetString(PyExc_ValueError, "Failed to create standard mouse cursors"); return NULL; }
}
if (global_state.num_os_windows >= MAX_CHILDREN) {
@ -176,7 +198,12 @@ create_new_os_window(PyObject UNUSED *self, PyObject *args) {
return NULL;
}
GLFWwindow *glfw_window = glfwCreateWindow(width, height, title, NULL, global_state.num_os_windows ? global_state.os_windows[0].handle : NULL);
if (glfw_window == NULL) { Py_CLEAR(self); PyErr_SetString(PyExc_ValueError, "Failed to create GLFWwindow"); return NULL; }
if (glfw_window == NULL) {
fprintf(stderr, "Failed to create a window at size: %dx%d, using a standard size instead.\n", width, height);
glfw_window = glfwCreateWindow(640, 400, title, NULL, global_state.num_os_windows ? global_state.os_windows[0].handle : NULL);
}
if (glfw_window == NULL) { PyErr_SetString(PyExc_ValueError, "Failed to create GLFWwindow"); return NULL; }
if (logo.pixels && logo.width && logo.height) glfwSetWindowIcon(glfw_window, 1, &logo);
OSWindow *w = add_os_window();
w->id = global_state.os_window_counter++;
glfwSetWindowUserPointer(glfw_window, w);
@ -224,22 +251,6 @@ glfw_terminate(PyObject UNUSED *self) {
Py_RETURN_NONE;
}
PyObject*
glfw_window_hint(PyObject UNUSED *self, PyObject *args) {
int hint, value;
if (!PyArg_ParseTuple(args, "ii", &hint, &value)) return NULL;
glfwWindowHint(hint, value);
Py_RETURN_NONE;
}
PyObject*
glfw_swap_interval(PyObject UNUSED *self, PyObject *args) {
int value;
if (!PyArg_ParseTuple(args, "i", &value)) return NULL;
glfwSwapInterval(value);
Py_RETURN_NONE;
}
PyObject*
glfw_wait_events(PyObject UNUSED *self, PyObject *args) {
double time = -1;
@ -408,10 +419,15 @@ hide_mouse(OSWindow *w) {
glfwSetInputMode(w->handle, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
}
static OSWindow *current_ctx_window = NULL;
void
make_window_context_current(OSWindow *w) {
if (current_ctx_window != w) {
glfwMakeContextCurrent(w->handle);
current_ctx_window = w;
if (w->viewport_size_dirty) update_viewport_size(w->viewport_width, w->viewport_height);
}
}
void
@ -471,14 +487,13 @@ primary_monitor_content_scale(PyObject UNUSED *self) {
static PyMethodDef module_methods[] = {
METHODB(create_new_os_window, METH_VARARGS),
METHODB(set_default_window_icon, METH_VARARGS),
METHODB(get_clipboard_string, METH_NOARGS),
METHODB(get_content_scale_for_window, METH_NOARGS),
METHODB(set_clipboard_string, METH_VARARGS),
METHODB(toggle_fullscreen, METH_NOARGS),
{"glfw_init", (PyCFunction)glfw_init, METH_NOARGS, ""},
{"glfw_terminate", (PyCFunction)glfw_terminate, METH_NOARGS, ""},
{"glfw_window_hint", (PyCFunction)glfw_window_hint, METH_VARARGS, ""},
{"glfw_swap_interval", (PyCFunction)glfw_swap_interval, METH_VARARGS, ""},
{"glfw_wait_events", (PyCFunction)glfw_wait_events, METH_VARARGS, ""},
{"glfw_post_empty_event", (PyCFunction)glfw_post_empty_event, METH_NOARGS, ""},
{"glfw_get_physical_dpi", (PyCFunction)glfw_get_physical_dpi, METH_NOARGS, ""},

View File

@ -5,7 +5,7 @@
from collections import namedtuple
from itertools import islice
from .constants import WindowGeometry, viewport_size, cell_size, get_boss
from .constants import WindowGeometry, get_boss
from .utils import pt_to_px

View File

@ -15,21 +15,17 @@ from .config import (
cached_values, load_cached_values, load_config, save_cached_values
)
from .constants import (
appname, defconf, isosx, iswayland, logo_data_file, str_version,
viewport_size
appname, defconf, isosx, iswayland, logo_data_file, str_version
)
from .fast_data_types import (
GL_VERSION_REQUIRED, GLFW_CONTEXT_VERSION_MAJOR,
GLFW_CONTEXT_VERSION_MINOR, GLFW_DECORATED, GLFW_OPENGL_CORE_PROFILE,
GLFW_OPENGL_FORWARD_COMPAT, GLFW_OPENGL_PROFILE, GLFW_SAMPLES,
GLFW_STENCIL_BITS, GLFWWindow, change_wcwidth, clear_buffers, gl_init,
glfw_init, glfw_init_hint_string, glfw_swap_interval, glfw_terminate,
glfw_window_hint, install_sigchld_handler, set_logical_dpi, set_options
change_wcwidth, create_os_window, glfw_init, glfw_init_hint_string,
glfw_terminate, install_sigchld_handler, set_default_window_icon,
set_logical_dpi, set_options
)
from .fonts.box_drawing import set_scale
from .layout import all_layouts
from .utils import (
color_as_int, detach, end_startup_notification, get_logical_dpi,
detach, end_startup_notification, get_logical_dpi,
init_startup_notification, safe_print
)
@ -142,73 +138,34 @@ def option_parser():
return parser
def setup_opengl(opts):
if opts.macos_hide_titlebar:
glfw_window_hint(GLFW_DECORATED, False)
glfw_window_hint(GLFW_CONTEXT_VERSION_MAJOR, GL_VERSION_REQUIRED[0])
glfw_window_hint(GLFW_CONTEXT_VERSION_MINOR, GL_VERSION_REQUIRED[1])
glfw_window_hint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE)
glfw_window_hint(GLFW_OPENGL_FORWARD_COMPAT, True)
glfw_window_hint(GLFW_SAMPLES, 0)
if isosx:
# OS X cannot handle 16bit stencil buffers
glfw_window_hint(GLFW_STENCIL_BITS, 8)
def initialize_window(window, opts, debug_gl=False):
viewport_size.width, viewport_size.height = window.get_framebuffer_size()
w, h = window.get_window_size()
viewport_size.x_ratio = viewport_size.width / float(w)
viewport_size.y_ratio = viewport_size.height / float(h)
gl_init(iswayland, debug_gl)
glfw_swap_interval(0)
clear_buffers(window.swap_buffers, color_as_int(opts.background))
# We dont turn this on as it causes rendering performance to be much worse,
# for example, dragging the mouse to select is laggy
# glfw_swap_interval(1)
def run_app(opts, args):
set_options(opts)
setup_opengl(opts)
set_scale(opts.box_drawing_scale)
set_options(opts, iswayland, args.debug_gl)
load_cached_values()
w, h = opts.initial_window_width, opts.initial_window_height
if 'window-size' in cached_values and opts.remember_window_size:
ws = cached_values['window-size']
try:
viewport_size.width, viewport_size.height = map(int, ws)
w, h = map(int, ws)
except Exception:
safe_print('Invalid cached window size, ignoring', file=sys.stderr)
viewport_size.width = max(100, viewport_size.width)
viewport_size.height = max(80, viewport_size.height)
else:
viewport_size.width = opts.initial_window_width
viewport_size.height = opts.initial_window_height
try:
window = GLFWWindow(viewport_size.width, viewport_size.height, args.cls)
except ValueError:
safe_print('Failed to create GLFW window with initial size:', viewport_size)
viewport_size.width = 640
viewport_size.height = 400
window = GLFWWindow(viewport_size.width, viewport_size.height, args.cls)
startup_ctx = init_startup_notification(window)
window_id = create_os_window(w, h, args.cls)
startup_ctx = init_startup_notification(window_id)
if isosx:
from .fast_data_types import cocoa_create_global_menu, cocoa_init
cocoa_init()
cocoa_create_global_menu()
elif not iswayland: # no window icons on wayland
with open(logo_data_file, 'rb') as f:
window.set_icon(f.read(), 256, 256)
set_default_window_icon(f.read(), 256, 256)
set_logical_dpi(*get_logical_dpi())
initialize_window(window, opts, args.debug_gl)
boss = Boss(window, opts, args)
boss = Boss(window_id, opts, args)
boss.start()
end_startup_notification(startup_ctx)
try:
boss.child_monitor.main_loop()
finally:
boss.destroy()
del window
cached_values['window-size'] = viewport_size.width, viewport_size.height
save_cached_values()

View File

@ -541,25 +541,9 @@ PYWRAP1(layout_sprite_map) {
Py_RETURN_NONE;
}
PYWRAP1(clear_buffers) {
PyObject *swap_buffers;
unsigned int bg;
PA("OI", &swap_buffers, &bg);
#define C(shift) ((float)((bg >> shift) & 0xff)) / 255.0
glClearColor(C(16), C(8), C(0), 1);
#undef C
glClear(GL_COLOR_BUFFER_BIT);
PyObject *ret = PyObject_CallFunctionObjArgs(swap_buffers, NULL);
if (ret == NULL) return NULL;
Py_DECREF(ret);
glClear(GL_COLOR_BUFFER_BIT);
Py_RETURN_NONE;
}
#define M(name, arg_type) {#name, (PyCFunction)name, arg_type, NULL}
#define MW(name, arg_type) {#name, (PyCFunction)py##name, arg_type, NULL}
static PyMethodDef module_methods[] = {
M(gl_init, METH_VARARGS),
M(compile_program, METH_VARARGS),
MW(create_vao, METH_NOARGS),
MW(remove_vao, METH_O),
@ -577,7 +561,6 @@ static PyMethodDef module_methods[] = {
MW(create_graphics_vao, METH_NOARGS),
MW(layout_sprite_map, METH_VARARGS),
MW(destroy_sprite_map, METH_NOARGS),
MW(clear_buffers, METH_VARARGS),
{NULL, NULL, 0, NULL} /* Sentinel */
};
@ -614,7 +597,6 @@ init_shaders(PyObject *module) {
C(GL_BLEND); C(GL_FLOAT); C(GL_UNSIGNED_INT); C(GL_ARRAY_BUFFER); C(GL_UNIFORM_BUFFER);
#undef C
PyModule_AddObject(module, "GL_VERSION_REQUIRED", Py_BuildValue("II", REQUIRED_VERSION_MAJOR, REQUIRED_VERSION_MINOR));
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
return true;
}

View File

@ -200,9 +200,23 @@ set_special_keys(PyObject *dict) {
}}
}
PYWRAP1(handle_for_window_id) {
id_type os_window_id;
PA("K", &os_window_id);
WITH_OS_WINDOW(os_window_id)
return PyLong_FromVoidPtr(os_window->handle);
END_WITH_OS_WINDOW
PyErr_SetString(PyExc_ValueError, "No such window");
return NULL;
}
PYWRAP1(set_options) {
PyObject *ret;
#define GA(name) ret = PyObject_GetAttrString(args, #name); if (ret == NULL) return NULL;
PyObject *ret, *opts;
int is_wayland, debug_gl = 0;
PA("Op|p", &opts, &is_wayland, &debug_gl);
global_state.is_wayland = is_wayland ? true : false;
global_state.debug_gl = debug_gl ? true : false;
#define GA(name) ret = PyObject_GetAttrString(opts, #name); if (ret == NULL) return NULL;
#define S(name, convert) { GA(name); global_state.opts.name = convert(ret); Py_DECREF(ret); if (PyErr_Occurred()) return NULL; }
S(visual_bell_duration, PyFloat_AsDouble);
S(enable_audio_bell, PyObject_IsTrue);
@ -215,12 +229,13 @@ PYWRAP1(set_options) {
S(open_url_modifiers, PyLong_AsUnsignedLong);
S(click_interval, PyFloat_AsDouble);
S(url_color, color_as_int);
S(background, color_as_int);
S(repaint_delay, repaint_delay);
S(input_delay, repaint_delay);
S(macos_option_as_alt, PyObject_IsTrue);
S(macos_hide_titlebar, PyObject_IsTrue);
PyObject *chars = PyObject_GetAttrString(args, "select_by_word_characters");
PyObject *chars = PyObject_GetAttrString(opts, "select_by_word_characters");
if (chars == NULL) return NULL;
for (size_t i = 0; i < MIN((size_t)PyUnicode_GET_LENGTH(chars), sizeof(OPT(select_by_word_characters))/sizeof(OPT(select_by_word_characters[0]))); i++) {
OPT(select_by_word_characters)[i] = PyUnicode_READ(PyUnicode_KIND(chars), PyUnicode_DATA(chars), i);
@ -231,7 +246,7 @@ PYWRAP1(set_options) {
GA(keymap); set_special_keys(ret);
Py_DECREF(ret); if (PyErr_Occurred()) return NULL;
PyObject *al = PyObject_GetAttrString(args, "adjust_line_height");
PyObject *al = PyObject_GetAttrString(opts, "adjust_line_height");
if (PyFloat_Check(al)) {
OPT(adjust_line_height_frac) = (float)PyFloat_AsDouble(al);
OPT(adjust_line_height_px) = 0;
@ -326,6 +341,7 @@ KKII(swap_windows)
static PyMethodDef module_methods[] = {
MW(set_options, METH_O),
MW(handle_for_window_id, METH_VARARGS),
MW(set_logical_dpi, METH_VARARGS),
MW(add_tab, METH_O),
MW(add_window, METH_VARARGS),

View File

@ -16,7 +16,7 @@ typedef struct {
CursorShape cursor_shape;
unsigned int open_url_modifiers;
char_type select_by_word_characters[256]; size_t select_by_word_characters_count;
color_type url_color;
color_type url_color, background;
double repaint_delay, input_delay;
bool focus_follows_mouse;
bool macos_option_as_alt, macos_hide_titlebar;
@ -102,6 +102,8 @@ typedef struct {
size_t num_os_windows, capacity;
OSWindow *callback_os_window, *focused_os_window;
bool close_all_windows;
bool is_wayland;
bool debug_gl;
} GlobalState;
extern GlobalState global_state;
@ -112,6 +114,7 @@ extern GlobalState global_state;
else Py_DECREF(cret_); \
}
void gl_init();
void mark_os_window_for_close(OSWindow* w, bool yes);
bool should_os_window_close(OSWindow* w);
bool should_os_window_be_rendered(OSWindow* w);