/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ /* ProxyIcon.cpp -- a label that you can drag from. Created: Chris Toshok , 1-Dec-96. */ #include "ProxyIcon.h" #include #define NONMOTIF_DND #ifdef DEBUG_toshok #define D(x) x #else #define D(x) #endif #if defined(USE_MOTIF_DND) fe_dnd_Source _xfe_dragsource = { 0 }; #else extern fe_dnd_Source _xfe_dragsource; #endif /* USE_MOTIF_DND */ XFE_ProxyIcon::XFE_ProxyIcon(XFE_Component *toplevel_component, Widget parent, char *name, fe_icon *icon) : XFE_Component(toplevel_component) { Widget label; m_icon = icon; m_toplevel = toplevel_component; label = XmCreateLabel(parent, name, NULL, 0); setBaseWidget(label); XtInsertEventHandler(label, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, False, buttonEventHandler, this, XtListHead); m_activity = 0; m_lastmotionx = m_lastmotiony = 0; m_dragtype = FE_DND_NONE; setIcon(icon); } void XFE_ProxyIcon::setIcon(fe_icon *icon) { m_icon = icon; if (m_icon && m_icon->pixmap) { XtVaSetValues(m_widget, XmNlabelType, XmPIXMAP, XmNlabelPixmap, icon->pixmap, NULL); } } fe_icon * XFE_ProxyIcon::getIcon() { return m_icon; } void XFE_ProxyIcon::setDragType(fe_dnd_Type dragtype, XFE_Component *drag_source, fe_dnd_SourceDropFunc sourcedropfunc) { m_dragtype = dragtype; m_source = drag_source; m_sourcedropfunc = sourcedropfunc; } void XFE_ProxyIcon::makeDragWidget(int x, int y) { Visual *v = 0; Colormap cmap = 0; Cardinal depth = 0; Widget label; // fe_icon *icon; Widget shell; Pixmap dragPixmap; D(printf("hot (x,y) = (%d,%d)\n", x, y);) if (_xfe_dragsource.widget) return; shell = m_toplevel->getBaseWidget(); XtVaGetValues (shell, XtNvisual, &v, XtNcolormap, &cmap, XtNdepth, &depth, 0); _xfe_dragsource.type = m_dragtype; // XXX column drags happen when the row was a header. _xfe_dragsource.hotx = x; _xfe_dragsource.hoty = y; _xfe_dragsource.closure = m_dragtype == FE_DND_COLUMN ? (void*)this : (void*)m_source; _xfe_dragsource.func = m_sourcedropfunc; XP_ASSERT(m_icon != NULL); if (m_icon == NULL) return; dragPixmap = m_icon->pixmap; _xfe_dragsource.widget = XtVaCreateWidget("drag_win", overrideShellWidgetClass, m_widget, XmNwidth, m_icon->width, XmNheight, m_icon->height, XmNvisual, v, XmNcolormap, cmap, XmNdepth, depth, XmNborderWidth, 0, NULL); label = XtVaCreateManagedWidget ("label", xmLabelWidgetClass, _xfe_dragsource.widget, XmNlabelType, XmPIXMAP, XmNlabelPixmap, dragPixmap, NULL); } void XFE_ProxyIcon::destroyDragWidget() { if (!_xfe_dragsource.widget) return; XtDestroyWidget (_xfe_dragsource.widget); _xfe_dragsource.widget = NULL; } void XFE_ProxyIcon::buttonEvent(XEvent *event, Boolean *c) { int x = event->xbutton.x; int y = event->xbutton.y; m_ignoreevents = False; switch (event->type) { case ButtonPress: D(printf ("ButtonPress\n");) /* Always ignore btn3. Btn3 is for popups. - dp */ if (event->xbutton.button == 3) break; m_activity |= ButtonPressMask; m_ignoreevents = True; m_lastmotionx = x; m_lastmotiony = y; // Save this position off so we can draw the widget // with the appropriate hot spot. Ie, you should drag // the icon from the point where you clicked on it, not // some predetermined hot spot.. m_hotSpot_x = x; m_hotSpot_y = y; break; case ButtonRelease: if (m_activity & ButtonPressMask) { if (m_activity & PointerMotionMask) { /* handle the drop */ fe_dnd_DoDrag(&_xfe_dragsource, event, FE_DND_DROP); fe_dnd_DoDrag(&_xfe_dragsource, event, FE_DND_END); destroyDragWidget(); } } m_activity = 0; break; #ifdef NONMOTIF_DND case MotionNotify: if (m_dragtype == FE_DND_NONE) break; if (!(m_activity & PointerMotionMask) && (abs(x - m_lastmotionx) < 5 && abs(y - m_lastmotiony) < 5)) { /* We aren't yet dragging, and the mouse hasn't moved enough for this to be considered a drag. */ break; } if (m_activity & ButtonPressMask) { /* ok, the pointer moved while a button was held. * we're gonna drag some stuff. */ m_ignoreevents = True; if (!(m_activity & PointerMotionMask)) { // Create a drag source. // We want the mouse-down location, not the last one. makeDragWidget(m_hotSpot_x, m_hotSpot_y); fe_dnd_DoDrag(&_xfe_dragsource, event, FE_DND_START); m_activity |= PointerMotionMask; } fe_dnd_DoDrag(&_xfe_dragsource, event, FE_DND_DRAG); /* Now, force all the additional mouse motion events that are lingering around on the server to come to us, so that Xt can compress them away. Yes, XSync really does improve performance in this case, not hurt it. */ XSync(XtDisplay(m_widget), False); } m_lastmotionx = x; m_lastmotiony = y; break; #endif } if (m_ignoreevents) *c = False; } void XFE_ProxyIcon::buttonEventHandler(Widget, XtPointer clientData, XEvent *event, Boolean *cont) { XFE_ProxyIcon *obj = (XFE_ProxyIcon*)clientData; obj->buttonEvent(event, cont); }