diff --git a/include/cef_linux.h b/include/cef_linux.h index d53297b2a..8653ce6ad 100644 --- a/include/cef_linux.h +++ b/include/cef_linux.h @@ -73,6 +73,9 @@ public: pthread_mutexattr_t attr_; }; +// Window handle. +#define CefWindowHandle cef_window_handle_t + // Class representing window information. class CefWindowInfo : public cef_window_info_t { @@ -99,7 +102,6 @@ public: void Reset() { - cef_string_clear(&m_windowName); Init(); } @@ -114,17 +116,19 @@ public: Init(); } + void SetAsChild(CefWindowHandle ParentWidget) + { + m_ParentWidget = ParentWidget; + } + CefWindowInfo& operator=(const CefWindowInfo& r) { return operator=(static_cast(r)); } CefWindowInfo& operator=(const cef_window_info_t& r) { - cef_string_copy(r.m_windowName.str, r.m_windowName.length, &m_windowName); - m_x = r.m_x; - m_y = r.m_y; - m_nWidth = r.m_nWidth; - m_nHeight = r.m_nHeight; + m_Widget = r.m_Widget; + m_ParentWidget = r.m_ParentWidget; return *this; } @@ -175,8 +179,6 @@ protected: } }; -// Window handle. -#define CefWindowHandle cef_window_handle_t #endif // defined(__linux__) #endif // _CEF_LINUX_H diff --git a/include/cef_types_linux.h b/include/cef_types_linux.h index d9ebe7e2c..328ee63f1 100644 --- a/include/cef_types_linux.h +++ b/include/cef_types_linux.h @@ -32,6 +32,7 @@ #define _CEF_TYPES_LINUX_H #if defined(__linux__) +#include #include "cef_string.h" #ifdef __cplusplus @@ -39,17 +40,16 @@ extern "C" { #endif // Window handle. -#define cef_window_handle_t void* +#define cef_window_handle_t GtkWidget* // Class representing window information. typedef struct _cef_window_info_t { - // Standard parameters required by CreateWindowEx() - cef_string_t m_windowName; - int m_x; - int m_y; - int m_nWidth; - int m_nHeight; + // Pointer for the parent GtkBox widget. + cef_window_handle_t m_ParentWidget; + + // Pointer for the new browser widget. + cef_window_handle_t m_Widget; } cef_window_info_t; // Class representing print context information. diff --git a/include/cef_types_mac.h b/include/cef_types_mac.h index b9c222dff..3b01095b0 100644 --- a/include/cef_types_mac.h +++ b/include/cef_types_mac.h @@ -44,7 +44,6 @@ extern "C" { // Class representing window information. typedef struct _cef_window_info_t { - // Standard parameters required by CreateWindowEx() cef_string_t m_windowName; int m_x; int m_y; diff --git a/libcef/browser_impl_gtk.cc b/libcef/browser_impl_gtk.cc new file mode 100644 index 000000000..77fa2f8db --- /dev/null +++ b/libcef/browser_impl_gtk.cc @@ -0,0 +1,130 @@ +// Copyright (c) 2011 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cef_context.h" +#include "browser_impl.h" +#include "browser_settings.h" + +#include + +#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/WebKit/chromium/public/WebRect.h" +#include "third_party/WebKit/WebKit/chromium/public/WebSize.h" +#include "third_party/WebKit/WebKit/chromium/public/WebView.h" +#include "webkit/glue/webpreferences.h" + +using WebKit::WebRect; +using WebKit::WebSize; + +CefWindowHandle CefBrowserImpl::GetWindowHandle() +{ + Lock(); + CefWindowHandle handle = window_info_.m_Widget; + Unlock(); + return handle; +} + +gfx::NativeWindow CefBrowserImpl::GetMainWndHandle() const { + GtkWidget* toplevel = gtk_widget_get_ancestor(window_info_.m_Widget, + GTK_TYPE_WINDOW); + return GTK_IS_WINDOW(toplevel) ? GTK_WINDOW(toplevel) : NULL; +} + +void CefBrowserImpl::UIT_CreateBrowser(const CefString& url) +{ + REQUIRE_UIT(); + + // Add a reference that will be released in UIT_DestroyBrowser(). + AddRef(); + + // Add the new browser to the list maintained by the context + _Context->AddBrowser(this); + + WebPreferences prefs; + BrowserToWebSettings(settings_, prefs); + + // Create the webview host object + webviewhost_.reset( + WebViewHost::Create(window_info_.m_ParentWidget, gfx::Rect(), + delegate_.get(), NULL, prefs)); + delegate_->RegisterDragDrop(); + + window_info_.m_Widget = webviewhost_->view_handle(); + + if(handler_.get()) { + // Notify the handler that we're done creating the new window + handler_->HandleAfterCreated(this); + } + + if(url.size() > 0) { + CefRefPtr frame = GetMainFrame(); + frame->AddRef(); + UIT_LoadURL(frame, url); + } +} + +void CefBrowserImpl::UIT_SetFocus(WebWidgetHost* host, bool enable) +{ + REQUIRE_UIT(); + if (!host) + return; + + if(enable) + gtk_widget_grab_focus(host->view_handle()); +} + +WebKit::WebWidget* CefBrowserImpl::UIT_CreatePopupWidget() +{ + REQUIRE_UIT(); + + DCHECK(!popuphost_); + popuphost_ = WebWidgetHost::Create(NULL, popup_delegate_.get()); + + // TODO(port): Show window. + + return popuphost_->webwidget(); +} + +void CefBrowserImpl::UIT_ClosePopupWidget() +{ + REQUIRE_UIT(); + + // TODO(port): Close window. + popuphost_ = NULL; +} + +bool CefBrowserImpl::UIT_ViewDocumentString(WebKit::WebFrame *frame) +{ + REQUIRE_UIT(); + + // TODO(port): Add implementation. + NOTIMPLEMENTED(); + return false; +} + +void CefBrowserImpl::UIT_PrintPage(int page_number, int total_pages, + const gfx::Size& canvas_size, + WebKit::WebFrame* frame) { + REQUIRE_UIT(); + + // TODO(port): Add implementation. + NOTIMPLEMENTED(); +} + +void CefBrowserImpl::UIT_PrintPages(WebKit::WebFrame* frame) { + REQUIRE_UIT(); + + // TODO(port): Add implementation. + NOTIMPLEMENTED(); +} + +int CefBrowserImpl::UIT_GetPagesCount(WebKit::WebFrame* frame) +{ + REQUIRE_UIT(); + + // TODO(port): Add implementation. + NOTIMPLEMENTED(); + return 0; +} diff --git a/libcef/browser_webview_delegate_gtk.cc b/libcef/browser_webview_delegate_gtk.cc new file mode 100644 index 000000000..c1171aba0 --- /dev/null +++ b/libcef/browser_webview_delegate_gtk.cc @@ -0,0 +1,252 @@ +// Copyright (c) 2011 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "browser_webview_delegate.h" +#include "browser_impl.h" + +#include +#include + +#include "base/message_loop.h" +#include "gfx/gtk_util.h" +#include "gfx/point.h" +#include "third_party/WebKit/WebKit/chromium/public/WebCursorInfo.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/WebKit/chromium/public/WebRect.h" +#include "third_party/WebKit/WebKit/chromium/public/WebString.h" +#include "third_party/WebKit/WebKit/chromium/public/WebView.h" +#include "webkit/glue/webcursor.h" +#include "webkit/glue/webdropdata.h" +#include "webkit/glue/webpreferences.h" +#include "webkit/glue/window_open_disposition.h" +#include "webkit/plugins/npapi/gtk_plugin_container_manager.h" +#include "webkit/plugins/npapi/plugin_list.h" +#include "webkit/plugins/npapi/webplugin.h" +#include "webkit/plugins/npapi/webplugin_delegate_impl.h" + +using WebKit::WebCursorInfo; +using WebKit::WebFrame; +using WebKit::WebNavigationPolicy; +using WebKit::WebPopupMenuInfo; +using WebKit::WebRect; +using WebKit::WebWidget; +using WebKit::WebView; + +namespace { + +enum SelectionClipboardType { + TEXT_HTML, + PLAIN_TEXT, +}; + +GdkAtom GetTextHtmlAtom() { + GdkAtom kTextHtmlGdkAtom = gdk_atom_intern_static_string("text/html"); + return kTextHtmlGdkAtom; +} + +void SelectionClipboardGetContents(GtkClipboard* clipboard, + GtkSelectionData* selection_data, guint info, gpointer data) { + // Ignore formats that we don't know about. + if (info != TEXT_HTML && info != PLAIN_TEXT) + return; + + WebView* webview = static_cast(data); + WebFrame* frame = webview->focusedFrame(); + if (!frame) + frame = webview->mainFrame(); + DCHECK(frame); + + std::string selection; + if (TEXT_HTML == info) { + selection = frame->selectionAsMarkup().utf8(); + } else { + selection = frame->selectionAsText().utf8(); + } + if (TEXT_HTML == info) { + gtk_selection_data_set(selection_data, + GetTextHtmlAtom(), + 8 /* bits per data unit, ie, char */, + reinterpret_cast(selection.data()), + selection.length()); + } else { + gtk_selection_data_set_text(selection_data, selection.data(), + selection.length()); + } +} + +} // namespace + +// WebViewClient -------------------------------------------------------------- + +WebWidget* BrowserWebViewDelegate::createPopupMenu( + const WebPopupMenuInfo& info) { + NOTREACHED(); + return NULL; +} + +void BrowserWebViewDelegate::showContextMenu( + WebKit::WebFrame* frame, const WebKit::WebContextMenuData& data) { + NOTIMPLEMENTED(); +} + +// WebWidgetClient ------------------------------------------------------------ + +void BrowserWebViewDelegate::show(WebNavigationPolicy policy) { + WebWidgetHost* host = GetWidgetHost(); + GtkWidget* drawing_area = host->view_handle(); + GtkWidget* window = + gtk_widget_get_parent(gtk_widget_get_parent(drawing_area)); + gtk_widget_show_all(window); +} + +void BrowserWebViewDelegate::closeWidgetSoon() { + if (this == browser_->GetWebViewDelegate()) { + MessageLoop::current()->PostTask(FROM_HERE, NewRunnableFunction( + >k_widget_destroy, GTK_WIDGET(browser_->GetMainWndHandle()))); + } else if (this == browser_->GetPopupDelegate()) { + browser_->UIT_ClosePopupWidget(); + } +} + +void BrowserWebViewDelegate::didChangeCursor(const WebCursorInfo& cursor_info) { + current_cursor_.InitFromCursorInfo(cursor_info); + GdkCursorType cursor_type = + static_cast(current_cursor_.GetCursorType()); + GdkCursor* gdk_cursor; + if (cursor_type == GDK_CURSOR_IS_PIXMAP) { + // TODO(port): WebKit bug https://bugs.webkit.org/show_bug.cgi?id=16388 is + // that calling gdk_window_set_cursor repeatedly is expensive. We should + // avoid it here where possible. + gdk_cursor = current_cursor_.GetCustomCursor(); + } else { + // Optimize the common case, where the cursor hasn't changed. + // However, we can switch between different pixmaps, so only on the + // non-pixmap branch. + if (cursor_type_ == cursor_type) + return; + if (cursor_type == GDK_LAST_CURSOR) + gdk_cursor = NULL; + else + gdk_cursor = gfx::GetCursor(cursor_type); + } + cursor_type_ = cursor_type; + gdk_window_set_cursor(browser_->GetWebViewWndHandle()->window, gdk_cursor); +} + +WebRect BrowserWebViewDelegate::windowRect() { + WebWidgetHost* host = GetWidgetHost(); + GtkWidget* drawing_area = host->view_handle(); + GtkWidget* vbox = gtk_widget_get_parent(drawing_area); + GtkWidget* window = gtk_widget_get_parent(vbox); + + gint x, y; + gtk_window_get_position(GTK_WINDOW(window), &x, &y); + x += vbox->allocation.x + drawing_area->allocation.x; + y += vbox->allocation.y + drawing_area->allocation.y; + + return WebRect(x, y, + drawing_area->allocation.width, + drawing_area->allocation.height); +} + +void BrowserWebViewDelegate::setWindowRect(const WebRect& rect) { + if (this == browser_->GetWebViewDelegate()) { + // TODO(port): Set the window rectangle. + } else if (this == browser_->GetPopupDelegate()) { + WebWidgetHost* host = GetWidgetHost(); + GtkWidget* drawing_area = host->view_handle(); + GtkWidget* window = + gtk_widget_get_parent(gtk_widget_get_parent(drawing_area)); + gtk_window_resize(GTK_WINDOW(window), rect.width, rect.height); + gtk_window_move(GTK_WINDOW(window), rect.x, rect.y); + } +} + +WebRect BrowserWebViewDelegate::rootWindowRect() { + if (WebWidgetHost* host = GetWidgetHost()) { + // We are being asked for the x/y and width/height of the entire browser + // window. This means the x/y is the distance from the corner of the + // screen, and the width/height is the size of the entire browser window. + // For example, this is used to implement window.screenX and window.screenY. + GtkWidget* drawing_area = host->view_handle(); + GtkWidget* window = + gtk_widget_get_parent(gtk_widget_get_parent(drawing_area)); + gint x, y, width, height; + gtk_window_get_position(GTK_WINDOW(window), &x, &y); + gtk_window_get_size(GTK_WINDOW(window), &width, &height); + return WebRect(x, y, width, height); + } + return WebRect(); +} + +WebRect BrowserWebViewDelegate::windowResizerRect() { + // Not necessary on Linux. + return WebRect(); +} + +void BrowserWebViewDelegate::runModal() { + NOTIMPLEMENTED(); +} + +// WebPluginPageDelegate ------------------------------------------------------ + +webkit::npapi::WebPluginDelegate* BrowserWebViewDelegate::CreatePluginDelegate( + const FilePath& path, + const std::string& mime_type) { + // TODO(evanm): we probably shouldn't be doing this mapping to X ids at + // this level. + GdkNativeWindow plugin_parent = + GDK_WINDOW_XWINDOW(browser_->GetWebViewHost()->view_handle()->window); + + return webkit::npapi::WebPluginDelegateImpl::Create(path, mime_type, + plugin_parent); +} + +void BrowserWebViewDelegate::CreatedPluginWindow( + gfx::PluginWindowHandle id) { + browser_->GetWebViewHost()->CreatePluginContainer(id); +} + +void BrowserWebViewDelegate::WillDestroyPluginWindow( + gfx::PluginWindowHandle id) { + browser_->GetWebViewHost()->DestroyPluginContainer(id); +} + +void BrowserWebViewDelegate::DidMovePlugin( + const webkit::npapi::WebPluginGeometry& move) { + WebWidgetHost* host = GetWidgetHost(); + webkit::npapi::GtkPluginContainerManager* plugin_container_manager = + static_cast(host)->plugin_container_manager(); + plugin_container_manager->MovePluginContainer(move); +} + +// Protected methods ---------------------------------------------------------- + +void BrowserWebViewDelegate::ShowJavaScriptAlert( + WebKit::WebFrame* webframe, const CefString& message) { + NOTIMPLEMENTED(); +} + +bool BrowserWebViewDelegate::ShowJavaScriptConfirm( + WebKit::WebFrame* webframe, const CefString& message) { + NOTIMPLEMENTED(); + return false; +} + +bool BrowserWebViewDelegate::ShowJavaScriptPrompt( + WebKit::WebFrame* webframe, const CefString& message, + const CefString& default_value, CefString* result) { + NOTIMPLEMENTED(); + return false; +} + +// Called to show the file chooser dialog. +bool BrowserWebViewDelegate::ShowFileChooser(std::vector& file_names, + const bool multi_select, + const WebKit::WebString& title, + const FilePath& default_file) { + NOTIMPLEMENTED(); + return false; +} diff --git a/libcef/cef_process_ui_thread_gtk.cc b/libcef/cef_process_ui_thread_gtk.cc new file mode 100644 index 000000000..19d6ee201 --- /dev/null +++ b/libcef/cef_process_ui_thread_gtk.cc @@ -0,0 +1,15 @@ +// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#include "cef_process_ui_thread.h" +#include "browser_impl.h" + +void CefProcessUIThread::PlatformInit() { + +} + +void CefProcessUIThread::PlatformCleanUp() { + +} + diff --git a/libcef/webview_host_gtk.cc b/libcef/webview_host_gtk.cc new file mode 100644 index 000000000..bcd2b1ed4 --- /dev/null +++ b/libcef/webview_host_gtk.cc @@ -0,0 +1,50 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#include "webview_host.h" +#include "browser_webview_delegate.h" + +#include "base/logging.h" +#include "gfx/rect.h" +#include "gfx/size.h" +#include "skia/ext/platform_canvas.h" +#include "third_party/WebKit/WebKit/chromium/public/WebView.h" +#include "webkit/glue/webpreferences.h" +#include "webkit/plugins/npapi/gtk_plugin_container.h" + +using WebKit::WebDevToolsAgentClient; +using WebKit::WebView; + +// static +WebViewHost* WebViewHost::Create(GtkWidget* parent_view, + const gfx::Rect& rect, + BrowserWebViewDelegate* delegate, + WebDevToolsAgentClient* dev_tools_client, + const WebPreferences& prefs) { + WebViewHost* host = new WebViewHost(); + + host->view_ = WebWidgetHost::CreateWidget(parent_view, host); + host->plugin_container_manager_.set_host_widget(host->view_); + + host->webwidget_ = WebView::create(delegate, dev_tools_client); + prefs.Apply(host->webview()); + host->webview()->initializeMainFrame(delegate); + host->webwidget_->layout(); + + return host; +} + +WebView* WebViewHost::webview() const { + return static_cast(webwidget_); +} + +void WebViewHost::CreatePluginContainer(gfx::PluginWindowHandle id) { + plugin_container_manager_.CreatePluginContainer(id); +} + +void WebViewHost::DestroyPluginContainer(gfx::PluginWindowHandle id) { + plugin_container_manager_.DestroyPluginContainer(id); +} diff --git a/libcef/webwidget_host_gtk.cc b/libcef/webwidget_host_gtk.cc new file mode 100644 index 000000000..37e36d5e7 --- /dev/null +++ b/libcef/webwidget_host_gtk.cc @@ -0,0 +1,437 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "webwidget_host.h" + +#include +#include +#include + +#include "base/basictypes.h" +#include "base/logging.h" +#include "skia/ext/bitmap_platform_device.h" +#include "skia/ext/platform_canvas.h" +#include "skia/ext/platform_device.h" +#include "third_party/WebKit/WebKit/chromium/public/gtk/WebInputEventFactory.h" +#include "third_party/WebKit/WebKit/chromium/public/x11/WebScreenInfoFactory.h" +#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" +#include "third_party/WebKit/WebKit/chromium/public/WebPopupMenu.h" +#include "third_party/WebKit/WebKit/chromium/public/WebScreenInfo.h" +#include "third_party/WebKit/WebKit/chromium/public/WebSize.h" + +using WebKit::WebInputEventFactory; +using WebKit::WebKeyboardEvent; +using WebKit::WebMouseEvent; +using WebKit::WebMouseWheelEvent; +using WebKit::WebPopupMenu; +using WebKit::WebScreenInfo; +using WebKit::WebScreenInfoFactory; +using WebKit::WebSize; +using WebKit::WebWidgetClient; + +namespace { + +// Used to store a backpointer to WebWidgetHost from our GtkWidget. +const char kWebWidgetHostKey[] = "webwidgethost"; + +// In response to an invalidation, we call into WebKit to do layout. On +// Windows, WM_PAINT is a virtual message so any extra invalidates that come up +// while it's doing layout are implicitly swallowed as soon as we actually do +// drawing via BeginPaint. +// +// Though GTK does know how to collapse multiple paint requests, it won't erase +// paint requests from the future when we start drawing. To avoid an infinite +// cycle of repaints, we track whether we're currently handling a redraw, and +// during that if we get told by WebKit that a region has become invalid, we +// still add that region to the local dirty rect but *don't* enqueue yet +// another "do a paint" message. +bool g_handling_expose = false; + +// ----------------------------------------------------------------------------- +// Callback functions to proxy to host... + +// The web contents are completely drawn and handled by WebKit, except that +// windowed plugins are GtkSockets on top of it. We need to place the +// GtkSockets inside a GtkContainer. We use a GtkFixed container, and the +// GtkSocket objects override a little bit to manage their size (see the code +// in webplugin_delegate_impl_gtk.cc). We listen on a the events we're +// interested in and forward them on to the WebWidgetHost. This class is a +// collection of static methods, implementing the widget related code. +class WebWidgetHostGtkWidget { + public: + // This will create a new widget used for hosting the web contents. We use + // our GtkDrawingAreaContainer here, for the reasons mentioned above. + static GtkWidget* CreateNewWidget(GtkWidget* parent_view, + WebWidgetHost* host) { + GtkWidget* widget = gtk_fixed_new(); + gtk_fixed_set_has_window(GTK_FIXED(widget), true); + + gtk_box_pack_start(GTK_BOX(parent_view), widget, TRUE, TRUE, 0); + + gtk_widget_add_events(widget, GDK_EXPOSURE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_KEY_PRESS_MASK | + GDK_KEY_RELEASE_MASK); + GTK_WIDGET_SET_FLAGS(widget, GTK_CAN_FOCUS); + g_signal_connect(widget, "size-request", + G_CALLBACK(&HandleSizeRequest), host); + g_signal_connect(widget, "size-allocate", + G_CALLBACK(&HandleSizeAllocate), host); + g_signal_connect(widget, "configure-event", + G_CALLBACK(&HandleConfigure), host); + g_signal_connect(widget, "expose-event", + G_CALLBACK(&HandleExpose), host); + g_signal_connect(widget, "destroy", + G_CALLBACK(&HandleDestroy), host); + g_signal_connect(widget, "key-press-event", + G_CALLBACK(&HandleKeyPress), host); + g_signal_connect(widget, "key-release-event", + G_CALLBACK(&HandleKeyRelease), host); + g_signal_connect(widget, "focus", + G_CALLBACK(&HandleFocus), host); + g_signal_connect(widget, "focus-in-event", + G_CALLBACK(&HandleFocusIn), host); + g_signal_connect(widget, "focus-out-event", + G_CALLBACK(&HandleFocusOut), host); + g_signal_connect(widget, "button-press-event", + G_CALLBACK(&HandleButtonPress), host); + g_signal_connect(widget, "button-release-event", + G_CALLBACK(&HandleButtonRelease), host); + g_signal_connect(widget, "motion-notify-event", + G_CALLBACK(&HandleMotionNotify), host); + g_signal_connect(widget, "scroll-event", + G_CALLBACK(&HandleScroll), host); + + g_object_set_data(G_OBJECT(widget), kWebWidgetHostKey, host); + return widget; + } + + private: + // Our size was requested. We let the GtkFixed do its normal calculation, + // after which this callback is called. The GtkFixed will come up with a + // requisition based on its children, which include plugin windows. Since + // we don't want to prevent resizing smaller than a plugin window, we need to + // control the size ourself. + static void HandleSizeRequest(GtkWidget* widget, + GtkRequisition* req, + WebWidgetHost* host) { + // This is arbitrary, but the WebKit scrollbars try to shrink themselves + // if the browser window is too small. Give them some space. + static const int kMinWidthHeight = 64; + + req->width = kMinWidthHeight; + req->height = kMinWidthHeight; + } + + // Our size has changed. + static void HandleSizeAllocate(GtkWidget* widget, + GtkAllocation* allocation, + WebWidgetHost* host) { + host->Resize(WebSize(allocation->width, allocation->height)); + } + + // Size, position, or stacking of the GdkWindow changed. + static gboolean HandleConfigure(GtkWidget* widget, + GdkEventConfigure* config, + WebWidgetHost* host) { + host->Resize(WebSize(config->width, config->height)); + return FALSE; + } + + // A portion of the GdkWindow needs to be redraw. + static gboolean HandleExpose(GtkWidget* widget, + GdkEventExpose* expose, + WebWidgetHost* host) { + // See comments above about what g_handling_expose is for. + g_handling_expose = true; + gfx::Rect rect(expose->area); + host->UpdatePaintRect(rect); + host->Paint(); + g_handling_expose = false; + return FALSE; + } + + // The GdkWindow was destroyed. + static gboolean HandleDestroy(GtkWidget* widget, void* unused) { + // The associated WebWidgetHost instance may have already been destroyed. + WebWidgetHost* host = static_cast( + g_object_get_data(G_OBJECT(widget), kWebWidgetHostKey)); + if (host) + host->WindowDestroyed(); + return FALSE; + } + + // Keyboard key pressed. + static gboolean HandleKeyPress(GtkWidget* widget, + GdkEventKey* event, + WebWidgetHost* host) { + host->webwidget()->handleInputEvent( + WebInputEventFactory::keyboardEvent(event)); + + // In the browser we do a ton of work with IMEs. This is some minimal + // code to make basic text work in test_shell, but doesn't cover IME. + // This is a copy of the logic in ProcessUnfilteredKeyPressEvent in + // render_widget_host_view_gtk.cc . + if (event->type == GDK_KEY_PRESS) { + WebKeyboardEvent wke = WebInputEventFactory::keyboardEvent(event); + if (wke.text[0]) { + wke.type = WebKit::WebInputEvent::Char; + host->webwidget()->handleInputEvent(wke); + } + } + + return FALSE; + } + + // Keyboard key released. + static gboolean HandleKeyRelease(GtkWidget* widget, + GdkEventKey* event, + WebWidgetHost* host) { + return HandleKeyPress(widget, event, host); + } + + // This signal is called when arrow keys or tab is pressed. If we return + // true, we prevent focus from being moved to another widget. If we want to + // allow focus to be moved outside of web contents, we need to implement + // WebViewDelegate::TakeFocus in the test webview delegate. + static gboolean HandleFocus(GtkWidget* widget, + GdkEventFocus* focus, + WebWidgetHost* host) { + return TRUE; + } + + // Keyboard focus entered. + static gboolean HandleFocusIn(GtkWidget* widget, + GdkEventFocus* focus, + WebWidgetHost* host) { + host->webwidget()->setFocus(true); + return TRUE; + } + + // Keyboard focus left. + static gboolean HandleFocusOut(GtkWidget* widget, + GdkEventFocus* focus, + WebWidgetHost* host) { + host->webwidget()->setFocus(false); + return TRUE; + } + + // Mouse button down. + static gboolean HandleButtonPress(GtkWidget* widget, + GdkEventButton* event, + WebWidgetHost* host) { + if (!(event->button == 1 || event->button == 2 || event->button == 3)) + return FALSE; // We do not forward any other buttons to the renderer. + if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) + return FALSE; + host->webwidget()->handleInputEvent( + WebInputEventFactory::mouseEvent(event)); + return FALSE; + } + + // Mouse button up. + static gboolean HandleButtonRelease(GtkWidget* widget, + GdkEventButton* event, + WebWidgetHost* host) { + return HandleButtonPress(widget, event, host); + } + + // Mouse pointer movements. + static gboolean HandleMotionNotify(GtkWidget* widget, + GdkEventMotion* event, + WebWidgetHost* host) { + host->webwidget()->handleInputEvent( + WebInputEventFactory::mouseEvent(event)); + return FALSE; + } + + // Mouse scroll wheel. + static gboolean HandleScroll(GtkWidget* widget, + GdkEventScroll* event, + WebWidgetHost* host) { + host->webwidget()->handleInputEvent( + WebInputEventFactory::mouseWheelEvent(event)); + return FALSE; + } + + DISALLOW_IMPLICIT_CONSTRUCTORS(WebWidgetHostGtkWidget); +}; + +// Return an Xlib Display pointer for the given widget. +Display* GtkWidgetGetDisplay(GtkWidget* widget) { + GdkDisplay* gdk_display = gtk_widget_get_display(widget); + return gdk_x11_display_get_xdisplay(gdk_display); +} + +// Return the screen number for the given widget. +int GtkWidgetGetScreenNum(GtkWidget* widget) { + GdkDisplay* gdk_display = gtk_widget_get_display(widget); + GdkScreen* gdk_screen = gdk_display_get_default_screen(gdk_display); + return gdk_x11_screen_get_screen_number(gdk_screen); +} + +} // namespace + +// This is provided so that the webview can reuse the custom GTK window code. +// static +gfx::NativeView WebWidgetHost::CreateWidget( + gfx::NativeView parent_view, WebWidgetHost* host) { + return WebWidgetHostGtkWidget::CreateNewWidget(parent_view, host); +} + +// static +WebWidgetHost* WebWidgetHost::Create(GtkWidget* parent_view, + WebWidgetClient* client) { + WebWidgetHost* host = new WebWidgetHost(); + host->view_ = CreateWidget(parent_view, host); + host->webwidget_ = WebPopupMenu::create(client); + // We manage our own double buffering because we need to be able to update + // the expose area in an ExposeEvent within the lifetime of the event handler. + gtk_widget_set_double_buffered(GTK_WIDGET(host->view_), false); + + return host; +} + +void WebWidgetHost::UpdatePaintRect(const gfx::Rect& rect) { + paint_rect_ = paint_rect_.Union(rect); +} + +void WebWidgetHost::DidInvalidateRect(const gfx::Rect& damaged_rect) { + DLOG_IF(WARNING, painting_) << "unexpected invalidation while painting"; + + UpdatePaintRect(damaged_rect); + + if (!g_handling_expose) { + gtk_widget_queue_draw_area(GTK_WIDGET(view_), damaged_rect.x(), + damaged_rect.y(), damaged_rect.width(), damaged_rect.height()); + } +} + +void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) { + // This is used for optimizing painting when the renderer is scrolled. We're + // currently not doing any optimizations so just invalidate the region. + DidInvalidateRect(clip_rect); +} + +void WebWidgetHost::ScheduleComposite() { + int width = logical_size_.width(); + int height = logical_size_.height(); + GdkRectangle grect = { + 0, + 0, + width, + height + }; + GdkWindow* window = view_->window; + gdk_window_invalidate_rect(window, &grect, 0); +} + +WebWidgetHost::WebWidgetHost() + : view_(NULL), + webwidget_(NULL), + scroll_dx_(0), + scroll_dy_(0) { + set_painting(false); +} + +WebWidgetHost::~WebWidgetHost() { + // We may be deleted before the view_. Clear out the signals so that we don't + // attempt to invoke something on a deleted object. + g_object_set_data(G_OBJECT(view_), kWebWidgetHostKey, NULL); + g_signal_handlers_disconnect_matched(view_, + G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, this); + webwidget_->close(); +} + +void WebWidgetHost::Resize(const gfx::Size &newsize) { + // The pixel buffer backing us is now the wrong size + canvas_.reset(); + logical_size_ = newsize; + webwidget_->resize(newsize); +} + +void WebWidgetHost::Paint() { + int width = logical_size_.width(); + int height = logical_size_.height(); + gfx::Rect client_rect(width, height); + + // Allocate a canvas if necessary + if (!canvas_.get()) { + ResetScrollRect(); + paint_rect_ = client_rect; + canvas_.reset(new skia::PlatformCanvas(width, height, true)); + if (!canvas_.get()) { + // memory allocation failed, we can't paint. + LOG(ERROR) << "Failed to allocate memory for " << width << "x" << height; + return; + } + } + + // This may result in more invalidation + webwidget_->layout(); + + // Paint the canvas if necessary. Allow painting to generate extra rects the + // first time we call it. This is necessary because some WebCore rendering + // objects update their layout only when painted. + // Store the total area painted in total_paint. Then tell the gdk window + // to update that area after we're done painting it. + gfx::Rect total_paint; + for (int i = 0; i < 2; ++i) { + paint_rect_ = client_rect.Intersect(paint_rect_); + if (!paint_rect_.IsEmpty()) { + gfx::Rect rect(paint_rect_); + paint_rect_ = gfx::Rect(); + + DLOG_IF(WARNING, i == 1) << "painting caused additional invalidations"; + PaintRect(rect); + total_paint = total_paint.Union(rect); + } + } + //DCHECK(paint_rect_.IsEmpty()); + + // Invalidate the paint region on the widget's underlying gdk window. Note + // that gdk_window_invalidate_* will generate extra expose events, which + // we wish to avoid. So instead we use calls to begin_paint/end_paint. + GdkRectangle grect = { + total_paint.x(), + total_paint.y(), + total_paint.width(), + total_paint.height(), + }; + GdkWindow* window = view_->window; + gdk_window_begin_paint_rect(window, &grect); + + // BitBlit to the gdk window. + cairo_t* source_surface = canvas_->beginPlatformPaint(); + cairo_t* cairo_drawable = gdk_cairo_create(window); + cairo_set_source_surface(cairo_drawable, cairo_get_target(source_surface), + 0, 0); + cairo_paint(cairo_drawable); + cairo_destroy(cairo_drawable); + + gdk_window_end_paint(window); +} + +WebScreenInfo WebWidgetHost::GetScreenInfo() { + Display* display = GtkWidgetGetDisplay(view_); + int screen_num = GtkWidgetGetScreenNum(view_); + return WebScreenInfoFactory::screenInfo(display, screen_num); +} + +void WebWidgetHost::ResetScrollRect() { + // This method is only needed for optimized scroll painting, which we don't + // care about in the test shell, yet. +} + +void WebWidgetHost::PaintRect(const gfx::Rect& rect) { + set_painting(true); + webwidget_->paint(canvas_.get(), rect); + set_painting(false); +} + +void WebWidgetHost::WindowDestroyed() { + delete this; +} diff --git a/libcef/xml_reader_impl.cc b/libcef/xml_reader_impl.cc index f09e93dd4..0215b58d8 100644 --- a/libcef/xml_reader_impl.cc +++ b/libcef/xml_reader_impl.cc @@ -1,4 +1,4 @@ -// Copyright (c) 20010 The Chromium Embedded Framework Authors. All rights +// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. diff --git a/libcef/xml_reader_impl.h b/libcef/xml_reader_impl.h index 430c76a98..83d33168d 100644 --- a/libcef/xml_reader_impl.h +++ b/libcef/xml_reader_impl.h @@ -1,4 +1,4 @@ -// Copyright (c) 20010 The Chromium Embedded Framework Authors. All rights +// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. diff --git a/libcef/zip_reader_impl.cc b/libcef/zip_reader_impl.cc index 6c0860942..872de891e 100644 --- a/libcef/zip_reader_impl.cc +++ b/libcef/zip_reader_impl.cc @@ -1,4 +1,4 @@ -// Copyright (c) 20010 The Chromium Embedded Framework Authors. All rights +// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. diff --git a/libcef/zip_reader_impl.h b/libcef/zip_reader_impl.h index b9ea28c3e..f847e9b65 100644 --- a/libcef/zip_reader_impl.h +++ b/libcef/zip_reader_impl.h @@ -1,4 +1,4 @@ -// Copyright (c) 20010 The Chromium Embedded Framework Authors. All rights +// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file.