diff options
author | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-22 17:56:06 +0000 |
---|---|---|
committer | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-22 17:56:06 +0000 |
commit | 4c3cd741778f0df792d6b8f4acbacd6675784aa8 (patch) | |
tree | 70211d12b189d67e9345244397262f3cefd21a6c | |
parent | 47e3a17c0dd7898eda6622d0bafe189b75db3c83 (diff) | |
download | chromium_src-4c3cd741778f0df792d6b8f4acbacd6675784aa8.zip chromium_src-4c3cd741778f0df792d6b8f4acbacd6675784aa8.tar.gz chromium_src-4c3cd741778f0df792d6b8f4acbacd6675784aa8.tar.bz2 |
Linux: move X operations from the IO to UI2 thread.
(r14075 take two)
Currently we perform several X operations on the IO thread including
geometry and clipboard work. This is causing races inside Xlib and
crashing the browser.
These are the result of synchronous calls from the renderer, so we
cannot route these requests to the UI thread without risking deadlock.
Thus we introduce the UI2 thread. This thread has a second connection
to the X server and can perform X operations safely the without UI
thread.
Work remains to be done:
Since we still have the hack where we pass GtkWidget pointers into the
renderer and back, we still have to access these structures from the
IO and UI2 threads. This still needs to be fixed, but this is not the
patch for it.
Also, not all the X calls from the IO thread have been moved over in
this patch; just a few small ones.
http://codereview.chromium.org/67145
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@14206 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/browser_process.h | 9 | ||||
-rw-r--r-- | chrome/browser/browser_process_impl.cc | 15 | ||||
-rw-r--r-- | chrome/browser/browser_process_impl.h | 14 | ||||
-rw-r--r-- | chrome/browser/chrome_thread.cc | 8 | ||||
-rw-r--r-- | chrome/browser/chrome_thread.h | 10 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.cc | 26 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.h | 14 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter_gtk.cc | 122 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter_mac.mm | 34 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter_win.cc | 15 | ||||
-rw-r--r-- | chrome/common/x11_util.cc | 30 | ||||
-rw-r--r-- | chrome/common/x11_util.h | 95 | ||||
-rw-r--r-- | chrome/test/testing_browser_process.h | 6 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_shell.gyp | 4 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_shell_x11.cc | 19 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_shell_x11.h | 18 | ||||
-rw-r--r-- | webkit/tools/test_shell/webwidget_host_gtk.cc | 7 | ||||
-rw-r--r-- | webkit/webkit.gyp | 10 |
18 files changed, 357 insertions, 99 deletions
diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h index d5758f0..15ead3e 100644 --- a/chrome/browser/browser_process.h +++ b/chrome/browser/browser_process.h @@ -96,6 +96,15 @@ class BrowserProcess { // database. History has its own thread since it has much higher traffic. virtual base::Thread* db_thread() = 0; +#if defined(OS_LINUX) + // Returns the thread that is used to process UI requests in cases were + // we can't route the request to the UI thread. Note that this thread + // should only be used by the IO thread and this method is only safe to call + // from the UI thread so, if you've ended up here, something has gone wrong. + // This method is only included for uniformity. + virtual base::Thread* background_x11_thread() = 0; +#endif + virtual sandbox::BrokerServices* broker_services() = 0; virtual IconManager* icon_manager() = 0; diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc index 5e1d9f3..5b7b6b6 100644 --- a/chrome/browser/browser_process_impl.cc +++ b/chrome/browser/browser_process_impl.cc @@ -171,6 +171,11 @@ BrowserProcessImpl::~BrowserProcessImpl() { io_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableFunction(chrome_browser_net::EnsureDnsPrefetchShutdown)); +#if defined(OS_LINUX) + // The IO thread must outlive the BACKGROUND_X11 thread. + background_x11_thread_.reset(); +#endif + // Need to stop io_thread_ before resource_dispatcher_host_, since // io_thread_ may still deref ResourceDispatcherHost and handle resource // request before going away. @@ -284,6 +289,16 @@ void BrowserProcessImpl::CreateIOThread() { // invoke the io_thread() accessor. PluginService::GetInstance(); +#if defined(OS_LINUX) + // The lifetime of the BACKGROUND_X11 thread is a subset of the IO thread so + // we start it now. + scoped_ptr<base::Thread> background_x11_thread( + new BrowserProcessSubThread(ChromeThread::BACKGROUND_X11)); + if (!background_x11_thread->Start()) + return; + background_x11_thread_.swap(background_x11_thread); +#endif + scoped_ptr<base::Thread> thread( new BrowserProcessSubThread(ChromeThread::IO)); base::Thread::Options options; diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h index 55b9dc2..0550ad9 100644 --- a/chrome/browser/browser_process_impl.h +++ b/chrome/browser/browser_process_impl.h @@ -73,6 +73,16 @@ class BrowserProcessImpl : public BrowserProcess, public NonThreadSafe { return db_thread_.get(); } +#if defined(OS_LINUX) + virtual base::Thread* background_x11_thread() { + DCHECK(CalledOnValidThread()); + // The BACKGROUND_X11 thread is created when the IO thread is created. + if (!created_io_thread_) + CreateIOThread(); + return background_x11_thread_.get(); + } +#endif + virtual ProfileManager* profile_manager() { DCHECK(CalledOnValidThread()); if (!created_profile_manager_) @@ -211,6 +221,10 @@ class BrowserProcessImpl : public BrowserProcess, public NonThreadSafe { bool created_io_thread_; scoped_ptr<base::Thread> io_thread_; +#if defined(OS_LINUX) + // This shares a created flag with the IO thread. + scoped_ptr<base::Thread> background_x11_thread_; +#endif bool created_file_thread_; scoped_ptr<base::Thread> file_thread_; diff --git a/chrome/browser/chrome_thread.cc b/chrome/browser/chrome_thread.cc index 9c0d10c..762ae76 100644 --- a/chrome/browser/chrome_thread.cc +++ b/chrome/browser/chrome_thread.cc @@ -9,6 +9,10 @@ static const char* chrome_thread_names[ChromeThread::ID_COUNT] = { "Chrome_IOThread", // IO "Chrome_FileThread", // FILE "Chrome_DBThread", // DB + "Chrome_HistoryThread", // HISTORY +#if defined(OS_LINUX) + "Chrome_Background_X11Thread", // BACKGROUND_X11 +#endif }; Lock ChromeThread::lock_; @@ -17,6 +21,10 @@ ChromeThread* ChromeThread::chrome_threads_[ID_COUNT] = { NULL, // IO NULL, // FILE NULL, // DB + NULL, // HISTORY +#if defined(OS_LINUX) + NULL, // BACKGROUND_X11 +#endif }; ChromeThread::ChromeThread(ChromeThread::ID identifier) diff --git a/chrome/browser/chrome_thread.h b/chrome/browser/chrome_thread.h index 6570f92..1fd1901 100644 --- a/chrome/browser/chrome_thread.h +++ b/chrome/browser/chrome_thread.h @@ -38,6 +38,16 @@ class ChromeThread : public base::Thread { // This is the thread that interacts with the database. DB, + // This is the thread that interacts with the history database. + HISTORY, + +#if defined(OS_LINUX) + // This thread has a second connection to the X server and is used to + // process UI requests when routing the request to the UI thread would risk + // deadlock. + BACKGROUND_X11, +#endif + // This identifier does not represent a thread. Instead it counts the // number of well-known threads. Insert new well-known threads before this // identifier. diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index 06433a1..71ae0d8 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -47,13 +47,13 @@ #include "third_party/WebKit/WebKit/chromium/public/win/WebScreenInfoFactory.h" #elif defined(OS_MACOSX) #include "third_party/WebKit/WebKit/chromium/public/mac/WebScreenInfoFactory.h" -#elif defined(OS_LINUX) -#include "third_party/WebKit/WebKit/chromium/public/gtk/WebScreenInfoFactory.h" #endif using WebKit::WebCache; using WebKit::WebScreenInfo; +#if !defined(OS_LINUX) using WebKit::WebScreenInfoFactory; +#endif namespace { @@ -213,6 +213,16 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& message) { if (!handled) { handled = true; IPC_BEGIN_MESSAGE_MAP_EX(ResourceMessageFilter, message, msg_is_ok) + // On Linux we need to dispatch these messages to the UI2 thread because + // we cannot make X calls from the IO thread. On other platforms, we can + // handle these calls directly. + IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetScreenInfo, + OnGetScreenInfo); + IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetWindowRect, + OnGetWindowRect); + IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetRootWindowRect, + OnGetRootWindowRect) + IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWindow, OnMsgCreateWindow) IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWidget, OnMsgCreateWidget) IPC_MESSAGE_HANDLER(ViewHostMsg_SetCookie, OnSetCookie) @@ -223,7 +233,6 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& message) { #if defined(OS_WIN) // This hack is Windows-specific. IPC_MESSAGE_HANDLER(ViewHostMsg_LoadFont, OnLoadFont) #endif - IPC_MESSAGE_HANDLER(ViewHostMsg_GetScreenInfo, OnGetScreenInfo) IPC_MESSAGE_HANDLER(ViewHostMsg_GetPlugins, OnGetPlugins) IPC_MESSAGE_HANDLER(ViewHostMsg_GetPluginPath, OnGetPluginPath) IPC_MESSAGE_HANDLER(ViewHostMsg_DownloadUrl, OnDownloadUrl) @@ -252,8 +261,6 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& message) { OnClipboardReadAsciiText) IPC_MESSAGE_HANDLER(ViewHostMsg_ClipboardReadHTML, OnClipboardReadHTML) - IPC_MESSAGE_HANDLER(ViewHostMsg_GetWindowRect, OnGetWindowRect) - IPC_MESSAGE_HANDLER(ViewHostMsg_GetRootWindowRect, OnGetRootWindowRect) IPC_MESSAGE_HANDLER(ViewHostMsg_GetMimeTypeFromExtension, OnGetMimeTypeFromExtension) IPC_MESSAGE_HANDLER(ViewHostMsg_GetMimeTypeFromFile, @@ -460,12 +467,17 @@ void ResourceMessageFilter::OnLoadFont(LOGFONT font) { } #endif +#if !defined(OS_LINUX) void ResourceMessageFilter::OnGetScreenInfo(gfx::NativeViewId view, - WebScreenInfo* results) { + IPC::Message* reply_msg) { // TODO(darin): Change this into a routed message so that we can eliminate // the NativeViewId parameter. - *results = WebScreenInfoFactory::screenInfo(gfx::NativeViewFromId(view)); + WebScreenInfo results = + WebScreenInfoFactory::screenInfo(gfx::NativeViewFromId(view)); + ViewHostMsg_GetScreenInfo::WriteReplyParams(reply_msg, results); + Send(reply_msg); } +#endif void ResourceMessageFilter::OnGetPlugins(bool refresh, std::vector<WebPluginInfo>* plugins) { diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h index 19566be..1ce2b95 100644 --- a/chrome/browser/renderer_host/resource_message_filter.h +++ b/chrome/browser/renderer_host/resource_message_filter.h @@ -125,8 +125,7 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, void OnLoadFont(LOGFONT font); #endif - void OnGetScreenInfo(gfx::NativeViewId window, - WebKit::WebScreenInfo* results); + void OnGetScreenInfo(gfx::NativeViewId window, IPC::Message* reply); void OnGetPlugins(bool refresh, std::vector<WebPluginInfo>* plugins); void OnGetPluginPath(const GURL& url, const std::string& mime_type, @@ -156,8 +155,8 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, void OnClipboardReadText(string16* result); void OnClipboardReadAsciiText(std::string* result); void OnClipboardReadHTML(string16* markup, GURL* src_url); - void OnGetWindowRect(gfx::NativeViewId window, gfx::Rect *rect); - void OnGetRootWindowRect(gfx::NativeViewId window, gfx::Rect *rect); + void OnGetWindowRect(gfx::NativeViewId window, IPC::Message* reply); + void OnGetRootWindowRect(gfx::NativeViewId window, IPC::Message* reply); void OnGetMimeTypeFromExtension(const FilePath::StringType& ext, std::string* mime_type); void OnGetMimeTypeFromFile(const FilePath& file_path, @@ -203,6 +202,13 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, void OnOpenChannelToExtension(const std::string& extension_id, int* port_id); void OnExtensionPostMessage(int port_id, const std::string& message); +#if defined(OS_LINUX) + void SendBackgroundX11Reply(IPC::Message* reply_msg); + void DoOnGetScreenInfo(gfx::NativeViewId view, IPC::Message* reply_msg); + void DoOnGetWindowRect(gfx::NativeViewId view, IPC::Message* reply_msg); + void DoOnGetRootWindowRect(gfx::NativeViewId view, IPC::Message* reply_msg); +#endif + // We have our own clipboard service because we want to access the clipboard // on the IO thread instead of forwarding (possibly synchronous) messages to // the UI thread. diff --git a/chrome/browser/renderer_host/resource_message_filter_gtk.cc b/chrome/browser/renderer_host/resource_message_filter_gtk.cc index 0616cd9..750356a 100644 --- a/chrome/browser/renderer_host/resource_message_filter_gtk.cc +++ b/chrome/browser/renderer_host/resource_message_filter_gtk.cc @@ -6,42 +6,106 @@ #include <gtk/gtk.h> +#include "chrome/browser/chrome_thread.h" +#include "chrome/common/render_messages.h" +#include "chrome/common/x11_util.h" + +#include "third_party/WebKit/WebKit/chromium/public/WebScreenInfo.h" +#include "third_party/WebKit/WebKit/chromium/public/x11/WebScreenInfoFactory.h" + +using WebKit::WebScreenInfo; +using WebKit::WebScreenInfoFactory; + // We get null window_ids passed into the two functions below; please see // http://crbug.com/9060 for more details. -void ResourceMessageFilter::OnGetWindowRect(gfx::NativeViewId window_id, - gfx::Rect* rect) { - if (!window_id) { - *rect = gfx::Rect(); - return; +// Called on the IO thread. +void ResourceMessageFilter::SendBackgroundX11Reply(IPC::Message* reply_msg) { + Send(reply_msg); +} + +// Called on the BACKGROUND_X11 thread. +void ResourceMessageFilter::DoOnGetScreenInfo(gfx::NativeViewId view, + IPC::Message* reply_msg) { + Display* display = x11_util::GetSecondaryDisplay(); + int screen = x11_util::GetDefaultScreen(display); + WebScreenInfo results = WebScreenInfoFactory::screenInfo(display, screen); + ViewHostMsg_GetScreenInfo::WriteReplyParams(reply_msg, results); + + ChromeThread::GetMessageLoop(ChromeThread::IO)->PostTask( + FROM_HERE, NewRunnableMethod( + this, &ResourceMessageFilter::SendBackgroundX11Reply, reply_msg)); +} + +// Called on the BACKGROUND_X11 thread. +void ResourceMessageFilter::DoOnGetWindowRect(gfx::NativeViewId view, + IPC::Message* reply_msg) { + gfx::Rect rect; + + if (view) { + XID window = x11_util::GetX11WindowFromGtkWidget( + gfx::NativeViewFromId(view)); + + int x, y; + unsigned width, height; + x11_util::GetWindowGeometry(&x, &y, &width, &height, window); + rect = gfx::Rect(x, y, width, height); } - // Ideally this would be gtk_widget_get_window but that's only - // from gtk 2.14 onwards. :( - GdkWindow* window = gfx::NativeViewFromId(window_id)->window; - DCHECK(window); - gint x, y, width, height; - // This is the "position of a window in root window coordinates". - gdk_window_get_origin(window, &x, &y); - gdk_window_get_size(window, &width, &height); - *rect = gfx::Rect(x, y, width, height); + ViewHostMsg_GetWindowRect::WriteReplyParams(reply_msg, rect); + + ChromeThread::GetMessageLoop(ChromeThread::IO)->PostTask( + FROM_HERE, NewRunnableMethod( + this, &ResourceMessageFilter::SendBackgroundX11Reply, reply_msg)); } -void ResourceMessageFilter::OnGetRootWindowRect(gfx::NativeViewId window_id, - gfx::Rect* rect) { - if (!window_id) { - *rect = gfx::Rect(); - return; +// Called on the BACKGROUND_X11 thread. +void ResourceMessageFilter::DoOnGetRootWindowRect(gfx::NativeViewId view, + IPC::Message* reply_msg) { + gfx::Rect rect; + + if (view && gfx::NativeViewFromId(view)->window) { + // Windows uses GetAncestor(window, GA_ROOT) here which probably means + // we want the top level window. + // TODO(agl): calling GTK from this thread is not safe. However, we still + // have to solve the issue where we pass GtkWidget* into the renderer and + // the solution to that should also fix this problem. + GdkWindow* gdk_window = + gdk_window_get_toplevel(gfx::NativeViewFromId(view)->window); + XID window = x11_util::GetX11WindowFromGdkWindow(gdk_window); + int x, y; + unsigned width, height; + x11_util::GetWindowGeometry(&x, &y, &width, &height, window); + rect = gfx::Rect(x, y, width, height); } - // Windows uses GetAncestor(window, GA_ROOT) here which probably means - // we want the top level window. - GdkWindow* window = - gdk_window_get_toplevel(gfx::NativeViewFromId(window_id)->window); - DCHECK(window); - gint x, y, width, height; - // This is the "position of a window in root window coordinates". - gdk_window_get_origin(window, &x, &y); - gdk_window_get_size(window, &width, &height); - *rect = gfx::Rect(x, y, width, height); + ViewHostMsg_GetRootWindowRect::WriteReplyParams(reply_msg, rect); + + ChromeThread::GetMessageLoop(ChromeThread::IO)->PostTask( + FROM_HERE, NewRunnableMethod( + this, &ResourceMessageFilter::SendBackgroundX11Reply, reply_msg)); +} + +// Called on the IO thread. +void ResourceMessageFilter::OnGetScreenInfo(gfx::NativeViewId view, + IPC::Message* reply_msg) { + ChromeThread::GetMessageLoop(ChromeThread::BACKGROUND_X11)->PostTask( + FROM_HERE, NewRunnableMethod( + this, &ResourceMessageFilter::DoOnGetScreenInfo, view, reply_msg)); +} + +// Called on the IO thread. +void ResourceMessageFilter::OnGetWindowRect(gfx::NativeViewId view, + IPC::Message* reply_msg) { + ChromeThread::GetMessageLoop(ChromeThread::BACKGROUND_X11)->PostTask( + FROM_HERE, NewRunnableMethod( + this, &ResourceMessageFilter::DoOnGetWindowRect, view, reply_msg)); +} + +// Called on the IO thread. +void ResourceMessageFilter::OnGetRootWindowRect(gfx::NativeViewId view, + IPC::Message* reply_msg) { + ChromeThread::GetMessageLoop(ChromeThread::BACKGROUND_X11)->PostTask( + FROM_HERE, NewRunnableMethod( + this, &ResourceMessageFilter::DoOnGetRootWindowRect, view, reply_msg)); } diff --git a/chrome/browser/renderer_host/resource_message_filter_mac.mm b/chrome/browser/renderer_host/resource_message_filter_mac.mm index c4b7531..7d740ac 100644 --- a/chrome/browser/renderer_host/resource_message_filter_mac.mm +++ b/chrome/browser/renderer_host/resource_message_filter_mac.mm @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "chrome/browser/renderer_host/resource_message_filter.h" +#include "chrome/common/render_messages.h" #import <Cocoa/Cocoa.h> @@ -23,28 +24,31 @@ gfx::Rect NSRectToRect(const NSRect rect, NSScreen* screen) { // http://crbug.com/9060 for more details. void ResourceMessageFilter::OnGetWindowRect(gfx::NativeViewId window_id, - gfx::Rect* rect) { + IPC::Message* reply_msg) { NSView* view = gfx::NativeViewFromId(window_id); - if (!view) { - *rect = gfx::Rect(); - return; + gfx::Rect rect; + + if (view) { + NSRect bounds = [view bounds]; + bounds = [view convertRect:bounds toView:nil]; + bounds.origin = [[view window] convertBaseToScreen:bounds.origin]; + rect = NSRectToRect(bounds, [[view window] screen]); } - NSRect bounds = [view bounds]; - bounds = [view convertRect:bounds toView:nil]; - bounds.origin = [[view window] convertBaseToScreen:bounds.origin]; - *rect = NSRectToRect(bounds, [[view window] screen]); + ViewHostMsg_GetWindowRect::WriteReplyParams(reply_msg, rect); + Send(reply_msg); } void ResourceMessageFilter::OnGetRootWindowRect(gfx::NativeViewId window_id, - gfx::Rect* rect) { + IPC::Message* reply_msg) { NSView* view = gfx::NativeViewFromId(window_id); - if (!view) { - *rect = gfx::Rect(); - return; + gfx::Rect rect; + if (view) { + NSWindow* window = [view window]; + NSRect bounds = [window frame]; + gfx::Rect rect = NSRectToRect(bounds, [window screen]); } - NSWindow* window = [view window]; - NSRect bounds = [window frame]; - *rect = NSRectToRect(bounds, [window screen]); + ViewHostMsg_GetRootWindowRect::WriteReplyParams(reply_msg, rect); + Send(reply_msg); } diff --git a/chrome/browser/renderer_host/resource_message_filter_win.cc b/chrome/browser/renderer_host/resource_message_filter_win.cc index 222e7ba..2aae6ed 100644 --- a/chrome/browser/renderer_host/resource_message_filter_win.cc +++ b/chrome/browser/renderer_host/resource_message_filter_win.cc @@ -3,23 +3,30 @@ // found in the LICENSE file. #include "chrome/browser/renderer_host/resource_message_filter.h" +#include "chrome/common/render_messages.h" // We get null window_ids passed into the two functions below; please see // http://crbug.com/9060 for more details. void ResourceMessageFilter::OnGetWindowRect(gfx::NativeViewId window_id, - gfx::Rect* rect) { + IPC::Message* reply_msg) { HWND window = gfx::NativeViewFromId(window_id); RECT window_rect = {0}; GetWindowRect(window, &window_rect); - *rect = window_rect; + gfx::Rect rect(window_rect); + + ViewHostMsg_GetWindowRect::WriteReplyParams(reply_msg, rect); + Send(reply_msg); } void ResourceMessageFilter::OnGetRootWindowRect(gfx::NativeViewId window_id, - gfx::Rect* rect) { + IPC::Message* reply_msg) { HWND window = gfx::NativeViewFromId(window_id); RECT window_rect = {0}; HWND root_window = ::GetAncestor(window, GA_ROOT); GetWindowRect(root_window, &window_rect); - *rect = window_rect; + gfx::Rect rect(window_rect); + + ViewHostMsg_GetRootWindowRect::WriteReplyParams(reply_msg, rect); + Send(reply_msg); } diff --git a/chrome/common/x11_util.cc b/chrome/common/x11_util.cc index d10c320..83fc02a 100644 --- a/chrome/common/x11_util.cc +++ b/chrome/common/x11_util.cc @@ -6,6 +6,7 @@ // ported from XCB since we can't use XCB on Ubuntu while its 32-bit support // remains woefully incomplete. +#include "base/thread.h" #include "chrome/common/x11_util.h" #include "chrome/common/x11_util_internal.h" @@ -98,6 +99,10 @@ bool QueryRenderSupport(Display* dpy) { return render_supported; } +int GetDefaultScreen(Display* display) { + return XDefaultScreen(display); +} + XID GetX11RootWindow() { return GDK_WINDOW_XID(gdk_get_default_root_window()); } @@ -106,6 +111,10 @@ XID GetX11WindowFromGtkWidget(GtkWidget* widget) { return GDK_WINDOW_XID(widget->window); } +XID GetX11WindowFromGdkWindow(GdkWindow* window) { + return GDK_WINDOW_XID(window); +} + void* GetVisualFromGtkWidget(GtkWidget* widget) { return GDK_VISUAL_XVISUAL(gtk_widget_get_visual(widget)); } @@ -219,4 +228,25 @@ void FreePixmap(Display* display, XID pixmap) { XFreePixmap(display, pixmap); } +// Called on BACKGROUND_X11 thread. +Display* GetSecondaryDisplay() { + static Display* display = NULL; + if (!display) { + display = XOpenDisplay(NULL); + CHECK(display); + } + + return display; +} + +// Called on BACKGROUND_X11 thread. +void GetWindowGeometry(int* x, int* y, unsigned* width, unsigned* height, + XID window) { + Window root_window; + unsigned border_width, depth; + + CHECK(XGetGeometry(GetSecondaryDisplay(), window, + &root_window, x, y, width, height, &border_width, &depth)); +} + } // namespace x11_util diff --git a/chrome/common/x11_util.h b/chrome/common/x11_util.h index 4800a69..aef133f 100644 --- a/chrome/common/x11_util.h +++ b/chrome/common/x11_util.h @@ -11,48 +11,75 @@ // we use a void* for Visual*). The Xlib headers are highly polluting so we try // hard to limit their spread into the rest of the code. +typedef struct _GdkDrawable GdkWindow; typedef struct _GtkWidget GtkWidget; typedef unsigned long XID; typedef struct _XDisplay Display; +namespace base { +class Thread; +} + namespace gfx { class Size; } namespace x11_util { - // These functions cache their results and must be called from the UI thread. - // Currently they don't support multiple screens/displays. - - // Return an X11 connection for the current, primary display. - Display* GetXDisplay(); - // Return true iff the connection supports X shared memory - bool QuerySharedMemorySupport(Display* dpy); - // Return true iff the display supports Xrender - bool QueryRenderSupport(Display* dpy); - - // These functions do not cache their results - - // Get the X window id for the default root window - XID GetX11RootWindow(); - // Get the X window id for the given GTK widget. - XID GetX11WindowFromGtkWidget(GtkWidget*); - // Get a Visual from the given widget. Since we don't include the Xlib - // headers, this is returned as a void*. - void* GetVisualFromGtkWidget(GtkWidget*); - // Return the number of bits-per-pixel for a pixmap of the given depth - int BitsPerPixelForPixmapDepth(Display*, int depth); - - // Return a handle to a server side pixmap. |shared_memory_key| is a SysV - // IPC key. The shared memory region must contain 32-bit pixels. - XID AttachSharedMemory(Display* display, int shared_memory_support); - void DetachSharedMemory(Display* display, XID shmseg); - - // Return a handle to an XRender picture where |pixmap| is a handle to a - // pixmap containing Skia ARGB data. - XID CreatePictureFromSkiaPixmap(Display* display, XID pixmap); - - void FreePicture(Display* display, XID picture); - void FreePixmap(Display* display, XID pixmap); -}; + +// These functions use the GDK default display and this /must/ be called from +// the UI thread. Thus, they don't support multiple displays. + +// These functions cache their results. + +// Return an X11 connection for the current, primary display. +Display* GetXDisplay(); +// Return true iff the connection supports X shared memory +bool QuerySharedMemorySupport(Display* dpy); +// Return true iff the display supports Xrender +bool QueryRenderSupport(Display* dpy); +// Return the default screen number for the display +int GetDefaultScreen(Display* display); + +// These functions do not cache their results + +// Get the X window id for the default root window +XID GetX11RootWindow(); +// Get the X window id for the given GTK widget. +XID GetX11WindowFromGtkWidget(GtkWidget*); +XID GetX11WindowFromGdkWindow(GdkWindow*); +// Get a Visual from the given widget. Since we don't include the Xlib +// headers, this is returned as a void*. +void* GetVisualFromGtkWidget(GtkWidget*); +// Return the number of bits-per-pixel for a pixmap of the given depth +int BitsPerPixelForPixmapDepth(Display*, int depth); + +// Return a handle to a server side pixmap. |shared_memory_key| is a SysV +// IPC key. The shared memory region must contain 32-bit pixels. +XID AttachSharedMemory(Display* display, int shared_memory_support); +void DetachSharedMemory(Display* display, XID shmseg); + +// Return a handle to an XRender picture where |pixmap| is a handle to a +// pixmap containing Skia ARGB data. +XID CreatePictureFromSkiaPixmap(Display* display, XID pixmap); + +void FreePicture(Display* display, XID picture); +void FreePixmap(Display* display, XID pixmap); + +// These functions are for performing X opertions outside of the UI thread. + +// Return the Display for the secondary X connection. We keep a second +// connection around for making X requests outside of the UI thread. +// This function may only be called from the BACKGROUND_X11 thread. +Display* GetSecondaryDisplay(); + +// Since one cannot include both WebKit header and Xlib headers in the same +// file (due to collisions), we wrap all the Xlib functions that we need here. +// These functions must be called on the BACKGROUND_X11 thread since they +// reference GetSecondaryDisplay(). + +void GetWindowGeometry(int* x, int* y, unsigned* width, unsigned* height, + XID window); + +} // namespace x11_util #endif // CHROME_COMMON_X11_UTIL_H_ diff --git a/chrome/test/testing_browser_process.h b/chrome/test/testing_browser_process.h index a507586..42949b0 100644 --- a/chrome/test/testing_browser_process.h +++ b/chrome/test/testing_browser_process.h @@ -44,6 +44,12 @@ class TestingBrowserProcess : public BrowserProcess { return NULL; } +#if defined(OS_LINUX) + virtual base::Thread* background_x11_thread() { + return NULL; + } +#endif + virtual base::Thread* file_thread() { return NULL; } diff --git a/webkit/tools/test_shell/test_shell.gyp b/webkit/tools/test_shell/test_shell.gyp index 3c0f3e7..393aa92 100644 --- a/webkit/tools/test_shell/test_shell.gyp +++ b/webkit/tools/test_shell/test_shell.gyp @@ -72,6 +72,7 @@ 'test_shell.cc', 'test_shell.h', 'test_shell_gtk.cc', + 'test_shell_x11.cc', 'test_shell_mac.mm', 'test_shell_platform_delegate.h', 'test_shell_platform_delegate_gtk.cc', @@ -116,7 +117,8 @@ 'cflags': ['-Wno-multichar'], }, { # else: OS!=linux 'sources/': [ - ['exclude', '_gtk\\.cc$'] + ['exclude', '_gtk\\.cc$'], + ['exclude', '_x11\\.cc$'], ], }], ['OS!="mac"', { diff --git a/webkit/tools/test_shell/test_shell_x11.cc b/webkit/tools/test_shell/test_shell_x11.cc new file mode 100644 index 0000000..865954b --- /dev/null +++ b/webkit/tools/test_shell/test_shell_x11.cc @@ -0,0 +1,19 @@ +#include <gtk/gtk.h> +#include <gdk/gdkx.h> + +#include "webkit/tools/test_shell/test_shell_x11.h" + +namespace test_shell_x11 { + +Display* GtkWidgetGetDisplay(GtkWidget* widget) { + GdkDisplay* gdk_display = gtk_widget_get_display(widget); + return gdk_x11_display_get_xdisplay(gdk_display); +} + +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 test_shell_x11 diff --git a/webkit/tools/test_shell/test_shell_x11.h b/webkit/tools/test_shell/test_shell_x11.h new file mode 100644 index 0000000..a17356d --- /dev/null +++ b/webkit/tools/test_shell/test_shell_x11.h @@ -0,0 +1,18 @@ +#ifndef WEBKIT_TOOLS_TEST_SHELL_TEST_SHELL_X11_H +#define WEBKIT_TOOLS_TEST_SHELL_TEST_SHELL_X11_H + +// This header is required because one cannot include both Xlib headers and +// WebKit headers in the same source file. + +typedef struct _XDisplay Display; + +namespace test_shell_x11 { + +// Return an Xlib Display pointer for the given widget +Display* GtkWidgetGetDisplay(GtkWidget* widget); +// Return the screen number for the given widget +int GtkWidgetGetScreenNum(GtkWidget* widget); + +} // namespace test_shell_x11 + +#endif // !WEBKIT_TOOLS_TEST_SHELL_TEST_SHELL_X11_H diff --git a/webkit/tools/test_shell/webwidget_host_gtk.cc b/webkit/tools/test_shell/webwidget_host_gtk.cc index 5645da7..3bba172 100644 --- a/webkit/tools/test_shell/webwidget_host_gtk.cc +++ b/webkit/tools/test_shell/webwidget_host_gtk.cc @@ -13,12 +13,13 @@ #include "skia/ext/platform_canvas_linux.h" #include "skia/ext/platform_device_linux.h" #include "third_party/WebKit/WebKit/chromium/public/gtk/WebInputEventFactory.h" -#include "third_party/WebKit/WebKit/chromium/public/gtk/WebScreenInfoFactory.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/WebScreenInfo.h" #include "third_party/WebKit/WebKit/chromium/public/WebSize.h" #include "webkit/glue/webwidget.h" #include "webkit/tools/test_shell/test_shell.h" +#include "webkit/tools/test_shell/test_shell_x11.h" using WebKit::WebInputEventFactory; using WebKit::WebKeyboardEvent; @@ -368,7 +369,9 @@ void WebWidgetHost::Paint() { } WebScreenInfo WebWidgetHost::GetScreenInfo() { - return WebScreenInfoFactory::screenInfo(view_); + Display* display = test_shell_x11::GtkWidgetGetDisplay(view_); + int screen_num = test_shell_x11::GtkWidgetGetScreenNum(view_); + return WebScreenInfoFactory::screenInfo(display, screen_num); } void WebWidgetHost::ResetScrollRect() { diff --git a/webkit/webkit.gyp b/webkit/webkit.gyp index f2bf19e2..65610d4 100644 --- a/webkit/webkit.gyp +++ b/webkit/webkit.gyp @@ -4154,7 +4154,7 @@ ], 'sources': [ '../third_party/WebKit/WebKit/chromium/public/gtk/WebInputEventFactory.h', - '../third_party/WebKit/WebKit/chromium/public/gtk/WebScreenInfoFactory.h', + '../third_party/WebKit/WebKit/chromium/public/x11/WebScreenInfoFactory.h', '../third_party/WebKit/WebKit/chromium/public/mac/WebInputEventFactory.h', '../third_party/WebKit/WebKit/chromium/public/mac/WebScreenInfoFactory.h', '../third_party/WebKit/WebKit/chromium/public/WebCache.h', @@ -4188,7 +4188,7 @@ '../third_party/WebKit/WebKit/chromium/src/ChromiumCurrentTime.cpp', '../third_party/WebKit/WebKit/chromium/src/ChromiumThreading.cpp', '../third_party/WebKit/WebKit/chromium/src/gtk/WebInputEventFactory.cpp', - '../third_party/WebKit/WebKit/chromium/src/gtk/WebScreenInfoFactory.cpp', + '../third_party/WebKit/WebKit/chromium/src/x11/WebScreenInfoFactory.cpp', '../third_party/WebKit/WebKit/chromium/src/mac/WebInputEventFactory.mm', '../third_party/WebKit/WebKit/chromium/src/mac/WebScreenInfoFactory.mm', '../third_party/WebKit/WebKit/chromium/src/WebCache.cpp', @@ -4209,10 +4209,14 @@ '../build/linux/system.gyp:gtk', ], 'include_dirs': [ + '../third_party/WebKit/WebKit/chromium/public/x11', '../third_party/WebKit/WebKit/chromium/public/gtk', ], }, { # else: OS!="linux" - 'sources/': [['exclude', '/gtk/']], + 'sources/': [ + ['exclude', '/gtk/'], + ['exclude', '/x11/'], + ], }], ['OS=="mac"', { 'include_dirs': [ |