1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "mojo/services/native_viewport/native_viewport.h" 6 7 #include <X11/Xlib.h> 8 #include <X11/Xutil.h> 9 10 #include "base/message_loop/message_loop.h" 11 #include "ui/events/event.h" 12 #include "ui/events/platform/platform_event_dispatcher.h" 13 #include "ui/events/platform/platform_event_source.h" 14 #include "ui/events/platform/x11/x11_event_source.h" 15 #include "ui/gfx/rect.h" 16 #include "ui/gfx/x/x11_types.h" 17 18 namespace mojo { 19 namespace services { 20 21 class NativeViewportX11 : public NativeViewport, 22 public ui::PlatformEventDispatcher { 23 public: 24 NativeViewportX11(NativeViewportDelegate* delegate) 25 : delegate_(delegate) { 26 } 27 28 virtual ~NativeViewportX11() { 29 event_source_->RemovePlatformEventDispatcher(this); 30 31 XDestroyWindow(gfx::GetXDisplay(), window_); 32 } 33 34 private: 35 // Overridden from NativeViewport: 36 virtual void Init(const gfx::Rect& bounds) OVERRIDE { 37 XDisplay* display = gfx::GetXDisplay(); 38 39 XSetWindowAttributes swa; 40 memset(&swa, 0, sizeof(swa)); 41 swa.override_redirect = False; 42 43 bounds_ = bounds; 44 window_ = XCreateWindow( 45 display, 46 DefaultRootWindow(display), 47 bounds_.x(), bounds_.y(), bounds_.width(), bounds_.height(), 48 0, // border width 49 CopyFromParent, // depth 50 InputOutput, 51 CopyFromParent, // visual 52 CWBackPixmap | CWOverrideRedirect, 53 &swa); 54 55 atom_wm_protocols_ = XInternAtom(display, "WM_PROTOCOLS", 1); 56 atom_wm_delete_window_ = XInternAtom(display, "WM_DELETE_WINDOW", 1); 57 XSetWMProtocols(display, window_, &atom_wm_delete_window_, 1); 58 59 event_source_ = ui::PlatformEventSource::CreateDefault(); 60 event_source_->AddPlatformEventDispatcher(this); 61 62 long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask | 63 KeyPressMask | KeyReleaseMask | EnterWindowMask | LeaveWindowMask | 64 ExposureMask | VisibilityChangeMask | StructureNotifyMask | 65 PropertyChangeMask | PointerMotionMask; 66 XSelectInput(display, window_, event_mask); 67 68 // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with 69 // the desktop environment. 70 XSetWMProperties(display, window_, NULL, NULL, NULL, 0, NULL, NULL, NULL); 71 72 // TODO(aa): Setup xinput2 events. 73 // See desktop_aura/desktop_window_tree_host_x11.cc. 74 75 delegate_->OnAcceleratedWidgetAvailable(window_); 76 } 77 78 virtual void Show() OVERRIDE { 79 XDisplay* display = gfx::GetXDisplay(); 80 XMapWindow(display, window_); 81 static_cast<ui::X11EventSource*>( 82 event_source_.get())->BlockUntilWindowMapped(window_); 83 XFlush(display); 84 } 85 86 virtual void Hide() OVERRIDE { 87 XWithdrawWindow(gfx::GetXDisplay(), window_, 0); 88 } 89 90 virtual void Close() OVERRIDE { 91 // TODO(beng): perform this in response to XWindow destruction. 92 delegate_->OnDestroyed(); 93 } 94 95 virtual gfx::Size GetSize() OVERRIDE { 96 return bounds_.size(); 97 } 98 99 virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE { 100 NOTIMPLEMENTED(); 101 } 102 103 virtual void SetCapture() OVERRIDE { 104 NOTIMPLEMENTED(); 105 } 106 107 virtual void ReleaseCapture() OVERRIDE { 108 NOTIMPLEMENTED(); 109 } 110 111 // ui::PlatformEventDispatcher: 112 virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE { 113 // TODO(aa): This is going to have to be thought through more carefully. 114 // Which events are appropriate to pass to clients? 115 switch (event->type) { 116 case KeyPress: 117 case KeyRelease: 118 case ButtonPress: 119 case ButtonRelease: 120 case MotionNotify: 121 return true; 122 case ClientMessage: 123 return event->xclient.message_type == atom_wm_protocols_; 124 default: 125 return false; 126 } 127 } 128 129 virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE { 130 if (event->type == ClientMessage) { 131 Atom protocol = static_cast<Atom>(event->xclient.data.l[0]); 132 if (protocol == atom_wm_delete_window_) 133 delegate_->OnDestroyed(); 134 } else if (event->type == KeyPress || event->type == KeyRelease) { 135 ui::KeyEvent key_event(event, false); 136 delegate_->OnEvent(&key_event); 137 } else if (event->type == ButtonPress || event->type == ButtonRelease || 138 event->type == MotionNotify) { 139 ui::MouseEvent mouse_event(event); 140 delegate_->OnEvent(&mouse_event); 141 } 142 return ui::POST_DISPATCH_NONE; 143 } 144 145 scoped_ptr<ui::PlatformEventSource> event_source_; 146 NativeViewportDelegate* delegate_; 147 gfx::Rect bounds_; 148 XID window_; 149 Atom atom_wm_protocols_; 150 Atom atom_wm_delete_window_; 151 152 DISALLOW_COPY_AND_ASSIGN(NativeViewportX11); 153 }; 154 155 // static 156 scoped_ptr<NativeViewport> NativeViewport::Create( 157 shell::Context* context, 158 NativeViewportDelegate* delegate) { 159 return scoped_ptr<NativeViewport>(new NativeViewportX11(delegate)).Pass(); 160 } 161 162 } // namespace services 163 } // namespace mojo 164