v0.0.44 - Move tab to new window on 'Open in New Window' (close original tab); keep app alive when main window closes if aux windows have tabs (delete-event handler)
This commit is contained in:
BIN
sovereign_browser-0.0.43.tar.gz
Normal file
BIN
sovereign_browser-0.0.43.tar.gz
Normal file
Binary file not shown.
80
src/main.c
80
src/main.c
@@ -505,7 +505,83 @@ static void agent_login_callback(void) {
|
||||
g_print("[login] Agent login detected.\n");
|
||||
}
|
||||
|
||||
/* ---- Window destroy ------------------------------------------------- */
|
||||
/* ---- Window close / destroy ----------------------------------------- *
|
||||
* The main window uses a delete-event handler to intercept the window
|
||||
* manager's close request BEFORE the window is destroyed. This lets us
|
||||
* close the main window's tabs cleanly (updating g_tab_count) and keep
|
||||
* the app running if auxiliary windows still have tabs. The app only
|
||||
* quits when the last window is closed (no tabs remain anywhere).
|
||||
*
|
||||
* delete-event: runs first. Closes all main-window tabs. If aux windows
|
||||
* still have tabs, returns TRUE to suppress destroy and hides the
|
||||
* main window. If no tabs remain, returns FALSE to let destroy
|
||||
* proceed → on_window_destroy → gtk_main_quit().
|
||||
* destroy: runs only when the app is truly shutting down. Performs
|
||||
* session save, net_services_shutdown, agent_server_stop, etc.
|
||||
*/
|
||||
|
||||
/* Guard flag: set while on_window_delete_event is closing the main
|
||||
* window's tabs. Prevents re-entrancy when tab_manager_close_tab()
|
||||
* calls gtk_window_close(g_window) after the last tab is closed, which
|
||||
* would re-emit delete-event. */
|
||||
static gboolean g_main_window_closing = FALSE;
|
||||
|
||||
static gboolean on_window_delete_event(GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
gpointer data) {
|
||||
(void)event;
|
||||
(void)data;
|
||||
|
||||
/* If we're already in the process of closing (re-entrant call from
|
||||
* tab_manager_close_tab → gtk_window_close), let the destroy
|
||||
* proceed. */
|
||||
if (g_main_window_closing) {
|
||||
return FALSE;
|
||||
}
|
||||
g_main_window_closing = TRUE;
|
||||
|
||||
/* Close all tabs that belong to the main window's notebook. We
|
||||
* identify main-window tabs by checking gtk_notebook_page_num on
|
||||
* the main notebook. tab_manager_close_tab handles removing from
|
||||
* the notebook and the g_tabs array. Re-scan each iteration because
|
||||
* closing shifts indices. */
|
||||
for (;;) {
|
||||
gboolean found = FALSE;
|
||||
GtkWidget *main_nb = tab_manager_get_main_notebook();
|
||||
if (main_nb == NULL) break;
|
||||
/* Close from the highest index down so removal doesn't shift
|
||||
* unprocessed indices. Find the highest-index tab in the main
|
||||
* notebook and close it. */
|
||||
for (int i = tab_manager_count() - 1; i >= 0; i--) {
|
||||
tab_info_t *tab = tab_manager_get(i);
|
||||
if (tab == NULL || tab->page == NULL) continue;
|
||||
if (gtk_notebook_page_num(GTK_NOTEBOOK(main_nb),
|
||||
tab->page) >= 0) {
|
||||
tab_manager_close_tab(i);
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) break;
|
||||
}
|
||||
|
||||
/* If auxiliary windows still have tabs, keep the app running.
|
||||
* Suppress the default destroy by returning TRUE, and hide the
|
||||
* main window. The aux windows continue independently. */
|
||||
if (tab_manager_count() > 0) {
|
||||
g_print("[windows] Main window closed but %d tab(s) remain in "
|
||||
"other window(s) — keeping app alive.\n",
|
||||
tab_manager_count());
|
||||
gtk_widget_hide(widget);
|
||||
g_main_window_closing = FALSE; /* allow re-opening later */
|
||||
return TRUE; /* suppress destroy */
|
||||
}
|
||||
|
||||
/* No tabs left anywhere — let the destroy proceed, which triggers
|
||||
* on_window_destroy and quits the app. Keep the guard set so any
|
||||
* re-entrant delete-event from the destroy path doesn't re-enter. */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void on_window_destroy(GtkWidget *widget, gpointer data) {
|
||||
(void)widget;
|
||||
@@ -761,6 +837,8 @@ int main(int argc, char **argv) {
|
||||
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title(GTK_WINDOW(window), "sovereign browser " SB_VERSION);
|
||||
gtk_window_set_default_size(GTK_WINDOW(window), 1024, 768);
|
||||
g_signal_connect(window, "delete-event",
|
||||
G_CALLBACK(on_window_delete_event), NULL);
|
||||
g_signal_connect(window, "destroy", G_CALLBACK(on_window_destroy), NULL);
|
||||
g_signal_connect(window, "key-press-event", G_CALLBACK(on_key_press), NULL);
|
||||
g_window = GTK_WINDOW(window);
|
||||
|
||||
@@ -3274,6 +3274,14 @@ int tab_manager_count(void) {
|
||||
return g_tab_count;
|
||||
}
|
||||
|
||||
/* Return the main window's notebook widget. Used by main.c's
|
||||
* delete-event handler to identify which tabs belong to the main window
|
||||
* (vs auxiliary windows) when closing the main window but keeping aux
|
||||
* windows alive. */
|
||||
GtkWidget *tab_manager_get_main_notebook(void) {
|
||||
return g_notebook;
|
||||
}
|
||||
|
||||
void tab_manager_set_title(int index, const char *title) {
|
||||
if (index < 0 || index >= g_tab_count) return;
|
||||
tab_info_t *tab = g_tabs[index];
|
||||
@@ -3344,10 +3352,31 @@ void tab_manager_open_in_new_window(int index) {
|
||||
if (index < 0 || index >= g_tab_count) return;
|
||||
tab_info_t *tab = g_tabs[index];
|
||||
if (tab == NULL) return;
|
||||
/* Open the tab's current URL in a new window. Pass the active
|
||||
* webview as the related view so the new window shares the
|
||||
* WebProcess. */
|
||||
tab_manager_new_window(tab->current_url, tab->webview);
|
||||
|
||||
/* Capture the URL before opening the new window — the original tab
|
||||
* will be closed below, which frees the tab_info_t. */
|
||||
char url_buf[TAB_URL_MAX];
|
||||
snprintf(url_buf, sizeof(url_buf), "%s", tab->current_url);
|
||||
|
||||
/* Open the URL in a new window. Pass the original tab's webview as
|
||||
* the related view so the new window shares the WebProcess. The new
|
||||
* window takes its own ref on the related view, so it's safe to
|
||||
* close the original tab afterwards. */
|
||||
GtkWidget *new_wv = tab_manager_new_window(url_buf, tab->webview);
|
||||
if (new_wv == NULL) {
|
||||
/* New window creation failed — keep the original tab open so the
|
||||
* user doesn't lose the page. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Close the original tab — "Open in New Window" moves the tab to a
|
||||
* new window rather than duplicating it. The index may have shifted
|
||||
* if tab_manager_new_window added tabs to the array, so re-resolve
|
||||
* the tab's current index by pointer. */
|
||||
int cur_index = tab_array_find(tab);
|
||||
if (cur_index >= 0) {
|
||||
tab_manager_close_tab(cur_index);
|
||||
}
|
||||
}
|
||||
|
||||
void tab_manager_new_window_blank(void) {
|
||||
|
||||
@@ -208,6 +208,14 @@ WebKitWebView *tab_manager_get_main_webview(void);
|
||||
*/
|
||||
gboolean tab_manager_sidebar_visible(void);
|
||||
|
||||
/*
|
||||
* Returns the main window's GtkNotebook widget. Used by main.c's
|
||||
* delete-event handler to identify which tabs belong to the main window
|
||||
* (vs auxiliary windows) when closing the main window but keeping aux
|
||||
* windows alive.
|
||||
*/
|
||||
GtkWidget *tab_manager_get_main_notebook(void);
|
||||
|
||||
/*
|
||||
* Re-hide the sidebar container after gtk_widget_show_all(window).
|
||||
* Call this in main.c after show_all so the sidebar (which is packed
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
#ifndef SOVEREIGN_BROWSER_VERSION_H
|
||||
#define SOVEREIGN_BROWSER_VERSION_H
|
||||
|
||||
#define SB_VERSION "v0.0.43"
|
||||
#define SB_VERSION "v0.0.44"
|
||||
#define SB_VERSION_MAJOR 0
|
||||
#define SB_VERSION_MINOR 0
|
||||
#define SB_VERSION_PATCH 43
|
||||
#define SB_VERSION_PATCH 44
|
||||
|
||||
#endif /* SOVEREIGN_BROWSER_VERSION_H */
|
||||
|
||||
Reference in New Issue
Block a user