📄 xdnd.c
字号:
unsigned long nitems; unsigned char *s = 0; if (prop == None) return 1; nread = 0; if (XGetWindowProperty (dnd->display, insert, prop, 0, 8, False, AnyPropertyType, &actual_type, &actual_fmt, &nitems, &bytes_after, &s) != Success) { XFree (s); return 1; } XFree (s); if (actual_type != XInternAtom (dnd->display, "INCR", False)) return paste_prop_internal (dnd, from, insert, prop, True); XDeleteProperty (dnd->display, insert, prop); gettimeofday (&tv_start, 0); for (;;) { long t; fd_set r; XEvent xe; if (XCheckMaskEvent (dnd->display, PropertyChangeMask, &xe)) { if (xe.type == PropertyNotify && xe.xproperty.state == PropertyNewValue) {/* time between arrivals of data */ gettimeofday (&tv_start, 0); if (paste_prop_internal (dnd, from, insert, prop, True)) break; } } else { tv.tv_sec = 0; tv.tv_usec = 10000; FD_ZERO (&r); FD_SET (ConnectionNumber (dnd->display), &r); select (ConnectionNumber (dnd->display) + 1, &r, 0, 0, &tv); if (FD_ISSET (ConnectionNumber (dnd->display), &r)) continue; } gettimeofday (&tv, 0); t = (tv.tv_sec - tv_start.tv_sec) * 1000000L + (tv.tv_usec - tv_start.tv_usec);/* no data for five seconds, so quit */ if (t > 5000000L) return 1; } return 0;}int outside_rectangle (int x, int y, XRectangle * r){ return (x < r->x || y < r->y || x >= r->x + r->width || y >= r->y + r->height);}/* avoids linking with the maths library */static float xdnd_sqrt (float x){ float last_ans, ans = 2, a; if (x <= 0.0) return 0.0; do { last_ans = ans; ans = (ans + x / ans) / 2; a = (ans - last_ans) / ans; if (a < 0.0) a = (-a); } while (a > 0.001); return ans;}#define print_marks print_win_marks(from,__FILE__,__LINE__);/* returns action on success, 0 otherwise */Atom xdnd_drag (DndClass * dnd, Window from, Atom action, Atom * typelist){ XEvent xevent, xevent_temp; Window over_window = 0, last_window = 0;#if XDND_VERSION >= 3 Window last_dropper_toplevel = 0; int internal_dropable = 1;#endif int n; DndCursor *cursor; float x_mouse, y_mouse; int result = 0, dnd_aware; if (!typelist) dnd_warning ("xdnd_drag() called with typelist = 0");/* first wait until the mouse moves more than five pixels */ do { XNextEvent (dnd->display, &xevent); if (xevent.type == ButtonRelease) { dnd_debug1 ("button release - no motion"); XSendEvent (dnd->display, xevent.xany.window, 0, ButtonReleaseMask, &xevent); return 0; } } while (xevent.type != MotionNotify); x_mouse = (float) xevent.xmotion.x_root; y_mouse = (float) xevent.xmotion.y_root; if (!dnd->drag_threshold) dnd->drag_threshold = 4.0; for (;;) { XNextEvent (dnd->display, &xevent); if (xevent.type == MotionNotify) if (xdnd_sqrt ((x_mouse - xevent.xmotion.x_root) * (x_mouse - xevent.xmotion.x_root) + (y_mouse - xevent.xmotion.y_root) * (y_mouse - xevent.xmotion.y_root)) > dnd->drag_threshold) break; if (xevent.type == ButtonRelease) { XSendEvent (dnd->display, xevent.xany.window, 0, ButtonReleaseMask, &xevent); return 0; } } dnd_debug1 ("moved 5 pixels - going to drag"); n = array_length (typelist); if (n > XDND_THREE) xdnd_set_type_list (dnd, from, typelist); xdnd_reset (dnd); dnd->stage = XDND_DRAG_STAGE_DRAGGING; for (cursor = &dnd->cursors[0]; cursor->width; cursor++) if (cursor->action == action) break; if (!cursor->width) cursor = &dnd->cursors[0];/* the mouse has been dragged a little, so this is a drag proper */ if (XGrabPointer (dnd->display, dnd->root_window, False, ButtonMotionMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, cursor->cursor, CurrentTime) != GrabSuccess) dnd_debug1 ("Unable to grab pointer"); while (xevent.xany.type != ButtonRelease) { XAllowEvents (dnd->display, SyncPointer, CurrentTime); XNextEvent (dnd->display, &xevent); switch (xevent.type) { case Expose: if (dnd->handle_expose_events) (*dnd->handle_expose_events) (dnd, &xevent); break; case EnterNotify:/* this event is not actually reported, so we find out by ourselves from motion events */ break; case LeaveNotify:/* this event is not actually reported, so we find out by ourselves from motion events */ break; case ButtonRelease:/* done, but must send a leave event */ dnd_debug1 ("ButtonRelease - exiting event loop"); break; case MotionNotify: dnd_aware = 0; dnd->dropper_toplevel = 0; memcpy (&xevent_temp, &xevent, sizeof (xevent)); xevent.xmotion.subwindow = xevent.xmotion.window; { Window root_return, child_return; int x_temp, y_temp; unsigned int mask_return; while (XQueryPointer (dnd->display, xevent.xmotion.subwindow, &root_return, &child_return, &x_temp, &y_temp, &xevent.xmotion.x, &xevent.xmotion.y, &mask_return)) {#if XDND_VERSION >= 3 if (!dnd_aware) { if ((dnd_aware = xdnd_is_dnd_aware (dnd, xevent.xmotion.subwindow, &dnd->dragging_version, typelist))) { dnd->dropper_toplevel = xevent.xmotion.subwindow; xevent.xmotion.x_root = x_temp; xevent.xmotion.y_root = y_temp; } }#else xevent.xmotion.x_root = x_temp; xevent.xmotion.y_root = y_temp;#endif if (!child_return) goto found_descendent; xevent.xmotion.subwindow = child_return; } break; } found_descendent:/* last_window is just for debug purposes */ if (last_window != xevent.xmotion.subwindow) { dnd_debug2 ("window crossing to %ld", xevent.xmotion.subwindow); dnd_debug2 (" current window is %ld", over_window); dnd_debug3 (" last_window = %ld, xmotion.subwindow = %ld", last_window, xevent.xmotion.subwindow);#if XDND_VERSION >= 3 dnd_debug3 (" dropper_toplevel = %ld, last_dropper_toplevel.subwindow = %ld", dnd->dropper_toplevel, last_dropper_toplevel);#endif dnd_debug3 (" dnd_aware = %d, dnd->options & XDND_OPTION_NO_HYSTERESIS = %ld", dnd_aware, (long) dnd->options & XDND_OPTION_NO_HYSTERESIS); }#if XDND_VERSION < 3/* is the new window dnd aware? if not stay in the old window */ if (over_window != xevent.xmotion.subwindow && last_window != xevent.xmotion.subwindow && ( (dnd_aware = xdnd_is_dnd_aware (dnd, xevent.xmotion.subwindow, &dnd->dragging_version, typelist)) || (dnd->options & XDND_OPTION_NO_HYSTERESIS) ))#else internal_dropable = 1; if (dnd->widget_exists && (*dnd->widget_exists) (dnd, xevent.xmotion.subwindow)) if (!xdnd_is_dnd_aware (dnd, xevent.xmotion.subwindow, &dnd->dragging_version, typelist)) internal_dropable = 0; dnd_debug3 ("dnd->dropper_toplevel = %ld, last_dropper_toplevel = %ld\n", dnd->dropper_toplevel, last_dropper_toplevel); if ((dnd->dropper_toplevel != last_dropper_toplevel || last_window != xevent.xmotion.subwindow) && internal_dropable && ( (dnd_aware) || (dnd->options & XDND_OPTION_NO_HYSTERESIS) ))#endif {/* leaving window we were over */ if (over_window) { if (dnd->stage == XDND_DRAG_STAGE_ENTERED) { dnd_debug1 ("got leave at right stage"); dnd->stage = XDND_DRAG_STAGE_DRAGGING; if (dnd->internal_drag) { dnd_debug1 (" our own widget"); if (dnd->widget_apply_leave) (*dnd->widget_apply_leave) (dnd, over_window); } else { dnd_debug1 (" not our widget - sending XdndLeave");#if XDND_VERSION < 3 xdnd_send_leave (dnd, over_window, from);#else if (dnd->dropper_toplevel != last_dropper_toplevel) { xdnd_send_leave (dnd, last_dropper_toplevel, from); } else { dnd_debug1 (" not sending leave --> dnd->dropper_toplevel == last_dropper_toplevel"); }#endif } dnd->internal_drag = 0; dnd->dropper_window = 0; dnd->ready_to_drop = 0; } else { dnd_debug1 ("got leave at wrong stage - ignoring"); } }/* entering window we are currently over */ over_window = xevent.xmotion.subwindow; if (dnd_aware) { dnd_debug1 (" is dnd aware"); dnd->stage = XDND_DRAG_STAGE_ENTERED; if (dnd->widget_exists && (*dnd->widget_exists) (dnd, over_window)) dnd->internal_drag = 1; if (dnd->internal_drag) { dnd_debug1 (" our own widget"); } else { dnd_debug2 (" not our widget - sending XdndEnter to %ld", over_window);#if XDND_VERSION < 3 xdnd_send_enter (dnd, over_window, from, typelist);#else if (dnd->dropper_toplevel != last_dropper_toplevel) xdnd_send_enter (dnd, dnd->dropper_toplevel, from, typelist);#endif } dnd->want_position = 1; dnd->ready_to_drop = 0; dnd->rectangle.width = dnd->rectangle.height = 0; dnd->dropper_window = over_window;/* we want an additional motion event in case the pointer enters and then stops */ XSendEvent (dnd->display, from, 0, ButtonMotionMask, &xevent_temp); XSync (dnd->display, 0); }#if XDND_VERSION >= 3 last_dropper_toplevel = dnd->dropper_toplevel;#endif/* we are now officially in a new window */ } else {/* got here, so we are just moving `inside' the same window */ if (dnd->stage == XDND_DRAG_STAGE_ENTERED) { dnd->supported_action = dnd->XdndActionCopy; dnd_debug1 ("got motion at right stage"); dnd->x = xevent.xmotion.x_root; dnd->y = xevent.xmotion.y_root; if (dnd->want_position || outside_rectangle (dnd->x, dnd->y, &dnd->rectangle)) { dnd_debug1 (" want position and outside rectangle"); if (dnd->internal_drag) { dnd_debug1 (" our own widget"); dnd->ready_to_drop = (*dnd->widget_apply_position) (dnd, over_window, from, action, dnd->x, dnd->y, xevent.xmotion.time, typelist, &dnd->want_position, &dnd->supported_action, &dnd->desired_type, &dnd->rectangle); /* if not ready, keep sending positions, this check is repeated below for XdndStatus from external widgets */ if (!dnd->ready_to_drop) { dnd->want_position = 1; dnd->rectangle.width = dnd->rectangle.height = 0; } dnd_debug2 (" return action=%ld", dnd->supported_action); } else {#if XDND_VERSION < 3 dnd_debug3 (" not our own widget - sending XdndPosition to %ld, action %ld", over_window, action); xdnd_send_position (dnd, over_window, from, action, dnd->x, dnd->y, xevent.xmotion.time);#else dnd_debug3 (" not our own widget - sending XdndPosition to %ld, action %ld", dnd->dropper_toplevel, action); xdnd_send_position (dnd, dnd->dropper_toplevel, from, action, dnd->x, dnd->y, xevent.xmotion.time);#endif } } else if (dnd->want_position) { dnd_debug1 (" inside rectangle"); } else { dnd_debug1 (" doesn't want position"); } } } last_window = xevent.xmotion.subwindow; break; case ClientMessage: dnd_debug1 ("ClientMessage recieved"); if (xevent.xclient.message_type == dnd->XdndStatus && !dnd->internal_drag) { dnd_debug1 (" XdndStatus recieved"); if (dnd->stage == XDND_DRAG_STAGE_ENTERED #if XDND_VERSION < 3 && XDND_STATUS_TARGET_WIN (&xevent) == dnd->dropper_window#endif ) { dnd_debug1 (" XdndStatus stage correct, dropper window correct"); dnd->want_position = XDND_STATUS_WANT_POSITION (&xevent); dnd->ready_to_drop = XDND_STATUS_WILL_ACCEPT (&xevent); dnd->rectangle.x = XDND_STATUS_RECT_X (&xevent); dnd->rectangle.y = XDND_STATUS_RECT_Y (&xevent); dnd->rectangle.width = XDND_STATUS_RECT_WIDTH (&xevent); dnd->rectangle.height = XDND_STATUS_RECT_HEIGHT (&xevent); dnd->supported_action = dnd->XdndActionCopy; if (dnd_version_at_least (dnd->dragging_version, 2)) dnd->supported_action = XDND_STATUS_ACTION (&xevent); dnd_debug3 (" return action=%ld, ready=%d", dnd->supported_action, dnd->ready_to_drop); /* if not ready, keep sending positions, this check is repeated above for internal widgets */ if (!dnd->ready_to_drop) { dnd->want_position = 1; dnd->rectangle.width = dnd->rectangle.height = 0; } dnd_debug3 (" rectangle = (x=%d, y=%d, ", dnd->rectangle.x, dnd->rectangle.y); dnd_debug4 ("w=%d, h=%d), want_position=%d\n", dnd->rectangle.width, dnd->rectangle.height, dnd->want_position); }#if XDND_VERSION < 3 else if (XDND_STATUS_TARGET_WIN (&xevent) != dnd->dropper_window) { dnd_debug3 (" XdndStatus XDND_STATUS_TARGET_WIN (&xevent) = %ld, dnd->dropper_window = %ld", XDND_STATUS_TARGET_WIN (&xevent), dnd->dropper_window); }#endif else { dnd_debug2 (" XdndStatus stage incorrect dnd->stage = %d", dnd->stage); } } break; case SelectionRequest:{/* the target widget MAY request data, so wait for SelectionRequest */ 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); } } break; } } if (dnd->ready_to_drop) { Time time; dnd_debug1 ("ready_to_drop - sending XdndDrop"); time = xevent.xbutton.time; if (dnd->internal_drag) {/* we are dealing with our own widget, no need to send drop events, just put the data straight */ int length = 0; unsigned char *data = 0; if (dnd->widget_insert_drop) { (*dnd->widget_get_data) (dnd, from, &data, &length, dnd->desired_type); if (data) { if (!(*dnd->widget_insert_drop) (dnd, data, length, 0, dnd->dropper_window, from, dnd->desired_type)) { result = dnd->supported_action; /* success - so return action to caller */ dnd_debug1 (" inserted data into widget - success"); } else { dnd_debug1 (" inserted data into widget - failed"); } xdnd_xfree (data); } else { dnd_debug1 (" got data from widget, but data is null"); } } } else { xdnd_set_selection_owner (dnd, from, dnd->desired_type);#if XDND_VERSION < 3
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -