scope windows: their own frame pump, and a diagnosis that names the GSK renderer
A second toplevel's frame clock is not the main window's: the tick binds, queues a render and mirrors the span, but with nothing asking GTK for frames on *that* window the area can sit with its queue full and present nothing -- a blank plot. Every scope window now carries a tick callback on its own area (`gtk_gl_area_queue_render` per frame), which is the request that keeps its frame clock running. The "cannot paint" diagnosis now names the window's GSK renderer (`[GSK renderer: GskVulkanRenderer]`) and says to restart with `GSK_RENDERER=gl` when it is the Vulkan one -- the interaction between the Vulkan GSK renderer and an embedded `GtkGLArea` in a second toplevel is a known trouble spot, and a tiling WM has no title bar to carry a title, so the sentence goes to stderr and the status bar instead.
This commit is contained in:
1 parent
fa2d0f12fc
commit
2279e2140a
2 files changed
+27
-3
No files matched your search
@@ -149,8 +149,12 @@ the signal page's *Plot on* buttons list **every window**: one group per window
|
|||||||
menu** — y axis (auto or a fixed range), *Fit X axis*, *Fit all*, remove a trace — acting on that
|
menu** — y axis (auto or a fixed range), *Fit X axis*, *Fit all*, remove a trace — acting on that
|
||||||
window's rows (the x fit resets the **shared** time span, so every view follows); a detached
|
window's rows (the x fit resets the **shared** time span, so every view follows); a detached
|
||||||
window's menu carries **Attach back to the main window** beside them. A window that cannot paint
|
window's menu carries **Attach back to the main window** beside them. A window that cannot paint
|
||||||
says so in its own title after two seconds (and on stderr): a blank plot is indistinguishable from
|
says so on stderr and in the status bar after two seconds, naming its **GSK renderer**: a blank
|
||||||
a context that failed, and the sentence names which.
|
plot is indistinguishable from a context that failed, and the GTK **Vulkan** renderer is known to
|
||||||
|
interact badly with an embedded `GtkGLArea` in a second toplevel — the sentence then says to
|
||||||
|
restart with `GSK_RENDERER=gl`. Each scope window also carries a **tick callback of its own**,
|
||||||
|
which keeps its toplevel's frame clock advancing: the main window's tick binds and queues the
|
||||||
|
render, but a second window whose clock never ticks presents nothing.
|
||||||
mode or the span.
|
mode or the span.
|
||||||
|
|
||||||
**The window.** The plot is the window. Under it sits a fixed-height **badge bar** (36 px). Its left
|
**The window.** The plot is the window. Under it sits a fixed-height **badge bar** (36 px). Its left
|
||||||
|
|||||||
+21
-1
@@ -621,6 +621,16 @@ void open_scope_window(App& app, int figure_row, bool detached) {
|
|||||||
g_object_set_data(G_OBJECT(scope->drop), "udpscope-scope", scope.get());
|
g_object_set_data(G_OBJECT(scope->drop), "udpscope-scope", scope.get());
|
||||||
g_signal_connect(scope->drop, "drop", G_CALLBACK(on_scope_drop_channel), &app);
|
g_signal_connect(scope->drop, "drop", G_CALLBACK(on_scope_drop_channel), &app);
|
||||||
gtk_widget_add_controller(scope->widget, GTK_EVENT_CONTROLLER(scope->drop));
|
gtk_widget_add_controller(scope->widget, GTK_EVENT_CONTROLLER(scope->drop));
|
||||||
|
// The window's own frame pump: a tick callback on its area asks GTK for one frame per tick,
|
||||||
|
// which is what keeps *this* toplevel's frame clock running. The main window's tick binds and
|
||||||
|
// queues the render, but a second toplevel whose clock is never advanced keeps its queue full
|
||||||
|
// and presents nothing -- a blank plot with axes nowhere to be seen.
|
||||||
|
gtk_widget_add_tick_callback(scope->widget,
|
||||||
|
+[](GtkWidget* widget, GdkFrameClock*, gpointer) -> gboolean {
|
||||||
|
gtk_gl_area_queue_render(GTK_GL_AREA(widget));
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
},
|
||||||
|
nullptr, nullptr);
|
||||||
// The window's own right-click menu: its y scales, its traces, its removals -- the same
|
// The window's own right-click menu: its y scales, its traces, its removals -- the same
|
||||||
// actions the main window's plot menu carries, aimed at **this window's** row set.
|
// actions the main window's plot menu carries, aimed at **this window's** row set.
|
||||||
GtkGesture* right = gtk_gesture_click_new();
|
GtkGesture* right = gtk_gesture_click_new();
|
||||||
@@ -4645,12 +4655,22 @@ gboolean tick(gpointer user) {
|
|||||||
const plot::Status st = scope->area->init_status();
|
const plot::Status st = scope->area->init_status();
|
||||||
const plot::u64 painted = scope->area->frames_painted();
|
const plot::u64 painted = scope->area->frames_painted();
|
||||||
if (!st || painted == 0) {
|
if (!st || painted == 0) {
|
||||||
const std::string why =
|
std::string why =
|
||||||
st ? std::string("the plot painted no frame in two seconds")
|
st ? std::string("the plot painted no frame in two seconds")
|
||||||
: std::string("GL context failed: ") + st.message;
|
: std::string("GL context failed: ") + st.message;
|
||||||
|
// Name the GSK renderer: the Vulkan one is known to interact badly with an embedded
|
||||||
|
// `GtkGLArea` in a second toplevel, and the workaround is one environment variable.
|
||||||
|
if (GskRenderer* r = gtk_native_get_renderer(GTK_NATIVE(scope->window))) {
|
||||||
|
const char* type = G_OBJECT_TYPE_NAME(r);
|
||||||
|
why += std::string(" [GSK renderer: ") + type + "]";
|
||||||
|
if (g_strstr_len(type, -1, "Vulkan") != nullptr) {
|
||||||
|
why += "; restart with GSK_RENDERER=gl to check";
|
||||||
|
}
|
||||||
|
}
|
||||||
std::fprintf(stderr, "[scope] window '%s' is not drawing: %s\n",
|
std::fprintf(stderr, "[scope] window '%s' is not drawing: %s\n",
|
||||||
scope->name.c_str(), why.c_str());
|
scope->name.c_str(), why.c_str());
|
||||||
std::fflush(stderr);
|
std::fflush(stderr);
|
||||||
|
set_notice(*app, "window '" + scope->name + "' is not drawing: " + why, 10);
|
||||||
if (scope->window != nullptr) {
|
if (scope->window != nullptr) {
|
||||||
const char* current = gtk_window_get_title(scope->window);
|
const char* current = gtk_window_get_title(scope->window);
|
||||||
gtk_window_set_title(scope->window,
|
gtk_window_set_title(scope->window,
|
||||||
|
|||||||
Reference in new issue
Block a user