FreeRDP/client/X11/xf_rail.c

599 lines
16 KiB
C
Raw Normal View History

/**
* FreeRDP: A Remote Desktop Protocol Client
* X11 RAIL
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <freerdp/utils/event.h>
#include <freerdp/utils/hexdump.h>
#include <freerdp/utils/rail.h>
#include <freerdp/rail/rail.h>
#include "xf_window.h"
#include "xf_rail.h"
xfreerdp: a quick workaround for some issues with TS Remote App. Currently in Remote App mode we have no option to interact with the remote desktop host before the first RAIL window is created. In many situations this interaction possibility is absolutely required. One example is that screen which gets displayed if another user is logged on. It requires clicking a button in pre-RAIL mode so that the currently logged on user gets notified to confirm or deny the connection. Another example is the option to log on graphically (e.g. for hosts that don't support NLA) without predefined credentials. Also if the administrator sets the "User must change password at next logon" option there is currently no way to do this in TS Remote App mode. This change basically lets xfreerdp create the main window in Remote App mode like in a normal session and xfi->remote_app is not set to true initially. As soon as the rail exec result event or the first rail window creation request is received (whatever comes first) the main window gets destroyed and xfi->remote_app is set to true. The second change is to disconnect immediately if the rail exec result event reports an error, e.g. if the specified app cannot be found or if it is not in the list of allowed applications. This fixes FreeRDP github issue #143 and issue #308. I'm aware that this is not the most elegant solution but it is definitely an improvement and probably good enough for 1.0. A nicer solution would be hiding the main window and only displaying it if no rail exec result or rail window creation event is received after a certain timeout ...
2012-01-02 13:27:04 +04:00
void xf_rail_enable_remoteapp_mode(xfInfo* xfi)
{
if (xfi->remote_app == false)
{
xfi->remote_app = true;
xfi->drawable = DefaultRootWindow(xfi->display);
xf_DestroyWindow(xfi, xfi->window);
xfi->window = NULL;
}
}
void xf_rail_paint(xfInfo* xfi, rdpRail* rail, sint32 uleft, sint32 utop, uint32 uright, uint32 ubottom)
{
xfWindow* xfw;
2012-05-18 01:34:52 +04:00
rdpWindow* window;
boolean intersect;
uint32 iwidth, iheight;
sint32 ileft, itop;
uint32 iright, ibottom;
sint32 wleft, wtop;
uint32 wright, wbottom;
window_list_rewind(rail->list);
while (window_list_has_next(rail->list))
{
window = window_list_get_next(rail->list);
xfw = (xfWindow*) window->extra;
// RDP can have zero width or height windows. X cannot, so we ignore these.
if (window->windowWidth == 0 || window->windowHeight == 0)
{
continue;
}
wleft = window->windowOffsetX;
wtop = window->windowOffsetY;
wright = window->windowOffsetX + window->windowWidth - 1;
wbottom = window->windowOffsetY + window->windowHeight - 1;
ileft = MAX(uleft, wleft);
itop = MAX(utop, wtop);
iright = MIN(uright, wright);
ibottom = MIN(ubottom, wbottom);
iwidth = iright - ileft + 1;
iheight = ibottom - itop + 1;
intersect = ((iright > ileft) && (ibottom > itop)) ? true : false;
if (intersect)
{
2012-05-18 01:34:52 +04:00
xf_UpdateWindowArea(xfi, xfw, ileft - wleft, itop - wtop, iwidth, iheight);
}
}
}
static void xf_rail_CreateWindow(rdpRail* rail, rdpWindow* window)
{
xfInfo* xfi;
xfWindow* xfw;
xfi = (xfInfo*) rail->extra;
xfreerdp: a quick workaround for some issues with TS Remote App. Currently in Remote App mode we have no option to interact with the remote desktop host before the first RAIL window is created. In many situations this interaction possibility is absolutely required. One example is that screen which gets displayed if another user is logged on. It requires clicking a button in pre-RAIL mode so that the currently logged on user gets notified to confirm or deny the connection. Another example is the option to log on graphically (e.g. for hosts that don't support NLA) without predefined credentials. Also if the administrator sets the "User must change password at next logon" option there is currently no way to do this in TS Remote App mode. This change basically lets xfreerdp create the main window in Remote App mode like in a normal session and xfi->remote_app is not set to true initially. As soon as the rail exec result event or the first rail window creation request is received (whatever comes first) the main window gets destroyed and xfi->remote_app is set to true. The second change is to disconnect immediately if the rail exec result event reports an error, e.g. if the specified app cannot be found or if it is not in the list of allowed applications. This fixes FreeRDP github issue #143 and issue #308. I'm aware that this is not the most elegant solution but it is definitely an improvement and probably good enough for 1.0. A nicer solution would be hiding the main window and only displaying it if no rail exec result or rail window creation event is received after a certain timeout ...
2012-01-02 13:27:04 +04:00
xf_rail_enable_remoteapp_mode(xfi);
xfw = xf_CreateWindow((xfInfo*) rail->extra, window,
window->windowOffsetX, window->windowOffsetY,
2011-08-22 07:54:02 +04:00
window->windowWidth, window->windowHeight,
window->windowId);
xf_SetWindowStyle(xfi, xfw, window->style, window->extendedStyle);
xf_SetWindowText(xfi, xfw, window->title);
window->extra = (void*) xfw;
window->extraId = (void*) xfw->handle;
}
static void xf_rail_MoveWindow(rdpRail* rail, rdpWindow* window)
{
xfInfo* xfi;
xfWindow* xfw;
xfi = (xfInfo*) rail->extra;
xfw = (xfWindow*) window->extra;
xf_MoveWindow(xfi, xfw,
window->windowOffsetX, window->windowOffsetY,
window->windowWidth, window->windowHeight);
}
static void xf_rail_ShowWindow(rdpRail* rail, rdpWindow* window, uint8 state)
{
xfInfo* xfi;
xfWindow* xfw;
xfi = (xfInfo*) rail->extra;
xfw = (xfWindow*) window->extra;
xf_ShowWindow(xfi, xfw, state);
}
static void xf_rail_SetWindowText(rdpRail* rail, rdpWindow* window)
{
xfInfo* xfi;
xfWindow* xfw;
xfi = (xfInfo*) rail->extra;
xfw = (xfWindow*) window->extra;
xf_SetWindowText(xfi, xfw, window->title);
}
static void xf_rail_SetWindowIcon(rdpRail* rail, rdpWindow* window, rdpIcon* icon)
{
xfInfo* xfi;
xfWindow* xfw;
xfi = (xfInfo*) rail->extra;
xfw = (xfWindow*) window->extra;
icon->extra = freerdp_icon_convert(icon->entry->bitsColor, NULL, icon->entry->bitsMask,
2011-08-22 06:30:49 +04:00
icon->entry->width, icon->entry->height, icon->entry->bpp, rail->clrconv);
xf_SetWindowIcon(xfi, xfw, icon);
}
static void xf_rail_SetWindowRects(rdpRail* rail, rdpWindow* window)
{
xfInfo* xfi;
xfWindow* xfw;
xfi = (xfInfo*) rail->extra;
xfw = (xfWindow*) window->extra;
2011-08-25 22:11:45 +04:00
xf_SetWindowRects(xfi, xfw, window->windowRects, window->numWindowRects);
}
static void xf_rail_SetWindowVisibilityRects(rdpRail* rail, rdpWindow* window)
{
xfInfo* xfi;
xfWindow* xfw;
xfi = (xfInfo*) rail->extra;
xfw = (xfWindow*) window->extra;
xf_SetWindowVisibilityRects(xfi, xfw, window->windowRects, window->numWindowRects);
}
static void xf_rail_DestroyWindow(rdpRail* rail, rdpWindow* window)
2011-08-18 06:31:27 +04:00
{
xfWindow* xfw;
xfw = (xfWindow*) window->extra;
xf_DestroyWindow((xfInfo*) rail->extra, xfw);
}
void xf_rail_register_callbacks(xfInfo* xfi, rdpRail* rail)
{
rail->extra = (void*) xfi;
rail->rail_CreateWindow = xf_rail_CreateWindow;
rail->rail_MoveWindow = xf_rail_MoveWindow;
rail->rail_ShowWindow = xf_rail_ShowWindow;
rail->rail_SetWindowText = xf_rail_SetWindowText;
rail->rail_SetWindowIcon = xf_rail_SetWindowIcon;
rail->rail_SetWindowRects = xf_rail_SetWindowRects;
rail->rail_SetWindowVisibilityRects = xf_rail_SetWindowVisibilityRects;
rail->rail_DestroyWindow = xf_rail_DestroyWindow;
}
static void xf_on_free_rail_client_event(RDP_EVENT* event)
{
if (event->event_class == RDP_EVENT_CLASS_RAIL)
{
rail_free_cloned_order(event->event_type, event->user_data);
}
}
static void xf_send_rail_client_event(rdpChannels* channels, uint16 event_type, void* param)
{
RDP_EVENT* out_event = NULL;
void * payload = NULL;
payload = rail_clone_order(event_type, param);
if (payload != NULL)
{
out_event = freerdp_event_new(RDP_EVENT_CLASS_RAIL, event_type,
xf_on_free_rail_client_event, payload);
freerdp_channels_send_event(channels, out_event);
}
}
void xf_rail_send_activate(xfInfo* xfi, Window xwindow, boolean enabled)
{
rdpRail* rail;
rdpChannels* channels;
rdpWindow* rail_window;
RAIL_ACTIVATE_ORDER activate;
rail = xfi->_context->rail;
channels = xfi->_context->channels;
rail_window = window_list_get_by_extra_id(rail->list, (void*) xwindow);
if (rail_window == NULL)
return;
activate.windowId = rail_window->windowId;
activate.enabled = enabled;
xf_send_rail_client_event(channels, RDP_EVENT_TYPE_RAIL_CLIENT_ACTIVATE, &activate);
}
void xf_rail_send_client_system_command(xfInfo* xfi, uint32 windowId, uint16 command)
{
rdpChannels* channels;
RAIL_SYSCOMMAND_ORDER syscommand;
channels = xfi->_context->channels;
syscommand.windowId = windowId;
syscommand.command = command;
xf_send_rail_client_event(channels, RDP_EVENT_TYPE_RAIL_CLIENT_SYSCOMMAND, &syscommand);
}
/**
* The position of the X window can become out of sync with the RDP window
* if the X window is moved locally by the window manager. In this event
* send an update to the RDP server informing it of the new window position
* and size.
*/
void xf_rail_adjust_position(xfInfo* xfi, rdpWindow *window)
{
xfWindow* xfw;
rdpChannels* channels;
RAIL_WINDOW_MOVE_ORDER window_move;
xfw = (xfWindow*) window->extra;
channels = xfi->_context->channels;
if (! xfw->is_mapped || xfw->local_move.state != LMS_NOT_ACTIVE)
return;
// If current window position disagrees with RDP window position, send
// update to RDP server
if ( xfw->left != window->windowOffsetX ||
xfw->top != window->windowOffsetY ||
xfw->width != window->windowWidth ||
xfw->height != window->windowHeight)
{
window_move.windowId = window->windowId;
window_move.left = xfw->left;
window_move.top = xfw->top;
window_move.right = xfw->right;
window_move.bottom = xfw->bottom;
DEBUG_X11_LMS("window=0x%X rc={l=%d t=%d r=%d b=%d} w=%u h=%u"
" RDP=0x%X rc={l=%d t=%d} w=%d h=%d",
(uint32) xfw->handle, xfw->left, xfw->top,
xfw->right, xfw->bottom, xfw->width, xfw->height,
window->windowId,
window->windowOffsetX, window->windowOffsetY,
window->windowWidth, window->windowHeight);
xf_send_rail_client_event(channels, RDP_EVENT_TYPE_RAIL_CLIENT_WINDOW_MOVE, &window_move);
}
}
void xf_rail_end_local_move(xfInfo* xfi, rdpWindow *window)
{
xfWindow* xfw;
rdpChannels* channels;
RAIL_WINDOW_MOVE_ORDER window_move;
int x,y;
rdpInput* input = xfi->instance->input;
xfw = (xfWindow*) window->extra;
channels = xfi->_context->channels;
// Send RDP client event to inform RDP server
window_move.windowId = window->windowId;
window_move.left = xfw->left;
window_move.top = xfw->top;
window_move.right = xfw->right + 1; // In the update to RDP the position is one past the window
window_move.bottom = xfw->bottom + 1;
DEBUG_X11_LMS("window=0x%X rc={l=%d t=%d r=%d b=%d} w=%d h=%d",
(uint32) xfw->handle,
xfw->left, xfw->top, xfw->right, xfw->bottom,
xfw->width, xfw->height);
xf_send_rail_client_event(channels, RDP_EVENT_TYPE_RAIL_CLIENT_WINDOW_MOVE, &window_move);
// Send synthetic button up event to the RDP server. This is per the RDP spec to
// indicate a local move has finished.
x = xfw->left + xfw->local_move.window_x;
y = xfw->top + xfw->local_move.window_y;
input->MouseEvent(input, PTR_FLAGS_BUTTON1, x, y);
// Proactively update the RAIL window dimensions. There is a race condition where
// we can start to receive GDI orders for the new window dimensions before we
// receive the RAIL ORDER for the new window size. This avoids that race condition.
window->windowOffsetX = xfw->left;
window->windowOffsetY = xfw->top;
window->windowWidth = xfw->width;
window->windowHeight = xfw->height;
xfw->local_move.state = LMS_TERMINATING;
}
void xf_process_rail_get_sysparams_event(xfInfo* xfi, rdpChannels* channels, RDP_EVENT* event)
{
RAIL_SYSPARAM_ORDER* sysparam;
sysparam = (RAIL_SYSPARAM_ORDER*) event->user_data;
sysparam->workArea.left = xfi->workArea.x;
sysparam->workArea.top = xfi->workArea.y;
sysparam->workArea.right = xfi->workArea.x + xfi->workArea.width;
sysparam->workArea.bottom = xfi->workArea.y + xfi->workArea.height;
sysparam->taskbarPos.left = 0;
sysparam->taskbarPos.top = 0;
sysparam->taskbarPos.right = 0;
sysparam->taskbarPos.bottom = 0;
sysparam->dragFullWindows = false;
xf_send_rail_client_event(channels, RDP_EVENT_TYPE_RAIL_CLIENT_SET_SYSPARAMS, sysparam);
}
const char* error_code_names[] =
{
"RAIL_EXEC_S_OK",
"RAIL_EXEC_E_HOOK_NOT_LOADED",
"RAIL_EXEC_E_DECODE_FAILED",
"RAIL_EXEC_E_NOT_IN_ALLOWLIST",
"RAIL_EXEC_E_FILE_NOT_FOUND",
"RAIL_EXEC_E_FAIL",
"RAIL_EXEC_E_SESSION_LOCKED"
};
void xf_process_rail_exec_result_event(xfInfo* xfi, rdpChannels* channels, RDP_EVENT* event)
{
RAIL_EXEC_RESULT_ORDER* exec_result;
exec_result = (RAIL_EXEC_RESULT_ORDER*) event->user_data;
if (exec_result->execResult != RAIL_EXEC_S_OK)
{
printf("RAIL exec error: execResult=%s NtError=0x%X\n",
error_code_names[exec_result->execResult], exec_result->rawResult);
xfreerdp: a quick workaround for some issues with TS Remote App. Currently in Remote App mode we have no option to interact with the remote desktop host before the first RAIL window is created. In many situations this interaction possibility is absolutely required. One example is that screen which gets displayed if another user is logged on. It requires clicking a button in pre-RAIL mode so that the currently logged on user gets notified to confirm or deny the connection. Another example is the option to log on graphically (e.g. for hosts that don't support NLA) without predefined credentials. Also if the administrator sets the "User must change password at next logon" option there is currently no way to do this in TS Remote App mode. This change basically lets xfreerdp create the main window in Remote App mode like in a normal session and xfi->remote_app is not set to true initially. As soon as the rail exec result event or the first rail window creation request is received (whatever comes first) the main window gets destroyed and xfi->remote_app is set to true. The second change is to disconnect immediately if the rail exec result event reports an error, e.g. if the specified app cannot be found or if it is not in the list of allowed applications. This fixes FreeRDP github issue #143 and issue #308. I'm aware that this is not the most elegant solution but it is definitely an improvement and probably good enough for 1.0. A nicer solution would be hiding the main window and only displaying it if no rail exec result or rail window creation event is received after a certain timeout ...
2012-01-02 13:27:04 +04:00
xfi->disconnect = True;
}
else
{
xf_rail_enable_remoteapp_mode(xfi);
}
}
void xf_process_rail_server_sysparam_event(xfInfo* xfi, rdpChannels* channels, RDP_EVENT* event)
{
RAIL_SYSPARAM_ORDER* sysparam = (RAIL_SYSPARAM_ORDER*) event->user_data;
switch (sysparam->param)
{
case SPI_SET_SCREEN_SAVE_ACTIVE:
break;
case SPI_SET_SCREEN_SAVE_SECURE:
break;
}
}
void xf_process_rail_server_minmaxinfo_event(xfInfo* xfi, rdpChannels* channels, RDP_EVENT* event)
{
rdpRail* rail;
rdpWindow* rail_window = NULL;
RAIL_MINMAXINFO_ORDER* minmax = (RAIL_MINMAXINFO_ORDER*) event->user_data;
rail = ((rdpContext*) xfi->context)->rail;
rail_window = window_list_get_by_id(rail->list, minmax->windowId);
if (rail_window != NULL)
{
xfWindow * window = NULL;
window = (xfWindow *) rail_window->extra;
DEBUG_X11_LMS("windowId=0x%X maxWidth=%d maxHeight=%d maxPosX=%d maxPosY=%d "
"minTrackWidth=%d minTrackHeight=%d maxTrackWidth=%d maxTrackHeight=%d",
minmax->windowId, minmax->maxWidth, minmax->maxHeight,
(sint16)minmax->maxPosX, (sint16)minmax->maxPosY,
minmax->minTrackWidth, minmax->minTrackHeight,
minmax->maxTrackWidth, minmax->maxTrackHeight);
xf_SetWindowMinMaxInfo(xfi, window, minmax->maxWidth, minmax->maxHeight, minmax->maxPosX, minmax->maxPosY,
minmax->minTrackWidth, minmax->minTrackHeight, minmax->maxTrackWidth, minmax->maxTrackHeight);
}
}
const char* movetype_names[] =
{
"(invalid)",
"RAIL_WMSZ_LEFT",
"RAIL_WMSZ_RIGHT",
"RAIL_WMSZ_TOP",
"RAIL_WMSZ_TOPLEFT",
"RAIL_WMSZ_TOPRIGHT",
"RAIL_WMSZ_BOTTOM",
"RAIL_WMSZ_BOTTOMLEFT",
"RAIL_WMSZ_BOTTOMRIGHT",
"RAIL_WMSZ_MOVE",
"RAIL_WMSZ_KEYMOVE",
"RAIL_WMSZ_KEYSIZE"
};
void xf_process_rail_server_localmovesize_event(xfInfo* xfi, rdpChannels* channels, RDP_EVENT* event)
{
rdpRail* rail;
rdpWindow* rail_window = NULL;
RAIL_LOCALMOVESIZE_ORDER* movesize = (RAIL_LOCALMOVESIZE_ORDER*) event->user_data;
int direction = 0;
Window child_window;
int x,y;
rail = ((rdpContext*) xfi->context)->rail;
rail_window = window_list_get_by_id(rail->list, movesize->windowId);
if (rail_window != NULL)
{
xfWindow* xfw = NULL;
xfw = (xfWindow*) rail_window->extra;
DEBUG_X11_LMS("windowId=0x%X isMoveSizeStart=%d moveSizeType=%s PosX=%d PosY=%d",
movesize->windowId, movesize->isMoveSizeStart,
movetype_names[movesize->moveSizeType], (sint16) movesize->posX, (sint16) movesize->posY);
switch (movesize->moveSizeType)
{
case RAIL_WMSZ_LEFT: //0x1
direction = _NET_WM_MOVERESIZE_SIZE_LEFT;
x = movesize->posX;
y = movesize->posY;
break;
case RAIL_WMSZ_RIGHT: //0x2
direction = _NET_WM_MOVERESIZE_SIZE_RIGHT;
x = movesize->posX;
y = movesize->posY;
break;
case RAIL_WMSZ_TOP: //0x3
direction = _NET_WM_MOVERESIZE_SIZE_TOP;
x = movesize->posX;
y = movesize->posY;
break;
case RAIL_WMSZ_TOPLEFT: //0x4
direction = _NET_WM_MOVERESIZE_SIZE_TOPLEFT;
x = movesize->posX;
y = movesize->posY;
break;
case RAIL_WMSZ_TOPRIGHT: //0x5
direction = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
x = movesize->posX;
y = movesize->posY;
break;
case RAIL_WMSZ_BOTTOM: //0x6
direction = _NET_WM_MOVERESIZE_SIZE_BOTTOM;
x = movesize->posX;
y = movesize->posY;
break;
case RAIL_WMSZ_BOTTOMLEFT: //0x7
direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
x = movesize->posX;
y = movesize->posY;
break;
case RAIL_WMSZ_BOTTOMRIGHT: //0x8
direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
x = movesize->posX;
y = movesize->posY;
break;
case RAIL_WMSZ_MOVE: //0x9
direction = _NET_WM_MOVERESIZE_MOVE;
XTranslateCoordinates(xfi->display, xfw->handle,
RootWindowOfScreen(xfi->screen),
movesize->posX, movesize->posY, &x, &y, &child_window);
break;
case RAIL_WMSZ_KEYMOVE: //0xA
direction = _NET_WM_MOVERESIZE_MOVE_KEYBOARD;
x = movesize->posX;
y = movesize->posY;
break;
case RAIL_WMSZ_KEYSIZE: //0xB
direction = _NET_WM_MOVERESIZE_SIZE_KEYBOARD;
x = movesize->posX;
y = movesize->posY;
break;
}
if (movesize->isMoveSizeStart)
{
xf_StartLocalMoveSize(xfi, xfw, direction, x, y);
} else {
xf_EndLocalMoveSize(xfi, xfw);
}
}
}
void xf_process_rail_appid_resp_event(xfInfo* xfi, rdpChannels* channels, RDP_EVENT* event)
{
RAIL_GET_APPID_RESP_ORDER* appid_resp =
(RAIL_GET_APPID_RESP_ORDER*)event->user_data;
printf("Server Application ID Response PDU: windowId=0x%X "
"applicationId=(length=%d dump)\n",
appid_resp->windowId, appid_resp->applicationId.length);
freerdp_hexdump(appid_resp->applicationId.string, appid_resp->applicationId.length);
}
void xf_process_rail_langbarinfo_event(xfInfo* xfi, rdpChannels* channels, RDP_EVENT* event)
{
RAIL_LANGBAR_INFO_ORDER* langbar =
(RAIL_LANGBAR_INFO_ORDER*) event->user_data;
printf("Language Bar Information PDU: languageBarStatus=0x%X\n",
langbar->languageBarStatus);
}
void xf_process_rail_event(xfInfo* xfi, rdpChannels* channels, RDP_EVENT* event)
{
switch (event->event_type)
{
case RDP_EVENT_TYPE_RAIL_CHANNEL_GET_SYSPARAMS:
xf_process_rail_get_sysparams_event(xfi, channels, event);
break;
case RDP_EVENT_TYPE_RAIL_CHANNEL_EXEC_RESULTS:
xf_process_rail_exec_result_event(xfi, channels, event);
break;
case RDP_EVENT_TYPE_RAIL_CHANNEL_SERVER_SYSPARAM:
xf_process_rail_server_sysparam_event(xfi, channels, event);
break;
case RDP_EVENT_TYPE_RAIL_CHANNEL_SERVER_MINMAXINFO:
xf_process_rail_server_minmaxinfo_event(xfi, channels, event);
break;
case RDP_EVENT_TYPE_RAIL_CHANNEL_SERVER_LOCALMOVESIZE:
xf_process_rail_server_localmovesize_event(xfi, channels, event);
break;
case RDP_EVENT_TYPE_RAIL_CHANNEL_APPID_RESP:
xf_process_rail_appid_resp_event(xfi, channels, event);
break;
case RDP_EVENT_TYPE_RAIL_CHANNEL_LANGBARINFO:
xf_process_rail_langbarinfo_event(xfi, channels, event);
break;
default:
break;
}
}