Chromium Code Reviews| Index: ui/aura/root_window_host_linux.cc |
| diff --git a/ui/aura/root_window_host_linux.cc b/ui/aura/root_window_host_linux.cc |
| index e6b61c1fed9c5a08372fec0391f57898200bb820..63dc4cf1808ecbca80918335752d6672680b219d 100644 |
| --- a/ui/aura/root_window_host_linux.cc |
| +++ b/ui/aura/root_window_host_linux.cc |
| @@ -4,6 +4,7 @@ |
| #include "ui/aura/root_window_host_linux.h" |
| +#include <strings.h> |
| #include <X11/cursorfont.h> |
| #include <X11/extensions/Xfixes.h> |
| #include <X11/extensions/XInput2.h> |
| @@ -11,6 +12,7 @@ |
| #include <X11/Xatom.h> |
| #include <X11/Xcursor/Xcursor.h> |
| #include <X11/Xlib.h> |
| + |
| #include <algorithm> |
| #include "base/command_line.h" |
| @@ -18,6 +20,8 @@ |
| #include "base/message_pump_aurax11.h" |
| #include "base/stl_util.h" |
| #include "base/stringprintf.h" |
| +#include "third_party/skia/include/core/SkBitmap.h" |
| +#include "third_party/skia/include/core/SkCanvas.h" |
| #include "ui/aura/client/capture_client.h" |
| #include "ui/aura/client/cursor_client.h" |
| #include "ui/aura/client/screen_position_client.h" |
| @@ -432,123 +436,6 @@ bool RootWindowHostLinux::Dispatch(const base::NativeEvent& event) { |
| return true; |
| } |
| -bool RootWindowHostLinux::DispatchEventForRootWindow( |
| - const base::NativeEvent& event) { |
| - switch (event->type) { |
| - case ConfigureNotify: |
| - DCHECK_EQ(x_root_window_, event->xconfigure.event); |
| - x_root_bounds_.SetRect(event->xconfigure.x, event->xconfigure.y, |
| - event->xconfigure.width, event->xconfigure.height); |
| - break; |
| - |
| - case GenericEvent: |
| - DispatchXI2Event(event); |
| - break; |
| - } |
| - |
| - return true; |
| -} |
| - |
| -void RootWindowHostLinux::DispatchXI2Event(const base::NativeEvent& event) { |
| - ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); |
| - XEvent* xev = event; |
| - if (!factory->ShouldProcessXI2Event(xev)) |
| - return; |
| - |
| - ui::EventType type = ui::EventTypeFromNative(xev); |
| - XEvent last_event; |
| - int num_coalesced = 0; |
| - |
| - switch (type) { |
| - case ui::ET_TOUCH_MOVED: |
| - num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event); |
| - if (num_coalesced > 0) |
| - xev = &last_event; |
| - // fallthrough |
| - case ui::ET_TOUCH_PRESSED: |
| - case ui::ET_TOUCH_RELEASED: { |
| - ui::TouchEvent touchev(xev); |
| -#if defined(OS_CHROMEOS) |
| - // X maps the touch-surface to the size of the X root-window. In |
| - // multi-monitor setup, the X root-window size is a combination of |
| - // both the monitor sizes. So it is necessary to remap the location of |
| - // the event from the X root-window to the X host-window for the aura |
| - // root-window. |
| - if (base::chromeos::IsRunningOnChromeOS()) { |
| - touchev.CalibrateLocation(x_root_bounds_.size(), bounds_.size()); |
| - if (!bounds_.Contains(touchev.location())) { |
| - // This might still be in the bezel region. |
| - gfx::Rect expanded(bounds_); |
| - expanded.Inset(-kXRootWindowPaddingLeft, |
| - -kXRootWindowPaddingTop, |
| - -kXRootWindowPaddingRight, |
| - -kXRootWindowPaddingBottom); |
| - if (!expanded.Contains(touchev.location())) |
| - break; |
| - } |
| - } |
| -#endif // defined(OS_CHROMEOS) |
| - delegate_->OnHostTouchEvent(&touchev); |
| - break; |
| - } |
| - case ui::ET_MOUSE_MOVED: |
| - case ui::ET_MOUSE_DRAGGED: |
| - case ui::ET_MOUSE_PRESSED: |
| - case ui::ET_MOUSE_RELEASED: |
| - case ui::ET_MOUSE_ENTERED: |
| - case ui::ET_MOUSE_EXITED: { |
| - if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) { |
| - // If this is a motion event, we want to coalesce all pending motion |
| - // events that are at the top of the queue. |
| - num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event); |
| - if (num_coalesced > 0) |
| - xev = &last_event; |
| - } else if (type == ui::ET_MOUSE_PRESSED) { |
| - XIDeviceEvent* xievent = |
| - static_cast<XIDeviceEvent*>(xev->xcookie.data); |
| - int button = xievent->detail; |
| - if (button == kBackMouseButton || button == kForwardMouseButton) { |
| - client::UserActionClient* gesture_client = |
| - client::GetUserActionClient(delegate_->AsRootWindow()); |
| - if (gesture_client) { |
| - bool reverse_direction = |
| - ui::IsTouchpadEvent(xev) && ui::IsNaturalScrollEnabled(); |
| - gesture_client->OnUserAction( |
| - (button == kBackMouseButton && !reverse_direction) || |
| - (button == kForwardMouseButton && reverse_direction) ? |
| - client::UserActionClient::BACK : |
| - client::UserActionClient::FORWARD); |
| - } |
| - break; |
| - } |
| - } |
| - ui::MouseEvent mouseev(xev); |
| - TranslateAndDispatchMouseEvent(&mouseev); |
| - break; |
| - } |
| - case ui::ET_MOUSEWHEEL: { |
| - ui::MouseWheelEvent mouseev(xev); |
| - TranslateAndDispatchMouseEvent(&mouseev); |
| - break; |
| - } |
| - case ui::ET_SCROLL_FLING_START: |
| - case ui::ET_SCROLL_FLING_CANCEL: |
| - case ui::ET_SCROLL: { |
| - ui::ScrollEvent scrollev(xev); |
| - delegate_->OnHostScrollEvent(&scrollev); |
| - break; |
| - } |
| - case ui::ET_UNKNOWN: |
| - break; |
| - default: |
| - NOTREACHED(); |
| - } |
| - |
| - // If we coalesced an event we need to free its cookie. |
| - if (num_coalesced > 0) |
| - XFreeEventData(xev->xgeneric.display, &last_event.xcookie); |
| -} |
| - |
| void RootWindowHostLinux::SetDelegate(RootWindowHostDelegate* delegate) { |
| delegate_ = delegate; |
| } |
| @@ -741,19 +628,53 @@ void RootWindowHostLinux::SetFocusWhenShown(bool focus_when_shown) { |
| } |
| } |
| +bool RootWindowHostLinux::CopyAreaToSkCanvas(const gfx::Rect& source_bounds, |
| + const gfx::Point& dest_offset, |
| + SkCanvas* canvas) { |
| + scoped_ptr<ui::XScopedImage> scoped_image(GetXImage(source_bounds)); |
| + if (!scoped_image.get()) |
| + return false; |
| + |
| + XImage* image = scoped_image->get(); |
| + DCHECK(image); |
| + |
| + if (image->bits_per_pixel == 32) { |
| + // Set the alpha channel before copying to the canvas. Otherwise, areas of |
| + // the framebuffer that were cleared by ply-image rather than being obscured |
| + // by an image during boot may end up transparent. |
| + // TODO(derat|marcheu): Remove this if/when ply-image has been updated to |
| + // set the framebuffer's alpha channel regardless of whether the device |
| + // claims to support alpha or not. |
| + for (int i = 0; i < image->width * image->height * 4; i += 4) |
| + image->data[i + 3] = 0xff; |
| + |
| + SkBitmap bitmap; |
| + bitmap.setConfig(SkBitmap::kARGB_8888_Config, |
| + image->width, image->height, |
| + image->bytes_per_line); |
| + bitmap.setPixels(image->data); |
| + SkCanvas::Config8888 config = |
| + (image->byte_order == LSBFirst) ? |
| + SkCanvas::kBGRA_Unpremul_Config8888 : |
| + SkCanvas::kRGBA_Unpremul_Config8888; |
| + canvas->writePixels(bitmap, dest_offset.x(), dest_offset.y(), config); |
| + } else if (image->bits_per_pixel == 24) { |
| + NOTIMPLEMENTED() << "Unsupported bits-per-pixel " << image->bits_per_pixel; |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| bool RootWindowHostLinux::GrabSnapshot( |
| const gfx::Rect& snapshot_bounds, |
| std::vector<unsigned char>* png_representation) { |
| - ui::XScopedImage image(XGetImage( |
| - xdisplay_, xwindow_, |
| - snapshot_bounds.x(), snapshot_bounds.y(), |
| - snapshot_bounds.width(), snapshot_bounds.height(), |
| - AllPlanes, ZPixmap)); |
| - |
| - if (!image.get()) { |
| - LOG(ERROR) << "XGetImage failed"; |
| + scoped_ptr<ui::XScopedImage> scoped_image(GetXImage(snapshot_bounds)); |
| + if (!scoped_image.get()) |
| return false; |
| - } |
| + |
| + XImage* image = scoped_image->get(); |
| + DCHECK(image); |
| gfx::PNGCodec::ColorFormat color_format; |
| @@ -827,6 +748,123 @@ void RootWindowHostLinux::PrepareForShutdown() { |
| base::MessagePumpAuraX11::Current()->RemoveDispatcherForWindow(xwindow_); |
| } |
| +bool RootWindowHostLinux::DispatchEventForRootWindow( |
|
Daniel Erat
2012/10/26 00:41:15
sorry, moved this code without any changes to it t
|
| + const base::NativeEvent& event) { |
| + switch (event->type) { |
| + case ConfigureNotify: |
| + DCHECK_EQ(x_root_window_, event->xconfigure.event); |
| + x_root_bounds_.SetRect(event->xconfigure.x, event->xconfigure.y, |
| + event->xconfigure.width, event->xconfigure.height); |
| + break; |
| + |
| + case GenericEvent: |
| + DispatchXI2Event(event); |
| + break; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +void RootWindowHostLinux::DispatchXI2Event(const base::NativeEvent& event) { |
| + ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); |
| + XEvent* xev = event; |
| + if (!factory->ShouldProcessXI2Event(xev)) |
| + return; |
| + |
| + ui::EventType type = ui::EventTypeFromNative(xev); |
| + XEvent last_event; |
| + int num_coalesced = 0; |
| + |
| + switch (type) { |
| + case ui::ET_TOUCH_MOVED: |
| + num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event); |
| + if (num_coalesced > 0) |
| + xev = &last_event; |
| + // fallthrough |
| + case ui::ET_TOUCH_PRESSED: |
| + case ui::ET_TOUCH_RELEASED: { |
| + ui::TouchEvent touchev(xev); |
| +#if defined(OS_CHROMEOS) |
| + // X maps the touch-surface to the size of the X root-window. In |
| + // multi-monitor setup, the X root-window size is a combination of |
| + // both the monitor sizes. So it is necessary to remap the location of |
| + // the event from the X root-window to the X host-window for the aura |
| + // root-window. |
| + if (base::chromeos::IsRunningOnChromeOS()) { |
| + touchev.CalibrateLocation(x_root_bounds_.size(), bounds_.size()); |
| + if (!bounds_.Contains(touchev.location())) { |
| + // This might still be in the bezel region. |
| + gfx::Rect expanded(bounds_); |
| + expanded.Inset(-kXRootWindowPaddingLeft, |
| + -kXRootWindowPaddingTop, |
| + -kXRootWindowPaddingRight, |
| + -kXRootWindowPaddingBottom); |
| + if (!expanded.Contains(touchev.location())) |
| + break; |
| + } |
| + } |
| +#endif // defined(OS_CHROMEOS) |
| + delegate_->OnHostTouchEvent(&touchev); |
| + break; |
| + } |
| + case ui::ET_MOUSE_MOVED: |
| + case ui::ET_MOUSE_DRAGGED: |
| + case ui::ET_MOUSE_PRESSED: |
| + case ui::ET_MOUSE_RELEASED: |
| + case ui::ET_MOUSE_ENTERED: |
| + case ui::ET_MOUSE_EXITED: { |
| + if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) { |
| + // If this is a motion event, we want to coalesce all pending motion |
| + // events that are at the top of the queue. |
| + num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event); |
| + if (num_coalesced > 0) |
| + xev = &last_event; |
| + } else if (type == ui::ET_MOUSE_PRESSED) { |
| + XIDeviceEvent* xievent = |
| + static_cast<XIDeviceEvent*>(xev->xcookie.data); |
| + int button = xievent->detail; |
| + if (button == kBackMouseButton || button == kForwardMouseButton) { |
| + client::UserActionClient* gesture_client = |
| + client::GetUserActionClient(delegate_->AsRootWindow()); |
| + if (gesture_client) { |
| + bool reverse_direction = |
| + ui::IsTouchpadEvent(xev) && ui::IsNaturalScrollEnabled(); |
| + gesture_client->OnUserAction( |
| + (button == kBackMouseButton && !reverse_direction) || |
| + (button == kForwardMouseButton && reverse_direction) ? |
| + client::UserActionClient::BACK : |
| + client::UserActionClient::FORWARD); |
| + } |
| + break; |
| + } |
| + } |
| + ui::MouseEvent mouseev(xev); |
| + TranslateAndDispatchMouseEvent(&mouseev); |
| + break; |
| + } |
| + case ui::ET_MOUSEWHEEL: { |
| + ui::MouseWheelEvent mouseev(xev); |
| + TranslateAndDispatchMouseEvent(&mouseev); |
| + break; |
| + } |
| + case ui::ET_SCROLL_FLING_START: |
| + case ui::ET_SCROLL_FLING_CANCEL: |
| + case ui::ET_SCROLL: { |
| + ui::ScrollEvent scrollev(xev); |
| + delegate_->OnHostScrollEvent(&scrollev); |
| + break; |
| + } |
| + case ui::ET_UNKNOWN: |
| + break; |
| + default: |
| + NOTREACHED(); |
| + } |
| + |
| + // If we coalesced an event we need to free its cookie. |
| + if (num_coalesced > 0) |
| + XFreeEventData(xev->xgeneric.display, &last_event.xcookie); |
| +} |
| + |
| bool RootWindowHostLinux::IsWindowManagerPresent() { |
| // Per ICCCM 2.8, "Manager Selections", window managers should take ownership |
| // of WM_Sn selections (where n is a screen number). |
| @@ -856,6 +894,20 @@ void RootWindowHostLinux::TranslateAndDispatchMouseEvent( |
| delegate_->OnHostMouseEvent(event); |
| } |
| +scoped_ptr<ui::XScopedImage> RootWindowHostLinux::GetXImage( |
| + const gfx::Rect& snapshot_bounds) { |
| + scoped_ptr<ui::XScopedImage> image(new ui::XScopedImage( |
| + XGetImage(xdisplay_, xwindow_, |
| + snapshot_bounds.x(), snapshot_bounds.y(), |
| + snapshot_bounds.width(), snapshot_bounds.height(), |
| + AllPlanes, ZPixmap))); |
| + if (!image->get()) { |
| + LOG(ERROR) << "XGetImage failed"; |
| + image.reset(); |
| + } |
| + return image.Pass(); |
| +} |
| + |
| // static |
| RootWindowHost* RootWindowHost::Create(const gfx::Rect& bounds) { |
| return new RootWindowHostLinux(bounds); |