diff --git a/sesman/chansrv/clipboard.c b/sesman/chansrv/clipboard.c index d14be594..9b3839db 100644 --- a/sesman/chansrv/clipboard.c +++ b/sesman/chansrv/clipboard.c @@ -55,6 +55,13 @@ static Time g_selection_time = 0; static struct stream* g_ins = 0; +static XSelectionRequestEvent g_selection_request_event[16]; +static int g_selection_request_event_count = 0; + +static char* g_data_in; +static int g_data_in_size; +static int g_data_in_time; + extern int g_cliprdr_chan_id; /* in chansrv.c */ extern Display* g_display; /* in chansrv.c */ @@ -199,6 +206,7 @@ clipboard_deinit(void) g_x_socket = 0; g_free(g_last_clip_data); g_last_clip_data = 0; + g_last_clip_size = 0; free_stream(g_ins); g_clip_up = 0; return 0; @@ -358,11 +366,20 @@ static int APP_CC clipboard_process_format_announce(struct stream* s, int clip_msg_status, int clip_msg_len) { + Window owner; + LOG(1, ("clipboard_process_format_announce: CLIPRDR_FORMAT_ANNOUNCE")); - //g_hexdump(s->p, s->end - s->p); clipboard_send_format_ack(); g_selection_time = clipboard_get_time(); XSetSelectionOwner(g_display, g_clipboard_atom, g_wnd, g_selection_time); + //XSetSelectionOwner(g_display, XA_PRIMARY, g_wnd, g_selection_time); + g_got_selection = 1; + owner = XGetSelectionOwner(g_display, g_clipboard_atom); + if (owner != g_wnd) + { + g_got_selection = 0; + LOG(0, ("clipboard_process_format_announce: XSetSelectionOwner failed")); + } return 0; } @@ -392,8 +409,77 @@ static int APP_CC clipboard_process_data_response(struct stream* s, int clip_msg_status, int clip_msg_len) { + XEvent xev; + XSelectionRequestEvent* lev; + twchar* wtext; + twchar wchr; + int len; + int index; + int wtext_size; + LOG(1, ("clipboard_process_data_response: CLIPRDR_DATA_RESPONSE")); - //g_hexdump(s->p, s->end - s->p); + len = (int)(s->end - s->p); + if (len < 1) + { + return 0; + } + g_hexdump(s->p, len); + wtext = (twchar*)g_malloc(((len / 2) + 1) * sizeof(twchar), 0); + if (wtext == 0) + { + return 0; + } + index = 0; + while (s_check(s)) + { + in_uint16_le(s, wchr); + wtext[index] = wchr; + if (wchr == 0) + { + break; + } + index++; + } + wtext[index] = 0; + len = g_wcstombs(0, wtext, 0); + if (len >= 0) + { + g_free(g_data_in); + g_data_in_size = 0; + g_data_in = (char*)g_malloc(len + 16, 0); + if (g_data_in == 0) + { + g_free(wtext); + return 0; + } + g_data_in_size = len; + g_wcstombs(g_data_in, wtext, len + 1); + len = g_strlen(g_data_in); + g_data_in_time = g_time3(); + } + if (g_data_in != 0) + { + for (index = 0; index < g_selection_request_event_count; index++) + { + lev = &(g_selection_request_event[index]); + XChangeProperty(g_display, lev->requestor, lev->property, + XA_STRING, 8, PropModeReplace, g_data_in, + g_strlen(g_data_in)); + g_memset(&xev, 0, sizeof(xev)); + xev.xselection.type = SelectionNotify; + xev.xselection.send_event = True; + xev.xselection.display = lev->display; + xev.xselection.requestor = lev->requestor; + xev.xselection.selection = lev->selection; + xev.xselection.target = lev->target; + xev.xselection.property = lev->property; + xev.xselection.time = CurrentTime; + XSendEvent(g_display, lev->requestor, False, NoEventMask, &xev); + LOG(1, ("clipboard_process_data_response: %d", lev->requestor)); + } + } + g_selection_request_event_count = 0; + g_free(wtext); return 0; } @@ -483,13 +569,18 @@ clipboard_process_selection_owner_notify(XEvent* xevent) lxevent = (XFixesSelectionNotifyEvent*)xevent; LOG(1, ("clipboard_process_selection_owner_notify: " - "window %d subtype %d owner %d", - lxevent->window, lxevent->subtype, lxevent->owner)); - if (lxevent->subtype == 0) + "window %d subtype %d owner %d g_wnd %d", + lxevent->window, lxevent->subtype, lxevent->owner, g_wnd)); + if (lxevent->owner == g_wnd) { - XConvertSelection(g_display, g_clipboard_atom, XA_STRING, - g_clip_property_atom, g_wnd, CurrentTime); + LOG(1, ("clipboard_process_selection_owner_notify: skipping, " + "onwer == g_wnd")); + g_got_selection = 1; + return 0; } + g_got_selection = 0; + XConvertSelection(g_display, g_clipboard_atom, g_targets_atom, + g_clip_property_atom, g_wnd, lxevent->timestamp); return 0; } @@ -595,9 +686,16 @@ clipboard_process_selection_notify(XEvent* xevent) int n_items; int fmt; int rv; + int index; + int convert_to_string; + int send_format_announce; + int atom; + int* atoms; Atom type; LOG(1, ("clipboard_process_selection_notify:")); + convert_to_string = 0; + send_format_announce = 0; rv = 0; data = 0; type = 0; @@ -610,34 +708,71 @@ clipboard_process_selection_notify(XEvent* xevent) } if (rv == 0) { - rv = clipboard_get_window_property(g_wnd, lxevent->property, &type, &fmt, + rv = clipboard_get_window_property(lxevent->requestor, lxevent->property, + &type, &fmt, &n_items, &data, &data_size); if (rv != 0) { LOG(0, ("clipboard_process_selection_notify: " "clipboard_get_window_property failed error %d", rv)); } - XDeleteProperty(g_display, g_wnd, g_clip_property_atom); + XDeleteProperty(g_display, lxevent->requestor, lxevent->property); } if (rv == 0) { - if (type == XA_STRING) + if (lxevent->selection == g_clipboard_atom) { - g_free(g_last_clip_data); - g_last_clip_size = data_size; - g_last_clip_data = g_malloc(g_last_clip_size + 1, 0); - g_last_clip_type = XA_STRING; - g_memcpy(g_last_clip_data, data, g_last_clip_size); - g_last_clip_data[g_last_clip_size] = 0; + if (lxevent->target == g_targets_atom) + { + if ((type == XA_ATOM) && (fmt == 32)) + { + atoms = (int*)data; + for (index = 0; index < n_items; index++) + { + atom = atoms[index]; + LOG(1, ("clipboard_process_selection_notify: %d %s %d", atom, + XGetAtomName(g_display, atom), XA_STRING)); + if (atom == XA_STRING) + { + convert_to_string = 1; + } + } + } + else + { + LOG(0, ("clipboard_process_selection_notify: error, target is " + "'TARGETS' and type[%d] or fmt[%d] not right, should be " + "type[%d], fmt[%d]", type, fmt, XA_ATOM, 32)); + } + } + else if (lxevent->target == XA_STRING) + { + LOG(10, ("clipboard_process_selection_notify: XA_STRING data_size %d", + data_size)); + g_free(g_last_clip_data); + g_last_clip_size = data_size; + g_last_clip_data = g_malloc(g_last_clip_size + 1, 0); + g_last_clip_type = XA_STRING; + g_memcpy(g_last_clip_data, data, g_last_clip_size); + g_last_clip_data[g_last_clip_size] = 0; + send_format_announce = 1; + } + else + { + LOG(0, ("clipboard_process_selection_notify: unknown target")); + } } else { - LOG(0, ("clipboard_process_selection_notify: unknown " - "clipboard data type %d", type)); - rv = 3; + LOG(0, ("clipboard_process_selection_notify: unknown selection")); } } - if (rv == 0) + if (convert_to_string) + { + XConvertSelection(g_display, g_clipboard_atom, XA_STRING, + g_clip_property_atom, g_wnd, CurrentTime); + } + if (send_format_announce) { if (clipboard_send_format_announce() != 0) { @@ -696,8 +831,8 @@ clipboard_process_selection_request(XEvent* xevent) XA_ATOM, 32, PropModeReplace, (tui8*)ui32, 4); g_memset(&xev, 0, sizeof(xev)); xev.xselection.type = SelectionNotify; - xev.xselection.serial = 0; xev.xselection.send_event = True; + xev.xselection.display = lxevent->display; xev.xselection.requestor = lxevent->requestor; xev.xselection.selection = lxevent->selection; xev.xselection.target = lxevent->target; @@ -715,8 +850,8 @@ clipboard_process_selection_request(XEvent* xevent) XA_INTEGER, 32, PropModeReplace, (tui8*)ui32, 1); g_memset(&xev, 0, sizeof(xev)); xev.xselection.type = SelectionNotify; - xev.xselection.serial = 0; xev.xselection.send_event = True; + xev.xselection.display = lxevent->display; xev.xselection.requestor = lxevent->requestor; xev.xselection.selection = lxevent->selection; xev.xselection.target = lxevent->target; @@ -743,12 +878,33 @@ clipboard_process_selection_request(XEvent* xevent) else if (lxevent->target == XA_STRING) { LOG(1, ("clipboard_process_selection_request: XA_STRING")); +/* + if (g_abs((g_time3() - g_data_in_time)) < 1000) + { + LOG(1, ("clipboard_process_selection_request: XA_STRING---------------------------")); + XChangeProperty(g_display, lxevent->requestor, lxevent->property, + XA_STRING, 8, PropModeReplace, g_data_in, + g_strlen(g_data_in)); + g_memset(&xev, 0, sizeof(xev)); + xev.xselection.type = SelectionNotify; + xev.xselection.send_event = True; + xev.xselection.display = lxevent->display; + xev.xselection.requestor = lxevent->requestor; + xev.xselection.selection = lxevent->selection; + xev.xselection.target = lxevent->target; + xev.xselection.property = lxevent->property; + xev.xselection.time = lxevent->time; + XSendEvent(g_display, lxevent->requestor, False, NoEventMask, &xev); + return 0; + } +*/ +/* XChangeProperty(g_display, lxevent->requestor, lxevent->property, - XA_STRING, 8, PropModeReplace, "test", 5); + XA_STRING, 8, PropModeReplace, "Jay--", 5); g_memset(&xev, 0, sizeof(xev)); xev.xselection.type = SelectionNotify; - xev.xselection.serial = 0; xev.xselection.send_event = True; + xev.xselection.display = lxevent->display; xev.xselection.requestor = lxevent->requestor; xev.xselection.selection = lxevent->selection; xev.xselection.target = lxevent->target; @@ -756,6 +912,22 @@ clipboard_process_selection_request(XEvent* xevent) xev.xselection.time = lxevent->time; XSendEvent(g_display, lxevent->requestor, False, NoEventMask, &xev); return 0; +*/ + if (g_selection_request_event_count > 10) + { + LOG(0, ("clipboard_process_selection_request: error, too many requests")); + } + else + { + g_memcpy(&(g_selection_request_event[g_selection_request_event_count]), + lxevent, sizeof(g_selection_request_event[0])); + if (g_selection_request_event_count == 0) + { + clipboard_send_data_request(); + } + g_selection_request_event_count++; + return 0; + } } else { @@ -764,8 +936,8 @@ clipboard_process_selection_request(XEvent* xevent) } g_memset(&xev, 0, sizeof(xev)); xev.xselection.type = SelectionNotify; - xev.xselection.serial = 0; xev.xselection.send_event = True; + xev.xselection.display = lxevent->display; xev.xselection.requestor = lxevent->requestor; xev.xselection.selection = lxevent->selection; xev.xselection.target = lxevent->target; @@ -791,7 +963,6 @@ static int APP_CC clipboard_process_selection_clear(XEvent* xevent) { LOG(1, ("clipboard_process_selection_clear:")); - g_got_selection = 0; return 0; } @@ -850,6 +1021,7 @@ clipboard_check_wait_objs(void) case MappingNotify: break; case PropertyNotify: + LOG(1, ("clipboard_check_wait_objs: PropertyNotify .window %d .state %d", xevent.xproperty.window, xevent.xproperty.state)); break; default: if (xevent.type == g_xfixes_event_base +