|
|
@@ -5,7 +5,6 @@
|
|
|
#include "lumacs/command_system.hpp"
|
|
|
#include "lumacs/minibuffer_manager.hpp" // Include for MinibufferManager and MinibufferMode
|
|
|
#include "lumacs/gtk_renderer.hpp" // Include for GtkRenderer
|
|
|
-#include "lumacs/gtk_window_controller.hpp" // Include for GtkWindowController
|
|
|
#include <iostream>
|
|
|
#include <filesystem>
|
|
|
#include <vector>
|
|
|
@@ -202,9 +201,6 @@ private:
|
|
|
// GtkRenderer instance
|
|
|
std::unique_ptr<GtkRenderer> gtk_renderer_;
|
|
|
|
|
|
- // GtkWindowController instances for each window
|
|
|
- std::vector<std::shared_ptr<GtkWindowController>> window_controllers_;
|
|
|
-
|
|
|
protected:
|
|
|
void on_activate() {
|
|
|
// Create main window and associate with the application
|
|
|
@@ -257,7 +253,7 @@ protected:
|
|
|
// Cursor blinking callback
|
|
|
bool on_cursor_blink() {
|
|
|
// Safety check - don't blink if core is destroyed or no drawing area
|
|
|
- if (!core_ || !app_) { // drawing_area_ is now managed by controllers
|
|
|
+ if (!core_ || !drawing_area_ || !app_) {
|
|
|
return false; // Stop the timer
|
|
|
}
|
|
|
|
|
|
@@ -269,17 +265,7 @@ protected:
|
|
|
try {
|
|
|
cursor_visible_ = !cursor_visible_;
|
|
|
core_->check_and_clear_message(); // Check and clear messages
|
|
|
-
|
|
|
- // Update all window controllers and queue redraws
|
|
|
- for (const auto& controller : window_controllers_) {
|
|
|
- controller->set_cursor_visible(cursor_visible_);
|
|
|
- // Each controller's drawing area will be redrawn by its own draw_func or here
|
|
|
- // For now, GtkEditor manages top-level redraws, but this might be refactored
|
|
|
- // if individual window redraws are sufficient
|
|
|
- }
|
|
|
- if (content_widget_) {
|
|
|
- queue_redraw_all_windows(content_widget_);
|
|
|
- }
|
|
|
+ drawing_area_->queue_draw();
|
|
|
} catch (...) {
|
|
|
return false; // Stop timer on any exception
|
|
|
}
|
|
|
@@ -302,9 +288,6 @@ protected:
|
|
|
// Clear the drawing area reference since we're rebuilding
|
|
|
drawing_area_ = nullptr;
|
|
|
|
|
|
- // Clear all window controllers
|
|
|
- window_controllers_.clear();
|
|
|
-
|
|
|
// Initialize cached active window to prevent focus jumping
|
|
|
cached_active_window_ = core_->active_window();
|
|
|
|
|
|
@@ -323,25 +306,116 @@ protected:
|
|
|
// Create a new DrawingArea for this window
|
|
|
auto drawing_area = Gtk::make_managed<Gtk::DrawingArea>();
|
|
|
|
|
|
- // Create a GtkWindowController for this DrawingArea
|
|
|
- auto controller = std::make_shared<GtkWindowController>(*core_, *gtk_renderer_, node->window, *drawing_area);
|
|
|
- controller->set_cached_active_window(cached_active_window_);
|
|
|
- controller->set_cursor_visible(cursor_visible_);
|
|
|
- controller->connect_events();
|
|
|
-
|
|
|
- // Store the controller to manage its lifetime and update cached_active_window_ and cursor_visible_
|
|
|
- window_controllers_.push_back(controller);
|
|
|
-
|
|
|
// Set up drawing for this specific window
|
|
|
// Use a weak reference to the window to avoid crashes if the layout is rebuilt
|
|
|
- drawing_area->set_draw_func([this, controller_ptr = controller](const Cairo::RefPtr<Cairo::Context>& cr, int width, int height) {
|
|
|
- if (controller_ptr) {
|
|
|
- controller_ptr->on_draw_event(cr, width, height);
|
|
|
+ std::weak_ptr<Window> weak_window = node->window;
|
|
|
+ drawing_area->set_draw_func([this, weak_window, drawing_area](const Cairo::RefPtr<Cairo::Context>& cr, int width, int height) {
|
|
|
+ if (auto window = weak_window.lock() && gtk_renderer_) {
|
|
|
+ gtk_renderer_->draw_window(cr, width, height, window, drawing_area, cached_active_window_, cursor_visible_);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
drawing_area->set_focusable(true);
|
|
|
|
|
|
+ // Add input handling
|
|
|
+ auto controller = Gtk::EventControllerKey::create();
|
|
|
+ // Use weak reference to window for key handling
|
|
|
+ std::weak_ptr<Window> weak_window_key = node->window;
|
|
|
+ controller->signal_key_pressed().connect([this, weak_window_key](guint keyval, guint keycode, Gdk::ModifierType state) -> bool {
|
|
|
+ // Ensure this window is active when it receives key input
|
|
|
+ if (auto window = weak_window_key.lock()) {
|
|
|
+ if (core_) {
|
|
|
+ core_->set_active_window(window);
|
|
|
+ cached_active_window_ = window; // Cache for rendering to prevent focus jumping
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // Now handled by GtkWindowController, so we need to instantiate it
|
|
|
+ return false;
|
|
|
+ }, false);
|
|
|
+ drawing_area->add_controller(controller);
|
|
|
+
|
|
|
+ // Add click handling to set active window explicitly and move cursor
|
|
|
+ // We use GestureClick instead of EventControllerFocus to avoid spurious focus changes
|
|
|
+ auto click_controller = Gtk::GestureClick::create();
|
|
|
+ std::weak_ptr<Window> weak_window_click = node->window;
|
|
|
+ click_controller->signal_pressed().connect([this, weak_window_click, drawing_area](int /*n_press*/, double x, double y) {
|
|
|
+ if (auto window = weak_window_click.lock()) {
|
|
|
+ // 1. Activate Window
|
|
|
+ if (core_ && core_->active_window() != window) {
|
|
|
+ core_->set_active_window(window);
|
|
|
+ cached_active_window_ = window; // Cache for rendering to prevent focus jumping
|
|
|
+ }
|
|
|
+ // IMPORTANT: Grab keyboard focus for this widget
|
|
|
+ drawing_area->grab_focus();
|
|
|
+
|
|
|
+ // 2. Move Cursor
|
|
|
+ if (gtk_renderer_) {
|
|
|
+ if (auto pos = gtk_renderer_->resolve_screen_pos(window, x, y)) {
|
|
|
+ window->set_cursor(*pos);
|
|
|
+ // Clear mark on simple click
|
|
|
+ window->buffer().deactivate_mark();
|
|
|
+ drawing_area->queue_draw();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ drawing_area->add_controller(click_controller);
|
|
|
+
|
|
|
+ // Add Drag Gesture for Selection
|
|
|
+ auto drag_controller = Gtk::GestureDrag::create();
|
|
|
+ std::weak_ptr<Window> weak_window_drag = node->window;
|
|
|
+
|
|
|
+ drag_controller->signal_drag_begin().connect([this, weak_window_drag, drawing_area](double x, double y) {
|
|
|
+ if (auto window = weak_window_drag.lock()) {
|
|
|
+ if (gtk_renderer_) {
|
|
|
+ if (auto pos = gtk_renderer_->resolve_screen_pos(window, x, y)) {
|
|
|
+ // Set mark at start of drag
|
|
|
+ window->buffer().set_mark(*pos);
|
|
|
+ window->set_cursor(*pos);
|
|
|
+ drawing_area->queue_draw();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ drag_controller->signal_drag_update().connect([this, weak_window_drag, drawing_area, drag_controller](double dx, double dy) {
|
|
|
+ if (auto window = weak_window_drag.lock()) {
|
|
|
+ double start_x, start_y;
|
|
|
+ if (drag_controller->get_start_point(start_x, start_y) && gtk_renderer_) {
|
|
|
+ double current_x = start_x + dx;
|
|
|
+ double current_y = start_y + dy;
|
|
|
+
|
|
|
+ if (auto pos = gtk_renderer_->resolve_screen_pos(window, current_x, current_y)) {
|
|
|
+ window->set_cursor(*pos);
|
|
|
+ drawing_area->queue_draw();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ drawing_area->add_controller(drag_controller);
|
|
|
+
|
|
|
+ // Add scroll handling
|
|
|
+ auto scroll_controller = Gtk::EventControllerScroll::create();
|
|
|
+ scroll_controller->set_flags(Gtk::EventControllerScroll::Flags::VERTICAL);
|
|
|
+ std::weak_ptr<Window> weak_window_scroll = node->window;
|
|
|
+ scroll_controller->signal_scroll().connect([weak_window_scroll, drawing_area](double /*dx*/, double dy) -> bool {
|
|
|
+ if (auto window = weak_window_scroll.lock()) {
|
|
|
+ // dy is usually 1.0 or -1.0 for wheel steps
|
|
|
+ // Scroll 3 lines per step
|
|
|
+ int lines = static_cast<int>(dy * 3.0);
|
|
|
+ if (lines != 0) {
|
|
|
+ window->scroll_lines(lines);
|
|
|
+ drawing_area->queue_draw();
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }, true);
|
|
|
+ drawing_area->add_controller(scroll_controller);
|
|
|
+
|
|
|
+ // Context menus and tooltips removed per user request (Phase A.1)
|
|
|
+
|
|
|
// Store reference for single-window compatibility
|
|
|
if (!drawing_area_) {
|
|
|
drawing_area_ = drawing_area;
|
|
|
@@ -380,4 +454,21 @@ protected:
|
|
|
return paned;
|
|
|
}
|
|
|
}
|
|
|
-};
|
|
|
+};
|
|
|
+
|
|
|
+std::unique_ptr<IEditorView> create_gtk_editor() {
|
|
|
+ return std::make_unique<GtkEditor>();
|
|
|
+}
|
|
|
+
|
|
|
+} // namespace lumacs
|
|
|
+
|
|
|
+#else // LUMACS_WITH_GTK not defined
|
|
|
+
|
|
|
+namespace lumacs {
|
|
|
+std::unique_ptr<IEditorView> create_gtk_editor() {
|
|
|
+ std::cerr << "Error: Lumacs was built without GTK support." << std::endl;
|
|
|
+ return nullptr;
|
|
|
+}
|
|
|
+} // namespace lumacs
|
|
|
+
|
|
|
+#endif
|