From 278d65282e0be5411a82d58905f0a7be6f2129cd Mon Sep 17 00:00:00 2001 From: jsorg71 Date: Wed, 2 Sep 2009 02:52:30 +0000 Subject: [PATCH] clipboard work --- sesman/chansrv/chansrv.c | 40 ++---- sesman/chansrv/chansrv.h | 4 +- sesman/chansrv/clipboard.c | 246 +++++++++++++++++++++++-------------- 3 files changed, 161 insertions(+), 129 deletions(-) diff --git a/sesman/chansrv/chansrv.c b/sesman/chansrv/chansrv.c index 1d1d9c1d..1e80534b 100644 --- a/sesman/chansrv/chansrv.c +++ b/sesman/chansrv/chansrv.c @@ -17,7 +17,6 @@ Copyright (C) Jay Sorg 2009 */ -#include #include "arch.h" #include "os_calls.h" #include "thread_calls.h" @@ -28,7 +27,6 @@ #include "clipboard.h" #include "devredir.h" -static tbus g_thread_done_event = 0; static struct trans* g_lis_trans = 0; static struct trans* g_con_trans = 0; static struct chan_item g_chan_items[32]; @@ -37,14 +35,14 @@ static int g_cliprdr_index = -1; static int g_rdpsnd_index = -1; static int g_rdpdr_index = -1; -tbus g_term_event = 0; +static tbus g_term_event = 0; +static tbus g_thread_done_event = 0; + int g_display_num = 0; int g_cliprdr_chan_id = -1; /* cliprdr */ int g_rdpsnd_chan_id = -1; /* rdpsnd */ int g_rdpdr_chan_id = -1; /* rdpdr */ -Display* g_display = 0; - /*****************************************************************************/ /* returns error */ int APP_CC @@ -553,26 +551,12 @@ get_display_num_from_display(char* display_text) } /*****************************************************************************/ -int DEFAULT_CC -my_error_handler(Display* dis, XErrorEvent* xer) -{ - char text[256]; - - XGetErrorText(dis, xer->error_code, text, 255); - LOG(1, ("error [%s]", text)); - return 0; -} - -/*****************************************************************************/ -/* The X server had an internal error. This is the last function called. - Do any cleanup that needs to be done on exit, like removing temporary files. - Don't worry about memory leaks */ -int DEFAULT_CC -my_fatal_handler(Display* dis) +int APP_CC +main_cleanup(void) { - LOG(1, ("fatal error, exiting")); g_delete_wait_obj(g_term_event); g_delete_wait_obj(g_thread_done_event); + g_deinit(); /* os_calls */ return 0; } @@ -600,14 +584,6 @@ main(int argc, char** argv) return 1; } LOG(1, ("main: using DISPLAY %d", g_display_num)); - g_display = XOpenDisplay(0); - if (g_display == 0) - { - LOG(0, ("main: XOpenDisplay failed")); - return 1; - } - XSetErrorHandler(my_error_handler); - XSetIOErrorHandler(my_fatal_handler); g_snprintf(text, 255, "xrdp_chansrv_%8.8x_main_term", pid); g_term_event = g_create_wait_obj(text); g_snprintf(text, 255, "xrdp_chansrv_%8.8x_thread_done", pid); @@ -631,9 +607,7 @@ main(int argc, char** argv) } } /* cleanup */ - g_delete_wait_obj(g_term_event); - g_delete_wait_obj(g_thread_done_event); + main_cleanup(); LOG(1, ("main: app exiting pid %d(0x%8.8x)", pid, pid)); - g_deinit(); /* os_calls */ return 0; } diff --git a/sesman/chansrv/chansrv.h b/sesman/chansrv/chansrv.h index 4ab4f1ae..d36e5ef5 100644 --- a/sesman/chansrv/chansrv.h +++ b/sesman/chansrv/chansrv.h @@ -14,8 +14,10 @@ struct chan_item int APP_CC send_channel_data(int chan_id, char* data, int size); +int APP_CC +main_cleanup(void); -#define LOG_LEVEL 10 +#define LOG_LEVEL 5 #define LOG(_a, _params) \ { \ diff --git a/sesman/chansrv/clipboard.c b/sesman/chansrv/clipboard.c index 983fe8bc..c8385045 100644 --- a/sesman/chansrv/clipboard.c +++ b/sesman/chansrv/clipboard.c @@ -64,9 +64,35 @@ static int g_data_in_size = 0; static int g_data_in_time = 0; static int g_data_in_up_to_date = 0; static int g_got_format_announce = 0; +static int g_waiting_for_data_response = 0; +static int g_waiting_for_data_response_time = 0; + +static Display* g_display = 0; extern int g_cliprdr_chan_id; /* in chansrv.c */ -extern Display* g_display; /* in chansrv.c */ + +/*****************************************************************************/ +int DEFAULT_CC +clipboard_error_handler(Display* dis, XErrorEvent* xer) +{ + char text[256]; + + XGetErrorText(dis, xer->error_code, text, 255); + LOG(1, ("error [%s]", text)); + return 0; +} + +/*****************************************************************************/ +/* The X server had an internal error. This is the last function called. + Do any cleanup that needs to be done on exit, like removing temporary files. + Don't worry about memory leaks */ +int DEFAULT_CC +clipboard_fatal_handler(Display* dis) +{ + LOG(1, ("fatal error, exiting")); + main_cleanup(); + return 0; +} /*****************************************************************************/ /* this is one way to get the current time from the x server */ @@ -111,12 +137,20 @@ clipboard_init(void) int ver_min; Status st; - LOG(1, ("xrdp-chansrv: in clipboard_init")); + LOG(5, ("xrdp-chansrv: in clipboard_init")); if (g_clip_up) { return 0; } rv = 0; + XSetErrorHandler(clipboard_error_handler); + XSetIOErrorHandler(clipboard_fatal_handler); + g_display = XOpenDisplay(0); + if (g_display == 0) + { + LOG(0, ("clipboard_init: XOpenDisplay failed")); + rv = 1; + } if (rv == 0) { g_x_socket = XConnectionNumber(g_display); @@ -146,9 +180,9 @@ clipboard_init(void) } if (rv == 0) { - LOG(1, ("clipboard_init: g_xfixes_event_base %d", g_xfixes_event_base)); + LOG(0, ("clipboard_init: g_xfixes_event_base %d", g_xfixes_event_base)); st = XFixesQueryVersion(g_display, &ver_maj, &ver_min); - LOG(1, ("clipboard_init st %d, maj %d min %d", st, ver_maj, ver_min)); + LOG(0, ("clipboard_init st %d, maj %d min %d", st, ver_maj, ver_min)); g_screen_num = DefaultScreen(g_display); g_screen = ScreenOfDisplay(g_display, g_screen_num); g_clip_property_atom = XInternAtom(g_display, "XRDP_CLIP_PROPERTY_ATOM", @@ -182,7 +216,7 @@ clipboard_init(void) out_uint32_le(s, 0); /* extra 4 bytes ? */ s_mark_end(s); size = (int)(s->end - s->data); - LOG(1, ("clipboard_init: data out, sending " + LOG(5, ("clipboard_init: data out, sending " "CLIPRDR_CONNECT (clip_msg_id = 1)")); rv = send_channel_data(g_cliprdr_chan_id, s->data, size); if (rv != 0) @@ -236,7 +270,7 @@ clipboard_send_data_request(void) int rv; int num_chars; - LOG(1, ("clipboard_send_data_request:")); + LOG(5, ("clipboard_send_data_request:")); if (!g_got_format_announce) { LOG(0, ("clipboard_send_data_request: error, no format announce")); @@ -251,7 +285,7 @@ clipboard_send_data_request(void) out_uint32_le(s, 0x0d); s_mark_end(s); size = (int)(s->end - s->data); - LOG(1, ("clipboard_send_data_request: data out, sending " + LOG(5, ("clipboard_send_data_request: data out, sending " "CLIPRDR_DATA_REQUEST (clip_msg_id = 4)")); rv = send_channel_data(g_cliprdr_chan_id, s->data, size); free_stream(s); @@ -274,7 +308,7 @@ clipboard_send_format_ack(void) out_uint32_le(s, 0); /* extra 4 bytes ? */ s_mark_end(s); size = (int)(s->end - s->data); - LOG(1, ("clipboard_send_format_ack: data out, sending " + LOG(5, ("clipboard_send_format_ack: data out, sending " "CLIPRDR_FORMAT_ACK (clip_msg_id = 3)")); rv = send_channel_data(g_cliprdr_chan_id, s->data, size); free_stream(s); @@ -298,7 +332,7 @@ clipboard_send_format_announce(void) out_uint8s(s, 0x90); s_mark_end(s); size = (int)(s->end - s->data); - LOG(1, ("clipboard_send_format_announce: data out, sending " + LOG(5, ("clipboard_send_format_announce: data out, sending " "CLIPRDR_FORMAT_ANNOUNCE (clip_msg_id = 2)")); rv = send_channel_data(g_cliprdr_chan_id, s->data, size); free_stream(s); @@ -348,7 +382,7 @@ clipboard_send_data_response(void) num_chars = 0; if (g_last_clip_data != 0) { - if (g_last_clip_type == XA_STRING) + if ((g_last_clip_type == XA_STRING) || (g_last_clip_type == g_utf8_atom)) { num_chars = g_mbstowcs(0, g_last_clip_data, 0); if (num_chars < 0) @@ -374,7 +408,7 @@ clipboard_send_data_response(void) out_uint32_le(s, 0); s_mark_end(s); size = (int)(s->end - s->data); - LOG(1, ("clipboard_send_data_response: data out, sending " + LOG(5, ("clipboard_send_data_response: data out, sending " "CLIPRDR_DATA_RESPONSE (clip_msg_id = 5) size %d num_chars %d", size, num_chars)); rv = send_channel_data(g_cliprdr_chan_id, s->data, size); @@ -400,6 +434,47 @@ clipboard_set_selection_owner(void) return 0; } +/*****************************************************************************/ +static int APP_CC +clipboard_provide_selection(XSelectionRequestEvent* req, Atom type, int format, + char* data, int length) +{ + XEvent xev; + + XChangeProperty(g_display, req->requestor, req->property, + type, format, PropModeReplace, (tui8*)data, length); + 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; +} + +/*****************************************************************************/ +static int APP_CC +clipboard_refuse_selection(XSelectionRequestEvent* req) +{ + XEvent xev; + + 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 = None; + xev.xselection.time = req->time; + XSendEvent(g_display, req->requestor, False, NoEventMask, &xev); + return 0; +} + /*****************************************************************************/ static int APP_CC clipboard_process_format_announce(struct stream* s, int clip_msg_status, @@ -407,7 +482,7 @@ clipboard_process_format_announce(struct stream* s, int clip_msg_status, { Window owner; - LOG(1, ("clipboard_process_format_announce: CLIPRDR_FORMAT_ANNOUNCE")); + LOG(5, ("clipboard_process_format_announce: CLIPRDR_FORMAT_ANNOUNCE")); //g_hexdump(s->p, s->end - s->p); clipboard_send_format_ack(); g_got_format_announce = 1; @@ -424,7 +499,7 @@ static int APP_CC clipboard_prcoess_format_ack(struct stream* s, int clip_msg_status, int clip_msg_len) { - LOG(1, ("clipboard_prcoess_format_ack: CLIPRDR_FORMAT_ACK")); + LOG(5, ("clipboard_prcoess_format_ack: CLIPRDR_FORMAT_ACK")); //g_hexdump(s->p, s->end - s->p); return 0; } @@ -434,7 +509,7 @@ static int APP_CC clipboard_process_data_request(struct stream* s, int clip_msg_status, int clip_msg_len) { - LOG(1, ("clipboard_process_data_request: CLIPRDR_DATA_REQUEST")); + LOG(5, ("clipboard_process_data_request: CLIPRDR_DATA_REQUEST")); //g_hexdump(s->p, s->end - s->p); clipboard_send_data_response(); return 0; @@ -454,7 +529,8 @@ clipboard_process_data_response(struct stream* s, int clip_msg_status, int wtext_size; int data_in_len; - LOG(1, ("clipboard_process_data_response: CLIPRDR_DATA_RESPONSE")); + LOG(5, ("clipboard_process_data_response: CLIPRDR_DATA_RESPONSE")); + g_waiting_for_data_response = 0; len = (int)(s->end - s->p); if (len < 1) { @@ -503,20 +579,9 @@ clipboard_process_data_response(struct stream* s, int clip_msg_status, for (index = 0; index < g_selection_request_event_count; index++) { lxev = &(g_selection_request_event[index]); - XChangeProperty(g_display, lxev->requestor, lxev->property, - lxev->target, 8, PropModeReplace, g_data_in, - data_in_len); - g_memset(&xev, 0, sizeof(xev)); - xev.xselection.type = SelectionNotify; - xev.xselection.send_event = True; - xev.xselection.display = lxev->display; - xev.xselection.requestor = lxev->requestor; - xev.xselection.selection = lxev->selection; - xev.xselection.target = lxev->target; - xev.xselection.property = lxev->property; - xev.xselection.time = lxev->time; - XSendEvent(g_display, lxev->requestor, False, NoEventMask, &xev); - LOG(1, ("clipboard_process_data_response: requestor %d data_in_len %d", + clipboard_provide_selection(lxev, lxev->target, 8, g_data_in, + data_in_len); + LOG(5, ("clipboard_process_data_response: requestor %d data_in_len %d", lxev->requestor, data_in_len)); } } @@ -611,12 +676,12 @@ clipboard_event_selection_owner_notify(XEvent* xevent) XFixesSelectionNotifyEvent* lxevent; lxevent = (XFixesSelectionNotifyEvent*)xevent; - LOG(1, ("clipboard_event_selection_owner_notify: " + LOG(5, ("clipboard_event_selection_owner_notify: " "window %d subtype %d owner %d g_wnd %d", lxevent->window, lxevent->subtype, lxevent->owner, g_wnd)); if (lxevent->owner == g_wnd) { - LOG(1, ("clipboard_event_selection_owner_notify: skipping, " + LOG(5, ("clipboard_event_selection_owner_notify: skipping, " "onwer == g_wnd")); g_got_selection = 1; return 0; @@ -731,13 +796,15 @@ clipboard_event_selection_notify(XEvent* xevent) int rv; int index; int convert_to_string; + int convert_to_utf8; int send_format_announce; int atom; int* atoms; Atom type; - LOG(1, ("clipboard_event_selection_notify:")); + LOG(5, ("clipboard_event_selection_notify:")); convert_to_string = 0; + convert_to_utf8 = 0; send_format_announce = 0; rv = 0; data = 0; @@ -773,9 +840,13 @@ clipboard_event_selection_notify(XEvent* xevent) for (index = 0; index < n_items; index++) { atom = atoms[index]; - LOG(1, ("clipboard_event_selection_notify: %d %s %d", atom, + LOG(5, ("clipboard_event_selection_notify: %d %s %d", atom, XGetAtomName(g_display, atom), XA_STRING)); - if (atom == XA_STRING) + if (atom == g_utf8_atom) + { + convert_to_utf8 = 1; + } + else if (atom == XA_STRING) { convert_to_string = 1; } @@ -788,9 +859,21 @@ clipboard_event_selection_notify(XEvent* xevent) "type[%d], fmt[%d]", type, fmt, XA_ATOM, 32)); } } + else if (lxevent->target == g_utf8_atom) + { + LOG(5, ("clipboard_event_selection_notify: UTF8_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 = g_utf8_atom; + 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 if (lxevent->target == XA_STRING) { - LOG(10, ("clipboard_event_selection_notify: XA_STRING data_size %d", + LOG(5, ("clipboard_event_selection_notify: XA_STRING data_size %d", data_size)); g_free(g_last_clip_data); g_last_clip_size = data_size; @@ -810,7 +893,12 @@ clipboard_event_selection_notify(XEvent* xevent) LOG(0, ("clipboard_event_selection_notify: unknown selection")); } } - if (convert_to_string) + if (convert_to_utf8) + { + XConvertSelection(g_display, g_clipboard_atom, g_utf8_atom, + g_clip_property_atom, g_wnd, lxevent->time); + } + else if (convert_to_string) { XConvertSelection(g_display, g_clipboard_atom, XA_STRING, g_clip_property_atom, g_wnd, lxevent->time); @@ -854,67 +942,43 @@ clipboard_event_selection_request(XEvent* xevent) char* xdata; lxev = (XSelectionRequestEvent*)xevent; - LOG(1, ("clipboard_event_selection_request: g_wnd %d, " + LOG(5, ("clipboard_event_selection_request: g_wnd %d, " ".requestor %d .owner %d .selection %d '%s' .target %d .property %d", g_wnd, lxev->requestor, lxev->owner, lxev->selection, XGetAtomName(g_display, lxev->selection), lxev->target, lxev->property)); if (lxev->property == None) { - LOG(1, ("clipboard_event_selection_request: lxev->property is None")); + LOG(5, ("clipboard_event_selection_request: lxev->property is None")); } else if (lxev->target == g_targets_atom) { /* requestor is asking what the selection can be converted to */ - LOG(1, ("clipboard_event_selection_request: g_targets_atom")); + LOG(5, ("clipboard_event_selection_request: g_targets_atom")); ui32[0] = g_targets_atom; ui32[1] = g_timestamp_atom; ui32[2] = g_multiple_atom; ui32[3] = XA_STRING; ui32[4] = g_utf8_atom; - XChangeProperty(g_display, lxev->requestor, lxev->property, - XA_ATOM, 32, PropModeReplace, (tui8*)ui32, 5); - g_memset(&xev, 0, sizeof(xev)); - xev.xselection.type = SelectionNotify; - xev.xselection.send_event = True; - xev.xselection.display = lxev->display; - xev.xselection.requestor = lxev->requestor; - xev.xselection.selection = lxev->selection; - xev.xselection.target = lxev->target; - xev.xselection.property = lxev->property; - xev.xselection.time = lxev->time; - XSendEvent(g_display, lxev->requestor, False, NoEventMask, &xev); - return 0; + return clipboard_provide_selection(lxev, XA_ATOM, 32, (char*)ui32, 5); } else if (lxev->target == g_timestamp_atom) { /* requestor is asking the time I got the selection */ - LOG(1, ("clipboard_event_selection_request: g_timestamp_atom")); + LOG(5, ("clipboard_event_selection_request: g_timestamp_atom")); ui32[0] = g_selection_time; - XChangeProperty(g_display, lxev->requestor, lxev->property, - XA_INTEGER, 32, PropModeReplace, (tui8*)ui32, 1); - g_memset(&xev, 0, sizeof(xev)); - xev.xselection.type = SelectionNotify; - xev.xselection.send_event = True; - xev.xselection.display = lxev->display; - xev.xselection.requestor = lxev->requestor; - xev.xselection.selection = lxev->selection; - xev.xselection.target = lxev->target; - xev.xselection.property = lxev->property; - xev.xselection.time = lxev->time; - XSendEvent(g_display, lxev->requestor, False, NoEventMask, &xev); - return 0; + return clipboard_provide_selection(lxev, XA_INTEGER, 32, (char*)ui32, 1); } else if (lxev->target == g_multiple_atom) { /* target, property pairs */ - LOG(1, ("clipboard_event_selection_request: g_multiple_atom")); + LOG(5, ("clipboard_event_selection_request: g_multiple_atom")); if (clipboard_get_window_property(xev.xselection.requestor, xev.xselection.property, &type, &fmt, &n_items, &xdata, &xdata_size) == 0) { - LOG(1, ("clipboard_event_selection_request: g_multiple_atom " + LOG(5, ("clipboard_event_selection_request: g_multiple_atom " "n_items %d", n_items)); /* todo */ g_free(xdata); @@ -922,24 +986,12 @@ clipboard_event_selection_request(XEvent* xevent) } else if ((lxev->target == XA_STRING) || (lxev->target == g_utf8_atom)) { - LOG(1, ("clipboard_event_selection_request: %s", + LOG(5, ("clipboard_event_selection_request: %s", XGetAtomName(g_display, lxev->target))); if (g_data_in_up_to_date) { - XChangeProperty(g_display, lxev->requestor, lxev->property, - lxev->target, 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 = lxev->display; - xev.xselection.requestor = lxev->requestor; - xev.xselection.selection = lxev->selection; - xev.xselection.target = lxev->target; - xev.xselection.property = lxev->property; - xev.xselection.time = lxev->time; - XSendEvent(g_display, lxev->requestor, False, NoEventMask, &xev); - return 0; + return clipboard_provide_selection(lxev, lxev->target, 8, + g_data_in, g_strlen(g_data_in)); } if (g_selection_request_event_count > 10) { @@ -952,6 +1004,8 @@ clipboard_event_selection_request(XEvent* xevent) if (g_selection_request_event_count == 0) { clipboard_send_data_request(); + g_waiting_for_data_response = 1; + g_waiting_for_data_response_time = clipboard_get_local_time(); } g_selection_request_event_count++; return 0; @@ -959,19 +1013,10 @@ clipboard_event_selection_request(XEvent* xevent) } else { - LOG(1, ("clipboard_event_selection_request: unknown " + LOG(0, ("clipboard_event_selection_request: unknown " "target %s", XGetAtomName(g_display, lxev->target))); } - g_memset(&xev, 0, sizeof(xev)); - xev.xselection.type = SelectionNotify; - xev.xselection.send_event = True; - xev.xselection.display = lxev->display; - xev.xselection.requestor = lxev->requestor; - xev.xselection.selection = lxev->selection; - xev.xselection.target = lxev->target; - xev.xselection.property = None; - xev.xselection.time = lxev->time; - XSendEvent(g_display, lxev->requestor, False, NoEventMask, &xev); + clipboard_refuse_selection(lxev); return 0; } @@ -990,7 +1035,7 @@ clipboard_event_selection_request(XEvent* xevent) static int APP_CC clipboard_event_selection_clear(XEvent* xevent) { - LOG(1, ("clipboard_event_selection_clear:")); + LOG(5, ("clipboard_event_selection_clear:")); return 0; } @@ -1040,6 +1085,7 @@ int APP_CC clipboard_check_wait_objs(void) { XEvent xevent; + int time_diff; if (!g_clip_up) { @@ -1053,6 +1099,16 @@ clipboard_check_wait_objs(void) LOG(0, ("clipboard_check_wait_objs: sck closed")); return 0; } + if (g_waiting_for_data_response) + { + time_diff = clipboard_get_local_time() - + g_waiting_for_data_response_time; + if (time_diff > 1000) + { + LOG(0, ("clipboard_check_wait_objs: warning, waiting for " + "data response too long")); + } + } while (XPending(g_display) > 0) { XNextEvent(g_display, &xevent);