Track window and application titles in C

Allows removing of the last bit fo python from the render loop
This commit is contained in:
Kovid Goyal 2017-09-13 13:02:11 +05:30
parent c41ede4d20
commit 6d8b59cb61
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
10 changed files with 55 additions and 48 deletions

View File

@ -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:

View File

@ -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();

View File

@ -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 */
};

View File

@ -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;

View File

@ -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 */
};

View File

@ -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

View File

@ -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),

View File

@ -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

View File

@ -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()

View File

@ -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)