Track window and application titles in C
Allows removing of the last bit fo python from the render loop
This commit is contained in:
parent
c41ede4d20
commit
6d8b59cb61
@ -8,7 +8,7 @@ from weakref import WeakValueDictionary
|
||||
from .char_grid import load_shader_programs
|
||||
from .config import MINIMUM_FONT_SIZE
|
||||
from .constants import (
|
||||
MODIFIER_KEYS, cell_size, is_key_pressed, isosx, mouse_button_pressed,
|
||||
MODIFIER_KEYS, cell_size, is_key_pressed, mouse_button_pressed,
|
||||
mouse_cursor_pos, set_boss, viewport_size, wakeup
|
||||
)
|
||||
from .fast_data_types import (
|
||||
@ -24,9 +24,6 @@ from .session import create_session
|
||||
from .tabs import SpecialWindow, TabManager
|
||||
from .utils import safe_print
|
||||
|
||||
if isosx:
|
||||
from .fast_data_types import cocoa_update_title
|
||||
|
||||
|
||||
class Timers(_Timers):
|
||||
|
||||
@ -96,7 +93,7 @@ class Boss:
|
||||
self.ui_timers = Timers()
|
||||
self.child_monitor = ChildMonitor(
|
||||
opts.repaint_delay / 1000.0, glfw_window.window_id(),
|
||||
self.on_child_death, self.ui_timers, self.render,
|
||||
self.on_child_death, self.ui_timers,
|
||||
DumpCommands(args) if args.dump_commands or args.dump_bytes else None)
|
||||
set_boss(self)
|
||||
self.current_font_size = opts.font_size
|
||||
@ -321,16 +318,6 @@ class Boss:
|
||||
except AttributeError:
|
||||
pass # needs glfw 3.3
|
||||
|
||||
def render(self):
|
||||
tab = self.active_tab
|
||||
if tab is None:
|
||||
return
|
||||
if tab.title != self.glfw_window_title:
|
||||
self.glfw_window_title = tab.title
|
||||
self.glfw_window.set_title(self.glfw_window_title)
|
||||
if isosx:
|
||||
cocoa_update_title(self.glfw_window_title)
|
||||
|
||||
def gui_close_window(self, window):
|
||||
window.destroy()
|
||||
for tab in self.tab_manager:
|
||||
|
||||
@ -112,12 +112,12 @@ self_pipe(int fds[2]) {
|
||||
static PyObject *
|
||||
new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
||||
ChildMonitor *self;
|
||||
PyObject *dump_callback, *death_notify, *timers, *wid, *render_func;
|
||||
PyObject *dump_callback, *death_notify, *timers, *wid;
|
||||
int ret;
|
||||
double repaint_delay;
|
||||
|
||||
if (created) { PyErr_SetString(PyExc_RuntimeError, "Can have only a single ChildMonitor instance"); return NULL; }
|
||||
if (!PyArg_ParseTuple(args, "dOOOOO", &repaint_delay, &wid, &death_notify, &timers, &render_func, &dump_callback)) return NULL;
|
||||
if (!PyArg_ParseTuple(args, "dOOOO", &repaint_delay, &wid, &death_notify, &timers, &dump_callback)) return NULL;
|
||||
glfw_window_id = PyLong_AsVoidPtr(wid);
|
||||
created = true;
|
||||
if ((ret = pthread_mutex_init(&children_lock, NULL)) != 0) {
|
||||
@ -133,7 +133,6 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
||||
self = (ChildMonitor *)type->tp_alloc(type, 0);
|
||||
if (self == NULL) return PyErr_NoMemory();
|
||||
self->death_notify = death_notify; Py_INCREF(death_notify);
|
||||
self->render_func = render_func; Py_INCREF(self->render_func);
|
||||
self->timers = (Timers*)timers; Py_INCREF(timers);
|
||||
if (dump_callback != Py_None) {
|
||||
self->dump_callback = dump_callback; Py_INCREF(dump_callback);
|
||||
@ -153,7 +152,6 @@ dealloc(ChildMonitor* self) {
|
||||
Py_CLEAR(self->dump_callback);
|
||||
Py_CLEAR(self->death_notify);
|
||||
Py_CLEAR(self->timers);
|
||||
Py_CLEAR(self->render_func);
|
||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||
while (remove_queue_count) {
|
||||
remove_queue_count--;
|
||||
@ -430,13 +428,15 @@ draw_cells_func draw_cells = NULL;
|
||||
draw_cursor_func draw_cursor = NULL;
|
||||
|
||||
static inline double
|
||||
cursor_width(unsigned int w, bool vert) {
|
||||
cursor_width(double w, bool vert) {
|
||||
double dpi = vert ? global_state.logical_dpi_x : global_state.logical_dpi_y;
|
||||
double ans = w * dpi / 72.0; // as pixels
|
||||
double factor = 2.0 / (vert ? global_state.viewport_width : global_state.viewport_height);
|
||||
return ans * factor;
|
||||
}
|
||||
|
||||
extern void cocoa_update_title(PyObject*);
|
||||
|
||||
static inline void
|
||||
render_cursor(ChildMonitor *self, Window *w, double now) {
|
||||
ScreenRenderData *rd = &w->render_data;
|
||||
@ -470,7 +470,6 @@ render_cursor(ChildMonitor *self, Window *w, double now) {
|
||||
|
||||
static inline bool
|
||||
render(ChildMonitor *self, double *timeout, double now) {
|
||||
PyObject *ret;
|
||||
double time_since_last_render = now - last_render_at;
|
||||
if (time_since_last_render > self->repaint_delay) {
|
||||
draw_borders();
|
||||
@ -486,12 +485,15 @@ render(ChildMonitor *self, double *timeout, double now) {
|
||||
}
|
||||
Window *w = tab->windows + tab->active_window;
|
||||
if (w->visible && WD.screen) render_cursor(self, w, now);
|
||||
if (w->title && w->title != global_state.application_title) {
|
||||
global_state.application_title = w->title;
|
||||
glfwSetWindowTitle(glfw_window_id, PyUnicode_AsUTF8(w->title));
|
||||
#ifdef __APPLE__
|
||||
cocoa_update_title(w->title);
|
||||
#endif
|
||||
}
|
||||
#undef WD
|
||||
}
|
||||
|
||||
ret = PyObject_CallFunctionObjArgs(self->render_func, NULL);
|
||||
if (ret == NULL) { PyErr_Print(); return false; }
|
||||
else Py_DECREF(ret);
|
||||
glfwSwapBuffers(glfw_window_id);
|
||||
last_render_at = now;
|
||||
} else {
|
||||
@ -548,8 +550,6 @@ cm_thread_write(PyObject UNUSED *self, PyObject *args) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
extern void hide_mouse_cursor();
|
||||
|
||||
static PyObject*
|
||||
main_loop(ChildMonitor *self) {
|
||||
#define main_loop_doc "The main thread loop"
|
||||
@ -558,7 +558,10 @@ main_loop(ChildMonitor *self) {
|
||||
while (!glfwWindowShouldClose(glfw_window_id)) {
|
||||
double now = monotonic();
|
||||
if (!render(self, &timeout, now)) break;
|
||||
if (global_state.mouse_visible && OPT(mouse_hide_wait) > 0 && now - global_state.last_mouse_activity_at > OPT(mouse_hide_wait)) hide_mouse_cursor();
|
||||
if (global_state.mouse_visible && OPT(mouse_hide_wait) > 0 && now - global_state.last_mouse_activity_at > OPT(mouse_hide_wait)) {
|
||||
glfwSetInputMode(glfw_window_id, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||
global_state.mouse_visible = false;
|
||||
}
|
||||
t = timers_timeout(self->timers);
|
||||
timeout = MIN(timeout, t);
|
||||
if (timeout < 0) glfwWaitEvents();
|
||||
|
||||
@ -131,8 +131,8 @@ cocoa_create_global_menu(PyObject UNUSED *_self) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyObject*
|
||||
cocoa_update_title(PyObject UNUSED *self, PyObject *pytitle) {
|
||||
void
|
||||
cocoa_update_title(PyObject *pytitle) {
|
||||
NSString *title = [[NSString alloc] initWithUTF8String:PyUnicode_AsUTF8(pytitle)];
|
||||
NSMenu *bar = [NSApp mainMenu];
|
||||
if (title_menu != NULL) {
|
||||
@ -178,7 +178,6 @@ static PyMethodDef module_methods[] = {
|
||||
{"cocoa_get_lang", (PyCFunction)cocoa_get_lang, METH_NOARGS, ""}, \
|
||||
{"cocoa_make_window_resizable", (PyCFunction)cocoa_make_window_resizable, METH_O, ""}, \
|
||||
{"cocoa_create_global_menu", (PyCFunction)cocoa_create_global_menu, METH_NOARGS, ""}, \
|
||||
{"cocoa_update_title", (PyCFunction)cocoa_update_title, METH_O, ""},
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
||||
@ -278,7 +278,7 @@ PyTypeObject Timers_Type;
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
|
||||
PyObject *dump_callback, *update_screen, *death_notify, *render_func;
|
||||
PyObject *dump_callback, *update_screen, *death_notify;
|
||||
Timers *timers;
|
||||
double repaint_delay;
|
||||
unsigned int count;
|
||||
|
||||
10
kitty/glfw.c
10
kitty/glfw.c
@ -331,15 +331,6 @@ set_window_icon(WindowWrapper *self, PyObject *args) {
|
||||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
_set_title(WindowWrapper *self, PyObject *args) {
|
||||
char *title;
|
||||
if(!PyArg_ParseTuple(args, "s", &title)) return NULL;
|
||||
glfwSetWindowTitle(self->window, title);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
get_framebuffer_size(WindowWrapper *self) {
|
||||
int w, h;
|
||||
@ -437,7 +428,6 @@ static PyMethodDef methods[] = {
|
||||
MND(set_clipboard_string, METH_VARARGS),
|
||||
MND(make_context_current, METH_NOARGS),
|
||||
MND(window_id, METH_NOARGS),
|
||||
{"set_title", (PyCFunction)_set_title, METH_VARARGS, ""},
|
||||
{"set_icon", (PyCFunction)set_window_icon, METH_VARARGS, ""},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
@ -175,7 +175,6 @@ def run_app(opts, args):
|
||||
viewport_size.width = 640
|
||||
viewport_size.height = 400
|
||||
window = GLFWWindow(viewport_size.width, viewport_size.height, args.cls)
|
||||
window.set_title(appname)
|
||||
window.make_context_current()
|
||||
if isosx:
|
||||
from .fast_data_types import cocoa_make_window_resizable, cocoa_create_global_menu
|
||||
|
||||
@ -40,16 +40,32 @@ add_tab(unsigned int id) {
|
||||
}
|
||||
|
||||
static inline void
|
||||
add_window(unsigned int tab_id, unsigned int id) {
|
||||
add_window(unsigned int tab_id, unsigned int id, PyObject *title) {
|
||||
WITH_TAB(tab_id);
|
||||
ensure_can_add(tab->windows, tab->num_windows, "Too many children (add_window)");
|
||||
tab->windows[tab->num_windows] = EMPTY_WINDOW;
|
||||
tab->windows[tab->num_windows].id = id;
|
||||
tab->windows[tab->num_windows].visible = true;
|
||||
tab->windows[tab->num_windows].title = title;
|
||||
Py_INCREF(tab->windows[tab->num_windows].title);
|
||||
tab->num_windows++;
|
||||
END_WITH_TAB;
|
||||
}
|
||||
|
||||
static inline void
|
||||
update_window_title(unsigned int tab_id, unsigned int window_id, PyObject *title) {
|
||||
WITH_TAB(tab_id);
|
||||
for (size_t i = 0; i < tab->num_windows; i++) {
|
||||
if (tab->windows[i].id == window_id) {
|
||||
Py_CLEAR(tab->windows[i].title);
|
||||
tab->windows[i].title = title;
|
||||
Py_INCREF(tab->windows[i].title);
|
||||
break;
|
||||
}
|
||||
}
|
||||
END_WITH_TAB;
|
||||
}
|
||||
|
||||
static inline void
|
||||
remove_tab(unsigned int id) {
|
||||
REMOVER(global_state.tabs, id, global_state.num_tabs, EMPTY_TAB, Tab, noop);
|
||||
@ -58,7 +74,7 @@ remove_tab(unsigned int id) {
|
||||
static inline void
|
||||
remove_window(unsigned int tab_id, unsigned int id) {
|
||||
WITH_TAB(tab_id);
|
||||
#define destroy_window(w) Py_CLEAR(w.render_data.screen)
|
||||
#define destroy_window(w) Py_CLEAR(w.render_data.screen); Py_CLEAR(w.title);
|
||||
REMOVER(tab->windows, id, tab->num_windows, EMPTY_WINDOW, Window, destroy_window);
|
||||
#undef destroy_window
|
||||
END_WITH_TAB;
|
||||
@ -159,8 +175,17 @@ PYWRAP0(destroy_global_data) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
#define WF(name) PYWRAP1(name) { \
|
||||
unsigned int tab_id, window_id; \
|
||||
PyObject *title; \
|
||||
PA("IIO", &tab_id, &window_id, &title); \
|
||||
name(tab_id, window_id, title); \
|
||||
Py_RETURN_NONE; \
|
||||
}
|
||||
WF(add_window)
|
||||
WF(update_window_title)
|
||||
|
||||
ONE_UINT(add_tab)
|
||||
TWO_UINT(add_window)
|
||||
ONE_UINT(remove_tab)
|
||||
TWO_UINT(remove_window)
|
||||
ONE_UINT(set_active_tab)
|
||||
@ -176,6 +201,7 @@ static PyMethodDef module_methods[] = {
|
||||
MW(set_logical_dpi, METH_VARARGS),
|
||||
MW(add_tab, METH_O),
|
||||
MW(add_window, METH_VARARGS),
|
||||
MW(update_window_title, METH_VARARGS),
|
||||
MW(remove_tab, METH_O),
|
||||
MW(remove_window, METH_VARARGS),
|
||||
MW(set_active_tab, METH_O),
|
||||
|
||||
@ -25,6 +25,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
unsigned int id;
|
||||
bool visible;
|
||||
PyObject *title;
|
||||
ScreenRenderData render_data;
|
||||
} Window;
|
||||
|
||||
@ -43,6 +44,7 @@ typedef struct {
|
||||
double cursor_blink_zero_time, last_mouse_activity_at;
|
||||
double logical_dpi_x, logical_dpi_y;
|
||||
int viewport_width, viewport_height;
|
||||
PyObject *application_title;
|
||||
} GlobalState;
|
||||
|
||||
#define EXTERNAL_FUNC(name, ret, ...) typedef ret (*name##_func)(__VA_ARGS__); extern name##_func name
|
||||
|
||||
@ -127,7 +127,7 @@ class Tab: # {{{
|
||||
window.title = window.override_title = override_title
|
||||
# Must add child before laying out so that resize_pty succeeds
|
||||
get_boss().add_child(window)
|
||||
add_window(self.id, window.id)
|
||||
add_window(self.id, window.id, window.override_title or window.title or appname)
|
||||
self.active_window_idx = self.current_layout.add_window(self.windows, window, self.active_window_idx)
|
||||
set_active_window(self.id, self.active_window_idx)
|
||||
self.relayout_borders()
|
||||
|
||||
@ -20,7 +20,7 @@ from .fast_data_types import (
|
||||
GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, GLFW_RELEASE, MOTION_MODE,
|
||||
SCROLL_FULL, SCROLL_LINE, SCROLL_PAGE, Screen, create_cell_vao,
|
||||
glfw_post_empty_event, remove_vao, set_window_render_data,
|
||||
update_window_visibility
|
||||
update_window_title, update_window_visibility
|
||||
)
|
||||
from .keys import get_key_map
|
||||
from .mouse import DRAG, MOVE, PRESS, RELEASE, encode_mouse_event
|
||||
@ -143,6 +143,7 @@ class Window:
|
||||
def title_changed(self, new_title):
|
||||
if self.override_title is None:
|
||||
self.title = sanitize_title(new_title or appname)
|
||||
update_window_title(self.tab_id, self.id, self.title)
|
||||
t = self.tabref()
|
||||
if t is not None:
|
||||
t.title_changed(self)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user