1 --- caja-1.28.0/src/timescale.c.orig 2024-02-26 08:42:41.085817612 +0100
2 +++ caja-1.28.0/src/timescale.c 2024-02-26 08:42:41.085766910 +0100
5 + * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
10 +#include "timescale.h"
13 +#include <libcaja-private/caja-zfs.h>
14 +#include <glib/gi18n-lib.h>
15 +#include <gdk/gdkkeysyms.h>
26 + char *mtime_short_str;
29 + char *used_space_str;
35 +struct TimeScalePrivate
42 + char *num_rev_string;
50 + gboolean scrollbar_set;
51 + gboolean key_pressed;
55 + GtkWidget *scrolled;
56 + GtkWidget *label_tip;
80 +static guint signals[LAST_SIGNAL];
82 +G_DEFINE_TYPE (TimeScale, timescale, GTK_TYPE_HBOX)
84 +#define TIMESCALE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_TIMESCALE, TimeScalePrivate))
87 +timescale_expose (GtkWidget *widget,
88 + GdkEventExpose *event, TimeScale *ts);
91 +query_tooltip (GtkWidget *widget,
94 + gboolean keyboard_tip,
95 + GtkTooltip *tooltip,
98 +key_pressed (GtkWidget *widget, GdkEventKey *event, TimeScale *ts);
100 +button_pressed (GtkWidget *widget, GdkEventButton *event, TimeScale *ts);
103 +print_snaps (GList *list)
110 + Snap *snap = (Snap*) tmp->data;
111 + printf ("=-= %d =-=\nname: %s\nmountpoint: %s\nmtime: %s\nused_space: %s\n",i,
112 + snap->name, snap->mountpoint, snap->mtime_str, snap->used_space_str);
119 +get_num_snap_string (GList *snap_list)
123 + GList *tmp = snap_list;
126 + char *size_str = NULL;
128 + for (tmp; tmp; tmp = tmp->next)
130 + Snap *snap = ((Snap*) tmp->data);
131 + total += snap->used_space;
137 + size_str = g_format_size (total);
140 + num_rev = g_strdup_printf (_("%d %s\n%s"),
141 + i - 1 /* Account for "Now" snapshot */,
143 + ngettext ("snapshot", "snapshots", i),
152 +get_date (GDate *date)
154 + return g_strdup_printf ("%d/%d/%d", g_date_get_day (date),
155 + g_date_get_month (date),
156 + g_date_get_year (date));
160 +trim_list_by_date (GList *list, int type)
166 + GDateWeekday weekday;
170 + time_now = time (NULL);
171 + g_date_set_time_t (&now, time_now);
172 + g_date_set_time_t (&range_min, time_now);
173 + GList *return_list = NULL;
175 + gboolean range = FALSE;
186 + weekday = g_date_get_weekday(&now);
187 + days_diff = weekday - G_DATE_MONDAY;
188 + memcpy (&range_max, &range_min, sizeof (GDate));
189 + g_date_subtract_days (&range_min, days_diff);
193 + g_date_subtract_days (&range_min, 7);
194 + weekday = g_date_get_weekday(&range_min);
195 + days_diff = weekday - G_DATE_MONDAY;
196 + g_date_subtract_days (&range_min, days_diff);
197 + memcpy (&range_max, &range_min, sizeof (GDate));
198 + g_date_add_days (&range_max, 6);
202 + g_date_set_dmy (&range_min, 1, g_date_get_month (&now),
203 + g_date_get_year (&now));
204 + g_date_set_time_t (&range_max, time_now);
208 + g_date_subtract_months (&range_min, 1);
209 + g_date_set_dmy (&range_min, 1,
210 + g_date_get_month (&range_min),
211 + g_date_get_year (&range_min));
212 + memcpy (&range_max, &range_min, sizeof (GDate));
213 + g_date_add_days (&range_max, g_date_get_days_in_month (g_date_get_month (&range_min), g_date_get_year (&range_min)) - 1);
220 + Snap* snap = (Snap*) list->data;
222 + if (snap->mtime != 0)
224 + g_date_set_time_t (&then, snap->mtime);
228 + if (g_date_get_julian (&now) - g_date_get_julian (&then) == days_diff)
229 + return_list = g_list_append (return_list, snap);
233 + if (g_date_compare (&then, &range_min) >= 0 && g_date_compare (&then, &range_max) <= 0)
234 + return_list = g_list_append (return_list, snap);
239 + return return_list;
243 +free_periods (TimeScale *ts)
245 + if (ts->priv->today)
247 + g_list_free (ts->priv->today);
248 + ts->priv->today = NULL;
250 + if (ts->priv->yesterday)
252 + g_list_free (ts->priv->yesterday);
253 + ts->priv->yesterday = NULL;
255 + if (ts->priv->this_week)
257 + g_list_free (ts->priv->this_week);
258 + ts->priv->this_week = NULL;
260 + if (ts->priv->last_week)
262 + g_list_free (ts->priv->last_week);
263 + ts->priv->last_week = NULL;
265 + if (ts->priv->this_month)
267 + g_list_free (ts->priv->this_month);
268 + ts->priv->this_month = NULL;
270 + if (ts->priv->last_month)
272 + g_list_free (ts->priv->last_month);
273 + ts->priv->last_month = NULL;
277 +static GtkListStore *
278 +create_periods (TimeScale *ts)
281 + GtkListStore* periods = gtk_list_store_new (3, G_TYPE_INT, G_TYPE_STRING, G_TYPE_POINTER);
285 + gtk_list_store_append (periods, &iter);
286 + gtk_list_store_set (periods, &iter, 0, ALL, 1, _("All"), 2, ts->priv->all_snaps, -1);
288 + ts->priv->today = trim_list_by_date (ts->priv->all_snaps, TODAY);
290 + if (ts->priv->today)
292 + gtk_list_store_append (periods, &iter);
293 + gtk_list_store_set (periods, &iter, 0, TODAY, 1, _("Today"), 2, ts->priv->today, -1);
296 + ts->priv->yesterday = trim_list_by_date (ts->priv->all_snaps, YESTERDAY);
297 + if (ts->priv->yesterday)
299 + gtk_list_store_append (periods, &iter);
300 + gtk_list_store_set (periods, &iter, 0, YESTERDAY, 1, _("Yesterday"), 2, ts->priv->yesterday, -1);
303 + ts->priv->this_week = trim_list_by_date (ts->priv->all_snaps, THIS_WEEK);
304 + if (ts->priv->this_week)
306 + gtk_list_store_append (periods, &iter);
307 + gtk_list_store_set (periods, &iter, 0, THIS_WEEK, 1, _("This Week"), 2, ts->priv->this_week, -1);
310 + ts->priv->last_week = trim_list_by_date (ts->priv->all_snaps, LAST_WEEK);
311 + if (ts->priv->last_week)
313 + gtk_list_store_append (periods, &iter);
314 + gtk_list_store_set (periods, &iter, 0, LAST_WEEK, 1, _("Last Week"), 2, ts->priv->last_week, -1);
317 + ts->priv->this_month = trim_list_by_date (ts->priv->all_snaps, THIS_MONTH);
318 + if (ts->priv->this_month)
320 + gtk_list_store_append (periods, &iter);
321 + gtk_list_store_set (periods, &iter, 0, THIS_MONTH, 1, _("This Month"), 2, ts->priv->this_month, -1);
324 + ts->priv->last_month = trim_list_by_date (ts->priv->all_snaps, LAST_MONTH);
325 + if (ts->priv->last_month)
327 + gtk_list_store_append (periods, &iter);
328 + gtk_list_store_set (periods, &iter, 0, LAST_MONTH, 1, _("Last Month"), 2, ts->priv->last_month, -1);
335 +period_changed (GtkComboBox *combo,
340 + GtkTreeModel *model;
344 + if (!gtk_combo_box_get_active_iter (combo, &iter))
347 + model = gtk_combo_box_get_model (combo);
349 + gtk_tree_model_get (model, &iter, 0, &type, 2, &period, -1);
351 + if (ts->priv->current_period == type)
354 + ts->priv->current_period = type;
356 + ts->priv->snaps = period;
358 + ts->priv->num_snaps = g_list_length (ts->priv->snaps);
359 + if (ts->priv->bar_x_end)
360 + g_free (ts->priv->bar_x_end);
362 + ts->priv->bar_x_end = g_new (int, g_list_length (ts->priv->snaps));
364 + ts->priv->current_pos = -1;
366 + if (ts->priv->num_rev_string)
367 + g_free (ts->priv->num_rev_string);
369 + ts->priv->num_rev_string = get_num_snap_string (ts->priv->snaps);
370 + gtk_label_set_label (GTK_LABEL (ts->priv->info), ts->priv->num_rev_string);
372 + gtk_widget_set_size_request (ts->priv->darea, ((BAR_SPACE + BAR_W_MAX ) * ts->priv->num_snaps) + PADDING * 2, 60);
374 + gtk_widget_queue_draw (ts->priv->darea);
378 +timescale_init (TimeScale *ts)
381 + GtkCellRenderer *renderer;
383 + ts->priv = TIMESCALE_GET_PRIVATE (ts);
384 + ts->priv->snaps = NULL;
385 + ts->priv->all_snaps = NULL;
386 + ts->priv->num_snaps = 0;
387 + ts->priv->bar_x_end = NULL;
388 + ts->priv->current_pos = 0;
389 + ts->priv->num_rev_string = NULL;
390 + ts->priv->current_period = ALL;
391 + ts->priv->today = NULL;
392 + ts->priv->yesterday = NULL;
393 + ts->priv->this_week = NULL;
394 + ts->priv->last_week = NULL;
395 + ts->priv->this_month = NULL;
396 + ts->priv->last_month = NULL;
397 + ts->priv->key_pressed = FALSE;
399 + gtk_box_set_homogeneous (GTK_BOX (ts), FALSE);
401 + /* setup drawing area */
403 + ts->priv->darea = gtk_drawing_area_new ();
405 + g_signal_connect(ts->priv->darea, "draw",
406 + G_CALLBACK(timescale_expose), ts);
408 + g_signal_connect (ts->priv->darea, "query-tooltip",
409 + G_CALLBACK (query_tooltip), ts);
411 + g_signal_connect(ts->priv->darea, "key-press-event",
412 + G_CALLBACK(key_pressed), ts);
413 + g_signal_connect(ts->priv->darea, "button_press_event",
414 + G_CALLBACK(button_pressed), ts);
415 + gtk_widget_set_can_focus(GTK_WIDGET (ts->priv->darea), TRUE);
416 + gtk_widget_add_events (GTK_WIDGET (ts->priv->darea), GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK);
417 + g_object_set (G_OBJECT (ts->priv->darea), "has-tooltip", TRUE, NULL);
418 + gtk_widget_set_size_request (GTK_WIDGET (ts->priv->darea), -1, 60);
420 + ts->priv->scrolled = gtk_scrolled_window_new (NULL, NULL);
421 + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (ts->priv->scrolled),
422 + GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
423 + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (ts->priv->scrolled),
425 + gtk_viewport_set_shadow_type (GTK_VIEWPORT (gtk_bin_get_child (GTK_BIN (ts->priv->scrolled))), GTK_SHADOW_NONE);
426 + gtk_widget_show (ts->priv->scrolled);
428 + ts->priv->label_tip = gtk_label_new ("Hello");
429 + gtk_widget_set_name (ts->priv->label_tip, "gtk-tooltip");
430 + g_object_ref_sink (ts->priv->label_tip);
431 + gtk_label_set_justify (GTK_LABEL (ts->priv->label_tip), GTK_JUSTIFY_CENTER);
433 + /* setup period combo and snap info */
435 + vbox = gtk_vbox_new (FALSE, 5);
436 + ts->priv->period = gtk_combo_box_new ();
437 + renderer = gtk_cell_renderer_text_new ();
438 + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (ts->priv->period),
441 + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (ts->priv->period), renderer,
444 + g_signal_connect (ts->priv->period, "changed", G_CALLBACK (period_changed), ts);
446 + ts->priv->info = gtk_label_new ("info\ninfo");
447 + gtk_label_set_justify (GTK_LABEL (ts->priv->info), GTK_JUSTIFY_CENTER);
448 + gtk_box_pack_start (GTK_BOX (vbox), ts->priv->period, FALSE, FALSE, 5);
449 + gtk_box_pack_end (GTK_BOX (vbox), ts->priv->info, FALSE, FALSE, 5);
451 + /* setup container */
453 + gtk_box_pack_start (GTK_BOX (ts), vbox, FALSE, FALSE, 0);
454 + gtk_box_pack_start (GTK_BOX (ts), ts->priv->scrolled, TRUE, TRUE, 0);
456 + gtk_widget_set_can_focus(GTK_WIDGET (ts), TRUE);
457 + gtk_widget_show_all (GTK_WIDGET (ts));
461 +get_max_snap_size (GList *snaps)
464 + float max_size = 0;
467 + GList *next = snaps->next;
468 + snap = (Snap*) snaps->data;
469 + if (snap->used_space > max_size)
470 + max_size = snap->used_space;
477 +get_now_snap (TimeScale* ts)
480 + last_snap = g_new0 (Snap, 1);
481 + last_snap->name = g_strdup (_("Now"));
482 + last_snap->mountpoint = g_strdup (_("None"));
483 + last_snap->mtime_str = g_strdup (_("Now"));
484 + last_snap->mtime_short_str = g_strdup (_("Now"));
485 + last_snap->used_space_str = g_strdup (_("-"));
486 + last_snap->used_space = 0.0;
487 + last_snap->type = NOW;
488 + last_snap->type_str = g_strdup (_("Current Directory"));
493 +get_type_str (SnapType type)
497 + case LOCAL_AUTOMATIC:
498 + return g_strdup (_("Automatic Snapshot"));
501 + return g_strdup (_("Manual Snapshot"));
503 + case REMOTE_AUTOMATIC:
504 + return g_strdup (_("Automatic Remote Backup"));
506 + case REMOTE_MANUAL:
507 + return g_strdup (_("Manual Remote Backup"));
516 +get_type (ZfsDataSet* snap)
520 + if (strstr (snap->name, "zfs-auto-snap"))
521 + return LOCAL_AUTOMATIC;
523 + return LOCAL_MANUAL;
527 + if (strstr (snap->name, "zfs-auto-snap"))
528 + return REMOTE_AUTOMATIC;
530 + return REMOTE_MANUAL;
535 +copy_zfs_list (GList *list)
538 + GList *new_list = NULL;
540 + GList *tmp_list = list;
543 + snap = (ZfsDataSet*) tmp_list->data;
544 + ts_shot = g_new0 (Snap, 1);
545 + ts_shot->name = g_strdup (snap->name);
546 + ts_shot->mountpoint = g_strdup (snap->mountpoint);
547 + ts_shot->mtime_str = g_strdup (snap->mtime_str);
548 + ts_shot->mtime_short_str = caja_date_as_string (snap->mtime, TRUE);
549 + ts_shot->used_space_str = g_strdup (snap->used_space_str);
550 + ts_shot->used_space = snap->used_space;
551 + ts_shot->mtime = snap->mtime;
552 + ts_shot->type = get_type (snap);
553 + ts_shot->type_str = get_type_str (ts_shot->type);
554 + new_list = g_list_append (new_list, ts_shot);
555 + tmp_list = tmp_list->next;
561 +free_snap (Snap *snap)
564 + g_free (snap->name);
565 + if (snap->mountpoint)
566 + g_free (snap->mountpoint);
567 + if (snap->mtime_str)
568 + g_free (snap->mtime_str);
569 + if (snap->mtime_short_str)
570 + g_free (snap->mtime_short_str);
571 + if (snap->used_space_str)
572 + g_free (snap->used_space_str);
573 + if (snap->type_str)
574 + g_free (snap->type_str);
580 +free_snap_list (GList *list)
582 + GList *tmp_list = list;
585 + free_snap ((Snap*) tmp_list->data);
586 + tmp_list = tmp_list->next;
592 +timescale_set_snapshots (TimeScale* ts, GList *list, int init_position)
594 + if (ts->priv->bar_x_end)
595 + g_free (ts->priv->bar_x_end);
597 + if (ts->priv->num_rev_string)
598 + g_free (ts->priv->num_rev_string);
600 + if (ts->priv->all_snaps)
601 + free_snap_list (ts->priv->all_snaps);
603 + ts->priv->all_snaps = copy_zfs_list (list);
604 + ts->priv->all_snaps = g_list_append (ts->priv->all_snaps, get_now_snap(ts));
605 + ts->priv->snaps = ts->priv->all_snaps;
606 + ts->priv->num_snaps = g_list_length (ts->priv->snaps);
608 + ts->priv->bar_x_end = g_new (int, g_list_length (ts->priv->snaps));
609 + ts->priv->current_pos = ts->priv->num_snaps - 1;
611 + if (init_position >= 0 && init_position <= ts->priv->num_snaps - 1)
612 + ts->priv->current_pos = init_position;
614 + ts->priv->num_rev_string = get_num_snap_string (ts->priv->snaps);
616 + gtk_label_set_label (GTK_LABEL (ts->priv->info), ts->priv->num_rev_string);
617 + ts->priv->current_period = ALL;
619 + gtk_combo_box_set_model (GTK_COMBO_BOX (ts->priv->period), GTK_TREE_MODEL (create_periods (ts)));
620 + gtk_combo_box_set_active (GTK_COMBO_BOX (ts->priv->period), ALL);
622 + gtk_widget_set_size_request (ts->priv->darea, ((BAR_SPACE + BAR_W_MAX) * ts->priv->num_snaps) + PADDING * 2, 60);
623 + ts->priv->scrollbar_set = FALSE;
629 + return g_object_new (TYPE_TIMESCALE, NULL);
633 +draw_type (cairo_t *cr, int x_c, int y_c, int w, SnapType type)
643 + cairo_move_to (cr,x,y_c);
644 + cairo_line_to (cr,x+w/2,y_c-w/2);
645 + cairo_line_to (cr,x+w,y_c);
647 + cairo_rectangle (cr, x, y, w, w/2);*/
649 + case LOCAL_AUTOMATIC:
650 + cairo_arc (cr, x_c, y_c, w/2, M_PI, M_PI*2);
652 + case REMOTE_MANUAL:
653 + /* cairo_rectangle (cr, x, y, w, w); */
654 + cairo_move_to (cr,x,y_c);
655 + cairo_line_to (cr,x+w/2,y_c+w/2);
656 + cairo_line_to (cr,x+w,y_c);
657 + cairo_line_to (cr,x+w/2,y_c-w/2);
659 + case REMOTE_AUTOMATIC:
660 + cairo_arc (cr, x_c, y_c, w/2, 0.0, M_PI*2);
668 +draw_rounded_bar (cairo_t *cr, int x, int y, double w, double h, int r)
670 + /* bottom y instead of top */
673 + if (h == 0 || h < (w / 2) + r)
676 + cairo_arc (cr, x+(w/2), y+.5, w/2, M_PI, M_PI*2);
677 + cairo_line_to (cr,x,y+.5);
688 + cairo_arc (cr, x+(w/2), y+(w/2), w/2, M_PI, M_PI*2); /* arc from H to C */
689 + cairo_line_to (cr,x+w,y+h-r); /* Move to D */
690 + cairo_curve_to(cr, x+w,y+h,x+w,y+h,x+w-r,y+h); /* Curve to E */
691 + cairo_line_to(cr, x+r,y+h); /* Line to F */
692 + cairo_curve_to(cr, x,y+h,x,y+h,x,y+h-r); /* Curve to G */
693 + cairo_line_to(cr, x,y+(w/2)); /* Line to H */
700 +draw_rounded_rec (cairo_t *cr, int x, int y, double w, double h, int r)
702 + /* bottom y instead of top */
707 + cairo_set_line_width (cr, 1);
708 + cairo_move_to (cr,x,y - .5);
709 + cairo_line_to (cr, x + w, y -.5);
722 + cairo_move_to (cr,x+r,y); /* Move to A */
723 + cairo_line_to (cr,x+w-r,y); /* Straight line to B */
724 + cairo_curve_to (cr,x+w,y,x+w,y,x+w,y+r); /* Curve to C, Control points are both at Q */
725 + cairo_line_to (cr,x+w,y+h-r); /* Move to D */
726 + cairo_curve_to(cr, x+w,y+h,x+w,y+h,x+w-r,y+h); /* Curve to E */
727 + cairo_line_to(cr, x+r,y+h); /* Line to F */
728 + cairo_curve_to(cr, x,y+h,x,y+h,x,y+h-r); /* Curve to G */
729 + cairo_line_to(cr, x,y+r); /* Line to H */
730 + cairo_curve_to(cr, x,y,x,y,x+r,y); /* Curve to A */
734 +set_cr_color (GtkWidget *widget, cairo_t* cr, SnapType type, double alpha)
741 + case REMOTE_MANUAL:
742 + s = gtk_widget_get_style(widget);
743 + gdk_cairo_set_source_color (cr, &s->dark[GTK_STATE_SELECTED]);
745 + case LOCAL_AUTOMATIC:
746 + case REMOTE_AUTOMATIC:
747 + s = gtk_widget_get_style(widget);
748 + gdk_cairo_set_source_color (cr, &s->light[GTK_STATE_SELECTED]);
751 + s = gtk_widget_get_style(widget);
752 + gdk_cairo_set_source_color (cr, &s->black);
759 +int get_snap_index_from_coord (TimeScale* ts, gdouble x, gdouble y)
763 + for (i = 0; i < ts->priv->num_snaps; i++)
765 + if (x < ts->priv->bar_x_end[i])
772 +timescale_expose (GtkWidget *widget,
773 + GdkEventExpose *event, TimeScale* ts)
775 + PangoContext *context;
776 + PangoFontMetrics *metrics;
777 + PangoRectangle logical_rect;
778 + gint ascent, descent;
779 + cairo_t *cr = gdk_cairo_create (gtk_widget_get_window (widget));
783 + int selected_x = -1;
784 + int remaining_timeline_space;
785 + int remaining_x_start;
786 + int remaining_x_end;
787 + int bar_space = BAR_SPACE;
788 + int bar_w = BAR_W_MAX;
789 + int line_padding = 3;
790 + float bar_max_h_inc;
793 + int line_height = 0;
794 + int timeline_line_height = 0;
795 + float max_size = 0;
796 + GList *view_snaps = NULL;
797 + int num_view_snaps = 0;
798 + PangoLayout *layout = pango_cairo_create_layout (cr);
799 + Snap *tmp_snap = NULL;
800 + gboolean space_left = TRUE;
801 + PangoFontDescription *timeline_font = NULL;
803 + if (gtk_widget_has_focus (widget)) {
804 + gtk_paint_focus (gtk_widget_get_style (widget), cr, gtk_widget_get_state (widget),
807 + gtk_widget_get_allocated_width(widget)-1, gtk_widget_get_allocated_height(widget)-1);
810 + if (!ts->priv->snaps)
813 + /* smaller font for timeline */
815 + timeline_font = pango_font_description_copy_static ((gtk_widget_get_style (widget))->font_desc);
816 + pango_font_description_set_size (timeline_font, pango_font_description_get_size (timeline_font) - (PANGO_SCALE*2));
818 + /* determine space needed for 2 lines of text + padding with
819 + * current widget->style->font_desc
820 + * and widget->style->font_desc - 1*/
822 + context = gtk_widget_get_pango_context (widget);
823 + metrics = pango_context_get_metrics (context, (gtk_widget_get_style (widget))->font_desc,
824 + pango_context_get_language (context));
825 + ascent = pango_font_metrics_get_ascent (metrics);
826 + descent = pango_font_metrics_get_descent (metrics);
827 + pango_font_metrics_unref (metrics);
829 + line_height = PANGO_PIXELS (ascent + descent);
831 + metrics = pango_context_get_metrics (context, timeline_font,
832 + pango_context_get_language (context));
833 + ascent = pango_font_metrics_get_ascent (metrics);
834 + descent = pango_font_metrics_get_descent (metrics);
835 + pango_font_metrics_unref (metrics);
837 + timeline_line_height = PANGO_PIXELS (ascent + descent);
841 + bar_max_h = gtk_widget_get_allocated_height(widget) - ((line_height + timeline_line_height) + PADDING * 4);
842 + y = gtk_widget_get_allocated_height(widget) - (line_height + (PADDING * 2));
844 + num_view_snaps = ts->priv->num_snaps;
845 + view_snaps = ts->priv->snaps;
847 + max_size = log ((float)get_max_snap_size (view_snaps));
849 + bar_max_h_inc = max_size / bar_max_h;
851 + if (!ts->priv->scrollbar_set)
853 + GtkAdjustment *adj;
854 + adj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (ts->priv->scrolled));
855 + gtk_adjustment_set_value (adj, gtk_adjustment_get_upper(adj) - gtk_adjustment_get_page_size (adj));
856 + gtk_adjustment_set_step_increment(adj, BAR_W_MAX + BAR_SPACE);
857 + gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (ts->priv->scrolled), adj);
858 + ts->priv->scrollbar_set = TRUE;
861 + /* draw the bars */
863 + cairo_set_line_width (cr, 1);
865 + for (i = 0; i < num_view_snaps; i++)
867 + tmp_snap = g_list_nth_data (view_snaps, i);
868 + int rounded_radius = ROUNDED_RADIUS;
870 + gboolean draw_bar = TRUE;
871 + double alpha = 1.0;
873 + if (tmp_snap->used_space != 0)
874 + height = (int) log (tmp_snap->used_space) / bar_max_h_inc;
876 + /*printf ("drawing %d height %d size %f log of size %f\n", i,
878 + tmp_snap->used_space, log (tmp_snap->used_space));*/
880 + if (height == 0 & tmp_snap->used_space != 0)
883 + if (tmp_snap->type == REMOTE_AUTOMATIC ||
884 + tmp_snap->type == REMOTE_MANUAL)
885 + height = bar_max_h - bar_max_h_inc; /* placeholder until we get rsync size */
887 + if (height < ROUNDED_RADIUS)
890 + /* printf ("height %d name %s size %s\n", height, tmp_snap->name, tmp_snap->used_space_str); */
892 + if (i == ts->priv->current_pos)
895 + cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1);
896 + draw_rounded_rec (cr, x-1, y+2, bar_w+2, bar_max_h+8, ROUNDED_RADIUS);
902 + selected_x = x-1 + ((bar_w+2) / 2);
904 + if (tmp_snap->type != NOW)
906 + char *selected_time_size = g_strdup_printf ("%s - %s",
907 + tmp_snap->mtime_str,
908 + tmp_snap->used_space_str);
909 + gdk_cairo_set_source_color (cr, gtk_widget_get_style(widget)->text);
910 + pango_layout_set_font_description (layout, gtk_widget_get_style(widget)->font_desc);
911 + pango_layout_set_text (layout, selected_time_size, -1);
912 + g_free (selected_time_size);
915 + pango_layout_set_text (layout, tmp_snap->mtime_str, -1);
918 + cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.8);
920 + ts->priv->bar_x_end[i] = x + bar_w;
925 + float tmp_w = bar_w;
926 + set_cr_color (widget, cr, tmp_snap->type, 1.0);
927 + if (tmp_snap->type == LOCAL_AUTOMATIC || tmp_snap->type == LOCAL_MANUAL)
933 + if (tmp_snap->type == LOCAL_AUTOMATIC || tmp_snap->type == REMOTE_AUTOMATIC)
934 + draw_rounded_bar (cr, x, tmp_y, tmp_w, height, rounded_radius);
935 + else if (tmp_snap->type == LOCAL_MANUAL || tmp_snap->type == REMOTE_MANUAL)
936 + draw_rounded_rec (cr, x, tmp_y, tmp_w, height, rounded_radius);
937 + else /* Now Shape */
938 + draw_type (cr, (x + ((bar_w+bar_space)/2)) - .5, y - (bar_max_h/2), bar_w - 4, REMOTE_MANUAL);
940 + if (tmp_snap->type == REMOTE_MANUAL || tmp_snap->type == REMOTE_AUTOMATIC || tmp_snap->type == NOW)
946 + x += bar_w + bar_space;
951 + /* ensure selected bar is visible on key press when scrollbar is enabled */
953 + if (ts->priv->current_pos != -1 && ts->priv->key_pressed)
956 + GtkAdjustment *adj;
957 + adj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (ts->priv->scrolled));
958 + ts->priv->key_pressed = FALSE;
960 + if (gtk_adjustment_get_value (adj) > selected_x)
962 + gtk_adjustment_set_value (adj, selected_x - BAR_W_MAX);
963 + gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (ts->priv->scrolled), adj);
965 + if (gtk_adjustment_get_value (adj) + gtk_adjustment_get_page_size (adj) < selected_x)
967 + gtk_adjustment_set_value (adj, (selected_x + BAR_W_MAX) - gtk_adjustment_get_page_size (adj));
968 + gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (ts->priv->scrolled), adj);
972 + pango_layout_set_font_description (layout, gtk_widget_get_style(widget)->font_desc);
974 + /* try to center the selected text */
976 + pango_layout_get_pixel_extents (layout,NULL, &logical_rect);
978 + if (ts->priv->current_pos != -1 && selected_x != -1)
981 + int right_space = last_bar_x - selected_x;
983 + if (logical_rect.width /2 > selected_x)
984 + /* no space on the left, left align */
985 + selected_x = PADDING;
986 + else if (logical_rect.width /2 > right_space)
987 + /* no space on the right, right align */
988 + selected_x = last_bar_x - logical_rect.width;
990 + selected_x -= logical_rect.width /2;
992 + if (selected_x < 0)
993 + selected_x = PADDING;
995 + /* draw background */
996 + cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1);
997 + draw_rounded_rec (cr, selected_x-2, line_height + 3 , logical_rect.width + 4, line_height+1, ROUNDED_RADIUS);
1001 + /* then selected text */
1002 + gdk_cairo_set_source_color (cr, gtk_widget_get_style(widget)->text);
1003 + cairo_move_to(cr, selected_x, PADDING);
1004 + pango_cairo_show_layout (cr, layout);
1010 + * try to draw oldest
1011 + * then "now" first
1012 + * then in between dates
1013 + * draw additional is possible starting with newest first */
1018 + /* Can the oldest time fit ? */
1019 + tmp_snap = g_list_nth_data (view_snaps, 0);
1020 + pango_layout_set_text (layout, tmp_snap->mtime_short_str, -1);
1021 + pango_layout_set_font_description (layout, timeline_font);
1022 + pango_layout_get_pixel_extents (layout,NULL, &logical_rect);
1024 + if (logical_rect.width > gtk_widget_get_allocated_width(widget))
1027 + /* draw anchor line */
1029 + x += bar_w/2 + .5;
1031 + cairo_set_line_width (cr, 1);
1032 + gdk_cairo_set_source_color (cr, gtk_widget_get_style(widget)->text_aa);
1033 + cairo_move_to (cr, x, gtk_widget_get_allocated_height(widget) - ((line_height + PADDING*2)-1));
1034 + cairo_line_to (cr, x, gtk_widget_get_allocated_height(widget) - (line_height/2 + PADDING)-.5);
1035 + cairo_line_to (cr, x+2.5, gtk_widget_get_allocated_height(widget) - (line_height/2 + PADDING)-.5);
1040 + gdk_cairo_set_source_color (cr, gtk_widget_get_style(widget)->text_aa);
1041 + cairo_move_to(cr, x, gtk_widget_get_allocated_height(widget) - (line_height + PADDING));
1042 + pango_cairo_show_layout (cr, layout);
1044 + remaining_timeline_space = last_bar_x - (x + logical_rect.width);
1046 + remaining_x_start = x + logical_rect.width;
1048 + /* try to draw last item */
1050 + tmp_snap = g_list_nth_data (view_snaps, num_view_snaps-1);
1051 + pango_layout_set_text (layout, tmp_snap->mtime_short_str, -1);
1052 + pango_layout_get_pixel_extents (layout,NULL, &logical_rect);
1054 + if (remaining_timeline_space < (logical_rect.width + bar_w))
1057 + remaining_timeline_space -= logical_rect.width + bar_w;
1062 + x -= bar_space + bar_w/2 + 0.5;
1064 + cairo_move_to (cr, x, gtk_widget_get_allocated_height(widget) - ((line_height + PADDING*2)-2));
1065 + cairo_line_to (cr, x, gtk_widget_get_allocated_height(widget) - (line_height/2 + PADDING)-.5);
1066 + cairo_line_to (cr, x-2.5, gtk_widget_get_allocated_height(widget) - (line_height/2 + PADDING)-.5);
1069 + cairo_move_to(cr, x - (logical_rect.width + 3.5),
1070 + gtk_widget_get_allocated_height(widget) - (line_height + PADDING));
1071 + pango_cairo_show_layout (cr, layout);
1073 + remaining_x_end = x - (logical_rect.width + 3.5);
1075 + /* now find the next bar that we can to the timeline and loop */
1078 + while (space_left)
1080 + int bar = get_snap_index_from_coord (ts, remaining_x_start, 0);
1081 + /* get the next snap */
1083 + if (bar >= num_view_snaps)
1086 + tmp_snap = g_list_nth_data (view_snaps, bar);
1087 + pango_layout_set_text (layout, tmp_snap->mtime_short_str, -1);
1089 + pango_layout_get_pixel_extents (layout,NULL, &logical_rect);
1091 + if (remaining_timeline_space < logical_rect.width + 4)
1094 + /* get middle x coord of current bar */
1096 + x = PADDING + ((bar_w + bar_space) * bar) + bar_w / 2;
1098 + if ( x + 4 + logical_rect.width > remaining_x_end)
1101 + /* draw anchor and text */
1104 + cairo_move_to (cr, x, gtk_widget_get_allocated_height(widget) - ((line_height + PADDING*2)-1));
1105 + cairo_line_to (cr, x, gtk_widget_get_allocated_height(widget) - (line_height/2 + PADDING)-.5);
1106 + cairo_line_to (cr, x+2.5, gtk_widget_get_allocated_height(widget) - (line_height/2 + PADDING)-.5);
1111 + cairo_move_to(cr, x,
1112 + gtk_widget_get_allocated_height(widget) - (line_height + PADDING));
1113 + pango_cairo_show_layout (cr, layout);
1115 + remaining_x_start = x + logical_rect.width;
1117 + remaining_timeline_space = remaining_x_end - remaining_x_start;
1119 + if (remaining_timeline_space <= 0)
1120 + space_left = FALSE;
1123 + if (timeline_font)
1124 + pango_font_description_free(timeline_font);
1125 + cairo_destroy(cr);
1131 +key_pressed (GtkWidget *widget, GdkEventKey *event, TimeScale* ts)
1133 + switch (event->keyval)
1135 + case GDK_KEY_KP_Left:
1136 + case GDK_KEY_KP_Up:
1137 + case GDK_KEY_Left:
1140 + if (ts->priv->current_pos >= 1)
1142 + ts->priv->current_pos -= 1;
1143 + gtk_widget_queue_draw (widget);
1144 + ts->priv->key_pressed = TRUE;
1145 + g_signal_emit (ts, signals[VALUE_CHANGED], 0);
1146 + /* printf ("key_pressed back %d\n", ts->priv->current_pos); */
1149 + case GDK_KEY_KP_Right:
1150 + case GDK_KEY_KP_Down:
1151 + case GDK_KEY_Right:
1152 + case GDK_KEY_Down:
1153 + if (ts->priv->current_pos <= ts->priv->num_snaps - 2)
1155 + ts->priv->current_pos += 1;
1156 + gtk_widget_queue_draw (widget);
1157 + ts->priv->key_pressed = TRUE;
1158 + g_signal_emit (ts, signals[VALUE_CHANGED], 0);
1159 + /* printf ("key_pressed forward %d\n", ts->priv->current_pos); */
1168 +int timescale_get_position (TimeScale* ts)
1170 + /* translate into all_snaps position */
1171 + gconstpointer data;
1172 + data = g_list_nth_data (ts->priv->snaps, ts->priv->current_pos);
1173 + return g_list_index (ts->priv->all_snaps, data);
1176 +static int match_func (ZfsDataSet *set, char *dir)
1178 + return strcmp (set->mountpoint, dir);
1182 +timescale_set_position (TimeScale* ts, char *mountpoint)
1184 + gboolean redraw = FALSE;
1185 + int num_snaps = g_list_length (ts->priv->all_snaps);
1189 + GList* match = NULL;
1190 + match = g_list_find_custom (ts->priv->all_snaps, mountpoint, (GCompareFunc)match_func);
1191 + pos = g_list_index (ts->priv->all_snaps, match->data);
1192 + if (pos != -1 && ts->priv->current_pos != pos)
1195 + ts->priv->current_pos = pos;
1199 + { /* Now special case */
1200 + if (ts->priv->current_pos != num_snaps - 1)
1203 + ts->priv->current_pos = num_snaps - 1;
1208 + gtk_widget_queue_draw (GTK_WIDGET (ts));
1212 +button_pressed (GtkWidget *widget, GdkEventButton *event, TimeScale* ts)
1216 + gtk_widget_grab_focus (widget);
1217 + new_pos = get_snap_index_from_coord (ts, event->x, event->y);
1219 + if (new_pos == -1)
1222 + if (new_pos != ts->priv->current_pos)
1224 + ts->priv->current_pos = new_pos;
1225 + /* printf ("button_pressed (%g,%g) selected %d\n", event->x, event->y, ts->priv->current_pos); */
1226 + g_signal_emit (ts, signals[VALUE_CHANGED], 0);
1227 + gtk_widget_queue_draw (widget);
1232 +query_tooltip (GtkWidget *widget,
1235 + gboolean keyboard_tip,
1236 + GtkTooltip *tooltip,
1239 + static gboolean set = FALSE;
1240 + static int old_pos = -1;
1241 + TimeScale* ts = TIMESCALE (data);
1242 + int new_pos = get_snap_index_from_coord (ts, x, y);
1243 + /* printf ("in query_tooltip new_pos %d total %d num_snap %d\n", new_pos, g_list_length (ts->priv->snaps), ts->priv->num_snaps); */
1244 + Snap *tmp_snap = NULL;
1247 + if (new_pos == -1)
1250 + if (new_pos != old_pos)
1252 + old_pos = new_pos;
1256 + if (new_pos >= ts->priv->num_snaps)
1259 + tmp_snap = g_list_nth_data (ts->priv->snaps, new_pos);
1261 + tip = g_strdup_printf ("%s\nCreated: %s\nSize: %s\nName: %s", tmp_snap->type_str, tmp_snap->mtime_str, tmp_snap->used_space_str, tmp_snap->name);
1262 + gtk_label_set_text (GTK_LABEL(ts->priv->label_tip), tip);
1263 + gtk_tooltip_set_custom (tooltip, ts->priv->label_tip);
1269 +timescale_class_init (TimeScaleClass *class)
1271 + GtkWidgetClass *widget_class;
1272 + GtkScaleClass *scale_class;
1273 + GObjectClass *object_class;
1275 + object_class = G_OBJECT_CLASS (class);
1276 + g_type_class_add_private (class, sizeof (TimeScalePrivate));
1278 + widget_class = GTK_WIDGET_CLASS (class);
1280 + signals[VALUE_CHANGED] =
1281 + g_signal_new ("value-changed",
1282 + G_TYPE_FROM_CLASS (object_class),
1283 + G_SIGNAL_RUN_LAST,
1284 + G_STRUCT_OFFSET (TimeScaleClass, value_changed),
1286 + g_cclosure_marshal_VOID__VOID,
1290 --- caja-1.28.0/src/timescale.h.orig 2024-02-26 08:42:41.085975314 +0100
1291 +++ caja-1.28.0/src/timescale.h 2024-02-26 08:42:41.085928246 +0100
1293 +#ifndef __TIMESCALE_H__
1294 +#define __TIMESCALE_H__
1297 +#include <gdk/gdk.h>
1298 +#include <gtk/gtk.h>
1303 +#define TYPE_TIMESCALE (timescale_get_type ())
1304 +#define TIMESCALE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_TIMESCALE, TimeScale))
1305 +#define TIMESCALE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_TIMESCALE, TimeScaleClass))
1306 +#define IS_TIMESCALE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_TIMESCALE))
1307 +#define IS_TIMESCALE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_TIMESCALE))
1308 +#define TIMESCALE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_TIMESCALE, TimeScaleClass))
1311 +typedef struct _TimeScale TimeScale;
1312 +typedef struct _TimeScaleClass TimeScaleClass;
1313 +typedef struct TimeScalePrivate TimeScalePrivate;
1318 + TimeScalePrivate *priv;
1321 +struct _TimeScaleClass
1323 + GtkHBoxClass parent_class;
1324 + void (* value_changed) (TimeScale *timescale);
1329 +GType timescale_get_type (void) G_GNUC_CONST;
1330 +GtkWidget* timescale_new ();
1331 +void timescale_set_snapshots (TimeScale* ts, GList *list, int init_position);
1332 +int timescale_get_position (TimeScale* ts);
1333 +void timescale_set_position (TimeScale* ts, char *mountpoint);
1336 +#define ROUNDED_RADIUS 6
1350 +#endif /* __TIMESCALE_H__ */