Skip to content

Commit 9a52efb

Browse files
authored
Update main.rs
1 parent e121cbe commit 9a52efb

File tree

1 file changed

+24
-213
lines changed

1 file changed

+24
-213
lines changed

src/main.rs

Lines changed: 24 additions & 213 deletions
Original file line numberDiff line numberDiff line change
@@ -1,223 +1,34 @@
1-
use gtk::gdk::RGBA;
2-
use gtk::gio::ApplicationFlags;
1+
use gio::prelude::*;
32
use gtk::prelude::*;
4-
use gtk::{Application, ApplicationWindow, Button, CssProvider, HeaderBar, Label, Notebook, Orientation, ScrolledWindow};
5-
use vte::{PtyFlags, Terminal};
6-
use vte::prelude::{TerminalExt, TerminalExtManual};
7-
use webkitgtk6::{WebContext, WebView};
8-
use webkitgtk6::prelude::WebViewExt;
9-
use which::which;
10-
use gio::Cancellable;
3+
use gio::ApplicationFlags;
4+
use gtk::Application;
5+
6+
mod style;
7+
mod ui;
8+
mod terminal;
9+
mod webview;
10+
11+
use style::apply_styles;
12+
use ui::build_ui;
1113

1214
fn main() {
13-
// Initialize GTK
14-
let app = Application::new(Some("com.example.rustterminal"), ApplicationFlags::default());
15+
// Initialize GTK application
16+
let app = Application::new(Some("com.example.hackerterm"), ApplicationFlags::default());
17+
18+
// Connect startup to apply global settings and styles
1519
app.connect_startup(|_| {
16-
// Set dark theme globally
20+
// Enable dark theme
1721
let settings = gtk::Settings::default().unwrap();
1822
settings.set_property("gtk-application-prefer-dark-theme", &true.to_value());
19-
settings.set_property("gtk-theme-name", &"Adwaita".to_value()); // Adwaita has dark variant
20-
// Load custom CSS for semi-transparent background and styling
21-
let provider = CssProvider::new();
22-
provider.load_from_data("
23-
window {
24-
background-color: rgba(0, 0, 0, 0.8); /* Semi-transparent dark background */
25-
}
26-
notebook {
27-
background-color: transparent;
28-
}
29-
scrolledwindow {
30-
background-color: transparent;
31-
}
32-
vte-terminal {
33-
background-color: transparent;
34-
color: #ffffff;
35-
font-family: monospace;
36-
font-size: 12pt;
37-
}
38-
");
39-
gtk::style_context_add_provider_for_display(
40-
&gtk::gdk::Display::default().unwrap(),
41-
&provider,
42-
gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
43-
);
44-
});
45-
app.connect_activate(build_ui);
46-
app.run();
47-
}
23+
settings.set_property("gtk-theme-name", &"Adwaita".to_value()); // Use Adwaita dark variant
4824

49-
fn build_ui(app: &Application) {
50-
let window = ApplicationWindow::builder()
51-
.application(app)
52-
.title("Rust Terminal")
53-
.default_width(800)
54-
.default_height(600)
55-
.build();
56-
// Create header bar
57-
let header = HeaderBar::new();
58-
header.set_show_title_buttons(true);
59-
window.set_titlebar(Some(&header));
60-
// Create notebook for tabs
61-
let notebook = Notebook::new();
62-
notebook.set_tab_pos(gtk::PositionType::Top);
63-
notebook.set_scrollable(true);
64-
// Add button to header to create new tab
65-
let add_button = Button::with_label("+");
66-
header.pack_start(&add_button);
67-
let notebook_weak = notebook.downgrade();
68-
add_button.connect_clicked(move |_| {
69-
if let Some(notebook) = notebook_weak.upgrade() {
70-
add_tab(&notebook);
71-
}
25+
// Apply custom styles
26+
apply_styles();
7227
});
73-
// Add initial tab
74-
add_tab(&notebook);
75-
window.set_child(Some(&notebook));
76-
window.present();
77-
}
7828

79-
fn add_tab(notebook: &Notebook) {
80-
// Create overlay for terminal and webview
81-
let overlay = gtk::Overlay::new();
82-
// Create VTE Terminal
83-
let terminal = Terminal::new();
84-
terminal.set_hexpand(true);
85-
terminal.set_vexpand(true);
86-
terminal.set_allow_hyperlink(true);
87-
// Determine shell: prefer zsh if available, fallback to bash
88-
let shell = if which("zsh").is_ok() {
89-
"/bin/zsh".to_string()
90-
} else {
91-
"/bin/bash".to_string()
92-
};
93-
// Spawn the shell in the terminal
94-
terminal.spawn_async(
95-
PtyFlags::DEFAULT,
96-
None,
97-
&[&shell],
98-
&[],
99-
glib::SpawnFlags::DEFAULT,
100-
|| {},
101-
-1,
102-
None::<&Cancellable>,
103-
|_| {},
104-
);
105-
overlay.set_child(Some(&terminal));
106-
// Create WebView for animations (transparent overlay)
107-
let context = WebContext::default().unwrap();
108-
let webview = WebView::builder().web_context(&context).build();
109-
webview.set_background_color(&RGBA::new(0.0, 0.0, 0.0, 0.0)); // Fully transparent
110-
// Load HTML with canvas and JavaScript for particle animations (simulating Hyperpower)
111-
let html = r#"
112-
<html>
113-
<head>
114-
<style>
115-
body, html {
116-
margin: 0;
117-
padding: 0;
118-
overflow: hidden;
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();
158-
}
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-
}
220-
}
221-
}
222-
});
29+
// Connect activate to build the UI
30+
app.connect_activate(build_ui);
31+
32+
// Run the application
33+
app.run();
22334
}

0 commit comments

Comments
 (0)