[gnome-calendar/gbsneto/gtk4: 29/37] WIP month-view: Port to GTK4




commit 25ca2bba004b26c2210ecbbba4b4e3c64ef251c0
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Sun Jan 23 21:03:42 2022 -0300

    WIP month-view: Port to GTK4
    
    A lot is missing, and this most certainly doesn't work.

 src/gui/views/gcal-month-cell.c     |  142 +---
 src/gui/views/gcal-month-cell.h     |    4 +-
 src/gui/views/gcal-month-cell.ui    |   63 +-
 src/gui/views/gcal-month-popover.c  |  560 +-----------
 src/gui/views/gcal-month-popover.ui |   27 +-
 src/gui/views/gcal-month-view.c     | 1601 ++++++++++++++++-------------------
 src/gui/views/gcal-month-view.h     |    2 +-
 src/gui/views/gcal-month-view.ui    |   54 +-
 src/gui/views/gcal-view.c           |    2 +-
 src/theme/Adwaita.css               |    1 -
 src/utils/gcal-utils.c              |   16 +-
 src/utils/gcal-utils.h              |    2 +-
 12 files changed, 807 insertions(+), 1667 deletions(-)
---
diff --git a/src/gui/views/gcal-month-cell.c b/src/gui/views/gcal-month-cell.c
index 5bb71a2a..c0b6cc3c 100644
--- a/src/gui/views/gcal-month-cell.c
+++ b/src/gui/views/gcal-month-cell.c
@@ -29,7 +29,7 @@
 
 struct _GcalMonthCell
 {
-  GtkEventBox         parent;
+  AdwBin              parent;
 
   GDateTime          *date;
   guint               n_overflow;
@@ -46,16 +46,12 @@ struct _GcalMonthCell
   gboolean            different_month;
   gboolean            selected;
 
-  /* internal fields */
-  gboolean            hovered : 1;
-  gboolean            pressed : 1;
-
   GcalContext        *context;
 
   GcalWeatherInfo    *weather_info;
 };
 
-G_DEFINE_TYPE (GcalMonthCell, gcal_month_cell, GTK_TYPE_EVENT_BOX)
+G_DEFINE_TYPE (GcalMonthCell, gcal_month_cell, ADW_TYPE_BIN)
 
 enum
 {
@@ -82,52 +78,14 @@ static void
 update_style_flags (GcalMonthCell *self)
 {
   g_autoptr (GDateTime) today = NULL;
-  GtkStyleContext *context;
-  GtkStateFlags flags;
-  GtkWidget *widget;
-
-  widget = GTK_WIDGET (self);
-  flags = gtk_widget_get_state_flags (widget);
-
-  if (self->hovered)
-    flags |= GTK_STATE_FLAG_PRELIGHT;
-  else
-    flags &= ~GTK_STATE_FLAG_PRELIGHT;
-
-  gtk_widget_set_state_flags (widget, flags, TRUE);
 
   /* Today */
   today = g_date_time_new_now_local ();
-  context = gtk_widget_get_style_context (GTK_WIDGET (self));
 
   if (gcal_date_time_compare_date (self->date, today) == 0)
-    gtk_style_context_add_class (context, "today");
+    gtk_widget_add_css_class (GTK_WIDGET (self), "today");
   else
-    gtk_style_context_remove_class (context, "today");
-}
-
-static gboolean
-should_propagate_button_event (GtkWidget      *widget,
-                               GdkEventButton *event_button)
-{
-  GcalMonthCell *self;
-  gdouble x, y;
-  gint button_height, height;
-
-  self = GCAL_MONTH_CELL (widget);
-  height = gtk_widget_get_allocated_height (widget);
-  button_height = gtk_widget_get_allocated_height (self->overflow_button);
-
-  x = event_button->x;
-  y = event_button->y;
-
-  if (!gcal_translate_child_window_position (widget, event_button->window, x, y, &x, &y))
-    return GDK_EVENT_PROPAGATE;
-
-  if (self->n_overflow > 0 && y > height - button_height)
-    return GDK_EVENT_STOP;
-
-  return GDK_EVENT_PROPAGATE;
+    gtk_widget_remove_css_class (GTK_WIDGET (self), "today");
 }
 
 
@@ -142,30 +100,6 @@ day_changed_cb (GcalClock     *clock,
   update_style_flags (self);
 }
 
-static gboolean
-enter_notify_event_cb (GtkWidget        *widget,
-                       GdkEventCrossing *event_crossing,
-                       GcalMonthCell    *self)
-{
-  self->hovered = TRUE;
-
-  update_style_flags (self);
-
-  return GDK_EVENT_PROPAGATE;
-}
-
-static gboolean
-leave_notify_event_cb (GtkWidget        *widget,
-                       GdkEventCrossing *event_crossing,
-                       GcalMonthCell    *self)
-{
-  self->hovered = FALSE;
-
-  update_style_flags (self);
-
-  return GDK_EVENT_PROPAGATE;
-}
-
 static void
 overflow_button_clicked_cb (GtkWidget     *button,
                             GcalMonthCell *self)
@@ -176,6 +110,9 @@ overflow_button_clicked_cb (GtkWidget     *button,
 /*
  * GtkWidget overrides
  */
+
+#if 0 // TODO: DND
+
 static gboolean
 gcal_month_cell_drag_motion (GtkWidget      *widget,
                              GdkDragContext *context,
@@ -297,51 +234,7 @@ gcal_month_cell_drag_leave (GtkWidget      *widget,
   gtk_drag_unhighlight (widget);
 }
 
-static gboolean
-gcal_month_cell_button_press_event (GtkWidget      *widget,
-                                    GdkEventButton *event_button)
-{
-  GcalMonthCell *self = GCAL_MONTH_CELL (widget);
-
-  self->pressed = TRUE;
-
-  return should_propagate_button_event (widget, event_button);
-}
-
-static gboolean
-gcal_month_cell_button_release_event (GtkWidget      *widget,
-                                      GdkEventButton *event_button)
-{
-  GcalMonthCell *self = GCAL_MONTH_CELL (widget);
-
-  if (!self->pressed)
-    return GDK_EVENT_STOP;
-
-  self->pressed = FALSE;
-
-  return should_propagate_button_event (widget, event_button);
-}
-
-static gboolean
-gcal_month_cell_draw (GtkWidget *widget,
-                      cairo_t   *cr)
-{
-  GtkStyleContext *context;
-  gint width, height;
-
-  width = gtk_widget_get_allocated_width (widget);
-  height = gtk_widget_get_allocated_height (widget);
-  context = gtk_widget_get_style_context (widget);
-
-  gtk_render_background (context, cr, 0, 0, width, height);
-  gtk_render_frame (context, cr, 0, 0, width, height);
-
-  if (gtk_widget_has_focus (widget))
-    gtk_render_focus (context, cr, 0, 0, width, height);
-
-  return GTK_WIDGET_CLASS (gcal_month_cell_parent_class)->draw (widget, cr);
-}
-
+#endif
 
 /*
  * GObject overrides
@@ -409,12 +302,11 @@ gcal_month_cell_class_init (GcalMonthCellClass *klass)
   object_class->set_property = gcal_month_cell_set_property;
   object_class->get_property = gcal_month_cell_get_property;
 
-  widget_class->button_press_event = gcal_month_cell_button_press_event;
-  widget_class->button_release_event = gcal_month_cell_button_release_event;
+#if 0 // TODO: DND
   widget_class->drag_motion = gcal_month_cell_drag_motion;
   widget_class->drag_drop = gcal_month_cell_drag_drop;
   widget_class->drag_leave = gcal_month_cell_drag_leave;
-  widget_class->draw = gcal_month_cell_draw;
+#endif
 
   signals[SHOW_OVERFLOW] = g_signal_new ("show-overflow",
                                          GCAL_TYPE_MONTH_CELL,
@@ -442,8 +334,6 @@ gcal_month_cell_class_init (GcalMonthCellClass *klass)
   gtk_widget_class_bind_template_child (widget_class, GcalMonthCell, temp_label);
   gtk_widget_class_bind_template_child (widget_class, GcalMonthCell, weather_icon);
 
-  gtk_widget_class_bind_template_callback (widget_class, enter_notify_event_cb);
-  gtk_widget_class_bind_template_callback (widget_class, leave_notify_event_cb);
   gtk_widget_class_bind_template_callback (widget_class, overflow_button_clicked_cb);
 
   gtk_widget_class_set_css_name (widget_class, "monthcell");
@@ -454,12 +344,14 @@ gcal_month_cell_init (GcalMonthCell *self)
 {
   gtk_widget_init_template (GTK_WIDGET (self));
 
+#if 0 // TODO: DND
   /* Setup the month cell as a drag n' drop destination */
   gtk_drag_dest_set (GTK_WIDGET (self),
                      0,
                      NULL,
                      0,
                      GDK_ACTION_MOVE);
+#endif
 }
 
 GtkWidget*
@@ -533,7 +425,7 @@ gcal_month_cell_set_weather (GcalMonthCell   *self,
       icon_name = gcal_weather_info_get_icon_name (info);
       temp_str = gcal_weather_info_get_temperature (info);
 
-      gtk_image_set_from_icon_name (self->weather_icon, icon_name, GTK_ICON_SIZE_SMALL_TOOLBAR);
+      gtk_image_set_from_icon_name (self->weather_icon, icon_name);
       gtk_label_set_text (self->temp_label, temp_str);
     }
 }
@@ -631,8 +523,8 @@ gcal_month_cell_get_content_space (GcalMonthCell *self)
   g_return_val_if_fail (GCAL_IS_MONTH_CELL (self), -1);
 
   context = gtk_widget_get_style_context (GTK_WIDGET (self));
-  gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &padding);
-  gtk_style_context_get_border (context, gtk_style_context_get_state (context), &border);
+  gtk_style_context_get_padding (context, &padding);
+  gtk_style_context_get_border (context, &border);
 
   return gtk_widget_get_allocated_height (GTK_WIDGET (self)) -
          gcal_month_cell_get_header_height (self) -
@@ -650,8 +542,8 @@ gcal_month_cell_get_header_height (GcalMonthCell *self)
   g_return_val_if_fail (GCAL_IS_MONTH_CELL (self), -1);
 
   context = gtk_widget_get_style_context (GTK_WIDGET (self->header_box));
-  gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &padding);
-  gtk_style_context_get_border (context, gtk_style_context_get_state (context), &border);
+  gtk_style_context_get_padding (context, &padding);
+  gtk_style_context_get_border (context, &border);
 
   return gtk_widget_get_allocated_height (self->header_box) +
          gtk_widget_get_margin_top (self->header_box) +
diff --git a/src/gui/views/gcal-month-cell.h b/src/gui/views/gcal-month-cell.h
index 6b1dcc83..09a6fe51 100644
--- a/src/gui/views/gcal-month-cell.h
+++ b/src/gui/views/gcal-month-cell.h
@@ -22,13 +22,13 @@
 #include "gcal-context.h"
 #include "gcal-weather-info.h"
 
-#include <gtk/gtk.h>
+#include <adwaita.h>
 
 G_BEGIN_DECLS
 
 #define GCAL_TYPE_MONTH_CELL (gcal_month_cell_get_type())
 
-G_DECLARE_FINAL_TYPE (GcalMonthCell, gcal_month_cell, GCAL, MONTH_CELL, GtkEventBox)
+G_DECLARE_FINAL_TYPE (GcalMonthCell, gcal_month_cell, GCAL, MONTH_CELL, AdwBin)
 
 GtkWidget*           gcal_month_cell_new                         (void);
 
diff --git a/src/gui/views/gcal-month-cell.ui b/src/gui/views/gcal-month-cell.ui
index 89904a41..46291a2c 100644
--- a/src/gui/views/gcal-month-cell.ui
+++ b/src/gui/views/gcal-month-cell.ui
@@ -1,28 +1,21 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
-  <template class="GcalMonthCell" parent="GtkEventBox">
-    <property name="visible">True</property>
-    <property name="can-focus">True</property>
-    <property name="expand">True</property>
-    <signal name="enter-notify-event" handler="enter_notify_event_cb" object="GcalMonthCell" swapped="no" />
-    <signal name="leave-notify-event" handler="leave_notify_event_cb" object="GcalMonthCell" swapped="no" />
+  <template class="GcalMonthCell" parent="AdwBin">
+    <property name="hexpand">True</property>
+    <property name="vexpand">True</property>
+    <property name="focusable">True</property>
     <child>
       <object class="GtkOverlay" id="overlay">
-        <property name="visible">True</property>
-        <property name="can-focus">True</property>
 
         <child type="overlay">
           <object class="GtkBox" id="header_box">
-            <property name="visible">True</property>
-            <property name="can-focus">False</property>
             <property name="valign">start</property>
             <property name="spacing">6</property>
-            <property name="margin">6</property>
-            <property name="margin-bottom">0</property>
+            <property name="margin-top">6</property>
+            <property name="margin-start">6</property>
+            <property name="margin-end">6</property>
             <child>
               <object class="GtkLabel" id="day_label">
-                <property name="visible">True</property>
-                <property name="can-focus">False</property>
                 <style>
                   <class name="day-label" />
                 </style>
@@ -32,8 +25,6 @@
             <!-- Weather forecast -->
             <child>
               <object class="GtkImage" id="weather_icon">
-                <property name="can-focus">False</property>
-                <property name="visible">True</property>
                 <property name="pixel_size">16</property>
                 <property name="margin-start">12</property>
                 <style>
@@ -44,8 +35,6 @@
 
             <child>
               <object class="GtkLabel" id="temp_label">
-                <property name="visible">True</property>
-                <property name="can-focus">True</property>
                 <style>
                   <class name="dim-label" />
                   <class name="temp-label" />
@@ -55,38 +44,18 @@
           </object>
         </child>
 
-        <!-- HACK: in Gtk3, insensitive widgets receive no events. We "fix" this
-             limitation by adding an always-sensitive GtkEventBox above the event,
-             and when the event is insensitive, the event box's event window is
-             above it -->
         <child type="overlay">
-          <object class="GtkEventBox" id="button_event_box">
-            <property name="visible">True</property>
-            <property name="can-focus">False</property>
-            <property name="above-child" bind-source="overflow_button" bind-property="sensitive" 
bind-flags="default|invert-boolean|sync-create" />
-            <signal name="enter-notify-event" handler="enter_notify_event_cb" object="GcalMonthCell" 
swapped="no" />
-            <signal name="leave-notify-event" handler="leave_notify_event_cb" object="GcalMonthCell" 
swapped="no" />
+          <object class="GtkButton" id="overflow_button">
+            <property name="valign">end</property>
+            <signal name="clicked" handler="overflow_button_clicked_cb" object="GcalMonthCell" swapped="no" 
/>
+            <style>
+              <class name="flat" />
+            </style>
             <child>
-              <object class="GtkButton" id="overflow_button">
-                <property name="visible">True</property>
-                <property name="can-focus">True</property>
-                <property name="valign">end</property>
-                <property name="receives-default">True</property>
-                <signal name="clicked" handler="overflow_button_clicked_cb" object="GcalMonthCell" 
swapped="no" />
-                <style>
-                  <class name="flat" />
-                </style>
+              <object class="GtkBox">
                 <child>
-                  <object class="GtkBox">
-                    <property name="visible">True</property>
-                    <property name="can-focus">False</property>
-                    <child>
-                      <object class="GtkLabel" id="overflow_label">
-                        <property name="visible">True</property>
-                        <property name="can-focus">False</property>
-                        <property name="ellipsize">end</property>
-                      </object>
-                    </child>
+                  <object class="GtkLabel" id="overflow_label">
+                    <property name="ellipsize">end</property>
                   </object>
                 </child>
               </object>
diff --git a/src/gui/views/gcal-month-popover.c b/src/gui/views/gcal-month-popover.c
index 05b044f5..a8a80df2 100644
--- a/src/gui/views/gcal-month-popover.c
+++ b/src/gui/views/gcal-month-popover.c
@@ -24,7 +24,7 @@
 #include "gcal-month-popover.h"
 #include "gcal-utils.h"
 
-#include <dazzle.h>
+#include <adwaita.h>
 
 #define RATIO_TO_RELATIVE  1.25
 #define MIN_WIDTH          250
@@ -34,27 +34,12 @@ struct _GcalMonthPopover
   GtkWindow           parent;
 
   GtkLabel           *day_label;
