@@ -95,6 +95,16 @@ module gtk_app |
| 95 | 95 | character(len=512), save :: pending_synthetic_child_name = "" |
| 96 | 96 | integer, save :: synthetic_nav_attempts = 0 ! Count attempts to avoid infinite loops |
| 97 | 97 | |
| 98 | + ! C interface for macOS native file picker |
| 99 | + interface |
| 100 | + function macos_show_folder_picker(output_path, max_len) bind(c, name='macos_show_folder_picker') |
| 101 | + import :: c_char, c_int |
| 102 | + character(kind=c_char), dimension(*) :: output_path |
| 103 | + integer(c_int), value :: max_len |
| 104 | + integer(c_int) :: macos_show_folder_picker |
| 105 | + end function macos_show_folder_picker |
| 106 | + end interface |
| 107 | + |
| 98 | 108 | contains |
| 99 | 109 | |
| 100 | 110 | ! Run the Sniffly GTK application |
@@ -540,13 +550,14 @@ contains |
| 540 | 550 | end subroutine load_custom_css |
| 541 | 551 | |
| 542 | 552 | ! Callback when Open Directory button is clicked |
| 543 | | - ! NOTE: Uses system command for file picking until GTK4 file dialog bindings are available |
| 553 | + ! Uses native macOS NSOpenPanel for fast, focus-preserving file picker |
| 544 | 554 | subroutine on_open_dir_clicked(button, user_data) bind(c) |
| 545 | 555 | type(c_ptr), value :: button, user_data |
| 546 | 556 | type(tab_state), pointer :: tab |
| 557 | + character(kind=c_char, len=1024) :: c_path |
| 547 | 558 | character(len=1024) :: selected_path |
| 548 | | - integer :: status |
| 549 | | - integer(c_int) :: idle_id |
| 559 | + integer(c_int) :: status |
| 560 | + integer :: i, path_len |
| 550 | 561 | |
| 551 | 562 | print *, "Open Directory button clicked!" |
| 552 | 563 | |
@@ -557,34 +568,37 @@ contains |
| 557 | 568 | return |
| 558 | 569 | end if |
| 559 | 570 | |
| 560 | | - ! Call helper to show native file picker |
| 561 | | - call show_native_directory_picker(selected_path, status) |
| 571 | + ! Call native macOS file picker (modal, maintains focus) |
| 572 | + status = macos_show_folder_picker(c_path, int(len(c_path), c_int)) |
| 562 | 573 | |
| 563 | | - if (status == 0 .and. len_trim(selected_path) > 0) then |
| 564 | | - ! Restore window focus after dialog using idle callback |
| 565 | | - ! (deferred to let macOS finish cleaning up osascript dialog) |
| 566 | | - if (c_associated(main_window_ptr)) then |
| 567 | | - idle_id = g_idle_add(c_funloc(restore_window_focus), c_null_ptr) |
| 568 | | - end if |
| 569 | | - print *, "Selected directory: ", trim(selected_path) |
| 574 | + if (status == 0) then |
| 575 | + ! Convert C string to Fortran string |
| 576 | + path_len = 0 |
| 577 | + do i = 1, len(c_path) |
| 578 | + if (c_path(i:i) == c_null_char) exit |
| 579 | + path_len = i |
| 580 | + end do |
| 570 | 581 | |
| 571 | | - ! Update tab scan path (but don't scan yet) |
| 572 | | - ! Remove trailing slash if present (C code doesn't like it) |
| 573 | | - if (len_trim(selected_path) > 1 .and. selected_path(len_trim(selected_path):len_trim(selected_path)) == '/') then |
| 574 | | - tab%scan_path = trim(selected_path(1:len_trim(selected_path)-1)) |
| 575 | | - print *, "DEBUG: Removed trailing slash from path" |
| 576 | | - else |
| 577 | | - tab%scan_path = trim(selected_path) |
| 578 | | - end if |
| 579 | | - print *, "DEBUG: Set tab scan_path to: '", trim(tab%scan_path), "'" |
| 580 | | - call set_scan_path(trim(tab%scan_path)) |
| 582 | + if (path_len > 0) then |
| 583 | + selected_path = c_path(1:path_len) |
| 584 | + print *, "Selected directory: ", trim(selected_path) |
| 581 | 585 | |
| 582 | | - ! Update path display entry |
| 583 | | - call update_path_entry(trim(tab%scan_path)) |
| 586 | + ! Update tab scan path (but don't scan yet) |
| 587 | + ! Remove trailing slash if present (C code doesn't like it) |
| 588 | + if (len_trim(selected_path) > 1 .and. & |
| 589 | + selected_path(len_trim(selected_path):len_trim(selected_path)) == '/') then |
| 590 | + tab%scan_path = trim(selected_path(1:len_trim(selected_path)-1)) |
| 591 | + else |
| 592 | + tab%scan_path = trim(selected_path) |
| 593 | + end if |
| 584 | 594 | |
| 585 | | - print *, "Path updated. Click Scan button to scan: ", trim(tab%scan_path) |
| 595 | + call set_scan_path(trim(tab%scan_path)) |
| 596 | + call update_path_entry(trim(tab%scan_path)) |
| 597 | + |
| 598 | + print *, "Path updated. Click Scan button to scan: ", trim(tab%scan_path) |
| 599 | + end if |
| 586 | 600 | else |
| 587 | | - print *, "Directory selection cancelled or failed" |
| 601 | + print *, "Directory selection cancelled" |
| 588 | 602 | end if |
| 589 | 603 | end subroutine on_open_dir_clicked |
| 590 | 604 | |