about summary refs log tree commit diff
path: root/nixpkgs/pkgs/desktops/pantheon/desktop/wingpanel-indicators/datetime/207.patch
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/pkgs/desktops/pantheon/desktop/wingpanel-indicators/datetime/207.patch')
-rw-r--r--nixpkgs/pkgs/desktops/pantheon/desktop/wingpanel-indicators/datetime/207.patch4726
1 files changed, 0 insertions, 4726 deletions
diff --git a/nixpkgs/pkgs/desktops/pantheon/desktop/wingpanel-indicators/datetime/207.patch b/nixpkgs/pkgs/desktops/pantheon/desktop/wingpanel-indicators/datetime/207.patch
deleted file mode 100644
index c4d6d8574a53..000000000000
--- a/nixpkgs/pkgs/desktops/pantheon/desktop/wingpanel-indicators/datetime/207.patch
+++ /dev/null
@@ -1,4726 +0,0 @@
-From 20228e34bf97f67b1dd542a22e92cd90f0db5c72 Mon Sep 17 00:00:00 2001
-From: Dirli <litandrej85@gmail.com>
-Date: Thu, 9 Apr 2020 16:30:16 +0300
-Subject: [PATCH 1/8] added a single namespace
-
----
- meson.build                                   |  14 +-
- src/DateIterator.vala                         |  82 -----
- src/DateRange.vala                            |  66 ----
- src/Indicator.vala                            | 341 +++++++++---------
- .../calendar => Models}/CalendarModel.vala    |   4 +-
- src/Services/TimeManager.vala                 | 230 ++++++------
- src/Util/DateIterator.vala                    |  84 +++++
- src/Util/DateRange.vala                       |  68 ++++
- src/{Widgets/calendar => Util}/Util.vala      |   8 +-
- src/Widgets/CalendarView.vala                 | 185 ++++++++++
- src/Widgets/EventRow.vala                     | 184 +++++-----
- src/Widgets/{calendar => }/Grid.vala          |  12 +-
- src/Widgets/GridDay.vala                      | 180 +++++++++
- src/Widgets/PanelLabel.vala                   |  80 ++--
- src/Widgets/calendar/CalendarView.vala        | 183 ----------
- src/Widgets/calendar/GridDay.vala             | 178 ---------
- 16 files changed, 957 insertions(+), 942 deletions(-)
- delete mode 100644 src/DateIterator.vala
- delete mode 100644 src/DateRange.vala
- rename src/{Widgets/calendar => Models}/CalendarModel.vala (99%)
- create mode 100644 src/Util/DateIterator.vala
- create mode 100644 src/Util/DateRange.vala
- rename src/{Widgets/calendar => Util}/Util.vala (96%)
- create mode 100644 src/Widgets/CalendarView.vala
- rename src/Widgets/{calendar => }/Grid.vala (95%)
- create mode 100644 src/Widgets/GridDay.vala
- delete mode 100644 src/Widgets/calendar/CalendarView.vala
- delete mode 100644 src/Widgets/calendar/GridDay.vala
-
-diff --git a/meson.build b/meson.build
-index 2555723..b44c5bd 100644
---- a/meson.build
-+++ b/meson.build
-@@ -39,16 +39,16 @@ endif
- shared_module(
-     meson.project_name(),
-     gresource,
--    'src/DateIterator.vala',
--    'src/DateRange.vala',
-     'src/Indicator.vala',
-+    'src/Util/DateIterator.vala',
-+    'src/Util/DateRange.vala',
-+    'src/Util/Util.vala',
-+    'src/Models/CalendarModel.vala',
-+    'src/Widgets/CalendarView.vala',
-     'src/Widgets/EventRow.vala',
-+    'src/Widgets/Grid.vala',
-+    'src/Widgets/GridDay.vala',
-     'src/Widgets/PanelLabel.vala',
--    'src/Widgets/calendar/CalendarModel.vala',
--    'src/Widgets/calendar/CalendarView.vala',
--    'src/Widgets/calendar/Grid.vala',
--    'src/Widgets/calendar/GridDay.vala',
--    'src/Widgets/calendar/Util.vala',
-     'src/Services/TimeManager.vala',
-     dependencies: [
-         dependency('glib-2.0'),
-diff --git a/src/DateIterator.vala b/src/DateIterator.vala
-deleted file mode 100644
-index 961895b..0000000
---- a/src/DateIterator.vala
-+++ /dev/null
-@@ -1,82 +0,0 @@
--/*
-- * Copyright 2011-2018 elementary, Inc. (https://elementary.io)
-- *
-- * This program is free software; you can redistribute it and/or
-- * modify it under the terms of the GNU General Public
-- * License as published by the Free Software Foundation; either
-- * version 2 of the License, or (at your option) any later version.
-- *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-- * General Public License for more details.
-- *
-- * You should have received a copy of the GNU General Public
-- * License along with this program; if not, write to the
-- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-- * Boston, MA 02110-1301 USA.
-- *
-- * Authored by: Corentin Noël <corentin@elementaryos.org>
-- */
--
--public class Util.DateIterator : Object, Gee.Traversable<GLib.DateTime>, Gee.Iterator<GLib.DateTime> {
--    public GLib.DateTime current { get; construct set; }
--    public Util.DateRange range { get; construct; }
--
--    // Required by Gee.Iterator
--    public bool valid {
--        get {
--            return true;
--        }
--    }
--
--    // Required by Gee.Iterator
--    public bool read_only {
--        get {
--            return false;
--        }
--    }
--
--    public DateIterator (Util.DateRange range) {
--        Object (
--            range: range,
--            current: range.first_dt.add_days (-1)
--        );
--    }
--
--    public bool @foreach (Gee.ForallFunc<GLib.DateTime> f) {
--        var element = range.first_dt;
--
--        while (element.compare (range.last_dt) < 0) {
--            if (f (element) == false) {
--                return false;
--            }
--
--            element = element.add_days (1);
--        }
--
--        return true;
--    }
--
--    public bool next () {
--        if (!has_next ()) {
--            return false;
--        }
--
--        current = this.current.add_days (1);
--
--        return true;
--    }
--
--    public bool has_next () {
--        return current.compare (range.last_dt) < 0;
--    }
--
--    public new GLib.DateTime get () {
--        return current;
--    }
--
--    public void remove () {
--        assert_not_reached ();
--    }
--}
-diff --git a/src/DateRange.vala b/src/DateRange.vala
-deleted file mode 100644
-index 08e4c00..0000000
---- a/src/DateRange.vala
-+++ /dev/null
-@@ -1,66 +0,0 @@
--/*
-- * Copyright 2011-2019 elementary, Inc. (https://elementary.io)
-- *
-- * This program is free software; you can redistribute it and/or
-- * modify it under the terms of the GNU General Public
-- * License as published by the Free Software Foundation; either
-- * version 2 of the License, or (at your option) any later version.
-- *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-- * General Public License for more details.
-- *
-- * You should have received a copy of the GNU General Public
-- * License along with this program; if not, write to the
-- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-- * Boston, MA 02110-1301 USA.
-- *
-- * Authored by: Corentin Noël <corentin@elementaryos.org>
-- */
--
--/* Represents date range from 'first' to 'last' inclusive */
--public class Util.DateRange : Object, Gee.Traversable<GLib.DateTime>, Gee.Iterable<GLib.DateTime> {
--    public GLib.DateTime first_dt { get; construct; }
--    public GLib.DateTime last_dt { get; construct; }
--
--    public bool @foreach (Gee.ForallFunc<GLib.DateTime> f) {
--        foreach (var date in this) {
--            if (f (date) == false) {
--                return false;
--            }
--        }
--
--        return true;
--    }
--
--    public DateRange (GLib.DateTime first, GLib.DateTime last) {
--        Object (
--            first_dt: first,
--            last_dt: last
--        );
--    }
--
--    public bool equals (DateRange other) {
--        return (first_dt == other.first_dt && last_dt == other.last_dt);
--    }
--
--    public Gee.Iterator<GLib.DateTime> iterator () {
--        return new DateIterator (this);
--    }
--
--    public Gee.List<GLib.DateTime> to_list () {
--        var list = new Gee.ArrayList<GLib.DateTime> ((Gee.EqualDataFunc<GLib.DateTime>? )datetime_equal_func);
--
--        foreach (var date in this) {
--            list.add (date);
--        }
--
--        return list;
--    }
--
--    /* Returns true if 'a' and 'b' are the same GLib.DateTime */
--    private bool datetime_equal_func (GLib.DateTime a, GLib.DateTime b) {
--        return a.equal (b);
--    }
--}
-diff --git a/src/Indicator.vala b/src/Indicator.vala
-index 77aa35c..b712c12 100644
---- a/src/Indicator.vala
-+++ b/src/Indicator.vala
-@@ -17,218 +17,219 @@
-  * Boston, MA 02110-1301 USA.
-  */
- 
--public class DateTime.Indicator : Wingpanel.Indicator {
--    public static GLib.Settings settings;
--
--    private Widgets.PanelLabel panel_label;
--    private Gtk.Grid main_grid;
--    private Widgets.CalendarView calendar;
--    private Gtk.ListBox event_listbox;
--    private uint update_events_idle_source = 0;
--
--    public Indicator () {
--        Object (
--            code_name: Wingpanel.Indicator.DATETIME,
--            display_name: _("Date & Time"),
--            description: _("The date and time indicator")
--        );
--    }
--
--    static construct {
--        settings = new GLib.Settings ("io.elementary.desktop.wingpanel.datetime");
--    }
-+namespace DateTimeIndicator {
-+    public class Indicator : Wingpanel.Indicator {
-+        public static GLib.Settings settings;
-+
-+        private Widgets.PanelLabel panel_label;
-+        private Gtk.Grid main_grid;
-+        private Widgets.CalendarView calendar;
-+        private Gtk.ListBox event_listbox;
-+        private uint update_events_idle_source = 0;
-+
-+        public Indicator () {
-+            Object (
-+                code_name: Wingpanel.Indicator.DATETIME,
-+                display_name: _("Date & Time"),
-+                description: _("The date and time indicator")
-+            );
-+        }
- 
--    construct {
--        visible = true;
--    }
-+        static construct {
-+            settings = new GLib.Settings ("io.elementary.desktop.wingpanel.datetime");
-+        }
- 
--    public override Gtk.Widget get_display_widget () {
--        if (panel_label == null) {
--            panel_label = new Widgets.PanelLabel ();
-+        construct {
-+            visible = true;
-         }
- 
--        return panel_label;
--    }
-+        public override Gtk.Widget get_display_widget () {
-+            if (panel_label == null) {
-+                panel_label = new Widgets.PanelLabel ();
-+            }
- 
--    public override Gtk.Widget? get_widget () {
--        if (main_grid == null) {
--            calendar = new Widgets.CalendarView ();
--            calendar.margin_bottom = 6;
--
--            var placeholder_label = new Gtk.Label (_("No Events on This Day"));
--            placeholder_label.wrap = true;
--            placeholder_label.wrap_mode = Pango.WrapMode.WORD;
--            placeholder_label.margin_start = 12;
--            placeholder_label.margin_end = 12;
--            placeholder_label.max_width_chars = 20;
--            placeholder_label.justify = Gtk.Justification.CENTER;
--            placeholder_label.show_all ();
--
--            var placeholder_style_context = placeholder_label.get_style_context ();
--            placeholder_style_context.add_class (Gtk.STYLE_CLASS_DIM_LABEL);
--            placeholder_style_context.add_class (Granite.STYLE_CLASS_H3_LABEL);
--
--            event_listbox = new Gtk.ListBox ();
--            event_listbox.selection_mode = Gtk.SelectionMode.NONE;
--            event_listbox.set_header_func (header_update_func);
--            event_listbox.set_placeholder (placeholder_label);
--            event_listbox.set_sort_func (sort_function);
--
--            var scrolled_window = new Gtk.ScrolledWindow (null, null);
--            scrolled_window.hscrollbar_policy = Gtk.PolicyType.NEVER;
--            scrolled_window.add (event_listbox);
--
--            var settings_button = new Gtk.ModelButton ();
--            settings_button.text = _("Date & Time Settings…");
--
--            main_grid = new Gtk.Grid ();
--            main_grid.margin_top = 12;
--            main_grid.attach (calendar, 0, 0);
--            main_grid.attach (new Gtk.Separator (Gtk.Orientation.VERTICAL), 1, 0);
--            main_grid.attach (scrolled_window, 2, 0);
--            main_grid.attach (new Wingpanel.Widgets.Separator (), 0, 2, 3);
--            main_grid.attach (settings_button, 0, 3, 3);
--
--            var size_group = new Gtk.SizeGroup (Gtk.SizeGroupMode.HORIZONTAL);
--            size_group.add_widget (calendar);
--            size_group.add_widget (event_listbox);
--
--            calendar.day_double_click.connect (() => {
--                close ();
--            });
-+            return panel_label;
-+        }
- 
--            calendar.selection_changed.connect ((date) => {
--                idle_update_events ();
--            });
-+        public override Gtk.Widget? get_widget () {
-+            if (main_grid == null) {
-+                calendar = new Widgets.CalendarView ();
-+                calendar.margin_bottom = 6;
-+
-+                var placeholder_label = new Gtk.Label (_("No Events on This Day"));
-+                placeholder_label.wrap = true;
-+                placeholder_label.wrap_mode = Pango.WrapMode.WORD;
-+                placeholder_label.margin_start = 12;
-+                placeholder_label.margin_end = 12;
-+                placeholder_label.max_width_chars = 20;
-+                placeholder_label.justify = Gtk.Justification.CENTER;
-+                placeholder_label.show_all ();
-+
-+                var placeholder_style_context = placeholder_label.get_style_context ();
-+                placeholder_style_context.add_class (Gtk.STYLE_CLASS_DIM_LABEL);
-+                placeholder_style_context.add_class (Granite.STYLE_CLASS_H3_LABEL);
-+
-+                event_listbox = new Gtk.ListBox ();
-+                event_listbox.selection_mode = Gtk.SelectionMode.NONE;
-+                event_listbox.set_header_func (header_update_func);
-+                event_listbox.set_placeholder (placeholder_label);
-+                event_listbox.set_sort_func (sort_function);
-+
-+                var scrolled_window = new Gtk.ScrolledWindow (null, null);
-+                scrolled_window.hscrollbar_policy = Gtk.PolicyType.NEVER;
-+                scrolled_window.add (event_listbox);
-+
-+                var settings_button = new Gtk.ModelButton ();
-+                settings_button.text = _("Date & Time Settings…");
-+
-+                main_grid = new Gtk.Grid ();
-+                main_grid.margin_top = 12;
-+                main_grid.attach (calendar, 0, 0);
-+                main_grid.attach (new Gtk.Separator (Gtk.Orientation.VERTICAL), 1, 0);
-+                main_grid.attach (scrolled_window, 2, 0);
-+                main_grid.attach (new Wingpanel.Widgets.Separator (), 0, 2, 3);
-+                main_grid.attach (settings_button, 0, 3, 3);
-+
-+                var size_group = new Gtk.SizeGroup (Gtk.SizeGroupMode.HORIZONTAL);
-+                size_group.add_widget (calendar);
-+                size_group.add_widget (event_listbox);
-+
-+                calendar.day_double_click.connect (() => {
-+                    close ();
-+                });
-+
-+                calendar.selection_changed.connect ((date) => {
-+                    idle_update_events ();
-+                });
-+
-+                event_listbox.row_activated.connect ((row) => {
-+                    calendar.show_date_in_maya (((EventRow) row).date);
-+                    close ();
-+                });
-+
-+                settings_button.clicked.connect (() => {
-+                    try {
-+                        AppInfo.launch_default_for_uri ("settings://time", null);
-+                    } catch (Error e) {
-+                        warning ("Failed to open time and date settings: %s", e.message);
-+                    }
-+                });
-+            }
- 
--            event_listbox.row_activated.connect ((row) => {
--                calendar.show_date_in_maya (((DateTime.EventRow) row).date);
--                close ();
--            });
-+            return main_grid;
-+        }
- 
--            settings_button.clicked.connect (() => {
--                try {
--                    AppInfo.launch_default_for_uri ("settings://time", null);
--                } catch (Error e) {
--                    warning ("Failed to open time and date settings: %s", e.message);
-+        private void header_update_func (Gtk.ListBoxRow lbrow, Gtk.ListBoxRow? lbbefore) {
-+            var row = (EventRow) lbrow;
-+            if (lbbefore != null) {
-+                var before = (EventRow) lbbefore;
-+                if (row.is_allday == before.is_allday) {
-+                    row.set_header (null);
-+                    return;
-                 }
--            });
--        }
- 
--        return main_grid;
--    }
-+                if (row.is_allday != before.is_allday) {
-+                    var header_label = new Granite.HeaderLabel (_("During the Day"));
-+                    header_label.margin_start = header_label.margin_end = 6;
- 
--    private void header_update_func (Gtk.ListBoxRow lbrow, Gtk.ListBoxRow? lbbefore) {
--        var row = (DateTime.EventRow) lbrow;
--        if (lbbefore != null) {
--            var before = (DateTime.EventRow) lbbefore;
--            if (row.is_allday == before.is_allday) {
--                row.set_header (null);
-+                    row.set_header (header_label);
-+                    return;
-+                }
-+            } else {
-+                if (row.is_allday) {
-+                    var allday_header = new Granite.HeaderLabel (_("All Day"));
-+                    allday_header.margin_start = allday_header.margin_end = 6;
-+
-+                    row.set_header (allday_header);
-+                }
-                 return;
-             }
-+        }
- 
--            if (row.is_allday != before.is_allday) {
--                var header_label = new Granite.HeaderLabel (_("During the Day"));
--                header_label.margin_start = header_label.margin_end = 6;
-+        [CCode (instance_pos = -1)]
-+        private int sort_function (Gtk.ListBoxRow child1, Gtk.ListBoxRow child2) {
-+            var e1 = (EventRow) child1;
-+            var e2 = (EventRow) child2;
- 
--                row.set_header (header_label);
--                return;
-+            if (e1.start_time.compare (e2.start_time) != 0) {
-+                return e1.start_time.compare (e2.start_time);
-             }
--        } else {
--            if (row.is_allday) {
--                var allday_header = new Granite.HeaderLabel (_("All Day"));
--                allday_header.margin_start = allday_header.margin_end = 6;
- 
--                row.set_header (allday_header);
-+            // If they have the same date, sort them wholeday first
-+            if (e1.is_allday) {
-+                return -1;
-+            } else if (e2.is_allday) {
-+                return 1;
-             }
--            return;
--        }
--    }
--
--    [CCode (instance_pos = -1)]
--    private int sort_function (Gtk.ListBoxRow child1, Gtk.ListBoxRow child2) {
--        var e1 = (EventRow) child1;
--        var e2 = (EventRow) child2;
- 
--        if (e1.start_time.compare (e2.start_time) != 0) {
--            return e1.start_time.compare (e2.start_time);
-+            return 0;
-         }
- 
--        // If they have the same date, sort them wholeday first
--        if (e1.is_allday) {
--            return -1;
--        } else if (e2.is_allday) {
--            return 1;
-+        private void update_events_model (E.Source source, Gee.Collection<ECal.Component> events) {
-+            idle_update_events ();
-         }
- 
--        return 0;
--    }
--
--    private void update_events_model (E.Source source, Gee.Collection<ECal.Component> events) {
--        idle_update_events ();
--    }
-+        private void idle_update_events () {
-+            if (update_events_idle_source > 0) {
-+                GLib.Source.remove (update_events_idle_source);
-+            }
- 
--    private void idle_update_events () {
--        if (update_events_idle_source > 0) {
--            GLib.Source.remove (update_events_idle_source);
-+            update_events_idle_source = GLib.Idle.add (update_events);
-         }
- 
--        update_events_idle_source = GLib.Idle.add (update_events);
--    }
--
--    private bool update_events () {
--        foreach (unowned Gtk.Widget widget in event_listbox.get_children ()) {
--            widget.destroy ();
--        }
-+        private bool update_events () {
-+            foreach (unowned Gtk.Widget widget in event_listbox.get_children ()) {
-+                widget.destroy ();
-+            }
- 
--        if (calendar.selected_date == null) {
--            update_events_idle_source = 0;
--            return GLib.Source.REMOVE;
--        }
-+            if (calendar.selected_date == null) {
-+                update_events_idle_source = 0;
-+                return GLib.Source.REMOVE;
-+            }
- 
--        var date = calendar.selected_date;
-+            var date = calendar.selected_date;
- 
--        var model = Widgets.CalendarModel.get_default ();
-+            var model = Models.CalendarModel.get_default ();
- 
--        var events_on_day = new Gee.TreeMap<string, DateTime.EventRow> ();
-+            var events_on_day = new Gee.TreeMap<string, EventRow> ();
- 
--        model.source_events.@foreach ((source, component_map) => {
--            foreach (var comp in component_map.get_values ()) {
--                if (Util.calcomp_is_on_day (comp, date)) {
--                    unowned ICal.Component ical = comp.get_icalcomponent ();
--                    var event_uid = ical.get_uid ();
--                    if (!events_on_day.has_key (event_uid)) {
--                        events_on_day[event_uid] = new DateTime.EventRow (date, ical, source);
-+            model.source_events.@foreach ((source, component_map) => {
-+                foreach (var comp in component_map.get_values ()) {
-+                    if (Util.calcomp_is_on_day (comp, date)) {
-+                        unowned ICal.Component ical = comp.get_icalcomponent ();
-+                        var event_uid = ical.get_uid ();
-+                        if (!events_on_day.has_key (event_uid)) {
-+                            events_on_day[event_uid] = new EventRow (date, ical, source);
- 
--                        event_listbox.add (events_on_day[event_uid]);
-+                            event_listbox.add (events_on_day[event_uid]);
-+                        }
-                     }
-                 }
--            }
--        });
-+            });
- 
--        event_listbox.show_all ();
--        update_events_idle_source = 0;
--        return GLib.Source.REMOVE;
--    }
-+            event_listbox.show_all ();
-+            update_events_idle_source = 0;
-+            return GLib.Source.REMOVE;
-+        }
- 
--    public override void opened () {
--        calendar.show_today ();
-+        public override void opened () {
-+            calendar.show_today ();
- 
--        Widgets.CalendarModel.get_default ().events_added.connect (update_events_model);
--        Widgets.CalendarModel.get_default ().events_updated.connect (update_events_model);
--        Widgets.CalendarModel.get_default ().events_removed.connect (update_events_model);
--    }
-+            Models.CalendarModel.get_default ().events_added.connect (update_events_model);
-+            Models.CalendarModel.get_default ().events_updated.connect (update_events_model);
-+            Models.CalendarModel.get_default ().events_removed.connect (update_events_model);
-+        }
- 
--    public override void closed () {
--        Widgets.CalendarModel.get_default ().events_added.disconnect (update_events_model);
--        Widgets.CalendarModel.get_default ().events_updated.disconnect (update_events_model);
--        Widgets.CalendarModel.get_default ().events_removed.disconnect (update_events_model);
-+        public override void closed () {
-+            Models.CalendarModel.get_default ().events_added.disconnect (update_events_model);
-+            Models.CalendarModel.get_default ().events_updated.disconnect (update_events_model);
-+            Models.CalendarModel.get_default ().events_removed.disconnect (update_events_model);
-+        }
-     }
- }
--
- public Wingpanel.Indicator get_indicator (Module module) {
-     debug ("Activating DateTime Indicator");
--    var indicator = new DateTime.Indicator ();
-+    var indicator = new DateTimeIndicator.Indicator ();
- 
-     return indicator;
- }
-diff --git a/src/Widgets/calendar/CalendarModel.vala b/src/Models/CalendarModel.vala
-similarity index 99%
-rename from src/Widgets/calendar/CalendarModel.vala
-rename to src/Models/CalendarModel.vala
-index 7602303..965b93e 100644
---- a/src/Widgets/calendar/CalendarModel.vala
-+++ b/src/Models/CalendarModel.vala
-@@ -15,8 +15,8 @@
-  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
-  */
- 
--namespace DateTime.Widgets {
--    public class CalendarModel : Object {
-+namespace DateTimeIndicator {
-+    public class Models.CalendarModel : Object {
-         /* The data_range is the range of dates for which this model is storing
-          * data.
-          *
-diff --git a/src/Services/TimeManager.vala b/src/Services/TimeManager.vala
-index b68f158..5baa136 100644
---- a/src/Services/TimeManager.vala
-+++ b/src/Services/TimeManager.vala
-@@ -32,153 +32,155 @@ interface FDO.Accounts : Object {
-     public abstract string find_user_by_name (string username) throws GLib.Error;
- }
- 
--public class DateTime.Services.TimeManager : Gtk.Calendar {
--    private static TimeManager? instance = null;
-+namespace DateTimeIndicator {
-+    public class Services.TimeManager : Gtk.Calendar {
-+        private static TimeManager? instance = null;
- 
--    public signal void minute_changed ();
-+        public signal void minute_changed ();
- 
--    private GLib.DateTime? current_time = null;
--    private uint timeout_id = 0;
--    private Manager? manager = null;
-+        private GLib.DateTime? current_time = null;
-+        private uint timeout_id = 0;
-+        private Manager? manager = null;
- 
--    public bool clock_show_seconds { get; set; }
--    public bool is_12h { get; set; }
-+        public bool clock_show_seconds { get; set; }
-+        public bool is_12h { get; set; }
- 
--    public TimeManager () {
--        update_current_time ();
--
--        if (current_time == null) {
--            return;
--        }
-+        public TimeManager () {
-+            update_current_time ();
- 
--        add_timeout ();
--        try {
--            var clock_settings = new GLib.Settings ("io.elementary.desktop.wingpanel.datetime");
--            clock_settings.bind ("clock-show-seconds", this, "clock-show-seconds", SettingsBindFlags.DEFAULT);
-+            if (current_time == null) {
-+                return;
-+            }
- 
--            notify["clock-show-seconds"].connect (() => {
--                add_timeout ();
--            });
-+            add_timeout ();
-+            try {
-+                var clock_settings = new GLib.Settings ("io.elementary.desktop.wingpanel.datetime");
-+                clock_settings.bind ("clock-show-seconds", this, "clock-show-seconds", SettingsBindFlags.DEFAULT);
- 
--            // Listen for the D-BUS server that controls time settings
--            Bus.watch_name (BusType.SYSTEM, "org.freedesktop.timedate1", BusNameWatcherFlags.NONE, on_watch, on_unwatch);
--            // Listen for the signal that is fired when waking up from sleep, then update time
--            manager = Bus.get_proxy_sync (BusType.SYSTEM, "org.freedesktop.login1", "/org/freedesktop/login1");
--            manager.prepare_for_sleep.connect ((sleeping) => {
--                if (!sleeping) {
--                    update_current_time ();
--                    minute_changed ();
-+                notify["clock-show-seconds"].connect (() => {
-                     add_timeout ();
--                }
--            });
--        } catch (Error e) {
--            warning (e.message);
-+                });
-+
-+                // Listen for the D-BUS server that controls time settings
-+                Bus.watch_name (BusType.SYSTEM, "org.freedesktop.timedate1", BusNameWatcherFlags.NONE, on_watch, on_unwatch);
-+                // Listen for the signal that is fired when waking up from sleep, then update time
-+                manager = Bus.get_proxy_sync (BusType.SYSTEM, "org.freedesktop.login1", "/org/freedesktop/login1");
-+                manager.prepare_for_sleep.connect ((sleeping) => {
-+                    if (!sleeping) {
-+                        update_current_time ();
-+                        minute_changed ();
-+                        add_timeout ();
-+                    }
-+                });
-+            } catch (Error e) {
-+                warning (e.message);
-+            }
-         }
--    }
--
--    construct {
--        setup_time_format.begin ();
--    }
- 
--    private async void setup_time_format () {
--        try {
--            var accounts_service = yield GLib.Bus.get_proxy<FDO.Accounts> (GLib.BusType.SYSTEM,
--                                                                           "org.freedesktop.Accounts",
--                                                                           "/org/freedesktop/Accounts");
--            var user_path = accounts_service.find_user_by_name (GLib.Environment.get_user_name ());
--
--            var greeter_act = yield GLib.Bus.get_proxy<Pantheon.AccountsService> (GLib.BusType.SYSTEM,
--                                                    "org.freedesktop.Accounts",
--                                                    user_path,
--                                                    GLib.DBusProxyFlags.GET_INVALIDATED_PROPERTIES);
--            is_12h = ("12h" in greeter_act.time_format);
--            ((GLib.DBusProxy) greeter_act).g_properties_changed.connect ((changed_properties, invalidated_properties) => {
--                if (changed_properties.lookup_value ("TimeFormat", GLib.VariantType.STRING) != null) {
--                    is_12h = ("12h" in greeter_act.time_format);
--                }
--            });
--        } catch (Error e) {
--            critical (e.message);
--            // Connect to the GSettings instead
--            var clock_settings = new GLib.Settings ("org.gnome.desktop.interface");
--            clock_settings.changed["clock-format"].connect (() => {
--                is_12h = ("12h" in clock_settings.get_string ("clock-format"));
--            });
--
--            is_12h = ("12h" in clock_settings.get_string ("clock-format"));
-+        construct {
-+            setup_time_format.begin ();
-         }
--    }
- 
--    private void on_watch (DBusConnection conn) {
--        // Start updating the time display quicker because someone is changing settings
--        add_timeout (true);
--    }
-+        private async void setup_time_format () {
-+            try {
-+                var accounts_service = yield GLib.Bus.get_proxy<FDO.Accounts> (GLib.BusType.SYSTEM,
-+                                                                               "org.freedesktop.Accounts",
-+                                                                               "/org/freedesktop/Accounts");
-+                var user_path = accounts_service.find_user_by_name (GLib.Environment.get_user_name ());
-+
-+                var greeter_act = yield GLib.Bus.get_proxy<Pantheon.AccountsService> (GLib.BusType.SYSTEM,
-+                                                        "org.freedesktop.Accounts",
-+                                                        user_path,
-+                                                        GLib.DBusProxyFlags.GET_INVALIDATED_PROPERTIES);
-+                is_12h = ("12h" in greeter_act.time_format);
-+                ((GLib.DBusProxy) greeter_act).g_properties_changed.connect ((changed_properties, invalidated_properties) => {
-+                    if (changed_properties.lookup_value ("TimeFormat", GLib.VariantType.STRING) != null) {
-+                        is_12h = ("12h" in greeter_act.time_format);
-+                    }
-+                });
-+            } catch (Error e) {
-+                critical (e.message);
-+                // Connect to the GSettings instead
-+                var clock_settings = new GLib.Settings ("org.gnome.desktop.interface");
-+                clock_settings.changed["clock-format"].connect (() => {
-+                    is_12h = ("12h" in clock_settings.get_string ("clock-format"));
-+                });
- 
--    private void on_unwatch (DBusConnection conn) {
--        // Stop updating the time display quicker
--        add_timeout (false);
--    }
-+                is_12h = ("12h" in clock_settings.get_string ("clock-format"));
-+            }
-+        }
- 
--    private void add_timeout (bool update_fast = false) {
--        uint interval;
--        if (update_fast || clock_show_seconds) {
--            interval = 500;
--        } else {
--            interval = calculate_time_until_next_minute ();
-+        private void on_watch (DBusConnection conn) {
-+            // Start updating the time display quicker because someone is changing settings
-+            add_timeout (true);
-         }
- 
--        if (timeout_id > 0) {
--            Source.remove (timeout_id);
-+        private void on_unwatch (DBusConnection conn) {
-+            // Stop updating the time display quicker
-+            add_timeout (false);
-         }
- 
--        timeout_id = Timeout.add (interval, () => {
--            update_current_time ();
--            minute_changed ();
--            add_timeout (update_fast);
-+        private void add_timeout (bool update_fast = false) {
-+            uint interval;
-+            if (update_fast || clock_show_seconds) {
-+                interval = 500;
-+            } else {
-+                interval = calculate_time_until_next_minute ();
-+            }
- 
--            return false;
--        });
--    }
-+            if (timeout_id > 0) {
-+                Source.remove (timeout_id);
-+            }
- 
--    public string format (string format) {
--        if (current_time == null) {
--            return "undef";
-+            timeout_id = Timeout.add (interval, () => {
-+                update_current_time ();
-+                minute_changed ();
-+                add_timeout (update_fast);
-+
-+                return false;
-+            });
-         }
- 
--        return current_time.format (format);
--    }
-+        public string format (string format) {
-+            if (current_time == null) {
-+                return "undef";
-+            }
- 
--    public GLib.DateTime get_current_time () {
--        return current_time;
--    }
-+            return current_time.format (format);
-+        }
- 
--    private void update_current_time () {
--        var local_time = new GLib.DateTime.now_local ();
-+        public GLib.DateTime get_current_time () {
-+            return current_time;
-+        }
- 
--        if (local_time == null) {
--            critical ("Can't get the local time.");
-+        private void update_current_time () {
-+            var local_time = new GLib.DateTime.now_local ();
- 
--            return;
--        }
-+            if (local_time == null) {
-+                critical ("Can't get the local time.");
- 
--        current_time = local_time;
--    }
-+                return;
-+            }
- 
--    private uint calculate_time_until_next_minute () {
--        if (current_time == null) {
--            return 60 * 1000;
-+            current_time = local_time;
-         }
- 
--        var seconds_until_next_minute = 60 - (current_time.to_unix () % 60);
-+        private uint calculate_time_until_next_minute () {
-+            if (current_time == null) {
-+                return 60 * 1000;
-+            }
- 
--        return (uint)seconds_until_next_minute * 1000;
--    }
-+            var seconds_until_next_minute = 60 - (current_time.to_unix () % 60);
- 
--    public static TimeManager get_default () {
--        if (instance == null) {
--            instance = new TimeManager ();
-+            return (uint)seconds_until_next_minute * 1000;
-         }
- 
--        return instance;
-+        public static TimeManager get_default () {
-+            if (instance == null) {
-+                instance = new TimeManager ();
-+            }
-+
-+            return instance;
-+        }
-     }
- }
-diff --git a/src/Util/DateIterator.vala b/src/Util/DateIterator.vala
-new file mode 100644
-index 0000000..c2c771e
---- /dev/null
-+++ b/src/Util/DateIterator.vala
-@@ -0,0 +1,84 @@
-+/*
-+ * Copyright 2011-2018 elementary, Inc. (https://elementary.io)
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2 of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public
-+ * License along with this program; if not, write to the
-+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-+ * Boston, MA 02110-1301 USA.
-+ *
-+ * Authored by: Corentin Noël <corentin@elementaryos.org>
-+ */
-+
-+namespace DateTimeIndicator {
-+    public class Util.DateIterator : Object, Gee.Traversable<GLib.DateTime>, Gee.Iterator<GLib.DateTime> {
-+        public GLib.DateTime current { get; construct set; }
-+        public Util.DateRange range { get; construct; }
-+
-+        // Required by Gee.Iterator
-+        public bool valid {
-+            get {
-+                return true;
-+            }
-+        }
-+
-+        // Required by Gee.Iterator
-+        public bool read_only {
-+            get {
-+                return false;
-+            }
-+        }
-+
-+        public DateIterator (Util.DateRange range) {
-+            Object (
-+                range: range,
-+                current: range.first_dt.add_days (-1)
-+            );
-+        }
-+
-+        public bool @foreach (Gee.ForallFunc<GLib.DateTime> f) {
-+            var element = range.first_dt;
-+
-+            while (element.compare (range.last_dt) < 0) {
-+                if (f (element) == false) {
-+                    return false;
-+                }
-+
-+                element = element.add_days (1);
-+            }
-+
-+            return true;
-+        }
-+
-+        public bool next () {
-+            if (!has_next ()) {
-+                return false;
-+            }
-+
-+            current = this.current.add_days (1);
-+
-+            return true;
-+        }
-+
-+        public bool has_next () {
-+            return current.compare (range.last_dt) < 0;
-+        }
-+
-+        public new GLib.DateTime get () {
-+            return current;
-+        }
-+
-+        public void remove () {
-+            assert_not_reached ();
-+        }
-+    }
-+}
-diff --git a/src/Util/DateRange.vala b/src/Util/DateRange.vala
-new file mode 100644
-index 0000000..82da7c8
---- /dev/null
-+++ b/src/Util/DateRange.vala
-@@ -0,0 +1,68 @@
-+/*
-+ * Copyright 2011-2019 elementary, Inc. (https://elementary.io)
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2 of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public
-+ * License along with this program; if not, write to the
-+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-+ * Boston, MA 02110-1301 USA.
-+ *
-+ * Authored by: Corentin Noël <corentin@elementaryos.org>
-+ */
-+
-+namespace DateTimeIndicator {
-+/* Represents date range from 'first' to 'last' inclusive */
-+    public class Util.DateRange : Object, Gee.Traversable<GLib.DateTime>, Gee.Iterable<GLib.DateTime> {
-+        public GLib.DateTime first_dt { get; construct; }
-+        public GLib.DateTime last_dt { get; construct; }
-+
-+        public bool @foreach (Gee.ForallFunc<GLib.DateTime> f) {
-+            foreach (var date in this) {
-+                if (f (date) == false) {
-+                    return false;
-+                }
-+            }
-+
-+            return true;
-+        }
-+
-+        public DateRange (GLib.DateTime first, GLib.DateTime last) {
-+            Object (
-+                first_dt: first,
-+                last_dt: last
-+            );
-+        }
-+
-+        public bool equals (DateRange other) {
-+            return (first_dt == other.first_dt && last_dt == other.last_dt);
-+        }
-+
-+        public Gee.Iterator<GLib.DateTime> iterator () {
-+            return new DateIterator (this);
-+        }
-+
-+        public Gee.List<GLib.DateTime> to_list () {
-+            var list = new Gee.ArrayList<GLib.DateTime> ((Gee.EqualDataFunc<GLib.DateTime>? )datetime_equal_func);
-+
-+            foreach (var date in this) {
-+                list.add (date);
-+            }
-+
-+            return list;
-+        }
-+
-+        /* Returns true if 'a' and 'b' are the same GLib.DateTime */
-+        private bool datetime_equal_func (GLib.DateTime a, GLib.DateTime b) {
-+            return a.equal (b);
-+        }
-+    }
-+}
-diff --git a/src/Widgets/calendar/Util.vala b/src/Util/Util.vala
-similarity index 96%
-rename from src/Widgets/calendar/Util.vala
-rename to src/Util/Util.vala
-index e51f784..c261f4b 100644
---- a/src/Widgets/calendar/Util.vala
-+++ b/src/Util/Util.vala
-@@ -19,7 +19,7 @@
-  * Authored by: Corentin Noël <corentin@elementaryos.org>
-  */
- 
--namespace Util {
-+namespace DateTimeIndicator.Util {
-     static bool has_scrolled = false;
- 
-     public bool on_scroll_event (Gdk.EventScroll event) {
-@@ -35,7 +35,7 @@ namespace Util {
- 
-         /* It's mouse scroll ! */
-         if (choice == 1 || choice == -1) {
--            DateTime.Widgets.CalendarModel.get_default ().change_month ((int)choice);
-+            Models.CalendarModel.get_default ().change_month ((int)choice);
- 
-             return true;
-         }
-@@ -46,14 +46,14 @@ namespace Util {
- 
-         if (choice > 0.3) {
-             reset_timer.begin ();
--            DateTime.Widgets.CalendarModel.get_default ().change_month (1);
-+            Models.CalendarModel.get_default ().change_month (1);
- 
-             return true;
-         }
- 
-         if (choice < -0.3) {
-             reset_timer.begin ();
--            DateTime.Widgets.CalendarModel.get_default ().change_month (-1);
-+            Models.CalendarModel.get_default ().change_month (-1);
- 
-             return true;
-         }
-diff --git a/src/Widgets/CalendarView.vala b/src/Widgets/CalendarView.vala
-new file mode 100644
-index 0000000..65cee28
---- /dev/null
-+++ b/src/Widgets/CalendarView.vala
-@@ -0,0 +1,185 @@
-+/*-
-+ * Copyright (c) 2011–2018 elementary, Inc. (https://elementary.io)
-+ *
-+ * This program is free software: you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation, either version 3 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+ *
-+ * Authored by: Maxwell Barvian
-+ *              Corentin Noël <corentin@elementaryos.org>
-+ */
-+
-+namespace DateTimeIndicator {
-+    public class Widgets.CalendarView : Gtk.Grid {
-+        public signal void day_double_click ();
-+        public signal void event_updates ();
-+        public signal void selection_changed (GLib.DateTime? new_date);
-+
-+        public GLib.DateTime? selected_date { get; private set; }
-+
-+        private Widgets.Grid grid;
-+        private Gtk.Stack stack;
-+        private Gtk.Grid big_grid;
-+
-+        construct {
-+            var label = new Gtk.Label (new GLib.DateTime.now_local ().format (_("%OB, %Y")));
-+            label.hexpand = true;
-+            label.margin_start = 6;
-+            label.xalign = 0;
-+            label.width_chars = 13;
-+
-+            var provider = new Gtk.CssProvider ();
-+            provider.load_from_resource ("/io/elementary/desktop/wingpanel/datetime/ControlHeader.css");
-+
-+            var label_style_context = label.get_style_context ();
-+            label_style_context.add_class ("header-label");
-+            label_style_context.add_provider (provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
-+
-+            var left_button = new Gtk.Button.from_icon_name ("pan-start-symbolic");
-+            var center_button = new Gtk.Button.from_icon_name ("office-calendar-symbolic");
-+            center_button.tooltip_text = _("Go to today's date");
-+            var right_button = new Gtk.Button.from_icon_name ("pan-end-symbolic");
-+
-+            var box_buttons = new Gtk.Grid ();
-+            box_buttons.margin_end = 6;
-+            box_buttons.valign = Gtk.Align.CENTER;
-+            box_buttons.get_style_context ().add_class (Gtk.STYLE_CLASS_LINKED);
-+            box_buttons.add (left_button);
-+            box_buttons.add (center_button);
-+            box_buttons.add (right_button);
-+
-+            big_grid = create_big_grid ();
-+
-+            stack = new Gtk.Stack ();
-+            stack.add (big_grid);
-+            stack.show_all ();
-+            stack.expand = true;
-+
-+            stack.notify["transition-running"].connect (() => {
-+                if (stack.transition_running == false) {
-+                    stack.get_children ().foreach ((child) => {
-+                        if (child != stack.visible_child) {
-+                            child.destroy ();
-+                        }
-+                    });
-+                }
-+            });
-+
-+            column_spacing = 6;
-+            row_spacing = 6;
-+            margin_start = margin_end = 10;
-+            attach (label, 0, 0);
-+            attach (box_buttons, 1, 0);
-+            attach (stack, 0, 1, 2);
-+
-+            var model = Models.CalendarModel.get_default ();
-+            model.notify["data-range"].connect (() => {
-+                label.label = model.month_start.format (_("%OB, %Y"));
-+
-+                sync_with_model ();
-+
-+                selected_date = null;
-+                selection_changed (selected_date);
-+            });
-+
-+            left_button.clicked.connect (() => {
-+                model.change_month (-1);
-+            });
-+
-+            right_button.clicked.connect (() => {
-+                model.change_month (1);
-+            });
-+
-+            center_button.clicked.connect (() => {
-+                show_today ();
-+            });
-+        }
-+
-+        private Gtk.Grid create_big_grid () {
-+            grid = new Widgets.Grid ();
-+            grid.show_all ();
-+
-+            grid.on_event_add.connect ((date) => {
-+                show_date_in_maya (date);
-+                day_double_click ();
-+            });
-+
-+            grid.selection_changed.connect ((date) => {
-+                selected_date = date;
-+                selection_changed (date);
-+            });
-+
-+            return grid;
-+        }
-+
-+        public void show_today () {
-+            var calmodel = Models.CalendarModel.get_default ();
-+            var today = Util.strip_time (new GLib.DateTime.now_local ());
-+            var start = Util.get_start_of_month (today);
-+            selected_date = today;
-+            if (!start.equal (calmodel.month_start)) {
-+                calmodel.month_start = start;
-+            }
-+            sync_with_model ();
-+
-+            grid.set_focus_to_today ();
-+        }
-+
-+        // TODO: As far as maya supports it use the Dbus Activation feature to run the calendar-app.
-+        public void show_date_in_maya (GLib.DateTime date) {
-+            var command = "io.elementary.calendar --show-day %s".printf (date.format ("%F"));
-+
-+            try {
-+                var appinfo = AppInfo.create_from_commandline (command, null, AppInfoCreateFlags.NONE);
-+                appinfo.launch_uris (null, null);
-+            } catch (GLib.Error e) {
-+                var dialog = new Granite.MessageDialog.with_image_from_icon_name (
-+                    _("Unable To Launch Calendar"),
-+                    _("The program \"io.elementary.calendar\" may not be installed"),
-+                    "dialog-error"
-+                );
-+                dialog.show_error_details (e.message);
-+                dialog.run ();
-+                dialog.destroy ();
-+            }
-+        }
-+
-+        /* Sets the calendar widgets to the date range of the model */
-+        private void sync_with_model () {
-+            var model = Models.CalendarModel.get_default ();
-+            if (grid.grid_range != null && (model.data_range.equals (grid.grid_range) || grid.grid_range.first_dt.compare (model.data_range.first_dt) == 0)) {
-+                grid.update_today ();
-+                return; // nothing else to do
-+            }
-+
-+            GLib.DateTime previous_first = null;
-+            if (grid.grid_range != null)
-+                previous_first = grid.grid_range.first_dt;
-+
-+            big_grid = create_big_grid ();
-+            stack.add (big_grid);
-+
-+            grid.set_range (model.data_range, model.month_start);
-+            grid.update_weeks (model.data_range.first_dt, model.num_weeks);
-+
-+            if (previous_first != null) {
-+                if (previous_first.compare (grid.grid_range.first_dt) == -1) {
-+                    stack.transition_type = Gtk.StackTransitionType.SLIDE_LEFT;
-+                } else {
-+                    stack.transition_type = Gtk.StackTransitionType.SLIDE_RIGHT;
-+                }
-+            }
-+
-+            stack.set_visible_child (big_grid);
-+        }
-+    }
-+}
-diff --git a/src/Widgets/EventRow.vala b/src/Widgets/EventRow.vala
-index 8e0513e..1268311 100644
---- a/src/Widgets/EventRow.vala
-+++ b/src/Widgets/EventRow.vala
-@@ -17,104 +17,106 @@
-  * Boston, MA 02110-1301 USA.
-  */
- 
--public class DateTime.EventRow : Gtk.ListBoxRow {
--    public GLib.DateTime date { get; construct; }
--    public unowned ICal.Component component { get; construct; }
--    public unowned E.SourceCalendar cal { get; construct; }
--
--    public GLib.DateTime start_time { get; private set; }
--    public GLib.DateTime? end_time { get; private set; }
--    public bool is_allday { get; private set; default = false; }
--
--    private static Services.TimeManager time_manager;
--    private static Gtk.CssProvider css_provider;
--
--    private Gtk.Grid grid;
--    private Gtk.Image event_image;
--    private Gtk.Label time_label;
--
--    public EventRow (GLib.DateTime date, ICal.Component component, E.Source source) {
--        Object (
--            component: component,
--            date: date,
--            cal: (E.SourceCalendar?) source.get_extension (E.SOURCE_EXTENSION_CALENDAR)
--        );
--    }
--
--    static construct {
--        css_provider = new Gtk.CssProvider ();
--        css_provider.load_from_resource ("/io/elementary/desktop/wingpanel/datetime/EventRow.css");
--
--        time_manager = Services.TimeManager.get_default ();
--    }
-+namespace DateTimeIndicator {
-+    public class EventRow : Gtk.ListBoxRow {
-+        public GLib.DateTime date { get; construct; }
-+        public unowned ICal.Component component { get; construct; }
-+        public unowned E.SourceCalendar cal { get; construct; }
-+
-+        public GLib.DateTime start_time { get; private set; }
-+        public GLib.DateTime? end_time { get; private set; }
-+        public bool is_allday { get; private set; default = false; }
-+
-+        private static Services.TimeManager time_manager;
-+        private static Gtk.CssProvider css_provider;
-+
-+        private Gtk.Grid grid;
-+        private Gtk.Image event_image;
-+        private Gtk.Label time_label;
-+
-+        public EventRow (GLib.DateTime date, ICal.Component component, E.Source source) {
-+            Object (
-+                component: component,
-+                date: date,
-+                cal: (E.SourceCalendar?) source.get_extension (E.SOURCE_EXTENSION_CALENDAR)
-+            );
-+        }
- 
--    construct {
--        start_time = Util.ical_to_date_time (component.get_dtstart ());
--        end_time = Util.ical_to_date_time (component.get_dtend ());
-+        static construct {
-+            css_provider = new Gtk.CssProvider ();
-+            css_provider.load_from_resource ("/io/elementary/desktop/wingpanel/datetime/EventRow.css");
- 
--        if (end_time != null && Util.is_the_all_day (start_time, end_time)) {
--            is_allday = true;
-+            time_manager = Services.TimeManager.get_default ();
-         }
- 
--        unowned string icon_name = "office-calendar-symbolic";
--        if (end_time == null) {
--            icon_name = "alarm-symbolic";
-+        construct {
-+            start_time = Util.ical_to_date_time (component.get_dtstart ());
-+            end_time = Util.ical_to_date_time (component.get_dtend ());
-+
-+            if (end_time != null && Util.is_the_all_day (start_time, end_time)) {
-+                is_allday = true;
-+            }
-+
-+            unowned string icon_name = "office-calendar-symbolic";
-+            if (end_time == null) {
-+                icon_name = "alarm-symbolic";
-+            }
-+
-+            event_image = new Gtk.Image.from_icon_name (icon_name, Gtk.IconSize.MENU);
-+            event_image.valign = Gtk.Align.START;
-+
-+            unowned Gtk.StyleContext event_image_context = event_image.get_style_context ();
-+            event_image_context.add_provider (css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
-+
-+            var name_label = new Gtk.Label (component.get_summary ());
-+            name_label.hexpand = true;
-+            name_label.ellipsize = Pango.EllipsizeMode.END;
-+            name_label.lines = 3;
-+            name_label.max_width_chars = 30;
-+            name_label.wrap = true;
-+            name_label.wrap_mode = Pango.WrapMode.WORD_CHAR;
-+            name_label.xalign = 0;
-+
-+            unowned Gtk.StyleContext name_label_context = name_label.get_style_context ();
-+            name_label_context.add_class ("title");
-+            name_label_context.add_provider (css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
-+
-+            time_label = new Gtk.Label (null);
-+            time_label.use_markup = true;
-+            time_label.xalign = 0;
-+            time_label.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL);
-+
-+            grid = new Gtk.Grid ();
-+            grid.column_spacing = 6;
-+            grid.margin = 3;
-+            grid.margin_start = grid.margin_end = 6;
-+            grid.attach (event_image, 0, 0);
-+            grid.attach (name_label, 1, 0);
-+            if (!is_allday) {
-+                grid.attach (time_label, 1, 1);
-+            }
-+
-+            unowned Gtk.StyleContext grid_context = grid.get_style_context ();
-+            grid_context.add_class ("event");
-+            grid_context.add_provider (css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
-+
-+            add (grid);
-+
-+            set_color ();
-+            cal.notify["color"].connect (set_color);
-+
-+            update_timelabel ();
-+            time_manager.notify["is-12h"].connect (update_timelabel);
-         }
- 
--        event_image = new Gtk.Image.from_icon_name (icon_name, Gtk.IconSize.MENU);
--        event_image.valign = Gtk.Align.START;
--
--        unowned Gtk.StyleContext event_image_context = event_image.get_style_context ();
--        event_image_context.add_provider (css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
--
--        var name_label = new Gtk.Label (component.get_summary ());
--        name_label.hexpand = true;
--        name_label.ellipsize = Pango.EllipsizeMode.END;
--        name_label.lines = 3;
--        name_label.max_width_chars = 30;
--        name_label.wrap = true;
--        name_label.wrap_mode = Pango.WrapMode.WORD_CHAR;
--        name_label.xalign = 0;
--
--        unowned Gtk.StyleContext name_label_context = name_label.get_style_context ();
--        name_label_context.add_class ("title");
--        name_label_context.add_provider (css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
--
--        time_label = new Gtk.Label (null);
--        time_label.use_markup = true;
--        time_label.xalign = 0;
--        time_label.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL);
--
--        grid = new Gtk.Grid ();
--        grid.column_spacing = 6;
--        grid.margin = 3;
--        grid.margin_start = grid.margin_end = 6;
--        grid.attach (event_image, 0, 0);
--        grid.attach (name_label, 1, 0);
--        if (!is_allday) {
--            grid.attach (time_label, 1, 1);
-+        private void update_timelabel () {
-+            var time_format = Granite.DateTime.get_default_time_format (time_manager.is_12h);
-+            time_label.label = "<small>%s – %s</small>".printf (start_time.format (time_format), end_time.format (time_format));
-         }
- 
--        unowned Gtk.StyleContext grid_context = grid.get_style_context ();
--        grid_context.add_class ("event");
--        grid_context.add_provider (css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
--
--        add (grid);
--
--        set_color ();
--        cal.notify["color"].connect (set_color);
--
--        update_timelabel ();
--        time_manager.notify["is-12h"].connect (update_timelabel);
--    }
--
--    private void update_timelabel () {
--        var time_format = Granite.DateTime.get_default_time_format (time_manager.is_12h);
--        time_label.label = "<small>%s – %s</small>".printf (start_time.format (time_format), end_time.format (time_format));
--    }
--
--    private void set_color () {
--        Util.set_event_calendar_color (cal, grid);
--        Util.set_event_calendar_color (cal, event_image);
-+        private void set_color () {
-+            Util.set_event_calendar_color (cal, grid);
-+            Util.set_event_calendar_color (cal, event_image);
-+        }
-     }
- }
-diff --git a/src/Widgets/calendar/Grid.vala b/src/Widgets/Grid.vala
-similarity index 95%
-rename from src/Widgets/calendar/Grid.vala
-rename to src/Widgets/Grid.vala
-index 2b48636..165d11d 100644
---- a/src/Widgets/calendar/Grid.vala
-+++ b/src/Widgets/Grid.vala
-@@ -20,11 +20,11 @@
-  *              Corentin Noël <corentin@elementaryos.org>
-  */
- 
--namespace DateTime.Widgets {
-+namespace DateTimeIndicator {
- /**
-  * Represents the entire date grid as a table.
-  */
--    public class Grid : Gtk.Grid {
-+    public class Widgets.Grid : Gtk.Grid {
-         public Util.DateRange grid_range { get; private set; }
- 
-         /*
-@@ -59,7 +59,7 @@ namespace DateTime.Widgets {
-             hexpand = true;
-             attach (week_sep_revealer, 1, 1, 1, 6);
- 
--            DateTime.Indicator.settings.bind ("show-weeks", week_sep_revealer, "reveal-child", GLib.SettingsBindFlags.DEFAULT);
-+            Indicator.settings.bind ("show-weeks", week_sep_revealer, "reveal-child", GLib.SettingsBindFlags.DEFAULT);
- 
-             data = new Gee.HashMap<uint, GridDay> ();
-             events |= Gdk.EventMask.SCROLL_MASK;
-@@ -77,7 +77,7 @@ namespace DateTime.Widgets {
-             day.set_selected (true);
-             day.set_state_flags (Gtk.StateFlags.FOCUSED, false);
-             selection_changed (selected_date);
--            var calmodel = CalendarModel.get_default ();
-+            var calmodel = Models.CalendarModel.get_default ();
-             var date_month = selected_date.get_month () - calmodel.month_start.get_month ();
-             var date_year = selected_date.get_year () - calmodel.month_start.get_year ();
- 
-@@ -127,7 +127,7 @@ namespace DateTime.Widgets {
-             /* Create new widgets for the new range */
- 
-             var date = Util.strip_time (today);
--            date = date.add_days (CalendarModel.get_default ().week_starts_on - date.get_day_of_week ());
-+            date = date.add_days (Models.CalendarModel.get_default ().week_starts_on - date.get_day_of_week ());
-             foreach (var label in header_labels) {
-                 label.label = date.format ("%a");
-                 date = date.add_days (1);
-@@ -221,7 +221,7 @@ namespace DateTime.Widgets {
-                 week_labels[c].add (week_label);
-                 week_labels[c].show_all ();
- 
--                DateTime.Indicator.settings.bind ("show-weeks", week_labels[c], "reveal-child", GLib.SettingsBindFlags.DEFAULT);
-+                Indicator.settings.bind ("show-weeks", week_labels[c], "reveal-child", GLib.SettingsBindFlags.DEFAULT);
- 
-                 attach (week_labels[c], 0, c + 1);
- 
-diff --git a/src/Widgets/GridDay.vala b/src/Widgets/GridDay.vala
-new file mode 100644
-index 0000000..8c44443
---- /dev/null
-+++ b/src/Widgets/GridDay.vala
-@@ -0,0 +1,180 @@
-+// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
-+/*-
-+ * Copyright (c) 2011–2018 elementary, Inc. (https://elementary.io)
-+ *
-+ * This program is free software: you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation, either version 3 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+ *
-+ * Authored by: Maxwell Barvian
-+ *              Corentin Noël <corentin@elementaryos.org>
-+ */
-+
-+namespace DateTimeIndicator {
-+/**
-+ * Represents a single day on the grid.
-+ */
-+    public class Widgets.GridDay : Gtk.EventBox {
-+        /*
-+         * Event emitted when the day is double clicked or the ENTER key is pressed.
-+         */
-+        public signal void on_event_add (GLib.DateTime date);
-+
-+        public GLib.DateTime date { get; construct set; }
-+
-+        private static Gtk.CssProvider provider;
-+        private static Models.CalendarModel model;
-+
-+        private Gee.HashMap<string, Gtk.Widget> event_dots;
-+        private Gtk.Grid event_grid;
-+        private Gtk.Label label;
-+        private bool valid_grab = false;
-+
-+        public GridDay (GLib.DateTime date) {
-+            Object (date: date);
-+        }
-+
-+        static construct {
-+            model = Models.CalendarModel.get_default ();
-+
-+            provider = new Gtk.CssProvider ();
-+            provider.load_from_resource ("/io/elementary/desktop/wingpanel/datetime/GridDay.css");
-+        }
-+
-+        construct {
-+            unowned Gtk.StyleContext style_context = get_style_context ();
-+            style_context.add_provider (provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
-+            style_context.add_class ("circular");
-+
-+            label = new Gtk.Label (null);
-+
-+            event_grid = new Gtk.Grid ();
-+            event_grid.halign = Gtk.Align.CENTER;
-+            event_grid.height_request = 6;
-+
-+            var grid = new Gtk.Grid ();
-+            grid.halign = grid.valign = Gtk.Align.CENTER;
-+            grid.attach (label, 0, 0);
-+            grid.attach (event_grid, 0, 1);
-+
-+            can_focus = true;
-+            events |= Gdk.EventMask.BUTTON_PRESS_MASK;
-+            events |= Gdk.EventMask.KEY_PRESS_MASK;
-+            events |= Gdk.EventMask.SMOOTH_SCROLL_MASK;
-+            set_size_request (35, 35);
-+            halign = Gtk.Align.CENTER;
-+            hexpand = true;
-+            add (grid);
-+            show_all ();
-+
-+            // Signals and handlers
-+            button_press_event.connect (on_button_press);
-+            key_press_event.connect (on_key_press);
-+            scroll_event.connect ((event) => {return Util.on_scroll_event (event);});
-+
-+            notify["date"].connect (() => {
-+                label.label = date.get_day_of_month ().to_string ();
-+            });
-+
-+            event_dots = new Gee.HashMap<string, Gtk.Widget> ();
-+
-+            model.events_added.connect (add_event_dots);
-+            model.events_removed.connect (remove_event_dots);
-+        }
-+
-+        private void add_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
-+            foreach (var component in events) {
-+                if (event_dots.size >= 3) {
-+                    return;
-+                }
-+
-+                if (Util.calcomp_is_on_day (component, date)) {
-+                    unowned ICal.Component ical = component.get_icalcomponent ();
-+
-+                    var event_uid = ical.get_uid ();
-+                    if (!event_dots.has_key (event_uid)) {
-+                        var event_dot = new Gtk.Image ();
-+                        event_dot.gicon = new ThemedIcon ("pager-checked-symbolic");
-+                        event_dot.pixel_size = 6;
-+
-+                        unowned Gtk.StyleContext style_context = event_dot.get_style_context ();
-+                        style_context.add_class (Granite.STYLE_CLASS_ACCENT);
-+                        style_context.add_provider (provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
-+
-+                        var source_calendar = (E.SourceCalendar?) source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
-+                        Util.set_event_calendar_color (source_calendar, event_dot);
-+
-+                        event_dots[event_uid] = event_dot;
-+
-+                        event_grid.add (event_dot);
-+                    }
-+                }
-+            }
-+
-+            event_grid.show_all ();
-+        }
-+
-+        private void remove_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
-+            foreach (var component in events) {
-+                unowned ICal.Component ical = component.get_icalcomponent ();
-+                var event_uid = ical.get_uid ();
-+                var dot = event_dots[event_uid];
-+                if (dot != null) {
-+                    dot.destroy ();
-+                    event_dots.remove (event_uid);
-+                }
-+            }
-+        }
-+
-+        public void set_selected (bool selected) {
-+            if (selected) {
-+                set_state_flags (Gtk.StateFlags.SELECTED, true);
-+            } else {
-+                set_state_flags (Gtk.StateFlags.NORMAL, true);
-+            }
-+        }
-+
-+        public void grab_focus_force () {
-+            valid_grab = true;
-+            grab_focus ();
-+        }
-+
-+        public override void grab_focus () {
-+            if (valid_grab) {
-+                base.grab_focus ();
-+                valid_grab = false;
-+            }
-+        }
-+
-+        public void sensitive_container (bool sens) {
-+            label.sensitive = sens;
-+            event_grid.sensitive = sens;
-+        }
-+
-+        private bool on_button_press (Gdk.EventButton event) {
-+            if (event.type == Gdk.EventType.2BUTTON_PRESS && event.button == Gdk.BUTTON_PRIMARY)
-+                on_event_add (date);
-+            valid_grab = true;
-+            grab_focus ();
-+            return false;
-+        }
-+
-+        private bool on_key_press (Gdk.EventKey event) {
-+            if (event.keyval == Gdk.keyval_from_name ("Return") ) {
-+                on_event_add (date);
-+                return true;
-+            }
-+
-+            return false;
-+        }
-+    }
-+}
-diff --git a/src/Widgets/PanelLabel.vala b/src/Widgets/PanelLabel.vala
-index f253f9b..dff9a21 100644
---- a/src/Widgets/PanelLabel.vala
-+++ b/src/Widgets/PanelLabel.vala
-@@ -17,55 +17,57 @@
-  * Boston, MA 02110-1301 USA.
-  */
- 
--public class DateTime.Widgets.PanelLabel : Gtk.Grid {
--    private Gtk.Label date_label;
--    private Gtk.Label time_label;
--    private Services.TimeManager time_manager;
-+namespace DateTimeIndicator {
-+    public class Widgets.PanelLabel : Gtk.Grid {
-+        private Gtk.Label date_label;
-+        private Gtk.Label time_label;
-+        private Services.TimeManager time_manager;
- 
--    public string clock_format { get; set; }
--    public bool clock_show_seconds { get; set; }
--    public bool clock_show_weekday { get; set; }
-+        public string clock_format { get; set; }
-+        public bool clock_show_seconds { get; set; }
-+        public bool clock_show_weekday { get; set; }
- 
--    construct {
--        date_label = new Gtk.Label (null);
--        date_label.margin_end = 12;
-+        construct {
-+            date_label = new Gtk.Label (null);
-+            date_label.margin_end = 12;
- 
--        var date_revealer = new Gtk.Revealer ();
--        date_revealer.transition_type = Gtk.RevealerTransitionType.SLIDE_LEFT;
--        date_revealer.add (date_label);
-+            var date_revealer = new Gtk.Revealer ();
-+            date_revealer.transition_type = Gtk.RevealerTransitionType.SLIDE_LEFT;
-+            date_revealer.add (date_label);
- 
--        time_label = new Gtk.Label (null);
-+            time_label = new Gtk.Label (null);
- 
--        valign = Gtk.Align.CENTER;
--        add (date_revealer);
--        add (time_label);
-+            valign = Gtk.Align.CENTER;
-+            add (date_revealer);
-+            add (time_label);
- 
--        var clock_settings = new GLib.Settings ("io.elementary.desktop.wingpanel.datetime");
--        clock_settings.bind ("clock-format", this, "clock-format", SettingsBindFlags.DEFAULT);
--        clock_settings.bind ("clock-show-seconds", this, "clock-show-seconds", SettingsBindFlags.DEFAULT);
--        clock_settings.bind ("clock-show-date", date_revealer, "reveal_child", SettingsBindFlags.DEFAULT);
--        clock_settings.bind ("clock-show-weekday", this, "clock-show-weekday", SettingsBindFlags.DEFAULT);
-+            var clock_settings = new GLib.Settings ("io.elementary.desktop.wingpanel.datetime");
-+            clock_settings.bind ("clock-format", this, "clock-format", SettingsBindFlags.DEFAULT);
-+            clock_settings.bind ("clock-show-seconds", this, "clock-show-seconds", SettingsBindFlags.DEFAULT);
-+            clock_settings.bind ("clock-show-date", date_revealer, "reveal_child", SettingsBindFlags.DEFAULT);
-+            clock_settings.bind ("clock-show-weekday", this, "clock-show-weekday", SettingsBindFlags.DEFAULT);
- 
--        notify.connect (() => {
--            update_labels ();
--        });
-+            notify.connect (() => {
-+                update_labels ();
-+            });
- 
--        time_manager = Services.TimeManager.get_default ();
--        time_manager.minute_changed.connect (update_labels);
--        time_manager.notify["is-12h"].connect (update_labels);
--    }
--
--    private void update_labels () {
--        string date_format;
--        if (clock_format == "ISO8601") {
--            date_format = "%F";
--        } else {
--            date_format = Granite.DateTime.get_default_date_format (clock_show_weekday, true, false);
-+            time_manager = Services.TimeManager.get_default ();
-+            time_manager.minute_changed.connect (update_labels);
-+            time_manager.notify["is-12h"].connect (update_labels);
-         }
- 
--        date_label.label = time_manager.format (date_format);
-+        private void update_labels () {
-+            string date_format;
-+            if (clock_format == "ISO8601") {
-+                date_format = "%F";
-+            } else {
-+                date_format = Granite.DateTime.get_default_date_format (clock_show_weekday, true, false);
-+            }
- 
--        string time_format = Granite.DateTime.get_default_time_format (time_manager.is_12h, clock_show_seconds);
--        time_label.label = time_manager.format (time_format);
-+            date_label.label = time_manager.format (date_format);
-+
-+            string time_format = Granite.DateTime.get_default_time_format (time_manager.is_12h, clock_show_seconds);
-+            time_label.label = time_manager.format (time_format);
-+        }
-     }
- }
-diff --git a/src/Widgets/calendar/CalendarView.vala b/src/Widgets/calendar/CalendarView.vala
-deleted file mode 100644
-index ef3f8f9..0000000
---- a/src/Widgets/calendar/CalendarView.vala
-+++ /dev/null
-@@ -1,183 +0,0 @@
--/*-
-- * Copyright (c) 2011–2018 elementary, Inc. (https://elementary.io)
-- *
-- * This program is free software: you can redistribute it and/or modify
-- * it under the terms of the GNU General Public License as published by
-- * the Free Software Foundation, either version 3 of the License, or
-- * (at your option) any later version.
-- *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- * GNU General Public License for more details.
-- *
-- * You should have received a copy of the GNU General Public License
-- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
-- *
-- * Authored by: Maxwell Barvian
-- *              Corentin Noël <corentin@elementaryos.org>
-- */
--
--public class DateTime.Widgets.CalendarView : Gtk.Grid {
--    public signal void day_double_click ();
--    public signal void event_updates ();
--    public signal void selection_changed (GLib.DateTime? new_date);
--
--    public GLib.DateTime? selected_date { get; private set; }
--
--    private Grid grid;
--    private Gtk.Stack stack;
--    private Gtk.Grid big_grid;
--
--    construct {
--        var label = new Gtk.Label (new GLib.DateTime.now_local ().format (_("%OB, %Y")));
--        label.hexpand = true;
--        label.margin_start = 6;
--        label.xalign = 0;
--        label.width_chars = 13;
--
--        var provider = new Gtk.CssProvider ();
--        provider.load_from_resource ("/io/elementary/desktop/wingpanel/datetime/ControlHeader.css");
--
--        var label_style_context = label.get_style_context ();
--        label_style_context.add_class ("header-label");
--        label_style_context.add_provider (provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
--
--        var left_button = new Gtk.Button.from_icon_name ("pan-start-symbolic");
--        var center_button = new Gtk.Button.from_icon_name ("office-calendar-symbolic");
--        center_button.tooltip_text = _("Go to today's date");
--        var right_button = new Gtk.Button.from_icon_name ("pan-end-symbolic");
--
--        var box_buttons = new Gtk.Grid ();
--        box_buttons.margin_end = 6;
--        box_buttons.valign = Gtk.Align.CENTER;
--        box_buttons.get_style_context ().add_class (Gtk.STYLE_CLASS_LINKED);
--        box_buttons.add (left_button);
--        box_buttons.add (center_button);
--        box_buttons.add (right_button);
--
--        big_grid = create_big_grid ();
--
--        stack = new Gtk.Stack ();
--        stack.add (big_grid);
--        stack.show_all ();
--        stack.expand = true;
--
--        stack.notify["transition-running"].connect (() => {
--            if (stack.transition_running == false) {
--                stack.get_children ().foreach ((child) => {
--                    if (child != stack.visible_child) {
--                        child.destroy ();
--                    }
--                });
--            }
--        });
--
--        column_spacing = 6;
--        row_spacing = 6;
--        margin_start = margin_end = 10;
--        attach (label, 0, 0);
--        attach (box_buttons, 1, 0);
--        attach (stack, 0, 1, 2);
--
--        var model = CalendarModel.get_default ();
--        model.notify["data-range"].connect (() => {
--            label.label = model.month_start.format (_("%OB, %Y"));
--
--            sync_with_model ();
--
--            selected_date = null;
--            selection_changed (selected_date);
--        });
--
--        left_button.clicked.connect (() => {
--            model.change_month (-1);
--        });
--
--        right_button.clicked.connect (() => {
--            model.change_month (1);
--        });
--
--        center_button.clicked.connect (() => {
--            show_today ();
--        });
--    }
--
--    private Gtk.Grid create_big_grid () {
--        grid = new DateTime.Widgets.Grid ();
--        grid.show_all ();
--
--        grid.on_event_add.connect ((date) => {
--            show_date_in_maya (date);
--            day_double_click ();
--        });
--
--        grid.selection_changed.connect ((date) => {
--            selected_date = date;
--            selection_changed (date);
--        });
--
--        return grid;
--    }
--
--    public void show_today () {
--        var calmodel = CalendarModel.get_default ();
--        var today = Util.strip_time (new GLib.DateTime.now_local ());
--        var start = Util.get_start_of_month (today);
--        selected_date = today;
--        if (!start.equal (calmodel.month_start)) {
--            calmodel.month_start = start;
--        }
--        sync_with_model ();
--
--        grid.set_focus_to_today ();
--    }
--
--    // TODO: As far as maya supports it use the Dbus Activation feature to run the calendar-app.
--    public void show_date_in_maya (GLib.DateTime date) {
--        var command = "io.elementary.calendar --show-day %s".printf (date.format ("%F"));
--
--        try {
--            var appinfo = AppInfo.create_from_commandline (command, null, AppInfoCreateFlags.NONE);
--            appinfo.launch_uris (null, null);
--        } catch (GLib.Error e) {
--            var dialog = new Granite.MessageDialog.with_image_from_icon_name (
--                _("Unable To Launch Calendar"),
--                _("The program \"io.elementary.calendar\" may not be installed"),
--                "dialog-error"
--            );
--            dialog.show_error_details (e.message);
--            dialog.run ();
--            dialog.destroy ();
--        }
--    }
--
--    /* Sets the calendar widgets to the date range of the model */
--    private void sync_with_model () {
--        var model = CalendarModel.get_default ();
--        if (grid.grid_range != null && (model.data_range.equals (grid.grid_range) || grid.grid_range.first_dt.compare (model.data_range.first_dt) == 0)) {
--            grid.update_today ();
--            return; // nothing else to do
--        }
--
--        GLib.DateTime previous_first = null;
--        if (grid.grid_range != null)
--            previous_first = grid.grid_range.first_dt;
--
--        big_grid = create_big_grid ();
--        stack.add (big_grid);
--
--        grid.set_range (model.data_range, model.month_start);
--        grid.update_weeks (model.data_range.first_dt, model.num_weeks);
--
--        if (previous_first != null) {
--            if (previous_first.compare (grid.grid_range.first_dt) == -1) {
--                stack.transition_type = Gtk.StackTransitionType.SLIDE_LEFT;
--            } else {
--                stack.transition_type = Gtk.StackTransitionType.SLIDE_RIGHT;
--            }
--        }
--
--        stack.set_visible_child (big_grid);
--    }
--}
-diff --git a/src/Widgets/calendar/GridDay.vala b/src/Widgets/calendar/GridDay.vala
-deleted file mode 100644
-index a9b5a28..0000000
---- a/src/Widgets/calendar/GridDay.vala
-+++ /dev/null
-@@ -1,178 +0,0 @@
--// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
--/*-
-- * Copyright (c) 2011–2018 elementary, Inc. (https://elementary.io)
-- *
-- * This program is free software: you can redistribute it and/or modify
-- * it under the terms of the GNU General Public License as published by
-- * the Free Software Foundation, either version 3 of the License, or
-- * (at your option) any later version.
-- *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- * GNU General Public License for more details.
-- *
-- * You should have received a copy of the GNU General Public License
-- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
-- *
-- * Authored by: Maxwell Barvian
-- *              Corentin Noël <corentin@elementaryos.org>
-- */
--
--/**
-- * Represents a single day on the grid.
-- */
--public class DateTime.Widgets.GridDay : Gtk.EventBox {
--    /*
--     * Event emitted when the day is double clicked or the ENTER key is pressed.
--     */
--    public signal void on_event_add (GLib.DateTime date);
--
--    public GLib.DateTime date { get; construct set; }
--
--    private static Gtk.CssProvider provider;
--    private static Widgets.CalendarModel model;
--
--    private Gee.HashMap<string, Gtk.Widget> event_dots;
--    private Gtk.Grid event_grid;
--    private Gtk.Label label;
--    private bool valid_grab = false;
--
--    public GridDay (GLib.DateTime date) {
--        Object (date: date);
--    }
--
--    static construct {
--        model = Widgets.CalendarModel.get_default ();
--
--        provider = new Gtk.CssProvider ();
--        provider.load_from_resource ("/io/elementary/desktop/wingpanel/datetime/GridDay.css");
--    }
--
--    construct {
--        unowned Gtk.StyleContext style_context = get_style_context ();
--        style_context.add_provider (provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
--        style_context.add_class ("circular");
--
--        label = new Gtk.Label (null);
--
--        event_grid = new Gtk.Grid ();
--        event_grid.halign = Gtk.Align.CENTER;
--        event_grid.height_request = 6;
--
--        var grid = new Gtk.Grid ();
--        grid.halign = grid.valign = Gtk.Align.CENTER;
--        grid.attach (label, 0, 0);
--        grid.attach (event_grid, 0, 1);
--
--        can_focus = true;
--        events |= Gdk.EventMask.BUTTON_PRESS_MASK;
--        events |= Gdk.EventMask.KEY_PRESS_MASK;
--        events |= Gdk.EventMask.SMOOTH_SCROLL_MASK;
--        set_size_request (35, 35);
--        halign = Gtk.Align.CENTER;
--        hexpand = true;
--        add (grid);
--        show_all ();
--
--        // Signals and handlers
--        button_press_event.connect (on_button_press);
--        key_press_event.connect (on_key_press);
--        scroll_event.connect ((event) => {return Util.on_scroll_event (event);});
--
--        notify["date"].connect (() => {
--            label.label = date.get_day_of_month ().to_string ();
--        });
--
--        event_dots = new Gee.HashMap<string, Gtk.Widget> ();
--
--        model.events_added.connect (add_event_dots);
--        model.events_removed.connect (remove_event_dots);
--    }
--
--    private void add_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
--        foreach (var component in events) {
--            if (event_dots.size >= 3) {
--                return;
--            }
--
--            if (Util.calcomp_is_on_day (component, date)) {
--                unowned ICal.Component ical = component.get_icalcomponent ();
--
--                var event_uid = ical.get_uid ();
--                if (!event_dots.has_key (event_uid)) {
--                    var event_dot = new Gtk.Image ();
--                    event_dot.gicon = new ThemedIcon ("pager-checked-symbolic");
--                    event_dot.pixel_size = 6;
--
--                    unowned Gtk.StyleContext style_context = event_dot.get_style_context ();
--                    style_context.add_class (Granite.STYLE_CLASS_ACCENT);
--                    style_context.add_provider (provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
--
--                    var source_calendar = (E.SourceCalendar?) source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
--                    Util.set_event_calendar_color (source_calendar, event_dot);
--
--                    event_dots[event_uid] = event_dot;
--
--                    event_grid.add (event_dot);
--                }
--            }
--        }
--
--        event_grid.show_all ();
--    }
--
--    private void remove_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
--        foreach (var component in events) {
--            unowned ICal.Component ical = component.get_icalcomponent ();
--            var event_uid = ical.get_uid ();
--            var dot = event_dots[event_uid];
--            if (dot != null) {
--                dot.destroy ();
--                event_dots.remove (event_uid);
--            }
--        }
--    }
--
--    public void set_selected (bool selected) {
--        if (selected) {
--            set_state_flags (Gtk.StateFlags.SELECTED, true);
--        } else {
--            set_state_flags (Gtk.StateFlags.NORMAL, true);
--        }
--    }
--
--    public void grab_focus_force () {
--        valid_grab = true;
--        grab_focus ();
--    }
--
--    public override void grab_focus () {
--        if (valid_grab) {
--            base.grab_focus ();
--            valid_grab = false;
--        }
--    }
--
--    public void sensitive_container (bool sens) {
--        label.sensitive = sens;
--        event_grid.sensitive = sens;
--    }
--
--    private bool on_button_press (Gdk.EventButton event) {
--        if (event.type == Gdk.EventType.2BUTTON_PRESS && event.button == Gdk.BUTTON_PRIMARY)
--            on_event_add (date);
--        valid_grab = true;
--        grab_focus ();
--        return false;
--    }
--
--    private bool on_key_press (Gdk.EventKey event) {
--        if (event.keyval == Gdk.keyval_from_name ("Return") ) {
--            on_event_add (date);
--            return true;
--        }
--
--        return false;
--    }
--}
-
-From 11f11073d74dac1d831560c3a92687531aaf846e Mon Sep 17 00:00:00 2001
-From: Dirli <litandrej85@gmail.com>
-Date: Thu, 9 Apr 2020 20:46:31 +0300
-Subject: [PATCH 2/8] Events list moved to a separate file
-
----
- meson.build                    |   1 +
- src/Indicator.vala             | 113 +++------------------------------
- src/Widgets/EventsListBox.vala | 102 +++++++++++++++++++++++++++++
- 3 files changed, 113 insertions(+), 103 deletions(-)
- create mode 100644 src/Widgets/EventsListBox.vala
-
-diff --git a/meson.build b/meson.build
-index b44c5bd..1b52276 100644
---- a/meson.build
-+++ b/meson.build
-@@ -46,6 +46,7 @@ shared_module(
-     'src/Models/CalendarModel.vala',
-     'src/Widgets/CalendarView.vala',
-     'src/Widgets/EventRow.vala',
-+    'src/Widgets/EventsListBox.vala',
-     'src/Widgets/Grid.vala',
-     'src/Widgets/GridDay.vala',
-     'src/Widgets/PanelLabel.vala',
-diff --git a/src/Indicator.vala b/src/Indicator.vala
-index b712c12..6a8d001 100644
---- a/src/Indicator.vala
-+++ b/src/Indicator.vala
-@@ -22,9 +22,9 @@ namespace DateTimeIndicator {
-         public static GLib.Settings settings;
- 
-         private Widgets.PanelLabel panel_label;
--        private Gtk.Grid main_grid;
-         private Widgets.CalendarView calendar;
--        private Gtk.ListBox event_listbox;
-+        private Widgets.EventsListBox event_listbox;
-+        private Gtk.Grid main_grid;
-         private uint update_events_idle_source = 0;
- 
-         public Indicator () {
-@@ -56,24 +56,7 @@ namespace DateTimeIndicator {
-                 calendar = new Widgets.CalendarView ();
-                 calendar.margin_bottom = 6;
- 
--                var placeholder_label = new Gtk.Label (_("No Events on This Day"));
--                placeholder_label.wrap = true;
--                placeholder_label.wrap_mode = Pango.WrapMode.WORD;
--                placeholder_label.margin_start = 12;
--                placeholder_label.margin_end = 12;
--                placeholder_label.max_width_chars = 20;
--                placeholder_label.justify = Gtk.Justification.CENTER;
--                placeholder_label.show_all ();
--
--                var placeholder_style_context = placeholder_label.get_style_context ();
--                placeholder_style_context.add_class (Gtk.STYLE_CLASS_DIM_LABEL);
--                placeholder_style_context.add_class (Granite.STYLE_CLASS_H3_LABEL);
--
--                event_listbox = new Gtk.ListBox ();
--                event_listbox.selection_mode = Gtk.SelectionMode.NONE;
--                event_listbox.set_header_func (header_update_func);
--                event_listbox.set_placeholder (placeholder_label);
--                event_listbox.set_sort_func (sort_function);
-+                event_listbox = new Widgets.EventsListBox ();
- 
-                 var scrolled_window = new Gtk.ScrolledWindow (null, null);
-                 scrolled_window.hscrollbar_policy = Gtk.PolicyType.NEVER;
-@@ -84,11 +67,11 @@ namespace DateTimeIndicator {
- 
-                 main_grid = new Gtk.Grid ();
-                 main_grid.margin_top = 12;
--                main_grid.attach (calendar, 0, 0);
--                main_grid.attach (new Gtk.Separator (Gtk.Orientation.VERTICAL), 1, 0);
--                main_grid.attach (scrolled_window, 2, 0);
--                main_grid.attach (new Wingpanel.Widgets.Separator (), 0, 2, 3);
--                main_grid.attach (settings_button, 0, 3, 3);
-+                main_grid.attach (calendar,                                     0, 0);
-+                main_grid.attach (new Wingpanel.Widgets.Separator (),           0, 1);
-+                main_grid.attach (settings_button,                              0, 2);
-+                main_grid.attach (new Gtk.Separator (Gtk.Orientation.VERTICAL), 1, 0, 1, 3);
-+                main_grid.attach (scrolled_window,                              2, 0, 1, 3);
- 
-                 var size_group = new Gtk.SizeGroup (Gtk.SizeGroupMode.HORIZONTAL);
-                 size_group.add_widget (calendar);
-@@ -119,52 +102,6 @@ namespace DateTimeIndicator {
-             return main_grid;
-         }
- 
--        private void header_update_func (Gtk.ListBoxRow lbrow, Gtk.ListBoxRow? lbbefore) {
--            var row = (EventRow) lbrow;
--            if (lbbefore != null) {
--                var before = (EventRow) lbbefore;
--                if (row.is_allday == before.is_allday) {
--                    row.set_header (null);
--                    return;
--                }
--
--                if (row.is_allday != before.is_allday) {
--                    var header_label = new Granite.HeaderLabel (_("During the Day"));
--                    header_label.margin_start = header_label.margin_end = 6;
--
--                    row.set_header (header_label);
--                    return;
--                }
--            } else {
--                if (row.is_allday) {
--                    var allday_header = new Granite.HeaderLabel (_("All Day"));
--                    allday_header.margin_start = allday_header.margin_end = 6;
--
--                    row.set_header (allday_header);
--                }
--                return;
--            }
--        }
--
--        [CCode (instance_pos = -1)]
--        private int sort_function (Gtk.ListBoxRow child1, Gtk.ListBoxRow child2) {
--            var e1 = (EventRow) child1;
--            var e2 = (EventRow) child2;
--
--            if (e1.start_time.compare (e2.start_time) != 0) {
--                return e1.start_time.compare (e2.start_time);
--            }
--
--            // If they have the same date, sort them wholeday first
--            if (e1.is_allday) {
--                return -1;
--            } else if (e2.is_allday) {
--                return 1;
--            }
--
--            return 0;
--        }
--
-         private void update_events_model (E.Source source, Gee.Collection<ECal.Component> events) {
-             idle_update_events ();
-         }
-@@ -174,42 +111,12 @@ namespace DateTimeIndicator {
-                 GLib.Source.remove (update_events_idle_source);
-             }
- 
--            update_events_idle_source = GLib.Idle.add (update_events);
--        }
--
--        private bool update_events () {
--            foreach (unowned Gtk.Widget widget in event_listbox.get_children ()) {
--                widget.destroy ();
--            }
-+            update_events_idle_source = GLib.Idle.add (() => {
-+                event_listbox.update_events (calendar.selected_date);
- 
--            if (calendar.selected_date == null) {
-                 update_events_idle_source = 0;
-                 return GLib.Source.REMOVE;
--            }
--
--            var date = calendar.selected_date;
--
--            var model = Models.CalendarModel.get_default ();
--
--            var events_on_day = new Gee.TreeMap<string, EventRow> ();
--
--            model.source_events.@foreach ((source, component_map) => {
--                foreach (var comp in component_map.get_values ()) {
--                    if (Util.calcomp_is_on_day (comp, date)) {
--                        unowned ICal.Component ical = comp.get_icalcomponent ();
--                        var event_uid = ical.get_uid ();
--                        if (!events_on_day.has_key (event_uid)) {
--                            events_on_day[event_uid] = new EventRow (date, ical, source);
--
--                            event_listbox.add (events_on_day[event_uid]);
--                        }
--                    }
--                }
-             });
--
--            event_listbox.show_all ();
--            update_events_idle_source = 0;
--            return GLib.Source.REMOVE;
-         }
- 
-         public override void opened () {
-diff --git a/src/Widgets/EventsListBox.vala b/src/Widgets/EventsListBox.vala
-new file mode 100644
-index 0000000..547e4c5
---- /dev/null
-+++ b/src/Widgets/EventsListBox.vala
-@@ -0,0 +1,102 @@
-+namespace DateTimeIndicator {
-+    public class Widgets.EventsListBox : Gtk.ListBox {
-+
-+        public EventsListBox () {
-+            selection_mode = Gtk.SelectionMode.NONE;
-+
-+            var placeholder_label = new Gtk.Label (_("No Events on This Day"));
-+            placeholder_label.wrap = true;
-+            placeholder_label.wrap_mode = Pango.WrapMode.WORD;
-+            placeholder_label.margin_start = 12;
-+            placeholder_label.margin_end = 12;
-+            placeholder_label.max_width_chars = 20;
-+            placeholder_label.justify = Gtk.Justification.CENTER;
-+            placeholder_label.show_all ();
-+
-+            var placeholder_style_context = placeholder_label.get_style_context ();
-+            placeholder_style_context.add_class (Gtk.STYLE_CLASS_DIM_LABEL);
-+            placeholder_style_context.add_class (Granite.STYLE_CLASS_H3_LABEL);
-+
-+            set_header_func (header_update_func);
-+            set_placeholder (placeholder_label);
-+            set_sort_func (sort_function);
-+        }
-+
-+        public void update_events (GLib.DateTime? selected_date) {
-+            foreach (unowned Gtk.Widget widget in get_children ()) {
-+                widget.destroy ();
-+            }
-+
-+            if (selected_date == null) {
-+                return;
-+            }
-+
-+            var model = Models.CalendarModel.get_default ();
-+
-+            var events_on_day = new Gee.TreeMap<string, EventRow> ();
-+
-+            model.source_events.@foreach ((source, component_map) => {
-+                foreach (var comp in component_map.get_values ()) {
-+                    if (Util.calcomp_is_on_day (comp, selected_date)) {
-+                        unowned ICal.Component ical = comp.get_icalcomponent ();
-+                        var event_uid = ical.get_uid ();
-+                        if (!events_on_day.has_key (event_uid)) {
-+                            events_on_day[event_uid] = new EventRow (selected_date, ical, source);
-+
-+                            add (events_on_day[event_uid]);
-+                        }
-+                    }
-+                }
-+            });
-+
-+            show_all ();
-+            return;
-+        }
-+
-+        private void header_update_func (Gtk.ListBoxRow lbrow, Gtk.ListBoxRow? lbbefore) {
-+            var row = (EventRow) lbrow;
-+            if (lbbefore != null) {
-+                var before = (EventRow) lbbefore;
-+                if (row.is_allday == before.is_allday) {
-+                    row.set_header (null);
-+                    return;
-+                }
-+
-+                if (row.is_allday != before.is_allday) {
-+                    var header_label = new Granite.HeaderLabel (_("During the Day"));
-+                    header_label.margin_start = header_label.margin_end = 6;
-+
-+                    row.set_header (header_label);
-+                    return;
-+                }
-+            } else {
-+                if (row.is_allday) {
-+                    var allday_header = new Granite.HeaderLabel (_("All Day"));
-+                    allday_header.margin_start = allday_header.margin_end = 6;
-+
-+                    row.set_header (allday_header);
-+                }
-+                return;
-+            }
-+        }
-+
-+        [CCode (instance_pos = -1)]
-+        private int sort_function (Gtk.ListBoxRow child1, Gtk.ListBoxRow child2) {
-+            var e1 = (EventRow) child1;
-+            var e2 = (EventRow) child2;
-+
-+            if (e1.start_time.compare (e2.start_time) != 0) {
-+                return e1.start_time.compare (e2.start_time);
-+            }
-+
-+            // If they have the same date, sort them wholeday first
-+            if (e1.is_allday) {
-+                return -1;
-+            } else if (e2.is_allday) {
-+                return 1;
-+            }
-+
-+            return 0;
-+        }
-+    }
-+}
-
-From 262d91676f78f031bcfbff637344e52c63ab89bd Mon Sep 17 00:00:00 2001
-From: Dirli <litandrej85@gmail.com>
-Date: Sat, 11 Apr 2020 21:56:33 +0300
-Subject: [PATCH 3/8] added event manager
-
----
- meson.build                     |   1 +
- src/Indicator.vala              |  38 ++++--
- src/Models/CalendarModel.vala   | 224 +------------------------------
- src/Services/EventsManager.vala | 226 ++++++++++++++++++++++++++++++++
- src/Util/Util.vala              |  57 ++------
- src/Widgets/CalendarView.vala   |   9 ++
- src/Widgets/EventsListBox.vala  |   7 +-
- src/Widgets/Grid.vala           |  31 +++++
- src/Widgets/GridDay.vala        | 111 +++++++++++-----
- 9 files changed, 385 insertions(+), 319 deletions(-)
- create mode 100644 src/Services/EventsManager.vala
-
-diff --git a/meson.build b/meson.build
-index 1b52276..e348e3d 100644
---- a/meson.build
-+++ b/meson.build
-@@ -50,6 +50,7 @@ shared_module(
-     'src/Widgets/Grid.vala',
-     'src/Widgets/GridDay.vala',
-     'src/Widgets/PanelLabel.vala',
-+    'src/Services/EventsManager.vala',
-     'src/Services/TimeManager.vala',
-     dependencies: [
-         dependency('glib-2.0'),
-diff --git a/src/Indicator.vala b/src/Indicator.vala
-index 6a8d001..bf4358f 100644
---- a/src/Indicator.vala
-+++ b/src/Indicator.vala
-@@ -24,9 +24,14 @@ namespace DateTimeIndicator {
-         private Widgets.PanelLabel panel_label;
-         private Widgets.CalendarView calendar;
-         private Widgets.EventsListBox event_listbox;
-+
-+        private Services.EventsManager event_manager;
-+
-         private Gtk.Grid main_grid;
-         private uint update_events_idle_source = 0;
- 
-+        private bool opened_widget = false;
-+
-         public Indicator () {
-             Object (
-                 code_name: Wingpanel.Indicator.DATETIME,
-@@ -56,10 +61,22 @@ namespace DateTimeIndicator {
-                 calendar = new Widgets.CalendarView ();
-                 calendar.margin_bottom = 6;
- 
-+                event_manager = new Services.EventsManager ();
-+                event_manager.events_updated.connect (update_events_model);
-+                event_manager.events_added.connect ((source, events) => {
-+                    calendar.add_event_dots (source, events);
-+                    update_events_model (source, events);
-+                });
-+                event_manager.events_removed.connect ((source, events) => {
-+                    calendar.remove_event_dots (source, events);
-+                    update_events_model (source, events);
-+                });
-+
-                 event_listbox = new Widgets.EventsListBox ();
- 
-                 var scrolled_window = new Gtk.ScrolledWindow (null, null);
-                 scrolled_window.hscrollbar_policy = Gtk.PolicyType.NEVER;
-+                scrolled_window.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC;
-                 scrolled_window.add (event_listbox);
- 
-                 var settings_button = new Gtk.ModelButton ();
-@@ -90,6 +107,12 @@ namespace DateTimeIndicator {
-                     close ();
-                 });
- 
-+                var model = Models.CalendarModel.get_default ();
-+                model.notify["month-start"].connect (() => {
-+                    model.compute_ranges ();
-+                    event_manager.load_all_sources ();
-+                });
-+
-                 settings_button.clicked.connect (() => {
-                     try {
-                         AppInfo.launch_default_for_uri ("settings://time", null);
-@@ -103,7 +126,9 @@ namespace DateTimeIndicator {
-         }
- 
-         private void update_events_model (E.Source source, Gee.Collection<ECal.Component> events) {
--            idle_update_events ();
-+            if (opened_widget) {
-+                idle_update_events ();
-+            }
-         }
- 
-         private void idle_update_events () {
-@@ -112,7 +137,7 @@ namespace DateTimeIndicator {
-             }
- 
-             update_events_idle_source = GLib.Idle.add (() => {
--                event_listbox.update_events (calendar.selected_date);
-+                event_listbox.update_events (calendar.selected_date, event_manager.source_events);
- 
-                 update_events_idle_source = 0;
-                 return GLib.Source.REMOVE;
-@@ -122,18 +147,15 @@ namespace DateTimeIndicator {
-         public override void opened () {
-             calendar.show_today ();
- 
--            Models.CalendarModel.get_default ().events_added.connect (update_events_model);
--            Models.CalendarModel.get_default ().events_updated.connect (update_events_model);
--            Models.CalendarModel.get_default ().events_removed.connect (update_events_model);
-+            opened_widget = true;
-         }
- 
-         public override void closed () {
--            Models.CalendarModel.get_default ().events_added.disconnect (update_events_model);
--            Models.CalendarModel.get_default ().events_updated.disconnect (update_events_model);
--            Models.CalendarModel.get_default ().events_removed.disconnect (update_events_model);
-+            opened_widget = false;
-         }
-     }
- }
-+
- public Wingpanel.Indicator get_indicator (Module module) {
-     debug ("Activating DateTime Indicator");
-     var indicator = new DateTimeIndicator.Indicator ();
-diff --git a/src/Models/CalendarModel.vala b/src/Models/CalendarModel.vala
-index 965b93e..d60a9ac 100644
---- a/src/Models/CalendarModel.vala
-+++ b/src/Models/CalendarModel.vala
-@@ -35,17 +35,6 @@ namespace DateTimeIndicator {
-         /* The start of week, ie. Monday=1 or Sunday=7 */
-         public GLib.DateWeekday week_starts_on { get; set; }
- 
--        public HashTable<E.Source, Gee.TreeMultiMap<string, ECal.Component>> source_events { get; private set; }
--
--        /* Notifies when events are added, updated, or removed */
--        public signal void events_added (E.Source source, Gee.Collection<ECal.Component> events);
--        public signal void events_updated (E.Source source, Gee.Collection<ECal.Component> events);
--        public signal void events_removed (E.Source source, Gee.Collection<ECal.Component> events);
--
--        private E.SourceRegistry registry { get; private set; }
--        private HashTable<string, ECal.Client> source_client;
--        private HashTable<string, ECal.ClientView> source_view;
--
-         private static CalendarModel? calendar_model = null;
- 
-         public static CalendarModel get_default () {
-@@ -59,12 +48,6 @@ namespace DateTimeIndicator {
-         }
- 
-         construct {
--            open.begin ();
--
--            source_client = new HashTable<string, ECal.Client> (str_hash, str_equal);
--            source_events = new HashTable<E.Source, Gee.TreeMultiMap<string, ECal.Component> > (Util.source_hash_func, Util.source_equal_func);
--            source_view = new HashTable<string, ECal.ClientView> (str_hash, str_equal);
--
-             int week_start = Posix.NLTime.FIRST_WEEKDAY.to_string ().data[0];
-             if (week_start >= 1 && week_start <= 7) {
-                 week_starts_on = (GLib.DateWeekday) (week_start - 1);
-@@ -72,66 +55,6 @@ namespace DateTimeIndicator {
- 
-             month_start = Util.get_start_of_month ();
-             compute_ranges ();
--            notify["month-start"].connect (on_parameter_changed);
--        }
--
--        private async void open () {
--            try {
--                registry = yield new E.SourceRegistry (null);
--                registry.source_removed.connect (remove_source);
--                registry.source_added.connect ((source) => add_source_async.begin (source));
--
--                // Add sources
--                registry.list_sources (E.SOURCE_EXTENSION_CALENDAR).foreach ((source) => {
--                    E.SourceCalendar cal = (E.SourceCalendar)source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
--                    if (cal.selected == true && source.enabled == true) {
--                        add_source_async.begin (source);
--                    }
--                });
--
--                load_all_sources ();
--            } catch (GLib.Error error) {
--                critical (error.message);
--            }
--        }
--
--        private void load_all_sources () {
--            lock (source_client) {
--                foreach (var id in source_client.get_keys ()) {
--                    var source = registry.ref_source (id);
--                    E.SourceCalendar cal = (E.SourceCalendar)source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
--
--                    if (cal.selected == true && source.enabled == true) {
--                        load_source (source);
--                    }
--                }
--            }
--        }
--
--        private void remove_source (E.Source source) {
--            debug ("Removing source '%s'", source.dup_display_name ());
--            /* Already out of the model, so do nothing */
--            unowned string uid = source.get_uid ();
--
--            if (!source_view.contains (uid)) {
--                return;
--            }
--
--            var current_view = source_view.get (uid);
--            try {
--                current_view.stop ();
--            } catch (Error e) {
--                warning (e.message);
--            }
--
--            source_view.remove (uid);
--            lock (source_client) {
--                source_client.remove (uid);
--            }
--
--            var events = source_events.get (source).get_values ().read_only_view;
--            events_removed (source, events);
--            source_events.remove (source);
-         }
- 
-         public void change_month (int relative) {
-@@ -144,7 +67,7 @@ namespace DateTimeIndicator {
- 
-         /* --- Helper Methods ---// */
- 
--        private void compute_ranges () {
-+        public void compute_ranges () {
-             var month_end = month_start.add_full (0, 1, -1);
- 
-             int dow = month_start.get_day_of_week ();
-@@ -182,150 +105,5 @@ namespace DateTimeIndicator {
- 
-             debug (@"Date ranges: ($data_range_first <= $month_start < $month_end <= $data_range_last)");
-         }
--
--        private void load_source (E.Source source) {
--            /* create empty source-event map */
--            var events = new Gee.TreeMultiMap<string, ECal.Component> (
--                (GLib.CompareDataFunc<ECal.Component>?) GLib.strcmp,
--                (GLib.CompareDataFunc<ECal.Component>?) Util.calcomponent_compare_func
--            );
--            source_events.set (source, events);
--            /* query client view */
--            var iso_first = ECal.isodate_from_time_t ((time_t)data_range.first_dt.to_unix ());
--            var iso_last = ECal.isodate_from_time_t ((time_t)data_range.last_dt.add_days (1).to_unix ());
--            var query = @"(occur-in-time-range? (make-time \"$iso_first\") (make-time \"$iso_last\"))";
--
--            ECal.Client client;
--            lock (source_client) {
--                client = source_client.get (source.dup_uid ());
--            }
--
--            if (client == null) {
--                return;
--            }
--
--            debug ("Getting client-view for source '%s'", source.dup_display_name ());
--            client.get_view.begin (query, null, (obj, results) => {
--                var view = on_client_view_received (results, source, client);
--                view.objects_added.connect ((objects) => on_objects_added (source, client, objects));
--                view.objects_removed.connect ((objects) => on_objects_removed (source, client, objects));
--                view.objects_modified.connect ((objects) => on_objects_modified (source, client, objects));
--                try {
--                    view.start ();
--                } catch (Error e) {
--                    critical (e.message);
--                }
--
--                source_view.set (source.dup_uid (), view);
--            });
--        }
--
--        private async void add_source_async (E.Source source) {
--            debug ("Adding source '%s'", source.dup_display_name ());
--            try {
--                var client = (ECal.Client) ECal.Client.connect_sync (source, ECal.ClientSourceType.EVENTS, -1, null);
--                source_client.insert (source.dup_uid (), client);
--            } catch (Error e) {
--                critical (e.message);
--            }
--
--            Idle.add (() => {
--                load_source (source);
--
--                return false;
--            });
--        }
--
--        private void debug_event (E.Source source, ECal.Component event) {
--            unowned ICal.Component comp = event.get_icalcomponent ();
--            debug (@"Event ['$(comp.get_summary())', $(source.dup_display_name()), $(comp.get_uid()))]");
--        }
--
--        /* --- Signal Handlers ---// */
--        private void on_parameter_changed () {
--            compute_ranges ();
--            load_all_sources ();
--        }
--
--        private ECal.ClientView on_client_view_received (AsyncResult results, E.Source source, ECal.Client client) {
--            ECal.ClientView view;
--            try {
--                debug ("Received client-view for source '%s'", source.dup_display_name ());
--                bool status = client.get_view.end (results, out view);
--                assert (status == true);
--            } catch (Error e) {
--                critical ("Error loading client-view from source '%s': %s", source.dup_display_name (), e.message);
--            }
--
--            return view;
--        }
--
--#if E_CAL_2_0
--        private void on_objects_added (E.Source source, ECal.Client client, SList<ICal.Component> objects) {
--#else
--        private void on_objects_added (E.Source source, ECal.Client client, SList<weak ICal.Component> objects) {
--#endif
--            debug (@"Received $(objects.length()) added event(s) for source '%s'", source.dup_display_name ());
--            var events = source_events.get (source);
--            var added_events = new Gee.ArrayList<ECal.Component> ((Gee.EqualDataFunc<ECal.Component>?) Util.calcomponent_equal_func);
--            objects.foreach ((comp) => {
--                unowned string uid = comp.get_uid ();
--#if E_CAL_2_0
--                client.generate_instances_for_object_sync (comp, (time_t) data_range.first_dt.to_unix (), (time_t) data_range.last_dt.to_unix (), null, (comp, start, end) => {
--                    var event = new ECal.Component.from_icalcomponent (comp);
--#else
--                client.generate_instances_for_object_sync (comp, (time_t) data_range.first_dt.to_unix (), (time_t) data_range.last_dt.to_unix (), (event, start, end) => {
--#endif
--                    debug_event (source, event);
--                    events.set (uid, event);
--                    added_events.add (event);
--                    return true;
--                });
--            });
--        }
--
--#if E_CAL_2_0
--        private void on_objects_modified (E.Source source, ECal.Client client, SList<ICal.Component> objects) {
--#else
--        private void on_objects_modified (E.Source source, ECal.Client client, SList<weak ICal.Component> objects) {
--#endif
--            debug (@"Received $(objects.length()) modified event(s) for source '%s'", source.dup_display_name ());
--            var updated_events = new Gee.ArrayList<ECal.Component> ((Gee.EqualDataFunc<ECal.Component>?) Util.calcomponent_equal_func);
--
--            objects.foreach ((comp) => {
--                unowned string uid = comp.get_uid ();
--                var events = source_events.get (source).get (uid);
--                updated_events.add_all (events);
--                foreach (var event in events) {
--                    debug_event (source, event);
--                }
--            });
--
--            events_updated (source, updated_events.read_only_view);
--        }
--
--#if E_CAL_2_0
--        private void on_objects_removed (E.Source source, ECal.Client client, SList<ECal.ComponentId?> cids) {
--#else
--        private void on_objects_removed (E.Source source, ECal.Client client, SList<weak ECal.ComponentId?> cids) {
--#endif
--            debug (@"Received $(cids.length()) removed event(s) for source '%s'", source.dup_display_name ());
--            var events = source_events.get (source);
--            var removed_events = new Gee.ArrayList<ECal.Component> ((Gee.EqualDataFunc<ECal.Component>?) Util.calcomponent_equal_func);
--
--            cids.foreach ((cid) => {
--                if (cid == null) {
--                    return;
--                }
--
--                var comps = events.get (cid.get_uid ());
--                foreach (ECal.Component event in comps) {
--                    removed_events.add (event);
--                    debug_event (source, event);
--                }
--            });
--
--            events_removed (source, removed_events.read_only_view);
--        }
-     }
- }
-diff --git a/src/Services/EventsManager.vala b/src/Services/EventsManager.vala
-new file mode 100644
-index 0000000..d939777
---- /dev/null
-+++ b/src/Services/EventsManager.vala
-@@ -0,0 +1,226 @@
-+namespace DateTimeIndicator {
-+    public class Services.EventsManager : GLib.Object {
-+        public signal void events_added (E.Source source, Gee.Collection<ECal.Component> events);
-+        public signal void events_updated (E.Source source, Gee.Collection<ECal.Component> events);
-+        public signal void events_removed (E.Source source, Gee.Collection<ECal.Component> events);
-+
-+        public HashTable<E.Source, Gee.TreeMultiMap<string, ECal.Component>> source_events { get; private set; }
-+
-+        private E.SourceRegistry registry { get; private set; }
-+        private HashTable<string, ECal.Client> source_client;
-+        private HashTable<string, ECal.ClientView> source_view;
-+
-+        public EventsManager () {
-+
-+        }
-+
-+        construct {
-+            source_client = new HashTable<string, ECal.Client> (str_hash, str_equal);
-+            source_events = new HashTable<E.Source, Gee.TreeMultiMap<string, ECal.Component> > (Util.source_hash_func, Util.source_equal_func);
-+            source_view = new HashTable<string, ECal.ClientView> (str_hash, str_equal);
-+
-+            open.begin ();
-+        }
-+
-+        private async void open () {
-+            try {
-+                registry = yield new E.SourceRegistry (null);
-+                registry.source_removed.connect (remove_source);
-+                registry.source_added.connect ((source) => add_source_async.begin (source));
-+
-+                // Add sources
-+                registry.list_sources (E.SOURCE_EXTENSION_CALENDAR).foreach ((source) => {
-+                    E.SourceCalendar cal = (E.SourceCalendar)source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
-+                    if (cal.selected == true && source.enabled == true) {
-+                        add_source_async.begin (source);
-+                    }
-+                });
-+
-+                load_all_sources ();
-+            } catch (GLib.Error error) {
-+                critical (error.message);
-+            }
-+        }
-+
-+        public void load_all_sources () {
-+            lock (source_client) {
-+                foreach (var id in source_client.get_keys ()) {
-+                    var source = registry.ref_source (id);
-+                    E.SourceCalendar cal = (E.SourceCalendar)source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
-+
-+                    if (cal.selected == true && source.enabled == true) {
-+                        load_source (source);
-+                    }
-+                }
-+            }
-+        }
-+
-+        private void remove_source (E.Source source) {
-+            debug ("Removing source '%s'", source.dup_display_name ());
-+            /* Already out of the model, so do nothing */
-+            unowned string uid = source.get_uid ();
-+
-+            if (!source_view.contains (uid)) {
-+                return;
-+            }
-+
-+            var current_view = source_view.get (uid);
-+            try {
-+                current_view.stop ();
-+            } catch (Error e) {
-+                warning (e.message);
-+            }
-+
-+            source_view.remove (uid);
-+            lock (source_client) {
-+                source_client.remove (uid);
-+            }
-+
-+            var events = source_events.get (source).get_values ().read_only_view;
-+            events_removed (source, events);
-+            source_events.remove (source);
-+        }
-+
-+        private void load_source (E.Source source) {
-+            var model = Models.CalendarModel.get_default ();
-+
-+            /* create empty source-event map */
-+            var events = new Gee.TreeMultiMap<string, ECal.Component> (
-+                (GLib.CompareDataFunc<ECal.Component>?) GLib.strcmp,
-+                (GLib.CompareDataFunc<ECal.Component>?) Util.calcomponent_compare_func
-+            );
-+            source_events.set (source, events);
-+            /* query client view */
-+            var iso_first = ECal.isodate_from_time_t ((time_t) model.data_range.first_dt.to_unix ());
-+            var iso_last = ECal.isodate_from_time_t ((time_t) model.data_range.last_dt.add_days (1).to_unix ());
-+            var query = @"(occur-in-time-range? (make-time \"$iso_first\") (make-time \"$iso_last\"))";
-+
-+            ECal.Client client;
-+            lock (source_client) {
-+                client = source_client.get (source.dup_uid ());
-+            }
-+
-+            if (client == null) {
-+                return;
-+            }
-+
-+            debug ("Getting client-view for source '%s'", source.dup_display_name ());
-+            client.get_view.begin (query, null, (obj, results) => {
-+                var view = on_client_view_received (results, source, client);
-+                view.objects_added.connect ((objects) => on_objects_added (source, client, objects));
-+                view.objects_removed.connect ((objects) => on_objects_removed (source, client, objects));
-+                view.objects_modified.connect ((objects) => on_objects_modified (source, client, objects));
-+                try {
-+                    view.start ();
-+                } catch (Error e) {
-+                    critical (e.message);
-+                }
-+
-+                source_view.set (source.dup_uid (), view);
-+            });
-+        }
-+
-+        private async void add_source_async (E.Source source) {
-+            debug ("Adding source '%s'", source.dup_display_name ());
-+            try {
-+                var client = (ECal.Client) ECal.Client.connect_sync (source, ECal.ClientSourceType.EVENTS, -1, null);
-+                source_client.insert (source.dup_uid (), client);
-+            } catch (Error e) {
-+                critical (e.message);
-+            }
-+
-+            Idle.add (() => {
-+                load_source (source);
-+
-+                return false;
-+            });
-+        }
-+
-+        private void debug_event (E.Source source, ECal.Component event) {
-+            unowned ICal.Component comp = event.get_icalcomponent ();
-+            debug (@"Event ['$(comp.get_summary())', $(source.dup_display_name()), $(comp.get_uid()))]");
-+        }
-+
-+        private ECal.ClientView on_client_view_received (AsyncResult results, E.Source source, ECal.Client client) {
-+            ECal.ClientView view;
-+            try {
-+                debug ("Received client-view for source '%s'", source.dup_display_name ());
-+                bool status = client.get_view.end (results, out view);
-+                assert (status == true);
-+            } catch (Error e) {
-+                critical ("Error loading client-view from source '%s': %s", source.dup_display_name (), e.message);
-+            }
-+
-+            return view;
-+        }
-+
-+#if E_CAL_2_0
-+        private void on_objects_added (E.Source source, ECal.Client client, SList<ICal.Component> objects) {
-+#else
-+        private void on_objects_added (E.Source source, ECal.Client client, SList<weak ICal.Component> objects) {
-+#endif
-+            debug (@"Received $(objects.length()) added event(s) for source '%s'", source.dup_display_name ());
-+            var events = source_events.get (source);
-+            var added_events = new Gee.ArrayList<ECal.Component> ((Gee.EqualDataFunc<ECal.Component>?) Util.calcomponent_equal_func);
-+            var model = Models.CalendarModel.get_default ();
-+            objects.foreach ((comp) => {
-+                unowned string uid = comp.get_uid ();
-+#if E_CAL_2_0
-+                client.generate_instances_for_object_sync (comp, (time_t) model.data_range.first_dt.to_unix (), (time_t) model.data_range.last_dt.to_unix (), null, (comp, start, end) => {
-+                    var event = new ECal.Component.from_icalcomponent (comp);
-+#else
-+                client.generate_instances_for_object_sync (comp, (time_t) model.data_range.first_dt.to_unix (), (time_t) model.data_range.last_dt.to_unix (), (event, start, end) => {
-+#endif
-+                    debug_event (source, event);
-+                    events.set (uid, event);
-+                    added_events.add (event);
-+                    return true;
-+                });
-+            });
-+        }
-+
-+#if E_CAL_2_0
-+        private void on_objects_modified (E.Source source, ECal.Client client, SList<ICal.Component> objects) {
-+#else
-+        private void on_objects_modified (E.Source source, ECal.Client client, SList<weak ICal.Component> objects) {
-+#endif
-+            debug (@"Received $(objects.length()) modified event(s) for source '%s'", source.dup_display_name ());
-+            var updated_events = new Gee.ArrayList<ECal.Component> ((Gee.EqualDataFunc<ECal.Component>?) Util.calcomponent_equal_func);
-+
-+            objects.foreach ((comp) => {
-+                unowned string uid = comp.get_uid ();
-+                var events = source_events.get (source).get (uid);
-+                updated_events.add_all (events);
-+                foreach (var event in events) {
-+                    debug_event (source, event);
-+                }
-+            });
-+
-+            events_updated (source, updated_events.read_only_view);
-+        }
-+
-+#if E_CAL_2_0
-+        private void on_objects_removed (E.Source source, ECal.Client client, SList<ECal.ComponentId?> cids) {
-+#else
-+        private void on_objects_removed (E.Source source, ECal.Client client, SList<weak ECal.ComponentId?> cids) {
-+#endif
-+            debug (@"Received $(cids.length()) removed event(s) for source '%s'", source.dup_display_name ());
-+            var events = source_events.get (source);
-+            var removed_events = new Gee.ArrayList<ECal.Component> ((Gee.EqualDataFunc<ECal.Component>?) Util.calcomponent_equal_func);
-+
-+            cids.foreach ((cid) => {
-+                if (cid == null) {
-+                    return;
-+                }
-+
-+                var comps = events.get (cid.get_uid ());
-+                foreach (ECal.Component event in comps) {
-+                    removed_events.add (event);
-+                    debug_event (source, event);
-+                }
-+            });
-+
-+            events_removed (source, removed_events.read_only_view);
-+        }
-+    }
-+}
-diff --git a/src/Util/Util.vala b/src/Util/Util.vala
-index c261f4b..b0bdf98 100644
---- a/src/Util/Util.vala
-+++ b/src/Util/Util.vala
-@@ -20,47 +20,6 @@
-  */
- 
- namespace DateTimeIndicator.Util {
--    static bool has_scrolled = false;
--
--    public bool on_scroll_event (Gdk.EventScroll event) {
--        double delta_x;
--        double delta_y;
--        event.get_scroll_deltas (out delta_x, out delta_y);
--
--        double choice = delta_x;
--
--        if (((int)delta_x).abs () < ((int)delta_y).abs ()) {
--            choice = delta_y;
--        }
--
--        /* It's mouse scroll ! */
--        if (choice == 1 || choice == -1) {
--            Models.CalendarModel.get_default ().change_month ((int)choice);
--
--            return true;
--        }
--
--        if (has_scrolled == true) {
--            return true;
--        }
--
--        if (choice > 0.3) {
--            reset_timer.begin ();
--            Models.CalendarModel.get_default ().change_month (1);
--
--            return true;
--        }
--
--        if (choice < -0.3) {
--            reset_timer.begin ();
--            Models.CalendarModel.get_default ().change_month (-1);
--
--            return true;
--        }
--
--        return false;
--    }
--
-     public GLib.DateTime get_start_of_month (owned GLib.DateTime? date = null) {
-         if (date == null) {
-             date = new GLib.DateTime.now_local ();
-@@ -225,12 +184,12 @@ namespace DateTimeIndicator.Util {
-         return a.dup_uid () == b.dup_uid ();
-     }
- 
--    public async void reset_timer () {
--        has_scrolled = true;
--        Timeout.add (500, () => {
--            has_scrolled = false;
--
--            return false;
--        });
--    }
-+    // public async void reset_timer () {
-+    //     has_scrolled = true;
-+    //     Timeout.add (500, () => {
-+    //         has_scrolled = false;
-+    //
-+    //         return false;
-+    //     });
-+    // }
- }
-diff --git a/src/Widgets/CalendarView.vala b/src/Widgets/CalendarView.vala
-index 65cee28..070580f 100644
---- a/src/Widgets/CalendarView.vala
-+++ b/src/Widgets/CalendarView.vala
-@@ -181,5 +181,14 @@ namespace DateTimeIndicator {
- 
-             stack.set_visible_child (big_grid);
-         }
-+
-+        public void add_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
-+            grid.add_event_dots (source, events);
-+        }
-+
-+
-+        public void remove_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
-+            grid.remove_event_dots (source, events);
-+        }
-     }
- }
-diff --git a/src/Widgets/EventsListBox.vala b/src/Widgets/EventsListBox.vala
-index 547e4c5..c25af2e 100644
---- a/src/Widgets/EventsListBox.vala
-+++ b/src/Widgets/EventsListBox.vala
-@@ -1,6 +1,5 @@
- namespace DateTimeIndicator {
-     public class Widgets.EventsListBox : Gtk.ListBox {
--
-         public EventsListBox () {
-             selection_mode = Gtk.SelectionMode.NONE;
- 
-@@ -22,7 +21,7 @@ namespace DateTimeIndicator {
-             set_sort_func (sort_function);
-         }
- 
--        public void update_events (GLib.DateTime? selected_date) {
-+        public void update_events (GLib.DateTime? selected_date, HashTable<E.Source, Gee.TreeMultiMap<string, ECal.Component>> source_events) {
-             foreach (unowned Gtk.Widget widget in get_children ()) {
-                 widget.destroy ();
-             }
-@@ -31,11 +30,9 @@ namespace DateTimeIndicator {
-                 return;
-             }
- 
--            var model = Models.CalendarModel.get_default ();
--
-             var events_on_day = new Gee.TreeMap<string, EventRow> ();
- 
--            model.source_events.@foreach ((source, component_map) => {
-+            source_events.@foreach ((source, component_map) => {
-                 foreach (var comp in component_map.get_values ()) {
-                     if (Util.calcomp_is_on_day (comp, selected_date)) {
-                         unowned ICal.Component ical = comp.get_icalcomponent ();
-diff --git a/src/Widgets/Grid.vala b/src/Widgets/Grid.vala
-index 165d11d..660f212 100644
---- a/src/Widgets/Grid.vala
-+++ b/src/Widgets/Grid.vala
-@@ -261,5 +261,36 @@ namespace DateTimeIndicator {
-             return date.get_year () * 10000 + date.get_month () * 100 + date.get_day_of_month ();
-         }
- 
-+        public void add_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
-+            data.foreach ((entry) => {
-+
-+                foreach (var component in events) {
-+                    if (entry.value.skip_day ()) {
-+                        return true;
-+                    }
-+
-+                    if (Util.calcomp_is_on_day (component, entry.value.date)) {
-+                        entry.value.add_dots (source, component.get_icalcomponent ());
-+                    }
-+                }
-+
-+                entry.value.show_event_grid ();
-+
-+                return true;
-+            });
-+        }
-+
-+        public void remove_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
-+            foreach (var component in events) {
-+                unowned ICal.Component ical = component.get_icalcomponent ();
-+                var event_uid = ical.get_uid ();
-+                data.foreach ((entry) => {
-+                    if (entry.value.exist_event (event_uid)) {
-+                        entry.value.remove_dots (event_uid);
-+                    }
-+                    return true;
-+                });
-+            }
-+        }
-     }
- }
-diff --git a/src/Widgets/GridDay.vala b/src/Widgets/GridDay.vala
-index 8c44443..00f82ea 100644
---- a/src/Widgets/GridDay.vala
-+++ b/src/Widgets/GridDay.vala
-@@ -31,6 +31,8 @@ namespace DateTimeIndicator {
- 
-         public GLib.DateTime date { get; construct set; }
- 
-+        private bool has_scrolled = false;
-+
-         private static Gtk.CssProvider provider;
-         private static Models.CalendarModel model;
- 
-@@ -79,59 +81,100 @@ namespace DateTimeIndicator {
-             // Signals and handlers
-             button_press_event.connect (on_button_press);
-             key_press_event.connect (on_key_press);
--            scroll_event.connect ((event) => {return Util.on_scroll_event (event);});
-+            scroll_event.connect (on_scroll_event);
- 
-             notify["date"].connect (() => {
-                 label.label = date.get_day_of_month ().to_string ();
-             });
- 
-             event_dots = new Gee.HashMap<string, Gtk.Widget> ();
--
--            model.events_added.connect (add_event_dots);
--            model.events_removed.connect (remove_event_dots);
-         }
- 
--        private void add_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
--            foreach (var component in events) {
--                if (event_dots.size >= 3) {
--                    return;
--                }
-+        public bool on_scroll_event (Gdk.EventScroll event) {
-+            double delta_x;
-+            double delta_y;
-+            event.get_scroll_deltas (out delta_x, out delta_y);
-+
-+            double choice = delta_x;
-+
-+            if (((int)delta_x).abs () < ((int)delta_y).abs ()) {
-+                choice = delta_y;
-+            }
-+
-+            /* It's mouse scroll ! */
-+            if (choice == 1 || choice == -1) {
-+                Models.CalendarModel.get_default ().change_month ((int)choice);
- 
--                if (Util.calcomp_is_on_day (component, date)) {
--                    unowned ICal.Component ical = component.get_icalcomponent ();
-+                return true;
-+            }
- 
--                    var event_uid = ical.get_uid ();
--                    if (!event_dots.has_key (event_uid)) {
--                        var event_dot = new Gtk.Image ();
--                        event_dot.gicon = new ThemedIcon ("pager-checked-symbolic");
--                        event_dot.pixel_size = 6;
-+            if (has_scrolled == true) {
-+                return true;
-+            }
- 
--                        unowned Gtk.StyleContext style_context = event_dot.get_style_context ();
--                        style_context.add_class (Granite.STYLE_CLASS_ACCENT);
--                        style_context.add_provider (provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
-+            if (choice > 0.3) {
-+                reset_timer.begin ();
-+                Models.CalendarModel.get_default ().change_month (1);
- 
--                        var source_calendar = (E.SourceCalendar?) source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
--                        Util.set_event_calendar_color (source_calendar, event_dot);
-+                return true;
-+            }
- 
--                        event_dots[event_uid] = event_dot;
-+            if (choice < -0.3) {
-+                reset_timer.begin ();
-+                Models.CalendarModel.get_default ().change_month (-1);
- 
--                        event_grid.add (event_dot);
--                    }
--                }
-+                return true;
-             }
- 
-+            return false;
-+        }
-+
-+        public async void reset_timer () {
-+            has_scrolled = true;
-+            Timeout.add (500, () => {
-+                has_scrolled = false;
-+
-+                return false;
-+            });
-+        }
-+
-+        public bool skip_day () {
-+            return event_dots.size >= 3 ? true : false;
-+        }
-+
-+        public void show_event_grid () {
-             event_grid.show_all ();
-         }
- 
--        private void remove_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
--            foreach (var component in events) {
--                unowned ICal.Component ical = component.get_icalcomponent ();
--                var event_uid = ical.get_uid ();
--                var dot = event_dots[event_uid];
--                if (dot != null) {
--                    dot.destroy ();
--                    event_dots.remove (event_uid);
--                }
-+        public void add_dots (E.Source source, ICal.Component ical) {
-+            var event_uid = ical.get_uid ();
-+            if (!event_dots.has_key (event_uid)) {
-+                var event_dot = new Gtk. Image ();
-+                event_dot.gicon = new ThemedIcon ("pager-checked-symbolic");
-+                event_dot.pixel_size = 6;
-+
-+                unowned Gtk.StyleContext style_context = event_dot.get_style_context ();
-+                style_context.add_class (Granite.STYLE_CLASS_ACCENT);
-+                style_context.add_provider (provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
-+
-+                var source_calendar = (E.SourceCalendar?) source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
-+                Util.set_event_calendar_color (source_calendar, event_dot);
-+
-+                event_dots[event_uid] = event_dot;
-+
-+                event_grid.add (event_dot);
-+            }
-+        }
-+
-+        public bool exist_event (string ical_uid) {
-+            return event_dots.has_key (ical_uid);
-+        }
-+
-+        public void remove_dots (string event_uid) {
-+            var dot = event_dots[event_uid];
-+            if (dot != null) {
-+                dot.destroy ();
-+                event_dots.unset (event_uid);
-             }
-         }
- 
-
-From c99db5e63b9c48aa1d069b97b98b0c07481de27d Mon Sep 17 00:00:00 2001
-From: Dirli <litandrej85@gmail.com>
-Date: Sat, 11 Apr 2020 23:44:14 +0300
-Subject: [PATCH 4/8] rename calendar elements
-
----
- meson.build                                   |  4 +--
- .../{GridDay.vala => CalendarDay.vala}        |  4 +--
- src/Widgets/{Grid.vala => CalendarGrid.vala}  | 26 +++++++--------
- src/Widgets/CalendarView.vala                 | 33 +++++++++----------
- 4 files changed, 33 insertions(+), 34 deletions(-)
- rename src/Widgets/{GridDay.vala => CalendarDay.vala} (98%)
- rename src/Widgets/{Grid.vala => CalendarGrid.vala} (91%)
-
-diff --git a/meson.build b/meson.build
-index e348e3d..dcdd9b2 100644
---- a/meson.build
-+++ b/meson.build
-@@ -44,11 +44,11 @@ shared_module(
-     'src/Util/DateRange.vala',
-     'src/Util/Util.vala',
-     'src/Models/CalendarModel.vala',
-+    'src/Widgets/CalendarDay.vala',
-+    'src/Widgets/CalendarGrid.vala',
-     'src/Widgets/CalendarView.vala',
-     'src/Widgets/EventRow.vala',
-     'src/Widgets/EventsListBox.vala',
--    'src/Widgets/Grid.vala',
--    'src/Widgets/GridDay.vala',
-     'src/Widgets/PanelLabel.vala',
-     'src/Services/EventsManager.vala',
-     'src/Services/TimeManager.vala',
-diff --git a/src/Widgets/GridDay.vala b/src/Widgets/CalendarDay.vala
-similarity index 98%
-rename from src/Widgets/GridDay.vala
-rename to src/Widgets/CalendarDay.vala
-index 00f82ea..a5ca920 100644
---- a/src/Widgets/GridDay.vala
-+++ b/src/Widgets/CalendarDay.vala
-@@ -23,7 +23,7 @@ namespace DateTimeIndicator {
- /**
-  * Represents a single day on the grid.
-  */
--    public class Widgets.GridDay : Gtk.EventBox {
-+    public class Widgets.CalendarDay : Gtk.EventBox {
-         /*
-          * Event emitted when the day is double clicked or the ENTER key is pressed.
-          */
-@@ -41,7 +41,7 @@ namespace DateTimeIndicator {
-         private Gtk.Label label;
-         private bool valid_grab = false;
- 
--        public GridDay (GLib.DateTime date) {
-+        public CalendarDay (GLib.DateTime date) {
-             Object (date: date);
-         }
- 
-diff --git a/src/Widgets/Grid.vala b/src/Widgets/CalendarGrid.vala
-similarity index 91%
-rename from src/Widgets/Grid.vala
-rename to src/Widgets/CalendarGrid.vala
-index 660f212..66e2757 100644
---- a/src/Widgets/Grid.vala
-+++ b/src/Widgets/CalendarGrid.vala
-@@ -24,7 +24,7 @@ namespace DateTimeIndicator {
- /**
-  * Represents the entire date grid as a table.
-  */
--    public class Widgets.Grid : Gtk.Grid {
-+    public class Widgets.CalendarGrid : Gtk.Grid {
-         public Util.DateRange grid_range { get; private set; }
- 
-         /*
-@@ -34,8 +34,8 @@ namespace DateTimeIndicator {
- 
-         public signal void selection_changed (GLib.DateTime new_date);
- 
--        private Gee.HashMap<uint, GridDay> data;
--        private GridDay selected_gridday;
-+        private Gee.HashMap<uint, Widgets.CalendarDay> data;
-+        private Widgets.CalendarDay selected_gridday;
-         private Gtk.Label[] header_labels;
-         private Gtk.Revealer[] week_labels;
- 
-@@ -61,12 +61,12 @@ namespace DateTimeIndicator {
- 
-             Indicator.settings.bind ("show-weeks", week_sep_revealer, "reveal-child", GLib.SettingsBindFlags.DEFAULT);
- 
--            data = new Gee.HashMap<uint, GridDay> ();
-+            data = new Gee.HashMap<uint, Widgets.CalendarDay> ();
-             events |= Gdk.EventMask.SCROLL_MASK;
-             events |= Gdk.EventMask.SMOOTH_SCROLL_MASK;
-         }
- 
--        private void on_day_focus_in (GridDay day) {
-+        private void on_day_focus_in (Widgets.CalendarDay day) {
-             debug ("on_day_focus_in %s", day.date.to_string ());
-             if (selected_gridday != null) {
-                 selected_gridday.set_selected (false);
-@@ -94,7 +94,7 @@ namespace DateTimeIndicator {
-             Gee.List<GLib.DateTime> dates = grid_range.to_list ();
-             for (int i = 0; i < dates.size; i++) {
-                 var date = dates[i];
--                GridDay? day = data[day_hash (date)];
-+                Widgets.CalendarDay? day = data[day_hash (date)];
-                 if (day != null && day.name == "today") {
-                     day.grab_focus_force ();
-                     return;
-@@ -119,7 +119,7 @@ namespace DateTimeIndicator {
- 
-             var new_dates = new_range.to_list ();
- 
--            var data_new = new Gee.HashMap<uint, GridDay> ();
-+            var data_new = new Gee.HashMap<uint, Widgets.CalendarDay> ();
- 
-             /* Assert that a valid number of weeks should be displayed */
-             assert (new_dates.size % 7 == 0);
-@@ -138,7 +138,7 @@ namespace DateTimeIndicator {
- 
-             for (i = 0; i < new_dates.size; i++) {
-                 var new_date = new_dates[i];
--                GridDay day;
-+                Widgets.CalendarDay day;
- 
-                 if (i < old_dates.size) {
-                     /* A widget already exists for this date, just change it */
-@@ -147,7 +147,7 @@ namespace DateTimeIndicator {
-                     day = update_day (data[day_hash (old_date)], new_date, today, month_start);
-                 } else {
-                     /* Still update_day to get the color of etc. right */
--                    day = update_day (new GridDay (new_date), new_date, today, month_start);
-+                    day = update_day (new Widgets.CalendarDay (new_date), new_date, today, month_start);
-                     day.on_event_add.connect ((date) => on_event_add (date));
-                     day.scroll_event.connect ((event) => { scroll_event (event); return false; });
-                     day.focus_in_event.connect ((event) => {
-@@ -182,9 +182,9 @@ namespace DateTimeIndicator {
-         }
- 
-         /**
--         * Updates the given GridDay so that it shows the given date. Changes to its style etc.
-+         * Updates the given CalendarDay so that it shows the given date. Changes to its style etc.
-          */
--        private GridDay update_day (GridDay day, GLib.DateTime new_date, GLib.DateTime today, GLib.DateTime month_start) {
-+        private Widgets.CalendarDay update_day (Widgets.CalendarDay day, GLib.DateTime new_date, GLib.DateTime today, GLib.DateTime month_start) {
-             update_today_style (day, new_date, today);
-             if (new_date.get_month () == month_start.get_month ()) {
-                 day.sensitive_container (true);
-@@ -237,13 +237,13 @@ namespace DateTimeIndicator {
-             int i = 0;
-             for (i = 0; i < dates.size; i++) {
-                 var date = dates[i];
--                GridDay? day = data[day_hash (date)];
-+                Widgets.CalendarDay? day = data[day_hash (date)];
-                 if (day == null) return;
-                 update_today_style (day, date, today);
-             }
-         }
- 
--        private void update_today_style (GridDay day, GLib.DateTime date, GLib.DateTime today) {
-+        private void update_today_style (Widgets.CalendarDay day, GLib.DateTime date, GLib.DateTime today) {
-             if (date.get_day_of_year () == today.get_day_of_year () && date.get_year () == today.get_year ()) {
-                 day.name = "today";
-                 day.get_style_context ().add_class (Granite.STYLE_CLASS_ACCENT);
-diff --git a/src/Widgets/CalendarView.vala b/src/Widgets/CalendarView.vala
-index 070580f..db2139c 100644
---- a/src/Widgets/CalendarView.vala
-+++ b/src/Widgets/CalendarView.vala
-@@ -26,7 +26,7 @@ namespace DateTimeIndicator {
- 
-         public GLib.DateTime? selected_date { get; private set; }
- 
--        private Widgets.Grid grid;
-+        private Widgets.CalendarGrid calendar_grid;
-         private Gtk.Stack stack;
-         private Gtk.Grid big_grid;
- 
-@@ -105,20 +105,20 @@ namespace DateTimeIndicator {
-         }
- 
-         private Gtk.Grid create_big_grid () {
--            grid = new Widgets.Grid ();
--            grid.show_all ();
-+            calendar_grid = new Widgets.CalendarGrid ();
-+            calendar_grid.show_all ();
- 
--            grid.on_event_add.connect ((date) => {
-+            calendar_grid.on_event_add.connect ((date) => {
-                 show_date_in_maya (date);
-                 day_double_click ();
-             });
- 
--            grid.selection_changed.connect ((date) => {
-+            calendar_grid.selection_changed.connect ((date) => {
-                 selected_date = date;
-                 selection_changed (date);
-             });
- 
--            return grid;
-+            return calendar_grid;
-         }
- 
-         public void show_today () {
-@@ -131,7 +131,7 @@ namespace DateTimeIndicator {
-             }
-             sync_with_model ();
- 
--            grid.set_focus_to_today ();
-+            calendar_grid.set_focus_to_today ();
-         }
- 
-         // TODO: As far as maya supports it use the Dbus Activation feature to run the calendar-app.
-@@ -156,23 +156,23 @@ namespace DateTimeIndicator {
-         /* Sets the calendar widgets to the date range of the model */
-         private void sync_with_model () {
-             var model = Models.CalendarModel.get_default ();
--            if (grid.grid_range != null && (model.data_range.equals (grid.grid_range) || grid.grid_range.first_dt.compare (model.data_range.first_dt) == 0)) {
--                grid.update_today ();
-+            if (calendar_grid.grid_range != null && (model.data_range.equals (calendar_grid.grid_range) || calendar_grid.grid_range.first_dt.compare (model.data_range.first_dt) == 0)) {
-+                calendar_grid.update_today ();
-                 return; // nothing else to do
-             }
- 
-             GLib.DateTime previous_first = null;
--            if (grid.grid_range != null)
--                previous_first = grid.grid_range.first_dt;
-+            if (calendar_grid.grid_range != null)
-+                previous_first = calendar_grid.grid_range.first_dt;
- 
-             big_grid = create_big_grid ();
-             stack.add (big_grid);
- 
--            grid.set_range (model.data_range, model.month_start);
--            grid.update_weeks (model.data_range.first_dt, model.num_weeks);
-+            calendar_grid.set_range (model.data_range, model.month_start);
-+            calendar_grid.update_weeks (model.data_range.first_dt, model.num_weeks);
- 
-             if (previous_first != null) {
--                if (previous_first.compare (grid.grid_range.first_dt) == -1) {
-+                if (previous_first.compare (calendar_grid.grid_range.first_dt) == -1) {
-                     stack.transition_type = Gtk.StackTransitionType.SLIDE_LEFT;
-                 } else {
-                     stack.transition_type = Gtk.StackTransitionType.SLIDE_RIGHT;
-@@ -183,12 +183,11 @@ namespace DateTimeIndicator {
-         }
- 
-         public void add_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
--            grid.add_event_dots (source, events);
-+            calendar_grid.add_event_dots (source, events);
-         }
- 
--
-         public void remove_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
--            grid.remove_event_dots (source, events);
-+            calendar_grid.remove_event_dots (source, events);
-         }
-     }
- }
-
-From 6b1b15305a9c90ff8b7e7244727a225984d34a14 Mon Sep 17 00:00:00 2001
-From: Dirli <litandrej85@gmail.com>
-Date: Sun, 12 Apr 2020 03:10:24 +0300
-Subject: [PATCH 5/8] evolution data server now optional
-
----
- meson.build                   | 55 ++++++++++++++---------
- meson_options.txt             |  1 +
- src/Indicator.vala            | 43 ++++++++++--------
- src/Util/Util.vala            | 85 ++++++++++++++++-------------------
- src/Widgets/CalendarDay.vala  |  2 +
- src/Widgets/CalendarGrid.vala |  2 +
- src/Widgets/CalendarView.vala |  2 +
- 7 files changed, 104 insertions(+), 86 deletions(-)
- create mode 100644 meson_options.txt
-
-diff --git a/meson.build b/meson.build
-index dcdd9b2..5fee9ab 100644
---- a/meson.build
-+++ b/meson.build
-@@ -24,18 +24,40 @@ gresource = gnome.compile_resources(
- wingpanel_dep = dependency('wingpanel-2.0')
- wingpanel_indicatorsdir = wingpanel_dep.get_pkgconfig_variable('indicatorsdir', define_variable: ['libdir', libdir])
- 
-+deps = [
-+    dependency('glib-2.0'),
-+    dependency('gobject-2.0'),
-+    dependency('granite'),
-+    dependency('gtk+-3.0'),
-+    wingpanel_dep,
-+    meson.get_compiler('vala').find_library('posix')
-+]
- 
--libecal_dep = dependency('libecal-2.0', required: false)
--if libecal_dep.found()
--    libical_dep = dependency('libical-glib')
--    add_project_arguments('--define=E_CAL_2_0', language: 'vala')
--    add_project_arguments('-DLIBICAL_GLIB_UNSTABLE_API=1', language: 'c')
--else
--    libecal_dep = dependency('libecal-1.2', version: '>=3.8.0')
--    libical_dep = dependency('libical')
--    add_project_arguments('--vapidir', join_paths(meson.current_source_dir(), 'vapi'), language: 'vala')
-+opt_files = []
-+
-+if get_option('evo')
-+    libecal_dep = dependency ('libecal-2.0', required: false)
-+    if libecal_dep.found()
-+        deps += dependency('libical-glib')
-+        deps += libecal_dep
-+        add_project_arguments('--define=E_CAL_2_0', language: 'vala')
-+        add_project_arguments('-DLIBICAL_GLIB_UNSTABLE_API=1', language: 'c')
-+    else
-+        deps += dependency('libecal-1.2', version: '>=3.8.0')
-+        deps += dependency('libical')
-+        add_project_arguments('--vapidir', join_paths(meson.current_source_dir(), 'vapi'), language: 'vala')
-+    endif
-+
-+    deps += dependency ('libedataserver-1.2')
-+    opt_files += files (
-+        'src/Widgets/EventRow.vala',
-+        'src/Widgets/EventsListBox.vala',
-+        'src/Services/EventsManager.vala',
-+    )
-+    add_project_arguments('--define=USE_EVO', language: 'vala')
- endif
- 
-+
- shared_module(
-     meson.project_name(),
-     gresource,
-@@ -47,21 +69,10 @@ shared_module(
-     'src/Widgets/CalendarDay.vala',
-     'src/Widgets/CalendarGrid.vala',
-     'src/Widgets/CalendarView.vala',
--    'src/Widgets/EventRow.vala',
--    'src/Widgets/EventsListBox.vala',
-     'src/Widgets/PanelLabel.vala',
--    'src/Services/EventsManager.vala',
-     'src/Services/TimeManager.vala',
--    dependencies: [
--        dependency('glib-2.0'),
--        dependency('gobject-2.0'),
--        dependency('granite'),
--        dependency('gtk+-3.0'),
--        libecal_dep,
--        dependency('libedataserver-1.2'),
--        libical_dep,
--        wingpanel_dep,
--    ],
-+    opt_files,
-+    dependencies: deps,
-     install: true,
-     install_dir : wingpanel_indicatorsdir,
- )
-diff --git a/meson_options.txt b/meson_options.txt
-new file mode 100644
-index 0000000..a1c9f0e
---- /dev/null
-+++ b/meson_options.txt
-@@ -0,0 +1 @@
-+option ('evo', type : 'boolean', value : true)
-diff --git a/src/Indicator.vala b/src/Indicator.vala
-index bf4358f..31c7af5 100644
---- a/src/Indicator.vala
-+++ b/src/Indicator.vala
-@@ -23,9 +23,11 @@ namespace DateTimeIndicator {
- 
-         private Widgets.PanelLabel panel_label;
-         private Widgets.CalendarView calendar;
--        private Widgets.EventsListBox event_listbox;
- 
-+#if USE_EVO
-+        private Widgets.EventsListBox event_listbox;
-         private Services.EventsManager event_manager;
-+#endif
- 
-         private Gtk.Grid main_grid;
-         private uint update_events_idle_source = 0;
-@@ -60,7 +62,20 @@ namespace DateTimeIndicator {
-             if (main_grid == null) {
-                 calendar = new Widgets.CalendarView ();
-                 calendar.margin_bottom = 6;
-+                calendar.day_double_click.connect (() => {
-+                    close ();
-+                });
-+
-+                var settings_button = new Gtk.ModelButton ();
-+                settings_button.text = _("Date & Time Settings…");
- 
-+                main_grid = new Gtk.Grid ();
-+                main_grid.margin_top = 12;
-+                main_grid.attach (calendar,                           0, 0);
-+                main_grid.attach (new Wingpanel.Widgets.Separator (), 0, 1);
-+                main_grid.attach (settings_button,                    0, 2);
-+
-+#if USE_EVO
-                 event_manager = new Services.EventsManager ();
-                 event_manager.events_updated.connect (update_events_model);
-                 event_manager.events_added.connect ((source, events) => {
-@@ -73,20 +88,16 @@ namespace DateTimeIndicator {
-                 });
- 
-                 event_listbox = new Widgets.EventsListBox ();
-+                event_listbox.row_activated.connect ((row) => {
-+                    calendar.show_date_in_maya (((EventRow) row).date);
-+                    close ();
-+                });
- 
-                 var scrolled_window = new Gtk.ScrolledWindow (null, null);
-                 scrolled_window.hscrollbar_policy = Gtk.PolicyType.NEVER;
-                 scrolled_window.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC;
-                 scrolled_window.add (event_listbox);
- 
--                var settings_button = new Gtk.ModelButton ();
--                settings_button.text = _("Date & Time Settings…");
--
--                main_grid = new Gtk.Grid ();
--                main_grid.margin_top = 12;
--                main_grid.attach (calendar,                                     0, 0);
--                main_grid.attach (new Wingpanel.Widgets.Separator (),           0, 1);
--                main_grid.attach (settings_button,                              0, 2);
-                 main_grid.attach (new Gtk.Separator (Gtk.Orientation.VERTICAL), 1, 0, 1, 3);
-                 main_grid.attach (scrolled_window,                              2, 0, 1, 3);
- 
-@@ -94,23 +105,17 @@ namespace DateTimeIndicator {
-                 size_group.add_widget (calendar);
-                 size_group.add_widget (event_listbox);
- 
--                calendar.day_double_click.connect (() => {
--                    close ();
--                });
--
-                 calendar.selection_changed.connect ((date) => {
-                     idle_update_events ();
-                 });
--
--                event_listbox.row_activated.connect ((row) => {
--                    calendar.show_date_in_maya (((EventRow) row).date);
--                    close ();
--                });
-+#endif
- 
-                 var model = Models.CalendarModel.get_default ();
-                 model.notify["month-start"].connect (() => {
-                     model.compute_ranges ();
-+#if USE_EVO
-                     event_manager.load_all_sources ();
-+#endif
-                 });
- 
-                 settings_button.clicked.connect (() => {
-@@ -125,6 +130,7 @@ namespace DateTimeIndicator {
-             return main_grid;
-         }
- 
-+#if USE_EVO
-         private void update_events_model (E.Source source, Gee.Collection<ECal.Component> events) {
-             if (opened_widget) {
-                 idle_update_events ();
-@@ -143,6 +149,7 @@ namespace DateTimeIndicator {
-                 return GLib.Source.REMOVE;
-             });
-         }
-+#endif
- 
-         public override void opened () {
-             calendar.show_today ();
-diff --git a/src/Util/Util.vala b/src/Util/Util.vala
-index b0bdf98..26b343a 100644
---- a/src/Util/Util.vala
-+++ b/src/Util/Util.vala
-@@ -32,38 +32,6 @@ namespace DateTimeIndicator.Util {
-         return datetime.add_full (0, 0, 0, -datetime.get_hour (), -datetime.get_minute (), -datetime.get_second ());
-     }
- 
--    /**
--     * Converts the given ICal.Time to a DateTime.
--     */
--    public TimeZone timezone_from_ical (ICal.Time date) {
--        int is_daylight;
--        var interval = date.get_timezone ().get_utc_offset (null, out is_daylight);
--        bool is_positive = interval >= 0;
--        interval = interval.abs ();
--        var hours = (interval / 3600);
--        var minutes = (interval % 3600) / 60;
--        var hour_string = "%s%02d:%02d".printf (is_positive ? "+" : "-", hours, minutes);
--
--        return new TimeZone (hour_string);
--    }
--
--    /**
--     * Converts the given ICal.Time to a DateTime.
--     * XXX : Track next versions of evolution in order to convert ICal.Timezone to GLib.TimeZone with a dedicated function…
--     */
--    public GLib.DateTime ical_to_date_time (ICal.Time date) {
--#if E_CAL_2_0
--        int year, month, day, hour, minute, second;
--        date.get_date (out year, out month, out day);
--        date.get_time (out hour, out minute, out second);
--        return new GLib.DateTime (timezone_from_ical (date), year, month,
--            day, hour, minute, second);
--#else
--        return new GLib.DateTime (timezone_from_ical (date), date.year, date.month,
--            date.day, date.hour, date.minute, date.second);
--#endif
--    }
--
-     /**
-      * Say if an event lasts all day.
-      */
-@@ -78,6 +46,7 @@ namespace DateTimeIndicator.Util {
-         }
-     }
- 
-+#if USE_EVO
-     private Gee.HashMap<string, Gtk.CssProvider>? providers;
-     public void set_event_calendar_color (E.SourceCalendar cal, Gtk.Widget widget) {
-         if (providers == null) {
-@@ -104,6 +73,38 @@ namespace DateTimeIndicator.Util {
-         style_context.add_provider (providers[color], Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
-     }
- 
-+    /**
-+     * Converts the given ICal.Time to a DateTime.
-+     */
-+    public TimeZone timezone_from_ical (ICal.Time date) {
-+        int is_daylight;
-+        var interval = date.get_timezone ().get_utc_offset (null, out is_daylight);
-+        bool is_positive = interval >= 0;
-+        interval = interval.abs ();
-+        var hours = (interval / 3600);
-+        var minutes = (interval % 3600) / 60;
-+        var hour_string = "%s%02d:%02d".printf (is_positive ? "+" : "-", hours, minutes);
-+
-+        return new TimeZone (hour_string);
-+    }
-+
-+    /**
-+     * Converts the given ICal.Time to a DateTime.
-+     * XXX : Track next versions of evolution in order to convert ICal.Timezone to GLib.TimeZone with a dedicated function…
-+     */
-+    public GLib.DateTime ical_to_date_time (ICal.Time date) {
-+#if E_CAL_2_0
-+        int year, month, day, hour, minute, second;
-+        date.get_date (out year, out month, out day);
-+        date.get_time (out hour, out minute, out second);
-+        return new GLib.DateTime (timezone_from_ical (date), year, month,
-+            day, hour, minute, second);
-+#else
-+        return new GLib.DateTime (timezone_from_ical (date), date.year, date.month,
-+            date.day, date.hour, date.minute, date.second);
-+#endif
-+    }
-+
-     /*
-      * Gee Utility Functions
-      */
-@@ -113,6 +114,11 @@ namespace DateTimeIndicator.Util {
-         return key.dup_uid (). hash ();
-     }
- 
-+    /* Returns true if 'a' and 'b' are the same E.Source */
-+    public bool source_equal_func (E.Source a, E.Source b) {
-+        return a.dup_uid () == b.dup_uid ();
-+    }
-+
-     /* Returns true if 'a' and 'b' are the same ECal.Component */
-     public bool calcomponent_equal_func (ECal.Component a, ECal.Component b) {
-         return a.get_id ().equal (b.get_id ());
-@@ -178,18 +184,5 @@ namespace DateTimeIndicator.Util {
- 
-         return false;
-     }
--
--    /* Returns true if 'a' and 'b' are the same E.Source */
--    public bool source_equal_func (E.Source a, E.Source b) {
--        return a.dup_uid () == b.dup_uid ();
--    }
--
--    // public async void reset_timer () {
--    //     has_scrolled = true;
--    //     Timeout.add (500, () => {
--    //         has_scrolled = false;
--    //
--    //         return false;
--    //     });
--    // }
-+#endif
- }
-diff --git a/src/Widgets/CalendarDay.vala b/src/Widgets/CalendarDay.vala
-index a5ca920..f9c742a 100644
---- a/src/Widgets/CalendarDay.vala
-+++ b/src/Widgets/CalendarDay.vala
-@@ -146,6 +146,7 @@ namespace DateTimeIndicator {
-             event_grid.show_all ();
-         }
- 
-+#if USE_EVO
-         public void add_dots (E.Source source, ICal.Component ical) {
-             var event_uid = ical.get_uid ();
-             if (!event_dots.has_key (event_uid)) {
-@@ -177,6 +178,7 @@ namespace DateTimeIndicator {
-                 event_dots.unset (event_uid);
-             }
-         }
-+#endif
- 
-         public void set_selected (bool selected) {
-             if (selected) {
-diff --git a/src/Widgets/CalendarGrid.vala b/src/Widgets/CalendarGrid.vala
-index 66e2757..1d1e06c 100644
---- a/src/Widgets/CalendarGrid.vala
-+++ b/src/Widgets/CalendarGrid.vala
-@@ -261,6 +261,7 @@ namespace DateTimeIndicator {
-             return date.get_year () * 10000 + date.get_month () * 100 + date.get_day_of_month ();
-         }
- 
-+#if USE_EVO
-         public void add_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
-             data.foreach ((entry) => {
- 
-@@ -292,5 +293,6 @@ namespace DateTimeIndicator {
-                 });
-             }
-         }
-+#endif
-     }
- }
-diff --git a/src/Widgets/CalendarView.vala b/src/Widgets/CalendarView.vala
-index db2139c..77c233c 100644
---- a/src/Widgets/CalendarView.vala
-+++ b/src/Widgets/CalendarView.vala
-@@ -182,6 +182,7 @@ namespace DateTimeIndicator {
-             stack.set_visible_child (big_grid);
-         }
- 
-+#if USE_EVO
-         public void add_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
-             calendar_grid.add_event_dots (source, events);
-         }
-@@ -189,5 +190,6 @@ namespace DateTimeIndicator {
-         public void remove_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
-             calendar_grid.remove_event_dots (source, events);
-         }
-+#endif
-     }
- }
-
-From 16715f5114c0597d6961880bf877f04414400334 Mon Sep 17 00:00:00 2001
-From: Dirli <litandrej85@gmail.com>
-Date: Mon, 13 Apr 2020 22:21:07 +0300
-Subject: [PATCH 6/8] returned dots in the calendar
-
----
- src/Indicator.vala              |  6 ++--
- src/Services/EventsManager.vala | 28 +++++----------
- src/Widgets/CalendarDay.vala    | 62 ++++++++++++++++++---------------
- src/Widgets/CalendarGrid.vala   | 29 ++++++---------
- 4 files changed, 57 insertions(+), 68 deletions(-)
-
-diff --git a/src/Indicator.vala b/src/Indicator.vala
-index 31c7af5..c7550aa 100644
---- a/src/Indicator.vala
-+++ b/src/Indicator.vala
-@@ -105,8 +105,10 @@ namespace DateTimeIndicator {
-                 size_group.add_widget (calendar);
-                 size_group.add_widget (event_listbox);
- 
--                calendar.selection_changed.connect ((date) => {
--                    idle_update_events ();
-+                event_manager.open.begin ((obj, res) => {
-+                    calendar.selection_changed.connect ((date) => {
-+                        idle_update_events ();
-+                    });
-                 });
- #endif
- 
-diff --git a/src/Services/EventsManager.vala b/src/Services/EventsManager.vala
-index d939777..ad0397d 100644
---- a/src/Services/EventsManager.vala
-+++ b/src/Services/EventsManager.vala
-@@ -10,33 +10,25 @@ namespace DateTimeIndicator {
-         private HashTable<string, ECal.Client> source_client;
-         private HashTable<string, ECal.ClientView> source_view;
- 
--        public EventsManager () {
--
--        }
--
-         construct {
-             source_client = new HashTable<string, ECal.Client> (str_hash, str_equal);
-             source_events = new HashTable<E.Source, Gee.TreeMultiMap<string, ECal.Component> > (Util.source_hash_func, Util.source_equal_func);
-             source_view = new HashTable<string, ECal.ClientView> (str_hash, str_equal);
--
--            open.begin ();
-         }
- 
--        private async void open () {
-+        public async void open () {
-             try {
-                 registry = yield new E.SourceRegistry (null);
-                 registry.source_removed.connect (remove_source);
--                registry.source_added.connect ((source) => add_source_async.begin (source));
-+                registry.source_added.connect (add_source);
- 
-                 // Add sources
-                 registry.list_sources (E.SOURCE_EXTENSION_CALENDAR).foreach ((source) => {
--                    E.SourceCalendar cal = (E.SourceCalendar)source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
-+                    E.SourceCalendar cal = (E.SourceCalendar) source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
-                     if (cal.selected == true && source.enabled == true) {
--                        add_source_async.begin (source);
-+                        add_source (source);
-                     }
-                 });
--
--                load_all_sources ();
-             } catch (GLib.Error error) {
-                 critical (error.message);
-             }
-@@ -46,7 +38,7 @@ namespace DateTimeIndicator {
-             lock (source_client) {
-                 foreach (var id in source_client.get_keys ()) {
-                     var source = registry.ref_source (id);
--                    E.SourceCalendar cal = (E.SourceCalendar)source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
-+                    E.SourceCalendar cal = (E.SourceCalendar) source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
- 
-                     if (cal.selected == true && source.enabled == true) {
-                         load_source (source);
-@@ -120,7 +112,7 @@ namespace DateTimeIndicator {
-             });
-         }
- 
--        private async void add_source_async (E.Source source) {
-+        private void add_source (E.Source source) {
-             debug ("Adding source '%s'", source.dup_display_name ());
-             try {
-                 var client = (ECal.Client) ECal.Client.connect_sync (source, ECal.ClientSourceType.EVENTS, -1, null);
-@@ -129,11 +121,7 @@ namespace DateTimeIndicator {
-                 critical (e.message);
-             }
- 
--            Idle.add (() => {
--                load_source (source);
--
--                return false;
--            });
-+            load_source (source);
-         }
- 
-         private void debug_event (E.Source source, ECal.Component event) {
-@@ -177,6 +165,8 @@ namespace DateTimeIndicator {
-                     return true;
-                 });
-             });
-+
-+            events_added (source, added_events.read_only_view);
-         }
- 
- #if E_CAL_2_0
-diff --git a/src/Widgets/CalendarDay.vala b/src/Widgets/CalendarDay.vala
-index f9c742a..a2c4922 100644
---- a/src/Widgets/CalendarDay.vala
-+++ b/src/Widgets/CalendarDay.vala
-@@ -36,7 +36,8 @@ namespace DateTimeIndicator {
-         private static Gtk.CssProvider provider;
-         private static Models.CalendarModel model;
- 
--        private Gee.HashMap<string, Gtk.Widget> event_dots;
-+        // private Gee.HashMap<string, Gtk.Widget> event_dots;
-+        private Gee.ArrayList<string> event_dots;
-         private Gtk.Grid event_grid;
-         private Gtk.Label label;
-         private bool valid_grab = false;
-@@ -87,7 +88,8 @@ namespace DateTimeIndicator {
-                 label.label = date.get_day_of_month ().to_string ();
-             });
- 
--            event_dots = new Gee.HashMap<string, Gtk.Widget> ();
-+            // event_dots = new Gee.HashMap<string, Gtk.Widget> ();
-+            event_dots = new Gee.ArrayList<string> ();
-         }
- 
-         public bool on_scroll_event (Gdk.EventScroll event) {
-@@ -138,44 +140,46 @@ namespace DateTimeIndicator {
-             });
-         }
- 
--        public bool skip_day () {
--            return event_dots.size >= 3 ? true : false;
--        }
--
--        public void show_event_grid () {
--            event_grid.show_all ();
--        }
--
- #if USE_EVO
-         public void add_dots (E.Source source, ICal.Component ical) {
-             var event_uid = ical.get_uid ();
--            if (!event_dots.has_key (event_uid)) {
--                var event_dot = new Gtk. Image ();
--                event_dot.gicon = new ThemedIcon ("pager-checked-symbolic");
--                event_dot.pixel_size = 6;
-+            if (event_dots.contains (event_uid)) {
-+                return;
-+            }
- 
--                unowned Gtk.StyleContext style_context = event_dot.get_style_context ();
--                style_context.add_class (Granite.STYLE_CLASS_ACCENT);
--                style_context.add_provider (provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
-+            event_dots.add (event_uid);
-+            if (event_dots.size > 3) {
-+                return;
-+            }
- 
--                var source_calendar = (E.SourceCalendar?) source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
--                Util.set_event_calendar_color (source_calendar, event_dot);
-+            var event_dot = new Gtk.Image ();
-+            event_dot.gicon = new ThemedIcon ("pager-checked-symbolic");
-+            event_dot.pixel_size = 6;
- 
--                event_dots[event_uid] = event_dot;
-+            unowned Gtk.StyleContext style_context = event_dot.get_style_context ();
-+            style_context.add_class (Granite.STYLE_CLASS_ACCENT);
-+            style_context.add_provider (provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
- 
--                event_grid.add (event_dot);
--            }
--        }
-+            var source_calendar = (E.SourceCalendar?) source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
-+            Util.set_event_calendar_color (source_calendar, event_dot);
- 
--        public bool exist_event (string ical_uid) {
--            return event_dots.has_key (ical_uid);
-+            event_grid.add (event_dot);
-+            event_dot.show ();
-         }
- 
-         public void remove_dots (string event_uid) {
--            var dot = event_dots[event_uid];
--            if (dot != null) {
--                dot.destroy ();
--                event_dots.unset (event_uid);
-+            if (event_dots.contains (event_uid)) {
-+                return;
-+            }
-+
-+            event_dots.remove (event_uid);
-+            if (event_dots.size >= 3) {
-+                return;
-+            }
-+
-+            var w = event_grid.get_children ();
-+            if (w.length () > 0) {
-+                w.nth_data (0).destroy ();
-             }
-         }
- #endif
-diff --git a/src/Widgets/CalendarGrid.vala b/src/Widgets/CalendarGrid.vala
-index 1d1e06c..c544404 100644
---- a/src/Widgets/CalendarGrid.vala
-+++ b/src/Widgets/CalendarGrid.vala
-@@ -263,22 +263,16 @@ namespace DateTimeIndicator {
- 
- #if USE_EVO
-         public void add_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
--            data.foreach ((entry) => {
--
--                foreach (var component in events) {
--                    if (entry.value.skip_day ()) {
--                        return true;
--                    }
--
--                    if (Util.calcomp_is_on_day (component, entry.value.date)) {
--                        entry.value.add_dots (source, component.get_icalcomponent ());
--                    }
-+            foreach (var component in events) {
-+                unowned ICal.Component? icomp = component.get_icalcomponent ();
-+                ICal.Time? start_time = icomp.get_dtstart ();
-+                time_t start_unix = start_time.as_timet ();
-+                var t = new DateTime.from_unix_utc (start_unix);
-+                var d_hash = day_hash (t);
-+                if (data.has_key (d_hash)) {
-+                    data[d_hash].add_dots (source, component.get_icalcomponent ());
-                 }
--
--                entry.value.show_event_grid ();
--
--                return true;
--            });
-+            }
-         }
- 
-         public void remove_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
-@@ -286,9 +280,8 @@ namespace DateTimeIndicator {
-                 unowned ICal.Component ical = component.get_icalcomponent ();
-                 var event_uid = ical.get_uid ();
-                 data.foreach ((entry) => {
--                    if (entry.value.exist_event (event_uid)) {
--                        entry.value.remove_dots (event_uid);
--                    }
-+                    entry.value.remove_dots (event_uid);
-+
-                     return true;
-                 });
-             }
-
-From 149da28659883b01ceb0773b35c018d31aa1d912 Mon Sep 17 00:00:00 2001
-From: Dirli <litandrej85@gmail.com>
-Date: Tue, 14 Apr 2020 00:16:01 +0300
-Subject: [PATCH 7/8] issue #55
-
----
- src/Services/EventsManager.vala |  2 ++
- src/Widgets/CalendarDay.vala    |  2 +-
- src/Widgets/CalendarGrid.vala   | 11 +++++++----
- 3 files changed, 10 insertions(+), 5 deletions(-)
-
-diff --git a/src/Services/EventsManager.vala b/src/Services/EventsManager.vala
-index ad0397d..959762f 100644
---- a/src/Services/EventsManager.vala
-+++ b/src/Services/EventsManager.vala
-@@ -208,6 +208,8 @@ namespace DateTimeIndicator {
-                     removed_events.add (event);
-                     debug_event (source, event);
-                 }
-+
-+                events.remove_all (cid.get_uid ());
-             });
- 
-             events_removed (source, removed_events.read_only_view);
-diff --git a/src/Widgets/CalendarDay.vala b/src/Widgets/CalendarDay.vala
-index a2c4922..10d088c 100644
---- a/src/Widgets/CalendarDay.vala
-+++ b/src/Widgets/CalendarDay.vala
-@@ -168,7 +168,7 @@ namespace DateTimeIndicator {
-         }
- 
-         public void remove_dots (string event_uid) {
--            if (event_dots.contains (event_uid)) {
-+            if (!event_dots.contains (event_uid)) {
-                 return;
-             }
- 
-diff --git a/src/Widgets/CalendarGrid.vala b/src/Widgets/CalendarGrid.vala
-index c544404..6e6cbdb 100644
---- a/src/Widgets/CalendarGrid.vala
-+++ b/src/Widgets/CalendarGrid.vala
-@@ -279,11 +279,14 @@ namespace DateTimeIndicator {
-             foreach (var component in events) {
-                 unowned ICal.Component ical = component.get_icalcomponent ();
-                 var event_uid = ical.get_uid ();
--                data.foreach ((entry) => {
--                    entry.value.remove_dots (event_uid);
- 
--                    return true;
--                });
-+                ICal.Time? start_time = ical.get_dtstart ();
-+                time_t start_unix = start_time.as_timet ();
-+                var t = new DateTime.from_unix_utc (start_unix);
-+                var d_hash = day_hash (t);
-+                if (data.has_key (d_hash)) {
-+                    data[d_hash].remove_dots (event_uid);
-+                }
-             }
-         }
- #endif
-
-From a3910e2b8242b8c4837cc764da7f268a02d05d6e Mon Sep 17 00:00:00 2001
-From: Dirli <litandrej85@gmail.com>
-Date: Fri, 17 Apr 2020 00:52:53 +0300
-Subject: [PATCH 8/8] issue #127
-
----
- src/Indicator.vala              |  1 +
- src/Models/CalendarModel.vala   | 17 ++++++---
- src/Services/EventsManager.vala | 17 +++++++++
- src/Widgets/CalendarDay.vala    |  3 +-
- src/Widgets/CalendarGrid.vala   | 66 ++++++++++++++++++++++-----------
- src/Widgets/CalendarView.vala   | 17 ++++-----
- src/Widgets/EventsListBox.vala  |  6 ++-
- 7 files changed, 87 insertions(+), 40 deletions(-)
-
-diff --git a/src/Indicator.vala b/src/Indicator.vala
-index c7550aa..63614e0 100644
---- a/src/Indicator.vala
-+++ b/src/Indicator.vala
-@@ -116,6 +116,7 @@ namespace DateTimeIndicator {
-                 model.notify["month-start"].connect (() => {
-                     model.compute_ranges ();
- #if USE_EVO
-+                    event_listbox.clear_list ();
-                     event_manager.load_all_sources ();
- #endif
-                 });
-diff --git a/src/Models/CalendarModel.vala b/src/Models/CalendarModel.vala
-index d60a9ac..48b6e78 100644
---- a/src/Models/CalendarModel.vala
-+++ b/src/Models/CalendarModel.vala
-@@ -57,12 +57,17 @@ namespace DateTimeIndicator {
-             compute_ranges ();
-         }
- 
--        public void change_month (int relative) {
--            month_start = month_start.add_months (relative);
--        }
--
--        public void change_year (int relative) {
--            month_start = month_start.add_years (relative);
-+        public void change_month (int m_relative, int y_relative = 0) {
-+            if (y_relative == 0) {
-+                month_start = month_start.add_months (m_relative);
-+            } else {
-+                if (m_relative == 0) {
-+                    month_start = month_start.add_years (y_relative);
-+                } else {
-+                    GLib.DateTime tmp_date = month_start.add_months (m_relative);
-+                    month_start = tmp_date.add_years (y_relative);
-+                }
-+            }
-         }
- 
-         /* --- Helper Methods ---// */
-diff --git a/src/Services/EventsManager.vala b/src/Services/EventsManager.vala
-index 959762f..6ece557 100644
---- a/src/Services/EventsManager.vala
-+++ b/src/Services/EventsManager.vala
-@@ -1,3 +1,20 @@
-+/*
-+ * Copyright (c) 2011-2020 elementary, Inc. (https://elementary.io)
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 3 of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+ * General Public License for more details.
-+ *
-+ *  You should have received a copy of the GNU General Public License
-+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+ */
-+
- namespace DateTimeIndicator {
-     public class Services.EventsManager : GLib.Object {
-         public signal void events_added (E.Source source, Gee.Collection<ECal.Component> events);
-diff --git a/src/Widgets/CalendarDay.vala b/src/Widgets/CalendarDay.vala
-index 10d088c..735fdc1 100644
---- a/src/Widgets/CalendarDay.vala
-+++ b/src/Widgets/CalendarDay.vala
-@@ -36,7 +36,6 @@ namespace DateTimeIndicator {
-         private static Gtk.CssProvider provider;
-         private static Models.CalendarModel model;
- 
--        // private Gee.HashMap<string, Gtk.Widget> event_dots;
-         private Gee.ArrayList<string> event_dots;
-         private Gtk.Grid event_grid;
-         private Gtk.Label label;
-@@ -105,7 +104,7 @@ namespace DateTimeIndicator {
- 
-             /* It's mouse scroll ! */
-             if (choice == 1 || choice == -1) {
--                Models.CalendarModel.get_default ().change_month ((int)choice);
-+                Models.CalendarModel.get_default ().change_month ((int) choice);
- 
-                 return true;
-             }
-diff --git a/src/Widgets/CalendarGrid.vala b/src/Widgets/CalendarGrid.vala
-index 6e6cbdb..ef8edb6 100644
---- a/src/Widgets/CalendarGrid.vala
-+++ b/src/Widgets/CalendarGrid.vala
-@@ -32,7 +32,7 @@ namespace DateTimeIndicator {
-          */
-         public signal void on_event_add (GLib.DateTime date);
- 
--        public signal void selection_changed (GLib.DateTime new_date);
-+        public signal void selection_changed (GLib.DateTime new_date, bool up);
- 
-         private Gee.HashMap<uint, Widgets.CalendarDay> data;
-         private Widgets.CalendarDay selected_gridday;
-@@ -66,25 +66,32 @@ namespace DateTimeIndicator {
-             events |= Gdk.EventMask.SMOOTH_SCROLL_MASK;
-         }
- 
--        private void on_day_focus_in (Widgets.CalendarDay day) {
--            debug ("on_day_focus_in %s", day.date.to_string ());
-+        private bool on_day_focus_in (Gdk.EventFocus event) {
-+            var day = get_focus_child ();
-+            if (day == null) {
-+                return false;
-+            }
-+
-             if (selected_gridday != null) {
-                 selected_gridday.set_selected (false);
-             }
- 
--            var selected_date = day.date;
--            selected_gridday = day;
--            day.set_selected (true);
-+            var selected_date = (day as Widgets.CalendarDay).date;
-+            selected_gridday = day as Widgets.CalendarDay;
-+            (day as Widgets.CalendarDay).set_selected (true);
-             day.set_state_flags (Gtk.StateFlags.FOCUSED, false);
--            selection_changed (selected_date);
-             var calmodel = Models.CalendarModel.get_default ();
-             var date_month = selected_date.get_month () - calmodel.month_start.get_month ();
-             var date_year = selected_date.get_year () - calmodel.month_start.get_year ();
- 
-             if (date_month != 0 || date_year != 0) {
--                calmodel.change_month (date_month);
--                calmodel.change_year (date_year);
-+                selection_changed (selected_date, false);
-+                calmodel.change_month (date_month, date_year);
-+            } else {
-+                selection_changed (selected_date, true);
-             }
-+
-+            return false;
-         }
- 
-         public void set_focus_to_today () {
-@@ -106,7 +113,7 @@ namespace DateTimeIndicator {
-          * Sets the given range to be displayed in the grid. Note that the number of days
-          * must remain the same.
-          */
--        public void set_range (Util.DateRange new_range, GLib.DateTime month_start) {
-+        public void set_range (Util.DateRange new_range, GLib.DateTime month_start, GLib.DateTime? selected_date) {
-             var today = new GLib.DateTime.now_local ();
- 
-             Gee.List<GLib.DateTime> old_dates;
-@@ -138,28 +145,46 @@ namespace DateTimeIndicator {
- 
-             for (i = 0; i < new_dates.size; i++) {
-                 var new_date = new_dates[i];
--                Widgets.CalendarDay day;
-+                Widgets.CalendarDay? day = null;
- 
-                 if (i < old_dates.size) {
-                     /* A widget already exists for this date, just change it */
- 
-                     var old_date = old_dates[i];
--                    day = update_day (data[day_hash (old_date)], new_date, today, month_start);
--                } else {
-+                    var d_hash = day_hash (old_date);
-+                    if (data.has_key (d_hash)) {
-+                        day = data[d_hash];
-+                    }
-+                }
-+
-+                if (day == null) {
-                     /* Still update_day to get the color of etc. right */
--                    day = update_day (new Widgets.CalendarDay (new_date), new_date, today, month_start);
-+                    day = new Widgets.CalendarDay (new_date);
-                     day.on_event_add.connect ((date) => on_event_add (date));
--                    day.scroll_event.connect ((event) => { scroll_event (event); return false; });
--                    day.focus_in_event.connect ((event) => {
--                        on_day_focus_in (day);
--
-+                    day.scroll_event.connect ((event) => {
-+                        scroll_event (event);
-                         return false;
-                     });
-+                    day.focus_in_event.connect (on_day_focus_in);
- 
-                     attach (day, col + 2, row);
-                     day.show_all ();
-                 }
- 
-+                update_day (day, new_date, month_start);
-+                update_today_style (day, new_date, today);
-+                if (selected_date != null && day.date.equal (selected_date)) {
-+                    /* disabled the signal to avoid unnecessary signals and selected
-+                    * the specified day from the new period */
-+                    debug (@"focus selected day $selected_date");
-+                    day.focus_in_event.disconnect (on_day_focus_in);
-+                    day.grab_focus_force ();
-+                    day.set_selected (true);
-+                    day.set_state_flags (Gtk.StateFlags.FOCUSED, false);
-+                    selected_gridday = day;
-+                    day.focus_in_event.connect (on_day_focus_in);
-+                }
-+
-                 col = (col + 1) % 7;
-                 row = (col == 0) ? row + 1 : row;
-                 data_new.set (day_hash (new_date), day);
-@@ -184,8 +209,7 @@ namespace DateTimeIndicator {
-         /**
-          * Updates the given CalendarDay so that it shows the given date. Changes to its style etc.
-          */
--        private Widgets.CalendarDay update_day (Widgets.CalendarDay day, GLib.DateTime new_date, GLib.DateTime today, GLib.DateTime month_start) {
--            update_today_style (day, new_date, today);
-+        private void update_day (Widgets.CalendarDay day, GLib.DateTime new_date, GLib.DateTime month_start) {
-             if (new_date.get_month () == month_start.get_month ()) {
-                 day.sensitive_container (true);
-             } else {
-@@ -193,8 +217,6 @@ namespace DateTimeIndicator {
-             }
- 
-             day.date = new_date;
--
--            return day;
-         }
- 
-         public void update_weeks (GLib.DateTime date, int nr_of_weeks) {
-diff --git a/src/Widgets/CalendarView.vala b/src/Widgets/CalendarView.vala
-index 77c233c..fe957ab 100644
---- a/src/Widgets/CalendarView.vala
-+++ b/src/Widgets/CalendarView.vala
-@@ -85,10 +85,7 @@ namespace DateTimeIndicator {
-             model.notify["data-range"].connect (() => {
-                 label.label = model.month_start.format (_("%OB, %Y"));
- 
--                sync_with_model ();
--
--                selected_date = null;
--                selection_changed (selected_date);
-+                sync_with_model (selected_date != null);
-             });
- 
-             left_button.clicked.connect (() => {
-@@ -113,9 +110,11 @@ namespace DateTimeIndicator {
-                 day_double_click ();
-             });
- 
--            calendar_grid.selection_changed.connect ((date) => {
-+            calendar_grid.selection_changed.connect ((date, up) => {
-                 selected_date = date;
--                selection_changed (date);
-+                if (up) {
-+                    selection_changed (date);
-+                }
-             });
- 
-             return calendar_grid;
-@@ -154,9 +153,9 @@ namespace DateTimeIndicator {
-         }
- 
-         /* Sets the calendar widgets to the date range of the model */
--        private void sync_with_model () {
-+        private void sync_with_model (bool show_selected = false) {
-             var model = Models.CalendarModel.get_default ();
--            if (calendar_grid.grid_range != null && (model.data_range.equals (calendar_grid.grid_range) || calendar_grid.grid_range.first_dt.compare (model.data_range.first_dt) == 0)) {
-+            if (!show_selected && calendar_grid.grid_range != null && (model.data_range.equals (calendar_grid.grid_range) || calendar_grid.grid_range.first_dt.compare (model.data_range.first_dt) == 0)) {
-                 calendar_grid.update_today ();
-                 return; // nothing else to do
-             }
-@@ -168,7 +167,7 @@ namespace DateTimeIndicator {
-             big_grid = create_big_grid ();
-             stack.add (big_grid);
- 
--            calendar_grid.set_range (model.data_range, model.month_start);
-+            calendar_grid.set_range (model.data_range, model.month_start, show_selected ? selected_date : null);
-             calendar_grid.update_weeks (model.data_range.first_dt, model.num_weeks);
- 
-             if (previous_first != null) {
-diff --git a/src/Widgets/EventsListBox.vala b/src/Widgets/EventsListBox.vala
-index c25af2e..9022072 100644
---- a/src/Widgets/EventsListBox.vala
-+++ b/src/Widgets/EventsListBox.vala
-@@ -21,10 +21,14 @@ namespace DateTimeIndicator {
-             set_sort_func (sort_function);
-         }
- 
--        public void update_events (GLib.DateTime? selected_date, HashTable<E.Source, Gee.TreeMultiMap<string, ECal.Component>> source_events) {
-+        public void clear_list () {
-             foreach (unowned Gtk.Widget widget in get_children ()) {
-                 widget.destroy ();
-             }
-+        }
-+
-+        public void update_events (GLib.DateTime? selected_date, HashTable<E.Source, Gee.TreeMultiMap<string, ECal.Component>> source_events) {
-+            clear_list ();
- 
-             if (selected_date == null) {
-                 return;