-  GtkWidget          *listbox;
+  GtkListBox         *listbox;
   GtkRevealer        *revealer;
   GtkWidget          *scrolled_window;
 
-  GtkWidget          *relative_to;
-  GtkWindow          *transient_for;
-
   GcalContext        *context;
 
-  DzlAnimation       *opacity_animation;
-  DzlAnimation       *position_animation;
-  DzlAnimation       *size_animation;
-
-  gulong              delete_event_handler;
-  gulong              configure_event_handler;
-  gulong              size_allocate_handler;
-
-  /* Positioning flags - range from [0, 1] */
-  gdouble             x_ratio;
-  gdouble             y_ratio;
-
   GDateTime          *date;
 };
 
@@ -67,16 +52,13 @@ enum
 {
   PROP_0,
   PROP_CONTEXT,
-  PROP_RELATIVE_TO,
-  PROP_X,
-  PROP_Y,
-  N_PROPS
+  N_PROPS,
 };
 
 enum
 {
   EVENT_ACTIVATED,
-  LAST_SIGNAL
+  LAST_SIGNAL,
 };
 
 static guint signals[LAST_SIGNAL] = { 0, };
@@ -87,220 +69,17 @@ static GParamSpec *properties [N_PROPS] = { NULL, };
  * Auxiliary functions
  */
 
-static void
-adjust_margin (GcalMonthPopover *self,
-               GdkRectangle     *area)
-{
-  GtkStyleContext *style_context;
-  GtkBorder margin;
-
-  style_context = gtk_widget_get_style_context (gtk_bin_get_child (GTK_BIN (self)));
-  gtk_style_context_get_margin (style_context,
-                                gtk_style_context_get_state (style_context),
-                                &margin);
-
-  area->x -= margin.right;
-  area->y -= margin.top;
-  area->width += margin.right + margin.left;
-  area->height += margin.top + margin.bottom;
-}
-
-static void
-animate_opacity (GcalMonthPopover *self,
-                 gdouble           target)
-{
-  DzlAnimation *animation;
-
-  if (self->opacity_animation)
-    dzl_animation_stop (self->opacity_animation);
-
-  /* Animate the opacity */
-  animation = dzl_object_animate (self,
-                                  DZL_ANIMATION_EASE_IN_OUT_CUBIC,
-                                  250,
-                                  gtk_widget_get_frame_clock (GTK_WIDGET (self)),
-                                  "opacity", target,
-                                  NULL);
-  dzl_set_weak_pointer (&self->opacity_animation, animation);
-}
-
-static void
-animate_position (GcalMonthPopover *self,
-                  gdouble           x_ratio,
-                  gdouble           y_ratio)
-{
-  DzlAnimation *animation;
-
-  if (self->position_animation)
-    dzl_animation_stop (self->position_animation);
-
-  /* Animate the opacity */
-  animation = dzl_object_animate (self,
-                                  DZL_ANIMATION_EASE_IN_OUT_CUBIC,
-                                  200,
-                                  gtk_widget_get_frame_clock (GTK_WIDGET (self)),
-                                  "x", x_ratio,
-                                  "y", y_ratio,
-                                  NULL);
-  dzl_set_weak_pointer (&self->position_animation, animation);
-}
-
-static void
-animate_size (GcalMonthPopover *self,
-              gint              target_width,
-              gint              target_height)
-{
-  DzlAnimation *animation;
-
-  if (self->size_animation)
-    dzl_animation_stop (self->size_animation);
-
-  /* Animate the size */
-  animation = dzl_object_animate (self,
-                                  DZL_ANIMATION_EASE_IN_OUT_CUBIC,
-                                  200,
-                                  gtk_widget_get_frame_clock (GTK_WIDGET (self)),
-                                  "width-request", target_width,
-                                  "height-request", target_height,
-                                  NULL);
-  dzl_set_weak_pointer (&self->size_animation, animation);
-}
-
-static void
-update_maximum_height (GcalMonthPopover *self)
-{
-  GdkWindow *window;
-  gint clip_height;
-
-  clip_height = 3000;
-  window = gtk_widget_get_window (GTK_WIDGET (self->relative_to));
-
-  if (window)
-    {
-      GdkDisplay *display;
-      GdkMonitor *monitor;
-
-      display = gtk_widget_get_display (GTK_WIDGET (self));
-      monitor = gdk_display_get_monitor_at_window (display, window);
-
-      if (monitor)
-        {
-          GdkRectangle workarea;
-
-          gdk_monitor_get_workarea (monitor, &workarea);
-
-          clip_height = workarea.height / 2;
-        }
-    }
-
-  g_object_set (self->scrolled_window,
-                "max-content-height", clip_height,
-                NULL);
-}
-
-static void
-update_position (GcalMonthPopover *self)
-{
-  GtkAllocation alloc;
-  GtkWidget *toplevel;
-  GdkWindow *window;
-  gint diff_w;
-  gint diff_h;
-  gint x;
-  gint y;
-
-  if (!gtk_widget_get_realized (GTK_WIDGET (self)))
-    return;
-
-  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self->relative_to));
-  window = gtk_widget_get_window (toplevel);
-
-  gtk_widget_get_allocation (GTK_WIDGET (self->relative_to), &alloc);
-
-  alloc.x = 0;
-  alloc.y = 0;
-
-  gtk_widget_translate_coordinates (GTK_WIDGET (self->relative_to), toplevel, 0, 0, &alloc.x, &alloc.y);
-
-  gdk_window_get_position (window, &x, &y);
-  alloc.x += x;
-  alloc.y += y;
-
-  adjust_margin (self, &alloc);
-
-  diff_w = (RATIO_TO_RELATIVE - 1) * alloc.width * (1.0 - self->x_ratio);
-  diff_h = (RATIO_TO_RELATIVE - 1) * alloc.height * (1.0 - self->y_ratio);
-
-  /* Animate the margins, not the (x, y) position) */
-  gtk_widget_set_margin_top (gtk_bin_get_child (GTK_BIN (self)), diff_h / 2);
-
-  if (gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL)
-    gtk_widget_set_margin_end (gtk_bin_get_child (GTK_BIN (self)), diff_w / 2);
-  else
-    gtk_widget_set_margin_start (gtk_bin_get_child (GTK_BIN (self)), diff_w / 2);
-}
-
-static void
-reposition_popover (GcalMonthPopover *self,
-                    gboolean          animate)
-{
-  GtkAllocation alloc;
-  GtkWidget *toplevel;
-  GdkWindow *window;
-  gint diff_w;
-  gint diff_h;
-  gint x;
-  gint y;
-
-  if (!gtk_widget_get_realized (GTK_WIDGET (self)))
-    return;
-
-  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self->relative_to));
-  window = gtk_widget_get_window (toplevel);
-
-  gtk_widget_get_allocation (GTK_WIDGET (self->relative_to), &alloc);
-
-  alloc.x = 0;
-  alloc.y = 0;
-
-  gtk_widget_translate_coordinates (GTK_WIDGET (self->relative_to), toplevel, 0, 0, &alloc.x, &alloc.y);
-
-  gdk_window_get_position (window, &x, &y);
-  alloc.x += x;
-  alloc.y += y;
-
-  adjust_margin (self, &alloc);
-  update_maximum_height (self);
-
-  diff_w = (RATIO_TO_RELATIVE - 1) * alloc.width;
-  diff_h = (RATIO_TO_RELATIVE - 1) * alloc.height;
-
-  gtk_window_move (GTK_WINDOW (self), alloc.x - diff_w / 2, alloc.y - diff_h / 2);
-
-  alloc.width = MAX (MIN_WIDTH, alloc.width);
-
-  if (animate)
-    {
-      gtk_widget_set_size_request (GTK_WIDGET (self), alloc.width, alloc.height);
-
-      animate_position (self, 1.0, 1.0);
-      animate_size (self, alloc.width * RATIO_TO_RELATIVE, alloc.height * RATIO_TO_RELATIVE);
-    }
-  else
-    {
-      gtk_widget_set_size_request (GTK_WIDGET (self), alloc.width * RATIO_TO_RELATIVE, alloc.height * 
RATIO_TO_RELATIVE);
-    }
-}
-
 static void
 update_event_list (GcalMonthPopover *self)
 {
   g_autoptr (GDateTime) start_dt = NULL;
   g_autoptr (GDateTime) end_dt = NULL;
   g_autoptr (GPtrArray) events = NULL;
+  GtkWidget *child;
   guint i;
 
-  gtk_container_foreach (GTK_CONTAINER (self->listbox), (GtkCallback) gtk_widget_destroy, NULL);
+  while ((child = gtk_widget_get_first_child (GTK_WIDGET (self->listbox))) != NULL)
+    gtk_list_box_remove (self->listbox, child);
 
   if (!gtk_widget_get_realized (GTK_WIDGET (self)) ||
       !gtk_widget_get_visible (GTK_WIDGET (self)) ||
@@ -344,7 +123,7 @@ update_event_list (GcalMonthPopover *self)
       gcal_event_widget_set_date_start (GCAL_EVENT_WIDGET (event_widget), event_start);
       gcal_event_widget_set_date_end (GCAL_EVENT_WIDGET (event_widget), event_end);
 
-      gtk_container_add (GTK_CONTAINER (self->listbox), event_widget);
+      gtk_list_box_append (self->listbox, event_widget);
 
       g_signal_connect_object (event_widget,
                                "activate",
@@ -352,8 +131,6 @@ update_event_list (GcalMonthPopover *self)
                                self,
                                0);
     }
-
-  gtk_widget_show_all (self->listbox);
 }
 
 
@@ -369,8 +146,8 @@ sort_func (GtkListBoxRow *a,
   GcalEventWidget *event_a;
   GcalEventWidget *event_b;
 
-  event_a = GCAL_EVENT_WIDGET (gtk_bin_get_child (GTK_BIN (a)));
-  event_b = GCAL_EVENT_WIDGET (gtk_bin_get_child (GTK_BIN (b)));
+  event_a = GCAL_EVENT_WIDGET (gtk_list_box_row_get_child (a));
+  event_b = GCAL_EVENT_WIDGET (gtk_list_box_row_get_child (b));
 
   return gcal_event_widget_sort_events (event_a, event_b);
 }
@@ -421,175 +198,6 @@ revealer_notify_child_revealed_cb (GcalMonthPopover *self,
     gtk_widget_hide (GTK_WIDGET (self));
 }
 
