diff --git a/src/main-window.ui b/src/main-window.ui index df4d34d..fdee97c 100644 --- a/src/main-window.ui +++ b/src/main-window.ui @@ -95,7 +95,6 @@ - False False False diff --git a/src/window.py b/src/window.py index 1e34f87..31fc3f7 100644 --- a/src/window.py +++ b/src/window.py @@ -133,14 +133,17 @@ class RosterWindow(Adw.ApplicationWindow): """Setup custom CSS for UI styling.""" css_provider = Gtk.CssProvider() css_provider.load_from_data(b""" - /* Reduce header bar padding and height */ + /* Force both header bars to same height */ headerbar { - min-height: 38px; + min-height: 46px; + max-height: 46px; + padding-top: 0; + padding-bottom: 0; padding-left: 0px; padding-right: 6px; } - /* Compact tab bar */ + /* Compact tab bar to fit in header bar */ tabbar { min-height: 0; padding: 0; @@ -149,11 +152,13 @@ class RosterWindow(Adw.ApplicationWindow): tabbar > scrolledwindow { min-height: 0; + padding: 0; + margin: 0; } tabbar tab { - min-height: 26px; - padding: 2px 8px; + min-height: 28px; + padding: 4px 10px; margin: 0 1px; } @@ -224,9 +229,10 @@ class RosterWindow(Adw.ApplicationWindow): del self.page_to_widget[page] # Check if we need to create a new tab - if self.tab_view.get_n_pages() == 1: # This page is still counted - # Schedule creating new tab BEFORE closing this one - GLib.idle_add(self._create_new_tab) + remaining_tabs = len(self.page_to_tab) + if remaining_tabs == 0: + # Schedule creating exactly one new tab + GLib.timeout_add(50, self._create_new_tab_once) # Close the page tab_view.close_page_finish(page, True) @@ -243,12 +249,22 @@ class RosterWindow(Adw.ApplicationWindow): del self.page_to_tab[page] del self.page_to_widget[page] - # If this will be the last tab, create a new one BEFORE returning - if self.tab_view.get_n_pages() == 1: # This page is still counted - GLib.idle_add(self._create_new_tab) + # If this will be the last tab, create a new one + # Check after we've removed our tracking to get accurate count + remaining_tabs = len(self.page_to_tab) + if remaining_tabs == 0: + # Use a single-shot timer to create exactly one new tab + GLib.timeout_add(50, self._create_new_tab_once) return False # Allow close + def _create_new_tab_once(self): + """Create a new tab (one-time callback).""" + # Only create if there really are no tabs + if self.tab_view.get_n_pages() == 0: + self._create_new_tab() + return False # Don't repeat + def _is_empty_new_request_tab(self): """Check if current tab is an empty 'New Request' tab.""" @@ -338,10 +354,15 @@ class RosterWindow(Adw.ApplicationWindow): def _on_tab_modified_changed(self, page, modified): """Update tab indicator when modified state changes.""" - if modified: - page.set_indicator_icon(Gio.ThemedIcon.new("dot-symbolic")) - else: - page.set_indicator_icon(None) + # Update the tab title with/without modified indicator + tab = self.page_to_tab.get(page) + if tab: + if modified: + # Add star to title + page.set_title(f"*{tab.name}") + else: + # Remove star from title + page.set_title(tab.name) def _switch_to_tab(self, tab_id): """Switch to a tab by its ID.""" @@ -745,12 +766,9 @@ class RosterWindow(Adw.ApplicationWindow): widget.original_request = original widget.modified = False - # Update tab page title + # Update tab page title (widget.modified is now False, so no star) page.set_title(name) - # This will trigger the modified-changed signal and clear the indicator - self._on_tab_modified_changed(page, False) - def _show_overwrite_dialog(self, project, name, existing_request_id, request): """Show dialog asking if user wants to overwrite existing request.""" dialog = Adw.AlertDialog()