| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/aura/desktop_host.h" | 5 #include "ui/aura/desktop_host.h" |
| 6 | 6 |
| 7 #include <X11/cursorfont.h> | 7 #include <X11/cursorfont.h> |
| 8 #include <X11/Xlib.h> | 8 #include <X11/Xlib.h> |
| 9 | 9 |
| 10 // Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class. | 10 // Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class. |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 191 | 191 |
| 192 // DesktopHost Overrides. | 192 // DesktopHost Overrides. |
| 193 virtual void SetDesktop(Desktop* desktop) OVERRIDE; | 193 virtual void SetDesktop(Desktop* desktop) OVERRIDE; |
| 194 virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE; | 194 virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE; |
| 195 virtual void Show() OVERRIDE; | 195 virtual void Show() OVERRIDE; |
| 196 virtual gfx::Size GetSize() const OVERRIDE; | 196 virtual gfx::Size GetSize() const OVERRIDE; |
| 197 virtual void SetSize(const gfx::Size& size) OVERRIDE; | 197 virtual void SetSize(const gfx::Size& size) OVERRIDE; |
| 198 virtual void SetCursor(gfx::NativeCursor cursor_type) OVERRIDE; | 198 virtual void SetCursor(gfx::NativeCursor cursor_type) OVERRIDE; |
| 199 virtual gfx::Point QueryMouseLocation() OVERRIDE; | 199 virtual gfx::Point QueryMouseLocation() OVERRIDE; |
| 200 | 200 |
| 201 // Returns true if there's an X window manager present. | 201 // Returns true if there's an X window manager present... in most cases. Some |
| 202 // window managers (notably, ion3) don't implement enough of ICCCM for us to |
| 203 // detect that they're there. |
| 202 bool IsWindowManagerPresent(); | 204 bool IsWindowManagerPresent(); |
| 203 | 205 |
| 204 Desktop* desktop_; | 206 Desktop* desktop_; |
| 205 | 207 |
| 206 // The display and the native X window hosting the desktop. | 208 // The display and the native X window hosting the desktop. |
| 207 Display* xdisplay_; | 209 Display* xdisplay_; |
| 208 ::Window xwindow_; | 210 ::Window xwindow_; |
| 209 | 211 |
| 210 // Current Aura cursor. | 212 // Current Aura cursor. |
| 211 gfx::NativeCursor current_cursor_; | 213 gfx::NativeCursor current_cursor_; |
| 212 | 214 |
| 213 // The size of |xwindow_|. | 215 // The size of |xwindow_|. |
| 214 gfx::Rect bounds_; | 216 gfx::Size size_; |
| 215 | |
| 216 // True while we requested configure, but haven't recieved configure event | |
| 217 // yet. | |
| 218 bool expect_configure_event_; | |
| 219 | 217 |
| 220 DISALLOW_COPY_AND_ASSIGN(DesktopHostLinux); | 218 DISALLOW_COPY_AND_ASSIGN(DesktopHostLinux); |
| 221 }; | 219 }; |
| 222 | 220 |
| 223 DesktopHostLinux::DesktopHostLinux(const gfx::Rect& bounds) | 221 DesktopHostLinux::DesktopHostLinux(const gfx::Rect& bounds) |
| 224 : desktop_(NULL), | 222 : desktop_(NULL), |
| 225 xdisplay_(NULL), | 223 xdisplay_(base::MessagePumpX::GetDefaultXDisplay()), |
| 226 xwindow_(0), | 224 xwindow_(0), |
| 227 current_cursor_(aura::kCursorNull), | 225 current_cursor_(aura::kCursorNull), |
| 228 bounds_(bounds) { | 226 size_(bounds.size()) { |
| 229 // This assumes that the message-pump creates and owns the display. | |
| 230 xdisplay_ = base::MessagePumpX::GetDefaultXDisplay(); | |
| 231 | |
| 232 // Ingore the requested bounds and just cover the whole screen if there's no | |
| 233 // X window manager present. | |
| 234 if (!IsWindowManagerPresent()) | |
| 235 bounds_.SetRect( | |
| 236 0, 0, DisplayWidth(xdisplay_, 0), DisplayHeight(xdisplay_, 0)); | |
| 237 | |
| 238 xwindow_ = XCreateSimpleWindow(xdisplay_, DefaultRootWindow(xdisplay_), | 227 xwindow_ = XCreateSimpleWindow(xdisplay_, DefaultRootWindow(xdisplay_), |
| 239 bounds_.x(), bounds_.y(), | 228 bounds.x(), bounds.y(), |
| 240 bounds_.width(), bounds_.height(), | 229 bounds.width(), bounds.height(), |
| 241 0, 0, 0); | 230 0, 0, 0); |
| 242 | 231 |
| 243 long event_mask = ButtonPressMask | ButtonReleaseMask | | 232 long event_mask = ButtonPressMask | ButtonReleaseMask | |
| 244 KeyPressMask | KeyReleaseMask | | 233 KeyPressMask | KeyReleaseMask | |
| 245 ExposureMask | VisibilityChangeMask | | 234 ExposureMask | VisibilityChangeMask | |
| 246 StructureNotifyMask | PropertyChangeMask | | 235 StructureNotifyMask | PropertyChangeMask | |
| 247 PointerMotionMask; | 236 PointerMotionMask; |
| 248 XSelectInput(xdisplay_, xwindow_, event_mask); | 237 XSelectInput(xdisplay_, xwindow_, event_mask); |
| 249 XFlush(xdisplay_); | 238 XFlush(xdisplay_); |
| 250 | 239 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 275 KeyEvent keyup_event(xev, false); | 264 KeyEvent keyup_event(xev, false); |
| 276 handled = desktop_->DispatchKeyEvent(&keyup_event); | 265 handled = desktop_->DispatchKeyEvent(&keyup_event); |
| 277 break; | 266 break; |
| 278 } | 267 } |
| 279 case ButtonPress: | 268 case ButtonPress: |
| 280 case ButtonRelease: { | 269 case ButtonRelease: { |
| 281 MouseEvent mouseev(xev); | 270 MouseEvent mouseev(xev); |
| 282 handled = desktop_->DispatchMouseEvent(&mouseev); | 271 handled = desktop_->DispatchMouseEvent(&mouseev); |
| 283 break; | 272 break; |
| 284 } | 273 } |
| 285 case MotionNotify: { | |
| 286 // Discard all but the most recent motion event that targets the same | |
| 287 // window with unchanged state. | |
| 288 XEvent last_event; | |
| 289 while (XPending(xev->xany.display)) { | |
| 290 XEvent next_event; | |
| 291 XPeekEvent(xev->xany.display, &next_event); | |
| 292 if (next_event.type == MotionNotify && | |
| 293 next_event.xmotion.window == xev->xmotion.window && | |
| 294 next_event.xmotion.subwindow == xev->xmotion.subwindow && | |
| 295 next_event.xmotion.state == xev->xmotion.state) { | |
| 296 XNextEvent(xev->xany.display, &last_event); | |
| 297 xev = &last_event; | |
| 298 } else { | |
| 299 break; | |
| 300 } | |
| 301 } | |
| 302 | |
| 303 MouseEvent mouseev(xev); | |
| 304 handled = desktop_->DispatchMouseEvent(&mouseev); | |
| 305 break; | |
| 306 } | |
| 307 case ConfigureNotify: { | 274 case ConfigureNotify: { |
| 308 DCHECK_EQ(xdisplay_, xev->xconfigure.display); | 275 DCHECK_EQ(xdisplay_, xev->xconfigure.display); |
| 309 DCHECK_EQ(xwindow_, xev->xconfigure.window); | 276 DCHECK_EQ(xwindow_, xev->xconfigure.window); |
| 310 DCHECK_EQ(xwindow_, xev->xconfigure.event); | 277 DCHECK_EQ(xwindow_, xev->xconfigure.event); |
| 311 | 278 |
| 312 // It's possible that the X window may be resized by some other means than | 279 // It's possible that the X window may be resized by some other means than |
| 313 // from within aura (e.g. the X window manager can change the size). Make | 280 // from within aura (e.g. the X window manager can change the size). Make |
| 314 // sure the desktop size is maintained properly. | 281 // sure the desktop size is maintained properly. |
| 315 gfx::Size size(xev->xconfigure.width, xev->xconfigure.height); | 282 gfx::Size size(xev->xconfigure.width, xev->xconfigure.height); |
| 316 if (bounds_.size() != size || expect_configure_event_) { | 283 if (size_ != size) { |
| 317 expect_configure_event_ = false; | 284 size_ = size; |
| 318 bounds_.set_size(size); | |
| 319 desktop_->OnHostResized(size); | 285 desktop_->OnHostResized(size); |
| 320 } | 286 } |
| 321 handled = true; | 287 handled = true; |
| 322 break; | 288 break; |
| 323 } | 289 } |
| 324 | |
| 325 case GenericEvent: { | 290 case GenericEvent: { |
| 326 ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); | 291 ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); |
| 327 if (!factory->ShouldProcessXI2Event(xev)) | 292 if (!factory->ShouldProcessXI2Event(xev)) |
| 328 break; | 293 break; |
| 329 | 294 |
| 330 // If this is a motion event we want to coalesce all pending motion | 295 // If this is a motion event we want to coalesce all pending motion |
| 331 // events that are at the top of the queue. | 296 // events that are at the top of the queue. |
| 332 XEvent last_event; | 297 XEvent last_event; |
| 333 int num_coalesced = 0; | 298 int num_coalesced = 0; |
| 334 if (xev->xgeneric.evtype == XI_Motion) { | 299 if (xev->xgeneric.evtype == XI_Motion) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 360 case ui::ET_UNKNOWN: | 325 case ui::ET_UNKNOWN: |
| 361 handled = false; | 326 handled = false; |
| 362 break; | 327 break; |
| 363 default: | 328 default: |
| 364 NOTREACHED(); | 329 NOTREACHED(); |
| 365 } | 330 } |
| 366 | 331 |
| 367 // If we coalesced an event we need to free its cookie. | 332 // If we coalesced an event we need to free its cookie. |
| 368 if (num_coalesced > 0) | 333 if (num_coalesced > 0) |
| 369 XFreeEventData(xev->xgeneric.display, &last_event.xcookie); | 334 XFreeEventData(xev->xgeneric.display, &last_event.xcookie); |
| 335 break; |
| 336 } |
| 337 case MapNotify: { |
| 338 // If there's no window manager running, we need to assign the X input |
| 339 // focus to our host window. |
| 340 if (!IsWindowManagerPresent()) |
| 341 XSetInputFocus(xdisplay_, xwindow_, RevertToNone, CurrentTime); |
| 342 handled = true; |
| 343 break; |
| 344 } |
| 345 case MotionNotify: { |
| 346 // Discard all but the most recent motion event that targets the same |
| 347 // window with unchanged state. |
| 348 XEvent last_event; |
| 349 while (XPending(xev->xany.display)) { |
| 350 XEvent next_event; |
| 351 XPeekEvent(xev->xany.display, &next_event); |
| 352 if (next_event.type == MotionNotify && |
| 353 next_event.xmotion.window == xev->xmotion.window && |
| 354 next_event.xmotion.subwindow == xev->xmotion.subwindow && |
| 355 next_event.xmotion.state == xev->xmotion.state) { |
| 356 XNextEvent(xev->xany.display, &last_event); |
| 357 xev = &last_event; |
| 358 } else { |
| 359 break; |
| 360 } |
| 361 } |
| 362 |
| 363 MouseEvent mouseev(xev); |
| 364 handled = desktop_->DispatchMouseEvent(&mouseev); |
| 365 break; |
| 370 } | 366 } |
| 371 } | 367 } |
| 372 return handled ? EVENT_PROCESSED : EVENT_IGNORED; | 368 return handled ? EVENT_PROCESSED : EVENT_IGNORED; |
| 373 } | 369 } |
| 374 | 370 |
| 375 void DesktopHostLinux::SetDesktop(Desktop* desktop) { | 371 void DesktopHostLinux::SetDesktop(Desktop* desktop) { |
| 376 desktop_ = desktop; | 372 desktop_ = desktop; |
| 377 } | 373 } |
| 378 | 374 |
| 379 gfx::AcceleratedWidget DesktopHostLinux::GetAcceleratedWidget() { | 375 gfx::AcceleratedWidget DesktopHostLinux::GetAcceleratedWidget() { |
| 380 return xwindow_; | 376 return xwindow_; |
| 381 } | 377 } |
| 382 | 378 |
| 383 void DesktopHostLinux::Show() { | 379 void DesktopHostLinux::Show() { |
| 384 XMapWindow(xdisplay_, xwindow_); | 380 XMapWindow(xdisplay_, xwindow_); |
| 385 | |
| 386 // If there's no window manager running, we need to assign the X input focus | |
| 387 // to our host window. (If there's no window manager running, it should also | |
| 388 // be safe to assume that the host window will have been mapped by the time | |
| 389 // that our SetInputFocus request is received.) | |
| 390 if (!IsWindowManagerPresent()) | |
| 391 XSetInputFocus(xdisplay_, xwindow_, RevertToNone, CurrentTime); | |
| 392 | |
| 393 XFlush(xdisplay_); | |
| 394 } | 381 } |
| 395 | 382 |
| 396 gfx::Size DesktopHostLinux::GetSize() const { | 383 gfx::Size DesktopHostLinux::GetSize() const { |
| 397 return bounds_.size(); | 384 return size_; |
| 398 } | 385 } |
| 399 | 386 |
| 400 void DesktopHostLinux::SetSize(const gfx::Size& size) { | 387 void DesktopHostLinux::SetSize(const gfx::Size& size) { |
| 401 if (bounds_.size() == size) | 388 if (size == size_) |
| 402 return; | 389 return; |
| 403 expect_configure_event_ = true; | 390 |
| 404 bounds_.set_size(size); | |
| 405 XResizeWindow(xdisplay_, xwindow_, size.width(), size.height()); | 391 XResizeWindow(xdisplay_, xwindow_, size.width(), size.height()); |
| 392 |
| 393 // Assume that the resize will go through as requested, which should be the |
| 394 // case if we're running without a window manager. If there's a window |
| 395 // manager, it can modify or ignore the request, but (per ICCCM) we'll get a |
| 396 // (possibly synthetic) ConfigureNotify about the actual size and correct |
| 397 // |size_| later. |
| 398 size_ = size; |
| 399 desktop_->OnHostResized(size); |
| 406 } | 400 } |
| 407 | 401 |
| 408 void DesktopHostLinux::SetCursor(gfx::NativeCursor cursor) { | 402 void DesktopHostLinux::SetCursor(gfx::NativeCursor cursor) { |
| 409 if (current_cursor_ == cursor) | 403 if (current_cursor_ == cursor) |
| 410 return; | 404 return; |
| 411 current_cursor_ = cursor; | 405 current_cursor_ = cursor; |
| 412 // Custom web cursors are handled directly. | 406 // Custom web cursors are handled directly. |
| 413 if (cursor == kCursorCustom) | 407 if (cursor == kCursorCustom) |
| 414 return; | 408 return; |
| 415 int cursor_shape = CursorShapeFromNative(cursor); | 409 int cursor_shape = CursorShapeFromNative(cursor); |
| 416 ::Cursor xcursor = ui::GetXCursor(cursor_shape); | 410 ::Cursor xcursor = ui::GetXCursor(cursor_shape); |
| 417 XDefineCursor(xdisplay_, xwindow_, xcursor); | 411 XDefineCursor(xdisplay_, xwindow_, xcursor); |
| 418 } | 412 } |
| 419 | 413 |
| 420 gfx::Point DesktopHostLinux::QueryMouseLocation() { | 414 gfx::Point DesktopHostLinux::QueryMouseLocation() { |
| 421 ::Window root_return, child_return; | 415 ::Window root_return, child_return; |
| 422 int root_x_return, root_y_return, win_x_return, win_y_return; | 416 int root_x_return, root_y_return, win_x_return, win_y_return; |
| 423 unsigned int mask_return; | 417 unsigned int mask_return; |
| 424 XQueryPointer(xdisplay_, | 418 XQueryPointer(xdisplay_, |
| 425 xwindow_, | 419 xwindow_, |
| 426 &root_return, | 420 &root_return, |
| 427 &child_return, | 421 &child_return, |
| 428 &root_x_return, &root_y_return, | 422 &root_x_return, &root_y_return, |
| 429 &win_x_return, &win_y_return, | 423 &win_x_return, &win_y_return, |
| 430 &mask_return); | 424 &mask_return); |
| 431 return gfx::Point(max(0, min(bounds_.width(), win_x_return)), | 425 return gfx::Point(max(0, min(size_.width(), win_x_return)), |
| 432 max(0, min(bounds_.height(), win_y_return))); | 426 max(0, min(size_.height(), win_y_return))); |
| 433 } | 427 } |
| 434 | 428 |
| 435 bool DesktopHostLinux::IsWindowManagerPresent() { | 429 bool DesktopHostLinux::IsWindowManagerPresent() { |
| 436 // Per ICCCM 2.8, "Manager Selections", window managers should take ownership | 430 // Per ICCCM 2.8, "Manager Selections", window managers should take ownership |
| 437 // of WM_Sn selections (where n is a screen number). | 431 // of WM_Sn selections (where n is a screen number). |
| 438 ::Atom wm_s0_atom = XInternAtom(xdisplay_, "WM_S0", False); | 432 ::Atom wm_s0_atom = XInternAtom(xdisplay_, "WM_S0", False); |
| 439 return XGetSelectionOwner(xdisplay_, wm_s0_atom) != None; | 433 return XGetSelectionOwner(xdisplay_, wm_s0_atom) != None; |
| 440 } | 434 } |
| 441 | 435 |
| 442 } // namespace | 436 } // namespace |
| 443 | 437 |
| 444 // static | 438 // static |
| 445 DesktopHost* DesktopHost::Create(const gfx::Rect& bounds) { | 439 DesktopHost* DesktopHost::Create(const gfx::Rect& bounds) { |
| 446 return new DesktopHostLinux(bounds); | 440 return new DesktopHostLinux(bounds); |
| 447 } | 441 } |
| 448 | 442 |
| 443 // static |
| 444 gfx::Size DesktopHost::GetNativeDisplaySize() { |
| 445 ::Display* xdisplay = base::MessagePumpX::GetDefaultXDisplay(); |
| 446 return gfx::Size(DisplayWidth(xdisplay, 0), DisplayHeight(xdisplay, 0)); |
| 447 } |
| 448 |
| 449 } // namespace aura | 449 } // namespace aura |
| OLD | NEW |