gardesk/gartop / 06bdaf3

Browse files

fix header text positioning and daemon connection handling

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
06bdaf389805eb6bb38ea8592c1b2a34b78d6af9
Parents
b4e3ac2
Tree
a93e835

2 changed files

StatusFile+-
M gartop/src/gui/app.rs 27 19
M gartop/src/gui/header.rs 4 2
gartop/src/gui/app.rsmodified
@@ -31,7 +31,7 @@ pub struct App {
3131
     should_quit: bool,
3232
     width: u32,
3333
     height: u32,
34
-    daemon_conn: Option<UnixStream>,
34
+    daemon_available: bool,
3535
     last_refresh: Instant,
3636
     status: Option<StatusInfo>,
3737
     cpu_stats: Option<CpuStats>,
@@ -74,8 +74,8 @@ impl App {
7474
         // Create header bar
7575
         let header = HeaderBar::new(Rect::new(0, 0, width, HEADER_HEIGHT));
7676
 
77
-        // Try to connect to daemon
78
-        let daemon_conn = Self::connect_daemon();
77
+        // Check if daemon is available
78
+        let daemon_available = Self::check_daemon();
7979
 
8080
         Ok(Self {
8181
             window,
@@ -86,7 +86,7 @@ impl App {
8686
             should_quit: false,
8787
             width,
8888
             height,
89
-            daemon_conn,
89
+            daemon_available,
9090
             last_refresh: Instant::now() - std::time::Duration::from_secs(10), // force immediate refresh
9191
             status: None,
9292
             cpu_stats: None,
@@ -94,25 +94,26 @@ impl App {
9494
         })
9595
     }
9696
 
97
-    /// Connect to the daemon, returns None if connection fails.
98
-    fn connect_daemon() -> Option<UnixStream> {
97
+    /// Check if daemon is available by attempting a connection.
98
+    fn check_daemon() -> bool {
9999
         let path = gartop_ipc::socket_path();
100100
         match UnixStream::connect(&path) {
101
-            Ok(stream) => {
102
-                stream.set_nonblocking(false).ok()?;
103
-                tracing::info!("Connected to daemon at {}", path.display());
104
-                Some(stream)
101
+            Ok(_) => {
102
+                tracing::info!("Daemon available at {}", path.display());
103
+                true
105104
             }
106105
             Err(e) => {
107
-                tracing::warn!("Failed to connect to daemon: {}", e);
108
-                None
106
+                tracing::warn!("Daemon not available: {}", e);
107
+                false
109108
             }
110109
         }
111110
     }
112111
 
113112
     /// Send a command to the daemon and get response.
114
-    fn send_command(&mut self, cmd: &Command) -> Option<Response> {
115
-        let stream = self.daemon_conn.as_mut()?;
113
+    /// Creates a fresh connection for each command since daemon closes after response.
114
+    fn send_command(&self, cmd: &Command) -> Option<Response> {
115
+        let path = gartop_ipc::socket_path();
116
+        let mut stream = UnixStream::connect(&path).ok()?;
116117
 
117118
         // Send command
118119
         let json = serde_json::to_string(cmd).ok()?;
@@ -120,7 +121,7 @@ impl App {
120121
         stream.flush().ok()?;
121122
 
122123
         // Read response
123
-        let mut reader = BufReader::new(stream.try_clone().ok()?);
124
+        let mut reader = BufReader::new(&stream);
124125
         let mut line = String::new();
125126
         reader.read_line(&mut line).ok()?;
126127
 
@@ -129,8 +130,11 @@ impl App {
129130
 
130131
     /// Refresh data from daemon.
131132
     fn refresh_data(&mut self) {
133
+        let mut any_success = false;
134
+
132135
         // Get status
133136
         if let Some(resp) = self.send_command(&Command::Status) {
137
+            any_success = true;
134138
             if resp.success {
135139
                 self.status = resp.data.and_then(|d| serde_json::from_value(d).ok());
136140
             }
@@ -138,6 +142,7 @@ impl App {
138142
 
139143
         // Get CPU stats
140144
         if let Some(resp) = self.send_command(&Command::GetCpu) {
145
+            any_success = true;
141146
             if resp.success {
142147
                 self.cpu_stats = resp.data.and_then(|d| serde_json::from_value(d).ok());
143148
             }
@@ -145,11 +150,14 @@ impl App {
145150
 
146151
         // Get memory stats
147152
         if let Some(resp) = self.send_command(&Command::GetMemory) {
153
+            any_success = true;
148154
             if resp.success {
149155
                 self.memory_stats = resp.data.and_then(|d| serde_json::from_value(d).ok());
150156
             }
151157
         }
152158
 
159
+        // Update daemon availability based on whether any command succeeded
160
+        self.daemon_available = any_success;
153161
         self.last_refresh = Instant::now();
154162
     }
155163
 
@@ -206,7 +214,7 @@ impl App {
206214
         let x = 20.0;
207215
         let line_height = 24.0;
208216
 
209
-        if self.daemon_conn.is_none() {
217
+        if !self.daemon_available {
210218
             self.renderer.text(
211219
                 "Not connected to daemon",
212220
                 x,
@@ -394,14 +402,14 @@ impl App {
394402
                 InputEvent::Idle => {
395403
                     // Periodic refresh
396404
                     if self.last_refresh.elapsed().as_secs_f64() >= REFRESH_INTERVAL {
397
-                        if self.daemon_conn.is_some() {
405
+                        if self.daemon_available {
398406
                             self.refresh_data();
399407
                             self.update_header();
400408
                             ev_loop.request_redraw();
401409
                         } else {
402410
                             // Try reconnecting
403
-                            self.daemon_conn = Self::connect_daemon();
404
-                            if self.daemon_conn.is_some() {
411
+                            self.daemon_available = Self::check_daemon();
412
+                            if self.daemon_available {
405413
                                 ev_loop.request_redraw();
406414
                             }
407415
                             self.last_refresh = Instant::now();
gartop/src/gui/header.rsmodified
@@ -42,7 +42,9 @@ impl HeaderBar {
4242
             color: theme.text,
4343
             ..Default::default()
4444
         };
45
-        renderer.text("gartop", 16.0, self.bounds.y as f64 + 20.0, &title_style)?;
45
+        // Center text vertically (y is baseline, so add font_size + padding)
46
+        let text_y = self.bounds.y as f64 + (self.bounds.height as f64 + title_style.font_size) / 2.0;
47
+        renderer.text("gartop", 16.0, text_y, &title_style)?;
4648
 
4749
         // Stats summary on right side
4850
         let stats_style = TextStyle {
@@ -72,7 +74,7 @@ impl HeaderBar {
7274
         // Position from right side
7375
         let right_margin = 16.0;
7476
         let spacing = 20.0;
75
-        let y = self.bounds.y as f64 + 20.0;
77
+        let y = self.bounds.y as f64 + (self.bounds.height as f64 + stats_style.font_size) / 2.0;
7678
 
7779
         let uptime_width = renderer.measure_text(&uptime_text, &stats_style)?.width as f64;
7880
         let mem_width = renderer.measure_text(&mem_text, &mem_style)?.width as f64;