Title: [277262] trunk/Source/WebKit
Revision
277262
Author
[email protected]
Date
2021-05-10 05:17:46 -0700 (Mon, 10 May 2021)

Log Message

[GTK] Add picker UI for <input type=date> and <input type=datetime-local>
https://bugs.webkit.org/show_bug.cgi?id=224924

Patch by Carlos Garcia Campos <[email protected]> on 2021-05-10
Reviewed by Adrian Perez de Castro.

Use a GtkPopover with a GtkCalendar.

* UIProcess/API/gtk/WebKitWebViewBase.cpp:
(webkitWebViewBaseSetFocus): Only notify the web process about focus changes when shouldNotifyFocusEvents is true.
(webkitWebViewBaseSetShouldNotifyFocusEvents): Set whether the web view should notify about focus changes to the
web process.
* UIProcess/API/gtk/WebKitWebViewBasePrivate.h:
* UIProcess/gtk/WebDateTimePickerGtk.cpp:
(WebKit::WebDateTimePickerGtk::~WebDateTimePickerGtk): Call invalidate instead of endPicker.
(WebKit::WebDateTimePickerGtk::invalidate): Destroy the popover and allow the web view to notify about focus
events again.
(WebKit::WebDateTimePickerGtk::endPicker): Invalidate and notify the parent.
(WebKit::timeToString): Helper to convert the time portions of a DateComponents to a string.
(WebKit::calendarDateToString): Helper to convert selected date to a string.
(WebKit::WebDateTimePickerGtk::didChooseDate): Notify the WebPageProxy about the selected date.
(WebKit::WebDateTimePickerGtk::showDateTimePicker): Create or update a GtkPopover with a calendar.
(WebKit::WebDateTimePickerGtk::update): Update the calendar and current date.
* UIProcess/gtk/WebDateTimePickerGtk.h:

Modified Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (277261 => 277262)


--- trunk/Source/WebKit/ChangeLog	2021-05-10 10:55:30 UTC (rev 277261)
+++ trunk/Source/WebKit/ChangeLog	2021-05-10 12:17:46 UTC (rev 277262)
@@ -1,5 +1,31 @@
 2021-05-10  Carlos Garcia Campos  <[email protected]>
 
+        [GTK] Add picker UI for <input type=date> and <input type=datetime-local>
+        https://bugs.webkit.org/show_bug.cgi?id=224924
+
+        Reviewed by Adrian Perez de Castro.
+
+        Use a GtkPopover with a GtkCalendar.
+
+        * UIProcess/API/gtk/WebKitWebViewBase.cpp:
+        (webkitWebViewBaseSetFocus): Only notify the web process about focus changes when shouldNotifyFocusEvents is true.
+        (webkitWebViewBaseSetShouldNotifyFocusEvents): Set whether the web view should notify about focus changes to the
+        web process.
+        * UIProcess/API/gtk/WebKitWebViewBasePrivate.h:
+        * UIProcess/gtk/WebDateTimePickerGtk.cpp:
+        (WebKit::WebDateTimePickerGtk::~WebDateTimePickerGtk): Call invalidate instead of endPicker.
+        (WebKit::WebDateTimePickerGtk::invalidate): Destroy the popover and allow the web view to notify about focus
+        events again.
+        (WebKit::WebDateTimePickerGtk::endPicker): Invalidate and notify the parent.
+        (WebKit::timeToString): Helper to convert the time portions of a DateComponents to a string.
+        (WebKit::calendarDateToString): Helper to convert selected date to a string.
+        (WebKit::WebDateTimePickerGtk::didChooseDate): Notify the WebPageProxy about the selected date.
+        (WebKit::WebDateTimePickerGtk::showDateTimePicker): Create or update a GtkPopover with a calendar.
+        (WebKit::WebDateTimePickerGtk::update): Update the calendar and current date.
+        * UIProcess/gtk/WebDateTimePickerGtk.h:
+
+2021-05-10  Carlos Garcia Campos  <[email protected]>
+
         [GTK] Use always async scrolling in accelerated compositing mode
         https://bugs.webkit.org/show_bug.cgi?id=225512
 

Modified: trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp (277261 => 277262)


--- trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp	2021-05-10 10:55:30 UTC (rev 277261)
+++ trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp	2021-05-10 12:17:46 UTC (rev 277262)
@@ -284,6 +284,7 @@
     IntSize contentsSize;
     Optional<MotionEvent> lastMotionEvent;
     bool isBlank;
+    bool shouldNotifyFocusEvents { true };
 
     GtkWindow* toplevelOnScreenWindow { nullptr };
 #if USE(GTK4)
@@ -2337,6 +2338,8 @@
 void webkitWebViewBaseSetFocus(WebKitWebViewBase* webViewBase, bool focused)
 {
     WebKitWebViewBasePrivate* priv = webViewBase->priv;
+    if (!priv->shouldNotifyFocusEvents)
+        return;
     if ((focused && priv->activityState & ActivityState::IsFocused) || (!focused && !(priv->activityState & ActivityState::IsFocused)))
         return;
 
@@ -2918,3 +2921,8 @@
     priv->pageGrabbedTouch = true;
     gtk_gesture_set_state(priv->touchGestureGroup, GTK_EVENT_SEQUENCE_DENIED);
 }
+
+void webkitWebViewBaseSetShouldNotifyFocusEvents(WebKitWebViewBase* webViewBase, bool shouldNotifyFocusEvents)
+{
+    webViewBase->priv->shouldNotifyFocusEvents = shouldNotifyFocusEvents;
+}

Modified: trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h (277261 => 277262)


--- trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h	2021-05-10 10:55:30 UTC (rev 277261)
+++ trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h	2021-05-10 12:17:46 UTC (rev 277262)
@@ -115,4 +115,5 @@
 void webkitWebViewBaseSynthesizeCompositionKeyPress(WebKitWebViewBase*, const String& text, Optional<Vector<WebCore::CompositionUnderline>>&&, Optional<WebKit::EditingRange>&&);
 
 void webkitWebViewBaseMakeBlank(WebKitWebViewBase*, bool);
-void webkitWebViewBasePageGrabbedTouch(WebKitWebViewBase* webkitWebViewBase);
+void webkitWebViewBasePageGrabbedTouch(WebKitWebViewBase*);
+void webkitWebViewBaseSetShouldNotifyFocusEvents(WebKitWebViewBase*, bool);

Modified: trunk/Source/WebKit/UIProcess/gtk/WebDateTimePickerGtk.cpp (277261 => 277262)


--- trunk/Source/WebKit/UIProcess/gtk/WebDateTimePickerGtk.cpp	2021-05-10 10:55:30 UTC (rev 277261)
+++ trunk/Source/WebKit/UIProcess/gtk/WebDateTimePickerGtk.cpp	2021-05-10 12:17:46 UTC (rev 277262)
@@ -27,11 +27,13 @@
 #include "config.h"
 #include "WebDateTimePickerGtk.h"
 
-#include <wtf/StackTrace.h>
-#include <wtf/StringPrintStream.h>
-
 #if ENABLE(DATE_AND_TIME_INPUT_TYPES)
 
+#include "WebKitWebViewBasePrivate.h"
+#include <gtk/gtk.h>
+#include <wtf/SetForScope.h>
+#include <wtf/glib/GRefPtr.h>
+
 namespace WebKit {
 
 Ref<WebDateTimePickerGtk> WebDateTimePickerGtk::create(WebPageProxy& page)
@@ -41,7 +43,7 @@
 
 WebDateTimePickerGtk::~WebDateTimePickerGtk()
 {
-    endPicker();
+    invalidate();
 }
 
 WebDateTimePickerGtk::WebDateTimePickerGtk(WebPageProxy& page)
@@ -49,14 +51,141 @@
 {
 }
 
+void WebDateTimePickerGtk::invalidate()
+{
+    if (!m_popover)
+        return;
+
+    g_signal_handlers_disconnect_by_data(m_popover, this);
+#if USE(GTK4)
+    auto* webView = gtk_widget_get_parent(m_popover);
+    gtk_widget_unparent(m_popover);
+#else
+    auto* webView = gtk_popover_get_relative_to(GTK_POPOVER(m_popover));
+    gtk_widget_destroy(m_popover);
+#endif
+    m_popover = nullptr;
+    m_calendar = nullptr;
+
+    webkitWebViewBaseSetShouldNotifyFocusEvents(WEBKIT_WEB_VIEW_BASE(webView), true);
+}
+
 void WebDateTimePickerGtk::endPicker()
 {
+    invalidate();
+    WebDateTimePicker::endPicker();
 }
 
+static String timeToString(const WebCore::DateComponents& time, WebCore::SecondFormat secondFormat)
+{
+    switch (secondFormat) {
+    case SecondFormat::None:
+        return makeString(pad('0', 2, time.hour()), ':', pad('0', 2, time.minute()));
+    case SecondFormat::Second:
+        return makeString(pad('0', 2, time.hour()), ':', pad('0', 2, time.minute()), ':', pad('0', 2, time.second()));
+    case SecondFormat::Millisecond:
+        return makeString(pad('0', 2, time.hour()), ':', pad('0', 2, time.minute()), ':', pad('0', 2, time.second()), '.', pad('0', 3, time.millisecond()));
+    }
+
+    ASSERT_NOT_REACHED();
+    return { };
+}
+
+static String calendarDateToString(int year, int month, int day, const Optional<WebCore::DateComponents>& date, WebCore::SecondFormat secondFormat)
+{
+    auto type = date ? date->type() : WebCore::DateComponentsType::Date;
+    switch (type) {
+    case WebCore::DateComponentsType::Date:
+        return makeString(pad('0', 4, year), '-', pad('0', 2, month + 1), '-', pad('0', 2, day));
+    case WebCore::DateComponentsType::DateTimeLocal:
+        return makeString(pad('0', 4, year), '-', pad('0', 2, month + 1), '-', pad('0', 2, day), 'T', timeToString(*date, secondFormat));
+    case WebCore::DateComponentsType::Invalid:
+    case WebCore::DateComponentsType::Month:
+    case WebCore::DateComponentsType::Time:
+    case WebCore::DateComponentsType::Week:
+        break;
+    }
+
+    ASSERT_NOT_REACHED();
+    return { };
+}
+
+void WebDateTimePickerGtk::didChooseDate()
+{
+    if (m_inUpdate)
+        return;
+
+    if (!m_page)
+        return;
+
+    int year, month, day;
+    g_object_get(m_calendar, "year", &year, "month", &month, "day", &day, nullptr);
+    m_page->didChooseDate(calendarDateToString(year, month, day, m_currentDate, m_secondFormat));
+}
+
 void WebDateTimePickerGtk::showDateTimePicker(WebCore::DateTimeChooserParameters&& params)
 {
+    if (m_popover) {
+        update(WTFMove(params));
+        return;
+    }
+
+    auto* webView = m_page->viewWidget();
+    webkitWebViewBaseSetShouldNotifyFocusEvents(WEBKIT_WEB_VIEW_BASE(webView), false);
+
+#if USE(GTK4)
+    m_popover = gtk_popover_new();
+    gtk_popover_set_has_arrow(GTK_POPOVER(m_popover), FALSE);
+    gtk_widget_set_parent(m_popover, webView);
+#else
+    m_popover = gtk_popover_new(webView);
+#endif
+    gtk_popover_set_position(GTK_POPOVER(m_popover), GTK_POS_BOTTOM);
+    GdkRectangle rectInRootView = params.anchorRectInRootView;
+    gtk_popover_set_pointing_to(GTK_POPOVER(m_popover), &rectInRootView);
+    g_signal_connect_swapped(m_popover, "closed", G_CALLBACK(+[](WebDateTimePickerGtk* picker) {
+        picker->endPicker();
+    }), this);
+
+    m_calendar = gtk_calendar_new();
+    g_signal_connect(m_calendar, "day-selected", G_CALLBACK(+[](GtkCalendar* calendar, WebDateTimePickerGtk* picker) {
+        picker->didChooseDate();
+    }), this);
+#if USE(GTK4)
+    gtk_popover_set_child(GTK_POPOVER(m_popover), m_calendar);
+#else
+    gtk_container_add(GTK_CONTAINER(m_popover), m_calendar);
+    gtk_widget_show(m_calendar);
+#endif
+
+    update(WTFMove(params));
+
+    gtk_popover_popup(GTK_POPOVER(m_popover));
 }
 
+void WebDateTimePickerGtk::update(WebCore::DateTimeChooserParameters&& params)
+{
+    SetForScope<bool> inUpdate(m_inUpdate, true);
+    if (params.type == "date")
+        m_currentDate = WebCore::DateComponents::fromParsingDate(params.currentValue);
+    else if (params.type == "datetime-local")
+        m_currentDate = WebCore::DateComponents::fromParsingDateTimeLocal(params.currentValue);
+
+    if (m_currentDate)
+        g_object_set(m_calendar, "year", m_currentDate->fullYear(), "month", m_currentDate->month(), "day", m_currentDate->monthDay(), nullptr);
+    else if (params.type == "datetime-local") {
+        GRefPtr<GDateTime> now = adoptGRef(g_date_time_new_now_local());
+        Seconds unixTime = Seconds(g_date_time_to_unix(now.get())) + Seconds::fromMicroseconds(g_date_time_get_utc_offset(now.get()));
+        m_currentDate = WebCore::DateComponents::fromMillisecondsSinceEpochForDateTimeLocal(unixTime.milliseconds());
+        if (params.hasMillisecondField)
+            m_secondFormat = WebCore::SecondFormat::Millisecond;
+        else if (params.hasSecondField)
+            m_secondFormat = WebCore::SecondFormat::Second;
+        else
+            m_secondFormat = WebCore::SecondFormat::None;
+    }
+}
+
 } // namespace WebKit
 
 #endif // ENABLE(DATE_AND_TIME_INPUT_TYPES)

