Index: ui/gl/gl_surface_glx.cc |
diff --git a/ui/gl/gl_surface_glx.cc b/ui/gl/gl_surface_glx.cc |
index 8b705dfbe93751c899daa05752cc585d64229097..422f6a044068e5b36946aa2bb6cf5168a76e474d 100644 |
--- a/ui/gl/gl_surface_glx.cc |
+++ b/ui/gl/gl_surface_glx.cc |
@@ -10,6 +10,7 @@ extern "C" { |
#include "base/basictypes.h" |
#include "base/debug/trace_event.h" |
+#include "base/lazy_instance.h" |
#include "base/logging.h" |
#include "base/memory/scoped_ptr.h" |
#include "base/memory/weak_ptr.h" |
@@ -39,7 +40,7 @@ class ScopedPtrXFree { |
} |
}; |
-Display* g_display; |
+Display* g_display = NULL; |
const char* g_glx_extensions = NULL; |
bool g_glx_context_create = false; |
bool g_glx_create_context_robustness_supported = false; |
@@ -315,7 +316,17 @@ bool GLSurfaceGLX::InitializeOneOff() { |
// it's own thread. |
XInitThreads(); |
+#if defined(TOOLKIT_GTK) |
+ // Be sure to use the X display handle and not the GTK display handle if this |
+ // is the GPU process. |
+ if (base::MessageLoop::current()->type() == base::MessageLoop::TYPE_GPU) |
+ g_display = base::MessagePumpX11::GetDefaultXDisplay(); |
+ else |
+ g_display = base::MessagePumpForUI::GetDefaultXDisplay(); |
+#else |
g_display = base::MessagePumpForUI::GetDefaultXDisplay(); |
+#endif |
+ |
if (!g_display) { |
LOG(ERROR) << "XOpenDisplay failed."; |
return false; |
@@ -388,31 +399,176 @@ void* GLSurfaceGLX::GetDisplay() { |
GLSurfaceGLX::~GLSurfaceGLX() {} |
+#if defined(TOOLKIT_GTK) |
+// A mechanism for forwarding XExpose events from one window to another. |
+// Because in the workaround for http://crbug.com/145600 the child window |
+// is placed on top of the parent window, only the child window will receive |
+// all expose events. These need to be forwared to the parent window to inform |
+// it that it should paint. |
+class XExposeEventForwarder : public base::MessagePumpObserver { |
piman
2013/09/11 23:05:09
nit: move this to an anonoymous namespace.
ccameron
2013/09/12 01:37:13
Done.
|
+ public: |
+ XExposeEventForwarder() { |
+ base::MessagePumpX11::Current()->AddObserver(this); |
+ } |
+ ~XExposeEventForwarder() { |
+ base::MessagePumpX11::Current()->RemoveObserver(this); |
piman
2013/09/11 23:05:09
If this is a lazy instance, the destructor will ru
ccameron
2013/09/12 01:37:13
Good catch, thanks. Moved to the Add/RemoveParentC
|
+ } |
+ |
+ void AddParentChildPair(gfx::AcceleratedWidget parent_window, |
+ gfx::AcceleratedWidget child_window) { |
+ DCHECK(child_to_parent_map_.find(child_window) == |
+ child_to_parent_map_.end()); |
+ child_to_parent_map_.insert(std::make_pair( |
+ child_window, parent_window)); |
+ } |
+ void RemoveParentChildPair(gfx::AcceleratedWidget parent_window, |
+ gfx::AcceleratedWidget child_window) { |
+ DCHECK(child_to_parent_map_.find(child_window) != |
+ child_to_parent_map_.end()); |
+ child_to_parent_map_.erase(child_window); |
+ } |
+ |
+ private: |
+ virtual base::EventStatus WillProcessEvent( |
+ const base::NativeEvent& xevent) OVERRIDE { |
+ if (xevent->type != Expose) |
+ return base::EVENT_CONTINUE; |
+ |
+ WindowMap::const_iterator found = child_to_parent_map_.find( |
+ xevent->xexpose.window); |
+ if (found == child_to_parent_map_.end()) |
+ return base::EVENT_CONTINUE; |
+ |
+ gfx::AcceleratedWidget target_window = found->second; |
+ XEvent forwarded_event = *xevent; |
+ forwarded_event.xexpose.window = target_window; |
+ XSendEvent(g_display, target_window, False, ExposureMask, |
+ &forwarded_event); |
+ return base::EVENT_CONTINUE; |
+ } |
+ virtual void DidProcessEvent(const base::NativeEvent& xevent) { |
+ } |
+ |
+ typedef std::map<gfx::AcceleratedWidget, gfx::AcceleratedWidget> WindowMap; |
+ WindowMap child_to_parent_map_; |
+}; |
+ |
+static base::LazyInstance<XExposeEventForwarder> g_xexpose_event_forwarder = |
+ LAZY_INSTANCE_INITIALIZER; |
+ |
+bool NativeViewGLSurfaceGLX::SetBackbufferAllocation(bool allocated) { |
+ if (allocated) |
+ return CreateChildWindow(); |
+ else |
+ DestroyChildWindow(); |
+ return true; |
+} |
+ |
+bool NativeViewGLSurfaceGLX::CreateChildWindow() { |
+ if (child_window_) |
+ return true; |
+ |
+ XWindowAttributes attributes; |
+ if (!XGetWindowAttributes(g_display, parent_window_, &attributes)) { |
piman
2013/09/11 23:05:09
Could we cache this? It requires a round trip to X
ccameron
2013/09/12 01:37:13
Actually, we can just use CopyFromParent and avoid
|
+ LOG(ERROR) << "XGetWindowAttributes failed for window " << parent_window_ |
+ << "."; |
+ return false; |
+ } |
+ |
+ XSetWindowAttributes set_window_attributes; |
+ set_window_attributes.event_mask = ExposureMask; |
+ child_window_ = XCreateWindow( |
+ g_display, parent_window_, 0, 0, attributes.width, attributes.height, 0, |
+ attributes.depth, InputOutput, attributes.visual, CWEventMask, |
+ &set_window_attributes); |
+ g_xexpose_event_forwarder.Pointer()->AddParentChildPair( |
+ parent_window_, child_window_); |
+ |
+ XMapWindow(g_display, child_window_); |
+ XFlush(g_display); |
+ |
+ // If the dummy window was current, make the child window current now. |
+ if (dummy_window_ == glXGetCurrentDrawable()) |
+ glXMakeCurrent(g_display, child_window_, glXGetCurrentContext()); |
+ |
+ return true; |
+} |
+ |
+void NativeViewGLSurfaceGLX::DestroyChildWindow() { |
+ if (!child_window_) |
+ return; |
+ |
piman
2013/09/11 23:05:09
Do we need to glXMakeCurrent the dummy_window_ her
ccameron
2013/09/12 01:37:13
Doesn't look like it. And I may make dummy_window_
|
+ g_xexpose_event_forwarder.Pointer()->RemoveParentChildPair( |
+ parent_window_, child_window_); |
+ XDestroyWindow(g_display, child_window_); |
+ XFlush(g_display); |
+ child_window_ = 0; |
+} |
+#endif |
+ |
NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window) |
- : window_(window), |
+ : parent_window_(window), |
+#if defined(TOOLKIT_GTK) |
+ child_window_(0), |
+ dummy_window_(0), |
+#endif |
config_(NULL) { |
} |
+gfx::AcceleratedWidget NativeViewGLSurfaceGLX::GetDrawableHandle() const { |
+#if defined(TOOLKIT_GTK) |
+ if (child_window_) |
+ return child_window_; |
+ return dummy_window_; |
+#else |
+ return parent_window_; |
+#endif |
+} |
+ |
bool NativeViewGLSurfaceGLX::Initialize() { |
XWindowAttributes attributes; |
- if (!XGetWindowAttributes(g_display, window_, &attributes)) { |
- LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << "."; |
+ if (!XGetWindowAttributes(g_display, parent_window_, &attributes)) { |
+ LOG(ERROR) << "XGetWindowAttributes failed for window " << parent_window_ |
+ << "."; |
return false; |
} |
size_ = gfx::Size(attributes.width, attributes.height); |
+ gfx::AcceleratedWidget window_for_vsync = parent_window_; |
+ |
+#if defined(TOOLKIT_GTK) |
+ CreateChildWindow(); |
+ dummy_window_ = XCreateWindow( |
+ g_display, parent_window_, 0, 0, 1, 1, 0, attributes.depth, InputOutput, |
+ attributes.visual, 0, NULL); |
+ window_for_vsync = dummy_window_; |
+#endif |
+ |
if (g_glx_oml_sync_control_supported) |
- vsync_provider_.reset(new OMLSyncControlVSyncProvider(window_)); |
+ vsync_provider_.reset(new OMLSyncControlVSyncProvider(window_for_vsync)); |
else if (g_glx_sgi_video_sync_supported) |
- vsync_provider_.reset(new SGIVideoSyncVSyncProvider(window_)); |
+ vsync_provider_.reset(new SGIVideoSyncVSyncProvider(window_for_vsync)); |
return true; |
} |
void NativeViewGLSurfaceGLX::Destroy() { |
+#if defined(TOOLKIT_GTK) |
+ if (dummy_window_) |
+ XDestroyWindow(g_display, dummy_window_); |
+ dummy_window_ = 0; |
+ |
+ DestroyChildWindow(); |
+#endif |
} |
bool NativeViewGLSurfaceGLX::Resize(const gfx::Size& size) { |
+#if defined(TOOLKIT_GTK) |
+ if (child_window_) { |
+ XResizeWindow(g_display, child_window_, size.width(), size.height()); |
+ XFlush(g_display); |
+ } |
+#endif |
size_ = size; |
return true; |
} |
@@ -422,7 +578,7 @@ bool NativeViewGLSurfaceGLX::IsOffscreen() { |
} |
bool NativeViewGLSurfaceGLX::SwapBuffers() { |
- glXSwapBuffers(g_display, window_); |
+ glXSwapBuffers(g_display, GetDrawableHandle()); |
return true; |
} |
@@ -431,7 +587,7 @@ gfx::Size NativeViewGLSurfaceGLX::GetSize() { |
} |
void* NativeViewGLSurfaceGLX::GetHandle() { |
- return reinterpret_cast<void*>(window_); |
+ return reinterpret_cast<void*>(GetDrawableHandle()); |
} |
std::string NativeViewGLSurfaceGLX::GetExtensions() { |
@@ -460,10 +616,10 @@ void* NativeViewGLSurfaceGLX::GetConfig() { |
XWindowAttributes attributes; |
if (!XGetWindowAttributes( |
g_display, |
- window_, |
+ parent_window_, |
&attributes)) { |
LOG(ERROR) << "XGetWindowAttributes failed for window " << |
- window_ << "."; |
+ parent_window_ << "."; |
return NULL; |
} |
@@ -507,7 +663,7 @@ void* NativeViewGLSurfaceGLX::GetConfig() { |
bool NativeViewGLSurfaceGLX::PostSubBuffer( |
int x, int y, int width, int height) { |
DCHECK(gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer); |
- glXCopySubBufferMESA(g_display, window_, x, y, width, height); |
+ glXCopySubBufferMESA(g_display, GetDrawableHandle(), x, y, width, height); |
return true; |
} |
@@ -516,7 +672,11 @@ VSyncProvider* NativeViewGLSurfaceGLX::GetVSyncProvider() { |
} |
NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX() |
- : window_(0), |
+ : parent_window_(0), |
+#if defined(TOOLKIT_GTK) |
+ child_window_(0), |
+ dummy_window_(0), |
+#endif |
config_(NULL) { |
} |