⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 277262 in webkit


Ignore:
Timestamp:
May 10, 2021, 5:17:46 AM (5 years ago)
Author:
commit-queue@webkit.org
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 <cgarcia@igalia.com> 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:
Location:
trunk/Source/WebKit
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebKit/ChangeLog

    r277258 r277262  
     12021-05-10  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [GTK] Add picker UI for <input type=date> and <input type=datetime-local>
     4        https://bugs.webkit.org/show_bug.cgi?id=224924
     5
     6        Reviewed by Adrian Perez de Castro.
     7
     8        Use a GtkPopover with a GtkCalendar.
     9
     10        * UIProcess/API/gtk/WebKitWebViewBase.cpp:
     11        (webkitWebViewBaseSetFocus): Only notify the web process about focus changes when shouldNotifyFocusEvents is true.
     12        (webkitWebViewBaseSetShouldNotifyFocusEvents): Set whether the web view should notify about focus changes to the
     13        web process.
     14        * UIProcess/API/gtk/WebKitWebViewBasePrivate.h:
     15        * UIProcess/gtk/WebDateTimePickerGtk.cpp:
     16        (WebKit::WebDateTimePickerGtk::~WebDateTimePickerGtk): Call invalidate instead of endPicker.
     17        (WebKit::WebDateTimePickerGtk::invalidate): Destroy the popover and allow the web view to notify about focus
     18        events again.
     19        (WebKit::WebDateTimePickerGtk::endPicker): Invalidate and notify the parent.
     20        (WebKit::timeToString): Helper to convert the time portions of a DateComponents to a string.
     21        (WebKit::calendarDateToString): Helper to convert selected date to a string.
     22        (WebKit::WebDateTimePickerGtk::didChooseDate): Notify the WebPageProxy about the selected date.
     23        (WebKit::WebDateTimePickerGtk::showDateTimePicker): Create or update a GtkPopover with a calendar.
     24        (WebKit::WebDateTimePickerGtk::update): Update the calendar and current date.
     25        * UIProcess/gtk/WebDateTimePickerGtk.h:
     26
    1272021-05-10  Carlos Garcia Campos  <cgarcia@igalia.com>
    228
  • trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp

    r277172 r277262  
    285285    Optional<MotionEvent> lastMotionEvent;
    286286    bool isBlank;
     287    bool shouldNotifyFocusEvents { true };
    287288
    288289    GtkWindow* toplevelOnScreenWindow { nullptr };
     
    23382339{
    23392340    WebKitWebViewBasePrivate* priv = webViewBase->priv;
     2341    if (!priv->shouldNotifyFocusEvents)
     2342        return;
    23402343    if ((focused && priv->activityState & ActivityState::IsFocused) || (!focused && !(priv->activityState & ActivityState::IsFocused)))
    23412344        return;
     
    29192922    gtk_gesture_set_state(priv->touchGestureGroup, GTK_EVENT_SEQUENCE_DENIED);
    29202923}
     2924
     2925void webkitWebViewBaseSetShouldNotifyFocusEvents(WebKitWebViewBase* webViewBase, bool shouldNotifyFocusEvents)
     2926{
     2927    webViewBase->priv->shouldNotifyFocusEvents = shouldNotifyFocusEvents;
     2928}
  • trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h

    r277172 r277262  
    116116
    117117void webkitWebViewBaseMakeBlank(WebKitWebViewBase*, bool);
    118 void webkitWebViewBasePageGrabbedTouch(WebKitWebViewBase* webkitWebViewBase);
     118void webkitWebViewBasePageGrabbedTouch(WebKitWebViewBase*);
     119void webkitWebViewBaseSetShouldNotifyFocusEvents(WebKitWebViewBase*, bool);
  • trunk/Source/WebKit/UIProcess/gtk/WebDateTimePickerGtk.cpp

    r276448 r277262  
    2828#include "WebDateTimePickerGtk.h"
    2929
    30 #include <wtf/StackTrace.h>
    31 #include <wtf/StringPrintStream.h>
     30#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
    3231
    33 #if ENABLE(DATE_AND_TIME_INPUT_TYPES)
     32#include "WebKitWebViewBasePrivate.h"
     33#include <gtk/gtk.h>
     34#include <wtf/SetForScope.h>
     35#include <wtf/glib/GRefPtr.h>
    3436
    3537namespace WebKit {
     
    4244WebDateTimePickerGtk::~WebDateTimePickerGtk()
    4345{
    44     endPicker();
     46    invalidate();
    4547}
    4648
     
    5052}
    5153
     54void WebDateTimePickerGtk::invalidate()
     55{
     56    if (!m_popover)
     57        return;
     58
     59    g_signal_handlers_disconnect_by_data(m_popover, this);
     60#if USE(GTK4)
     61    auto* webView = gtk_widget_get_parent(m_popover);
     62    gtk_widget_unparent(m_popover);
     63#else
     64    auto* webView = gtk_popover_get_relative_to(GTK_POPOVER(m_popover));
     65    gtk_widget_destroy(m_popover);
     66#endif
     67    m_popover = nullptr;
     68    m_calendar = nullptr;
     69
     70    webkitWebViewBaseSetShouldNotifyFocusEvents(WEBKIT_WEB_VIEW_BASE(webView), true);
     71}
     72
    5273void WebDateTimePickerGtk::endPicker()
    5374{
     75    invalidate();
     76    WebDateTimePicker::endPicker();
     77}
     78
     79static String timeToString(const WebCore::DateComponents& time, WebCore::SecondFormat secondFormat)
     80{
     81    switch (secondFormat) {
     82    case SecondFormat::None:
     83        return makeString(pad('0', 2, time.hour()), ':', pad('0', 2, time.minute()));
     84    case SecondFormat::Second:
     85        return makeString(pad('0', 2, time.hour()), ':', pad('0', 2, time.minute()), ':', pad('0', 2, time.second()));
     86    case SecondFormat::Millisecond:
     87        return makeString(pad('0', 2, time.hour()), ':', pad('0', 2, time.minute()), ':', pad('0', 2, time.second()), '.', pad('0', 3, time.millisecond()));
     88    }
     89
     90    ASSERT_NOT_REACHED();
     91    return { };
     92}
     93
     94static String calendarDateToString(int year, int month, int day, const Optional<WebCore::DateComponents>& date, WebCore::SecondFormat secondFormat)
     95{
     96    auto type = date ? date->type() : WebCore::DateComponentsType::Date;
     97    switch (type) {
     98    case WebCore::DateComponentsType::Date:
     99        return makeString(pad('0', 4, year), '-', pad('0', 2, month + 1), '-', pad('0', 2, day));
     100    case WebCore::DateComponentsType::DateTimeLocal:
     101        return makeString(pad('0', 4, year), '-', pad('0', 2, month + 1), '-', pad('0', 2, day), 'T', timeToString(*date, secondFormat));
     102    case WebCore::DateComponentsType::Invalid:
     103    case WebCore::DateComponentsType::Month:
     104    case WebCore::DateComponentsType::Time:
     105    case WebCore::DateComponentsType::Week:
     106        break;
     107    }
     108
     109    ASSERT_NOT_REACHED();
     110    return { };
     111}
     112
     113void WebDateTimePickerGtk::didChooseDate()
     114{
     115    if (m_inUpdate)
     116        return;
     117
     118    if (!m_page)
     119        return;
     120
     121    int year, month, day;
     122    g_object_get(m_calendar, "year", &year, "month", &month, "day", &day, nullptr);
     123    m_page->didChooseDate(calendarDateToString(year, month, day, m_currentDate, m_secondFormat));
    54124}
    55125
    56126void WebDateTimePickerGtk::showDateTimePicker(WebCore::DateTimeChooserParameters&& params)
    57127{
     128    if (m_popover) {
     129        update(WTFMove(params));
     130        return;
     131    }
     132
     133    auto* webView = m_page->viewWidget();
     134    webkitWebViewBaseSetShouldNotifyFocusEvents(WEBKIT_WEB_VIEW_BASE(webView), false);
     135
     136#if USE(GTK4)
     137    m_popover = gtk_popover_new();
     138    gtk_popover_set_has_arrow(GTK_POPOVER(m_popover), FALSE);
     139    gtk_widget_set_parent(m_popover, webView);
     140#else
     141    m_popover = gtk_popover_new(webView);
     142#endif
     143    gtk_popover_set_position(GTK_POPOVER(m_popover), GTK_POS_BOTTOM);
     144    GdkRectangle rectInRootView = params.anchorRectInRootView;
     145    gtk_popover_set_pointing_to(GTK_POPOVER(m_popover), &rectInRootView);
     146    g_signal_connect_swapped(m_popover, "closed", G_CALLBACK(+[](WebDateTimePickerGtk* picker) {
     147        picker->endPicker();
     148    }), this);
     149
     150    m_calendar = gtk_calendar_new();
     151    g_signal_connect(m_calendar, "day-selected", G_CALLBACK(+[](GtkCalendar* calendar, WebDateTimePickerGtk* picker) {
     152        picker->didChooseDate();
     153    }), this);
     154#if USE(GTK4)
     155    gtk_popover_set_child(GTK_POPOVER(m_popover), m_calendar);
     156#else
     157    gtk_container_add(GTK_CONTAINER(m_popover), m_calendar);
     158    gtk_widget_show(m_calendar);
     159#endif
     160
     161    update(WTFMove(params));
     162
     163    gtk_popover_popup(GTK_POPOVER(m_popover));
     164}
     165
     166void WebDateTimePickerGtk::update(WebCore::DateTimeChooserParameters&& params)
     167{
     168    SetForScope<bool> inUpdate(m_inUpdate, true);
     169    if (params.type == "date")
     170        m_currentDate = WebCore::DateComponents::fromParsingDate(params.currentValue);
     171    else if (params.type == "datetime-local")
     172        m_currentDate = WebCore::DateComponents::fromParsingDateTimeLocal(params.currentValue);
     173
     174    if (m_currentDate)
     175        g_object_set(m_calendar, "year", m_currentDate->fullYear(), "month", m_currentDate->month(), "day", m_currentDate->monthDay(), nullptr);
     176    else if (params.type == "datetime-local") {
     177        GRefPtr<GDateTime> now = adoptGRef(g_date_time_new_now_local());
     178        Seconds unixTime = Seconds(g_date_time_to_unix(now.get())) + Seconds::fromMicroseconds(g_date_time_get_utc_offset(now.get()));
     179        m_currentDate = WebCore::DateComponents::fromMillisecondsSinceEpochForDateTimeLocal(unixTime.milliseconds());
     180        if (params.hasMillisecondField)
     181            m_secondFormat = WebCore::SecondFormat::Millisecond;
     182        else if (params.hasSecondField)
     183            m_secondFormat = WebCore::SecondFormat::Second;
     184        else
     185            m_secondFormat = WebCore::SecondFormat::None;
     186    }
    58187}
    59188
  • trunk/Source/WebKit/UIProcess/gtk/WebDateTimePickerGtk.h

    r276448 r277262  
    3030
    3131#include "WebDateTimePicker.h"
     32#include <WebCore/DateComponents.h>
    3233#include <WebCore/DateTimeChooserParameters.h>
    3334
     
    4445    void endPicker() final;
    4546    void showDateTimePicker(WebCore::DateTimeChooserParameters&&) final;
     47
     48    void update(WebCore::DateTimeChooserParameters&&);
     49    void didChooseDate();
     50    void invalidate();
     51
     52    GtkWidget* m_popover { nullptr };
     53    GtkWidget* m_calendar { nullptr };
     54    Optional<WebCore::DateComponents> m_currentDate;
     55    WebCore::SecondFormat m_secondFormat { WebCore::SecondFormat::None };
     56    bool m_inUpdate { false };
    4657};
    4758
Note: See TracChangeset for help on using the changeset viewer.