home *** CD-ROM | disk | FTP | other *** search
- /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * The contents of this file are subject to the Netscape Public License
- * Version 1.0 (the "NPL"); you may not use this file except in
- * compliance with the NPL. You may obtain a copy of the NPL at
- * http://www.mozilla.org/NPL/
- *
- * Software distributed under the NPL is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
- * for the specific language governing rights and limitations under the
- * NPL.
- *
- * The Initial Developer of this code under the NPL is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation. All Rights
- * Reserved.
-
- dragdrop.c --- Very simplistic drag and drop support.
- Created: Terry Weissman <terry@netscape.com>, 27-Jun-95.
- */
-
- #include "mozilla.h"
- #include "xfe.h"
- #include "dragdrop.h"
-
- #include <Xfe/Xfe.h> /* for xfe widgets and utilities */
-
- typedef struct DropSite {
- Widget widget;
- fe_dnd_DropFunc func;
- void* closure;
- struct DropSite* next;
- } DropSite;
-
- static DropSite* FirstDropSite = NULL;
-
- static void
- fe_dnd_dropsite_destroyed(Widget widget, XtPointer closure,
- XtPointer call_data)
- {
- DropSite* site = (DropSite*) closure;
- DropSite** tmp;
- assert(widget == site->widget);
- for (tmp = &FirstDropSite ; *tmp ; tmp = &((*tmp)->next)) {
- if (*tmp == site) {
- *tmp = site->next;
- XP_FREE(site);
- return;
- }
- }
- abort();
- }
-
- void
- fe_dnd_CreateDrop(Widget widget, fe_dnd_DropFunc func, void* closure)
- {
- DropSite* tmp = XP_NEW_ZAP(DropSite);
- tmp->widget = widget;
- tmp->func = func;
- tmp->closure = closure;
- tmp->next = FirstDropSite;
- FirstDropSite = tmp;
-
- XtAddCallback(widget, XmNdestroyCallback, fe_dnd_dropsite_destroyed, tmp);
- }
-
-
-
- void
- fe_dnd_DoDrag(fe_dnd_Source* source, XEvent* event, fe_dnd_Event type)
- {
- Display* dpy = XtDisplay(source->widget);
- int x = event->xbutton.x_root - source->hotx;
- int y = event->xbutton.y_root - source->hoty;
- DropSite* site;
- Window dropwindow = None;
- XtRealizeWidget(source->widget);
- XMoveWindow(dpy, XtWindow(source->widget), x, y);
- if (type == FE_DND_START) {
- XtPopup(source->widget, XtGrabNone);
- }
- for (site = FirstDropSite ; site ; site = site->next) {
- XP_Bool callit = TRUE;
- if (type == FE_DND_DROP) {
- /* Only call drops if it is actually on this widget. */
- Position rootx;
- Position rooty;
- XtTranslateCoords(site->widget, 0, 0, &rootx, &rooty);
- if (event->xbutton.x_root < rootx || event->xbutton.y_root < rooty) {
- callit = FALSE;
- } else {
- rootx += XfeWidth(site->widget);
- rooty += XfeHeight(site->widget);
- if (event->xbutton.x_root >= rootx || event->xbutton.y_root >= rooty) {
- callit = FALSE;
- } else {
- /* Huh. Well, it looks like we're over this widget, but we have more
- tests to try. First, make sure that this widget and all of its
- ancesters are managed at the moment. (For some reason, the
- uppermost widget, the Shell widget, is generally not managed even
- when visible, so we stop checking once we've hit a shell.)
-
- We might also want to check for mapped, as well as managed, but
- that seems a bit awkward to do right now, and is not strictly
- necessary. Such checks would be nice to do during dragging as
- well as dropping; it would help prevent us from drawing into
- iconified windows. */
- Widget widget;
- Window toplevelwindow = 0;
- for (widget = site->widget;
- widget && !XtIsShell(widget);
- widget = XtParent(widget)) {
- if (!XtIsManaged(widget)) {
- callit = FALSE;
- break;
- }
- }
- if (callit) {
- /* OK, the final acid test: is the mouse really on the window in
- question? I am trusting that we don't have any layout where the
- widget is obscured by some other widget within the same toplevel
- window; I'm more worried about the case where there is another
- toplevel window above this widget's toplevel window and below
- the mouse. (There maybe ought to be a grab on during some of
- this.) */
- if (dropwindow == None) {
- /* Figure out what toplevel window we are pointing at. Done
- only once; this does require a round trip to the X server. */
- Window rootreturn;
- int rootx, rooty, winx, winy;
- unsigned int mask;
- XUnmapWindow(dpy, XtWindow(source->widget));
- if (!XQueryPointer(dpy, event->xbutton.root, &rootreturn,
- &dropwindow, &rootx, &rooty, &winx, &winy,
- &mask)) {
- /* This is not very likely -- the cursor has moved to another
- screen since we got the drop event. Whatever.*/
- dropwindow = None;
- }
- if (dropwindow == None) {
- /* Well, it appears that the drop didn't even happen on a
- window at all; the mouse is pointing at the root window.
- How bizarre, especially since the rectangle check showed
- we were within a widget. I guess it could happen if we
- iconified a window, and then dropped where it was when
- uniconified.
-
- At any rate, we shouldn't deliver a drop event to anywhere.
- Break out of the loop where we've been looking for a
- destination. */
- break;
- }
- }
- /* Find out what X window is the topmost container for this
- site, so we can test if it's the same that XQueryWindow
- returned. Note that we can't easily cache this result; it
- can change if the window manager decides to reparent the
- shell to another window. Which can happen, for example, if
- we unmap this window and map it later.
-
- Anyway, finding this toplevel window can take several round
- trips to the server. First we find the uppermost window we can
- from the widget hierarchy, and then we work up our way up
- the X window tree. */
- for (widget = site->widget; widget; widget = XtParent(widget)) {
- Window w = XtWindow(widget);
- if (w) toplevelwindow = w;
- if (XtIsShell(widget)) {
- /* Sometimes a shell has another shell as a parent (I guess
- for trasient-for and stuff), so be sure we stop before
- going to that other shell. */
- break;
- }
- }
- if (toplevelwindow) {
- Window parent;
- Window root;
- Window* children;
- unsigned int numchildren;
- while (toplevelwindow != dropwindow) {
- /* There oughta be a better call then XQueryTree... */
- if (!XQueryTree(dpy, toplevelwindow, &root, &parent,
- &children, &numchildren)) {
- /* The call failed. I dunno how it can do that. Uh, uh,
- well, we'll just not drop in there, shall we. ### */
- XP_ASSERT(0);
- break;
- }
- if (children) XFree(children);
- if (parent == root) break;
- toplevelwindow = parent;
- }
- }
- if (dropwindow != toplevelwindow) {
- callit = FALSE;
- }
- }
- }
- }
- }
- if (callit) {
- (*site->func)(site->widget, site->closure, type, source, event);
- if (type == FE_DND_DROP) {
- /* Never drop on more than one dropsite. */
- break;
- }
- }
- }
- }
-