+2012-02-20 Philippe Normand <pnormand@igalia.com>
+
+ [GTK] FullScreen signals
+ https://bugs.webkit.org/show_bug.cgi?id=76181
+
+ Reviewed by Martin Robinson.
+
+ Added entering-fullscreen and leaving-fullscreen signals, meant to
+ be used by the user agent to be notified when an element requests
+ full screen display and when the full screen display is to be
+ disabled.
+
+ * WebCoreSupport/ChromeClientGtk.cpp:
+ (WebKit::ChromeClient::supportsFullScreenForElement):
+ (WebKit::onFullscreenGtkKeyPressEvent):
+ (WebKit::ChromeClient::cancelFullScreen):
+ (WebKit::ChromeClient::enterFullScreenForElement):
+ (WebKit::ChromeClient::exitFullScreenForElement):
+ * WebCoreSupport/ChromeClientGtk.h:
+ * tests/testwebview.c:
+ * webkit/webkitwebview.cpp:
+ (webkit_web_view_real_entering_fullscreen):
+ (webkit_web_view_real_leaving_fullscreen):
+ (webkit_web_view_class_init):
+ * webkit/webkitwebview.h:
+
2012-02-22 Ryosuke Niwa <rniwa@webkit.org>
Remove the remaining uses of CSSStyleDeclaration in Editor
#include "RefPtrCairo.h"
#include "SearchPopupMenuGtk.h"
#include "SecurityOrigin.h"
+#include "WebKitDOMBinding.h"
+#include "WebKitDOMHTMLElementPrivate.h"
#include "WindowFeatures.h"
#include "webkitgeolocationpolicydecision.h"
#include "webkitgeolocationpolicydecisionprivate.h"
#include "webkitwebview.h"
#include "webkitwebviewprivate.h"
#include "webkitwebwindowfeaturesprivate.h"
+#include <gdk/gdk.h>
+#include <gdk/gdkkeysyms.h>
#include <glib.h>
#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>
#if ENABLE(FULLSCREEN_API)
bool ChromeClient::supportsFullScreenForElement(const WebCore::Element* element, bool withKeyboard)
{
- return true;
+ return !withKeyboard;
+}
+
+static gboolean onFullscreenGtkKeyPressEvent(GtkWidget* widget, GdkEventKey* event, ChromeClient* chromeClient)
+{
+ switch (event->keyval) {
+ case GDK_KEY_Escape:
+ case GDK_KEY_f:
+ case GDK_KEY_F:
+ chromeClient->cancelFullScreen();
+ return TRUE;
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+void ChromeClient::cancelFullScreen()
+{
+ ASSERT(m_fullScreenElement);
+ m_fullScreenElement->document()->webkitCancelFullScreen();
}
void ChromeClient::enterFullScreenForElement(WebCore::Element* element)
{
+ gboolean returnValue;
+ GRefPtr<WebKitDOMHTMLElement> kitElement(adoptGRef(kit(reinterpret_cast<HTMLElement*>(element))));
+ g_signal_emit_by_name(m_webView, "entering-fullscreen", kitElement.get(), &returnValue);
+ if (returnValue)
+ return;
+
+ GtkWidget* window = gtk_widget_get_toplevel(GTK_WIDGET(m_webView));
+ if (!widgetIsOnscreenToplevelWindow(window))
+ return;
+
+ g_signal_connect(window, "key-press-event", G_CALLBACK(onFullscreenGtkKeyPressEvent), this);
+
+ m_fullScreenElement = adoptRef(element);
+
element->document()->webkitWillEnterFullScreenForElement(element);
m_adjustmentWatcher.disableAllScrollbars();
-#if ENABLE(VIDEO)
- if (element->tagName() == "VIDEO")
- enterFullscreenForNode(static_cast<Node*>(element));
-#endif
+ gtk_window_fullscreen(GTK_WINDOW(window));
element->document()->webkitDidEnterFullScreenForElement(element);
}
void ChromeClient::exitFullScreenForElement(WebCore::Element* element)
{
+ gboolean returnValue;
+ GRefPtr<WebKitDOMHTMLElement> kitElement(adoptGRef(kit(reinterpret_cast<HTMLElement*>(element))));
+ g_signal_emit_by_name(m_webView, "leaving-fullscreen", kitElement.get(), &returnValue);
+ if (returnValue)
+ return;
+
+ GtkWidget* window = gtk_widget_get_toplevel(GTK_WIDGET(m_webView));
+ ASSERT(widgetIsOnscreenToplevelWindow(window));
+ g_signal_handlers_disconnect_by_func(window, reinterpret_cast<void*>(onFullscreenGtkKeyPressEvent), this);
+
element->document()->webkitWillExitFullScreenForElement(element);
+ gtk_window_unfullscreen(GTK_WINDOW(window));
m_adjustmentWatcher.enableAllScrollbars();
-#if ENABLE(VIDEO)
- if (element->tagName() == "VIDEO")
- webViewExitFullscreen(m_webView);
-#endif
element->document()->webkitDidExitFullScreenForElement(element);
+ m_fullScreenElement.clear();
}
#endif
virtual bool supportsFullScreenForElement(const Element*, bool withKeyboard);
virtual void enterFullScreenForElement(Element*);
virtual void exitFullScreenForElement(Element*);
+ void cancelFullScreen();
#endif
virtual bool shouldRubberBandInDirection(ScrollDirection) const { return true; }
unsigned int m_repaintSoonSourceId;
void invalidateWidgetRect(const IntRect&);
+#if ENABLE(FULLSCREEN_API)
+ RefPtr<Element> m_fullScreenElement;
+#endif
};
}
g_main_loop_unref(loop);
}
+static gboolean emitKeyStroke(WebKitWebView* webView)
+{
+ GdkEvent* pressEvent = gdk_event_new(GDK_KEY_PRESS);
+ pressEvent->key.keyval = GDK_KEY_f;
+ GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(webView));
+ pressEvent->key.window = window;
+ g_object_ref(pressEvent->key.window);
+
+ GdkDeviceManager* manager = gdk_display_get_device_manager(gdk_window_get_display(window));
+ gdk_event_set_device(pressEvent, gdk_device_manager_get_client_pointer(manager));
+
+ // When synthesizing an event, an invalid hardware_keycode value
+ // can cause it to be badly processed by Gtk+.
+ GdkKeymapKey* keys;
+ gint n_keys;
+ if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), GDK_KEY_f, &keys, &n_keys)) {
+ pressEvent->key.hardware_keycode = keys[0].keycode;
+ g_free(keys);
+ }
+
+ GdkEvent* releaseEvent = gdk_event_copy(pressEvent);
+ gtk_main_do_event(pressEvent);
+ gdk_event_free(pressEvent);
+ releaseEvent->key.type = GDK_KEY_RELEASE;
+ gtk_main_do_event(releaseEvent);
+ gdk_event_free(releaseEvent);
+
+ return FALSE;
+}
+
+static gboolean entering_fullscreen_cb(WebKitWebView* webView, GObject* element, gboolean blocked)
+{
+ if (blocked)
+ g_main_loop_quit(loop);
+ else
+ g_timeout_add(200, (GSourceFunc) emitKeyStroke, webView);
+ return blocked;
+}
+
+static gboolean leaving_fullscreen_cb(WebKitWebView* webView, GObject* element, gpointer data)
+{
+ g_main_loop_quit(loop);
+ return FALSE;
+}
+
+static void test_webkit_web_view_fullscreen(gconstpointer blocked)
+{
+ GtkWidget* window;
+ GtkWidget* web_view;
+ WebKitWebSettings *settings;
+
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ web_view = webkit_web_view_new();
+
+ settings = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(web_view));
+ g_object_set(settings, "enable-fullscreen", TRUE, NULL);
+ webkit_web_view_set_settings(WEBKIT_WEB_VIEW(web_view), settings);
+
+ gtk_container_add(GTK_CONTAINER(window), web_view);
+
+ gtk_widget_show_all(window);
+
+ loop = g_main_loop_new(NULL, TRUE);
+
+ g_signal_connect(web_view, "entering-fullscreen", G_CALLBACK(entering_fullscreen_cb), (gpointer) blocked);
+ g_signal_connect(web_view, "leaving-fullscreen", G_CALLBACK(leaving_fullscreen_cb), NULL);
+
+ webkit_web_view_load_string(WEBKIT_WEB_VIEW(web_view), "<html><body>"
+ "<script>"
+ "var eventName = 'keypress';"
+ "document.addEventListener(eventName, function () {"
+ " document.documentElement.webkitRequestFullScreen();"
+ "}, false);"
+ "</script></body></html>", NULL, NULL, NULL);
+
+ g_timeout_add(100, (GSourceFunc) emitKeyStroke, WEBKIT_WEB_VIEW(web_view));
+ g_main_loop_run(loop);
+
+ gtk_widget_destroy(window);
+}
+
int main(int argc, char** argv)
{
SoupServer* server;
g_test_add_func("/webkit/webview/window-features", test_webkit_web_view_window_features);
g_test_add_func("/webkit/webview/webview-in-offscreen-window-does-not-crash", test_webkit_web_view_in_offscreen_window_does_not_crash);
g_test_add_func("/webkit/webview/webview-does-not-steal-focus", test_webkit_web_view_does_not_steal_focus);
+ g_test_add_data_func("/webkit/webview/fullscreen", GINT_TO_POINTER(FALSE), test_webkit_web_view_fullscreen);
+ g_test_add_data_func("/webkit/webview/fullscreen-blocked", GINT_TO_POINTER(TRUE), test_webkit_web_view_fullscreen);
return g_test_run ();
}
RESOURCE_LOAD_FINISHED,
RESOURCE_CONTENT_LENGTH_RECEIVED,
RESOURCE_LOAD_FAILED,
+ ENTERING_FULLSCREEN,
+ LEAVING_FULLSCREEN,
LAST_SIGNAL
};
return TRUE;
}
+static gboolean webkit_web_view_real_entering_fullscreen(WebKitWebView* webView)
+{
+ return FALSE;
+}
+
+static gboolean webkit_web_view_real_leaving_fullscreen(WebKitWebView* webView)
+{
+ return FALSE;
+}
+
static void webkit_web_view_dispose(GObject* object)
{
WebKitWebView* webView = WEBKIT_WEB_VIEW(object);
G_TYPE_NONE, 1,
WEBKIT_TYPE_VIEWPORT_ATTRIBUTES);
+ /**
+ * WebKitWebView::entering-fullscreen:
+ * @web_view: the #WebKitWebView on which the signal is emitted.
+ * @element: the #WebKitDOMHTMLElement which has requested full screen display.
+ *
+ * Emitted when JavaScript code calls
+ * <function>element.webkitRequestFullScreen</function>. If the
+ * signal is not handled the WebView will proceed to full screen
+ * its top level window. This signal can be used by client code to
+ * request permission to the user prior doing the full screen
+ * transition and eventually prepare the top-level window
+ * (e.g. hide some widgets that would otherwise be part of the
+ * full screen window).
+ *
+ * Returns: %TRUE to stop other handlers from being invoked for the event.
+ * %FALSE to continue emission of the event.
+ *
+ * Since: 1.9.0
+ */
+ webkit_web_view_signals[ENTERING_FULLSCREEN] =
+ g_signal_new("entering-fullscreen",
+ G_TYPE_FROM_CLASS(webViewClass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(WebKitWebViewClass, entering_fullscreen),
+ g_signal_accumulator_true_handled, 0,
+ webkit_marshal_BOOLEAN__OBJECT,
+ G_TYPE_BOOLEAN, 1, WEBKIT_TYPE_DOM_HTML_ELEMENT);
+
+
+ /**
+ * WebKitWebView::leaving-fullscreen:
+ * @web_view: the #WebKitWebView on which the signal is emitted.
+ * @element: the #WebKitDOMHTMLElement which is currently displayed full screen.
+ *
+ * Emitted when the WebView is about to restore its top level
+ * window out of its full screen state. This signal can be used by
+ * client code to restore widgets hidden during the
+ * entering-fullscreen stage for instance.
+ *
+ * Returns: %TRUE to stop other handlers from being invoked for the event.
+ * %FALSE to continue emission of the event.
+ *
+ * Since: 1.9.0
+ */
+ webkit_web_view_signals[LEAVING_FULLSCREEN] =
+ g_signal_new("leaving-fullscreen",
+ G_TYPE_FROM_CLASS(webViewClass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(WebKitWebViewClass, leaving_fullscreen),
+ g_signal_accumulator_true_handled, 0,
+ webkit_marshal_BOOLEAN__OBJECT,
+ G_TYPE_BOOLEAN, 1, WEBKIT_TYPE_DOM_HTML_ELEMENT);
+
/*
* WebKitWebView::resource-response-received
* @webView: the object which received the signal
webViewClass->redo = webkit_web_view_real_redo;
webViewClass->move_cursor = webkit_web_view_real_move_cursor;
webViewClass->should_allow_editing_action = webkit_web_view_real_should_allow_editing_action;
+ webViewClass->entering_fullscreen = webkit_web_view_real_entering_fullscreen;
+ webViewClass->leaving_fullscreen = webkit_web_view_real_leaving_fullscreen;
GObjectClass* objectClass = G_OBJECT_CLASS(webViewClass);
objectClass->dispose = webkit_web_view_dispose;
void (* undo) (WebKitWebView *web_view);
void (* redo) (WebKitWebView *web_view);
gboolean (* should_allow_editing_action) (WebKitWebView *web_view);
+ gboolean (* entering_fullscreen) (WebKitWebView *web_view);
+ gboolean (* leaving_fullscreen) (WebKitWebView *web_view);
/* Padding for future expansion */
void (*_webkit_reserved0) (void);
- void (*_webkit_reserved1) (void);
- void (*_webkit_reserved2) (void);
};
WEBKIT_API GType
+2012-02-20 Philippe Normand <pnormand@igalia.com>
+
+ [GTK] FullScreen signals
+ https://bugs.webkit.org/show_bug.cgi?id=76181
+
+ Reviewed by Martin Robinson.
+
+ Use the two new entering/leaving fullscreen signals to hide/show
+ the tool bar, the status bar and ask the user's permission before
+ entering fullscreen.
+
+ * GtkLauncher/main.c:
+ (webViewFullscreenMessageWindowClose):
+ (webViewWindowStateEvent):
+ (hide_widget):
+ (show_widget):
+ (webViewEnteringFullScreen):
+ (webViewLeavingFullScreen):
+ (createBrowser):
+ (createWindow):
+
2012-02-22 Rob Flack <flackr@chromium.org>
Update Linux ChromiumOS builders in flakiness dashboard.
return TRUE;
}
-static GtkWidget* createBrowser(GtkWidget* window, GtkWidget* uriEntry, GtkWidget* statusbar, WebKitWebView* webView)
+static gboolean webViewFullscreenMessageWindowClose(GtkWidget *dialog)
+{
+ if (GTK_IS_WIDGET(dialog))
+ gtk_widget_destroy(dialog);
+ return FALSE;
+}
+
+static gboolean webViewWindowStateEvent(GtkWidget *widget, GdkEventWindowState *event, WebKitWebView *webView)
+{
+ if (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) {
+ WebKitWebFrame *frame = webkit_web_view_get_main_frame(webView);
+ const gchar *uri = webkit_web_frame_get_uri(frame);
+ GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(webView));
+ if (!gtk_widget_is_toplevel(window) || !GTK_IS_WINDOW(window) || GTK_IS_OFFSCREEN_WINDOW(window))
+ window = 0;
+
+ GtkWidget *dialog = gtk_message_dialog_new(window ? GTK_WINDOW(window) : 0,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_CLOSE,
+ "%s is now full screen. Press ESC or f to exit.", uri);
+ g_signal_connect_swapped(dialog, "response", G_CALLBACK(gtk_widget_destroy), dialog);
+ g_timeout_add(1500, (GSourceFunc) webViewFullscreenMessageWindowClose, dialog);
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ }
+ return TRUE;
+}
+
+static void hideWidget(GtkWidget* widget, gpointer data)
+{
+ if (!GTK_IS_SCROLLED_WINDOW(widget))
+ gtk_widget_hide(widget);
+}
+
+static void showWidget(GtkWidget* widget, gpointer data)
+{
+ if (!GTK_IS_SCROLLED_WINDOW(widget))
+ gtk_widget_show(widget);
+}
+
+static gboolean webViewEnteringFullScreen(WebKitWebView *webView, GObject *element, GtkWidget* vbox)
+{
+ WebKitWebFrame *frame = webkit_web_view_get_main_frame(webView);
+ const gchar *uri = webkit_web_frame_get_uri(frame);
+ GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(webView));
+ if (!gtk_widget_is_toplevel(window) || !GTK_IS_WINDOW(window) || GTK_IS_OFFSCREEN_WINDOW(window))
+ window = 0;
+
+ GtkWidget *dialog = gtk_message_dialog_new(window ? GTK_WINDOW(window) : 0,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_YES_NO,
+ "Allow full screen display of %s ?", uri);
+ gint result = gtk_dialog_run(GTK_DIALOG(dialog));
+ if (result == GTK_RESPONSE_YES) {
+ gtk_container_foreach(GTK_CONTAINER(vbox), (GtkCallback) hideWidget, NULL);
+ gtk_widget_destroy(GTK_WIDGET(dialog));
+ return FALSE;
+ }
+ gtk_widget_destroy(GTK_WIDGET(dialog));
+ return TRUE;
+}
+
+static gboolean webViewLeavingFullScreen(WebKitWebView *webView, GObject *element, GtkWidget* vbox)
+{
+ GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(webView));
+ if (gtk_widget_is_toplevel(window) && GTK_IS_WINDOW(window) && !GTK_IS_OFFSCREEN_WINDOW(window))
+ g_signal_handlers_disconnect_by_func(window, G_CALLBACK(webViewWindowStateEvent), webView);
+ gtk_container_foreach(GTK_CONTAINER(vbox), (GtkCallback) showWidget, NULL);
+ return FALSE;
+}
+
+static GtkWidget* createBrowser(GtkWidget* window, GtkWidget* uriEntry, GtkWidget* statusbar, WebKitWebView* webView, GtkWidget* vbox)
{
GtkWidget *scrolledWindow = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledWindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
g_signal_connect(webView, "create-web-view", G_CALLBACK(createWebViewCb), window);
g_signal_connect(webView, "web-view-ready", G_CALLBACK(webViewReadyCb), window);
g_signal_connect(webView, "close-web-view", G_CALLBACK(closeWebViewCb), window);
+ g_signal_connect(webView, "entering-fullscreen", G_CALLBACK(webViewEnteringFullScreen), vbox);
+ g_signal_connect(webView, "leaving-fullscreen", G_CALLBACK(webViewLeavingFullScreen), vbox);
return scrolledWindow;
}
#endif
statusbar = createStatusbar(webView);
gtk_box_pack_start(GTK_BOX(vbox), createToolbar(uriEntry, webView), FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(vbox), createBrowser(window, uriEntry, statusbar, webView), TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), createBrowser(window, uriEntry, statusbar, webView, vbox), TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), vbox);