Closed Bug 121251 Opened 23 years ago Closed 22 years ago

gtk2 needs drag and drop

Categories

(Core :: DOM: Copy & Paste and Drag & Drop, defect)

x86
Linux
defect
Not set
normal

Tracking

()

RESOLVED FIXED

People

(Reporter: blizzard, Assigned: blizzard)

References

Details

Attachments

(2 files, 2 obsolete files)

The gtk2 port needs drag and drop done.  Need to figure out if we can share any
of the code with the gtk1.2 code - there's a lot there.
Blocks: gtk2
*** Bug 146374 has been marked as a duplicate of this bug. ***
Mozilla also does not drag and drop correctly to and from KDE3/QT3. Mozilla is an isolated application on the modern desktop. 
Hi, Chris
   I want to work on this bug and below is my investigation in DND. If there is
any error, please tell me. Your guidance will make this work better.

1. Difference of DND between gtk1.2 and gtk2.0:
        Gtk2 includes all the DND interfaces defined in gtk1.2( the declarations
of interface are identical). Additionally, gtk2 includes 8 new interfaces, all
of which provide new (but nonsignificant) functions. All new interfaces don't
intervene existing interfaces. So we can use all the code in
widget/src/gtk/nsDragService.cpp(h) without modificaiton. (Testing demonstrates
that adding "nsDragService.cpp/h" to widget/src/gtk2 has no compiling error) .

2. To Do
       Such work is not enough because DND doesn't like CCP(cut, copy&paste).
All CCP implementation locates in nsClipboard.cpp(h) which provide interfaces
just like providing service. CCP's implementation has no relation to individual
widget. But DND's operation concern every widget because any widget may be DND
source and DND destination. So widget must deal with DND signal such as
"drag_motion", "drag_leave", "drag_drop", "drag_data_received".
"widget/src/gtk/nsWidget.cpp(h) & nsWindow.cpp(h) has a lot of code dealing with
DND, but the counterpart at "widget/src/gtk2" has no such code. So next step is
writing DND code in widget implementation at "widget/src/gtk2".
The biggest difference will be how the target of the drag is determined.  In the
old code, there was a lot of X hackery that was used to determine exactly which
window was the target of the drag.  Because Mozilla in this case is a real Gtk
widget, we can use the standard signals and the window target of the drag to get
the real target.  So, basically, the code is greatly simplified.

As for the nsDragService code, I think that there's a lot of opportunity to
clean it up.  It probably doesn't need to be as complicated as it was because
the gtk interfaces are so much cleaner.
Hi, Chris
	Now, Jeff and I are doing DND work. I am going to implement the DND function for
mozilla widget. These days I am looking into "DND" part of gtk1.2 widget
implementation and "EVENT HANDLE" part of gtk2 widget implementation. I want to
follow the way below. Please point out if there is any mistaken, thanks a lot.
----------------------------------------------------------------------
   In "widget/src/gtk", nsWindow handle 4 DND signal "drag_motion",
"drag_leave", "drag_drop", "drag_data_received". These signals are bound to
"mShell", which means these signals are captured by nsWindow where events don't
really happen. After nsWindow who has "mShell" got the event, it look for the
innermost nsWindow for the event (that is nsWindow where event really happen),
generate nsMouseEvent(type="NS_DRAGDROP_EVENT") and forward it to the innermost
nsWindow. When looking for innermost nsWindow, it use a lot of Xlib functions.
	In "widget/src/gtk2", signal is bound to "mContainer". After nsWindow who as
"mContainer" got the event, it get the gdkwindow where event happens from
"event->window", then through "g_object_get_data(G_OBJECT(window), "nsWindow")"
found the "innermost" nsWindow. It's much simpler than "widget/src/gtk" because
its better structure of nsWindow.	

TODO

	So, all the things to do is to find proper nsWindow to handle the event, where
"widget/src/gtk" and "widget/src/gtk2" going different way. For DND, I need to
bind 4 DND signal "drag_motion", "drag_leave", "drag_drop", "drag_data_received"
to "mContainer" just like "button_press_event" or "button_release_event". Then
in handler, find the proper nsWindow to handle DND signal. 
That sounds pretty reasonable.  You need to attach the right signals to the
container, which it sounds like you understand, and then translate the signals
to the right inner nsWindow.  I haven't looked at it personally, but it appears
that the x/y coordinates of the drag event are still always relative to the
container, not a possible inner window.  This means that we still need to do
some translation from the outer window location to the inner window x/y to
deliver the Mozilla event.

Please don't use the Xlib code that's in the current gtk 1.2 code.  It should be
relatively easy to walk the children and siblings to get the correct coordinates.

But all in all, that looks OK.  Here's a tip.  I think that you might be able to
hook up to the drag_end signal on the source side to catch the end of the drag.
 You might be able to part of the inner loop bits that way.
CURRENT PROBLEM:

  Chris, I can't find the right inner nsWindow when Drag and Drop. 
  When other events happen such as "button_press", I can get gdk window throgh
CALLBACK function, then get the corresponding nsWindow. But all the CALLBACK
functions of DND don't provide GdkEvent, so I can't get gdk window.

  DND CALLBACK function returns "GdkDragContext", which contains source window
and destination window(gdkwindow) of the current drag. Because when setting
possible drag dest, only the mContainer is set(mContainer is a GtkWidget,
mDrawingarea is not). So we always get mContainer's gdkwindow through
GdkDragContext's dest window.

  That is to say, I can't get the right inner nsWindow through the information
DND CALLBACK functions provide.

SUBSTITUE SOLUTION:

  I use Xlib to get the right inner nsWindow as gtk1.2 does instead, [GTK2] DND
works well. Now the only thing left is to find how to get the right inner
nsWindow without using Xlib. 
  
  Chris, do you have any good idea? Thanks.
  

  

  

   

>   That is to say, I can't get the right inner nsWindow through the information
> DND CALLBACK functions provide.

That's exactly what I was saying.  Instead of using the Xlib functions provided,
you can walk the list of children of the window (this is available in the
nsIWidget interface) and find the inner target.
This is a testing patch of gtk2 DND. It use xlib to locate the right inner
nsWindow because the children list of nsWindow is not complete, and the right
inner nsWindow can't be found through "GetChildren" of nsIWidget.

The detail description of the current problem is in the next attachment.
Why don't you use the children at the gdk level?  gdk_window_peek_children() and
friends.  That doesn't require X roundtrips and it should contain all the
information you need.
Locating the right inner nsWindow means walking the tree of window(gdkwindow or
xwindow) looking for which child window who matches the coords.  But several
windows may match the corrds at the same time. So, the top one (up in z-order)
should be chosen. This siutation happens when browser has several tabs. All
tab's windows lap over and only one is at the top. 

This means when locating the right inner window, the same input of
"GetInnerMostWindow" (the outer window and the coords) may have different
output(the right inner window) due to the different current top window.

The tree of gdkwindow was created when generating gdk window and won't change
afterward. Only the tree of xwindow can response the change. So gdkwindow tree
can't be used to locating the rigth inner window. My testing demonstrate this.
Using xlib is a feasible(maybe only) way.

Another Question(about Xlib):

The children "XQueryTree" return are listed in current stacking order, from
bottommost (first) to topmost (last). But the code of gtk ("GetInnerMostWindow")
search from bottommost to topmost(first to last), when the top one should be
searched first. I am confused why this works well.

The same function won't work in "gtk2" (that's what I expected :-)), changing to
"search from topmost to bottommost" fix the problem. But then, the DND of
composer can't find the target window when dragging. Further investigation found
that the user selected tab's window of composer is not at the top of xwindow
tree. "GetInnerMostWindow" didn't return the right inner window. Now, I am
really confused by all these question:

1. why gtk DND of brower & composer works normally when "GetInnerMostWindow"
search from bottommost to topmost in the xwindow tree.
2. why gtk2 DND of composer won't work while DND of browser works well.

The patch use the original "GetInnerMostWindow" of gtk, which make the DND of
browser don't work well when several tabs exist. But the content can be dragged
into composer.

I can't figure out the reason because it seems not to do with DND.
I think I can answer part of the problem of COMMENT#12 now. Finding which is the
right inner window should use z-order and judge whether it's visible. Adding
"visible" judgement in "GetInnerMostWindow" has fixed the problem.

I don't know if it's sufficient only to judge "visible".If answer is "YES",
walking the gdk window tree is perfect to locating the right inner window.

My Demo walking gdkwindow tree without z-order info seems to say it's "YES", but
I don't know if it fits all case. 
I was going to suggest that you check the visibility on the gdk window, to tell
which windows were hidden.
This patch locates the right inner window walking through gdkwindow tree and
judge the "visibility" instead of using xlib function.
This patch make coding style better than the old one.
And make changes:
1. Add "check the number of iteration" in nsDragService::GetTargetDragData
2. Move "record the last gdk event time"(so don't touch nsCommonWidget.h/cpp)
Attachment #89913 - Attachment is obsolete: true
Attachment #90483 - Attachment is obsolete: true
I made a couple of minor changes and checked this in.  I removed the #ifdefs
around the LOG() statements since we want those built for debugging.  I also
made a couple of minor string changes because a couple of interfaces changed
since the patch was made.

Yay, marking FIXED!
Status: NEW → RESOLVED
Closed: 22 years ago
Resolution: --- → FIXED
it looks like nsDragService.h and nsDragService.cpp were not cvs added.
Status: RESOLVED → REOPENED
Resolution: FIXED → ---
Woops (*blush*).
Status: REOPENED → RESOLVED
Closed: 22 years ago22 years ago
Resolution: --- → FIXED
Thank Chris for reveiwing and checking in the patch! also for all the nights you
spend to chat with us! Wish to see you on IRC again :-)
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: