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 |