@@ -34,11 +34,13 @@ typedef struct {
3434 GtkWidget * wind_label ;
3535 GtkWidget * sun_label ;
3636 GtkWidget * web_view ;
37+ GtkWidget * overlay_vbox ;
3738
3839 /* State */
3940 WeatherData weather ;
4041 AnimState anim ;
4142 gboolean fullscreen ;
43+ double drift_time ;
4244
4345 /* Configuration */
4446 double latitude ;
@@ -114,8 +116,9 @@ static void update_weather_labels(void)
114116 return ;
115117 }
116118
117- char temp_buf [32 ];
118- snprintf (temp_buf , sizeof (temp_buf ), "%.0f\u00B0C" , app .weather .temperature );
119+ char temp_buf [64 ];
120+ snprintf (temp_buf , sizeof (temp_buf ), "%.0f\u00B0C \U0001F4A7 %d%%" ,
121+ app .weather .temperature , app .weather .humidity );
119122 gtk_label_set_text (GTK_LABEL (app .temp_label ), temp_buf );
120123
121124 gtk_label_set_text (GTK_LABEL (app .desc_label ),
@@ -150,6 +153,17 @@ static gboolean on_draw(GtkWidget *widget, cairo_t *cr, gpointer data)
150153 return FALSE;
151154}
152155
156+ static void on_drawing_area_size_allocate (GtkWidget * widget ,
157+ GdkRectangle * allocation ,
158+ gpointer data )
159+ {
160+ (void )widget ;
161+ (void )data ;
162+
163+ app .anim .width = allocation -> width ;
164+ app .anim .height = allocation -> height ;
165+ }
166+
153167/* ------------------------------------------------------------------ */
154168/* Timers */
155169/* ------------------------------------------------------------------ */
@@ -168,6 +182,22 @@ static gboolean on_clock_tick(gpointer data)
168182{
169183 (void )data ;
170184 update_clock_label ();
185+
186+ /* Slow circular drift of text overlay to prevent screen burn-in.
187+ * Full cycle ~5 minutes, radius ~15 pixels -- barely noticeable.
188+ * Use opposing margins so the total stays constant and GTK
189+ * never sees a negative value or an out-of-bounds allocation. */
190+ app .drift_time += 1.0 ;
191+ double period = 300.0 ; /* seconds per full circle */
192+ double radius = 15.0 ; /* pixels */
193+ int dx = (int )(sin (app .drift_time * 2.0 * M_PI / period ) * radius );
194+ int dy = (int )(cos (app .drift_time * 2.0 * M_PI / period ) * radius );
195+
196+ gtk_widget_set_margin_start (app .overlay_vbox , (int )radius + dx );
197+ gtk_widget_set_margin_end (app .overlay_vbox , (int )radius - dx );
198+ gtk_widget_set_margin_top (app .overlay_vbox , (int )radius + dy );
199+ gtk_widget_set_margin_bottom (app .overlay_vbox , (int )radius - dy );
200+
171201 return G_SOURCE_CONTINUE ;
172202}
173203
@@ -209,15 +239,10 @@ static gboolean on_key_press(GtkWidget *widget, GdkEventKey *event,
209239 return FALSE;
210240}
211241
212- static gboolean on_button_press (GtkWidget * widget , GdkEventButton * event ,
213- gpointer data )
242+ static void toggle_web_view (void )
214243{
215- (void )widget ;
216- (void )event ;
217- (void )data ;
218-
219244 if (!app .web_url || !app .web_url [0 ])
220- return FALSE ;
245+ return ;
221246
222247 const gchar * current = gtk_stack_get_visible_child_name (GTK_STACK (app .stack ));
223248
@@ -228,7 +253,7 @@ static gboolean on_button_press(GtkWidget *widget, GdkEventButton *event,
228253 app .webview_timeout = 0 ;
229254 }
230255 gtk_stack_set_visible_child_name (GTK_STACK (app .stack ), "weather" );
231- return TRUE ;
256+ return ;
232257 }
233258
234259 /* Switch to web view */
@@ -238,6 +263,27 @@ static gboolean on_button_press(GtkWidget *widget, GdkEventButton *event,
238263 if (app .webview_timeout )
239264 g_source_remove (app .webview_timeout );
240265 app .webview_timeout = g_timeout_add_seconds (30 , on_webview_timeout , NULL );
266+ }
267+
268+ static gboolean on_button_press (GtkWidget * widget , GdkEventButton * event ,
269+ gpointer data )
270+ {
271+ (void )widget ;
272+ (void )event ;
273+ (void )data ;
274+
275+ toggle_web_view ();
276+ return TRUE;
277+ }
278+
279+ static gboolean on_touch_event (GtkWidget * widget , GdkEventTouch * event ,
280+ gpointer data )
281+ {
282+ (void )widget ;
283+ (void )data ;
284+
285+ if (event -> type == GDK_TOUCH_END )
286+ toggle_web_view ();
241287
242288 return TRUE;
243289}
@@ -251,6 +297,8 @@ static GtkWidget *create_weather_view(void)
251297 /* Drawing area as the background */
252298 app .drawing_area = gtk_drawing_area_new ();
253299 g_signal_connect (app .drawing_area , "draw" , G_CALLBACK (on_draw ), NULL );
300+ g_signal_connect (app .drawing_area , "size-allocate" ,
301+ G_CALLBACK (on_drawing_area_size_allocate ), NULL );
254302
255303 /* Overlay labels */
256304 app .time_label = gtk_label_new ("--:--" );
@@ -283,6 +331,7 @@ static GtkWidget *create_weather_view(void)
283331 GtkWidget * vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL , 10 );
284332 gtk_widget_set_halign (vbox , GTK_ALIGN_CENTER );
285333 gtk_widget_set_valign (vbox , GTK_ALIGN_CENTER );
334+ app .overlay_vbox = vbox ;
286335 gtk_box_pack_start (GTK_BOX (vbox ), app .time_label , FALSE, FALSE, 0 );
287336 gtk_box_pack_start (GTK_BOX (vbox ), app .temp_label , FALSE, FALSE, 0 );
288337 gtk_box_pack_start (GTK_BOX (vbox ), app .desc_label , FALSE, FALSE, 0 );
@@ -418,9 +467,13 @@ int main(int argc, char *argv[])
418467 gtk_window_fullscreen (GTK_WINDOW (app .window ));
419468
420469 /* Enable input events on the window */
421- gtk_widget_add_events (app .window , GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK );
470+ gtk_widget_add_events (app .window ,
471+ GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK |
472+ GDK_TOUCH_MASK );
422473 g_signal_connect (app .window , "button-press-event" ,
423474 G_CALLBACK (on_button_press ), NULL );
475+ g_signal_connect (app .window , "touch-event" ,
476+ G_CALLBACK (on_touch_event ), NULL );
424477 g_signal_connect (app .window , "key-press-event" ,
425478 G_CALLBACK (on_key_press ), NULL );
426479
@@ -439,8 +492,8 @@ int main(int argc, char *argv[])
439492
440493 gtk_container_add (GTK_CONTAINER (app .window ), app .stack );
441494
442- /* Initialize animation */
443- anim_init (& app .anim , 1024 , 600 );
495+ /* Initialize animation -- actual size comes from size-allocate */
496+ anim_init (& app .anim , 1024 , 600 ); /* defaults, overridden on realize */
444497
445498 /* Initial weather fetch */
446499 app .weather = weather_fetch (app .latitude , app .longitude );
0 commit comments