From 142a93829b3224550fe27c3c5d60d255f3a6424d Mon Sep 17 00:00:00 2001 From: Jim Grandy Date: Sat, 6 Jul 2013 08:42:05 -0700 Subject: [PATCH] Hand-apply patches (chansrv/rail) from Authentic8: 516fd1d 6a4fb28 c038a99 --- sesman/chansrv/chansrv.c | 139 +++++++++++++++++++++++++++++++++ sesman/chansrv/chansrv.h | 2 + sesman/chansrv/rail.c | 162 +++++++++++++++++---------------------- 3 files changed, 212 insertions(+), 91 deletions(-) diff --git a/sesman/chansrv/chansrv.c b/sesman/chansrv/chansrv.c index d5fbd765..2603d598 100644 --- a/sesman/chansrv/chansrv.c +++ b/sesman/chansrv/chansrv.c @@ -76,6 +76,143 @@ int g_exec_pid = 0; /* this variable gets bumped up once per DVC we create */ tui32 g_dvc_chan_id = 100; +struct timeout_obj +{ + tui32 mstime; + void* data; + void (*callback)(void* data); + struct timeout_obj* next; +}; + +static struct timeout_obj* g_timeout_head = 0; +static struct timeout_obj* g_timeout_tail = 0; + +/*****************************************************************************/ +int APP_CC +add_timeout(int msoffset, void (*callback)(void* data), void* data) +{ + struct timeout_obj* tobj; + tui32 now; + + LOG(10, ("add_timeout:")); + now = g_time3(); + tobj = g_malloc(sizeof(struct timeout_obj), 1); + tobj->mstime = now + msoffset; + tobj->callback = callback; + tobj->data = data; + if (g_timeout_tail == 0) + { + g_timeout_head = tobj; + g_timeout_tail = tobj; + } + else + { + g_timeout_tail->next = tobj; + g_timeout_tail = tobj; + } + return 0; +} + +/*****************************************************************************/ +static int APP_CC +get_timeout(int* timeout) +{ + struct timeout_obj* tobj; + tui32 now; + int ltimeout; + + LOG(10, ("get_timeout:")); + ltimeout = *timeout; + if (ltimeout < 1) + { + ltimeout = 0; + } + tobj = g_timeout_head; + if (tobj != 0) + { + now = g_time3(); + while (tobj != 0) + { + LOG(10, (" now %u tobj->mstime %u", now, tobj->mstime)); + if (now < tobj->mstime) + { + ltimeout = tobj->mstime - now; + } + tobj = tobj->next; + } + } + if (ltimeout > 0) + { + LOG(10, (" ltimeout %d", ltimeout)); + if (*timeout < 1) + { + *timeout = ltimeout; + } + else + { + if (*timeout > ltimeout) + { + *timeout = ltimeout; + } + } + } + return 0; +} + +/*****************************************************************************/ +static int APP_CC +check_timeout(void) +{ + struct timeout_obj* tobj; + struct timeout_obj* last_tobj; + struct timeout_obj* temp_tobj; + int count; + tui32 now; + + LOG(10, ("check_timeout:")); + count = 0; + tobj = g_timeout_head; + if (tobj != 0) + { + last_tobj = 0; + while (tobj != 0) + { + count++; + now = g_time3(); + if (now >= tobj->mstime) + { + tobj->callback(tobj->data); + if (last_tobj == 0) + { + g_timeout_head = tobj->next; + if (g_timeout_head == 0) + { + g_timeout_tail = 0; + } + } + else + { + last_tobj->next = tobj->next; + if (g_timeout_tail == tobj) + { + g_timeout_tail = last_tobj; + } + } + temp_tobj = tobj; + tobj = tobj->next; + g_free(temp_tobj); + } + else + { + last_tobj = tobj; + tobj = tobj->next; + } + } + } + LOG(10, (" count %d", count)); + return 0; +} + /*****************************************************************************/ /* add data to chan_item, on its way to the client */ /* returns error */ @@ -940,6 +1077,7 @@ channel_thread_loop(void *in_val) while (g_obj_wait(objs, num_objs, 0, 0, timeout) == 0) { + check_timeout(); if (g_is_wait_obj_set(g_term_event)) { LOGM((LOG_LEVEL_INFO, "channel_thread_loop: g_term_event set")); @@ -1022,6 +1160,7 @@ channel_thread_loop(void *in_val) sound_get_wait_objs(objs, &num_objs, &timeout); dev_redir_get_wait_objs(objs, &num_objs, &timeout); xfuse_get_wait_objs(objs, &num_objs, &timeout); + get_timeout(&timeout); } /* end while (g_obj_wait(objs, num_objs, 0, 0, timeout) == 0) */ } diff --git a/sesman/chansrv/chansrv.h b/sesman/chansrv/chansrv.h index 1754bbb0..4eb5752a 100644 --- a/sesman/chansrv/chansrv.h +++ b/sesman/chansrv/chansrv.h @@ -57,6 +57,8 @@ struct xrdp_api_data int APP_CC send_channel_data(int chan_id, char *data, int size); int APP_CC send_rail_drawing_orders(char* data, int size); int APP_CC main_cleanup(void); +int APP_CC +add_timeout(int msoffset, void (*callback)(void* data), void* data); int APP_CC find_empty_slot_in_dvc_channels(); struct xrdp_api_data * APP_CC struct_from_dvc_chan_id(tui32 dvc_chan_id); int remove_struct_with_chan_id(tui32 dvc_chan_id); diff --git a/sesman/chansrv/rail.c b/sesman/chansrv/rail.c index a0964914..59b19411 100644 --- a/sesman/chansrv/rail.c +++ b/sesman/chansrv/rail.c @@ -61,6 +61,10 @@ static int g_rail_running = 1; /* list of valid rail windows */ static struct list* g_window_list = 0; +static int g_got_focus = 0; +static int g_focus_counter = 0; +static Window g_focus_win = 0; + /* used in valid field of struct rail_window_data */ #define RWD_X (1 << 0) #define RWD_Y (1 << 1) @@ -150,6 +154,24 @@ static int APP_CC rail_win_set_state(Window win, unsigned long state); static int APP_CC rail_show_window(Window window_id, int show_state); static int APP_CC rail_win_send_text(Window win); +/*****************************************************************************/ +static int APP_CC +rail_send_key_esc(int window_id) +{ + XEvent event; + + g_memset(&event, 0, sizeof(event)); + event.type = KeyPress; + event.xkey.same_screen = True; + event.xkey.root = g_root_window; + event.xkey.window = window_id; + event.xkey.keycode = 9; + XSendEvent(g_display, window_id, True, 0xfff, &event); + event.type = KeyRelease; + XSendEvent(g_display, window_id, True, 0xfff, &event); + return 0; +} + /*****************************************************************************/ static struct rail_window_data* APP_CC rail_get_window_data(Window window) @@ -414,87 +436,35 @@ rail_process_exec(struct stream *s, int size) return 0; } -/*****************************************************************************/ -static void APP_CC -rail_simulate_mouse_click(int button) -{ - /* - * The below code can be referenced from: - * http://www.linuxquestions.org/questions/programming-9/simulating-a-mouse-click-594576/#post2936738 - */ - XEvent event; - g_memset(&event, 0x00, sizeof(event)); - - event.type = ButtonPress; - event.xbutton.button = button; - event.xbutton.same_screen = True; - - XQueryPointer(g_display, g_root_window, &event.xbutton.root, - &event.xbutton.window, &event.xbutton.x_root, - &event.xbutton.y_root, &event.xbutton.x, - &event.xbutton.y, &event.xbutton.state); - - event.xbutton.subwindow = event.xbutton.window; - - while(event.xbutton.subwindow) - { - event.xbutton.window = event.xbutton.subwindow; - - XQueryPointer(g_display, event.xbutton.window, &event.xbutton.root, - &event.xbutton.subwindow, &event.xbutton.x_root, - &event.xbutton.y_root, &event.xbutton.x, - &event.xbutton.y, &event.xbutton.state); - } - - if(XSendEvent(g_display, PointerWindow, True, 0xfff, &event) == 0) - { - LOG(0, (" error sending mouse event")); - } - - XFlush(g_display); - - g_sleep(100); - - event.type = ButtonRelease; - event.xbutton.state = 0x100; - - if(XSendEvent(g_display, PointerWindow, True, 0xfff, &event) == 0) - { - LOG(0, (" error sending mouse event")); - } - - XFlush(g_display); -} - /******************************************************************************/ static int APP_CC -rail_win_popdown(int window_id) +rail_win_popdown(void) { int rv = 0; - unsigned int i; + int i; unsigned int nchild; Window r; Window p; Window* children; + XWindowAttributes window_attributes; /* * Check the tree of current existing X windows and dismiss - * the managed rail popups by simulating a mouse click, so + * the managed rail popups by simulating a esc key, so * that the requested window can be closed properly. */ XQueryTree(g_display, g_root_window, &r, &p, &children, &nchild); - for (i = 0; i < nchild; i++) + for (i = nchild - 1; i >= 0; i--) { - XWindowAttributes window_attributes; XGetWindowAttributes(g_display, children[i], &window_attributes); if (window_attributes.override_redirect && window_attributes.map_state == IsViewable && - list_index_of(g_window_list, children[i]) >= 0) { - LOG(0, (" dismiss pop up 0x%8.8x", children[i])); - rail_simulate_mouse_click(Button1); + list_index_of(g_window_list, children[i]) >= 0) + { + LOG(10, (" dismiss pop up 0x%8.8x", children[i])); + rail_send_key_esc(children[i]); rv = 1; - break; } } @@ -510,13 +480,7 @@ rail_close_window(int window_id) LOG(0, ("chansrv::rail_close_window:")); - if (rail_win_popdown(window_id)) - { - return 0; - } - - /* don't receive UnmapNotify for closing window */ - XSelectInput(g_display, window_id, PropertyChangeMask); + rail_win_popdown(); g_memset(&ce, 0, sizeof(ce)); ce.xclient.type = ClientMessage; @@ -531,6 +495,18 @@ rail_close_window(int window_id) return 0; } +/*****************************************************************************/ +void DEFAULT_CC +my_timoeut(void* data) +{ + LOG(10, ("my_timoeut: g_got_focus %d", g_got_focus)); + if (g_focus_counter == (int)(long)data) + { + LOG(10, ("my_timoeut: g_focus_counter %d", g_focus_counter)); + rail_win_popdown(); + } +} + /*****************************************************************************/ static int APP_CC rail_process_activate(struct stream *s, int size) @@ -543,22 +519,37 @@ rail_process_activate(struct stream *s, int size) LOG(10, ("chansrv::rail_process_activate:")); in_uint32_le(s, window_id); in_uint8(s, enabled); + g_focus_counter++; + g_got_focus = enabled; LOG(10, (" window_id 0x%8.8x enabled %d", window_id, enabled)); XGetWindowAttributes(g_display, window_id, &window_attributes); if (enabled) { - if (window_attributes.map_state != IsViewable) + if (g_focus_win == window_id) { /* In case that window is unmapped upon minimization and not yet mapped*/ XMapWindow(g_display, window_id); } - XGetTransientForHint(g_display, window_id, &transient_for); - if (transient_for > 0) + else { - // Owner window should be raised up as well - XRaiseWindow(g_display, transient_for); + rail_win_popdown(); + if (window_attributes.map_state != IsViewable) + { + /* In case that window is unmapped upon minimization and not yet mapped */ + XMapWindow(g_display, window_id); + } + XGetTransientForHint(g_display, window_id, &transient_for); + if (transient_for > 0) + { + /* Owner window should be raised up as well */ + XRaiseWindow(g_display, transient_for); + } + LOG(10, ("chansrv::rail_process_activate: calling XRaiseWindow 0x%8.8x", window_id)); + XRaiseWindow(g_display, window_id); + LOG(10, ("chansrv::rail_process_activate: calling XSetInputFocus 0x%8.8x", window_id)); + XSetInputFocus(g_display, window_id, RevertToParent, CurrentTime); } LOG(10, ("chansrv::rail_process_activate: calling XRaiseWindow 0x%8.8x", window_id)); XRaiseWindow(g_display, window_id); @@ -570,10 +561,7 @@ rail_process_activate(struct stream *s, int size) LOG(10, (" window attributes: override_redirect %d", window_attributes.override_redirect)); - if (window_attributes.override_redirect) { - LOG(10, (" dismiss popup window 0x%8.8x", window_id)); - XUnmapWindow(g_display, window_id); - } + add_timeout(200, my_timoeut, (void*)(long)g_focus_counter); } return 0; } @@ -1094,7 +1082,7 @@ rail_win_send_text(Window win) { if (g_strncmp(rwd->title, data, 63) == 0) { - LOG(0, ("chansrv::rail_win_send_text: skipping, title not changed")); + LOG(10, ("chansrv::rail_win_send_text: skipping, title not changed")); XFree(data); XFree(rwd); return 0; @@ -1665,6 +1653,10 @@ rail_xevent(void *xevent) case CreateNotify: LOG(10, (" got CreateNotify window 0x%8.8x parent 0x%8.8x", lxevent->xcreatewindow.window, lxevent->xcreatewindow.parent)); + XSelectInput(g_display, lxevent->xcreatewindow.window, + PropertyChangeMask | StructureNotifyMask | + FocusChangeMask | + EnterWindowMask | LeaveWindowMask); break; case DestroyNotify: @@ -1680,8 +1672,6 @@ rail_xevent(void *xevent) case MapRequest: LOG(10, (" got MapRequest window 0x%8.8x", lxevent->xmaprequest.window)); - XSelectInput(g_display, lxevent->xmaprequest.window, - PropertyChangeMask | StructureNotifyMask); XMapWindow(g_display, lxevent->xmaprequest.window); break; @@ -1709,23 +1699,12 @@ rail_xevent(void *xevent) if (lxevent->xunmap.window != lxevent->xunmap.event && is_window_valid_child_of_root(lxevent->xunmap.window)) { - int state = rail_win_get_state(lxevent->xunmap.window); index = list_index_of(g_window_list, lxevent->xunmap.window); LOG(10, (" window 0x%8.8x is unmapped", lxevent->xunmap.window)); if (index >= 0) { -#if 0 - XGetWindowAttributes(g_display, lxevent->xunmap.window, &wnd_attributes); - if (wnd_attributes.override_redirect) - { - LOG(10, (" hide popup")); - rail_show_window(lxevent->xunmap.window, 0x0); - rv = 0; - } -#else rail_show_window(lxevent->xunmap.window, 0x0); rv = 0; -#endif } } break; @@ -1757,6 +1736,7 @@ rail_xevent(void *xevent) case FocusIn: LOG(10, (" got FocusIn")); + g_focus_win = lxevent->xfocus.window; break; case ButtonPress: