chansrv: work on clipboard

This commit is contained in:
Jay Sorg 2012-10-14 18:08:06 -07:00
parent 37d4f5725c
commit faec53b7f3
2 changed files with 134 additions and 35 deletions

View File

@ -147,6 +147,11 @@ static int g_cliprdr_flags = CB_USE_LONG_FORMAT_NAMES |
static int g_formatIds[16]; static int g_formatIds[16];
static int g_num_formatIds = 0; static int g_num_formatIds = 0;
/* this is used because client will ask for the same thing more than
once in successiotn */
int g_last_client_request_xrdp_clip_type = 0;
unsigned int g_last_client_request_xrdp_clip_time = 0;
/*****************************************************************************/ /*****************************************************************************/
/* this is one way to get the current time from the x server */ /* this is one way to get the current time from the x server */
static Time APP_CC static Time APP_CC
@ -559,7 +564,7 @@ clipboard_send_format_announce(int xrdp_clip_type)
out_uint32_le(s, 0); out_uint32_le(s, 0);
s_mark_end(s); s_mark_end(s);
size = (int)(s->end - s->data); size = (int)(s->end - s->data);
g_hexdump(s->data, size); //g_hexdump(s->data, size);
LOGM((LOG_LEVEL_DEBUG, "clipboard_send_format_announce: data out, sending " LOGM((LOG_LEVEL_DEBUG, "clipboard_send_format_announce: data out, sending "
"CLIPRDR_FORMAT_ANNOUNCE (clip_msg_id = 2)")); "CLIPRDR_FORMAT_ANNOUNCE (clip_msg_id = 2)"));
rv = send_channel_data(g_cliprdr_chan_id, s->data, size); rv = send_channel_data(g_cliprdr_chan_id, s->data, size);
@ -694,19 +699,42 @@ clipboard_provide_selection(XSelectionRequestEvent *req, Atom type, int format,
char *data, int length) char *data, int length)
{ {
XEvent xev; XEvent xev;
long val1;
XChangeProperty(g_display, req->requestor, req->property, LLOGLN(0, ("clipboard_provide_selection: length %d", length));
type, format, PropModeReplace, (tui8 *)data, length); if (length <= 16 * 1024 * 1024)
g_memset(&xev, 0, sizeof(xev)); {
xev.xselection.type = SelectionNotify; XChangeProperty(g_display, req->requestor, req->property,
xev.xselection.send_event = True; type, format, PropModeReplace, (tui8 *)data, length);
xev.xselection.display = req->display; g_memset(&xev, 0, sizeof(xev));
xev.xselection.requestor = req->requestor; xev.xselection.type = SelectionNotify;
xev.xselection.selection = req->selection; xev.xselection.send_event = True;
xev.xselection.target = req->target; xev.xselection.display = req->display;
xev.xselection.property = req->property; xev.xselection.requestor = req->requestor;
xev.xselection.time = req->time; xev.xselection.selection = req->selection;
XSendEvent(g_display, req->requestor, False, NoEventMask, &xev); xev.xselection.target = req->target;
xev.xselection.property = req->property;
xev.xselection.time = req->time;
XSendEvent(g_display, req->requestor, False, NoEventMask, &xev);
}
else
{
/* start the INCR process */
LLOGLN(0, ("clipboard_provide_selection: start INCR"));
val1 = 0;
XChangeProperty(g_display, req->requestor, req->property,
g_incr_atom, 32, PropModeReplace, (tui8 *)&val1, 1);
g_memset(&xev, 0, sizeof(xev));
xev.xselection.type = SelectionNotify;
xev.xselection.send_event = True;
xev.xselection.display = req->display;
xev.xselection.requestor = req->requestor;
xev.xselection.selection = req->selection;
xev.xselection.target = req->target;
xev.xselection.property = req->property;
xev.xselection.time = req->time;
XSendEvent(g_display, req->requestor, False, NoEventMask, &xev);
}
return 0; return 0;
} }
@ -746,7 +774,7 @@ clipboard_process_format_announce(struct stream *s, int clip_msg_status,
LOGM((LOG_LEVEL_DEBUG, "clipboard_process_format_announce: " LOGM((LOG_LEVEL_DEBUG, "clipboard_process_format_announce: "
"CLIPRDR_FORMAT_ANNOUNCE")); "CLIPRDR_FORMAT_ANNOUNCE"));
LLOGLN(10, ("clipboard_process_format_announce %d", clip_msg_len)); LLOGLN(10, ("clipboard_process_format_announce %d", clip_msg_len));
g_hexdump(s->p, s->end - s->p); //g_hexdump(s->p, s->end - s->p);
clipboard_send_format_ack(); clipboard_send_format_ack();
g_got_format_announce = 1; g_got_format_announce = 1;
g_data_in_up_to_date = 0; g_data_in_up_to_date = 0;
@ -806,7 +834,7 @@ clipboard_prcoess_format_ack(struct stream *s, int clip_msg_status,
{ {
LOGM((LOG_LEVEL_DEBUG, "clipboard_prcoess_format_ack: CLIPRDR_FORMAT_ACK")); LOGM((LOG_LEVEL_DEBUG, "clipboard_prcoess_format_ack: CLIPRDR_FORMAT_ACK"));
LLOGLN(10, ("clipboard_prcoess_format_ack:")); LLOGLN(10, ("clipboard_prcoess_format_ack:"));
g_hexdump(s->p, s->end - s->p); //g_hexdump(s->p, s->end - s->p);
return 0; return 0;
} }
@ -839,28 +867,73 @@ clipboard_process_data_request(struct stream *s, int clip_msg_status,
int clip_msg_len) int clip_msg_len)
{ {
int requestedFormatId; int requestedFormatId;
tui32 now;
tui32 tdiff;
LOGM((LOG_LEVEL_DEBUG, "clipboard_process_data_request: " LOGM((LOG_LEVEL_DEBUG, "clipboard_process_data_request: "
"CLIPRDR_DATA_REQUEST")); "CLIPRDR_DATA_REQUEST"));
LLOGLN(10, ("clipboard_process_data_request:")); LLOGLN(10, ("clipboard_process_data_request:"));
g_hexdump(s->p, s->end - s->p); //g_hexdump(s->p, s->end - s->p);
now = xcommon_get_local_time();
tdiff = now - g_last_client_request_xrdp_clip_time;
in_uint32_le(s, requestedFormatId); in_uint32_le(s, requestedFormatId);
switch (requestedFormatId) switch (requestedFormatId)
{ {
case CB_FORMAT_FILE: /* 0xC0BC */ case CB_FORMAT_FILE: /* 0xC0BC */
LLOGLN(10, ("clipboard_process_data_request: CB_FORMAT_FILE %d", g_last_clip_type)); if ((tdiff < 500) &&
XConvertSelection(g_display, g_clipboard_atom, g_last_clip_type, (g_last_client_request_xrdp_clip_type == XRDP_CB_FILE))
g_clip_property_atom, g_wnd, CurrentTime); {
LLOGLN(10, ("clipboard_process_data_request: CB_FORMAT_FILE, "
"sending last data tdiff %d", tdiff));
clipboard_send_data_response_for_file(g_last_clip_data,
g_last_clip_size);
}
else
{
LLOGLN(10, ("clipboard_process_data_request: CB_FORMAT_FILE, "
"calling XConvertSelection to g_utf8_atom "
"tdiff %d", tdiff));
g_last_client_request_xrdp_clip_type = XRDP_CB_FILE;
g_last_client_request_xrdp_clip_time = now;
XConvertSelection(g_display, g_clipboard_atom, g_utf8_atom,
g_clip_property_atom, g_wnd, CurrentTime);
}
break; break;
case CB_FORMAT_DIB: /* 0x0008 */ case CB_FORMAT_DIB: /* 0x0008 */
LLOGLN(10, ("clipboard_process_data_request: CB_FORMAT_DIB")); if ((tdiff < 500) &&
XConvertSelection(g_display, g_clipboard_atom, g_last_clip_type, (g_last_client_request_xrdp_clip_type == XRDP_CB_BITMAP))
g_clip_property_atom, g_wnd, CurrentTime); {
LLOGLN(10, ("clipboard_process_data_request: CB_FORMAT_DIB, "
"sending last data tdiff %d", tdiff));
clipboard_send_data_response_for_image(g_last_clip_data,
g_last_clip_size);
}
else
{
LLOGLN(10, ("clipboard_process_data_request: CB_FORMAT_DIB, "
"calling XConvertSelection to g_image_bmp_atom "
"tdiff %d", tdiff));
XConvertSelection(g_display, g_clipboard_atom, g_image_bmp_atom,
g_clip_property_atom, g_wnd, CurrentTime);
}
break; break;
case CB_FORMAT_UNICODETEXT: /* 0x000D */ case CB_FORMAT_UNICODETEXT: /* 0x000D */
LLOGLN(10, ("clipboard_process_data_request: CB_FORMAT_UNICODETEXT")); if ((tdiff < 500) &&
XConvertSelection(g_display, g_clipboard_atom, g_last_clip_type, (g_last_client_request_xrdp_clip_type == XRDP_CB_TEXT))
g_clip_property_atom, g_wnd, CurrentTime); {
LLOGLN(10, ("clipboard_process_data_request: CB_FORMAT_UNICODETEXT, "
"sending last data tdiff %d", tdiff));
clipboard_send_data_response_for_image(g_last_clip_data,
g_last_clip_size);
}
else
{
LLOGLN(10, ("clipboard_process_data_request: CB_FORMAT_UNICODETEXT, "
"calling XConvertSelection to g_utf8_atom "
"tdiff %d", tdiff));
XConvertSelection(g_display, g_clipboard_atom, g_utf8_atom,
g_clip_property_atom, g_wnd, CurrentTime);
}
break; break;
default: default:
LLOGLN(10, ("clipboard_process_data_request: unknown type %d", LLOGLN(10, ("clipboard_process_data_request: unknown type %d",
@ -880,8 +953,8 @@ clipboard_process_data_request(struct stream *s, int clip_msg_status,
clipboard data. */ clipboard data. */
static int APP_CC static int APP_CC
clipboard_process_data_response_for_image(struct stream *s, clipboard_process_data_response_for_image(struct stream *s,
int clip_msg_status, int clip_msg_status,
int clip_msg_len) int clip_msg_len)
{ {
XSelectionRequestEvent *lxev = &g_saved_selection_req_event; XSelectionRequestEvent *lxev = &g_saved_selection_req_event;
char *cptr; char *cptr;
@ -931,7 +1004,8 @@ clipboard_process_data_response_for_image(struct stream *s,
g_data_in_time = clipboard_get_local_time(); g_data_in_time = clipboard_get_local_time();
g_data_in_up_to_date = 1; g_data_in_up_to_date = 1;
} }
LLOGLN(10, ("clipboard_process_data_response_for_image: calling "
"clipboard_provide_selection with %d bytes", len));
clipboard_provide_selection(lxev, lxev->target, 8, cptr, len); clipboard_provide_selection(lxev, lxev->target, 8, cptr, len);
return 0; return 0;
} }
@ -1260,13 +1334,19 @@ clipboard_get_window_property(Window wnd, Atom prop, Atom *type, int *fmt,
if (ltype == g_incr_atom) if (ltype == g_incr_atom)
{ {
LOGM((LOG_LEVEL_DEBUG, "clipboard_get_window_property: INCR start")); LOGM((LOG_LEVEL_DEBUG, "clipboard_get_window_property: INCR start"));
LLOGLN(10, ("clipboard_get_window_property: INCR start")); LLOGLN(10, ("clipboard_get_window_property: INCR start lfmt %d "
"ln_items %d llen_after %d", lfmt, ln_items, llen_after));
g_incr_in_progress = 1; g_incr_in_progress = 1;
g_incr_atom_type = prop; g_incr_atom_type = prop;
g_incr_data_size = 0; g_incr_data_size = 0;
g_free(g_incr_data); g_free(g_incr_data);
g_incr_data = 0; g_incr_data = 0;
/* this will start the incr process */
XDeleteProperty(g_display, g_wnd, prop); XDeleteProperty(g_display, g_wnd, prop);
if (type != 0)
{
*type = ltype;
}
return 0; return 0;
} }
@ -1426,6 +1506,15 @@ clipboard_event_selection_notify(XEvent *xevent)
} }
XDeleteProperty(g_display, lxevent->requestor, lxevent->property); XDeleteProperty(g_display, lxevent->requestor, lxevent->property);
if (type == g_incr_atom)
{
/* nothing more to do here, the data is comming in through
PropertyNotify */
LLOGLN(0, ("clipboard_event_selection_notify: type is INCR"));
return 0;
}
} }
if (rv == 0) if (rv == 0)
@ -1783,10 +1872,19 @@ clipboard_event_property_notify(XEvent *xevent)
".state %d .atom %d", xevent->xproperty.window, ".state %d .atom %d", xevent->xproperty.window,
xevent->xproperty.state, xevent->xproperty.atom)); xevent->xproperty.state, xevent->xproperty.atom));
if (g_incr_in_progress &&
(xevent->xproperty.atom == g_incr_atom_type) &&
(xevent->xproperty.state == PropertyDelete))
{
/* this is used for when copying a large clipboard to the other app,
it will delete the property so we know to send the next one */
LLOGLN(10, ("clipboard_event_property_notify: INCR PropertyDelete"));
}
if (g_incr_in_progress && if (g_incr_in_progress &&
(xevent->xproperty.atom == g_incr_atom_type) && (xevent->xproperty.atom == g_incr_atom_type) &&
(xevent->xproperty.state == PropertyNewValue)) (xevent->xproperty.state == PropertyNewValue))
{ {
LLOGLN(10, ("clipboard_event_property_notify: INCR PropertyNewValue"));
rv = XGetWindowProperty(g_display, g_wnd, g_incr_atom_type, 0, 0, 0, rv = XGetWindowProperty(g_display, g_wnd, g_incr_atom_type, 0, 0, 0,
AnyPropertyType, &actual_type_return, &actual_format_return, AnyPropertyType, &actual_type_return, &actual_format_return,
&nitems_returned, &bytes_left, (unsigned char **) &data); &nitems_returned, &bytes_left, (unsigned char **) &data);
@ -1866,6 +1964,7 @@ clipboard_event_property_notify(XEvent *xevent)
return 0; return 0;
} }
LLOGLN(10, ("clipboard_event_property_notify: new_data_len %d", new_data_len));
g_incr_data = cptr; g_incr_data = cptr;
g_memcpy(g_incr_data + g_incr_data_size, data, new_data_len); g_memcpy(g_incr_data + g_incr_data_size, data, new_data_len);
g_incr_data_size += new_data_len; g_incr_data_size += new_data_len;

View File

@ -173,14 +173,14 @@ clipboard_send_data_response_for_file(char *data, int data_size)
LLOGLN(10, ("clipboard_send_data_response_for_file: g_last_clip_size %d", LLOGLN(10, ("clipboard_send_data_response_for_file: g_last_clip_size %d",
g_last_clip_size)); g_last_clip_size));
g_hexdump(data, data_size); //g_hexdump(data, data_size);
clipboard_get_files(data, data_size); clipboard_get_files(data, data_size);
cItems = g_num_files; cItems = g_num_files;
bytes_after_header = cItems * 592 + 4; bytes_after_header = cItems * 592 + 4;
make_stream(s); make_stream(s);
init_stream(s, 64 + bytes_after_header); init_stream(s, 64 + bytes_after_header);
out_uint16_le(s, CB_FORMAT_DATA_RESPONSE); /* 5 CLIPRDR_DATA_RESPONSE */ out_uint16_le(s, CB_FORMAT_DATA_RESPONSE); /* 5 CLIPRDR_DATA_RESPONSE */
out_uint16_le(s, 1); // CB_RESPONSE_OK); /* 1 status */ out_uint16_le(s, CB_RESPONSE_OK); /* 1 status */
out_uint32_le(s, bytes_after_header); out_uint32_le(s, bytes_after_header);
out_uint32_le(s, cItems); out_uint32_le(s, cItems);
for (index = 0; index < cItems; index++) for (index = 0; index < cItems; index++)
@ -199,7 +199,7 @@ clipboard_send_data_response_for_file(char *data, int data_size)
/* file size */ /* file size */
out_uint32_le(s, 0); out_uint32_le(s, 0);
out_uint32_le(s, g_files[index].size); out_uint32_le(s, g_files[index].size);
g_writeln("jay size %d", g_files[index].size); //g_writeln("jay size %d", g_files[index].size);
g_snprintf(fn, 255, "%s", g_files[index].filename); g_snprintf(fn, 255, "%s", g_files[index].filename);
clipboard_out_unicode(s, fn, 256); clipboard_out_unicode(s, fn, 256);
out_uint8s(s, 8); /* pad */ out_uint8s(s, 8); /* pad */
@ -207,7 +207,7 @@ clipboard_send_data_response_for_file(char *data, int data_size)
out_uint32_le(s, 0); out_uint32_le(s, 0);
s_mark_end(s); s_mark_end(s);
size = (int)(s->end - s->data); size = (int)(s->end - s->data);
g_hexdump(s->data, size); //g_hexdump(s->data, size);
rv = send_channel_data(g_cliprdr_chan_id, s->data, size); rv = send_channel_data(g_cliprdr_chan_id, s->data, size);
free_stream(s); free_stream(s);
return rv; return rv;
@ -270,7 +270,7 @@ clipboard_send_file_data(int streamId, int lindex,
init_stream(s, cbRequested + 64); init_stream(s, cbRequested + 64);
//g_memset(s->data + 12, 26, cbRequested); //g_memset(s->data + 12, 26, cbRequested);
size = g_file_read(fd, s->data + 12, cbRequested); size = g_file_read(fd, s->data + 12, cbRequested);
g_writeln("size %d", size); //g_writeln("size %d", size);
if (size < 1) if (size < 1)
{ {
LLOGLN(10, ("clipboard_send_file_data: read error, want %d got %d", LLOGLN(10, ("clipboard_send_file_data: read error, want %d got %d",
@ -307,7 +307,7 @@ clipboard_process_file_request(struct stream *s, int clip_msg_status,
//int clipDataId; //int clipDataId;
LLOGLN(10, ("clipboard_process_file_request:")); LLOGLN(10, ("clipboard_process_file_request:"));
g_hexdump(s->p, clip_msg_len); //g_hexdump(s->p, clip_msg_len);
in_uint32_le(s, streamId); in_uint32_le(s, streamId);
in_uint32_le(s, lindex); in_uint32_le(s, lindex);
in_uint32_le(s, dwFlags); in_uint32_le(s, dwFlags);