Modified: trunk/Source/WebKit/UIProcess/gtk/WebDateTimePickerGtk.h (277261 => 277262)


--- trunk/Source/WebKit/UIProcess/gtk/WebDateTimePickerGtk.h	2021-05-10 10:55:30 UTC (rev 277261)
+++ trunk/Source/WebKit/UIProcess/gtk/WebDateTimePickerGtk.h	2021-05-10 12:17:46 UTC (rev 277262)
@@ -29,6 +29,7 @@
 #if ENABLE(DATE_AND_TIME_INPUT_TYPES)
 
 #include "WebDateTimePicker.h"
+#include <WebCore/DateComponents.h>
 #include <WebCore/DateTimeChooserParameters.h>
 
 namespace WebKit {
@@ -43,6 +44,16 @@
 
     void endPicker() final;
     void showDateTimePicker(WebCore::DateTimeChooserParameters&&) final;
+
+    void update(WebCore::DateTimeChooserParameters&&);
+    void didChooseDate();
+    void invalidate();
+
+    GtkWidget* m_popover { nullptr };
+    GtkWidget* m_calendar { nullptr };
+    Optional<WebCore::DateComponents> m_currentDate;
+    WebCore::SecondFormat m_secondFormat { WebCore::SecondFormat::None };
+    bool m_inUpdate { false };
 };
 
 } // namespace WebKit
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to