📄 xdnd.c
字号:
xdnd_send_drop (dnd, dnd->dropper_window, from, time);#else xdnd_send_drop (dnd, dnd->dropper_toplevel, from, time);#endif } if (!dnd->internal_drag) for (;;) { XAllowEvents (dnd->display, SyncPointer, CurrentTime); XNextEvent (dnd->display, &xevent); if (xevent.type == ClientMessage && xevent.xclient.message_type == dnd->XdndFinished) { dnd_debug1 ("XdndFinished");#if XDND_VERSION < 3 if (XDND_FINISHED_TARGET_WIN (&xevent) == dnd->dropper_window) {#endif dnd_debug2 (" source correct - exiting event loop, action=%ld", dnd->supported_action); result = dnd->supported_action; /* success - so return action to caller */ break;#if XDND_VERSION < 3 }#endif } else if (xevent.type == Expose) { if (dnd->handle_expose_events) (*dnd->handle_expose_events) (dnd, &xevent); } else if (xevent.type == MotionNotify) { if (xevent.xmotion.time > time + (dnd->time_out ? dnd->time_out * 1000 : 10000)) { /* allow a ten second timeout as default */ dnd_debug1 ("timeout - exiting event loop"); break; } } else if (xevent.type == SelectionRequest && xevent.xselectionrequest.selection == dnd->XdndSelection) {/* the target widget is going to request data, so check for SelectionRequest events */ int length = 0; unsigned char *data = 0; dnd_debug1 ("SelectionRequest - getting widget data"); (*dnd->widget_get_data) (dnd, from, &data, &length, xevent.xselectionrequest.target); if (data) { dnd_debug1 (" sending selection"); xdnd_selection_send (dnd, &xevent.xselectionrequest, data, length); xdnd_xfree (data); }/* don't wait for a XdndFinished event */ if (!dnd_version_at_least (dnd->dragging_version, 2)) break; } } } else { dnd_debug1 ("not ready_to_drop - ungrabbing pointer"); } XUngrabPointer (dnd->display, CurrentTime); xdnd_reset (dnd); return result;}/* returns non-zero if event is handled */int xdnd_handle_drop_events (DndClass * dnd, XEvent * xevent){ int result = 0; if (xevent->type == SelectionNotify) { dnd_debug1 ("got SelectionNotify"); if (xevent->xselection.property == dnd->Xdnd_NON_PROTOCOL_ATOM && dnd->stage == XDND_DROP_STAGE_CONVERTING) { int error; dnd_debug1 (" property is Xdnd_NON_PROTOCOL_ATOM - getting selection"); error = xdnd_get_selection (dnd, dnd->dragger_window, xevent->xselection.property, xevent->xany.window);/* error is not actually used, i think future versions of the protocol maybe should return an error status to the calling window with the XdndFinished client message */ if (dnd_version_at_least (dnd->dragging_version, 2)) {#if XDND_VERSION >= 3 xdnd_send_finished (dnd, dnd->dragger_window, dnd->dropper_toplevel, error);#else xdnd_send_finished (dnd, dnd->dragger_window, dnd->dropper_window, error);#endif dnd_debug1 (" sending finished"); } xdnd_xfree (dnd->dragger_typelist); xdnd_reset (dnd); dnd->stage = XDND_DROP_STAGE_IDLE; result = 1; } else { dnd_debug1 (" property is not Xdnd_NON_PROTOCOL_ATOM - ignoring"); } } else if (xevent->type == ClientMessage) { dnd_debug2 ("got ClientMessage to xevent->xany.window = %ld", xevent->xany.window); if (xevent->xclient.message_type == dnd->XdndEnter) { dnd_debug2 (" message_type is XdndEnter, version = %ld", XDND_ENTER_VERSION (xevent));#if XDND_VERSION >= 3 if (XDND_ENTER_VERSION (xevent) < 3) return 0;#endif xdnd_reset (dnd); dnd->dragger_window = XDND_ENTER_SOURCE_WIN (xevent);#if XDND_VERSION >= 3 dnd->dropper_toplevel = xevent->xany.window; dnd->dropper_window = 0; /* enter goes to the top level window only, so we don't really know what the sub window is yet */#else dnd->dropper_window = xevent->xany.window;#endif xdnd_xfree (dnd->dragger_typelist); if (XDND_ENTER_THREE_TYPES (xevent)) { dnd_debug1 (" three types only"); xdnd_get_three_types (dnd, xevent, &dnd->dragger_typelist); } else { dnd_debug1 (" more than three types - getting list"); xdnd_get_type_list (dnd, dnd->dragger_window, &dnd->dragger_typelist); } if (dnd->dragger_typelist) dnd->stage = XDND_DROP_STAGE_ENTERED; else dnd_debug1 (" typelist returned as zero!"); dnd->dragging_version = XDND_ENTER_VERSION (xevent); result = 1; } else if (xevent->xclient.message_type == dnd->XdndLeave) {#if XDND_VERSION >= 3 if (xevent->xany.window == dnd->dropper_toplevel && dnd->dropper_window) xevent->xany.window = dnd->dropper_window;#endif dnd_debug1 (" message_type is XdndLeave"); if (dnd->dragger_window == XDND_LEAVE_SOURCE_WIN (xevent) && dnd->stage == XDND_DROP_STAGE_ENTERED) { dnd_debug1 (" leaving"); if (dnd->widget_apply_leave) (*dnd->widget_apply_leave) (dnd, xevent->xany.window); dnd->stage = XDND_DROP_STAGE_IDLE; xdnd_xfree (dnd->dragger_typelist); result = 1; dnd->dropper_toplevel = dnd->dropper_window = 0; } else { dnd_debug1 (" wrong stage or from wrong window"); } } else if (xevent->xclient.message_type == dnd->XdndPosition) { dnd_debug2 (" message_type is XdndPosition to %ld", xevent->xany.window); if (dnd->dragger_window == XDND_POSITION_SOURCE_WIN (xevent) && dnd->stage == XDND_DROP_STAGE_ENTERED) { int want_position; Atom action; XRectangle rectangle; Window last_window; last_window = dnd->dropper_window;#if XDND_VERSION >= 3/* version 3 gives us the top-level window only. WE have to find the child that the pointer is over: */ if (1 || xevent->xany.window != dnd->dropper_toplevel || !dnd->dropper_window) { Window parent, child, new_child = 0; dnd->dropper_toplevel = xevent->xany.window; parent = dnd->root_window; child = dnd->dropper_toplevel; for (;;) { int xd, yd; new_child = 0; if (!XTranslateCoordinates (dnd->display, parent, child, XDND_POSITION_ROOT_X (xevent), XDND_POSITION_ROOT_Y (xevent), &xd, &yd, &new_child)) break; if (!new_child) break; child = new_child; } dnd->dropper_window = xevent->xany.window = child; dnd_debug2 (" child window translates to %ld", dnd->dropper_window); } else if (xevent->xany.window == dnd->dropper_toplevel && dnd->dropper_window) { xevent->xany.window = dnd->dropper_window; dnd_debug2 (" child window previously found: %ld", dnd->dropper_window); }#endif action = dnd->XdndActionCopy; dnd->supported_action = dnd->XdndActionCopy; dnd->x = XDND_POSITION_ROOT_X (xevent); dnd->y = XDND_POSITION_ROOT_Y (xevent); dnd->time = CurrentTime; if (dnd_version_at_least (dnd->dragging_version, 1)) dnd->time = XDND_POSITION_TIME (xevent); if (dnd_version_at_least (dnd->dragging_version, 1)) action = XDND_POSITION_ACTION (xevent);#if XDND_VERSION >= 3 if (last_window && last_window != xevent->xany.window) if (dnd->widget_apply_leave) (*dnd->widget_apply_leave) (dnd, last_window);#endif dnd->will_accept = (*dnd->widget_apply_position) (dnd, xevent->xany.window, dnd->dragger_window, action, dnd->x, dnd->y, dnd->time, dnd->dragger_typelist, &want_position, &dnd->supported_action, &dnd->desired_type, &rectangle); dnd_debug2 (" will accept = %d", dnd->will_accept);#if XDND_VERSION >= 3 dnd_debug2 (" sending status of %ld", dnd->dropper_toplevel); xdnd_send_status (dnd, dnd->dragger_window, dnd->dropper_toplevel, dnd->will_accept, want_position, rectangle.x, rectangle.y, rectangle.width, rectangle.height, dnd->supported_action);#else dnd_debug2 (" sending status of %ld", xevent->xany.window); xdnd_send_status (dnd, dnd->dragger_window, xevent->xany.window, dnd->will_accept, want_position, rectangle.x, rectangle.y, rectangle.width, rectangle.height, dnd->supported_action);#endif result = 1; } else { dnd_debug1 (" wrong stage or from wrong window"); } } else if (xevent->xclient.message_type == dnd->XdndDrop) {#if XDND_VERSION >= 3 if (xevent->xany.window == dnd->dropper_toplevel && dnd->dropper_window) xevent->xany.window = dnd->dropper_window;#endif dnd_debug1 (" message_type is XdndDrop"); if (dnd->dragger_window == XDND_DROP_SOURCE_WIN (xevent) && dnd->stage == XDND_DROP_STAGE_ENTERED) { dnd->time = CurrentTime; if (dnd_version_at_least (dnd->dragging_version, 1)) dnd->time = XDND_DROP_TIME (xevent); if (dnd->will_accept) { dnd_debug1 (" will_accept is true - converting selectiong"); dnd_debug2 (" my window is %ld", dnd->dropper_window); dnd_debug2 (" source window is %ld", dnd->dragger_window); xdnd_convert_selection (dnd, dnd->dragger_window, dnd->dropper_window, dnd->desired_type); dnd->stage = XDND_DROP_STAGE_CONVERTING; } else { dnd_debug1 (" will_accept is false - sending finished"); if (dnd_version_at_least (dnd->dragging_version, 2)) {#if XDND_VERSION >= 3 xdnd_send_finished (dnd, dnd->dragger_window, dnd->dropper_toplevel, 1);#else xdnd_send_finished (dnd, dnd->dragger_window, xevent->xany.window, 1);#endif } xdnd_xfree (dnd->dragger_typelist); xdnd_reset (dnd); dnd->stage = XDND_DROP_STAGE_IDLE; } result = 1; } else { dnd_debug1 (" wrong stage or from wrong window"); } } } return result;}/* Following here is a sample implementation: Suppose we want a window to recieve drops, but do not want to be concerned with setting up all the DndClass methods. All we then do is call xdnd_get_drop() whenever a ClientMessage is recieved. If the message has nothing to do with XDND, xdnd_get_drop quickly returns 0. If it is a XdndEnter message, then xdnd_get_drop enters its own XNextEvent loop and handles all XDND protocol messages internally, returning the action requested. You should pass a desired typelist and actionlist to xdnd_get_type. These must be null terminated arrays of atoms, or a null pointer if you would like any action or type to be accepted. If typelist is null then the first type of the dragging widgets typelist will be the one used. If actionlist is null, then only XdndActionCopy will be accepted. The result is stored in *data, length, type, x and y. *data must be free'd. */struct xdnd_get_drop_info { unsigned char *drop_data; int drop_data_length; int x, y; Atom return_type; Atom return_action; Atom *typelist; Atom *actionlist;};static int widget_insert_drop (DndClass * dnd, unsigned char *data, int length, int remaining, Window into, Window from, Atom type){ struct xdnd_get_drop_info *i; i = (struct xdnd_get_drop_info *) dnd->user_hook1; if (!i->drop_data) { i->drop_data = malloc (length); if (!i->drop_data) return 1; memcpy (i->drop_data, data, length); i->drop_data_length = length; } else { unsigned char *t; t = malloc (i->drop_data_length + length); if (!t) { free (i->drop_data); i->drop_data = 0; return 1; } memcpy (t, i->drop_data, i->drop_data_length); memcpy (t + i->drop_data_length, data, length); free (i->drop_data); i->drop_data = t; i->drop_data_length += length; } return 0;}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_return, Atom * desired_type, XRectangle * rectangle){ int i, j; struct xdnd_get_drop_info *info; Atom *dropper_typelist, supported_type = 0; Atom *supported_actions, supported_action = 0; info = (struct xdnd_get_drop_info *) dnd->user_hook1; dropper_typelist = info->typelist; supported_actions = info->actionlist; if (dropper_typelist) {/* find a correlation: */ for (j = 0; dropper_typelist[j]; j++) { for (i = 0; typelist[i]; i++) { if (typelist[i] == dropper_typelist[j]) { supported_type = typelist[i]; break; } } if (supported_type) break; } } else {/* user did not specify, so return first type */ supported_type = typelist[0]; }/* not supported, so return false */ if (!supported_type) return 0; if (supported_actions) { for (j = 0; supported_actions[j]; j++) { if (action == supported_actions[j]) { supported_action = action; break; } } } else {/* user did not specify */ if (action == dnd->XdndActionCopy) supported_action = action; } if (!supported_action) return 0; *want_position = 1; rectangle->x = rectangle->y = 0; rectangle->width = rectangle->height = 0; info->return_action = *supported_action_return = supported_action; info->return_type = *desired_type = supported_type; info->x = x; info->y = y; return 1;}Atom xdnd_get_drop (Display * display, XEvent * xevent, Atom * typelist, Atom * actionlist, unsigned char **data, int *length, Atom * type, int *x, int *y){ Atom action = 0; static int initialised = 0; static DndClass dnd; if (!initialised) { xdnd_init (&dnd, display); initialised = 1; } if (xevent->type != ClientMessage || xevent->xclient.message_type != dnd.XdndEnter) { return 0; } else { struct xdnd_get_drop_info i;/* setup user structure */ memset (&i, 0, sizeof (i)); i.typelist = actionlist; i.typelist = typelist; dnd.user_hook1 = &i;/* setup methods */ dnd.widget_insert_drop = widget_insert_drop; dnd.widget_apply_position = widget_apply_position;/* main loop */ for (;;) { xdnd_handle_drop_events (&dnd, xevent); if (dnd.stage == XDND_DROP_STAGE_IDLE) break; XNextEvent (dnd.display, xevent); }/* return results */ if (i.drop_data) { *length = i.drop_data_length; *data = i.drop_data; action = i.return_action; *type = i.return_type; *x = i.x; *y = i.y; } } return action;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -