| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h" | 5 #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h" |
| 6 | 6 |
| 7 #include <X11/Xatom.h> | 7 #include <X11/Xatom.h> |
| 8 | 8 |
| 9 #include "base/event_types.h" | 9 #include "base/event_types.h" |
| 10 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 73 | 73 |
| 74 // The time to wait since sending the last XdndPosition message before | 74 // The time to wait since sending the last XdndPosition message before |
| 75 // reprocessing the most recent mouse move event in case that the window | 75 // reprocessing the most recent mouse move event in case that the window |
| 76 // stacking order has changed and |source_current_window_| needs to be updated. | 76 // stacking order has changed and |source_current_window_| needs to be updated. |
| 77 const int kRepeatMouseMoveTimeoutMs = 350; | 77 const int kRepeatMouseMoveTimeoutMs = 350; |
| 78 | 78 |
| 79 static base::LazyInstance< | 79 static base::LazyInstance< |
| 80 std::map< ::Window, views::DesktopDragDropClientAuraX11*> >::Leaky | 80 std::map< ::Window, views::DesktopDragDropClientAuraX11*> >::Leaky |
| 81 g_live_client_map = LAZY_INSTANCE_INITIALIZER; | 81 g_live_client_map = LAZY_INSTANCE_INITIALIZER; |
| 82 | 82 |
| 83 // Returns the topmost X11 window at |screen_point| if it is advertising that | |
| 84 // is supports the Xdnd protocol. Will return the window under the pointer as | |
| 85 // |mouse_window|. If there's a Xdnd aware window, it will be returned in | |
| 86 // |dest_window|. | |
| 87 void FindWindowFor(const gfx::Point& screen_point, | |
| 88 ::Window* mouse_window, | |
| 89 ::Window* dest_window) { | |
| 90 views::X11TopmostWindowFinder finder; | |
| 91 *mouse_window = finder.FindWindowAt(screen_point); | |
| 92 *dest_window = None; | |
| 93 | |
| 94 if (*mouse_window == None) | |
| 95 return; | |
| 96 | |
| 97 // Figure out which window we should test as XdndAware. If mouse_window has | |
| 98 // XdndProxy, it will set that proxy on target, and if not, |target|'s | |
| 99 // original value will remain. | |
| 100 XID target = *mouse_window; | |
| 101 ui::GetXIDProperty(*mouse_window, "XdndProxy", &target); | |
| 102 | |
| 103 int version; | |
| 104 if (ui::GetIntProperty(target, "XdndAware", &version) && | |
| 105 version >= kMinXdndVersion) { | |
| 106 *dest_window = target; | |
| 107 } | |
| 108 } | |
| 109 | |
| 110 } // namespace | 83 } // namespace |
| 111 | 84 |
| 112 namespace views { | 85 namespace views { |
| 113 | 86 |
| 114 DesktopDragDropClientAuraX11* | 87 DesktopDragDropClientAuraX11* |
| 115 DesktopDragDropClientAuraX11::g_current_drag_drop_client = NULL; | 88 DesktopDragDropClientAuraX11::g_current_drag_drop_client = NULL; |
| 116 | 89 |
| 117 class DesktopDragDropClientAuraX11::X11DragContext | 90 class DesktopDragDropClientAuraX11::X11DragContext |
| 118 : public ui::PlatformEventDispatcher { | 91 : public ui::PlatformEventDispatcher { |
| 119 public: | 92 public: |
| (...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 529 unsigned long event_time = next_position_message_->second; | 502 unsigned long event_time = next_position_message_->second; |
| 530 next_position_message_.reset(); | 503 next_position_message_.reset(); |
| 531 | 504 |
| 532 SendXdndPosition(source_window, p, event_time); | 505 SendXdndPosition(source_window, p, event_time); |
| 533 } | 506 } |
| 534 } | 507 } |
| 535 | 508 |
| 536 void DesktopDragDropClientAuraX11::OnXdndFinished( | 509 void DesktopDragDropClientAuraX11::OnXdndFinished( |
| 537 const XClientMessageEvent& event) { | 510 const XClientMessageEvent& event) { |
| 538 DVLOG(1) << "XdndFinished"; | 511 DVLOG(1) << "XdndFinished"; |
| 512 unsigned long source_window = event.data.l[0]; |
| 513 if (source_current_window_ != source_window) |
| 514 return; |
| 515 |
| 516 // Clear |negotiated_operation_| if the drag was rejected. |
| 517 if ((event.data.l[1] & 1) == 0) |
| 518 negotiated_operation_ = ui::DragDropTypes::DRAG_NONE; |
| 539 | 519 |
| 540 // Clear |source_current_window_| to avoid sending XdndLeave upon ending the | 520 // Clear |source_current_window_| to avoid sending XdndLeave upon ending the |
| 541 // move loop. | 521 // move loop. |
| 542 source_current_window_ = None; | 522 source_current_window_ = None; |
| 543 move_loop_.EndMoveLoop(); | 523 move_loop_.EndMoveLoop(); |
| 544 } | 524 } |
| 545 | 525 |
| 546 void DesktopDragDropClientAuraX11::OnXdndDrop( | 526 void DesktopDragDropClientAuraX11::OnXdndDrop( |
| 547 const XClientMessageEvent& event) { | 527 const XClientMessageEvent& event) { |
| 548 DVLOG(1) << "XdndDrop"; | 528 DVLOG(1) << "XdndDrop"; |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 724 void DesktopDragDropClientAuraX11::OnMoveLoopEnded() { | 704 void DesktopDragDropClientAuraX11::OnMoveLoopEnded() { |
| 725 if (source_current_window_ != None) { | 705 if (source_current_window_ != None) { |
| 726 SendXdndLeave(source_current_window_); | 706 SendXdndLeave(source_current_window_); |
| 727 source_current_window_ = None; | 707 source_current_window_ = None; |
| 728 } | 708 } |
| 729 target_current_context_.reset(); | 709 target_current_context_.reset(); |
| 730 repeat_mouse_move_timer_.Stop(); | 710 repeat_mouse_move_timer_.Stop(); |
| 731 end_move_loop_timer_.Stop(); | 711 end_move_loop_timer_.Stop(); |
| 732 } | 712 } |
| 733 | 713 |
| 714 XID DesktopDragDropClientAuraX11::FindWindowFor( |
| 715 const gfx::Point& screen_point) { |
| 716 views::X11TopmostWindowFinder finder; |
| 717 ::Window target = finder.FindWindowAt(screen_point); |
| 718 |
| 719 if (target == None) |
| 720 return None; |
| 721 |
| 722 // Figure out which window we should test as XdndAware. If mouse_window has |
| 723 // XdndProxy, it will set that proxy on target, and if not, |target|'s |
| 724 // original value will remain. |
| 725 ui::GetXIDProperty(target, "XdndProxy", &target); |
| 726 |
| 727 int version; |
| 728 if (ui::GetIntProperty(target, "XdndAware", &version) && |
| 729 version >= kMinXdndVersion) { |
| 730 return target; |
| 731 } |
| 732 return None; |
| 733 } |
| 734 |
| 735 void DesktopDragDropClientAuraX11::SendXClientEvent(::Window xid, |
| 736 XEvent* xev) { |
| 737 DCHECK_EQ(ClientMessage, xev->type); |
| 738 |
| 739 // Don't send messages to the X11 message queue if we can help it. |
| 740 DesktopDragDropClientAuraX11* short_circuit = GetForWindow(xid); |
| 741 if (short_circuit) { |
| 742 Atom message_type = xev->xclient.message_type; |
| 743 if (message_type == atom_cache_.GetAtom("XdndEnter")) { |
| 744 short_circuit->OnXdndEnter(xev->xclient); |
| 745 return; |
| 746 } else if (message_type == atom_cache_.GetAtom("XdndLeave")) { |
| 747 short_circuit->OnXdndLeave(xev->xclient); |
| 748 return; |
| 749 } else if (message_type == atom_cache_.GetAtom("XdndPosition")) { |
| 750 short_circuit->OnXdndPosition(xev->xclient); |
| 751 return; |
| 752 } else if (message_type == atom_cache_.GetAtom("XdndStatus")) { |
| 753 short_circuit->OnXdndStatus(xev->xclient); |
| 754 return; |
| 755 } else if (message_type == atom_cache_.GetAtom("XdndFinished")) { |
| 756 short_circuit->OnXdndFinished(xev->xclient); |
| 757 return; |
| 758 } else if (message_type == atom_cache_.GetAtom("XdndDrop")) { |
| 759 short_circuit->OnXdndDrop(xev->xclient); |
| 760 return; |
| 761 } |
| 762 } |
| 763 |
| 764 // I don't understand why the GTK+ code is doing what it's doing here. It |
| 765 // goes out of its way to send the XEvent so that it receives a callback on |
| 766 // success or failure, and when it fails, it then sends an internal |
| 767 // GdkEvent about the failed drag. (And sending this message doesn't appear |
| 768 // to go through normal xlib machinery, but instead passes through the low |
| 769 // level xProto (the x11 wire format) that I don't understand. |
| 770 // |
| 771 // I'm unsure if I have to jump through those hoops, or if XSendEvent is |
| 772 // sufficient. |
| 773 XSendEvent(xdisplay_, xid, False, 0, xev); |
| 774 } |
| 775 |
| 734 void DesktopDragDropClientAuraX11::ProcessMouseMove( | 776 void DesktopDragDropClientAuraX11::ProcessMouseMove( |
| 735 const gfx::Point& screen_point, | 777 const gfx::Point& screen_point, |
| 736 unsigned long event_time) { | 778 unsigned long event_time) { |
| 737 if (source_state_ != SOURCE_STATE_OTHER) | 779 if (source_state_ != SOURCE_STATE_OTHER) |
| 738 return; | 780 return; |
| 739 | 781 |
| 740 // Find the current window the cursor is over. | 782 // Find the current window the cursor is over. |
| 741 ::Window mouse_window = None; | 783 ::Window dest_window = FindWindowFor(screen_point); |
| 742 ::Window dest_window = None; | |
| 743 FindWindowFor(screen_point, &mouse_window, &dest_window); | |
| 744 | 784 |
| 745 if (source_current_window_ != dest_window) { | 785 if (source_current_window_ != dest_window) { |
| 746 if (source_current_window_ != None) | 786 if (source_current_window_ != None) |
| 747 SendXdndLeave(source_current_window_); | 787 SendXdndLeave(source_current_window_); |
| 748 | 788 |
| 749 source_current_window_ = dest_window; | 789 source_current_window_ = dest_window; |
| 750 waiting_on_status_ = false; | 790 waiting_on_status_ = false; |
| 751 next_position_message_.reset(); | 791 next_position_message_.reset(); |
| 752 status_received_since_enter_ = false; | 792 status_received_since_enter_ = false; |
| 753 negotiated_operation_ = ui::DragDropTypes::DRAG_NONE; | 793 negotiated_operation_ = ui::DragDropTypes::DRAG_NONE; |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 981 xev.xclient.format = 32; | 1021 xev.xclient.format = 32; |
| 982 xev.xclient.window = dest_window; | 1022 xev.xclient.window = dest_window; |
| 983 xev.xclient.data.l[0] = xwindow_; | 1023 xev.xclient.data.l[0] = xwindow_; |
| 984 xev.xclient.data.l[1] = 0; | 1024 xev.xclient.data.l[1] = 0; |
| 985 xev.xclient.data.l[2] = CurrentTime; | 1025 xev.xclient.data.l[2] = CurrentTime; |
| 986 xev.xclient.data.l[3] = None; | 1026 xev.xclient.data.l[3] = None; |
| 987 xev.xclient.data.l[4] = None; | 1027 xev.xclient.data.l[4] = None; |
| 988 SendXClientEvent(dest_window, &xev); | 1028 SendXClientEvent(dest_window, &xev); |
| 989 } | 1029 } |
| 990 | 1030 |
| 991 void DesktopDragDropClientAuraX11::SendXClientEvent(::Window xid, | |
| 992 XEvent* xev) { | |
| 993 DCHECK_EQ(ClientMessage, xev->type); | |
| 994 | |
| 995 // Don't send messages to the X11 message queue if we can help it. | |
| 996 DesktopDragDropClientAuraX11* short_circuit = GetForWindow(xid); | |
| 997 if (short_circuit) { | |
| 998 Atom message_type = xev->xclient.message_type; | |
| 999 if (message_type == atom_cache_.GetAtom("XdndEnter")) { | |
| 1000 short_circuit->OnXdndEnter(xev->xclient); | |
| 1001 return; | |
| 1002 } else if (message_type == atom_cache_.GetAtom("XdndLeave")) { | |
| 1003 short_circuit->OnXdndLeave(xev->xclient); | |
| 1004 return; | |
| 1005 } else if (message_type == atom_cache_.GetAtom("XdndPosition")) { | |
| 1006 short_circuit->OnXdndPosition(xev->xclient); | |
| 1007 return; | |
| 1008 } else if (message_type == atom_cache_.GetAtom("XdndStatus")) { | |
| 1009 short_circuit->OnXdndStatus(xev->xclient); | |
| 1010 return; | |
| 1011 } else if (message_type == atom_cache_.GetAtom("XdndFinished")) { | |
| 1012 short_circuit->OnXdndFinished(xev->xclient); | |
| 1013 return; | |
| 1014 } else if (message_type == atom_cache_.GetAtom("XdndDrop")) { | |
| 1015 short_circuit->OnXdndDrop(xev->xclient); | |
| 1016 return; | |
| 1017 } | |
| 1018 } | |
| 1019 | |
| 1020 // I don't understand why the GTK+ code is doing what it's doing here. It | |
| 1021 // goes out of its way to send the XEvent so that it receives a callback on | |
| 1022 // success or failure, and when it fails, it then sends an internal | |
| 1023 // GdkEvent about the failed drag. (And sending this message doesn't appear | |
| 1024 // to go through normal xlib machinery, but instead passes through the low | |
| 1025 // level xProto (the x11 wire format) that I don't understand. | |
| 1026 // | |
| 1027 // I'm unsure if I have to jump through those hoops, or if XSendEvent is | |
| 1028 // sufficient. | |
| 1029 XSendEvent(xdisplay_, xid, False, 0, xev); | |
| 1030 } | |
| 1031 | |
| 1032 } // namespace views | 1031 } // namespace views |
| OLD | NEW |