|
|
@@ -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();
|