Explorar el Código

fix: Resolve segfault on app close and add arrow key navigation

Segfault Fix:
- Add defensive checks in cursor blink callback for app state
- Use idle callback for delayed quit to prevent race conditions
- Improve destructor cleanup with exception handling
- Check app registration status before accessing GTK objects

Arrow Key Support:
- Add fallback handlers for ArrowUp, ArrowDown, ArrowLeft, ArrowRight
- Implement proper line wrapping for left/right navigation
- Maintain column position when moving up/down between lines
- Handle buffer boundaries correctly

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Bernardo Magri hace 1 mes
padre
commit
1866fef330
Se han modificado 1 ficheros con 67 adiciones y 4 borrados
  1. 67 4
      src/gtk_editor.cpp

+ 67 - 4
src/gtk_editor.cpp

@@ -29,8 +29,19 @@ public:
         if (cursor_timer_connection_.connected()) {
             cursor_timer_connection_.disconnect();
         }
+        
         // Clear core pointer to prevent any callbacks during GTK cleanup
         core_ = nullptr;
+        
+        // If we still have an app reference, try to quit gracefully
+        if (app_ && app_->is_registered()) {
+            try {
+                app_->quit();
+            } catch (...) {
+                // Ignore exceptions during cleanup
+            }
+        }
+        
         // Clear widget pointers - GTK manages their lifetime
         drawing_area_ = nullptr;
         window_ = nullptr;
@@ -62,7 +73,12 @@ public:
             if (cursor_timer_connection_.connected()) {
                 cursor_timer_connection_.disconnect();
             }
-            app_->quit(); // Quit the application gracefully
+            // Use idle callback to quit safely after current event processing
+            Glib::signal_idle().connect_once([this]() {
+                if (app_) {
+                    app_->quit();
+                }
+            });
         }
     }
 
@@ -225,12 +241,22 @@ protected:
     // Cursor blinking callback
     bool on_cursor_blink() {
         // Safety check - don't blink if core is destroyed or no drawing area
-        if (!core_ || !drawing_area_) {
+        if (!core_ || !drawing_area_ || !app_) {
+            return false; // Stop the timer
+        }
+        
+        // Double check that the app is still running
+        if (!app_->is_registered()) {
             return false; // Stop the timer
         }
         
-        cursor_visible_ = !cursor_visible_;
-        drawing_area_->queue_draw();
+        try {
+            cursor_visible_ = !cursor_visible_;
+            drawing_area_->queue_draw();
+        } catch (...) {
+            return false; // Stop timer on any exception
+        }
+        
         return true; // Continue timer
     }
 
@@ -381,6 +407,43 @@ protected:
                 auto cursor = core_->cursor();
                 core_->buffer().erase_char({cursor.line, cursor.column + 1});
             }
+            // Arrow key navigation
+            else if (key_name == "ArrowUp") {
+                auto cursor = core_->cursor();
+                if (cursor.line > 0) {
+                    const auto& target_line = core_->buffer().line(cursor.line - 1);
+                    size_t new_col = std::min(cursor.column, target_line.length());
+                    core_->set_cursor({cursor.line - 1, new_col});
+                }
+            }
+            else if (key_name == "ArrowDown") {
+                auto cursor = core_->cursor();
+                if (cursor.line < core_->buffer().line_count() - 1) {
+                    const auto& target_line = core_->buffer().line(cursor.line + 1);
+                    size_t new_col = std::min(cursor.column, target_line.length());
+                    core_->set_cursor({cursor.line + 1, new_col});
+                }
+            }
+            else if (key_name == "ArrowLeft") {
+                auto cursor = core_->cursor();
+                if (cursor.column > 0) {
+                    core_->set_cursor({cursor.line, cursor.column - 1});
+                } else if (cursor.line > 0) {
+                    // Move to end of previous line
+                    const auto& prev_line = core_->buffer().line(cursor.line - 1);
+                    core_->set_cursor({cursor.line - 1, prev_line.length()});
+                }
+            }
+            else if (key_name == "ArrowRight") {
+                auto cursor = core_->cursor();
+                const auto& current_line = core_->buffer().line(cursor.line);
+                if (cursor.column < current_line.length()) {
+                    core_->set_cursor({cursor.line, cursor.column + 1});
+                } else if (cursor.line < core_->buffer().line_count() - 1) {
+                    // Move to beginning of next line
+                    core_->set_cursor({cursor.line + 1, 0});
+                }
+            }
             // Insert printable characters if unbound
             else if (key_name.size() == 1 && key_name[0] >= 32 && key_name[0] <= 126) {
                 auto cursor = core_->cursor();