-static gboolean
-transient_for_configure_event_cb (GcalMonthPopover *self,
-                                  GdkEvent         *event,
-                                  GtkWindow        *toplevel)
-{
-  gtk_widget_hide (GTK_WIDGET (self));
-  return FALSE;
-}
-
-static gboolean
-transient_for_delete_event_cb (GcalMonthPopover *self,
-                               GdkEvent         *event,
-                               GtkWindow        *toplevel)
-{
-  gtk_widget_hide (GTK_WIDGET (self));
-  return FALSE;
-}
-
-static void
-transient_for_size_allocate_cb (GcalMonthPopover *self,
-                                GtkAllocation    *allocation,
-                                GtkWindow        *toplevel)
-{
-  reposition_popover (self, FALSE);
-}
-
-
-/*
- * GtkWidget overrides
- */
-
-static void
-gcal_month_popover_destroy (GtkWidget *widget)
-{
-  GcalMonthPopover *self = (GcalMonthPopover *)widget;
-
-  if (self->transient_for)
-    {
-      g_signal_handler_disconnect (self->transient_for, self->size_allocate_handler);
-      g_signal_handler_disconnect (self->transient_for, self->configure_event_handler);
-      g_signal_handler_disconnect (self->transient_for, self->delete_event_handler);
-
-      self->size_allocate_handler = 0;
-      self->configure_event_handler = 0;
-      self->delete_event_handler = 0;
-
-      self->transient_for = NULL;
-    }
-
-  if (self->opacity_animation)
-    {
-      dzl_animation_stop (self->opacity_animation);
-      dzl_clear_weak_pointer (&self->opacity_animation);
-    }
-
-  if (self->position_animation)
-    {
-      dzl_animation_stop (self->position_animation);
-      dzl_clear_weak_pointer (&self->position_animation);
-    }
-
-  if (self->size_animation)
-    {
-      dzl_animation_stop (self->size_animation);
-      dzl_clear_weak_pointer (&self->size_animation);
-    }
-
-  gcal_month_popover_set_relative_to (self, NULL);
-
-  GTK_WIDGET_CLASS (gcal_month_popover_parent_class)->destroy (widget);
-}
-
-static gboolean
-gcal_month_popover_focus_out_event (GtkWidget     *widget,
-                                    GdkEventFocus *event_focus)
-{
-  gcal_month_popover_popdown (GCAL_MONTH_POPOVER (widget));
-
-  return GTK_WIDGET_CLASS (gcal_month_popover_parent_class)->focus_out_event (widget, event_focus);
-}
-
-static void
-gcal_month_popover_hide (GtkWidget *widget)
-{
-  GcalMonthPopover *self = (GcalMonthPopover *)widget;
-
-  if (self->transient_for)
-    gtk_window_group_remove_window (gtk_window_get_group (self->transient_for), GTK_WINDOW (self));
-
-  g_signal_handler_disconnect (self->transient_for, self->delete_event_handler);
-  g_signal_handler_disconnect (self->transient_for, self->size_allocate_handler);
-  g_signal_handler_disconnect (self->transient_for, self->configure_event_handler);
-
-  self->delete_event_handler = 0;
-  self->size_allocate_handler = 0;
-  self->configure_event_handler = 0;
-
-  self->transient_for = NULL;
-
-  gcal_month_popover_popdown (self);
-
-  GTK_WIDGET_CLASS (gcal_month_popover_parent_class)->hide (widget);
-}
-
-static void
-gcal_month_popover_show (GtkWidget *widget)
-{
-  GcalMonthPopover *self = (GcalMonthPopover *)widget;
-
-  if (self->relative_to)
-    {
-      GtkWidget *toplevel;
-
-      toplevel = gtk_widget_get_ancestor (GTK_WIDGET (self->relative_to), GTK_TYPE_WINDOW);
-
-      if (GTK_IS_WINDOW (toplevel))
-        {
-          self->transient_for = GTK_WINDOW (toplevel);
-
-          gtk_window_group_add_window (gtk_window_get_group (self->transient_for), GTK_WINDOW (self));
-
-          self->delete_event_handler =
-            g_signal_connect_object (toplevel,
-                                     "delete-event",
-                                     G_CALLBACK (transient_for_delete_event_cb),
-                                     self,
-                                     G_CONNECT_SWAPPED);
-
-          self->size_allocate_handler =
-            g_signal_connect_object (toplevel,
-                                     "size-allocate",
-                                     G_CALLBACK (transient_for_size_allocate_cb),
-                                     self,
-                                     G_CONNECT_SWAPPED | G_CONNECT_AFTER);
-
-          self->configure_event_handler =
-            g_signal_connect_object (toplevel,
-                                     "configure-event",
-                                     G_CALLBACK (transient_for_configure_event_cb),
-                                     self,
-                                     G_CONNECT_SWAPPED);
-
-          gtk_window_set_transient_for (GTK_WINDOW (self), self->transient_for);
-
-          reposition_popover (self, FALSE);
-        }
-    }
-
-  GTK_WIDGET_CLASS (gcal_month_popover_parent_class)->show (widget);
-}
-
-static void
-gcal_month_popover_realize (GtkWidget *widget)
-{
-  GcalMonthPopover *self = (GcalMonthPopover *)widget;
-  GdkScreen *screen;
-  GdkVisual *visual;
-
-  screen = gtk_widget_get_screen (widget);
-  visual = gdk_screen_get_rgba_visual (screen);
-
-  if (visual)
-    gtk_widget_set_visual (widget, visual);
-
-  GTK_WIDGET_CLASS (gcal_month_popover_parent_class)->realize (widget);
-
-  reposition_popover (self, TRUE);
-}
-
 
 /*
  * GObject overrides
@@ -609,18 +217,6 @@ gcal_month_popover_get_property (GObject    *object,
       g_value_set_object (value, self->context);
       break;
 
-    case PROP_RELATIVE_TO:
-      g_value_set_object (value, self->relative_to);
-      break;
-
-    case PROP_X:
-      g_value_set_double (value, self->x_ratio);
-      break;
-
-    case PROP_Y:
-      g_value_set_double (value, self->y_ratio);
-      break;
-
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -640,21 +236,6 @@ gcal_month_popover_set_property (GObject      *object,
       self->context = g_value_dup_object (value);
       break;
 
-    case PROP_RELATIVE_TO:
-      gcal_month_popover_set_relative_to (self, g_value_get_object (value));
-      break;
-
-    case PROP_X:
-      self->x_ratio = g_value_get_double (value);
-      update_position (self);
-      break;
-
-
-    case PROP_Y:
-      self->y_ratio = g_value_get_double (value);
-      update_position (self);
-      break;
-
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -669,40 +250,12 @@ gcal_month_popover_class_init (GcalMonthPopoverClass *klass)
   object_class->get_property = gcal_month_popover_get_property;
   object_class->set_property = gcal_month_popover_set_property;
 
-  widget_class->destroy = gcal_month_popover_destroy;
-  widget_class->focus_out_event = gcal_month_popover_focus_out_event;
-  widget_class->hide = gcal_month_popover_hide;
-  widget_class->show = gcal_month_popover_show;
-  widget_class->realize = gcal_month_popover_realize;
-
   properties [PROP_CONTEXT] = g_param_spec_object ("context",
                                                    "Context",
                                                    "Context",
                                                    GCAL_TYPE_CONTEXT,
                                                    G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | 
G_PARAM_STATIC_STRINGS);
 
-  properties [PROP_RELATIVE_TO] = g_param_spec_object ("relative-to",
-                                                       "Relative To",
-                                                       "The widget to be relative to",
-                                                       GTK_TYPE_WIDGET,
-                                                       (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | 
G_PARAM_STATIC_STRINGS));
-
-  properties [PROP_X] = g_param_spec_double ("x",
-                                             "X Percent position",
-                                             "X Percent position",
-                                             0.0,
-                                             1.0,
-                                             0.0,
-                                             (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | 
G_PARAM_STATIC_STRINGS));
-
-  properties [PROP_Y] = g_param_spec_double ("y",
-                                             "Y Percent position",
-                                             "Y Percent position",
-                                             0.0,
-                                             1.0,
-                                             0.0,
-                                             (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | 
G_PARAM_STATIC_STRINGS));
-
   g_object_class_install_properties (object_class, N_PROPS, properties);
 
   signals[EVENT_ACTIVATED] = g_signal_new ("event-activated",
@@ -731,12 +284,6 @@ gcal_month_popover_init (GcalMonthPopover *self)
 {
   gtk_widget_init_template (GTK_WIDGET (self));
 
-  gtk_window_set_type_hint (GTK_WINDOW (self), GDK_WINDOW_TYPE_HINT_COMBO);
-  gtk_window_set_decorated (GTK_WINDOW (self), FALSE);
-  gtk_window_set_resizable (GTK_WINDOW (self), FALSE);
-  gtk_window_set_skip_pager_hint (GTK_WINDOW (self), TRUE);
-  gtk_window_set_skip_taskbar_hint (GTK_WINDOW (self), TRUE);
-
   g_signal_connect_object (self->revealer,
                            "notify::child-revealed",
                            G_CALLBACK (revealer_notify_child_revealed_cb),
@@ -749,37 +296,7 @@ gcal_month_popover_init (GcalMonthPopover *self)
 GtkWidget*
 gcal_month_popover_new (void)
 {
-  return g_object_new (GCAL_TYPE_MONTH_POPOVER,
-                       "type", GTK_WINDOW_POPUP,
-                       NULL);
-}
-
-void
-gcal_month_popover_set_relative_to (GcalMonthPopover *self,
-                                    GtkWidget        *relative_to)
-{
-  g_return_if_fail (GCAL_MONTH_POPOVER (self));
-  g_return_if_fail (!relative_to || GTK_IS_WIDGET (relative_to));
-
-  if (self->relative_to == relative_to)
-    return;
-
-  if (self->relative_to)
-    {
-      g_signal_handlers_disconnect_by_func (self->relative_to, gtk_widget_destroyed, &self->relative_to);
-      self->relative_to = NULL;
-    }
-
-  if (relative_to)
-    {
-      self->relative_to = relative_to;
-      g_signal_connect (self->relative_to,
-                        "destroy",
-                        G_CALLBACK (gtk_widget_destroyed),
-                        &self->relative_to);
-    }
-
-  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RELATIVE_TO]);
+  return g_object_new (GCAL_TYPE_MONTH_POPOVER, NULL);
 }
 
 void
@@ -789,25 +306,6 @@ gcal_month_popover_popup (GcalMonthPopover *self)
 
   g_return_if_fail (GCAL_IS_MONTH_POPOVER (self));
 
-  if (self->relative_to)
-    {
-      GtkAllocation alloc;
-      GdkDisplay *display;
-      GdkMonitor *monitor;
-      GdkWindow *window;
-      gint min_height;
-      gint nat_height;
-
-      display = gtk_widget_get_display (GTK_WIDGET (self->relative_to));
-      window = gtk_widget_get_window (GTK_WIDGET (self->relative_to));
-      monitor = gdk_display_get_monitor_at_window (display, window);
-
-      gtk_widget_get_preferred_height (GTK_WIDGET (self), &min_height, &nat_height);
-      gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
-
-      duration = dzl_animation_calculate_duration (monitor, alloc.height, nat_height);
-    }
-
   gtk_widget_show (GTK_WIDGET (self));
 
   gtk_revealer_set_transition_duration (self->revealer, duration);
@@ -816,48 +314,14 @@ gcal_month_popover_popup (GcalMonthPopover *self)
   update_event_list (self);
 
   gtk_widget_grab_focus (GTK_WIDGET (self));
-
-  /* Animations */
-  animate_opacity (self, 1.0);
-  reposition_popover (self, TRUE);
 }
 
 void
 gcal_month_popover_popdown (GcalMonthPopover *self)
 {
-  GtkAllocation alloc;
-  GdkDisplay *display;
-  GdkMonitor *monitor;
-  GdkWindow *window;
-  guint duration;
-
   g_return_if_fail (GCAL_IS_MONTH_POPOVER (self));
 
-  if (!gtk_widget_get_realized (GTK_WIDGET (self)))
-    return;
-
-  display = gtk_widget_get_display (GTK_WIDGET (self->relative_to));
-  window = gtk_widget_get_window (GTK_WIDGET (self->relative_to));
-  monitor = gdk_display_get_monitor_at_window (display, window);
-
-  gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
-
-  duration = dzl_animation_calculate_duration (monitor, alloc.height, 0);
-
-  gtk_revealer_set_transition_duration (self->revealer, duration);
-  gtk_revealer_set_reveal_child (self->revealer, FALSE);
-
-  /* Animations */
-  gtk_widget_get_allocation (GTK_WIDGET (self->relative_to), &alloc);
-  gtk_widget_translate_coordinates (self->relative_to,
-                                    gtk_widget_get_toplevel (self->relative_to), 0, 0, &alloc.x, &alloc.y);
-  adjust_margin (self, &alloc);
-
-  alloc.width = MAX (MIN_WIDTH, alloc.width);
-
-  animate_opacity (self, 0.0);
-  animate_position (self, 0.0, 0.0);
-  animate_size (self, alloc.width, alloc.height);
+  // TODO
 }
 
 GDateTime*
diff --git a/src/gui/views/gcal-month-popover.ui b/src/gui/views/gcal-month-popover.ui
index 3433e05c..137e53f1 100644
--- a/src/gui/views/gcal-month-popover.ui
+++ b/src/gui/views/gcal-month-popover.ui
@@ -6,18 +6,15 @@
     <property name="destroy-with-parent">true</property>
     <child>
       <object class="GtkBox">
-        <property name="visible">true</property>
         <property name="orientation">vertical</property>
         <property name="spacing">12</property>
 
         <!-- Day label & close button-->
         <child>
           <object class="GtkBox">
-            <property name="visible">true</property>
 
             <child>
               <object class="GtkLabel" id="day_label">
-                <property name="visible">true</property>
                 <property name="label">12</property>
                 <property name="xalign">0.0</property>
                 <property name="hexpand">true</property>
@@ -29,17 +26,13 @@
 
             <child>
               <object class="GtkButton">
-                <property name="visible">true</property>
                 <property name="halign">end</property>
                 <property name="valign">start</property>
-                <property name="relief">none</property>
+                <property name="icon-name">window-close-symbolic</property>
                 <signal name="clicked" handler="close_button_clicked_cb" object="GcalMonthPopover" 
swapped="yes" />
-                <child>
-                  <object class="GtkImage">
-                    <property name="visible">true</property>
-                    <property name="icon-name">window-close-symbolic</property>
-                  </object>
-                </child>
+                <style>
+                  <class name="flat" />
+                </style>
               </object>
             </child>
 
@@ -52,22 +45,17 @@
             <property name="reveal-child">false</property>
             <property name="transition-duration">200</property>
             <property name="transition-type">slide-down</property>
-            <property name="visible">true</property>
             <child>
               <object class="GtkBox" id="top_box">
                 <property name="orientation">vertical</property>
-                <property name="visible">true</property>
                 <child>
-                  <object class="DzlElasticBin" id="elastic">
-                    <property name="visible">true</property>
+                  <object class="AdwBin" id="elastic">
                     <child>
                       <object class="GtkScrolledWindow" id="scrolled_window">
                         <property name="hscrollbar-policy">never</property>
                         <property name="propagate-natural-height">true</property>
-                        <property name="visible">true</property>
                         <child>
                           <object class="GtkListBox" id="listbox">
-                            <property name="visible">true</property>
                             <property name="selection-mode">none</property>
                             <style>
                               <class name="background" />
@@ -86,10 +74,11 @@
         <!-- New Event button -->
         <child>
           <object class="GtkButton" id="new_event_button">
-            <property name="visible">true</property>
-            <property name="relief">none</property>
             <property name="label" translatable="yes">New Event…</property>
             <signal name="clicked" handler="new_event_button_clicked_cb" object="GcalMonthPopover" 
swapped="no" />
+            <style>
+              <class name="flat" />
+            </style>
           </object>
         </child>
 
diff --git a/src/gui/views/gcal-month-view.c b/src/gui/views/gcal-month-view.c
index 18f52cdc..a4274d24 100644
--- a/src/gui/views/gcal-month-view.c
+++ b/src/gui/views/gcal-month-view.c
@@ -44,12 +44,10 @@ typedef struct
 
 struct _GcalMonthView
 {
-  GtkContainer        parent;
+  GtkWidget           parent;
 
   GcalMonthPopover   *overflow_popover;
 
-  GdkWindow          *event_window;
-
   /* Header widgets */
   GtkWidget          *header;
   GtkWidget          *label_0;
@@ -67,6 +65,8 @@ struct _GcalMonthView
   GtkWidget          *grid;
   GtkWidget          *month_cell[6][7]; /* unowned */
 
+  GtkEventController *motion_controller;
+
   /*
    * Hash to keep children widgets (all of them, parent widgets and its parts if there's any),
    * uuid as key and a list of all the instances of the event as value. Here, the first widget
@@ -75,13 +75,13 @@ struct _GcalMonthView
   GHashTable         *children;
 
   /*
-   * Hash containig single-cell events, day of the month, on month-view, month of the year on
+   * Hash containing single-cell events, day of the month, on month-view, month of the year on
    * year-view as key anda list of the events that belongs to this cell
    */
   GHashTable         *single_cell_children;
 
   /*
-   * A sorted list containig multiday events. This one contains only parents events, to find out
+   * A sorted list containing multiday events. This one contains only parents events, to find out
    * its parts @children will be used.
    */
   GList              *multi_cell_children;
@@ -121,8 +121,6 @@ struct _GcalMonthView
   /* property */
   GDateTime          *date;
   GcalContext        *context;
-
-  gboolean            pending_event_allocation;
 };
 
 
