⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dnd.c

📁 具有IDE功能的编辑器
💻 C
字号:
/* dnd.c - drag and drop support   Copyright (C) 1996-2000 Paul Sheer   This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 2 of the License, or   (at your option) any later version.   This program 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 General Public License for more details.   You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA   02111-1307, USA. *//*    The cursor bitmaps and the cursor initialisation routines are from   the DND package which can be found with the OffiX package at   sunsite.unc.edu. These are Copyright (C) 1996 C閟ar Crusius.   I also took a look at his code to get a better idea how get my Dnd   working the same, and small parts of the code are modifications   from there. */#include <config.h>#ifdef HAVE_DND#include <my_string.h>#include <stdlib.h>#include <stdio.h>#include "pool.h"#include <sys/types.h>#include <sys/stat.h>#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include <X11/Xlib.h>#include <X11/Xutil.h>#include <X11/Xresource.h>#include <X11/Xatom.h>#include <X11/cursorfont.h>#include "cursor/file.xbm"#include "cursor/file_mask.xbm"#include "cursor/files.xbm"#include "cursor/files_mask.xbm"#include "cursor/dir.xbm"#include "cursor/dir_mask.xbm"#include "cursor/text.xbm"#include "cursor/text_mask.xbm"#include "cursor/grey.xbm"#include "cursor/grey_mask.xbm"#include "cursor/link.xbm"#include "cursor/link_mask.xbm"#include "cursor/app.xbm"#include "cursor/app_mask.xbm"#include "cursor/url.xbm"#include "cursor/url_mask.xbm"#include "cursor/mime.xbm"#include "cursor/mime_mask.xbm"#include "app_glob.c"#include "coolwidget.h"#include "mad.h"/* #define DND_DEBUG *//* what dnd version for sending drops *//* (recieving drops we support both versions simultaneously) */int option_dnd_version = 1;Atom DndProtocol, DndSelection, DndAcknowledge;Atom OldDndProtocol, OldDndSelection;typedef struct {    int Width, Height;    unsigned char *ImageData, *MaskData;    int HotSpotX, HotSpotY;    Pixmap ImagePixmap, MaskPixmap;    Cursor CursorID;} CursorData;static CursorData DndCursor[] ={    {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}};static int num_cursors = sizeof (DndCursor) / sizeof (CursorData);static char dnd_directory[MAX_PATH_LEN] = "";/* return the prepending directory (see CDndFileList() below) */char *CDndDirectory (void){    return dnd_directory;}char *striptrailing (char *s, int c){    int i;    i = strlen (s) - 1;    while (i >= 0) {	if (s[i] == c) {	    s[i--] = 0;	    continue;	}	break;    }    return s;}/*   Sets the directory, must be a null terminated complete path.   Strips trailing slashes. */void CSetDndDirectory (char *d){    if (!d)	return;    strcpy (dnd_directory, d);    striptrailing (dnd_directory, '/');    if (*dnd_directory)	return;    *dnd_directory = '/';}/*   Takes a newline separate list of files,   returns a null separate list of complete path names   by prepending dnd_directory to each file name.   returns 0 if no files in list.   result must always be free'd.   returns l as the total length of data.   returns num_files as the number of files in the list.   Alters t */char *CDndFileList (char *t, int *l, int *num_files){    char *p, *q, *r, *result;    int i;    int path_len, len;/* strip leading newlines */    while (*t == '\n')	t++;/* strip trailing newlines */    striptrailing (t, '\n');    if (!*t)	return 0;/* count files */    for (i = 1, p = t; *p; p++)	if (*p == '\n')	    i++;    *num_files = i;    len = (unsigned long) p - (unsigned long) t;    path_len = strlen (dnd_directory);    result = CMalloc ((path_len + 2) * i + len + 2);    r = result;    p = t;    for (;;) {	q = strchr (p, '\n');	if (!q)	    q = t + len;	*q = 0;	strcpy (r, dnd_directory);	r += path_len;	*r++ = '/';	strcpy (r, p);	r += (unsigned long) q - (unsigned long) p;	*r++ = 0;	if ((unsigned long) q == (unsigned long) t + len)	    break;	p = ++q;    }    *r = 0;    *l = (unsigned long) r - (unsigned long) result;    return result;}/* Dnd initialisation */void initialise_drag_n_drop (void){    int screen, i;    Colormap colormap;    Window root;    XColor Black, White;    DndAcknowledge = XInternAtom (CDisplay, "_DND_ACKNOWLEDGE", False);    DndProtocol = XInternAtom (CDisplay, "_DND_PROTOCOL", False);    DndSelection = XInternAtom (CDisplay, "_DND_SELECTION", False);    OldDndProtocol = XInternAtom (CDisplay, "DndProtocol", False);    OldDndSelection = XInternAtom (CDisplay, "DndSelection", False);    screen = DefaultScreen (CDisplay);    colormap = DefaultColormap (CDisplay, screen);    root = CRoot;    Black.pixel = BlackPixel (CDisplay, screen);    White.pixel = WhitePixel (CDisplay, screen);    XQueryColor (CDisplay, colormap, &Black);    XQueryColor (CDisplay, colormap, &White);    for (i = 1; i < num_cursors; i++) {	DndCursor[i].ImagePixmap =	    XCreateBitmapFromData (CDisplay, root,				   (char *) DndCursor[i].ImageData,				   DndCursor[i].Width,				   DndCursor[i].Height);	DndCursor[i].MaskPixmap =	    XCreateBitmapFromData (CDisplay, root,				   (char *) DndCursor[i].MaskData,				   DndCursor[i].Width,				   DndCursor[i].Height);	DndCursor[i].CursorID =	    XCreatePixmapCursor (CDisplay, DndCursor[i].ImagePixmap,				 DndCursor[i].MaskPixmap,				 &Black, &White,				 DndCursor[i].HotSpotX,				 DndCursor[i].HotSpotY);    }    DndCursor[0].CursorID = XCreateFontCursor (CDisplay, XC_question_arrow);}static void change_file_to_directory (int *data_type, char *data){    struct stat stats;    if (*data_type != DndFile)	return;    if (lstat (data, &stats))	return;    if (S_ISDIR (stats.st_mode))	*data_type = DndDir;}/*   This does a drag.   This is copied somewhat from the dnd Xt code by C閟ar Crusius    so it should behave almost exactly the way his does.   From is the sending window. data_type is a dnd type in coolwidget.h,   data is the actual data, and length is its length.   pointer state is the state of the pointer.   I set the pointer state to that *during* the drag, not before.   See eh_editor in editwidget.c for details.   The routines doesn't do anything until the mouse has moved more than   five pixels. If the user releases the button before dragging,   the button release event is sent back to the calling window. */void CDrag (Window from, int data_type, unsigned char *data, int length, unsigned long pointer_state){    XEvent e;    long x, y;    float x_mouse, y_mouse;    Window root;    Window target, dispatch;    change_file_to_directory (&data_type, (char *) data);#ifdef DND_DEBUG/* NLS ? */    printf ("Drag start\n");#endif/* first wait until the mouse moves more than ten pixels */    do {	XNextEvent (CDisplay, &e);	if (e.type == ButtonRelease) {	    XSendEvent (CDisplay, e.xany.window, 0, ButtonReleaseMask, &e);	    return;	}    } while (e.type != MotionNotify);    x_mouse = (float) e.xmotion.x_root;    y_mouse = (float) e.xmotion.y_root;    for (;;) {	XNextEvent (CDisplay, &e);	if (e.type == MotionNotify)	    if (my_sqrt ((x_mouse - e.xmotion.x_root) * (x_mouse - e.xmotion.x_root) +			 (y_mouse - e.xmotion.y_root) * (y_mouse - e.xmotion.y_root)) > 5.0)		break;	if (e.type == ButtonRelease) {	    XSendEvent (CDisplay, e.xany.window, 0, ButtonReleaseMask, &e);	    return;	}    }/* the mouse has been dragged a little, so this is a drag proper */    root = CRoot;    XChangeProperty (CDisplay, root, option_dnd_version ? DndSelection : OldDndSelection, XA_STRING, 8,		     PropModeReplace, data, length);    XGrabPointer (CDisplay, root, False,		  ButtonMotionMask | ButtonPressMask | ButtonReleaseMask,		  GrabModeSync, GrabModeAsync, root,		  DndCursor[data_type].CursorID, CurrentTime);    do {	XAllowEvents (CDisplay, SyncPointer, CurrentTime);	XNextEvent (CDisplay, &e);    } while (e.type != ButtonRelease);    XUngrabPointer (CDisplay, CurrentTime);    if (!e.xbutton.subwindow) {#ifdef DND_DEBUG/* NLS ? */	printf ("Pointer on root window, Drag end\n");#endif	return;    }    target = my_XmuClientWindow (CDisplay, e.xbutton.subwindow);    if (target == e.xbutton.subwindow)	dispatch = target;    else	dispatch = PointerWindow;    x = e.xbutton.x_root;    y = e.xbutton.y_root;    e.xclient.type = ClientMessage;    e.xclient.display = CDisplay;    e.xclient.message_type = option_dnd_version ? DndProtocol : OldDndProtocol;    e.xclient.format = 32;    e.xclient.window = target;    e.xclient.data.l[0] = data_type;    e.xclient.data.l[1] = pointer_state;    e.xclient.data.l[2] = from;    e.xclient.data.l[3] = x + y * 65536L;    e.xclient.data.l[4] = option_dnd_version;    /* Send the drop message */    XSendEvent (CDisplay, dispatch, True, NoEventMask, &e);#ifdef DND_DEBUG/* NLS ? */    printf ("Drop send to window %ld from %ld, Drag end\n", target, from);#endif}void this_pool_insert (void *p, int c){    unsigned char ch;    ch = c;    pool_write ((POOL *) p, &ch, 1);}void paste_prop (void *data, void (*insert) (void *, int), Window win, unsigned prop, int delete);/*   Returns data_type on success, DndNotDnd if not a Dnd drop.   Unneeded values can be passed as null. */int CGetDrop (XEvent * xe, unsigned char **data, unsigned long *size, int *x, int *y){    POOL *p;    if (xe->type != ClientMessage) {#ifdef DND_DEBUG/* NLS ? */	printf ("None ClientMessage event to window %ld\n", xe->xany.window);#endif	return DndNotDnd;    }#ifdef DND_DEBUG/* NLS ? */    printf ("ClientMessage event to window %ld\n", xe->xany.window);#endif    if ((xe->xclient.message_type == DndProtocol && xe->xclient.data.l[4] == 1)	||	(xe->xclient.message_type == OldDndProtocol && xe->xclient.data.l[4] == 0)) {	/* continue */    } else {	return DndNotDnd;    }#ifdef DND_DEBUG/* NLS ? */    printf ("Drop recieved at window %ld from window %ld\n", xe->xclient.window, xe->xclient.data.l[2]);#endif    p = pool_init ();    paste_prop (p, this_pool_insert, CRoot, xe->xclient.data.l[4] ? DndSelection : OldDndSelection, False);    if (size)	*size = pool_length (p);    *data = pool_break (p);    if (x)	*x = xe->xclient.data.l[3] & 0xFFFF;    if (y)	*y = xe->xclient.data.l[3] >> 16;    return xe->xclient.data.l[0];}/*    Sends an acknowledge event that the drop was recieved. This is my   extension to the protocol, but cooledit doesn't depend on   an acknowledge event being recieved, so everything will   work as usual when communicating with apps that don't    support this. xe is the drop event that you recived and   is not be modified. */void CDropAcknowledge (XEvent * xe){    XEvent e;    e.xclient.type = ClientMessage;    e.xclient.display = CDisplay;    e.xclient.message_type = DndAcknowledge;    e.xclient.format = 32;    e.xclient.window = xe->xclient.data.l[2];	/* to window that send the drop */    e.xclient.data.l[0] = xe->xclient.data.l[0];	/* data type */    e.xclient.data.l[1] = xe->xclient.data.l[1];	/* pointer state of the pointer when the drop was send */    e.xclient.data.l[2] = xe->xclient.window;	/* from this window */    e.xclient.data.l[3] = 0;	/* not used */    e.xclient.data.l[4] = 1;	/* same dnd version, since this extension can be 				   ignored, there is no need to have a new version */    XSendEvent (CDisplay, e.xclient.window, True, NoEventMask, &e);#ifdef DND_DEBUG/* NLS ? */    printf ("acknowledge send to window %ld from %ld, return\n", xe->xclient.data.l[2], xe->xclient.window);#endif}/*   Checks if xe is an acknowledge event.   Returns data_type if so and the state that the pointer was in   when the drag was initiated.   Returns DndNotDnd if not an acknowledge event. */int CIsDropAcknowledge (XEvent * xe, unsigned int *state){    if (xe->type != ClientMessage)	return DndNotDnd;    if (xe->xclient.message_type != DndAcknowledge || xe->xclient.data.l[4] != 1)	return DndNotDnd;    if (state)	*state = xe->xclient.data.l[1];    return xe->xclient.data.l[0];}#endif				/* HAVE_DND */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -