Initial commit - from Precise source
[freerdp-ubuntu-pcb-backport.git] / client / X11 / xf_rail.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Client
3  * X11 RAIL
4  *
5  * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #include <X11/Xlib.h>
21 #include <X11/Xutil.h>
22
23 #include <freerdp/utils/event.h>
24 #include <freerdp/utils/hexdump.h>
25 #include <freerdp/utils/rail.h>
26 #include <freerdp/rail/rail.h>
27
28 #include "xf_window.h"
29 #include "xf_rail.h"
30
31 void xf_rail_enable_remoteapp_mode(xfInfo* xfi)
32 {
33         if (xfi->remote_app == false)
34         {
35                 xfi->remote_app = true;
36                 xfi->drawable = DefaultRootWindow(xfi->display);
37                 xf_DestroyWindow(xfi, xfi->window);
38                 xfi->window = NULL;
39         }
40 }
41
42 void xf_rail_paint(xfInfo* xfi, rdpRail* rail, sint32 uleft, sint32 utop, uint32 uright, uint32 ubottom)
43 {
44         xfWindow* xfw;
45         rdpWindow* window;
46         boolean intersect;
47         uint32 iwidth, iheight;
48         sint32 ileft, itop;
49         uint32 iright, ibottom;
50         sint32 wleft, wtop; 
51         uint32 wright, wbottom;
52
53         window_list_rewind(rail->list);
54
55         while (window_list_has_next(rail->list))
56         {
57                 window = window_list_get_next(rail->list);
58                 xfw = (xfWindow*) window->extra;
59
60                 // RDP can have zero width or height windows.  X cannot, so we ignore these.
61
62                 if (window->windowWidth == 0 || window->windowHeight == 0)
63                 {
64                         continue;
65                 }
66
67                 wleft = window->windowOffsetX;
68                 wtop = window->windowOffsetY;
69                 wright = window->windowOffsetX + window->windowWidth - 1;
70                 wbottom = window->windowOffsetY + window->windowHeight - 1;
71
72                 ileft = MAX(uleft, wleft);
73                 itop = MAX(utop, wtop);
74                 iright = MIN(uright, wright);
75                 ibottom = MIN(ubottom, wbottom);
76
77                 iwidth = iright - ileft + 1;
78                 iheight = ibottom - itop + 1;
79
80                 intersect = ((iright > ileft) && (ibottom > itop)) ? true : false;
81
82                 if (intersect)
83                 {
84                         xf_UpdateWindowArea(xfi, xfw, ileft - wleft, itop - wtop, iwidth, iheight);
85                 }
86         }
87 }
88
89 void xf_rail_CreateWindow(rdpRail* rail, rdpWindow* window)
90 {
91         xfInfo* xfi;
92         xfWindow* xfw;
93
94         xfi = (xfInfo*) rail->extra;
95
96         xf_rail_enable_remoteapp_mode(xfi);
97
98         xfw = xf_CreateWindow((xfInfo*) rail->extra, window,
99                         window->windowOffsetX, window->windowOffsetY,
100                         window->windowWidth, window->windowHeight,
101                         window->windowId);
102
103         xf_SetWindowStyle(xfi, xfw, window->style, window->extendedStyle);
104
105         XStoreName(xfi->display, xfw->handle, window->title);
106
107         window->extra = (void*) xfw;
108         window->extraId = (void*) xfw->handle;
109 }
110
111 void xf_rail_MoveWindow(rdpRail* rail, rdpWindow* window)
112 {
113         xfInfo* xfi;
114         xfWindow* xfw;
115
116         xfi = (xfInfo*) rail->extra;
117         xfw = (xfWindow*) window->extra;
118
119         // Do nothing if window is already in the correct position
120         if ( xfw->left == window->windowOffsetX && 
121                 xfw->top == window->windowOffsetY && 
122                 xfw->width == window->windowWidth && 
123                 xfw->height == window->windowHeight)
124         {
125                 return;
126         }
127
128         xf_MoveWindow((xfInfo*) rail->extra, xfw,
129                         window->windowOffsetX, window->windowOffsetY,
130                         window->windowWidth, window->windowHeight);
131 }
132
133 void xf_rail_ShowWindow(rdpRail* rail, rdpWindow* window, uint8 state)
134 {
135         xfInfo* xfi;
136         xfWindow* xfw;
137
138         xfi = (xfInfo*) rail->extra;
139         xfw = (xfWindow*) window->extra;
140
141         xf_ShowWindow((xfInfo*) rail->extra, xfw, state);
142 }
143
144 void xf_rail_SetWindowText(rdpRail* rail, rdpWindow* window)
145 {
146         xfInfo* xfi;
147         xfWindow* xfw;
148
149         xfi = (xfInfo*) rail->extra;
150         xfw = (xfWindow*) window->extra;
151
152         XStoreName(xfi->display, xfw->handle, window->title);
153 }
154
155 void xf_rail_SetWindowIcon(rdpRail* rail, rdpWindow* window, rdpIcon* icon)
156 {
157         xfInfo* xfi;
158         xfWindow* xfw;
159
160         xfi = (xfInfo*) rail->extra;
161         xfw = (xfWindow*) window->extra;
162
163         icon->extra = freerdp_icon_convert(icon->entry->bitsColor, NULL, icon->entry->bitsMask,
164                         icon->entry->width, icon->entry->height, icon->entry->bpp, rail->clrconv);
165
166         xf_SetWindowIcon(xfi, xfw, icon);
167 }
168
169 void xf_rail_SetWindowRects(rdpRail* rail, rdpWindow* window)
170 {
171         xfInfo* xfi;
172         xfWindow* xfw;
173
174         xfi = (xfInfo*) rail->extra;
175         xfw = (xfWindow*) window->extra;
176
177         xf_SetWindowRects(xfi, xfw, window->windowRects, window->numWindowRects);
178 }
179
180 void xf_rail_SetWindowVisibilityRects(rdpRail* rail, rdpWindow* window)
181 {
182         xfInfo* xfi;
183         xfWindow* xfw;
184
185         xfi = (xfInfo*) rail->extra;
186         xfw = (xfWindow*) window->extra;
187
188         xf_SetWindowVisibilityRects(xfi, xfw, window->windowRects, window->numWindowRects);
189 }
190
191 void xf_rail_DestroyWindow(rdpRail* rail, rdpWindow* window)
192 {
193         xfWindow* xfw;
194         xfw = (xfWindow*) window->extra;
195         xf_DestroyWindow((xfInfo*) rail->extra, xfw);
196 }
197
198 void xf_rail_register_callbacks(xfInfo* xfi, rdpRail* rail)
199 {
200         rail->extra = (void*) xfi;
201         rail->rail_CreateWindow = xf_rail_CreateWindow;
202         rail->rail_MoveWindow = xf_rail_MoveWindow;
203         rail->rail_ShowWindow = xf_rail_ShowWindow;
204         rail->rail_SetWindowText = xf_rail_SetWindowText;
205         rail->rail_SetWindowIcon = xf_rail_SetWindowIcon;
206         rail->rail_SetWindowRects = xf_rail_SetWindowRects;
207         rail->rail_SetWindowVisibilityRects = xf_rail_SetWindowVisibilityRects;
208         rail->rail_DestroyWindow = xf_rail_DestroyWindow;
209 }
210
211 static void xf_on_free_rail_client_event(RDP_EVENT* event)
212 {
213         if (event->event_class == RDP_EVENT_CLASS_RAIL)
214         {
215                 rail_free_cloned_order(event->event_type, event->user_data);
216         }
217 }
218
219 static void xf_send_rail_client_event(rdpChannels* channels, uint16 event_type, void* param)
220 {
221         RDP_EVENT* out_event = NULL;
222         void * payload = NULL;
223
224         payload = rail_clone_order(event_type, param);
225         if (payload != NULL)
226         {
227                 out_event = freerdp_event_new(RDP_EVENT_CLASS_RAIL, event_type,
228                         xf_on_free_rail_client_event, payload);
229                 freerdp_channels_send_event(channels, out_event);
230         }
231 }
232
233 void xf_rail_send_activate(xfInfo* xfi, Window xwindow, boolean enabled)
234 {
235         rdpRail* rail;
236         rdpChannels* channels;
237         rdpWindow* rail_window;
238         RAIL_ACTIVATE_ORDER activate;
239
240         rail = xfi->_context->rail;
241         channels = xfi->_context->channels;
242
243         rail_window = window_list_get_by_extra_id(rail->list, (void*) xwindow);
244
245         if (rail_window == NULL)
246                 return;
247
248         activate.windowId = rail_window->windowId;
249         activate.enabled = enabled;
250
251         xf_send_rail_client_event(channels, RDP_EVENT_TYPE_RAIL_CLIENT_ACTIVATE, &activate);
252 }
253
254 void xf_rail_send_client_system_command(xfInfo* xfi, uint32 windowId, uint16 command)
255 {
256         rdpChannels* channels;
257         RAIL_SYSCOMMAND_ORDER syscommand;
258
259         channels = xfi->_context->channels;
260
261         syscommand.windowId = windowId;
262         syscommand.command = command;
263
264         xf_send_rail_client_event(channels, RDP_EVENT_TYPE_RAIL_CLIENT_SYSCOMMAND, &syscommand);
265 }
266
267 /**
268  * The position of the X window can become out of sync with the RDP window
269  * if the X window is moved locally by the window manager.  In this event
270  * send an update to the RDP server informing it of the new window position
271  * and size.
272  */
273 void xf_rail_adjust_position(xfInfo* xfi, rdpWindow *window)
274 {
275         xfWindow* xfw;
276         rdpChannels* channels;
277         RAIL_WINDOW_MOVE_ORDER window_move;
278
279         xfw = (xfWindow*) window->extra;
280         channels = xfi->_context->channels;
281
282         if (! xfw->is_mapped || xfw->local_move.state != LMS_NOT_ACTIVE)
283                 return;
284
285         // If current window position disagrees with RDP window position, send
286         // update to RDP server
287         if ( xfw->left != window->windowOffsetX ||
288                 xfw->top != window->windowOffsetY ||
289                 xfw->width != window->windowWidth ||
290                 xfw->height != window->windowHeight)
291         {
292                 window_move.windowId = window->windowId;
293                 window_move.left = xfw->left;
294                 window_move.top = xfw->top;
295                 window_move.right = xfw->right;
296                 window_move.bottom = xfw->bottom;
297
298                 DEBUG_X11_LMS("window=0x%X rc={l=%d t=%d r=%d b=%d} w=%u h=%u"
299                         "  RDP=0x%X rc={l=%d t=%d} w=%d h=%d",
300                         (uint32) xfw->handle, xfw->left, xfw->top, 
301                         xfw->right, xfw->bottom, xfw->width, xfw->height,
302                         window->windowId,
303                         window->windowOffsetX, window->windowOffsetY, 
304                         window->windowWidth, window->windowHeight);
305
306                 xf_send_rail_client_event(channels, RDP_EVENT_TYPE_RAIL_CLIENT_WINDOW_MOVE, &window_move);
307         }
308 }
309
310 void xf_rail_end_local_move(xfInfo* xfi, rdpWindow *window)
311 {
312         xfWindow* xfw;
313         rdpChannels* channels;
314         RAIL_WINDOW_MOVE_ORDER window_move;
315         int x,y;
316         rdpInput* input = xfi->instance->input;
317
318         xfw = (xfWindow*) window->extra;
319         channels = xfi->_context->channels;
320
321         // Send RDP client event to inform RDP server
322
323         window_move.windowId = window->windowId;
324         window_move.left = xfw->left;
325         window_move.top = xfw->top;
326         window_move.right = xfw->right + 1;   // In the update to RDP the position is one past the window
327         window_move.bottom = xfw->bottom + 1;
328
329         DEBUG_X11_LMS("window=0x%X rc={l=%d t=%d r=%d b=%d} w=%d h=%d",
330                 (uint32) xfw->handle, 
331                 xfw->left, xfw->top, xfw->right, xfw->bottom,
332                 xfw->width, xfw->height);
333
334         xf_send_rail_client_event(channels, RDP_EVENT_TYPE_RAIL_CLIENT_WINDOW_MOVE, &window_move);
335
336         // Send synthetic button up event to the RDP server.  This is per the RDP spec to
337         // indicate a local move has finished.
338
339         x = xfw->left + xfw->local_move.window_x;
340         y = xfw->top + xfw->local_move.window_y;
341         input->MouseEvent(input, PTR_FLAGS_BUTTON1, x, y);
342
343         // Proactively update the RAIL window dimensions.  There is a race condition where
344         // we can start to receive GDI orders for the new window dimensions before we 
345         // receive the RAIL ORDER for the new window size.  This avoids that race condition.
346
347         window->windowOffsetX = xfw->left;
348         window->windowOffsetY = xfw->top;
349         window->windowWidth = xfw->width;
350         window->windowHeight = xfw->height;
351
352         xfw->local_move.state = LMS_TERMINATING;
353 }
354
355 void xf_process_rail_get_sysparams_event(xfInfo* xfi, rdpChannels* channels, RDP_EVENT* event)
356 {
357         RAIL_SYSPARAM_ORDER* sysparam;
358
359         sysparam = (RAIL_SYSPARAM_ORDER*) event->user_data;
360
361         sysparam->workArea.left = xfi->workArea.x;
362         sysparam->workArea.top = xfi->workArea.y;
363         sysparam->workArea.right = xfi->workArea.x + xfi->workArea.width;
364         sysparam->workArea.bottom = xfi->workArea.y + xfi->workArea.height;
365
366         sysparam->taskbarPos.left = 0;
367         sysparam->taskbarPos.top = 0;
368         sysparam->taskbarPos.right = 0;
369         sysparam->taskbarPos.bottom = 0;
370
371         sysparam->dragFullWindows = false;
372
373         xf_send_rail_client_event(channels, RDP_EVENT_TYPE_RAIL_CLIENT_SET_SYSPARAMS, sysparam);
374 }
375
376 const char* error_code_names[] =
377 {
378                 "RAIL_EXEC_S_OK",
379                 "RAIL_EXEC_E_HOOK_NOT_LOADED",
380                 "RAIL_EXEC_E_DECODE_FAILED",
381                 "RAIL_EXEC_E_NOT_IN_ALLOWLIST",
382                 "RAIL_EXEC_E_FILE_NOT_FOUND",
383                 "RAIL_EXEC_E_FAIL",
384                 "RAIL_EXEC_E_SESSION_LOCKED"
385 };
386
387 void xf_process_rail_exec_result_event(xfInfo* xfi, rdpChannels* channels, RDP_EVENT* event)
388 {
389         RAIL_EXEC_RESULT_ORDER* exec_result;
390
391         exec_result = (RAIL_EXEC_RESULT_ORDER*) event->user_data;
392
393         if (exec_result->execResult != RAIL_EXEC_S_OK)
394         {
395                 printf("RAIL exec error: execResult=%s NtError=0x%X\n",
396                         error_code_names[exec_result->execResult], exec_result->rawResult);
397                 xfi->disconnect = True;
398         }
399         else
400         {
401                 xf_rail_enable_remoteapp_mode(xfi);
402         }
403 }
404
405 void xf_process_rail_server_sysparam_event(xfInfo* xfi, rdpChannels* channels, RDP_EVENT* event)
406 {
407         RAIL_SYSPARAM_ORDER* sysparam = (RAIL_SYSPARAM_ORDER*) event->user_data;
408
409         switch (sysparam->param)
410         {
411                 case SPI_SET_SCREEN_SAVE_ACTIVE:
412                         break;
413
414                 case SPI_SET_SCREEN_SAVE_SECURE:
415                         break;
416         }
417 }
418
419 void xf_process_rail_server_minmaxinfo_event(xfInfo* xfi, rdpChannels* channels, RDP_EVENT* event)
420 {
421         rdpRail* rail;
422         rdpWindow* rail_window = NULL;
423         RAIL_MINMAXINFO_ORDER* minmax = (RAIL_MINMAXINFO_ORDER*) event->user_data;
424
425         rail = ((rdpContext*) xfi->context)->rail;
426         rail_window = window_list_get_by_id(rail->list, minmax->windowId);
427
428         if (rail_window != NULL)
429         {
430                 xfWindow * window = NULL;
431                 window = (xfWindow *) rail_window->extra;
432
433                 DEBUG_X11_LMS("windowId=0x%X maxWidth=%d maxHeight=%d maxPosX=%d maxPosY=%d "
434                         "minTrackWidth=%d minTrackHeight=%d maxTrackWidth=%d maxTrackHeight=%d",
435                         minmax->windowId, minmax->maxWidth, minmax->maxHeight,
436                         (sint16)minmax->maxPosX, (sint16)minmax->maxPosY,
437                         minmax->minTrackWidth, minmax->minTrackHeight,
438                         minmax->maxTrackWidth, minmax->maxTrackHeight);
439
440                 xf_SetWindowMinMaxInfo(xfi, window, minmax->maxWidth, minmax->maxHeight, minmax->maxPosX, minmax->maxPosY,
441                         minmax->minTrackWidth, minmax->minTrackHeight, minmax->maxTrackWidth, minmax->maxTrackHeight);
442         }
443 }
444
445 const char* movetype_names[] =
446 {
447         "(invalid)",
448         "RAIL_WMSZ_LEFT",
449         "RAIL_WMSZ_RIGHT",
450         "RAIL_WMSZ_TOP",
451         "RAIL_WMSZ_TOPLEFT",
452         "RAIL_WMSZ_TOPRIGHT",
453         "RAIL_WMSZ_BOTTOM",
454         "RAIL_WMSZ_BOTTOMLEFT",
455         "RAIL_WMSZ_BOTTOMRIGHT",
456         "RAIL_WMSZ_MOVE",
457         "RAIL_WMSZ_KEYMOVE",
458         "RAIL_WMSZ_KEYSIZE"
459 };
460
461 void xf_process_rail_server_localmovesize_event(xfInfo* xfi, rdpChannels* channels, RDP_EVENT* event)
462 {
463         rdpRail* rail;
464         rdpWindow* rail_window = NULL;
465         RAIL_LOCALMOVESIZE_ORDER* movesize = (RAIL_LOCALMOVESIZE_ORDER*) event->user_data;
466         int direction = 0;
467         Window child_window;
468         int x,y;
469
470         rail = ((rdpContext*) xfi->context)->rail;
471         rail_window = window_list_get_by_id(rail->list, movesize->windowId);
472
473         if (rail_window != NULL)
474         {
475                 xfWindow* xfw = NULL;
476                 xfw = (xfWindow*) rail_window->extra;
477
478                 DEBUG_X11_LMS("windowId=0x%X isMoveSizeStart=%d moveSizeType=%s PosX=%d PosY=%d",
479                         movesize->windowId, movesize->isMoveSizeStart,
480                         movetype_names[movesize->moveSizeType], (sint16) movesize->posX, (sint16) movesize->posY);
481
482                 switch (movesize->moveSizeType)
483                 {
484                         case RAIL_WMSZ_LEFT: //0x1
485                                 direction = _NET_WM_MOVERESIZE_SIZE_LEFT;
486                                 x = movesize->posX;
487                                 y = movesize->posY;
488                                 break;
489                         case RAIL_WMSZ_RIGHT: //0x2
490                                 direction = _NET_WM_MOVERESIZE_SIZE_RIGHT;
491                                 x = movesize->posX;
492                                 y = movesize->posY;
493                                 break;
494                         case RAIL_WMSZ_TOP: //0x3
495                                 direction = _NET_WM_MOVERESIZE_SIZE_TOP;
496                                 x = movesize->posX;
497                                 y = movesize->posY;
498                                 break;
499                         case RAIL_WMSZ_TOPLEFT: //0x4
500                                 direction = _NET_WM_MOVERESIZE_SIZE_TOPLEFT;
501                                 x = movesize->posX;
502                                 y = movesize->posY;
503                                 break;
504                         case RAIL_WMSZ_TOPRIGHT: //0x5
505                                 direction = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
506                                 x = movesize->posX;
507                                 y = movesize->posY;
508                                 break;
509                         case RAIL_WMSZ_BOTTOM: //0x6
510                                 direction = _NET_WM_MOVERESIZE_SIZE_BOTTOM;
511                                 x = movesize->posX;
512                                 y = movesize->posY;
513                                 break;
514                         case RAIL_WMSZ_BOTTOMLEFT: //0x7
515                                 direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
516                                 x = movesize->posX;
517                                 y = movesize->posY;
518                                 break;
519                         case RAIL_WMSZ_BOTTOMRIGHT: //0x8
520                                 direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
521                                 x = movesize->posX;
522                                 y = movesize->posY;
523                                 break;
524                         case RAIL_WMSZ_MOVE: //0x9
525                                 direction = _NET_WM_MOVERESIZE_MOVE;
526                                 XTranslateCoordinates(xfi->display, xfw->handle, 
527                                         RootWindowOfScreen(xfi->screen), 
528                                         movesize->posX, movesize->posY, &x, &y, &child_window);
529                                 break;
530                         case RAIL_WMSZ_KEYMOVE: //0xA
531                                 direction = _NET_WM_MOVERESIZE_MOVE_KEYBOARD;
532                                 x = movesize->posX;
533                                 y = movesize->posY;
534                                 break;
535                         case RAIL_WMSZ_KEYSIZE: //0xB
536                                 direction = _NET_WM_MOVERESIZE_SIZE_KEYBOARD;
537                                 x = movesize->posX;
538                                 y = movesize->posY;
539                                 break;
540                 }
541
542                 if (movesize->isMoveSizeStart)
543                 {
544                         xf_StartLocalMoveSize(xfi, xfw, direction, x, y);
545                 } else {
546                         xf_EndLocalMoveSize(xfi, xfw);
547                 }
548         }
549 }
550
551 void xf_process_rail_appid_resp_event(xfInfo* xfi, rdpChannels* channels, RDP_EVENT* event)
552 {
553         RAIL_GET_APPID_RESP_ORDER* appid_resp =
554                 (RAIL_GET_APPID_RESP_ORDER*)event->user_data;
555
556         printf("Server Application ID Response PDU: windowId=0x%X "
557                 "applicationId=(length=%d dump)\n",
558                 appid_resp->windowId, appid_resp->applicationId.length);
559
560         freerdp_hexdump(appid_resp->applicationId.string, appid_resp->applicationId.length);
561 }
562
563 void xf_process_rail_langbarinfo_event(xfInfo* xfi, rdpChannels* channels, RDP_EVENT* event)
564 {
565         RAIL_LANGBAR_INFO_ORDER* langbar =
566                 (RAIL_LANGBAR_INFO_ORDER*) event->user_data;
567
568         printf("Language Bar Information PDU: languageBarStatus=0x%X\n",
569                 langbar->languageBarStatus);
570 }
571
572 void xf_process_rail_event(xfInfo* xfi, rdpChannels* channels, RDP_EVENT* event)
573 {
574         switch (event->event_type)
575         {
576                 case RDP_EVENT_TYPE_RAIL_CHANNEL_GET_SYSPARAMS:
577                         xf_process_rail_get_sysparams_event(xfi, channels, event);
578                         break;
579
580                 case RDP_EVENT_TYPE_RAIL_CHANNEL_EXEC_RESULTS:
581                         xf_process_rail_exec_result_event(xfi, channels, event);
582                         break;
583
584                 case RDP_EVENT_TYPE_RAIL_CHANNEL_SERVER_SYSPARAM:
585                         xf_process_rail_server_sysparam_event(xfi, channels, event);
586                         break;
587
588                 case RDP_EVENT_TYPE_RAIL_CHANNEL_SERVER_MINMAXINFO:
589                         xf_process_rail_server_minmaxinfo_event(xfi, channels, event);
590                         break;
591
592                 case RDP_EVENT_TYPE_RAIL_CHANNEL_SERVER_LOCALMOVESIZE:
593                         xf_process_rail_server_localmovesize_event(xfi, channels, event);
594                         break;
595
596                 case RDP_EVENT_TYPE_RAIL_CHANNEL_APPID_RESP:
597                         xf_process_rail_appid_resp_event(xfi, channels, event);
598                         break;
599
600                 case RDP_EVENT_TYPE_RAIL_CHANNEL_LANGBARINFO:
601                         xf_process_rail_langbarinfo_event(xfi, channels, event);
602                         break;
603
604                 default:
605                         break;
606         }
607 }