mousemark.c

来自「具有IDE功能的编辑器」· C语言 代码 · 共 532 行

C
532
字号
/* mousemark.c - mouse stuff marking dragging   Copyright (C) 1996-2000 the Free Software Foundation   Authors: 1996, 1997 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.*/#include <config.h>#ifndef GTK#include "coolwidget.h"#endifint just_dropped_something = 0;#include "edit.h"#include <X11/Xmd.h>#include <X11/Xatom.h>#ifndef GTK#include "app_glob.c"#include "coollocal.h"#endif#include "editcmddef.h"#include "xdnd.h"#ifdef GTK#include "src/mad.h"#else#include "mad.h"#endif#ifndef HAVE_DNDAtom **xdnd_typelist_send = 0;Atom **xdnd_typelist_receive = 0;#define NUM_SIMPLE_TYPES 10/* each entry is listed in order of what we would like the RECEIVE */static char *mime_type_send[NUM_SIMPLE_TYPES][10] ={    {0},			/* DndUnknown 0 */    {0},			/* DndRawData 1 */    {"url/url", "text/plain", 0},	/* DndFile    2 (input widget) */    {"text/plain", "text/uri-list", 0},	/* DndFiles   3 (fielded text box) */    {"text/plain", "application/octet-stream", 0},	/* DndText    4 (editor widget) *//* don't use these: */    {0},			/* DndLink    5 */    {0},			/* DndDir     6 */    {0},			/* DndExe     7 */    {0},			/* DndURL     8 */    {0},			/* DndMIME    9 */};static char *mime_type_recieve[NUM_SIMPLE_TYPES][10] ={    {0},	/* DndUnknown 0 */    {0},	/* DndRawData 1 */    {"url/url", "text/uri-list", "text/plain", 0},	/* DndFile    2 (input widget) */    {0},	/* DndFiles   3 */    {"url/url", "text/plain", "application/octet-stream", "text/uri-list", 0},	/* DndText    4 (editor widget) *//* don't use these: */    {0},			/* DndLink    5 */    {0},			/* DndDir     6 */    {0},			/* DndExe     7 */    {0},			/* DndURL     8 */    {0},			/* DndMIME    9 */};#ifndef GTKstatic char dnd_directory[MAX_PATH_LEN] = "/";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;}/* return the prepending directory (see CDndFileList() below) */char *CDndDirectory (void){    return dnd_directory;}/*   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 newline separate list of complete `file:' 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, len, done = 0;/* 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;    result = CMalloc ((strlen (dnd_directory) + strlen ("file:") + 2) * i + len + 2);    r = result;    p = t;    while (!done) {	q = strchr (p, '\n');	if (q)	    *q = 0;	else	    done = 1;	strcpy (r, "file:");	if (*p != '/') {	    strcat (r, dnd_directory);	    strcat (r, "/");	}	strcat (r, p);	r += strlen (r);	*r++ = '\n';	p = ++q;    }    *r = 0;    *l = (unsigned long) r - (unsigned long) result;    return result;}Window get_focus_border_widget (void);static void widget_apply_leave (DndClass * dnd, Window widgets_window){    CWidget *w;    w = CWidgetOfWindow (widgets_window);    if (get_focus_border_widget () == widgets_window)	destroy_focus_border ();    if (w)	CExpose (w->ident);}static int widget_insert_drop (DndClass * dnd, unsigned char *data, int length, int remaining, Window into, Window from, Atom type){    CWidget *w;    char *p;    w = CWidgetOfWindow (into);    if (!w)	return 1;    if (w->funcs->insert_drop) {	int r;	Window child_return;	int xd, yd;	if (!dnd->user_hook1)	    dnd->user_hook2 = dnd->user_hook1 = CMalloc (length + remaining + 1);	memcpy (dnd->user_hook2, data, length);	p = dnd->user_hook2;	p += length;	/* avoids ansi warning */	dnd->user_hook2 = p;	if (remaining)	    return 0;	XTranslateCoordinates (CDisplay, CRoot, into, dnd->x, dnd->y, &xd, &yd, &child_return);	r = (*w->funcs->insert_drop) (w->funcs->data, from, dnd->user_hook1, (unsigned long) dnd->user_hook2 - (unsigned long) dnd->user_hook1, xd, yd, type, dnd->supported_action);	free (dnd->user_hook1);	dnd->user_hook1 = dnd->user_hook2 = 0;	if (get_focus_border_widget () == into)	    destroy_focus_border ();	CExpose (w->ident);	return r;    }    return 1;}static int array_length (Atom * a){    int n;    for (n = 0; a[n]; n++);    return n;}/* X11R5 does not have XGetAtomNames function: */static Status my_XGetAtomNames (Display * display, Atom * atoms, int count, char **names_return){    int i;    for (i = 0; i < count; i++)	if (!(names_return[i] = XGetAtomName (display, atoms[i])))	    return 0;    return 1;}static int widget_apply_position (DndClass * dnd, Window widgets_window, Window from,		      Atom action, int x, int y, Time t, Atom * typelist,	int *want_position, Atom * supported_action, Atom * desired_type,				  XRectangle * rectangle){    CWidget *w;    Window child_return;    int xt, yt;    int xd, yd;    long click;    int i, j;    Atom result = 0;    w = CWidgetOfWindow (widgets_window);    if (!w)	return 0;/* doesn't have mouse funcs - not a drop widget?? */    if (!w->funcs)        return 0;/* input widgets can't drop to themselves :-( */    if (w->kind == C_TEXTINPUT_WIDGET && widgets_window == from)	return 0;/* look up mime types from my own list of supported types */    for (j = 0; xdnd_typelist_receive[w->funcs->types][j]; j++) {	for (i = 0; typelist[i]; i++) {	    if (typelist[i] == xdnd_typelist_receive[w->funcs->types][j]) {		result = typelist[i];		break;	    }	}	if (result)	    break;    }    if (!result && w->funcs->mime_majors) {	char **names_return;	names_return = CMalloc ((array_length (typelist) + 1) * sizeof (char *));	memset (names_return, 0, (array_length (typelist) + 1) * sizeof (char *));	if (my_XGetAtomNames (CDisplay, typelist, array_length (typelist), names_return)) {	    for (i = 0; i < array_length (typelist); i++) {		for (j = 0; w->funcs->mime_majors[j]; j++) {		    if (!strncmp (w->funcs->mime_majors[j], names_return[i], strlen (w->funcs->mime_majors[j]))) {			result = typelist[i];			break;		    }		}		if (result)		    break;	    }	    for (i = 0; i < array_length (typelist); i++)		if (names_return[i])		    XFree (names_return[i]);	}    }/* not supported, so return false */    if (!result)	return 0;    XTranslateCoordinates (CDisplay, CRoot, widgets_window, x, y, &xd, &yd, &child_return);    if (xd < -40 || yd < -40 || xd >= CWidthOf (w) + 40 || yd >= CHeightOf (w) + 40)	return 0;/* things that can receive a drop are in the editor font by definition. */    CPushFont ("editor", 0);    if (w->funcs->xy && w->funcs->cp && w->funcs->move) {	(*w->funcs->xy) (xd, yd, &xt, &yt);	click = (*w->funcs->cp) (w->funcs->data, xt, yt);	if (w->funcs->fin_mark)	    (*w->funcs->fin_mark) (w->funcs->data);	if (w->funcs->move)	    (*w->funcs->move) (w->funcs->data, click, yt);	if (w->funcs->redraw)	    (*w->funcs->redraw) (w->funcs->data, click);    }    CPopFont ();/* we want more position messages */    *want_position = 1;/* we only support copy and move */    if (action == dnd->XdndActionMove) {	*supported_action = dnd->XdndActionMove;    } else {	*supported_action = dnd->XdndActionCopy;    }    *desired_type = result;    rectangle->x = x - 1;    rectangle->y = y - 1;    rectangle->width = rectangle->height = 2;    if (get_focus_border_widget () != widgets_window) {	destroy_focus_border ();	create_focus_border (w, 4);    }    CExpose (w->ident);    return 1;}static void widget_get_data (DndClass * dnd, Window window, unsigned char **data, int *length, Atom type){    int t = DndText;    long start_mark, end_mark;    CWidget *w;    w = CWidgetOfWindow (window);    if (!w) {	return;    }    if (!w->funcs)	return;    if ((*w->funcs->marks) (w->funcs->data, &start_mark, &end_mark)) {	return;    }    if (type == XInternAtom (dnd->display, "url/url", False))	t = DndFile;    else if (type == XInternAtom (dnd->display, "text/uri-list", False))	t = DndFiles;    *data = (unsigned char *) (*w->funcs->get_block) (w->funcs->data, start_mark, end_mark, &t, length);}static int widget_exists (DndClass * dnd, Window window){    return (CWidgetOfWindow (window) != 0);}static void handle_expose_events (DndClass * dnd, XEvent * xevent){    if (!xevent->xexpose.count)	render_focus_border (xevent->xexpose.window);    return;}void mouse_init (void){    CDndClass->handle_expose_events = handle_expose_events;    CDndClass->widget_insert_drop = widget_insert_drop;    CDndClass->widget_exists = widget_exists;    CDndClass->widget_apply_position = widget_apply_position;    CDndClass->widget_get_data = widget_get_data;    CDndClass->widget_apply_leave = widget_apply_leave;    CDndClass->options |= XDND_OPTION_NO_HYSTERESIS;    CDndClass->user_hook1 = CDndClass->user_hook2 = 0;    if (!xdnd_typelist_receive) {	int i;	xdnd_typelist_receive = malloc ((NUM_SIMPLE_TYPES + 1) * sizeof (Atom *));	xdnd_typelist_send = malloc ((NUM_SIMPLE_TYPES + 1) * sizeof (Atom *));	for (i = 0; i < NUM_SIMPLE_TYPES; i++) {	    int j;	    xdnd_typelist_receive[i] = CMalloc (32 * sizeof (Atom));	    for (j = 0; mime_type_recieve[i][j]; j++) {		xdnd_typelist_receive[i][j] = XInternAtom (CDndClass->display, mime_type_recieve[i][j], False);		xdnd_typelist_receive[i][j + 1] = 0;	    }	    xdnd_typelist_receive[i + 1] = 0;	    xdnd_typelist_send[i] = CMalloc (32 * sizeof (Atom));	    for (j = 0; mime_type_send[i][j]; j++) {		xdnd_typelist_send[i][j] = XInternAtom (CDndClass->display, mime_type_send[i][j], False);		xdnd_typelist_send[i][j + 1] = 0;	    }	    xdnd_typelist_send[i + 1] = 0;	}    }}void mouse_shut (void){    if (xdnd_typelist_receive) {	int i;	for (i = 0; xdnd_typelist_send[i]; i++)	    free (xdnd_typelist_send[i]);	free (xdnd_typelist_send);	xdnd_typelist_send = 0;	for (i = 0; xdnd_typelist_receive[i]; i++)	    free (xdnd_typelist_receive[i]);	free (xdnd_typelist_receive);	xdnd_typelist_receive = 0;    }}#endif  /* !GTK */struct mouse_funcs *mouse_funcs_new (void *data, struct mouse_funcs *m){    struct mouse_funcs *p;    p = CMalloc (sizeof (*m));    memcpy (p, m, sizeof (*m));    p->data = data;    return p;}#endif /* HAVE_DND */void mouse_mark (XEvent * event, int double_click, struct mouse_funcs *funcs){    void *data;    static unsigned long win_press = 0;    static int state = 0;	/* 0 = button up, 1 = button pressed, 2 = button pressed and dragging */    static int x_last, y_last;    long click;    data = funcs->data;    if (event->type == ButtonPress) {	long start_mark, end_mark;	state = 1;	win_press = (unsigned long) event->xbutton.window;	(*funcs->xy) (event->xbutton.x, event->xbutton.y, &x_last, &y_last);	click = (*funcs->cp) (data, x_last, y_last);	if (!(*funcs->marks) (data, &start_mark, &end_mark)) {	    if ((*funcs->range) (data, start_mark, end_mark, click)) {		/* if clicked on highlighted text */		unsigned char *t;		int l;#ifdef HAVE_DND		int type;		t = (unsigned char *) (*funcs->get_block) (data, start_mark, end_mark, &type, &l);		if (t) {		    just_dropped_something = 1;		    CDrag (event->xbutton.window, type, t, l, event->xbutton.button == Button1 ? Button1Mask : 0);		    free (t);		}#else#ifndef GTK		/* this is just to get the type which depends on the number of lines selected for 		    the fileselection box: */		t = (unsigned char *) (*funcs->get_block) (data, start_mark, end_mark, &funcs->types, &l);		if (t) {		    free (t);		    set_cursor_visible ();		    if (xdnd_drag (CDndClass, event->xbutton.window,				event->xbutton.button == Button1 ? CDndClass->XdndActionCopy : CDndClass->XdndActionMove,				xdnd_typelist_send[funcs->types]) == CDndClass->XdndActionMove) {			if (funcs->delete_block)			    (*funcs->delete_block) (data);		    }		}#endif#endif		if (funcs->fin_mark)		    (*funcs->fin_mark) (data);		return;	    }	}	just_dropped_something = 0;	if (funcs->fin_mark)	    (*funcs->fin_mark) (data);	(*funcs->move) (data, click, y_last);	if (double_click && funcs->dclick) {	    (*funcs->dclick) (data, event);	    state = 0;	}	if (funcs->redraw)	    (*funcs->redraw) (data, click);    } else if (event->type == ButtonRelease && state > 0 && win_press == (unsigned long) event->xbutton.window && !double_click) {	int x, y;	long start_mark, end_mark;	(*funcs->xy) (event->xbutton.x, event->xbutton.y, &x, &y);	click = (*funcs->cp) (data, x, y);	(*funcs->move) (data, click, y);	if (state == 2)	    goto unhighlight;	if (!(*funcs->marks) (data, &start_mark, &end_mark)) {	    if ((*funcs->range) (data, start_mark, end_mark, click)) {		/* if clicked on highlighted text */	      unhighlight:		if (funcs->release_mark)		    (*funcs->release_mark) (data, event);	    }	}	state = 0;	if (funcs->redraw)	    (*funcs->redraw) (data, click);    } else if (event->type == MotionNotify && state > 0 && win_press == (unsigned long) event->xbutton.window && event->xbutton.state) {	int x, y;	if (!event->xmotion.state)	    return;	(*funcs->xy) (event->xbutton.x, event->xbutton.y, &x, &y);	if (x == x_last && y == y_last && state == 1)	    return;	click = (*funcs->cp) (data, x, y);	if (state == 1) {	    state = 2;	    if (funcs->move_mark)		(funcs->move_mark) (data);	}	(*funcs->move) (data, click, y);	if (funcs->motion)	    (*funcs->motion) (data, click);	if (funcs->redraw)	    (*funcs->redraw) (data, click);    }}

⌨️ 快捷键说明

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