home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / dragdrop.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  7.2 KB  |  210 lines

  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  
  18.    dragdrop.c --- Very simplistic drag and drop support.
  19.    Created: Terry Weissman <terry@netscape.com>, 27-Jun-95.
  20.  */
  21.  
  22. #include "mozilla.h"
  23. #include "xfe.h"
  24. #include "dragdrop.h"
  25.  
  26. #include <Xfe/Xfe.h>            /* for xfe widgets and utilities */
  27.  
  28. typedef struct DropSite {
  29.   Widget widget;
  30.   fe_dnd_DropFunc func;
  31.   void* closure;
  32.   struct DropSite* next;
  33. } DropSite;
  34.  
  35. static DropSite* FirstDropSite = NULL;
  36.  
  37. static void
  38. fe_dnd_dropsite_destroyed(Widget widget, XtPointer closure,
  39.               XtPointer call_data)
  40. {
  41.   DropSite* site = (DropSite*) closure;
  42.   DropSite** tmp;
  43.   assert(widget == site->widget);
  44.   for (tmp = &FirstDropSite ; *tmp ; tmp = &((*tmp)->next)) {
  45.     if (*tmp == site) {
  46.       *tmp = site->next;
  47.       XP_FREE(site);
  48.       return;
  49.     }
  50.   }
  51.   abort();
  52. }
  53.  
  54. void
  55. fe_dnd_CreateDrop(Widget widget, fe_dnd_DropFunc func, void* closure)
  56. {
  57.   DropSite* tmp = XP_NEW_ZAP(DropSite);
  58.   tmp->widget = widget;
  59.   tmp->func = func;
  60.   tmp->closure = closure;
  61.   tmp->next = FirstDropSite;
  62.   FirstDropSite = tmp;
  63.  
  64.   XtAddCallback(widget, XmNdestroyCallback, fe_dnd_dropsite_destroyed, tmp);
  65. }
  66.  
  67.  
  68.  
  69. void
  70. fe_dnd_DoDrag(fe_dnd_Source* source, XEvent* event, fe_dnd_Event type)
  71. {
  72.   Display* dpy = XtDisplay(source->widget);
  73.   int x = event->xbutton.x_root - source->hotx;
  74.   int y = event->xbutton.y_root - source->hoty;
  75.   DropSite* site;
  76.   Window dropwindow = None;
  77.   XtRealizeWidget(source->widget);
  78.   XMoveWindow(dpy, XtWindow(source->widget), x, y);
  79.   if (type == FE_DND_START) {
  80.     XtPopup(source->widget, XtGrabNone);
  81.   }
  82.   for (site = FirstDropSite ; site ; site = site->next) {
  83.     XP_Bool callit = TRUE;
  84.     if (type == FE_DND_DROP) {
  85.       /* Only call drops if it is actually on this widget. */
  86.       Position rootx;
  87.       Position rooty;
  88.       XtTranslateCoords(site->widget, 0, 0, &rootx, &rooty);
  89.       if (event->xbutton.x_root < rootx || event->xbutton.y_root < rooty) {
  90.     callit = FALSE;
  91.       } else {
  92.     rootx += XfeWidth(site->widget);
  93.     rooty += XfeHeight(site->widget);
  94.     if (event->xbutton.x_root >= rootx || event->xbutton.y_root >= rooty) {
  95.       callit = FALSE;
  96.     } else {
  97.       /* Huh.  Well, it looks like we're over this widget, but we have more
  98.          tests to try.  First, make sure that this widget and all of its
  99.          ancesters are managed at the moment.  (For some reason, the
  100.          uppermost widget, the Shell widget, is generally not managed even
  101.          when visible, so we stop checking once we've hit a shell.)
  102.  
  103.          We might also want to check for mapped, as well as managed, but
  104.          that seems a bit awkward to do right now, and is not strictly
  105.          necessary.  Such checks would be nice to do during dragging as
  106.          well as dropping; it would help prevent us from drawing into
  107.          iconified windows. */
  108.       Widget widget;
  109.       Window toplevelwindow = 0;
  110.       for (widget = site->widget;
  111.            widget && !XtIsShell(widget);
  112.            widget = XtParent(widget)) {
  113.         if (!XtIsManaged(widget)) {
  114.           callit = FALSE;
  115.           break;
  116.         }
  117.       }
  118.       if (callit) {
  119.         /* OK, the final acid test: is the mouse really on the window in
  120.            question?  I am trusting that we don't have any layout where the
  121.            widget is obscured by some other widget within the same toplevel
  122.            window; I'm more worried about the case where there is another
  123.            toplevel window above this widget's toplevel window and below
  124.            the mouse.  (There maybe ought to be a grab on during some of
  125.            this.) */
  126.         if (dropwindow == None) {
  127.           /* Figure out what toplevel window we are pointing at.  Done
  128.          only once; this does require a round trip to the X server. */
  129.           Window rootreturn;
  130.           int rootx, rooty, winx, winy;
  131.           unsigned int mask;
  132.           XUnmapWindow(dpy, XtWindow(source->widget));
  133.           if (!XQueryPointer(dpy, event->xbutton.root, &rootreturn,
  134.                  &dropwindow, &rootx, &rooty, &winx, &winy,
  135.                  &mask)) {
  136.         /* This is not very likely -- the cursor has moved to another
  137.            screen since we got the drop event.  Whatever.*/
  138.         dropwindow = None;
  139.           }
  140.           if (dropwindow == None) {
  141.         /* Well, it appears that the drop didn't even happen on a
  142.            window at all; the mouse is pointing at the root window.
  143.            How bizarre, especially since the rectangle check showed
  144.            we were within a widget.  I guess it could happen if we
  145.            iconified a window, and then dropped where it was when
  146.            uniconified.
  147.  
  148.            At any rate, we shouldn't deliver a drop event to anywhere.
  149.            Break out of the loop where we've been looking for a
  150.            destination. */
  151.         break;
  152.           }
  153.         }
  154.         /* Find out what X window is the topmost container for this
  155.            site, so we can test if it's the same that XQueryWindow
  156.            returned.  Note that we can't easily cache this result; it
  157.            can change if the window manager decides to reparent the
  158.            shell to another window.  Which can happen, for example, if
  159.            we unmap this window and map it later.
  160.  
  161.            Anyway, finding this toplevel window can take several round
  162.            trips to the server.  First we find the uppermost window we can
  163.            from the widget hierarchy, and then we work up our way up
  164.            the X window tree. */
  165.         for (widget = site->widget; widget; widget = XtParent(widget)) {
  166.           Window w = XtWindow(widget);
  167.           if (w) toplevelwindow = w;
  168.           if (XtIsShell(widget)) {
  169.         /* Sometimes a shell has another shell as a parent (I guess
  170.            for trasient-for and stuff), so be sure we stop before
  171.            going to that other shell. */
  172.         break;
  173.           }
  174.         }
  175.         if (toplevelwindow) {
  176.           Window parent;
  177.           Window root;
  178.           Window* children;
  179.           unsigned int numchildren;
  180.           while (toplevelwindow != dropwindow) {
  181.         /* There oughta be a better call then XQueryTree... */
  182.         if (!XQueryTree(dpy, toplevelwindow, &root, &parent,
  183.                 &children, &numchildren)) {
  184.           /* The call failed.  I dunno how it can do that.  Uh, uh,
  185.              well, we'll just not drop in there, shall we.  ### */
  186.           XP_ASSERT(0);
  187.           break;
  188.         }
  189.         if (children) XFree(children);
  190.         if (parent == root) break;
  191.         toplevelwindow = parent;
  192.           }
  193.         }
  194.         if (dropwindow != toplevelwindow) {
  195.           callit = FALSE;
  196.         }
  197.       }
  198.     }
  199.       }
  200.     }
  201.     if (callit) {
  202.       (*site->func)(site->widget, site->closure, type, source, event);
  203.       if (type == FE_DND_DROP) {
  204.     /* Never drop on more than one dropsite. */
  205.     break;
  206.       }
  207.     }
  208.   }
  209. }
  210.