Mercurial > hg > xemacs-beta
diff src/offix.c @ 197:acd284d43ca1 r20-3b25
Import from CVS: tag r20-3b25
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:00:02 +0200 |
parents | |
children | 78478c60bfcd |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/offix.c Mon Aug 13 10:00:02 2007 +0200 @@ -0,0 +1,436 @@ +/* +This is a modified DND 1.0 library which does not depend on Xt +event handling. +Modifications Copyright (c) 1997 Oliver Graf <ograf@fga.de> + +Original DND lib +Copyright (C) 1996 César Crusius + +This file is part of the DND Library. This library is free +software; you can redistribute it and/or modify it under the terms of +the GNU Library General Public License as published by the Free +Software Foundation; either version 2 of the License, or (at your +option) any later version. This library is distributed in the hope +that it will be useful, but WITHOUT ANY WARRANTY; without even the +implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the GNU Library General Public License for more details. +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* #define DEBUG */ + +#include "offix.h" +#include <X11/cursorfont.h> +#include <X11/Xatom.h> +#include <X11/Xmu/WinUtil.h> +#include <stdio.h> +#include <stdlib.h> +#include <values.h> + +/* Local variables */ +static Display *dpy; /* current display */ +static int DragPrecision; /* minimum dx,dy to start drag */ +static int Dragging; /* Drag state flag */ +static int DataOK; /* Non-zero if data registered */ +static Atom DndProtocol; /* ClientMessage identifier */ +static Atom DndSelection; /* For the data transfers */ +static Atom OldDndProtocol; /* Version 0 atom */ +static Atom OldDndSelection;/* Version 0 atom */ +static Atom WM_STATE; /* Needed for icon stuff */ +static Window Target; /* Drop window */ +static Widget MainWidget; /* Main widget of application */ +static int DataType; /* Current drag data type */ +static int RootFlag; /* Non-zero if dropped on root */ +static XColor Black,White; /* For the cursors */ + +/*========================================================================= + * Data for the standard Dnd cursors + *=========================================================================*/ +#include "offix-cursors.h" + +/*=============================================================== CursorData + * CursorData contains all the data for the cursors bitmaps + *==========================================================================*/ +typedef struct +{ + int Width,Height; + char *ImageData,*MaskData; + int HotSpotX,HotSpotY; + Pixmap ImagePixmap,MaskPixmap; + Cursor CursorID; +} CursorData; + +static CursorData DndCursor[DndEND]={ + { 0,0,NULL,NULL,0,0,0 }, + { grey_width, grey_height,grey_bits,grey_mask_bits, + grey_x_hot,grey_y_hot}, + { file_width,file_height,file_bits,file_mask_bits, + file_x_hot,file_y_hot}, + { files_width,files_height,files_bits,files_mask_bits, + files_x_hot,files_y_hot}, + { text_width,text_height,text_bits,text_mask_bits, + text_x_hot,text_y_hot }, + { dir_width,dir_height,dir_bits,dir_mask_bits, + dir_x_hot,dir_y_hot }, + { link_width,link_height,link_bits,link_mask_bits, + link_x_hot,link_y_hot}, + { app_width,app_height,app_bits,app_mask_bits, + app_x_hot,app_y_hot }, + { url_width,url_height,url_bits,url_mask_bits, + url_x_hot,url_y_hot }, + { mime_width,mime_height,mime_bits,mime_mask_bits, + mime_x_hot,mime_y_hot } +}; + +/* Local prototypes */ +int DndIsDragging(void); +void DndStartAction(Widget widget, + XtPointer data, + XEvent *event, + Boolean *p); +void DndPropertyHandler(Widget widget, + XtPointer data, + XEvent *event, + Boolean *p); + +/*======================================================== DndHandleDragging + * Takes care of the drag and drop process. Wait until the pointer had moved + * a little. Then takes control over the pointer until the buttons are + * released. After that send a Drag And Drop ClientMessage event. Returns + * non-zero if a drop did take place. + *===========================================================================*/ +int DndHandleDragging(Widget widget,XEvent *event) +{ + XEvent Event; + Window root = RootWindowOfScreen(XtScreenOfObject(widget)); + XtAppContext app= XtWidgetToApplicationContext(widget); + Window DispatchWindow; + int DropX,DropY; + + if(Dragging) return 0; + + XUngrabPointer(dpy,CurrentTime); + /* Take control over the pointer */ + XGrabPointer(dpy,root,False, + ButtonMotionMask|ButtonPressMask|ButtonReleaseMask, + GrabModeSync,GrabModeAsync,root, + DndCursor[DataType].CursorID, + CurrentTime); + + /* Wait for button release */ + Dragging=1; RootFlag=0; + while(Dragging) + { + XAllowEvents(dpy,SyncPointer,CurrentTime); + XtAppNextEvent(app,&Event); + switch(Event.type) + { + case ButtonRelease: + if(Event.xbutton.subwindow) + RootFlag=0; + else + RootFlag=1; + Dragging=0; + break; + default: + XtDispatchEvent(&Event); + break; + } + } + DataOK=0; + /* Now release the pointer */ + XUngrabPointer(dpy,CurrentTime); + /* Try to guess if the drop occurred in the root window */ + if(!RootFlag) + { + Target=XmuClientWindow(dpy,Event.xbutton.subwindow); + if (Target==Event.xbutton.subwindow) + DispatchWindow=Target; + else + DispatchWindow=PointerWindow; + } + else + Target=DispatchWindow=XtWindow(MainWidget); + + /* Now build the event structure */ + DropX=Event.xbutton.x_root; + DropY=Event.xbutton.y_root; + Event.xclient.type = ClientMessage; + Event.xclient.display = dpy; + Event.xclient.message_type = DndProtocol; + Event.xclient.format = 32; + Event.xclient.window = Target; + Event.xclient.data.l[0] = DataType; + Event.xclient.data.l[1] = (long)event->xbutton.state; + Event.xclient.data.l[2] = (long)XtWindow(widget); + Event.xclient.data.l[3] = DropX + 65536L*(long)DropY; + Event.xclient.data.l[4] = 1; + + /* Send the drop message */ + XSendEvent(dpy,DispatchWindow,True,NoEventMask,&Event); + /* Send an old style version of the message just in case */ + Event.xclient.message_type = OldDndProtocol; + XSendEvent(dpy,DispatchWindow,True,NoEventMask,&Event); + +#ifdef DEBUG + fprintf(stderr,"ClientMessage sent to 0x%x(0x%x).\n", + DispatchWindow,Target); + fprintf(stderr,"The drop coordinates are (%d,%d).\n",DropX,DropY); +#endif + + return 1; +} + +/*=============================================================== DndIsIcon + * Return non-zero if the application is iconic (widget=toplevel) + *========================================================================*/ +int +DndIsIcon(Widget widget) +{ + Atom JunkAtom; + int JunkInt; + unsigned long WinState,JunkLong; + unsigned char *Property; + + XGetWindowProperty(dpy,XtWindow(widget),WM_STATE, + 0L,2L,False,AnyPropertyType, + &JunkAtom,&JunkInt,&WinState,&JunkLong, + &Property); + WinState=(unsigned long)(*((long*)Property)); + return (WinState==3); +} + +/*============================================================ DndInitialize + * Must be called anywhere before the top level widget creation and the + * main loop. Initialize global variables and bind the DndDispatch function + * to the top level widget. Creates the cursors to be used in drag actions. + *=========================================================================*/ +void +DndInitialize(Widget shell) +{ + int screen,i; + Colormap colormap; + Window root; + + dpy = XtDisplayOfObject(shell); + screen = DefaultScreen(dpy); + colormap= DefaultColormap(dpy,screen); + root = DefaultRootWindow(dpy); + + + Black.pixel=BlackPixel(dpy,screen); + White.pixel=WhitePixel(dpy,screen); + XQueryColor(dpy,colormap,&Black); + XQueryColor(dpy,colormap,&White); + + for(i=1;i!=DndEND;i++) + { + DndCursor[i].ImagePixmap= + XCreateBitmapFromData(dpy,root, + DndCursor[i].ImageData, + DndCursor[i].Width, + DndCursor[i].Height); + DndCursor[i].MaskPixmap= + XCreateBitmapFromData(dpy,root, + DndCursor[i].MaskData, + DndCursor[i].Width, + DndCursor[i].Height); + DndCursor[i].CursorID= + XCreatePixmapCursor(dpy,DndCursor[i].ImagePixmap, + DndCursor[i].MaskPixmap, + &Black,&White, + DndCursor[i].HotSpotX, + DndCursor[i].HotSpotY); + } + + DndCursor[0].CursorID=XCreateFontCursor(dpy,XC_question_arrow); + + /* These two are for older versions */ + OldDndProtocol=XInternAtom(dpy,"DndProtocol",FALSE); + OldDndSelection=XInternAtom(dpy,"DndSelection",FALSE); + /* Now the correct stuff */ + DndProtocol=XInternAtom(dpy,"_DND_PROTOCOL",FALSE); + DndSelection=XInternAtom(dpy,"_DND_SELECTION",FALSE); + + WM_STATE=XInternAtom(dpy,"WM_STATE",True); + Dragging=0; + DragPrecision=10; + RootFlag=0; + MainWidget=shell; +} + +int DndIsDragging(void) { return Dragging; } + +/*================================================================= DndSetData + * Updates the selection data. + *===========================================================================*/ +void DndSetData(int Type,unsigned char *Data,unsigned long Size) +{ + Window root = DefaultRootWindow(dpy); + int AuxSize; + unsigned char *AuxData; + unsigned long BackSize=Size; + + if (DataOK) return; + + /* Set the data type -- allow any type */ + DataType = Type; + + /* Set the data */ + AuxData = Data; + AuxSize = ( Size <= MAXINT ? (int)Size : MAXINT ); + XChangeProperty(dpy,root,DndSelection,XA_STRING,8, + PropModeReplace,Data,AuxSize); + for(Size-=(unsigned long)AuxSize;Size;Size-=(unsigned long)AuxSize) + { + Data+=AuxSize; + AuxSize = ( (Size<=(MAXINT)) ? (int)Size : (MAXINT) ); + XChangeProperty(dpy,root,DndSelection,XA_STRING,8, + PropModeAppend,Data,AuxSize); + } + + /* Set the data for old DND version */ + Size = BackSize; + AuxData = Data; + AuxSize = ( Size <= MAXINT ? (int)Size : MAXINT ); + XChangeProperty(dpy,root,OldDndSelection,XA_STRING,8, + PropModeReplace,Data,AuxSize); + for(Size-=(unsigned long)AuxSize;Size;Size-=(unsigned long)AuxSize) + { + Data+=AuxSize; + AuxSize = ( (Size<=(MAXINT)) ? (int)Size : (MAXINT) ); + XChangeProperty(dpy,root,OldDndSelection,XA_STRING,8, + PropModeAppend,Data,AuxSize); + } + + /* Everything is now ok */ + DataOK=1; +} + +/*================================================================== DndGetData + * Return a pointer to the current data. Se HOWTO for more details. + *===========================================================================*/ +void DndGetData(XEvent *event, unsigned char **Data,unsigned long *Size) +{ + Window root = DefaultRootWindow(dpy); + + Atom ActualType,ActualDndSelection; + int ActualFormat; + unsigned long RemainingBytes; + + ActualDndSelection=(DndProtocolVersion(event) == 0L ? + OldDndSelection : + DndSelection ); + + XGetWindowProperty(dpy,root,ActualDndSelection, + 0L,1000000L, + FALSE,AnyPropertyType, + &ActualType,&ActualFormat, + Size,&RemainingBytes, + Data); +} + +/*================================== DndDataType DndDragButtons DndSourceWidget + * + * Return information about the Dnd event received. If a non-dnd event is + * passed, the function DndDataType returns DndNotDnd, and the others + * return zero. + *===========================================================================*/ +int DndDataType(XEvent *event) +{ + int Type; + + if(!DndIsDropMessage(event)) return DndNotDnd; + Type=(int)(event->xclient.data.l[0]); + if(Type>=DndEND) Type=DndUnknown; + return Type; +} + +unsigned int DndDragButtons(XEvent *event) +{ + if(!DndIsDropMessage(event)) return 0; + return (unsigned int)(event->xclient.data.l[1]); +} + +Window DndSourceWindow(XEvent *event) +{ + if(!DndIsDropMessage(event)) return 0; + if(DndProtocolVersion(event)<__DragAndDropH__) + /* We will try to do something about it, but nothing is certain */ + return XtWindow((Widget)(event->xclient.data.l[2])); + return (Window)(event->xclient.data.l[2]); +} + +void DndDropRootCoordinates(XEvent *event,int *x,int *y) +{ + if(!DndIsDropMessage(event)) + { + *x=0; *y=0; + return; + } + + /* If it is an old protocol version we try to get the coordinates + using the current pointer position. Of course, the pointer may have + moved since the drop, but there's nothing we can do about it. + */ + if(DndProtocolVersion(event)<1L) + { + Window root_return,child_return; + int win_x_return,win_y_return; + unsigned int mask_return; + + XQueryPointer(dpy,DefaultRootWindow(dpy), + &root_return,&child_return,x,y, + &win_x_return,&win_y_return,&mask_return); + return; + } + /* Thanks god you are using a decent protocol version */ + *x=(int)((long)(event->xclient.data.l[3]) & 0xffff); + *y=(int)((long)(event->xclient.data.l[3])/65536); +} + +void DndDropCoordinates(Widget widget,XEvent *event,int *x,int *y) +{ + int root_x,root_y; + Window child_return; + + DndDropRootCoordinates(event,&root_x,&root_y); + XTranslateCoordinates(dpy,DefaultRootWindow(dpy), + XtWindow(widget), + root_x,root_y, + x,y, + &child_return); +} + +long DndProtocolVersion(XEvent *event) +{ + if(!DndIsDropMessage(event)) return -1L; + return event->xclient.data.l[4]; +} + +int DndIsDropMessage(XEvent *event) +{ + if(event->xclient.type != ClientMessage) return 0; + if(event->xclient.message_type == OldDndProtocol && + event->xclient.data.l[4]==0) return 1; + if(event->xclient.message_type == DndProtocol) return 1; + return 0; +} + +void DndChangeCursor(int Type,int width,int height,char *image,char *mask, + int hot_x,int hot_y) +{ + DndCursor[Type].ImagePixmap= + XCreateBitmapFromData(dpy,DefaultRootWindow(dpy), + image,width,height); + DndCursor[Type].MaskPixmap= + XCreateBitmapFromData(dpy,DefaultRootWindow(dpy), + mask,width,height); + DndCursor[Type].CursorID= + XCreatePixmapCursor(dpy,DndCursor[Type].ImagePixmap, + DndCursor[Type].MaskPixmap, + &Black,&White, + hot_x,hot_y); +}