diff --git a/sesman/chansrv/rail.c b/sesman/chansrv/rail.c index b74c3a8b..cdb77ae0 100644 --- a/sesman/chansrv/rail.c +++ b/sesman/chansrv/rail.c @@ -324,6 +324,94 @@ 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); + + usleep(100000); + + 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) +{ + int rv = 0; + unsigned int i; + unsigned int nchild; + Window r; + Window p; + Window* children; + + /* + * Check the tree of current existing X windows and dismiss + * the managed rail popups by simulating a mouse click, 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++) + { + 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); + rv = 1; + break; + } + } + + XFree(children); + return rv; +} + /******************************************************************************/ static int APP_CC rail_close_window(int window_id) @@ -332,6 +420,11 @@ 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); @@ -344,6 +437,7 @@ rail_close_window(int window_id) ce.xclient.data.l[0] = g_wm_delete_window_atom; ce.xclient.data.l[1] = CurrentTime; XSendEvent(g_display, window_id, False, NoEventMask, &ce); + return 0; } @@ -353,14 +447,22 @@ rail_process_activate(struct stream *s, int size) { int window_id; int enabled; + XWindowAttributes window_attributes; LOG(10, ("chansrv::rail_process_activate:")); in_uint32_le(s, window_id); in_uint8(s, 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) + { + /* In case that window is unmapped upon minimization and not yet mapped*/ + XMapWindow(g_display, window_id); + } 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)); @@ -374,8 +476,6 @@ rail_process_activate(struct stream *s, int size) if (window_attributes.override_redirect) { LOG(10, (" dismiss popup window 0x%8.8x", window_id)); XUnmapWindow(g_display, window_id); - //rail_win_set_state(window_id, 0x3); - //rail_show_window(window_id, 0x0); } } return 0; @@ -574,12 +674,19 @@ rail_minmax_window(int window_id, int max) static int APP_CC rail_restore_window(int window_id) { + XWindowAttributes window_attributes; + LOG(10, ("chansrv::rail_restore_window 0x%8.8x:", window_id)); - XMapWindow(g_display, window_id); + XGetWindowAttributes(g_display, window_id, &window_attributes); + if (window_attributes.map_state != IsViewable) + { + XMapWindow(g_display, window_id); + } 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); + return 0; } @@ -939,7 +1046,8 @@ rail_create_window(Window window_id, Window parent_id) int i = 0; int flags; - int state; + int index; + Window transient_for = 0; struct stream* s; LOG(10, ("chansrv::rail_create_window 0x%8.8x", window_id)); @@ -951,8 +1059,8 @@ rail_create_window(Window window_id, Window parent_id) LOG(10, (" x %d y %d width %d height %d border_width %d", x, y, width, height, border)); - state = rail_win_get_state(window_id); - if ((state == 0) || (state == -1)) + index = list_index_of(g_window_list, window_id); + if (index == -1) { LOG(10, (" create new window")); flags = WINDOW_ORDER_TYPE_WINDOW | WINDOW_ORDER_STATE_NEW; @@ -966,11 +1074,19 @@ rail_create_window(Window window_id, Window parent_id) title_size = rail_win_get_text(window_id, &title_bytes); + XGetTransientForHint(g_display, window_id, &transient_for); + if (attributes.override_redirect) { style = RAIL_STYLE_TOOLTIP; ext_style = RAIL_EXT_STYLE_TOOLTIP; } + else if (transient_for > 0) + { + style = RAIL_STYLE_DIALOG; + ext_style = RAIL_EXT_STYLE_DIALOG; + parent_id = transient_for; + } else { style = RAIL_STYLE_NORMAL; @@ -1049,6 +1165,94 @@ rail_create_window(Window window_id, Window parent_id) return 0; } +/*****************************************************************************/ +/* returns 0, event handled, 1 unhandled */ +int APP_CC +rail_configure_window(XConfigureEvent *config) +{ + int x; + int y; + tui32 width; + tui32 height; + int num_window_rects = 1; + int num_visibility_rects = 1; + int i = 0; + int flags; + int index; + int window_id; + + struct stream* s; + + window_id = config->window; + + LOG(10, ("chansrv::rail_configure_window 0x%8.8x", window_id)); + + + LOG(10, (" x %d y %d width %d height %d border_width %d", config->x, + config->y, config->width, config->height, config->border_width)); + + index = list_index_of(g_window_list, window_id); + if (index == -1) + { + /* window isn't mapped yet */ + return; + } + + flags = WINDOW_ORDER_TYPE_WINDOW; + + make_stream(s); + init_stream(s, 1024); + + out_uint32_le(s, 10); /* configure_window */ + out_uint32_le(s, window_id); /* window_id */ + + out_uint32_le(s, 0); /* client_offset_x */ + out_uint32_le(s, 0); /* client_offset_y */ + flags |= WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET; + out_uint32_le(s, config->width); /* client_area_width */ + out_uint32_le(s, config->height); /* client_area_height */ + flags |= WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE; + out_uint32_le(s, 0); /* rp_content */ + out_uint32_le(s, g_root_window); /* root_parent_handle */ + flags |= WINDOW_ORDER_FIELD_ROOT_PARENT; + out_uint32_le(s, config->x); /* window_offset_x */ + out_uint32_le(s, config->y); /* window_offset_y */ + flags |= WINDOW_ORDER_FIELD_WND_OFFSET; + out_uint32_le(s, 0); /* window_client_delta_x */ + out_uint32_le(s, 0); /* window_client_delta_y */ + flags |= WINDOW_ORDER_FIELD_WND_CLIENT_DELTA; + out_uint32_le(s, config->width); /* window_width */ + out_uint32_le(s, config->height); /* window_height */ + flags |= WINDOW_ORDER_FIELD_WND_SIZE; + out_uint16_le(s, num_window_rects); /* num_window_rects */ + for (i = 0; i < num_window_rects; i++) + { + out_uint16_le(s, 0); /* left */ + out_uint16_le(s, 0); /* top */ + out_uint16_le(s, config->width); /* right */ + out_uint16_le(s, config->height); /* bottom */ + } + flags |= WINDOW_ORDER_FIELD_WND_RECTS; + out_uint32_le(s, config->x); /* visible_offset_x */ + out_uint32_le(s, config->y); /* visible_offset_y */ + flags |= WINDOW_ORDER_FIELD_VIS_OFFSET; + out_uint16_le(s, num_visibility_rects); /* num_visibility_rects */ + for (i = 0; i < num_visibility_rects; i++) + { + out_uint16_le(s, 0); /* left */ + out_uint16_le(s, 0); /* top */ + out_uint16_le(s, config->width); /* right */ + out_uint16_le(s, config->height); /* bottom */ + } + flags |= WINDOW_ORDER_FIELD_VISIBILITY; + out_uint32_le(s, flags); /*flags*/ + + s_mark_end(s); + send_rail_drawing_orders(s->data, (int)(s->end - s->data)); + free_stream(s); + return 0; +} + /*****************************************************************************/ /* returns 0, event handled, 1 unhandled */ int APP_CC @@ -1109,11 +1313,6 @@ rail_xevent(void *xevent) case CreateNotify: LOG(10, (" got CreateNotify 0x%8.8x", lxevent->xcreatewindow.window)); - XSelectInput(g_display, lxevent->xcreatewindow.window, - PropertyChangeMask | StructureNotifyMask); - rail_win_set_state(lxevent->xcreatewindow.window, 0x0); /* WithdrawnState */ - list_add_item(g_window_list, lxevent->xcreatewindow.window); - rv = 0; break; case DestroyNotify: @@ -1129,8 +1328,9 @@ rail_xevent(void *xevent) case MapRequest: LOG(10, (" got MapRequest 0x%8.8x", lxevent->xmaprequest.window)); + XSelectInput(g_display, lxevent->xmaprequest.window, + PropertyChangeMask | StructureNotifyMask); XMapWindow(g_display, lxevent->xmaprequest.window); - rv = 0; break; case MapNotify: @@ -1141,9 +1341,9 @@ rail_xevent(void *xevent) if (wnd_attributes.map_state == IsViewable) { rail_create_window(lxevent->xmap.window, lxevent->xmap.event); - rail_win_set_state(lxevent->xmap.window, 0x1); /* NormalState */ if (!wnd_attributes.override_redirect) { + rail_win_set_state(lxevent->xmap.window, 0x1); /* NormalState */ rail_win_send_text(lxevent->xmap.window); } rv = 0; @@ -1153,19 +1353,19 @@ rail_xevent(void *xevent) case UnmapNotify: LOG(10, (" got UnmapNotify 0x%8.8x", lxevent->xunmap.event)); - if (lxevent->xunmap.window == lxevent->xunmap.event && + 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 (state != -1 && state != 0x3) + if (index >= 0) { - LOG(10, (" trying to dismiss popup")); XGetWindowAttributes(g_display, lxevent->xunmap.window, &wnd_attributes); if (wnd_attributes.override_redirect) { + LOG(10, (" hide popup")); rail_show_window(lxevent->xunmap.window, 0x0); - rail_win_set_state(lxevent->xunmap.window, 0x3); rv = 0; } } @@ -1173,7 +1373,16 @@ rail_xevent(void *xevent) break; case ConfigureNotify: - LOG(10, (" got ConfigureNotify")); + LOG(10, (" got ConfigureNotify 0x%8.8x event 0x%8.8x", lxevent->xconfigure.window, + lxevent->xconfigure.event)); +#if 0 + if (lxevent->xconfigure.window != lxevent->xconfigure.event && + !lxevent->xconfigure.override_redirect) + { + rail_configure_window(&lxevent->xconfigure); + rv = 0; + } +#endif break; case FocusIn: diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 88c24611..67c53a28 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -755,6 +755,73 @@ xrdp_mm_process_rail_create_window(struct xrdp_mm* self, struct stream* s) return rv; } +/*****************************************************************************/ +/* returns error + process rail configure window order */ +static int APP_CC +xrdp_mm_process_rail_configure_window(struct xrdp_mm* self, struct stream* s) +{ + int flags; + int window_id; + int index; + int bytes; + int rv; + struct rail_window_state_order rwso; + + g_memset(&rwso, 0, sizeof(rwso)); + in_uint32_le(s, window_id); + + g_writeln("xrdp_mm_process_rail_configure_window: 0x%8.8x", window_id); + + in_uint32_le(s, rwso.client_offset_x); + in_uint32_le(s, rwso.client_offset_y); + in_uint32_le(s, rwso.client_area_width); + in_uint32_le(s, rwso.client_area_height); + in_uint32_le(s, rwso.rp_content); + in_uint32_le(s, rwso.root_parent_handle); + in_uint32_le(s, rwso.window_offset_x); + in_uint32_le(s, rwso.window_offset_y); + in_uint32_le(s, rwso.window_client_delta_x); + in_uint32_le(s, rwso.window_client_delta_y); + in_uint32_le(s, rwso.window_width); + in_uint32_le(s, rwso.window_height); + in_uint16_le(s, rwso.num_window_rects); + if (rwso.num_window_rects > 0) + { + bytes = sizeof(struct rail_window_rect) * rwso.num_window_rects; + rwso.window_rects = (struct rail_window_rect*)g_malloc(bytes, 0); + for (index = 0; index < rwso.num_window_rects; index++) + { + in_uint16_le(s, rwso.window_rects[index].left); + in_uint16_le(s, rwso.window_rects[index].top); + in_uint16_le(s, rwso.window_rects[index].right); + in_uint16_le(s, rwso.window_rects[index].bottom); + } + } + in_uint32_le(s, rwso.visible_offset_x); + in_uint32_le(s, rwso.visible_offset_y); + in_uint16_le(s, rwso.num_visibility_rects); + if (rwso.num_visibility_rects > 0) + { + bytes = sizeof(struct rail_window_rect) * rwso.num_visibility_rects; + rwso.visibility_rects = (struct rail_window_rect*)g_malloc(bytes, 0); + for (index = 0; index < rwso.num_visibility_rects; index++) + { + in_uint16_le(s, rwso.visibility_rects[index].left); + in_uint16_le(s, rwso.visibility_rects[index].top); + in_uint16_le(s, rwso.visibility_rects[index].right); + in_uint16_le(s, rwso.visibility_rects[index].bottom); + } + } + in_uint32_le(s, flags); + rv = libxrdp_orders_init(self->wm->session); + rv = libxrdp_window_new_update(self->wm->session, window_id, &rwso, flags); + rv = libxrdp_orders_send(self->wm->session); + g_free(rwso.window_rects); + g_free(rwso.visibility_rects); + return rv; +} + /*****************************************************************************/ /* returns error process rail destroy window order */