--- a/ui/gtk/window.c Sun Aug 24 15:24:16 2025 +0200 +++ b/ui/gtk/window.c Sat Oct 04 14:52:59 2025 +0200 @@ -49,6 +49,9 @@ static int window_default_width = 650; static int window_default_height = 550; +static int splitview_window_default_pos = -1; +static UiBool splitview_window_use_prop = TRUE; + static gboolean ui_window_destroy(void *data) { UiObject *obj = data; uic_object_destroy(obj); @@ -77,6 +80,36 @@ } static gboolean ui_window_close_request(UiObject *obj) { + if(obj->widget) { + void *appwindow = g_object_get_data(G_OBJECT(obj->widget), "ui.appwindow"); + if(appwindow) { + int width = 0; + int height = 0; +#if GTK_CHECK_VERSION(4, 10, 0) + graphene_rect_t bounds; + if(gtk_widget_compute_bounds(obj->widget, obj->widget, &bounds)) { + width = bounds.size.width; + height = bounds.size.height; + } +#elif GTK_CHECK_VERSION(4, 0, 0) + GtkAllocation alloc; + gtk_widget_get_allocation(GTK_WIDGET(obj->widget), &alloc); + width = alloc.width; + height = alloc.height; +#else + gtk_window_get_size(GTK_WINDOW(obj->widget), &width, &height); +#endif + if(width > 0 && height > 0) { + char width_str[32]; + char height_str[32]; + snprintf(width_str, 32, "%d", width); + snprintf(height_str, 32, "%d", height); + ui_set_property("ui.window.width", width_str); + ui_set_property("ui.window.height", height_str); + } + } + } + uic_context_prepare_close(obj->ctx); obj->ref--; if(obj->ref > 0) { @@ -101,7 +134,14 @@ } #endif -static UiObject* create_window(const char *title, void *window_data, UiBool sidebar, UiBool simple) { +static void save_window_splitview_pos(GtkWidget *widget, void *unused) { + int pos = gtk_paned_get_position(GTK_PANED(widget)); + char buf[32]; + snprintf(buf, 32, "%d", pos); + ui_set_property("ui.window.splitview.pos", buf); +} + +static UiObject* create_window(const char *title, void *window_data, UiBool sidebar, UiBool splitview, UiBool simple) { UiObject *obj = uic_object_new_toplevel(); #ifdef UI_LIBADWAITA @@ -122,19 +162,28 @@ gtk_window_set_title(GTK_WINDOW(obj->widget), title); } - const char *width = ui_get_property("ui.window.width"); - const char *height = ui_get_property("ui.window.height"); - if(width && height) { - gtk_window_set_default_size( + if(!simple) { + g_object_set_data(G_OBJECT(obj->widget), "ui.appwindow", obj); + } + + int window_width = window_default_width; + int window_height = window_default_height; + if(!simple) { + const char *width = ui_get_property("ui.window.width"); + const char *height = ui_get_property("ui.window.height"); + if(width && height) { + int w = atoi(width); + int h = atoi(height); + if(w > 0 && h > 0) { + window_width = w; + window_height = h; + } + } + } + gtk_window_set_default_size( GTK_WINDOW(obj->widget), - atoi(width), - atoi(height)); - } else { - gtk_window_set_default_size( - GTK_WINDOW(obj->widget), - window_default_width + sidebar*250, - window_default_height); - } + window_width, + window_height); obj->destroy = ui_window_widget_destroy; g_signal_connect( @@ -161,50 +210,95 @@ GtkWidget *toolbar_view = adw_toolbar_view_new(); adw_toolbar_view_set_content(ADW_TOOLBAR_VIEW(toolbar_view), vbox); - GtkWidget *content_box = ui_gtk_vbox_new(0); - BOX_ADD_EXPAND(GTK_BOX(vbox), content_box); + GtkWidget *headerbar_sidebar = NULL; + GtkWidget *headerbar_main = adw_header_bar_new(); + GtkWidget *headerbar_right = NULL; - GtkWidget *sidebar_headerbar = NULL; + GtkWidget *content = toolbar_view; + if(splitview) { + content = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); + g_signal_connect( + content, + "destroy", + G_CALLBACK(save_window_splitview_pos), + NULL); + + const char *splitview_pos_str = ui_get_property("ui.window.splitview.pos"); + int pos = splitview_window_default_pos; + if(pos < 0) { + pos = window_width / 2; + } + if(splitview_pos_str && splitview_window_use_prop) { + int splitview_pos = atoi(splitview_pos_str); + if(splitview_pos > 0) { + pos = splitview_pos; + } + } + gtk_paned_set_position(GTK_PANED(content), pos); + + GtkWidget *right_panel = adw_toolbar_view_new(); + GtkWidget *right_vbox = ui_gtk_vbox_new(0); + adw_toolbar_view_set_content(ADW_TOOLBAR_VIEW(right_panel), right_vbox); + + headerbar_right = adw_header_bar_new(); + adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_right), FALSE); + adw_toolbar_view_add_top_bar(ADW_TOOLBAR_VIEW(right_panel), headerbar_right); + + adw_header_bar_set_show_end_title_buttons(ADW_HEADER_BAR(headerbar_main), FALSE); + + gtk_paned_set_start_child(GTK_PANED(content), toolbar_view); + gtk_paned_set_end_child(GTK_PANED(content), right_panel); + + g_object_set_data(G_OBJECT(obj->widget), "ui_window_splitview", content); + g_object_set_data(G_OBJECT(obj->widget), "ui_left_panel", vbox); + g_object_set_data(G_OBJECT(obj->widget), "ui_right_panel", right_vbox); + } + + GtkWidget *content_box = vbox; + if(sidebar) { GtkWidget *splitview = adw_overlay_split_view_new(); adw_application_window_set_content(ADW_APPLICATION_WINDOW(obj->widget), splitview); GtkWidget *sidebar_toolbar_view = adw_toolbar_view_new(); adw_overlay_split_view_set_sidebar(ADW_OVERLAY_SPLIT_VIEW(splitview), sidebar_toolbar_view); - sidebar_headerbar = adw_header_bar_new(); - adw_toolbar_view_add_top_bar(ADW_TOOLBAR_VIEW(sidebar_toolbar_view), sidebar_headerbar); + headerbar_sidebar = adw_header_bar_new(); + adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE); + adw_toolbar_view_add_top_bar(ADW_TOOLBAR_VIEW(sidebar_toolbar_view), headerbar_sidebar); - adw_overlay_split_view_set_content(ADW_OVERLAY_SPLIT_VIEW(splitview), toolbar_view); + adw_overlay_split_view_set_content(ADW_OVERLAY_SPLIT_VIEW(splitview), content); g_object_set_data(G_OBJECT(obj->widget), "ui_sidebar", sidebar_toolbar_view); } else { - adw_application_window_set_content(ADW_APPLICATION_WINDOW(obj->widget), toolbar_view); + adw_application_window_set_content(ADW_APPLICATION_WINDOW(obj->widget), content); } - GtkWidget *headerbar = adw_header_bar_new(); - const char *show_title = ui_get_property("ui.gtk.window.showtitle"); if(show_title) { if(!strcmp(show_title, "main") && sidebar) { - adw_header_bar_set_show_title(ADW_HEADER_BAR(sidebar_headerbar), FALSE); + adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE); } else if(!strcmp(show_title, "sidebar")) { - adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar), FALSE); + adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_main), FALSE); + adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), TRUE); } else if(!strcmp(show_title, "false")) { - adw_header_bar_set_show_title(ADW_HEADER_BAR(sidebar_headerbar), FALSE); - adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar), FALSE); + adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE); + adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_main), FALSE); } else { fprintf(stderr, "Unknown value '%s' for property ui.gtk.window.showtitle\n", show_title); - adw_header_bar_set_show_title(ADW_HEADER_BAR(sidebar_headerbar), FALSE); + adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE); } } else { - adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar), FALSE); + adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_main), FALSE); + if(sidebar) { + adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), TRUE); + } } - adw_toolbar_view_add_top_bar(ADW_TOOLBAR_VIEW(toolbar_view), headerbar); - g_object_set_data(G_OBJECT(obj->widget), "ui_headerbar", headerbar); + adw_toolbar_view_add_top_bar(ADW_TOOLBAR_VIEW(toolbar_view), headerbar_main); + g_object_set_data(G_OBJECT(obj->widget), "ui_headerbar", headerbar_main); if(!simple) { - ui_fill_headerbar(obj, headerbar); + ui_fill_headerbar(obj, headerbar_sidebar, headerbar_main, headerbar_right); } #elif GTK_MAJOR_VERSION >= 4 GtkWidget *content_box = ui_gtk_vbox_new(0); @@ -286,15 +380,19 @@ UiObject* ui_window(const char *title, void *window_data) { - return create_window(title, window_data, FALSE, FALSE); + return create_window(title, window_data, FALSE, FALSE, FALSE); } UiObject *ui_sidebar_window(const char *title, void *window_data) { - return create_window(title, window_data, TRUE, FALSE); + return create_window(title, window_data, TRUE, FALSE, FALSE); +} + +UIEXPORT UiObject *ui_splitview_window(const char *title, UiBool sidebar) { + return create_window(title, NULL, sidebar, TRUE, FALSE); } UiObject* ui_simple_window(const char *title, void *window_data) { - return create_window(title, window_data, FALSE, TRUE); + return create_window(title, window_data, FALSE, FALSE, TRUE); } void ui_window_size(UiObject *obj, int width, int height) { @@ -304,6 +402,38 @@ height); } +void ui_window_default_size(int width, int height) { + window_default_width = width; + window_default_height = height; +} + +void ui_splitview_window_set_pos(UiObject *obj, int pos) { + GtkWidget *splitview = g_object_get_data(G_OBJECT(obj->widget), "ui_window_splitview"); + if(splitview) { + gtk_paned_set_position(GTK_PANED(splitview), pos); + } else { + fprintf(stderr, "Error: window has no splitview\n"); + } +} + +int ui_splitview_window_get_pos(UiObject *obj) { + GtkWidget *splitview = g_object_get_data(G_OBJECT(obj->widget), "ui_window_splitview"); + if(splitview) { + return gtk_paned_get_position(GTK_PANED(splitview)); + } else { + fprintf(stderr, "Error: window has no splitview\n"); + } + return 0; +} + +void ui_splitview_window_set_default_pos(int pos) { + splitview_window_default_pos = pos; +} + +void ui_splitview_window_use_property(UiBool enable) { + splitview_window_use_prop = enable; +} + #ifdef UI_LIBADWAITA static void dialog_response(AdwAlertDialog *self, gchar *response, UiEventData *data) { @@ -693,18 +823,6 @@ G_CALLBACK(ui_destroy_userdata), event); - - UiEvent evt; - evt.obj = obj; - evt.document = evt.obj->ctx->document; - evt.window = evt.obj->window; - evt.intval = 0; - - UiFileList flist; - flist.files = NULL; - flist.nfiles = 0; - evt.eventdata = &flist; - gtk_widget_show(dialog); } #endif