roundabout,
created on Sunday, 29 June 2025, 20:25:11 (1751228711),
received on Sunday, 29 June 2025, 20:25:14 (1751228714)
Author identity: vlad <vlad.muntoiu@gmail.com>
9417fde57a0253b3f6cf4d9fdf55e6160cab0984
gpanthera.cc
@@ -547,7 +547,6 @@ namespace gPanthera {
auto new_notebook = Gtk::make_managed<ContentNotebook>(new_stack, new_switcher, this_notebook ? this_notebook->get_tab_position() : Gtk::PositionType::TOP);
new_stack->add_page(*page);
new_stack->set_visible_child(*page);
content_manager->set_last_operated_page(page);
if(x < width / 4) {
this->make_paned(Gtk::Orientation::HORIZONTAL, Gtk::PackType::START);
if(auto paned = dynamic_cast<Gtk::Paned*>(this->get_parent()->get_parent())) {
@@ -569,6 +568,7 @@ namespace gPanthera {
paned->set_end_child(*new_notebook);
}
}
content_manager->set_last_operated_page(page);
}
return true; // Drop OK
@@ -1008,6 +1008,7 @@ namespace gPanthera {
void ContentPage::redock(ContentStack *stack) {
if(stack == nullptr) {
content_manager->signal_page_moving.emit(this);
if(this->stack) {
this->stack->remove(*this);
if(dynamic_cast<ContentNotebook*>(this->stack->get_parent()) && !this->stack->get_first_child()) {
@@ -1028,6 +1029,7 @@ namespace gPanthera {
if(this->stack == stack) {
return;
}
content_manager->signal_page_moving.emit(this);
if(this->stack != nullptr) {
if(dynamic_cast<ContentNotebook*>(this->stack->get_parent()) && (!this->stack->get_first_child() || (this->stack->get_first_child() == this && !this->stack->get_first_child()->get_next_sibling()))) {
this->stack->remove(*this);
@@ -1045,6 +1047,7 @@ namespace gPanthera {
old_stack->signal_leave_empty.emit();
}
}
content_manager->signal_page_moved.emit(this);
}
ContentPage::ContentPage(std::shared_ptr<ContentManager> content_manager, ContentStack *stack, Gtk::Widget *child, Gtk::Widget *tab_widget) :
gpanthera.hh
@@ -127,7 +127,7 @@ namespace gPanthera {
public:
ContentPage *get_last_operated_page() const;
void set_last_operated_page(ContentPage *page);
sigc::signal<void(ContentPage*)> signal_page_operated;
sigc::signal<void(ContentPage*)> signal_page_operated, signal_page_moving, signal_page_moved;
std::vector<ContentStack*> stacks;
ContentManager();
panthera-www.cc
@@ -315,8 +315,30 @@ private:
HistoryViewer *history_viewer;
gPanthera::ContentPage *controlled_page = nullptr;
gPanthera::ContentStack *controlled_stack = nullptr;
Glib::RefPtr<Gio::SimpleAction> back_action, forward_action, reload_action;
Gtk::Button *go_button;
void enable_controls() {
back_action->set_enabled(true);
forward_action->set_enabled(true);
reload_action->set_enabled(true);
url_bar->set_sensitive(true);
go_button->set_sensitive(true);
}
void disable_controls() {
back_action->set_enabled(false);
forward_action->set_enabled(false);
reload_action->set_enabled(false);
url_bar->set_sensitive(false);
url_bar->set_text("");
go_button->set_sensitive(false);
}
sigc::connection moving_connection, moved_connection;
public:
friend class PantheraWww;
explicit PantheraWindow(Gtk::Application *application) : Gtk::ApplicationWindow() {
// There is a constructor with Glib::RefPtr<Gtk::Application>, but it is not appropriate
// because the window will own the application, creating a cycle
@@ -361,9 +383,9 @@ public:
outer_paned->set_start_child(*dock_stack_2);
auto inner_paned = Gtk::make_managed<Gtk::Paned>(Gtk::Orientation::VERTICAL);
auto content = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 0);
panthera->content_manager = std::make_shared<gPanthera::ContentManager>();
std::function<bool(gPanthera::ContentPage*)> detach_handler;
detach_handler = [](gPanthera::ContentPage *widget) {
detach_handler = [this](gPanthera::ContentPage *widget) {
auto new_stack = Gtk::make_managed<gPanthera::ContentStack>(widget->content_manager, widget->get_stack()->get_detach_handler());
auto new_switcher = Gtk::make_managed<gPanthera::ContentTabBar>(new_stack, Gtk::Orientation::HORIZONTAL, dynamic_cast<gPanthera::ContentTabBar*>(widget->get_stack()->get_parent()->get_first_child())->get_extra_child_function());
auto new_notebook = Gtk::make_managed<gPanthera::ContentNotebook>(new_stack, new_switcher);
@@ -374,6 +396,9 @@ public:
window->close();
delete window;
});
controlled_page = nullptr;
controlled_stack = nullptr;
disable_controls();
return true;
};
@@ -416,7 +441,7 @@ public:
}
};
// Go
auto go_button = Gtk::make_managed<Gtk::Button>(_("Go"));
go_button = Gtk::make_managed<Gtk::Button>(_("Go"));
go_button->signal_clicked().connect(load_url_callback);
url_bar->signal_activate().connect(load_url_callback);
panthera->content_manager->signal_page_operated.connect([this, panthera](gPanthera::ContentPage *page) {
@@ -433,17 +458,23 @@ public:
controlled_page = page;
controlled_stack = page->get_stack();
panthera->controlled_stack = page->get_stack();
url_bar->set_text(webkit_web_view_get_uri(WEBKIT_WEB_VIEW(page->get_child()->get_first_child()->gobj())));
guint url_update_handler = g_signal_connect(page->get_child()->get_first_child()->gobj(), "notify", G_CALLBACK(panthera->notify_focused_callback), this);
std::shared_ptr<sigc::connection> control_signal_handler = std::make_shared<sigc::connection>();
*control_signal_handler = page->signal_control_status_changed.connect([this, page, control_signal_handler, url_update_handler](bool controlled) {
if(!controlled) {
control_signal_handler->disconnect();
if(page->get_child() && page->get_child()->get_first_child() && WEBKIT_IS_WEB_VIEW(page->get_child()->get_first_child()->gobj())) {
g_signal_handler_disconnect(page->get_child()->get_first_child()->gobj(), url_update_handler);
}
if(WEBKIT_WEB_VIEW(page->get_child()->get_first_child()->gobj())) {
if(webkit_web_view_get_uri(WEBKIT_WEB_VIEW(page->get_child()->get_first_child()->gobj()))) {
url_bar->set_text(webkit_web_view_get_uri(WEBKIT_WEB_VIEW(page->get_child()->get_first_child()->gobj())));
}
});
guint url_update_handler = g_signal_connect(page->get_child()->get_first_child()->gobj(), "notify", G_CALLBACK(panthera->notify_focused_callback), this);
std::shared_ptr<sigc::connection> control_signal_handler = std::make_shared<sigc::connection>();
*control_signal_handler = page->signal_control_status_changed.connect([this, page, control_signal_handler, url_update_handler](bool controlled) {
if(!controlled) {
control_signal_handler->disconnect();
if(page->get_child() && page->get_child()->get_first_child() && WEBKIT_IS_WEB_VIEW(page->get_child()->get_first_child()->gobj())) {
g_signal_handler_disconnect(page->get_child()->get_first_child()->gobj(), url_update_handler);
}
}
});
}
enable_controls();
});
history_viewer = Gtk::make_managed<HistoryViewer>(layout_manager, panthera->history_manager);
history_viewer->signal_open_url.connect([this, panthera](const std::string &url) {
@@ -460,7 +491,7 @@ public:
reload_button->set_child(*Gtk::make_managed<Gtk::Image>(Gio::Icon::create("view-refresh-symbolic")));
reload_button->set_tooltip_text(_("Reload"));
auto back_action = Gio::SimpleAction::create("go_back");
back_action = Gio::SimpleAction::create("go_back");
add_action(back_action);
back_action->signal_activate().connect([this, panthera](const Glib::VariantBase&) {
if(controlled_page) {
@@ -471,7 +502,7 @@ public:
});
back_button->set_action_name("win.go_back");
auto forward_action = Gio::SimpleAction::create("go_forward");
forward_action = Gio::SimpleAction::create("go_forward");
add_action(forward_action);
forward_action->signal_activate().connect([this, panthera](const Glib::VariantBase&) {
if(controlled_page) {
@@ -482,7 +513,7 @@ public:
});
forward_button->set_action_name("win.go_forward");
auto reload_action = Gio::SimpleAction::create("reload");
reload_action = Gio::SimpleAction::create("reload");
add_action(reload_action);
reload_action->signal_activate().connect([this, panthera](const Glib::VariantBase&) {
if(controlled_page) {
@@ -564,8 +595,29 @@ public:
std::cout << "Layout changed: " << layout_manager->get_layout_as_json() << std::endl;
});
set_show_menubar(true);
// As the window is initially empty, disable most actions
disable_controls();
moving_connection = panthera->content_manager->signal_page_moving.connect([this, panthera](gPanthera::ContentPage *page) {
if(page->get_root() == this) {
controlled_page = nullptr;
controlled_stack = nullptr;
disable_controls();
}
});
moved_connection = panthera->content_manager->signal_page_moved.connect([this, panthera](gPanthera::ContentPage *page) {
if(page->get_root() == this) {
panthera->content_manager->set_last_operated_page(page);
page->get_stack()->set_visible_child(*page);
enable_controls();
}
});
}
~PantheraWindow() override {
moving_connection.disconnect();
moved_connection.disconnect();
}
~PantheraWindow() override = default;
};
void PantheraWww::load_change_callback(WebKitWebView *object, WebKitLoadEvent load_event, gpointer data) {
@@ -621,6 +673,14 @@ void PantheraWww::notify_focused_callback(GObject *object, GParamSpec *pspec, gp
if(auto main_window = dynamic_cast<PantheraWindow*>(page->get_root())) {
main_window->url_bar->set_text(webkit_web_view_get_uri(WEBKIT_WEB_VIEW(object)));
}
} else if(g_strcmp0(pspec->name, "title") == 0) {
if(auto window = dynamic_cast<Gtk::Window*>(page->get_root())) {
if(webkit_web_view_get_title(WEBKIT_WEB_VIEW(object))) {
window->set_title(webkit_web_view_get_title(WEBKIT_WEB_VIEW(object)));
} else {
window->set_title(_("Untitled"));
}
}
}
}
}
@@ -724,6 +784,7 @@ PantheraWindow *PantheraWww::make_window() {
void PantheraWww::on_startup() {
bindtextdomain("panthera-www", "./locales");
textdomain("panthera-www");
content_manager = std::make_shared<gPanthera::ContentManager>();
Gtk::Application::on_startup();
// Get search engines
std::ifstream search_engines_file_in("search_engines.json");
@@ -738,6 +799,17 @@ void PantheraWww::on_startup() {
search_engines_file_out << empty_json.dump(4);
}
// Set window titles on tab switch
content_manager->signal_page_operated.connect([this](gPanthera::ContentPage *page) {
if(auto window = dynamic_cast<Gtk::Window*>(page->get_root())) {
if(webkit_web_view_get_title(WEBKIT_WEB_VIEW(page->get_child()->get_first_child()->gobj()))) {
window->set_title(webkit_web_view_get_title(WEBKIT_WEB_VIEW(page->get_child()->get_first_child()->gobj())));
} else {
window->set_title(_("Untitled"));
}
}
});
// Load settings
new_tab_page = "about:blank";
std::ifstream settings_file_in("settings.json");