@@ -144,13 +142,15 @@ static void          on_month_cell_show_overflow_popover_cb      (GcalMonthCell
 static void          gcal_timeline_subscriber_interface_init     (GcalTimelineSubscriberInterface *iface);
 
 
-G_DEFINE_TYPE_WITH_CODE (GcalMonthView, gcal_month_view, GTK_TYPE_CONTAINER,
+G_DEFINE_TYPE_WITH_CODE (GcalMonthView, gcal_month_view, GTK_TYPE_WIDGET,
                          G_IMPLEMENT_INTERFACE (GCAL_TYPE_VIEW, gcal_view_interface_init)
                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
                                                 gtk_buildable_interface_init)
                          G_IMPLEMENT_INTERFACE (GCAL_TYPE_TIMELINE_SUBSCRIBER,
                                                 gcal_timeline_subscriber_interface_init));
 
+static GtkBuildableIface *parent_buildable_iface;
+
 enum
 {
   PROP_0,
@@ -167,6 +167,7 @@ enum
 static inline void
 cancel_selection (GcalMonthView *self)
 {
+  gtk_event_controller_set_propagation_phase (self->motion_controller, GTK_PHASE_NONE);
   g_clear_pointer (&self->start_mark_cell, g_date_time_unref);
   g_clear_pointer (&self->end_mark_cell, g_date_time_unref);
 }
@@ -195,8 +196,8 @@ setup_child_widget (GcalMonthView *self,
 static gboolean
 emit_create_event (GcalMonthView *self)
 {
-  GtkAllocation alloc;
   GDateTime *end_dt,*start_dt;
+  GtkWidget *month_cell;
   gboolean should_clear_end;
   gdouble x, y;
   gint cell;
@@ -237,11 +238,15 @@ emit_create_event (GcalMonthView *self)
 
   /* Get the corresponding GcalMonthCell */
   cell = g_date_time_get_day_of_month (self->end_mark_cell) + self->days_delay - 1;
+  month_cell = self->month_cell[cell / 7][cell % 7];
 
-  gtk_widget_get_allocation (self->month_cell[cell / 7][cell % 7], &alloc);
+  x = gtk_widget_get_allocated_width (month_cell) / 2.0;
+  y = gtk_widget_get_allocated_height (month_cell) / 2.0;
 
-  x = alloc.x + alloc.width / 2.0;
-  y = alloc.y + alloc.height / 2.0;
+  gtk_widget_translate_coordinates (month_cell,
+                                    GTK_WIDGET (self),
+                                    x, y,
+                                    &x, &y);
 
   g_signal_emit_by_name (self, "create-event", start_dt, end_dt, x, y);
 
@@ -257,35 +262,37 @@ get_month_cell_at_position (GcalMonthView *self,
                             gdouble        y,
                             gint          *cell)
 {
-  gint i;
+  GtkWidget *widget;
+  gint i = -1;
 
-  if (y < gtk_widget_get_allocated_height (self->header))
-    return NULL;
+  widget = gtk_widget_pick (GTK_WIDGET (self), x, y, GTK_PICK_INSENSITIVE);
+
+  if (!widget)
+    goto out;
+
+  widget = gtk_widget_get_ancestor (widget, GCAL_TYPE_MONTH_CELL);
+
+  if (!widget)
+    goto out;
 
   for (i = 0; i < 42; i++)
     {
-      GtkAllocation alloc;
       guint row, col;
 
       row = i / 7;
       col = i % 7;
 
-      gtk_widget_get_allocation (self->month_cell[row][col], &alloc);
-
-      if (x >= alloc.x && x < alloc.x + alloc.width &&
-          y >= alloc.y && y < alloc.y + alloc.height)
-        {
-          if (cell)
-            *cell = i;
-
-          return self->month_cell[row][col];
-        }
+      if (self->month_cell[row][col] == widget)
+        break;
     }
 
+  g_assert (i >= 0 && i < 42);
+
+out:
   if (cell)
-    *cell = -1;
+    *cell = i;
 
-  return NULL;
+  return widget;
 }
 
 static void
@@ -396,8 +403,12 @@ calculate_multiday_event_blocks (GcalMonthView *self,
       /* Calculate the minimum event height */
       context = gtk_widget_get_style_context (GTK_WIDGET (event_widget));
 
-      gtk_style_context_get_margin (context, gtk_style_context_get_state (context), &margin);
-      gtk_widget_get_preferred_height (GTK_WIDGET (event_widget), &minimum_height, NULL);
+      gtk_style_context_get_margin (context, &margin);
+      gtk_widget_measure (GTK_WIDGET (event_widget),
+                          GTK_ORIENTATION_VERTICAL,
+                          -1,
+                          &minimum_height,
+                          NULL, NULL, NULL);
 
       minimum_height += margin.top + margin.bottom;
 
@@ -435,7 +446,6 @@ calculate_multiday_event_blocks (GcalMonthView *self,
               event = gcal_event_widget_get_event (GCAL_EVENT_WIDGET (event_widget));
 
               event_widget = gcal_event_widget_clone (GCAL_EVENT_WIDGET (event_widget));
-              gtk_widget_show (event_widget);
               setup_child_widget (self, event_widget);
 
               aux = g_hash_table_lookup (self->children, gcal_event_get_uid (event));
@@ -465,25 +475,6 @@ calculate_multiday_event_blocks (GcalMonthView *self,
   GCAL_RETURN (blocks);
 }
 
-static void
-cleanup_overflow_information (GcalMonthView *self)
-{
-  g_autoptr (GList) widgets = NULL;
-  GList *aux = NULL;
-  GList *l = NULL;
-
-  /* Remove every widget' parts, but the master widget */
-  widgets = g_hash_table_get_values (self->children);
-
-  for (aux = widgets; aux; aux = g_list_next (aux))
-    l = g_list_concat (l, g_list_copy (g_list_next (aux->data)));
-
-  g_list_free_full (l, (GDestroyNotify) gtk_widget_destroy);
-
-  /* Clean overflow information */
-  g_hash_table_remove_all (self->overflow_cells);
-}
-
 static void
 remove_cell_border_and_padding (GtkWidget *cell,
                                 gdouble   *x,
@@ -496,8 +487,8 @@ remove_cell_border_and_padding (GtkWidget *cell,
   gint header_height;
 
   cell_context = gtk_widget_get_style_context (cell);
-  gtk_style_context_get_border (cell_context, gtk_style_context_get_state (cell_context), &cell_border);
-  gtk_style_context_get_padding (cell_context, gtk_style_context_get_state (cell_context), &cell_padding);
+  gtk_style_context_get_border (cell_context, &cell_border);
+  gtk_style_context_get_padding (cell_context, &cell_padding);
 
   header_height = gcal_month_cell_get_header_height (GCAL_MONTH_CELL (cell));
 
@@ -565,7 +556,11 @@ get_real_event_widget_height (GtkWidget *widget)
 {
   gint min_height;
 
-  gtk_widget_get_preferred_height (widget, &min_height, NULL);
+  gtk_widget_measure (GTK_WIDGET (widget),
+                      GTK_ORIENTATION_VERTICAL,
+                      -1,
+                      &min_height,
+                      NULL, NULL, NULL);
 
   min_height += gtk_widget_get_margin_top (widget);
   min_height += gtk_widget_get_margin_bottom (widget);
@@ -588,21 +583,23 @@ allocate_multiday_events (GcalMonthView *self,
                           gdouble       *vertical_cell_space,
                           gdouble       *size_left,
                           gint          *events_at_day,
-                          gint          *allocated_events_at_day)
+                          gint          *allocated_events_at_day,
+                          gint           baseline)
 {
   g_autoptr (GcalRange) month_range = NULL;
   GtkAllocation event_allocation;
   GtkBorder margin;
   GList *l;
   gboolean is_rtl;
+  gint header_height;
 
   is_rtl = gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL;
   month_range = gcal_timeline_subscriber_get_range (GCAL_TIMELINE_SUBSCRIBER (self));
+  header_height = gtk_widget_get_allocated_height (self->header);
 
   for (l = self->multi_cell_children; l; l = g_list_next (l))
     {
       g_autoptr (GPtrArray) blocks = NULL;
-      GtkStyleContext *child_context;
       GtkWidget *child_widget;
       GcalEvent *event;
       gint block_idx;
@@ -613,7 +610,6 @@ allocate_multiday_events (GcalMonthView *self,
         continue;
 
       event = gcal_event_widget_get_event (l->data);
-      child_context = gtk_widget_get_style_context (l->data);
 
       if (!month_view_contains_event (month_range, event))
         continue;
@@ -659,7 +655,6 @@ allocate_multiday_events (GcalMonthView *self,
           day = cell - self->days_delay + 1;
 
           child_widget = block->event_widget;
-          child_context = gtk_widget_get_style_context (child_widget);
 
           /* No space left, add to the overflow and continue */
           if (!block->visible)
@@ -718,13 +713,11 @@ allocate_multiday_events (GcalMonthView *self,
           gcal_event_widget_set_date_end (GCAL_EVENT_WIDGET (child_widget), dt_end);
 
           /* Position and allocate the child widget */
-          gtk_style_context_get_margin (gtk_widget_get_style_context (child_widget),
-                                        gtk_style_context_get_state (child_context),
-                                        &margin);
+          gtk_style_context_get_margin (gtk_widget_get_style_context (child_widget), &margin);
 
 
           pos_x = first_cell_allocation.x + margin.left;
-          pos_y = first_cell_allocation.y + margin.top;
+          pos_y = first_cell_allocation.y + margin.top + header_height;
           width = last_cell_allocation.x + last_cell_allocation.width - first_cell_allocation.x;
 
           remove_cell_border_and_padding (month_cell, &pos_x, &pos_y, &width);
@@ -740,7 +733,7 @@ allocate_multiday_events (GcalMonthView *self,
           event_allocation.width = width - (margin.left + margin.right);
           event_allocation.height = minimum_height;
 
-          gtk_widget_size_allocate (child_widget, &event_allocation);
+          gtk_widget_size_allocate (child_widget, &event_allocation, baseline);
 
           /* update size_left */
           for (j = 0; j < length; j++)
@@ -757,7 +750,8 @@ allocate_single_day_events (GcalMonthView *self,
                             gdouble       *vertical_cell_space,
                             gdouble       *size_left,
                             gint          *events_at_day,
-                            gint          *allocated_events_at_day)
+                            gint          *allocated_events_at_day,
+                            gint           baseline)
 {
   g_autoptr (GcalRange) month_range = NULL;
   GHashTableIter iter;
@@ -765,8 +759,10 @@ allocate_single_day_events (GcalMonthView *self,
   GtkAllocation cell_allocation;
   GtkBorder margin;
   gpointer key, value;
+  gint header_height;
 
   month_range = gcal_timeline_subscriber_get_range (GCAL_TIMELINE_SUBSCRIBER (self));
+  header_height = gtk_widget_get_allocated_height (self->header);
 
   g_hash_table_iter_init (&iter, self->single_cell_children);
 
@@ -809,7 +805,7 @@ allocate_single_day_events (GcalMonthView *self,
 
           child_context = gtk_widget_get_style_context (child_widget);
 
-          gtk_style_context_get_margin (child_context, gtk_style_context_get_state (child_context), &margin);
+          gtk_style_context_get_margin (child_context, &margin);
           minimum_height = get_real_event_widget_height (child_widget) + margin.top + margin.bottom;
 
           /* Check for overflow */
@@ -841,7 +837,7 @@ allocate_single_day_events (GcalMonthView *self,
           gtk_widget_set_child_visible (child_widget, TRUE);
 
           pos_x = cell_allocation.x + margin.left;
-          pos_y = cell_allocation.y + margin.top;
+          pos_y = cell_allocation.y + margin.top + header_height;
           width = cell_allocation.width;
 
           remove_cell_border_and_padding (month_cell, &pos_x, &pos_y, &width);
@@ -852,7 +848,7 @@ allocate_single_day_events (GcalMonthView *self,
           event_allocation.height = minimum_height;
 
           gtk_widget_set_child_visible (child_widget, TRUE);
-          gtk_widget_size_allocate (child_widget, &event_allocation);
+          gtk_widget_size_allocate (child_widget, &event_allocation, baseline);
 
           size_left[cell] -= minimum_height + margin.top + margin.bottom;
         }
@@ -1080,1046 +1076,869 @@ update_weekday_labels (GcalMonthView *self)
     }
 }
 
-
-/*
- * Callbacks
- */
-
-static void
-add_new_event_button_cb (GtkWidget *button,
-                         gpointer   user_data)
+static inline guint
+get_child_cell (GcalMonthView   *self,
+                GcalEventWidget *child)
 {
-  GcalMonthView *self;
-  GDateTime *start_date;
-  gint day;
-
-  self = GCAL_MONTH_VIEW (user_data);
-
-  gcal_month_popover_popdown (self->overflow_popover);
+  GcalEvent *event;
+  GDateTime *dt;
+  gint cell;
 
-  day = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (self->overflow_popover), "selected-day"));
-  start_date = g_date_time_new_local (g_date_time_get_year (self->date),
-                                      g_date_time_get_month (self->date),
-                                      day, 0, 0, 0);
+  event = gcal_event_widget_get_event (child);
+  dt = gcal_event_get_date_start (event);
 
-  g_signal_emit_by_name (GCAL_VIEW (user_data), "create-event-detailed", start_date, NULL);
+  /* Don't adjust the date when the event is all day */
+  if (gcal_event_get_all_day (event))
+    {
+      cell = g_date_time_get_day_of_month (dt);
+    }
+  else
+    {
+      dt = g_date_time_to_local (dt);
+      cell = g_date_time_get_day_of_month (dt);
 
-  g_date_time_unref (start_date);
-}
+      g_clear_pointer (&dt, g_date_time_unref);
+    }
 
-static void
-on_event_activated_cb (GcalEventWidget *widget,
-                       GcalMonthView   *self)
-{
-  activate_event (self, widget);
+  return cell;
 }
 
 static void
-on_event_widget_visibility_changed_cb (GtkWidget     *event_widget,
-                                       GParamSpec    *pspec,
-                                       GcalMonthView *self)
+add_event_widget (GcalMonthView *self,
+                  GtkWidget     *widget)
 {
-  self->pending_event_allocation = TRUE;
-  gtk_widget_queue_resize (GTK_WIDGET (self));
-}
+  GcalEvent *event;
+  const gchar *uuid;
+  GList *l = NULL;
 
-static void
-on_month_cell_show_overflow_popover_cb (GcalMonthCell *cell,
-                                        GtkWidget     *button,
-                                        GcalMonthView *self)
-{
-  GcalMonthPopover *popover;
+  g_return_if_fail (GCAL_IS_EVENT_WIDGET (widget));
+  g_return_if_fail (gtk_widget_get_parent (widget) == NULL);
 
-  popover = GCAL_MONTH_POPOVER (self->overflow_popover);
+  event = gcal_event_widget_get_event (GCAL_EVENT_WIDGET (widget));
+  uuid = gcal_event_get_uid (event);
 
-  cancel_selection (self);
+  /* inserting in all children hash */
+  if (g_hash_table_lookup (self->children, uuid) != NULL)
+    {
+      g_warning ("Event with uuid: %s already added", uuid);
+      g_object_unref (widget);
+      return;
+    }
 
-  gcal_month_popover_set_relative_to (popover, GTK_WIDGET (cell));
-  gcal_month_popover_set_date (popover, gcal_month_cell_get_date (cell));
-  gcal_month_popover_popup (popover);
-}
+  l = g_list_append (l, widget);
+  g_hash_table_insert (self->children, g_strdup (uuid), l);
 
-static void
-on_month_popover_event_activated_cb (GcalMonthPopover *month_popover,
-                                     GcalEventWidget  *event_widget,
-                                     GcalMonthView    *self)
-{
-  activate_event (self, event_widget);
-}
+  if (gcal_event_is_multiday (event))
+    {
+      self->multi_cell_children = g_list_insert_sorted (self->multi_cell_children,
+                                                        widget,
+                                                        (GCompareFunc) gcal_event_widget_sort_events);
+    }
+  else
+    {
+      guint cell_idx;
 
-static void
-on_weather_service_weather_changed_cb (GcalWeatherService *weather_service,
-                                       GcalMonthView      *self)
-{
-  update_weather (self, TRUE);
-}
+      cell_idx = get_child_cell (self, GCAL_EVENT_WIDGET (widget));
 
+      l = g_hash_table_lookup (self->single_cell_children, GINT_TO_POINTER (cell_idx));
+      l = g_list_insert_sorted (l, widget, (GCompareFunc) gcal_event_widget_compare_by_start_date);
 
-/*
- * GcalView interface
- */
+      if (g_list_length (l) != 1)
+        g_hash_table_steal (self->single_cell_children, GINT_TO_POINTER (cell_idx));
 
-static GDateTime*
-gcal_month_view_get_date (GcalView *view)
-{
-  GcalMonthView *self = GCAL_MONTH_VIEW (view);
+      g_hash_table_insert (self->single_cell_children, GINT_TO_POINTER (cell_idx), l);
+    }
 
-  return self->date;
+  setup_child_widget (self, widget);
 }
 
 static void
-gcal_month_view_set_date (GcalView  *view,
-                          GDateTime *date)
+remove_event_widget (GcalMonthView *self,
+                     GtkWidget     *widget)
 {
-  g_autofree gchar *new_date_string = NULL;
-  GcalMonthView *self;
+  GtkWidget *master_widget;
+  GcalEvent *event;
+  GList *l, *aux;
+  const gchar *uuid;
 
-  GCAL_ENTRY;
+  g_return_if_fail (gtk_widget_get_parent (widget) == GTK_WIDGET (self));
 
-  self = GCAL_MONTH_VIEW (view);
+  if (!GCAL_IS_EVENT_WIDGET (widget))
+    goto out;
 
-  gcal_set_date_time (&self->date, date);
+  event = gcal_event_widget_get_event (GCAL_EVENT_WIDGET (widget));
+  uuid = gcal_event_get_uid (event);
 
-  self->days_delay = (time_day_of_week (1, g_date_time_get_month (self->date) - 1, g_date_time_get_year 
(self->date)) - self->first_weekday + 7) % 7;
-  self->keyboard_cell = self->days_delay + (g_date_time_get_day_of_month (self->date) - 1);
+  l = g_hash_table_lookup (self->children, uuid);
 
-  new_date_string = g_date_time_format (date, "%x %X %z");
-  GCAL_TRACE_MSG ("new date: %s", new_date_string);
+  if (l)
+    {
+      gtk_widget_unparent (widget);
 
-  update_header_labels (self);
-  update_month_cells (self);
+      master_widget = (GtkWidget*) l->data;
+      if (widget == master_widget)
+        {
+          if (g_list_find (self->multi_cell_children, widget) != NULL)
+            {
+              self->multi_cell_children = g_list_remove (self->multi_cell_children, widget);
 
-  gcal_timeline_subscriber_range_changed (GCAL_TIMELINE_SUBSCRIBER (view));
+              aux = g_list_next (l);
+              if (aux != NULL)
+                {
+                  l->next = NULL;
+                  aux->prev = NULL;
+                  g_list_foreach (aux, (GFunc) gtk_widget_unparent, NULL);
+                  g_list_free (aux);
+                }
+            }
+          else
+            {
+              GHashTableIter iter;
+              gpointer key, value;
 
-  GCAL_EXIT;
-}
+              /*
+               * When an event is changed, we can't rely on it's old date
+               * to remove the corresponding widget. Because of that, we have
+               * to iter through all the widgets to see which one matches
+               */
+              g_hash_table_iter_init (&iter, self->single_cell_children);
 
-static void
-gcal_month_view_clear_marks (GcalView *view)
-{
-  cancel_selection (GCAL_MONTH_VIEW (view));
-  update_month_cells (GCAL_MONTH_VIEW (view));
+              while (g_hash_table_iter_next (&iter, &key, &value))
+                {
+                  gboolean should_break;
 
-  gtk_widget_queue_allocate (GTK_WIDGET (view));
-}
+                  should_break = FALSE;
 
-static GList*
-gcal_month_view_get_children_by_uuid (GcalView              *view,
-                                      GcalRecurrenceModType  mod,
-                                      const gchar           *uuid)
-{
-  GHashTableIter iter;
-  GcalMonthView *self;
-  GList *children;
-  GList *tmp;
+                  for (aux = value; aux != NULL; aux = aux->next)
+                    {
+                      if (aux->data == widget)
+                        {
+                          aux = g_list_remove (g_list_copy (value), widget);
 
-  self = GCAL_MONTH_VIEW (view);
-  children = NULL;
+                          /*
+                           * If we removed the event and there's no event left for
+                           * the day, remove the key from the table. If there are
+                           * events for that day, replace the list.
+                           */
+                          if (!aux)
+                            g_hash_table_remove (self->single_cell_children, key);
+                          else
+                            g_hash_table_replace (self->single_cell_children, key, aux);
 
-  g_hash_table_iter_init (&iter, self->children);
+                          should_break = TRUE;
 
-  while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &tmp))
-    children = g_list_concat (children, g_list_copy (tmp));
+                          break;
+                        }
+                    }
 
-  return filter_event_list_by_uid_and_modtype (children, mod, uuid);
-}
+                  if (should_break)
+                    break;
+                }
+            }
+        }
 
-static GDateTime*
-gcal_month_view_get_next_date (GcalView *view)
-{
-  GcalMonthView *self = GCAL_MONTH_VIEW (view);
+      l = g_list_remove (g_list_copy (l), widget);
 
-  g_assert (self->date != NULL);
-  return g_date_time_add_months (self->date, 1);
-}
-
-
-static GDateTime*
-gcal_month_view_get_previous_date (GcalView *view)
-{
-  GcalMonthView *self = GCAL_MONTH_VIEW (view);
+      if (!l)
+        g_hash_table_remove (self->children, uuid);
+      else
+        g_hash_table_replace (self->children, g_strdup (uuid), l);
+    }
 
-  g_assert (self->date != NULL);
-  return g_date_time_add_months (self->date, -1);
+out:
+  gtk_widget_queue_resize (GTK_WIDGET (self));
 }
 
 static void
-gcal_view_interface_init (GcalViewInterface *iface)
+cleanup_overflow_information (GcalMonthView *self)
 {
-  iface->get_date = gcal_month_view_get_date;
-  iface->set_date = gcal_month_view_set_date;
-  iface->clear_marks = gcal_month_view_clear_marks;
-  iface->get_children_by_uuid = gcal_month_view_get_children_by_uuid;
-  iface->get_next_date = gcal_month_view_get_next_date;
-  iface->get_previous_date = gcal_month_view_get_previous_date;
-}
-
+  g_autoptr (GList) widget_lists = NULL;
+  GList *l = NULL;
 
-/*
- * GtkBuildable interface
- */
+  /* Remove every widget' parts, but the master widget */
+  widget_lists = g_hash_table_get_values (self->children);
 
-static void
-gcal_month_view_add_child (GtkBuildable *buildable,
-                           GtkBuilder   *builder,
-                           GObject      *child,
-                           const gchar  *type)
-{
-  GcalMonthView *self = GCAL_MONTH_VIEW (buildable);
+  for (l = widget_lists; l; l = l->next)
+    {
+      g_autoptr (GList) widgets = g_list_copy (l->data);
+      GList *l2;
 
-  if (type && strcmp (type, "header") == 0)
-    setup_header_widget  (self, GTK_WIDGET (child));
-  else if (type && strcmp (type, "grid") == 0)
-    setup_month_grid  (self, GTK_WIDGET (child));
-  else
-    GTK_BUILDER_WARN_INVALID_CHILD_TYPE (buildable, type);
-}
+      for (l2 = widgets->next; l2; l2 = l2->next)
+        remove_event_widget (self, l2->data);
+    }
 
-static void
-gtk_buildable_interface_init (GtkBuildableIface *iface)
-{
-  iface->add_child = gcal_month_view_add_child;
+  /* Clean overflow information */
+  g_hash_table_remove_all (self->overflow_cells);
 }
 
 
 /*
- * GcalTimelineSubscriber iface
+ * Callbacks
  */
 
-static GcalRange*
-gcal_month_view_get_range (GcalTimelineSubscriber *subscriber)
-{
-  g_autoptr (GDateTime) month_start = NULL;
-  g_autoptr (GDateTime) month_end = NULL;
-  GcalMonthView *self;
-
-  self = GCAL_MONTH_VIEW (subscriber);
-  month_start = g_date_time_new_local (g_date_time_get_year (self->date),
-                                       g_date_time_get_month (self->date),
-                                       1, 0, 0, 0);
-  month_end = g_date_time_add_months (month_start, 1);
-
-  return gcal_range_new (month_start, month_end, GCAL_RANGE_DEFAULT);
-}
-
 static void
-gcal_month_view_add_event (GcalTimelineSubscriber *subscriber,
-                           GcalEvent              *event)
+add_new_event_button_cb (GtkWidget *button,
+                         gpointer   user_data)
 {
   GcalMonthView *self;
-  GcalCalendar *calendar;
-  GtkWidget *event_widget;
+  GDateTime *start_date;
+  gint day;
 
-  self = GCAL_MONTH_VIEW (subscriber);
-  calendar = gcal_event_get_calendar (event);
+  self = GCAL_MONTH_VIEW (user_data);
 
-  event_widget = gcal_event_widget_new (self->context, event);
-  gcal_event_widget_set_read_only (GCAL_EVENT_WIDGET (event_widget), gcal_calendar_is_read_only (calendar));
+  gcal_month_popover_popdown (self->overflow_popover);
+
+  day = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (self->overflow_popover), "selected-day"));
+  start_date = g_date_time_new_local (g_date_time_get_year (self->date),
+                                      g_date_time_get_month (self->date),
+                                      day, 0, 0, 0);
 
-  gtk_widget_show (event_widget);
-  gtk_container_add (GTK_CONTAINER (subscriber), event_widget);
+  g_signal_emit_by_name (GCAL_VIEW (user_data), "create-event-detailed", start_date, NULL);
 
-  self->pending_event_allocation = TRUE;
+  g_date_time_unref (start_date);
 }
 
 static void
-gcal_month_view_update_event (GcalTimelineSubscriber *subscriber,
-                              GcalEvent              *event)
+on_click_gesture_pressed_cb (GtkGestureClick *click_gesture,
+                             gint             n_press,
+                             gdouble          x,
+                             gdouble          y,
+                             GcalMonthView   *self)
 {
-  GcalMonthView *self;
-  GtkWidget *new_widget;
-  GList *l;
+  gint days, clicked_cell;
 
   GCAL_ENTRY;
 
-  self = GCAL_MONTH_VIEW (subscriber);
+  days = self->days_delay + gcal_date_time_get_days_in_month (self->date);
 
-  l = g_hash_table_lookup (self->children, gcal_event_get_uid (event));
+  get_month_cell_at_position (self, x, y, &clicked_cell);
 
-  if (!l)
+  if (clicked_cell >= self->days_delay && clicked_cell < days)
     {
-      g_warning ("%s: Widget with uuid: %s not found in view: %s",
-                 G_STRFUNC,
-                 gcal_event_get_uid (event),
-                 gtk_widget_get_name (GTK_WIDGET (subscriber)));
-      return;
-    }
-
-  /* Destroy the old event widget (split event widgets will be destroyed too) */
-  gtk_widget_destroy (l->data);
+      gtk_event_controller_set_propagation_phase (self->motion_controller, GTK_PHASE_BUBBLE);
 
-  /* Create and add the new event widget */
-  new_widget = gcal_event_widget_new (self->context, event);
-  gtk_widget_show (new_widget);
-  gtk_container_add (GTK_CONTAINER (subscriber), new_widget);
+      g_clear_pointer (&self->start_mark_cell, g_date_time_unref);
 
-  self->pending_event_allocation = TRUE;
+      self->keyboard_cell = clicked_cell;
+      self->start_mark_cell = g_date_time_new_local (g_date_time_get_year (self->date),
+                                                     g_date_time_get_month (self->date),
+                                                     self->keyboard_cell - self->days_delay + 1,
+                                                     0, 0, 0);
 
-  GCAL_EXIT;
+      update_month_cells (self);
+    }
 }
 
 static void
-gcal_month_view_remove_event (GcalTimelineSubscriber *subscriber,
-                              GcalEvent              *event)
+on_click_gesture_released_cb (GtkGestureClick *click_gesture,
+                              gint             n_press,
+                              gdouble          x,
+                              gdouble          y,
+                              GcalMonthView   *self)
 {
-  GcalMonthView *self;
-  const gchar *uuid;
-  GList *l;
+  gint days, current_day;
 
   GCAL_ENTRY;
 
-  self = GCAL_MONTH_VIEW (subscriber);
-  uuid = gcal_event_get_uid (event);
-  l = g_hash_table_lookup (self->children, uuid);
-
-  if (!l)
-    {
-      g_warning ("%s: Widget with uuid: %s not found in view: %s",
-                 G_STRFUNC,
-                 uuid,
-                 gtk_widget_get_name (GTK_WIDGET (subscriber)));
-      GCAL_RETURN ();
-    }
-
-  gtk_widget_destroy (l->data);
-
-  self->pending_event_allocation = TRUE;
+  days = self->days_delay + gcal_date_time_get_days_in_month (self->date);
 
-  GCAL_EXIT;
-}
+  get_month_cell_at_position (self, x, y, &current_day);
 
-static void
-gcal_timeline_subscriber_interface_init (GcalTimelineSubscriberInterface *iface)
-{
-  iface->get_range = gcal_month_view_get_range;
-  iface->add_event = gcal_month_view_add_event;
-  iface->update_event = gcal_month_view_update_event;
-  iface->remove_event = gcal_month_view_remove_event;
-}
+  if (current_day >= self->days_delay && current_day < days)
+    {
+      g_autoptr (GDateTime) new_active_date = NULL;
 
+      self->keyboard_cell = current_day;
+      new_active_date = g_date_time_new_local (g_date_time_get_year (self->date),
+                                               g_date_time_get_month (self->date),
+                                               current_day - self->days_delay + 1,
+                                               0, 0, 0);
 
-/*
- * GtkContainer overrides
- */
+      gcal_set_date_time (&self->end_mark_cell, new_active_date);
+      gcal_set_date_time (&self->date, new_active_date);
 
-static inline guint
-get_child_cell (GcalMonthView   *self,
-                GcalEventWidget *child)
-{
-  GcalEvent *event;
-  GDateTime *dt;
-  gint cell;
+      /* First, make sure to show the popover */
+      emit_create_event (self);
 
-  event = gcal_event_widget_get_event (child);
-  dt = gcal_event_get_date_start (event);
+      update_month_cells (self);
 
-  /* Don't adjust the date when the event is all day */
-  if (gcal_event_get_all_day (event))
-    {
-      cell = g_date_time_get_day_of_month (dt);
+      /* Then update the active date */
+      g_object_notify (G_OBJECT (self), "active-date");
     }
   else
     {
-      dt = g_date_time_to_local (dt);
-      cell = g_date_time_get_day_of_month (dt);
-
-      g_clear_pointer (&dt, g_date_time_unref);
+      /* If the button is released over an invalid cell, entirely cancel the selection */
+      cancel_selection (self);
+      gtk_widget_queue_resize (GTK_WIDGET (self));
     }
 
-  return cell;
+  gtk_event_controller_set_propagation_phase (self->motion_controller, GTK_PHASE_NONE);
 }
 
 static void
-gcal_month_view_add (GtkContainer *container,
-                     GtkWidget    *widget)
+on_event_activated_cb (GcalEventWidget *widget,
+                       GcalMonthView   *self)
 {
-  GcalMonthView *self;
-  GcalEvent *event;
-  const gchar *uuid;
-  GList *l = NULL;
-
-  g_return_if_fail (GCAL_IS_EVENT_WIDGET (widget));
-  g_return_if_fail (gtk_widget_get_parent (widget) == NULL);
-
-  self = GCAL_MONTH_VIEW (container);
-  event = gcal_event_widget_get_event (GCAL_EVENT_WIDGET (widget));
-  uuid = gcal_event_get_uid (event);
-
-  /* inserting in all children hash */
-  if (g_hash_table_lookup (self->children, uuid) != NULL)
-    {
-      g_warning ("Event with uuid: %s already added", uuid);
-      gtk_widget_destroy (widget);
-      return;
-    }
-
-  l = g_list_append (l, widget);
-  g_hash_table_insert (self->children, g_strdup (uuid), l);
-
-  if (gcal_event_is_multiday (event))
-    {
-      self->multi_cell_children = g_list_insert_sorted (self->multi_cell_children,
-                                                        widget,
-                                                        (GCompareFunc) gcal_event_widget_sort_events);
-    }
-  else
-    {
-      guint cell_idx;
-
-      cell_idx = get_child_cell (self, GCAL_EVENT_WIDGET (widget));
-
-      l = g_hash_table_lookup (self->single_cell_children, GINT_TO_POINTER (cell_idx));
-      l = g_list_insert_sorted (l, widget, (GCompareFunc) gcal_event_widget_compare_by_start_date);
-
-      if (g_list_length (l) != 1)
-        g_hash_table_steal (self->single_cell_children, GINT_TO_POINTER (cell_idx));
-
-      g_hash_table_insert (self->single_cell_children, GINT_TO_POINTER (cell_idx), l);
-    }
-
-  setup_child_widget (self, widget);
+  activate_event (self, widget);
 }
 
 static void
-gcal_month_view_remove (GtkContainer *container,
-                        GtkWidget    *widget)
+on_event_widget_visibility_changed_cb (GtkWidget     *event_widget,
+                                       GParamSpec    *pspec,
+                                       GcalMonthView *self)
 {
-  GcalMonthView *self;
-  GtkWidget *master_widget;
-  GcalEvent *event;
-  GList *l, *aux;
-  const gchar *uuid;
-
-  g_return_if_fail (gtk_widget_get_parent (widget) == GTK_WIDGET (container));
+  gtk_widget_queue_resize (GTK_WIDGET (self));
+}
 
-  if (!GCAL_IS_EVENT_WIDGET (widget))
-    goto out;
+static gboolean
+on_key_controller_key_pressed_cb (GtkEventControllerKey *key_controller,
+                                  guint                  keyval,
+                                  guint                  keycode,
+                                  GdkModifierType        state,
+                                  GcalMonthView         *self)
+{
+  g_autoptr (GDateTime) new_date = NULL;
+  gboolean create_event;
+  gboolean selection;
+  gboolean valid_key;
+  gboolean is_ltr;
+  gint days_in_month;
+  gint min, max, diff, month_change, current_day;
+  gint row, col;
 
-  self = GCAL_MONTH_VIEW (container);
-  event = gcal_event_widget_get_event (GCAL_EVENT_WIDGET (widget));
-  uuid = gcal_event_get_uid (event);
+  GCAL_ENTRY;
 
-  l = g_hash_table_lookup (self->children, uuid);
+  selection = state & GDK_SHIFT_MASK;
+  create_event = FALSE;
+  valid_key = FALSE;
+  diff = 0;
+  month_change = 0;
+  days_in_month = gcal_date_time_get_days_in_month (self->date);
+  current_day = self->keyboard_cell - self->days_delay + 1;
+  min = self->days_delay;
+  max = self->days_delay + days_in_month - 1;
+  is_ltr = gtk_widget_get_direction (GTK_WIDGET (self)) != GTK_TEXT_DIR_RTL;
 
-  if (l)
+  /*
+   * If it's starting the selection right now, it should mark the current keyboard
+   * focused cell as the start, and then update the end mark after updating the
+   * focused cell.
+   */
+  if (selection && self->start_mark_cell == NULL)
     {
-      gtk_widget_unparent (widget);
-
-      master_widget = (GtkWidget*) l->data;
-      if (widget == master_widget)
-        {
-          if (g_list_find (self->multi_cell_children, widget) != NULL)
-            {
-              self->multi_cell_children = g_list_remove (self->multi_cell_children, widget);
-
-              aux = g_list_next (l);
-              if (aux != NULL)
-                {
-                  l->next = NULL;
-                  aux->prev = NULL;
-                  g_list_foreach (aux, (GFunc) gtk_widget_unparent, NULL);
-                  g_list_free (aux);
-                }
-            }
-          else
-            {
-              GHashTableIter iter;
-              gpointer key, value;
-
-              /*
-               * When an event is changed, we can't rely on it's old date
-               * to remove the corresponding widget. Because of that, we have
-               * to iter through all the widgets to see which one matches
-               */
-              g_hash_table_iter_init (&iter, self->single_cell_children);
-
-              while (g_hash_table_iter_next (&iter, &key, &value))
-                {
-                  gboolean should_break;
+      self->start_mark_cell = g_date_time_new_local (g_date_time_get_year (self->date),
+                                                     g_date_time_get_month (self->date),
+                                                     current_day,
+                                                     0, 0, 0);
+    }
 
-                  should_break = FALSE;
+  switch (keyval)
+    {
+    case GDK_KEY_Up:
+      valid_key = TRUE;
+      diff = -7;
+      break;
 
-                  for (aux = value; aux != NULL; aux = aux->next)
-                    {
-                      if (aux->data == widget)
-                        {
-                          aux = g_list_remove (g_list_copy (value), widget);
+    case GDK_KEY_Down:
+      valid_key = TRUE;
+      diff = 7;
+      break;
 
-                          /*
-                           * If we removed the event and there's no event left for
-                           * the day, remove the key from the table. If there are
-                           * events for that day, replace the list.
-                           */
-                          if (!aux)
-                            g_hash_table_remove (self->single_cell_children, key);
-                          else
-                            g_hash_table_replace (self->single_cell_children, key, aux);
+    case GDK_KEY_Left:
+      valid_key = TRUE;
+      diff = is_ltr ? -1 : 1;
+      break;
 
-                          should_break = TRUE;
+    case GDK_KEY_Right:
+      valid_key = TRUE;
+      diff = is_ltr ? 1 : -1;
+      break;
 
-                          break;
-                        }
-                    }
+    case GDK_KEY_Return:
+      /*
+       * If it's not on the selection mode (i.e. shift is not pressed), we should
+       * simulate it by changing the start & end selected cells = keyboard cell.
+       */
+      if (!selection && !self->start_mark_cell && !self->end_mark_cell)
+        {
+          g_autoptr (GDateTime) new_mark = NULL;
 
-                  if (should_break)
-                    break;
-                }
-            }
+          new_mark = g_date_time_new_local (g_date_time_get_year (self->date),
+                                            g_date_time_get_month (self->date),
+                                            current_day,
+                                            0, 0, 0);
+          self->start_mark_cell = g_object_ref (new_mark);
+          self->end_mark_cell = g_object_ref (new_mark);
         }
 
-      l = g_list_remove (g_list_copy (l), widget);
-
-      if (!l)
-        g_hash_table_remove (self->children, uuid);
-      else
-        g_hash_table_replace (self->children, g_strdup (uuid), l);
-    }
-
-out:
-  gtk_widget_queue_resize (GTK_WIDGET (container));
-}
-
-static void
-gcal_month_view_forall (GtkContainer *container,
-                        gboolean      include_internals,
-                        GtkCallback   callback,
-                        gpointer      callback_data)
-{
-  GcalMonthView *self;
-  GList *l, *l2, *aux = NULL;
-
-  self = GCAL_MONTH_VIEW (container);
-
-  /* Header */
-  if (self->header)
-    (*callback) (self->header, callback_data);
-
-  /* Grid */
-  if (self->grid)
-    (*callback) (self->grid, callback_data);
+      create_event = TRUE;
+      break;
 
-  /* Event widgets */
-  l2 = g_hash_table_get_values (self->children);
+    case GDK_KEY_Escape:
+      cancel_selection (self);
+      break;
 
-  for (l = l2; l != NULL; l = g_list_next (l))
-    aux = g_list_concat (aux, g_list_reverse (g_list_copy (l->data)));
+    default:
+      GCAL_RETURN (GDK_EVENT_PROPAGATE);
+    }
 
-  g_list_free (l2);
+  g_message ("Keyboard cell: %d, diff: %d (min: %d, max: %d)", self->keyboard_cell, diff, min, max);
 
-  l = aux;
-  while (aux)
+  if (self->keyboard_cell + diff <= max && self->keyboard_cell + diff >= min)
     {
-      GtkWidget *widget = (GtkWidget*) aux->data;
-      aux = aux->next;
-
-      (*callback) (widget, callback_data);
+      self->keyboard_cell += diff;
     }
+  else
+    {
+      g_autoptr (GDateTime) new_month = NULL;
 
-  g_list_free (l);
-}
+      month_change = self->keyboard_cell + diff > max ? 1 : -1;
+      new_month = g_date_time_add_months (self->date, month_change);
 
+      self->days_delay = (time_day_of_week (1, g_date_time_get_month (new_month) - 1, g_date_time_get_year 
(new_month)) - self->first_weekday + 7) % 7;
 
-/*
- * GtkWidget overrides
- */
+      /*
+       * Set keyboard cell value to the sum or difference of days delay of successive
+       * month or last day of preceding month and overload value depending on
+       * month_change. Overload value is the equal to the deviation of the value
+       * of keboard_cell from the min or max value of the current month depending
+       * on the overload point.
+       */
+      if (month_change == 1)
+        self->keyboard_cell = self->days_delay + self->keyboard_cell + diff - max - 1;
+      else
+        self->keyboard_cell = self->days_delay + gcal_date_time_get_days_in_month (new_month) - min + 
self->keyboard_cell + diff;
+    }
 
-static void
-gcal_month_view_realize (GtkWidget *widget)
-{
-  GcalMonthView *self;
-  GdkWindow *parent_window;
-  GdkWindowAttr attributes;
-  gint attributes_mask;
-  GtkAllocation allocation;
+  /* Focus the selected month cell */
+  row = self->keyboard_cell / 7;
+  col = self->keyboard_cell % 7;
 
-  self = GCAL_MONTH_VIEW (widget);
-  gtk_widget_set_realized (widget, TRUE);
-
-  parent_window = gtk_widget_get_parent_window (widget);
-  gtk_widget_set_window (widget, g_object_ref (parent_window));
-
-  gtk_widget_get_allocation (widget, &allocation);
-
-  attributes.window_type = GDK_WINDOW_CHILD;
-  attributes.wclass = GDK_INPUT_ONLY;
-  attributes.x = allocation.x;
-  attributes.y = allocation.y;
-  attributes.width = allocation.width;
-  attributes.height = allocation.height;
-  attributes.event_mask = gtk_widget_get_events (widget);
-  attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
-                            GDK_BUTTON_RELEASE_MASK |
-                            GDK_BUTTON1_MOTION_MASK |
-                            GDK_POINTER_MOTION_HINT_MASK |
-                            GDK_POINTER_MOTION_MASK |
-                            GDK_ENTER_NOTIFY_MASK |
-                            GDK_LEAVE_NOTIFY_MASK |
-                            GDK_SCROLL_MASK |
-                            GDK_SMOOTH_SCROLL_MASK);
-  attributes_mask = GDK_WA_X | GDK_WA_Y;
-
-  self->event_window = gdk_window_new (parent_window,
-                                       &attributes,
-                                       attributes_mask);
-  gtk_widget_register_window (widget, self->event_window);
-}
+  gtk_widget_grab_focus (self->month_cell[row][col]);
 
-static void
-gcal_month_view_unrealize (GtkWidget *widget)
-{
-  GcalMonthView *self = GCAL_MONTH_VIEW (widget);
+  /* Update the active date */
+  new_date = g_date_time_add_days (self->date, diff);
+  gcal_set_date_time (&self->date, new_date);
+
+  /*
+   * We can only emit the :create-event signal ~after~ grabbing the focus, otherwise
+   * the popover is instantly hidden.
+   */
+  if (create_event)
+    emit_create_event (self);
+
+  g_object_notify (G_OBJECT (self), "active-date");
 
-  if (self->event_window)
+  if (selection)
+    {
+      self->end_mark_cell = g_date_time_new_local (g_date_time_get_year (self->date),
+                                                   g_date_time_get_month (self->date),
+                                                   current_day,
+                                                   0, 0, 0);
+    }
+  else if (!selection && valid_key)
     {
-      gtk_widget_unregister_window (widget, self->event_window);
-      gdk_window_destroy (self->event_window);
-      self->event_window = NULL;
+      /* Cancel selection if SHIFT is not pressed */
+      cancel_selection (self);
     }
 
-  GTK_WIDGET_CLASS (gcal_month_view_parent_class)->unrealize (widget);
+  GCAL_RETURN (GDK_EVENT_STOP);
 }
 
 static void
-gcal_month_view_map (GtkWidget *widget)
+on_month_cell_show_overflow_popover_cb (GcalMonthCell *cell,
+                                        GtkWidget     *button,
+                                        GcalMonthView *self)
 {
-  GcalMonthView *self = GCAL_MONTH_VIEW (widget);
+  GcalMonthPopover *popover;
+
+  popover = GCAL_MONTH_POPOVER (self->overflow_popover);
 
-  if (self->event_window)
-    gdk_window_show (self->event_window);
+  cancel_selection (self);
 
-  GTK_WIDGET_CLASS (gcal_month_view_parent_class)->map (widget);
+  //gcal_month_popover_set_relative_to (popover, GTK_WIDGET (cell));
+  gcal_month_popover_set_date (popover, gcal_month_cell_get_date (cell));
+  gcal_month_popover_popup (popover);
 }
 
 static void
-gcal_month_view_unmap (GtkWidget *widget)
+on_month_popover_event_activated_cb (GcalMonthPopover *month_popover,
+                                     GcalEventWidget  *event_widget,
+                                     GcalMonthView    *self)
 {
-  GcalMonthView *self = GCAL_MONTH_VIEW (widget);
-
-  if (self->event_window)
-    gdk_window_hide (self->event_window);
-
-  GTK_WIDGET_CLASS (gcal_month_view_parent_class)->unmap (widget);
+  activate_event (self, event_widget);
 }
 
 static void
-gcal_month_view_size_allocate (GtkWidget     *widget,
-                               GtkAllocation *allocation)
+on_motion_controller_motion_cb (GtkEventControllerMotion *motion_controller,
+                                gdouble                   x,
+                                gdouble                   y,
+                                GcalMonthView            *self)
 {
-  GtkAllocation child_allocation;
-  GtkAllocation old_alloc;
-  GcalMonthView *self;
-  gint header_height;
-  gint grid_height;
-  gint i;
+  gint days;
+  gint new_end_cell;
 
   GCAL_ENTRY;
 
-  self = GCAL_MONTH_VIEW (widget);
+  days = self->days_delay + gcal_date_time_get_days_in_month (self->date);
 
-  /* Allocate the widget */
-  gtk_widget_get_allocation (widget, &old_alloc);
-  gtk_widget_set_allocation (widget, allocation);
+  get_month_cell_at_position (self, x, y, &new_end_cell);
 
-  if (gtk_widget_get_realized (widget))
-    gdk_window_move_resize (self->event_window, allocation->x, allocation->y, allocation->width, 
allocation->height);
+  if (self->start_mark_cell)
+    {
+      if (new_end_cell < self->days_delay || new_end_cell >= days)
+        return;
 
-  /* Header */
-  gtk_widget_get_preferred_height (self->header, &header_height, NULL);
+      /* Let the keyboard focus track the pointer */
+      self->keyboard_cell = new_end_cell;
 
-  child_allocation.x = allocation->x;
-  child_allocation.y = allocation->y;
-  child_allocation.width = allocation->width;
-  child_allocation.height = header_height;
+      g_clear_pointer (&self->end_mark_cell, g_date_time_unref);
+      self->end_mark_cell = g_date_time_new_local (g_date_time_get_year (self->date),
+                                                   g_date_time_get_month (self->date),
+                                                   new_end_cell - self->days_delay + 1,
+                                                   0, 0, 0);
+
+      update_month_cells (self);
+    }
 
-  gtk_widget_size_allocate (self->header, &child_allocation);
+  GCAL_EXIT;
+}
 
-  /* Grid */
-  gtk_widget_get_preferred_height (self->grid, &grid_height, NULL);
+static gboolean
+on_scroll_controller_scrolled_cb (GtkEventControllerScroll *scroll_controller,
+                                  gdouble                   dx,
+                                  gdouble                   dy,
+                                  GcalMonthView            *self)
+{
+  g_autoptr (GDateTime) new_date = NULL;
+  GdkEvent *current_event;
+  gint diff;
 
-  child_allocation.x = allocation->x;
-  child_allocation.y = allocation->y + header_height;
-  child_allocation.width = allocation->width;
-  child_allocation.height = MAX (allocation->height - header_height, grid_height);
+  current_event = gtk_event_controller_get_current_event (GTK_EVENT_CONTROLLER (scroll_controller));
 
-  gtk_widget_size_allocate (self->grid, &child_allocation);
+  if (!should_change_date_for_scroll (&self->scroll_value, current_event))
+    return GDK_EVENT_PROPAGATE;
 
-  /*
-   * At this point, the internal widgets (grid and header) already received the allocation they
-   * asked for, and are happy. Now it comes the tricky part: when GTK is allocating sizes (here),
-   * we cannot show or hide or add or remove widgets. Doing that can potentially trigger an infinite
-   * allocation cycle, and this function will keep running forever nonstop, the CPU will melt, the
-   * fans will scream and users will cry in anger.
-   *
-   * Thus, to avoid the infinite allocation cycle, we *only* update the event widgets when something
-   * actually changed - either a new event widget was added (pending_event_allocation) or the size
-   * of the Month view changed.
-   *
-   * The following code can be read as the pseudo-code:
-   *
-   *   if (something changed)
-   *     recalculate and recreate event widgets;
-   */
-  if (self->pending_event_allocation ||
-      allocation->width != old_alloc.width ||
-      allocation->height != old_alloc.height)
-    {
-      gdouble vertical_cell_space [42];
-      gdouble size_left [42];
-      gint allocated_events_at_day [42] = { 0, };
-      gint events_at_day [42] = { 0, };
+  diff = self->scroll_value > 0.0 ? 1.0 : -1.0;
+  new_date = g_date_time_add_months (self->date, diff);
 
-      /* Remove every widget' parts, but the master widget */
-      cleanup_overflow_information (self);
+  gcal_set_date_time (&self->date, new_date);
+  self->scroll_value = 0.0;
 
-      /* Event widgets */
-      count_events_per_day (self, events_at_day);
+  g_object_notify (G_OBJECT (self), "active-date");
 
-      for (i = 0; i < 42; i++)
-        {
-          gint h = gcal_month_cell_get_content_space (GCAL_MONTH_CELL (self->month_cell[i / 7][i % 7]));
+  return GDK_EVENT_STOP;
+}
 
-          vertical_cell_space[i] = h;
-          size_left[i] = h;
-        }
 
-      /* Allocate multidays events before single day events, as they have a higher priority */
-      allocate_multiday_events (self, vertical_cell_space, size_left, events_at_day, 
allocated_events_at_day);
-      allocate_single_day_events (self, vertical_cell_space, size_left, events_at_day, 
allocated_events_at_day);
-    }
+static void
+on_weather_service_weather_changed_cb (GcalWeatherService *weather_service,
+                                       GcalMonthView      *self)
+{
+  update_weather (self, TRUE);
+}
 
-  queue_update_month_cells (self);
 
-  self->pending_event_allocation = FALSE;
+/*
+ * GcalView interface
+ */
 
-  GCAL_EXIT;
+static GDateTime*
+gcal_month_view_get_date (GcalView *view)
+{
+  GcalMonthView *self = GCAL_MONTH_VIEW (view);
+
+  return self->date;
 }
 
-static gboolean
-gcal_month_view_button_press (GtkWidget      *widget,
-                              GdkEventButton *event)
+static void
+gcal_month_view_set_date (GcalView  *view,
+                          GDateTime *date)
 {
+  g_autofree gchar *new_date_string = NULL;
   GcalMonthView *self;
-  gdouble x, y;
-  gint days, clicked_cell;
 
   GCAL_ENTRY;
 
-  self = GCAL_MONTH_VIEW (widget);
-  days = self->days_delay + gcal_date_time_get_days_in_month (self->date);
+  self = GCAL_MONTH_VIEW (view);
 
-  /* The event may have come from a child widget, so make it relative to the month view */
-  if (!gcal_translate_child_window_position (widget, event->window, event->x, event->y, &x, &y))
-    return GDK_EVENT_PROPAGATE;
+  gcal_set_date_time (&self->date, date);
 
-  get_month_cell_at_position (self, x, y, &clicked_cell);
+  self->days_delay = (time_day_of_week (1, g_date_time_get_month (self->date) - 1, g_date_time_get_year 
(self->date)) - self->first_weekday + 7) % 7;
+  self->keyboard_cell = self->days_delay + (g_date_time_get_day_of_month (self->date) - 1);
 
-  if (clicked_cell >= self->days_delay && clicked_cell < days)
-    {
-      g_clear_pointer (&self->start_mark_cell, g_date_time_unref);
+  new_date_string = g_date_time_format (date, "%x %X %z");
+  GCAL_TRACE_MSG ("new date: %s", new_date_string);
 
-      self->keyboard_cell = clicked_cell;
-      self->start_mark_cell = g_date_time_new_local (g_date_time_get_year (self->date),
-                                                     g_date_time_get_month (self->date),
-                                                     self->keyboard_cell - self->days_delay + 1,
-                                                     0, 0, 0);
+  update_header_labels (self);
+  update_month_cells (self);
 
-      update_month_cells (self);
-    }
+  gcal_timeline_subscriber_range_changed (GCAL_TIMELINE_SUBSCRIBER (view));
 
-  GCAL_RETURN (GDK_EVENT_PROPAGATE);
+  GCAL_EXIT;
 }
 
-static gboolean
-gcal_month_view_motion_notify_event (GtkWidget      *widget,
-                                     GdkEventMotion *event)
+static void
+gcal_month_view_clear_marks (GcalView *view)
 {
-  GcalMonthView *self;
-  gdouble x, y;
-  gint days;
-  gint new_end_cell;
-
-  GCAL_ENTRY;
-
-  self = GCAL_MONTH_VIEW (widget);
-  days = self->days_delay + gcal_date_time_get_days_in_month (self->date);
-
-  if (!gcal_translate_child_window_position (widget, event->window, event->x, event->y, &x, &y))
-    GCAL_RETURN (GDK_EVENT_PROPAGATE);
-
-  get_month_cell_at_position (self, x, y, &new_end_cell);
+  cancel_selection (GCAL_MONTH_VIEW (view));
+  update_month_cells (GCAL_MONTH_VIEW (view));
 
-  if (self->start_mark_cell)
-    {
-      if (!(event->state & GDK_BUTTON_PRESS_MASK))
-        GCAL_RETURN (GDK_EVENT_STOP);
+  gtk_widget_queue_allocate (GTK_WIDGET (view));
+}
 
-      if (new_end_cell < self->days_delay || new_end_cell >= days)
-        GCAL_RETURN (GDK_EVENT_PROPAGATE);
+static GList*
+gcal_month_view_get_children_by_uuid (GcalView              *view,
+                                      GcalRecurrenceModType  mod,
+                                      const gchar           *uuid)
+{
+  return filter_children_by_uid_and_modtype (GTK_WIDGET (view), mod, uuid);
+}
 
-      /* Let the keyboard focus track the pointer */
-      self->keyboard_cell = new_end_cell;
+static GDateTime*
+gcal_month_view_get_next_date (GcalView *view)
+{
+  GcalMonthView *self = GCAL_MONTH_VIEW (view);
 
-      g_clear_pointer (&self->end_mark_cell, g_date_time_unref);
-      self->end_mark_cell = g_date_time_new_local (g_date_time_get_year (self->date),
-                                                   g_date_time_get_month (self->date),
-                                                   new_end_cell - self->days_delay + 1,
-                                                   0, 0, 0);
+  g_assert (self->date != NULL);
+  return g_date_time_add_months (self->date, 1);
+}
 
-      update_month_cells (self);
 
-      GCAL_RETURN (GDK_EVENT_STOP);
-    }
-  else
-    {
-      if (gtk_widget_is_visible (GTK_WIDGET (self->overflow_popover)))
-        GCAL_RETURN (GDK_EVENT_PROPAGATE);
-    }
+static GDateTime*
+gcal_month_view_get_previous_date (GcalView *view)
+{
+  GcalMonthView *self = GCAL_MONTH_VIEW (view);
 
-  GCAL_RETURN (GDK_EVENT_PROPAGATE);
+  g_assert (self->date != NULL);
+  return g_date_time_add_months (self->date, -1);
 }
 
-static gboolean
-gcal_month_view_button_release (GtkWidget      *widget,
-                                GdkEventButton *event)
+static void
+gcal_view_interface_init (GcalViewInterface *iface)
 {
-  GcalMonthView *self;
-  gdouble x, y;
-  gint days, current_day;
-
-  GCAL_ENTRY;
-
-  self = GCAL_MONTH_VIEW (widget);
-  days = self->days_delay + gcal_date_time_get_days_in_month (self->date);
+  iface->get_date = gcal_month_view_get_date;
+  iface->set_date = gcal_month_view_set_date;
+  iface->clear_marks = gcal_month_view_clear_marks;
+  iface->get_children_by_uuid = gcal_month_view_get_children_by_uuid;
+  iface->get_next_date = gcal_month_view_get_next_date;
+  iface->get_previous_date = gcal_month_view_get_previous_date;
+}
 
-  if (!gcal_translate_child_window_position (widget, event->window, event->x, event->y, &x, &y))
-    GCAL_RETURN (GDK_EVENT_PROPAGATE);
 
-  get_month_cell_at_position (self, x, y, &current_day);
+/*
+ * GtkBuildable interface
+ */
 
-  if (current_day >= self->days_delay && current_day < days)
-    {
-      g_autoptr (GDateTime) new_active_date = NULL;
-      gboolean valid;
+static void
+gcal_month_view_add_child (GtkBuildable *buildable,
+                           GtkBuilder   *builder,
+                           GObject      *child,
+                           const gchar  *type)
+{
+  GcalMonthView *self = GCAL_MONTH_VIEW (buildable);
 
-      self->keyboard_cell = current_day;
-      new_active_date = g_date_time_new_local (g_date_time_get_year (self->date),
-                                               g_date_time_get_month (self->date),
-                                               current_day - self->days_delay + 1,
-                                               0, 0, 0);
+  if (type && strcmp (type, "header") == 0)
+    setup_header_widget  (self, GTK_WIDGET (child));
+  else if (type && strcmp (type, "grid") == 0)
+    setup_month_grid  (self, GTK_WIDGET (child));
+  else
+    parent_buildable_iface->add_child (buildable, builder, child, type);
+}
 
-      gcal_set_date_time (&self->end_mark_cell, new_active_date);
-      gcal_set_date_time (&self->date, new_active_date);
+static void
+gtk_buildable_interface_init (GtkBuildableIface *iface)
+{
+  parent_buildable_iface = g_type_interface_peek_parent (iface);
 
-      /* First, make sure to show the popover */
-      valid = emit_create_event (self);
+  iface->add_child = gcal_month_view_add_child;
+}
 
-      update_month_cells (self);
 
-      /* Then update the active date */
-      g_object_notify (G_OBJECT (self), "active-date");
+/*
+ * GcalTimelineSubscriber iface
+ */
 
-      GCAL_RETURN (valid);
-    }
-  else
-    {
-      /* If the button is released over an invalid cell, entirely cancel the selection */
-      cancel_selection (GCAL_MONTH_VIEW (widget));
+static GcalRange*
+gcal_month_view_get_range (GcalTimelineSubscriber *subscriber)
+{
+  g_autoptr (GDateTime) month_start = NULL;
+  g_autoptr (GDateTime) month_end = NULL;
+  GcalMonthView *self;
 
-      gtk_widget_queue_resize (widget);
+  self = GCAL_MONTH_VIEW (subscriber);
+  month_start = g_date_time_new_local (g_date_time_get_year (self->date),
+                                       g_date_time_get_month (self->date),
+                                       1, 0, 0, 0);
+  month_end = g_date_time_add_months (month_start, 1);
 
-      GCAL_RETURN (GDK_EVENT_PROPAGATE);
-    }
+  return gcal_range_new (month_start, month_end, GCAL_RANGE_DEFAULT);
 }
 
 static void
-gcal_month_view_direction_changed (GtkWidget        *widget,
-                                   GtkTextDirection  previous_direction)
+gcal_month_view_add_event (GcalTimelineSubscriber *subscriber,
+                           GcalEvent              *event)
 {
-  GcalMonthView *self = GCAL_MONTH_VIEW (widget);
+  GcalMonthView *self;
+  GcalCalendar *calendar;
+  GtkWidget *event_widget;
+
+  self = GCAL_MONTH_VIEW (subscriber);
+  calendar = gcal_event_get_calendar (event);
 
-  self->pending_event_allocation = TRUE;
+  event_widget = gcal_event_widget_new (self->context, event);
+  gcal_event_widget_set_read_only (GCAL_EVENT_WIDGET (event_widget), gcal_calendar_is_read_only (calendar));
 
-  gtk_widget_queue_resize (widget);
+  add_event_widget (self, event_widget);
 }
 
-static gboolean
-gcal_month_view_key_press (GtkWidget   *widget,
-                           GdkEventKey *event)
+static void
+gcal_month_view_update_event (GcalTimelineSubscriber *subscriber,
+                              GcalEvent              *event)
 {
   GcalMonthView *self;
-  gboolean create_event;
-  gboolean selection;
-  gboolean valid_key;
-  gboolean is_ltr;
-  gint days_in_month;
-  gint min, max, diff, month_change, current_day;
-  gint row, col;
+  GtkWidget *new_widget;
+  GList *l;
 
-  g_return_val_if_fail (GCAL_IS_MONTH_VIEW (widget), FALSE);
+  GCAL_ENTRY;
 
-  self = GCAL_MONTH_VIEW (widget);
-  selection = event->state & GDK_SHIFT_MASK;
-  create_event = FALSE;
-  valid_key = FALSE;
-  diff = 0;
-  month_change = 0;
-  days_in_month = gcal_date_time_get_days_in_month (self->date);
-  current_day = self->keyboard_cell - self->days_delay + 1;
-  min = self->days_delay;
-  max = self->days_delay + days_in_month - 1;
-  is_ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
+  self = GCAL_MONTH_VIEW (subscriber);
 
-  /*
-   * If it's starting the selection right now, it should mark the current keyboard
-   * focused cell as the start, and then update the end mark after updating the
-   * focused cell.
-   */
-  if (selection && self->start_mark_cell == NULL)
-    {
-      self->start_mark_cell = g_date_time_new_local (g_date_time_get_year (self->date),
-                                                     g_date_time_get_month (self->date),
-                                                     current_day,
-                                                     0, 0, 0);
-    }
+  l = g_hash_table_lookup (self->children, gcal_event_get_uid (event));
 
-  switch (event->keyval)
+  if (!l)
     {
-    case GDK_KEY_Up:
-      valid_key = TRUE;
-      diff = -7;
-      break;
-
-    case GDK_KEY_Down:
-      valid_key = TRUE;
-      diff = 7;
-      break;
-
-    case GDK_KEY_Left:
-      valid_key = TRUE;
-      diff = is_ltr ? -1 : 1;
-      break;
+      g_warning ("%s: Widget with uuid: %s not found in view: %s",
+                 G_STRFUNC,
+                 gcal_event_get_uid (event),
+                 gtk_widget_get_name (GTK_WIDGET (subscriber)));
+      return;
+    }
 
-    case GDK_KEY_Right:
-      valid_key = TRUE;
-      diff = is_ltr ? 1 : -1;
-      break;
+  /* Destroy the old event widget (split event widgets will be destroyed too) */
+  remove_event_widget (self, l->data);
 
-    case GDK_KEY_Return:
-      /*
-       * If it's not on the selection mode (i.e. shift is not pressed), we should
-       * simulate it by changing the start & end selected cells = keyboard cell.
-       */
-      if (!selection && !self->start_mark_cell && !self->end_mark_cell)
-        {
-          g_autoptr (GDateTime) new_mark = NULL;
+  /* Create and add the new event widget */
+  new_widget = gcal_event_widget_new (self->context, event);
+  add_event_widget (self, new_widget);
 
-          new_mark = g_date_time_new_local (g_date_time_get_year (self->date),
-                                            g_date_time_get_month (self->date),
-                                            current_day,
-                                            0, 0, 0);
-          self->start_mark_cell = g_object_ref (new_mark);
-          self->end_mark_cell = g_object_ref (new_mark);
-        }
+  GCAL_EXIT;
+}
 
-      create_event = TRUE;
-      break;
+static void
+gcal_month_view_remove_event (GcalTimelineSubscriber *subscriber,
+                              GcalEvent              *event)
+{
+  GcalMonthView *self;
+  const gchar *uuid;
+  GList *l;
 
-    case GDK_KEY_Escape:
-      cancel_selection (GCAL_MONTH_VIEW (widget));
-      break;
+  GCAL_ENTRY;
 
-    default:
-      return GDK_EVENT_PROPAGATE;
-    }
+  self = GCAL_MONTH_VIEW (subscriber);
+  uuid = gcal_event_get_uid (event);
+  l = g_hash_table_lookup (self->children, uuid);
 
-  if (self->keyboard_cell + diff <= max && self->keyboard_cell + diff >= min)
+  if (!l)
     {
-      self->keyboard_cell += diff;
+      g_warning ("%s: Widget with uuid: %s not found in view: %s",
+                 G_STRFUNC,
+                 uuid,
+                 gtk_widget_get_name (GTK_WIDGET (subscriber)));
+      GCAL_RETURN ();
     }
-  else
-    {
-      g_autoptr (GDateTime) new_month = NULL;
 
-      month_change = self->keyboard_cell + diff > max ? 1 : -1;
-      new_month = g_date_time_add_months (self->date, month_change);
+  remove_event_widget (self, l->data);
 
-      self->days_delay = (time_day_of_week (1, g_date_time_get_month (new_month) - 1, g_date_time_get_year 
(new_month)) - self->first_weekday + 7) % 7;
+  GCAL_EXIT;
+}
 
-      /*
-       * Set keyboard cell value to the sum or difference of days delay of successive
-       * month or last day of preceeding month and overload value depending on
-       * month_change. Overload value is the equal to the deviation of the value
-       * of keboard_cell from the min or max value of the current month depending
-       * on the overload point.
-       */
-      if (month_change == 1)
-        self->keyboard_cell = self->days_delay + self->keyboard_cell + diff - max - 1;
-      else
-        self->keyboard_cell = self->days_delay + gcal_date_time_get_days_in_month (new_month) - min + 
self->keyboard_cell + diff;
-    }
+static void
+gcal_timeline_subscriber_interface_init (GcalTimelineSubscriberInterface *iface)
+{
+  iface->get_range = gcal_month_view_get_range;
+  iface->add_event = gcal_month_view_add_event;
+  iface->update_event = gcal_month_view_update_event;
+  iface->remove_event = gcal_month_view_remove_event;
+}
 
-  /* Focus the selected month cell */
-  row = self->keyboard_cell / 7;
-  col = self->keyboard_cell % 7;
 
-  gtk_widget_grab_focus (self->month_cell[row][col]);
+/*
+ * GtkWidget overrides
+ */
 
-  current_day = self->keyboard_cell - self->days_delay + 1;
-  //self->date->day = current_day;
+static void
+gcal_month_view_size_allocate (GtkWidget *widget,
+                               gint       width,
+                               gint       height,
+                               gint       baseline)
+{
+  GtkAllocation child_allocation;
+  GtkAllocation old_alloc;
+  GcalMonthView *self;
+  gdouble vertical_cell_space [42];
+  gdouble size_left [42];
+  gint allocated_events_at_day [42] = { 0, };
+  gint events_at_day [42] = { 0, };
+  gint header_height;
+  gint grid_height;
+  gint i;
 
-  /*
-   * We can only emit the :create-event signal ~after~ grabbing the focus, otherwise
-   * the popover is instantly hidden.
-   */
-  if (create_event)
-    emit_create_event (self);
+  GCAL_ENTRY;
 
-  g_object_notify (G_OBJECT (widget), "active-date");
+  self = GCAL_MONTH_VIEW (widget);
 
-  if (selection)
-    {
-      self->end_mark_cell = g_date_time_new_local (g_date_time_get_year (self->date),
-                                                   g_date_time_get_month (self->date),
-                                                   current_day,
-                                                   0, 0, 0);
-    }
-  else if (!selection && valid_key)
-    {
-      /* Cancel selection if SHIFT is not pressed */
-      cancel_selection (GCAL_MONTH_VIEW (widget));
-    }
+  /* Allocate the widget */
+  gtk_widget_get_allocation (widget, &old_alloc);
 
-  return GDK_EVENT_STOP;
-}
+  /* Header */
+  gtk_widget_measure (GTK_WIDGET (self->header),
+                      GTK_ORIENTATION_VERTICAL,
+                      -1,
+                      &header_height,
+                      NULL, NULL, NULL);
+
+  child_allocation.x = 0;
+  child_allocation.y = 0;
+  child_allocation.width = width;
+  child_allocation.height = header_height;
 
-static gboolean
-gcal_month_view_scroll_event (GtkWidget      *widget,
-                              GdkEventScroll *scroll_event)
-{
-  GcalMonthView *self = GCAL_MONTH_VIEW (widget);
+  gtk_widget_size_allocate (self->header, &child_allocation, baseline);
 
-  /*
-   * If we accumulated enough scrolling, change the month. Otherwise, we'd scroll
-   * waaay too fast.
-   */
-  if (should_change_date_for_scroll (&self->scroll_value, scroll_event))
-    {
-      g_autoptr (GDateTime) new_date = NULL;
-      gint diff;
+  /* Grid */
+  gtk_widget_measure (GTK_WIDGET (self->grid),
+                      GTK_ORIENTATION_VERTICAL,
+                      -1,
+                      &grid_height,
+                      NULL, NULL, NULL);
 
-      diff = self->scroll_value > 0 ? 1 : -1;
-      new_date = g_date_time_add_months (self->date, diff);
+  child_allocation.x = 0;
+  child_allocation.y = header_height;
+  child_allocation.width = width;
+  child_allocation.height = MAX (height - header_height, grid_height);
 
-      gcal_clear_date_time (&self->date);
-      self->date = g_steal_pointer (&new_date);
-      self->scroll_value = 0;
+  gtk_widget_size_allocate (self->grid, &child_allocation, baseline);
 
-      gtk_widget_queue_draw (widget);
+  /* Remove every widget' parts, but the master widget */
+  cleanup_overflow_information (self);
+
+  /* Event widgets */
+  count_events_per_day (self, events_at_day);
+
+  for (i = 0; i < 42; i++)
+    {
+      gint h = gcal_month_cell_get_content_space (GCAL_MONTH_CELL (self->month_cell[i / 7][i % 7]));
 
-      g_object_notify (G_OBJECT (widget), "active-date");
+      vertical_cell_space[i] = h;
+      size_left[i] = h;
     }
 
-  return GDK_EVENT_STOP;
+  allocate_multiday_events (self, vertical_cell_space, size_left, events_at_day, allocated_events_at_day, 
baseline);
+  allocate_single_day_events (self, vertical_cell_space, size_left, events_at_day, allocated_events_at_day, 
baseline);
+
+  queue_update_month_cells (self);
+
+  GCAL_EXIT;
 }
 
 
@@ -2200,21 +2019,27 @@ gcal_month_view_finalize (GObject *object)
   GcalMonthView *self = GCAL_MONTH_VIEW (object);
 
   gcal_clear_date_time (&self->date);
+  g_clear_object (&self->context);
+  g_clear_handle_id (&self->update_grid_id, g_source_remove);
+
+  /* Chain up to parent's finalize() method. */
+  G_OBJECT_CLASS (gcal_month_view_parent_class)->finalize (object);
+}
+
+static void
+gcal_month_view_dispose (GObject *object)
+{
+  GcalMonthView *self = GCAL_MONTH_VIEW (object);
+
+  g_clear_pointer (&self->header, gtk_widget_unparent);
+  g_clear_pointer (&self->grid, gtk_widget_unparent);
+
   g_clear_pointer (&self->children, g_hash_table_destroy);
   g_clear_pointer (&self->single_cell_children, g_hash_table_destroy);
   g_clear_pointer (&self->overflow_cells, g_hash_table_destroy);
   g_clear_pointer (&self->multi_cell_children, g_list_free);
 
-  g_clear_object (&self->context);
-
-  if (self->update_grid_id > 0)
-    {
-      g_source_remove (self->update_grid_id);
-      self->update_grid_id = 0;
-    }
-
-  /* Chain up to parent's finalize() method. */
-  G_OBJECT_CLASS (gcal_month_view_parent_class)->finalize (object);
+  G_OBJECT_CLASS (gcal_month_view_parent_class)->dispose (object);
 }
 
 static void
@@ -2222,30 +2047,19 @@ gcal_month_view_class_init (GcalMonthViewClass *klass)
 {
   GObjectClass *object_class;
   GtkWidgetClass *widget_class;
-  GtkContainerClass *container_class;
 
   object_class = G_OBJECT_CLASS (klass);
   object_class->set_property = gcal_month_view_set_property;
   object_class->get_property = gcal_month_view_get_property;
   object_class->finalize = gcal_month_view_finalize;
+  object_class->dispose = gcal_month_view_dispose;
 
   widget_class = GTK_WIDGET_CLASS (klass);
-  widget_class->realize = gcal_month_view_realize;
-  widget_class->unrealize = gcal_month_view_unrealize;
-  widget_class->map = gcal_month_view_map;
-  widget_class->unmap = gcal_month_view_unmap;
   widget_class->size_allocate = gcal_month_view_size_allocate;
-  widget_class->button_press_event = gcal_month_view_button_press;
-  widget_class->motion_notify_event = gcal_month_view_motion_notify_event;
-  widget_class->button_release_event = gcal_month_view_button_release;
-  widget_class->direction_changed = gcal_month_view_direction_changed;
+#if 0 // TODO: event handling
   widget_class->key_press_event = gcal_month_view_key_press;
   widget_class->scroll_event = gcal_month_view_scroll_event;
-
-  container_class = GTK_CONTAINER_CLASS (klass);
-  container_class->add = gcal_month_view_add;
-  container_class->remove = gcal_month_view_remove;
-  container_class->forall = gcal_month_view_forall;
+#endif
 
   g_object_class_override_property (object_class, PROP_DATE, "active-date");
   g_object_class_override_property (object_class, PROP_CONTEXT, "context");
@@ -2260,9 +2074,15 @@ gcal_month_view_class_init (GcalMonthViewClass *klass)
   gtk_widget_class_bind_template_child (widget_class, GcalMonthView, label_5);
   gtk_widget_class_bind_template_child (widget_class, GcalMonthView, label_6);
   gtk_widget_class_bind_template_child (widget_class, GcalMonthView, month_label);
+  gtk_widget_class_bind_template_child (widget_class, GcalMonthView, motion_controller);
   gtk_widget_class_bind_template_child (widget_class, GcalMonthView, year_label);
 
   gtk_widget_class_bind_template_callback (widget_class, add_new_event_button_cb);
+  gtk_widget_class_bind_template_callback (widget_class, on_click_gesture_pressed_cb);
+  gtk_widget_class_bind_template_callback (widget_class, on_click_gesture_released_cb);
+  gtk_widget_class_bind_template_callback (widget_class, on_key_controller_key_pressed_cb);
+  gtk_widget_class_bind_template_callback (widget_class, on_motion_controller_motion_cb);
+  gtk_widget_class_bind_template_callback (widget_class, on_scroll_controller_scrolled_cb);
 
   gtk_widget_class_set_css_name (widget_class, "calendar-view");
 
@@ -2274,12 +2094,9 @@ gcal_month_view_init (GcalMonthView *self)
 {
   gtk_widget_init_template (GTK_WIDGET (self));
 
-  gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
-
   self->children = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_list_free);
   self->single_cell_children = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) 
g_list_free);
   self->overflow_cells = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) 
g_list_free);
-  self->pending_event_allocation = FALSE;
 
   /* First weekday */
   self->first_weekday = get_first_weekday ();
@@ -2304,6 +2121,10 @@ gcal_month_view_init (GcalMonthView *self)
                           "context",
                           G_BINDING_DEFAULT);
 
-  g_signal_connect_object (self->overflow_popover, "event-activated", G_CALLBACK 
(on_month_popover_event_activated_cb), self, 0);
+  g_signal_connect_object (self->overflow_popover,
+                           "event-activated",
+                           G_CALLBACK (on_month_popover_event_activated_cb),
+                           self,
+                           0);
 }
 
diff --git a/src/gui/views/gcal-month-view.h b/src/gui/views/gcal-month-view.h
index c560b72f..d5d5fb50 100644
--- a/src/gui/views/gcal-month-view.h
+++ b/src/gui/views/gcal-month-view.h
@@ -26,7 +26,7 @@ G_BEGIN_DECLS
 
 #define GCAL_TYPE_MONTH_VIEW  (gcal_month_view_get_type ())
 
-G_DECLARE_FINAL_TYPE (GcalMonthView, gcal_month_view, GCAL, MONTH_VIEW, GtkContainer)
+G_DECLARE_FINAL_TYPE (GcalMonthView, gcal_month_view, GCAL, MONTH_VIEW, GtkWidget)
 
 G_END_DECLS
 
diff --git a/src/gui/views/gcal-month-view.ui b/src/gui/views/gcal-month-view.ui
index afb6977a..e043f446 100644
--- a/src/gui/views/gcal-month-view.ui
+++ b/src/gui/views/gcal-month-view.ui
@@ -1,20 +1,43 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
-  <template class="GcalMonthView" parent="GtkContainer">
+  <template class="GcalMonthView" parent="GtkWidget">
+
+    <child>
+      <object class="GtkGestureClick">
+        <property name="button">1</property>
+        <signal name="pressed" handler="on_click_gesture_pressed_cb" object="GcalMonthView" swapped="no" />
+        <signal name="released" handler="on_click_gesture_released_cb" object="GcalMonthView" swapped="no" />
+      </object>
+    </child>
+
+    <child>
+      <object class="GtkEventControllerMotion" id="motion_controller">
+        <property name="propagation-phase">none</property>
+        <signal name="motion" handler="on_motion_controller_motion_cb" object="GcalMonthView" swapped="no" />
+      </object>
+    </child>
+
+    <child>
+      <object class="GtkEventControllerKey">
+        <signal name="key-pressed" handler="on_key_controller_key_pressed_cb" object="GcalMonthView" 
swapped="no" />
+      </object>
+    </child>
+
+    <child>
+      <object class="GtkEventControllerScroll">
+        <property name="flags">vertical</property>
+        <signal name="scroll" handler="on_scroll_controller_scrolled_cb" object="GcalMonthView" swapped="no" 
/>
+      </object>
+    </child>
 
     <!-- Header -->
     <child type="header">
       <object class="GtkBox">
-        <property name="visible">true</property>
-        <property name="can_focus">false</property>
         <property name="orientation">vertical</property>
         <child>
           <object class="GtkBox">
-            <property name="visible">true</property>
             <child>
               <object class="GtkLabel" id="month_label">
-                <property name="visible">true</property>
-                <property name="can_focus">false</property>
                 <property name="hexpand">true</property>
                 <property name="xalign">0.0</property>
                 <style>
@@ -24,8 +47,6 @@
             </child>
             <child>
               <object class="GtkLabel" id="year_label">
-                <property name="visible">true</property>
-                <property name="can_focus">false</property>
                 <property name="hexpand">true</property>
                 <property name="xalign">1.0</property>
                 <style>
@@ -38,15 +59,12 @@
 
         <child>
           <object class="GtkBox">
-            <property name="visible">true</property>
             <property name="spacing">6</property>
             <property name="margin-start">6</property>
             <property name="margin-end">6</property>
             <property name="margin-bottom">6</property>
             <child>
               <object class="GtkLabel" id="label_0">
-                <property name="visible">true</property>
-                <property name="can_focus">false</property>
                 <property name="hexpand">true</property>
                 <property name="xalign">0.0</property>
                 <style>
@@ -57,8 +75,6 @@
 
             <child>
               <object class="GtkLabel" id="label_1">
-                <property name="visible">true</property>
-                <property name="can_focus">false</property>
                 <property name="hexpand">true</property>
                 <property name="xalign">0.0</property>
                 <style>
@@ -69,8 +85,6 @@
 
             <child>
               <object class="GtkLabel" id="label_2">
-                <property name="visible">true</property>
-                <property name="can_focus">false</property>
                 <property name="hexpand">true</property>
                 <property name="xalign">0.0</property>
                 <style>
@@ -81,8 +95,6 @@
 
             <child>
               <object class="GtkLabel" id="label_3">
-                <property name="visible">true</property>
-                <property name="can_focus">false</property>
                 <property name="hexpand">true</property>
                 <property name="xalign">0.0</property>
                 <style>
@@ -93,8 +105,6 @@
 
             <child>
               <object class="GtkLabel" id="label_4">
-                <property name="visible">true</property>
-                <property name="can_focus">false</property>
                 <property name="hexpand">true</property>
                 <property name="xalign">0.0</property>
                 <style>
@@ -105,8 +115,6 @@
 
             <child>
               <object class="GtkLabel" id="label_5">
-                <property name="visible">true</property>
-                <property name="can_focus">false</property>
                 <property name="hexpand">true</property>
                 <property name="xalign">0.0</property>
                 <style>
@@ -117,8 +125,6 @@
 
             <child>
               <object class="GtkLabel" id="label_6">
-                <property name="visible">true</property>
-                <property name="can_focus">false</property>
                 <property name="hexpand">true</property>
                 <property name="xalign">0.0</property>
                 <style>
@@ -135,8 +141,6 @@
     <!-- Grid -->
     <child type="grid">
       <object class="GtkGrid" id="grid">
-        <property name="visible">true</property>
-        <property name="can-focus">false</property>
         <property name="row-homogeneous">true</property>
         <property name="column-homogeneous">true</property>
       </object>
diff --git a/src/gui/views/gcal-view.c b/src/gui/views/gcal-view.c
index 5defdbab..46e8f087 100644
--- a/src/gui/views/gcal-view.c
+++ b/src/gui/views/gcal-view.c
@@ -40,7 +40,7 @@ gcal_view_default_init (GcalViewInterface *iface)
   g_object_interface_install_property (iface,
                                        g_param_spec_boxed ("active-date",
                                                            "The active date",
-                                                           "The active/selecetd date in the view",
+                                                           "The active/selected date in the view",
                                                            G_TYPE_DATE_TIME,
                                                            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
diff --git a/src/theme/Adwaita.css b/src/theme/Adwaita.css
index 93a6078d..d4183d64 100644
--- a/src/theme/Adwaita.css
+++ b/src/theme/Adwaita.css
@@ -16,7 +16,6 @@ label.secondary-label {
 }
 
 calendar-view {
-    padding: 6px;
     font-size: 10pt;
 }
 
diff --git a/src/utils/gcal-utils.c b/src/utils/gcal-utils.c
index a8ca0ba0..91d37e59 100644
--- a/src/utils/gcal-utils.c
+++ b/src/utils/gcal-utils.c
@@ -877,7 +877,7 @@ get_alarm_trigger_minutes (GcalEvent          *event,
 /**
  * should_change_date_for_scroll:
  * @scroll_value: the current scroll value
- * @scroll_event: the #GdkEventScroll that is being parsed
+ * @scroll_event: the #GdkEvent that is being parsed
  *
  * Utility function to check if the date should change based
  * on the scroll. The date is changed when the user scrolls
@@ -887,12 +887,14 @@ get_alarm_trigger_minutes (GcalEvent          *event,
  * Returns: %TRUE if the date should change, %FALSE otherwise.
  */
 gboolean
-should_change_date_for_scroll (gdouble        *scroll_value,
-                               GdkEventScroll *scroll_event)
+should_change_date_for_scroll (gdouble  *scroll_value,
+                               GdkEvent *scroll_event)
 {
-  gdouble delta_y;
+  gdouble dx, dy;
 
-  switch (scroll_event->direction)
+  g_return_val_if_fail (gdk_event_get_event_type (scroll_event) == GDK_SCROLL, FALSE);
+
+  switch (gdk_scroll_event_get_direction (scroll_event))
     {
     case GDK_SCROLL_DOWN:
       *scroll_value = SCROLL_HARDNESS;
@@ -903,8 +905,8 @@ should_change_date_for_scroll (gdouble        *scroll_value,
       break;
 
     case GDK_SCROLL_SMOOTH:
-      gdk_event_get_scroll_deltas ((GdkEvent*) scroll_event, NULL, &delta_y);
-      *scroll_value += delta_y;
+      gdk_scroll_event_get_deltas (scroll_event, &dx, &dy);
+      *scroll_value += dy;
       break;
 
     /* Ignore horizontal scrolling for now */
diff --git a/src/utils/gcal-utils.h b/src/utils/gcal-utils.h
index bc0eb3b6..cf94f2e7 100644
--- a/src/utils/gcal-utils.h
+++ b/src/utils/gcal-utils.h
@@ -106,7 +106,7 @@ gint                 get_alarm_trigger_minutes                   (GcalEvent
                                                                   ECalComponentAlarm *alarm);
 
 gboolean             should_change_date_for_scroll               (gdouble            *scroll_value,
-                                                                  GdkEventScroll     *scroll_event);
+                                                                  GdkEvent           *scroll_event);
 
 gboolean             is_source_enabled                           (ESource            *source);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]