@@ -7,6 +7,7 @@ use vte::prelude::{TerminalExt, TerminalExtManual};
77use webkitgtk6:: { WebContext , WebView } ;
88use webkitgtk6:: prelude:: WebViewExt ;
99use which:: which;
10+ use gio:: Cancellable ;
1011
1112fn main ( ) {
1213 // Initialize GTK
@@ -37,8 +38,8 @@ fn main() {
3738 " ) ;
3839 gtk:: style_context_add_provider_for_display (
3940 & gtk:: gdk:: Display :: default ( ) . unwrap ( ) ,
40- & provider,
41- gtk:: STYLE_PROVIDER_PRIORITY_APPLICATION ,
41+ & provider,
42+ gtk:: STYLE_PROVIDER_PRIORITY_APPLICATION ,
4243 ) ;
4344 } ) ;
4445 app. connect_activate ( build_ui) ;
@@ -96,10 +97,10 @@ fn add_tab(notebook: &Notebook) {
9697 & [ & shell] ,
9798 & [ ] ,
9899 glib:: SpawnFlags :: DEFAULT ,
99- None :: < & ( dyn Fn ( ) + ' static ) > ,
100- -1 ,
101- None ,
102- |_| { } ,
100+ || { } ,
101+ -1 ,
102+ None :: < & Cancellable > ,
103+ |_| { } ,
103104 ) ;
104105 overlay. set_child ( Some ( & terminal) ) ;
105106 // Create WebView for animations (transparent overlay)
@@ -115,115 +116,108 @@ fn add_tab(notebook: &Notebook) {
115116 margin: 0;
116117 padding: 0;
117118 overflow: hidden;
118- background: transparent;
119- }
120- canvas {
121- display: block;
122- position: absolute;
123- top: 0;
124- left: 0;
125- width: 100%;
126- height: 100%;
127- pointer-events: none; /* Allow clicks to pass through */
128- }
129- </style>
130- </head>
131- <body>
132- <canvas id="canvas"></canvas>
133- <script>
134- const canvas = document.getElementById('canvas');
135- const ctx = canvas.getContext('2d');
136- let particles = [];
137- let animationFrameId;
138- function resizeCanvas() {
139- canvas.width = window.innerWidth;
140- canvas.height = window.innerHeight;
141- }
142- window.addEventListener('resize', resizeCanvas);
143- resizeCanvas();
144- class Particle {
145- constructor(x, y) {
146- this.x = x;
147- this.y = y;
148- this.size = Math.random() * 5 + 2;
149- this.speedX = Math.random() * 4 - 2;
150- this.speedY = Math.random() * 4 - 2;
151- this.color = `rgba(${Math.random()*255}, ${Math.random()*255}, ${Math.random()*255}, ${Math.random() * 0.5 + 0.5})`;
152- this.life = 30 + Math.random() * 20;
153- }
154- update() {
155- this.x += this.speedX;
156- this.y += this.speedY;
157- this.speedY += 0.1; // Gravity effect
158- this.life -= 1;
159- if (this.size > 0.2) this.size -= 0.1;
160- }
161- draw() {
162- ctx.fillStyle = this.color;
163- ctx.beginPath();
164- ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
165- ctx.fill();
166- }
167- }
168- function animate() {
169- ctx.clearRect(0, 0, canvas.width, canvas.height);
170- particles = particles.filter(particle => {
171- particle.update();
172- particle.draw();
173- return particle.life > 0;
174- });
175- animationFrameId = requestAnimationFrame(animate);
176- }
177- animate();
178- // Function to spawn particles (called from Rust on input)
179- function spawnParticles(count = 50) {
180- const x = Math.random() * canvas.width;
181- const y = Math.random() * canvas.height;
182- for (let i = 0; i < count; i++) {
183- particles.push(new Particle(x, y));
184- }
185- }
186- </script>
187- </body>
188- </html>
189- "# ;
190- webview. load_html ( html, None ) ;
191- // Make webview expand and overlay
192- webview. set_hexpand ( true ) ;
193- webview. set_vexpand ( true ) ;
194- overlay. add_overlay ( & webview) ;
195- // Connect to VTE commit signal to trigger particles on text input
196- let webview_clone = webview. clone ( ) ;
197- terminal. connect_commit ( move |_, text, _| {
198- if !text. is_empty ( ) {
199- // Trigger JavaScript to spawn particles
200- webview_clone. evaluate_javascript ( "spawnParticles(50);" , None , None , None , |_| { } ) ;
119+ background: transparent; }
120+ canvas { display: block; position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; /* Allow clicks to pass through */ }
121+ </style>
122+ </head>
123+ <body>
124+ <canvas id="canvas"></canvas>
125+ <script>
126+ const canvas = document.getElementById('canvas');
127+ const ctx = canvas.getContext('2d');
128+ let particles = [];
129+ let animationFrameId;
130+ function resizeCanvas() {
131+ canvas.width = window.innerWidth;
132+ canvas.height = window.innerHeight;
133+ }
134+ window.addEventListener('resize', resizeCanvas);
135+ resizeCanvas();
136+ class Particle {
137+ constructor(x, y) {
138+ this.x = x;
139+ this.y = y;
140+ this.size = Math.random() * 5 + 2;
141+ this.speedX = Math.random() * 4 - 2;
142+ this.speedY = Math.random() * 4 - 2;
143+ this.color = `rgba(${Math.random()*255}, ${Math.random()*255}, ${Math.random()*255}, ${Math.random() * 0.5 + 0.5})`;
144+ this.life = 30 + Math.random() * 20;
145+ }
146+ update() {
147+ this.x += this.speedX;
148+ this.y += this.speedY;
149+ this.speedY += 0.1; // Gravity effect
150+ this.life -= 1;
151+ if (this.size > 0.2) this.size -= 0.1;
152+ }
153+ draw() {
154+ ctx.fillStyle = this.color;
155+ ctx.beginPath();
156+ ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
157+ ctx.fill();
201158 }
202- } ) ;
203- // Wrap in ScrolledWindow for better handling
204- let scrolled = ScrolledWindow :: new ( ) ;
205- scrolled. set_child ( Some ( & overlay) ) ;
206- scrolled. set_hexpand ( true ) ;
207- scrolled. set_vexpand ( true ) ;
208- // Add to notebook with close button
209- let tab_box = gtk:: Box :: new ( Orientation :: Horizontal , 0 ) ;
210- let label = Label :: new ( Some ( "Terminal" ) ) ;
211- tab_box. append ( & label) ;
212- let close_button = Button :: builder ( )
213- . icon_name ( "window-close-symbolic" )
214- . css_classes ( vec ! [ "flat" . to_string( ) ] )
215- . build ( ) ;
216- tab_box. append ( & close_button) ;
217- let _ = notebook. append_page ( & scrolled, Some ( & tab_box) ) ;
218- let notebook_weak = notebook. downgrade ( ) ;
219- let scrolled_weak = scrolled. downgrade ( ) ;
220- close_button. connect_clicked ( move |_| {
221- if let Some ( notebook) = notebook_weak. upgrade ( ) {
222- if let Some ( scrolled) = scrolled_weak. upgrade ( ) {
223- if let Some ( page) = notebook. page_num ( & scrolled) {
224- notebook. remove_page ( Some ( page) ) ;
159+ }
160+ function animate() {
161+ ctx.clearRect(0, 0, canvas.width, canvas.height);
162+ particles = particles.filter(particle => {
163+ particle.update();
164+ particle.draw();
165+ return particle.life > 0;
166+ });
167+ animationFrameId = requestAnimationFrame(animate);
168+ }
169+ animate();
170+ // Function to spawn particles (called from Rust on input)
171+ function spawnParticles(count = 50) {
172+ const x = Math.random() * canvas.width;
173+ const y = Math.random() * canvas.height;
174+ for (let i = 0; i < count; i++) {
175+ particles.push(new Particle(x, y));
176+ }
177+ }
178+ </script>
179+ </body>
180+ </html>
181+ "# ;
182+ webview. load_html ( html, None ) ;
183+ // Make webview expand and overlay
184+ webview. set_hexpand ( true ) ;
185+ webview. set_vexpand ( true ) ;
186+ overlay. add_overlay ( & webview) ;
187+ webview. set_sensitive ( false ) ;
188+ webview. set_can_focus ( false ) ;
189+ // Connect to VTE commit signal to trigger particles on text input
190+ let webview_clone = webview. clone ( ) ;
191+ terminal. connect_commit ( move |_, text, _| {
192+ if !text. is_empty ( ) {
193+ // Trigger JavaScript to spawn particles
194+ webview_clone. evaluate_javascript ( "spawnParticles(50);" , None , None , None :: < & Cancellable > , |_| { } ) ;
195+ }
196+ } ) ;
197+ // Wrap in ScrolledWindow for better handling
198+ let scrolled = ScrolledWindow :: new ( ) ;
199+ scrolled. set_child ( Some ( & overlay) ) ;
200+ scrolled. set_hexpand ( true ) ;
201+ scrolled. set_vexpand ( true ) ;
202+ // Add to notebook with close button
203+ let tab_box = gtk:: Box :: new ( Orientation :: Horizontal , 0 ) ;
204+ let label = Label :: new ( Some ( "Terminal" ) ) ;
205+ tab_box. append ( & label) ;
206+ let close_button = Button :: builder ( )
207+ . icon_name ( "window-close-symbolic" )
208+ . css_classes ( vec ! [ "flat" . to_string( ) ] )
209+ . build ( ) ;
210+ tab_box. append ( & close_button) ;
211+ let _ = notebook. append_page ( & scrolled, Some ( & tab_box) ) ;
212+ let notebook_weak = notebook. downgrade ( ) ;
213+ let scrolled_weak = scrolled. downgrade ( ) ;
214+ close_button. connect_clicked ( move |_| {
215+ if let Some ( notebook) = notebook_weak. upgrade ( ) {
216+ if let Some ( scrolled) = scrolled_weak. upgrade ( ) {
217+ if let Some ( page) = notebook. page_num ( & scrolled) {
218+ notebook. remove_page ( Some ( page) ) ;
219+ }
225220 }
226221 }
227- }
228- } ) ;
222+ } ) ;
229223}
0 commit comments