1+ // src/terminal.rs
12use gio:: Cancellable ;
23use glib:: { clone:: Downgrade , SpawnFlags } ;
34use gtk:: prelude:: * ;
@@ -7,25 +8,21 @@ use vte::prelude::{TerminalExt, TerminalExtManual};
78use webkitgtk6:: prelude:: WebViewExt ;
89use which:: which;
910use crate :: webview:: setup_webview;
10-
1111pub fn add_tab ( notebook : & gtk:: Notebook ) {
1212 // Create overlay for terminal and webview
1313 let overlay = Overlay :: new ( ) ;
14-
1514 // Create VTE Terminal
1615 let terminal = Terminal :: new ( ) ;
1716 terminal. set_hexpand ( true ) ;
1817 terminal. set_vexpand ( true ) ;
1918 terminal. set_allow_hyperlink ( true ) ;
2019 terminal. set_cursor_shape ( CursorShape :: Ibeam ) ; // Modern cursor
21-
2220 // Determine shell: prefer zsh, fallback to bash
2321 let shell = if which ( "zsh" ) . is_ok ( ) {
2422 "/bin/zsh" . to_string ( )
2523 } else {
2624 "/bin/bash" . to_string ( )
2725 } ;
28-
2926 // Spawn the shell in the terminal
3027 terminal. spawn_async (
3128 PtyFlags :: DEFAULT ,
@@ -38,48 +35,51 @@ pub fn add_tab(notebook: >k::Notebook) {
3835 None :: < & Cancellable > ,
3936 |_| { } ,
4037 ) ;
41-
4238 // Add terminal to overlay
4339 overlay. set_child ( Some ( & terminal) ) ;
44-
4540 // Create and setup WebView for animations
4641 let webview = setup_webview ( ) ;
4742 overlay. add_overlay ( & webview) ;
48-
4943 // Make webview non-interactive
5044 webview. set_sensitive ( false ) ;
5145 webview. set_can_focus ( false ) ;
52-
53- // Connect terminal commit to trigger particles
46+ // Connect terminal commit to trigger particles at cursor position
5447 let webview_clone = webview. clone ( ) ;
48+ let terminal_clone = terminal. clone ( ) ;
5549 terminal. connect_commit ( move |_, text, _| {
5650 if !text. is_empty ( ) {
57- webview_clone. evaluate_javascript ( "spawnParticles(80);" , None , None , None :: < & Cancellable > , |_| { } ) ; // More particles for effect
51+ // Get cursor position in chars
52+ let ( col, row) = terminal_clone. cursor_position ( ) ;
53+ // Convert to pixels
54+ let char_width = terminal_clone. char_width ( ) as f64 ;
55+ let char_height = terminal_clone. char_height ( ) as f64 ;
56+ let padding = terminal_clone. style_context ( ) . padding ( ) ;
57+ let pad_left = padding. left ( ) as f64 ;
58+ let pad_top = padding. top ( ) as f64 ;
59+ let x = ( pad_left + ( col as f64 * char_width) ) as i32 ;
60+ let y = ( pad_top + ( row as f64 * char_height) ) as i32 ;
61+ // Trigger JS with position
62+ webview_clone. evaluate_javascript ( & format ! ( "spawnParticles({}, {});" , x, y) , None , None , None :: < & Cancellable > , |_| { } ) ;
5863 }
5964 } ) ;
60-
6165 // Wrap in ScrolledWindow
6266 let scrolled = ScrolledWindow :: new ( ) ;
6367 scrolled. set_child ( Some ( & overlay) ) ;
6468 scrolled. set_hexpand ( true ) ;
6569 scrolled. set_vexpand ( true ) ;
6670 scrolled. set_policy ( gtk:: PolicyType :: Automatic , gtk:: PolicyType :: Automatic ) ;
67-
6871 // Create tab label with close button
6972 let tab_box = GtkBox :: new ( Orientation :: Horizontal , 4 ) ;
7073 let label = Label :: new ( Some ( "Hackeros Term" ) ) ;
7174 tab_box. append ( & label) ;
72-
7375 let close_button = Button :: builder ( )
74- . icon_name ( "window-close-symbolic" )
75- . css_classes ( vec ! [ "flat" . to_string( ) ] )
76- . build ( ) ;
76+ . icon_name ( "window-close-symbolic" )
77+ . css_classes ( vec ! [ "flat" . to_string( ) ] )
78+ . build ( ) ;
7779 tab_box. append ( & close_button) ;
78-
7980 // Add to notebook
8081 let page = notebook. append_page ( & scrolled, Some ( & tab_box) ) ;
8182 notebook. set_tab_reorderable ( & scrolled, true ) ; // Allow reordering tabs
82-
8383 // Connect close button
8484 let notebook_weak = Downgrade :: downgrade ( & notebook) ;
8585 let scrolled_weak = Downgrade :: downgrade ( & scrolled) ;
@@ -90,7 +90,6 @@ pub fn add_tab(notebook: >k::Notebook) {
9090 }
9191 }
9292 } ) ;
93-
9493 // Select the new tab
9594 notebook. set_current_page ( Some ( page) ) ;
9695}
0 commit comments