diff --git a/sesman/chansrv/chansrv.c b/sesman/chansrv/chansrv.c index 388d0273..db26958a 100644 --- a/sesman/chansrv/chansrv.c +++ b/sesman/chansrv/chansrv.c @@ -228,6 +228,31 @@ send_channel_data(int chan_id, char *data, int size) return 1; } +/*****************************************************************************/ +/* returns error */ +int APP_CC +send_rail_drawing_orders(char* data, int size) +{ + LOGM((LOG_LEVEL_DEBUG, "chansrv::send_rail_drawing_orders: size %d", size)); + + struct stream* s; + int error; + + s = trans_get_out_s(g_con_trans, 8192); + out_uint32_le(s, 0); /* version */ + out_uint32_le(s, 8 + 8 + size); /* size */ + out_uint32_le(s, 10); /* msg id */ + out_uint32_le(s, 8 + size); /* size */ + out_uint8a(s, data, size); + s_mark_end(s); + error = trans_force_write(g_con_trans); + if (error != 0) + { + return 1; + } + return 0; +} + /*****************************************************************************/ /* returns error */ static int APP_CC @@ -501,6 +526,19 @@ process_message_channel_data(struct stream *s) return rv; } +/*****************************************************************************/ +/* returns error */ +static int APP_CC +process_message_channel_rail_title_request(struct stream* s) +{ + int window_id; + LOG(10, ("process_message_channel_rail_title_request:")); + + in_uint32_le(s, window_id); + rail_request_title(window_id); + return 0; +} + /*****************************************************************************/ /* returns error */ static int APP_CC @@ -558,6 +596,9 @@ process_message(void) case 7: /* channel data response */ rv = process_message_channel_data_response(s); break; + case 9: + rv = process_message_channel_rail_title_request(s); + break; default: LOGM((LOG_LEVEL_ERROR, "process_message: error in process_message ", "unknown msg %d", id)); diff --git a/sesman/chansrv/chansrv.h b/sesman/chansrv/chansrv.h index bca30ca4..1754bbb0 100644 --- a/sesman/chansrv/chansrv.h +++ b/sesman/chansrv/chansrv.h @@ -55,6 +55,7 @@ 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 find_empty_slot_in_dvc_channels(); struct xrdp_api_data * APP_CC struct_from_dvc_chan_id(tui32 dvc_chan_id); diff --git a/sesman/chansrv/rail.c b/sesman/chansrv/rail.c index cfa3c5de..a84c68b6 100644 --- a/sesman/chansrv/rail.c +++ b/sesman/chansrv/rail.c @@ -41,6 +41,8 @@ extern Screen *g_screen; /* in xcommon.c */ extern Window g_root_window; /* in xcommon.c */ extern Atom g_wm_delete_window_atom; /* in xcommon.c */ extern Atom g_wm_protocols_atom; /* in xcommon.c */ +extern Atom g_utf8_string; /* in xcommon.c */ +extern Atom g_net_wm_name; /* in xcommon.c */ int g_rail_up = 0; @@ -270,6 +272,25 @@ rail_process_exec(struct stream *s, int size) return 0; } +/******************************************************************************/ +static int APP_CC +rail_close_window(int window_id) +{ + XEvent ce; + + LOG(0, ("chansrv::rail_close_window:")); + g_memset(&ce, 0, sizeof(ce)); + ce.xclient.type = ClientMessage; + ce.xclient.message_type = g_wm_protocols_atom; + ce.xclient.display = g_display; + ce.xclient.window = window_id; + ce.xclient.format = 32; + 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; +} + /*****************************************************************************/ static int APP_CC rail_process_activate(struct stream *s, int size) @@ -288,8 +309,15 @@ rail_process_activate(struct stream *s, int size) 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); - } + } else { + XWindowAttributes window_attributes; + XGetWindowAttributes(g_display, window_id, &window_attributes); + if (window_attributes.override_redirect) { + LOG(10, (" dismiss popup window 0x%8.8x", window_id)); + rail_close_window(window_id); + } + } return 0; } @@ -307,21 +335,25 @@ rail_process_system_param(struct stream *s, int size) /******************************************************************************/ static int APP_CC -rail_close_window(int window_id) +rail_minmax_window(int window_id, int max) { - XEvent ce; + LOG(10, ("chansrv::rail_minmax_window 0x%8.8x:", window_id)); + if (max) + { + + } else { + XUnmapWindow(g_display, window_id); + LOG(10, (" XUnmapWindow")); + } +} - LOG(0, ("chansrv::rail_close_window:")); - g_memset(&ce, 0, sizeof(ce)); - ce.xclient.type = ClientMessage; - ce.xclient.message_type = g_wm_protocols_atom; - ce.xclient.display = g_display; - ce.xclient.window = window_id; - ce.xclient.format = 32; - 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; +/*****************************************************************************/ +static int APP_CC +rail_restore_window(int window_id) +{ + LOG(10, ("chansrv::rail_restore_window 0x%8.8x:", window_id)); + LOG(10, (" XMapWindow")); + XMapWindow(g_display, window_id); } /*****************************************************************************/ @@ -345,6 +377,7 @@ rail_process_system_command(struct stream *s, int size) break; case SC_MINIMIZE: LOG(10, (" window_id 0x%8.8x SC_MINIMIZE", window_id)); + rail_minmax_window(window_id, 0); break; case SC_MAXIMIZE: LOG(10, (" window_id 0x%8.8x SC_MAXIMIZE", window_id)); @@ -358,6 +391,7 @@ rail_process_system_command(struct stream *s, int size) break; case SC_RESTORE: LOG(10, (" window_id 0x%8.8x SC_RESTORE", window_id)); + rail_restore_window(window_id); break; case SC_DEFAULT: LOG(10, (" window_id 0x%8.8x SC_DEFAULT", window_id)); @@ -588,6 +622,89 @@ rail_data_in(struct stream *s, int chan_id, int chan_flags, int length, return 0; } +/*****************************************************************************/ +int APP_CC +rail_get_property(Display *display, Window target, Atom type, Atom property, + unsigned char** data, unsigned long* count) { + Atom atom_return; + int size; + unsigned long nitems, bytes_left; + + int ret = XGetWindowProperty(display, target, property, + 0l, 1l, False, + type, &atom_return, &size, + &nitems, &bytes_left, data); + if (ret != Success || nitems < 1) + { + return 0; + } + + if (bytes_left != 0) + { + XFree(*data); + unsigned long remain = ((size / 8) * nitems) + bytes_left; + ret = XGetWindowProperty(g_display, target, + property, 0l, remain, False, + type, &atom_return, &size, + &nitems, &bytes_left, data); + if (ret != Success) + { + return 1; + } + } + + *count = nitems; + return 0; +} + +/*****************************************************************************/ +const int APP_CC +rail_send_win_text(Display *disp, Window win) { + unsigned char *data = 0; + unsigned long nitems = 0; + struct stream* s; + + rail_get_property(disp, win, g_utf8_string, g_net_wm_name, + &data, &nitems); + if (nitems == 0) + { + /* _NET_WM_NAME isn't set, use WM_NAME (XFetchName) instead */ + XFetchName(disp, win, (char **)&data); + } + + if (data) + { + int i = 0; + for (;;i++) + { + if (data[i] == '\0') + { + break; + } + } + LOG(10, ("rail_send_win_text: 0x%8.8x text 0x%x size %d", win, data, i)); + make_stream(s); + init_stream(s, 1024); + + out_uint32_le(s, 2); /* update title info */ + out_uint32_le(s, win); /* window id */ + out_uint32_le(s, i); /* title size */ + out_uint8a(s, data, i); /* title */ + s_mark_end(s); + send_rail_drawing_orders(s->data, (int)(s->end - s->data)); + free_stream(s); + XFree(data); + } + return 0; +} + +/*****************************************************************************/ +int APP_CC +rail_request_title(int window_id) +{ + return rail_send_win_text(g_display, (Window)window_id); +} + /*****************************************************************************/ /* returns 0, event handled, 1 unhandled */ int APP_CC @@ -596,6 +713,14 @@ rail_xevent(void *xevent) XEvent *lxevent; XWindowChanges xwc; int rv; + int nchildren_return = 0; + Window root_return; + Window parent_return; + Window *children_return; + Window wreturn; + int revert_to; + XWindowAttributes wnd_attributes; + char* prop_name; LOG(10, ("chansrv::rail_xevent:")); @@ -609,6 +734,17 @@ rail_xevent(void *xevent) switch (lxevent->type) { + case PropertyNotify: + prop_name = XGetAtomName(g_display, lxevent->xproperty.atom); + LOG(10, (" got PropertyNotify window_id 0x%8.8x %s", + lxevent->xproperty.window, prop_name)); + if (strcmp(prop_name, "WM_NAME") == 0 || + strcmp(prop_name, "_NEW_WM_NAME") == 0) + { + rail_send_win_text(g_display, lxevent->xproperty.window); + rv = 0; + } + break; case ConfigureRequest: LOG(10, (" got ConfigureRequest window_id 0x%8.8x", lxevent->xconfigurerequest.window)); g_memset(&xwc, 0, sizeof(xwc)); @@ -626,6 +762,13 @@ rail_xevent(void *xevent) rv = 0; break; + case CreateNotify: + LOG(10, (" got CreateNotify")); + XSelectInput(g_display, lxevent->xcreatewindow.window, + PropertyChangeMask | StructureNotifyMask); + v = 0; + break; + case MapRequest: LOG(10, (" got MapRequest")); XMapWindow(g_display, lxevent->xmaprequest.window); diff --git a/sesman/chansrv/rail.h b/sesman/chansrv/rail.h index 7dbcbc5a..50bbfd36 100644 --- a/sesman/chansrv/rail.h +++ b/sesman/chansrv/rail.h @@ -31,5 +31,6 @@ rail_data_in(struct stream* s, int chan_id, int chan_flags, int length, int total_length); int APP_CC rail_xevent(void* xevent); +int APP_CC rail_request_title(int window_id); #endif diff --git a/sesman/chansrv/xcommon.c b/sesman/chansrv/xcommon.c index c5a91cae..8fd8e741 100644 --- a/sesman/chansrv/xcommon.c +++ b/sesman/chansrv/xcommon.c @@ -40,6 +40,8 @@ int g_screen_num = 0; Window g_root_window = 0; Atom g_wm_delete_window_atom = 0; Atom g_wm_protocols_atom = 0; +Atom g_utf8_string = 0; +Atom g_net_wm_name = 0; /*****************************************************************************/ static int DEFAULT_CC @@ -117,6 +119,8 @@ xcommon_init(void) g_wm_delete_window_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", 0); g_wm_protocols_atom = XInternAtom(g_display, "WM_PROTOCOLS", 0); + g_utf8_string = XInternAtom(g_display, "UTF8_STRIING", 0); + g_net_wm_name = XInternAtom(g_display, "_NET_WM_NAME", 0); return 0; } diff --git a/xorg/X11R7.6/rdp/rdpdraw.c b/xorg/X11R7.6/rdp/rdpdraw.c index 4b900f4e..45148d6d 100644 --- a/xorg/X11R7.6/rdp/rdpdraw.c +++ b/xorg/X11R7.6/rdp/rdpdraw.c @@ -852,6 +852,8 @@ rdpDestroyWindow(WindowPtr pWindow) if (g_use_rail) { + LLOGLN(10, (" rdpup_delete_window")); + rdpup_delete_window(pWindow, priv); } return rv; @@ -942,7 +944,16 @@ rdpUnrealizeWindow(WindowPtr pWindow) { LLOGLN(10, ("rdpUnrealizeWindow:")); priv->status = 0; - rdpup_delete_window(pWindow, priv); + if (pWindow->overrideRedirect) { + /* + * Popups are unmapped by X server, so probably + * they will be mapped again. Thereby we should + * just hide those popups instead of destroying + * them. + */ + LLOGLN(10, (" rdpup_show_window")); + rdpup_show_window(pWindow, priv, 0x0); /* 0x0 - do not show the window */ + } } } diff --git a/xorg/X11R7.6/rdp/rdpup.c b/xorg/X11R7.6/rdp/rdpup.c index 06c8bd73..dc59e26d 100644 --- a/xorg/X11R7.6/rdp/rdpup.c +++ b/xorg/X11R7.6/rdp/rdpup.c @@ -1772,7 +1772,7 @@ rdpup_create_window(WindowPtr pWindow, rdpWindowRec *priv) out_uint32_le(g_out_s, style); /* style */ out_uint32_le(g_out_s, ext_style); /* extended_style */ flags |= WINDOW_ORDER_FIELD_STYLE; - out_uint32_le(g_out_s, 0); /* show_state */ + out_uint32_le(g_out_s, 0x05); /* show_state */ flags |= WINDOW_ORDER_FIELD_SHOW; out_uint16_le(g_out_s, title_bytes); /* title_info */ out_uint8a(g_out_s, title, title_bytes); @@ -1842,6 +1842,27 @@ rdpup_delete_window(WindowPtr pWindow, rdpWindowRec *priv) } } +/******************************************************************************/ +void +rdpup_show_window(WindowPtr pWindow, rdpWindowRec* priv, int showState) +{ + LLOGLN(10, ("rdpup_show_window: id 0x%8.8x state 0x%x", pWindow->drawable.id, + showState)); + if (g_connected) + { + int flags = WINDOW_ORDER_TYPE_WINDOW; + + rdpup_pre_check(16); + out_uint16_le(g_out_s, 27); + out_uint16_le(g_out_s, 16); + g_count++; + out_uint32_le(g_out_s, pWindow->drawable.id); + flags |= WINDOW_ORDER_FIELD_SHOW; + out_uint32_le(g_out_s, flags); + out_uint32_le(g_out_s, showState); + } +} + /******************************************************************************/ int rdpup_check_dirty(PixmapPtr pDirtyPixmap, rdpPixmapRec *pDirtyPriv) diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 0a79810b..aeac2868 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -675,6 +675,79 @@ xrdp_mm_trans_process_channel_data(struct xrdp_mm *self, struct trans *trans) return rv; } +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_mm_trans_send_channel_rail_title_request(struct xrdp_mm* self, + int window_id) +{ + struct stream* s; + + s = trans_get_out_s(self->chan_trans, 8192); + g_writeln("xrdp_mm_trans_send_channel_rail_title_request: 0x%8.8x", + window_id); + + if (s == 0) + { + return 1; + } + out_uint32_le(s, 0); /* version */ + out_uint32_le(s, 8 + 8 + 4); /* size */ + out_uint32_le(s, 9); /* msg id */ + out_uint32_le(s, 8 + 4); /* size */ + out_uint32_le(s, window_id); + s_mark_end(s); + return trans_force_write(self->chan_trans); +} + +/*****************************************************************************/ +/* returns error + process alternate secondary drawing orders for rail channel */ +static int APP_CC +xrdp_mm_process_rail_drawing_orders(struct xrdp_mm* self, struct trans* trans) +{ + struct stream* s; + int size; + int order_type; + int window_id; + int flags; + int rv = 0; + struct rail_window_state_order rwso; + + g_writeln("xrdp_mm_process_rail_drawing_orders:"); + + s = trans_get_in_s(trans); + if (s == 0) + { + return 1; + } + in_uint32_le(s, order_type); + + switch(order_type) + { + case 2: /* update title info */ + in_uint32_le(s, window_id); + g_writeln(" update window title info: 0x%8.8x", window_id); + + g_memset(&rwso, 0, sizeof(rwso)); + in_uint32_le(s, size); /* title size */ + rwso.title_info = g_malloc(size + 1, 0); + in_uint8a(s, rwso.title_info, size); + rwso.title_info[size] = 0; + flags = WINDOW_ORDER_FIELD_TITLE; + 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_writeln(" set window title %s %d", rwso.title_info, rv); + g_free(rwso.title_info); + break; + default: + break; + } + + return 0; +} + /*****************************************************************************/ /* returns error process a message for the channel handler */ @@ -708,6 +781,9 @@ xrdp_mm_chan_process_msg(struct xrdp_mm *self, struct trans *trans, case 8: /* channel data */ rv = xrdp_mm_trans_process_channel_data(self, trans); break; + case 10: /* rail alternate secondary drawing orders */ + rv = xrdp_mm_process_rail_drawing_orders(self, trans); + break; default: log_message(LOG_LEVEL_ERROR,"xrdp_mm_chan_process_msg: unknown id %d", id); break; @@ -2551,6 +2627,12 @@ server_window_new_update(struct xrdp_mod *mod, int window_id, struct xrdp_wm *wm; wm = (struct xrdp_wm *)(mod->wm); + if ((flags & WINDOW_ORDER_STATE_NEW) && + !(window_state->style & 0x80000000)) + { + /* requesting title info / icon info */ + xrdp_mm_trans_send_channel_rail_title_request(wm->mm, window_id); + } return libxrdp_window_new_update(wm->session, window_id, window_state, flags); } diff --git a/xup/xup.c b/xup/xup.c index 5320a3c9..9fdfef71 100644 --- a/xup/xup.c +++ b/xup/xup.c @@ -473,6 +473,25 @@ process_server_window_new_update(struct mod *mod, struct stream *s) return rv; } +/******************************************************************************/ +/* return error */ +static int APP_CC +process_server_window_show(struct mod* mod, struct stream* s) +{ + int window_id; + int rv; + int flags; + struct rail_window_state_order rwso; + + g_memset(&rwso, 0, sizeof(rwso)); + in_uint32_le(s, window_id); + in_uint32_le(s, flags); + in_uint32_le(s, rwso.show_state); + mod->server_window_new_update(mod, window_id, &rwso, flags); + rv = 0; + return rv; +} + /******************************************************************************/ /* return error */ static int APP_CC @@ -658,6 +677,9 @@ lib_mod_process_orders(struct mod *mod, int type, struct stream *s) case 26: /* server_window_delete */ rv = process_server_window_delete(mod, s); break; + case 27: /* server_window_new_update - show */ + rv = process_server_window_show(mod, s); + break; case 51: /* server_set_pointer_ex */ rv = process_server_set_pointer_ex(mod, s); break;