The basic problem is this:
I have a bunch of widgets that the user can move around. This is achieved by using a GtkOverlay as the outer container, and inside this, is a bunch of GtkFixed, each containing the corresponding widget:
- GtkOverlay
- GtkFixed
- Widget A
- GtkFixed
- Widget B
- ...
- GtkFixed
The reason for the outer GtkOverlay is that GtkFixed lacks support for z-index. Now each GtkFixed covers the entire area. Thus, to make it possible to activate a widget that is currently below, the pass-through property has to be set on each child of the GtkOverlay. The system works for the leaf widgets GtkScale and GtkDrawingArea. However, If I put something inside a GtkScrolledWindow in GTK assumes that the GtkScrolledWindow is located in the upper left corner of the GtkFixed, which in general is wrong. Unsetting the pass-through property solves the problem, but then other widgets become inaccessible. Is there any workaround for this.
I think the proper solution would be to have each child of the GtkOverlay not to occupy the whole area. Then pass-through would not be needed, but I think it is not possible to do this with GTK (or maybe you could if you write your own layout container, which behaves like a web page with free floating layers.
Minimal non-working example:
//@ {
//@ "targets":[{"name":"minimal-nonworking-example-so-64090741","type":"application", "pkgconfig_libs":["gtk+-3.0"]}]
//@ }
#include <gtk/gtk.h>
#include <string>
#include <vector>
#include <algorithm>
// To be able to feed the list box
template<class Callback>
void readlines(FILE* src, Callback&& cb)
{
std::string buffer;
while(true)
{
auto ch_in = getc(src);
if(ch_in == -1)
{
if(buffer.size() != 0)
{
cb(buffer);
}
return;
}
if(ch_in=='\n')
{
cb(buffer);
buffer.clear();
}
else
{
buffer+=ch_in;
}
}
}
int main(int argc, char** argv)
{
gtk_init(&argc, &argv);
auto mainwin = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
gtk_window_set_title(mainwin, "ListBoxTest");
gtk_window_set_default_size(mainwin, 800, 500);
auto overlay = GTK_OVERLAY(gtk_overlay_new());
gtk_container_add(GTK_CONTAINER(mainwin), GTK_WIDGET(overlay));
gtk_widget_set_size_request(GTK_WIDGET(overlay), 500, 300);
auto frame = GTK_FRAME(gtk_frame_new(nullptr));
auto fixed = GTK_FIXED(gtk_fixed_new());
gtk_fixed_put(fixed, GTK_WIDGET(frame), 60, 60);
gtk_overlay_add_overlay(overlay, GTK_WIDGET(fixed));
// {
// Without this line, GtkScrolledWindow works as expected, but if there were more layers
// other layers would become inaccessible
gtk_overlay_set_overlay_pass_through(overlay, GTK_WIDGET(fixed), TRUE);
// }
gtk_overlay_reorder_overlay(overlay, GTK_WIDGET(fixed), -1);
auto scrolled_window = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(nullptr, nullptr));
gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(scrolled_window));
gtk_widget_set_size_request(GTK_WIDGET(frame), 128, 128);
auto listbox = GTK_LIST_BOX(gtk_list_box_new());
gtk_container_add(GTK_CONTAINER(scrolled_window), GTK_WIDGET(listbox));
gtk_widget_show_all(GTK_WIDGET(mainwin));
readlines(stdin, [listbox](auto&& item) {
auto label = GTK_LABEL(gtk_label_new(item.c_str()));
gtk_label_set_justify(label, GTK_JUSTIFY_LEFT);
gtk_widget_set_halign(GTK_WIDGET(label), GTK_ALIGN_START);
gtk_list_box_insert(listbox, GTK_WIDGET(label), -1);
});
gtk_widget_show_all(GTK_WIDGET(fixed));
gtk_main();
gtk_widget_destroy(GTK_WIDGET(mainwin));
return 0;
}