2 * FreeRDP: A Remote Desktop Protocol Client
5 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include <X11/Xutil.h>
23 #include <freerdp/kbd/kbd.h>
24 #include <freerdp/kbd/vkcodes.h>
27 #include "xf_window.h"
28 #include "xf_cliprdr.h"
32 static const char* const X11_EVENT_STRINGS[] =
71 void xf_send_mouse_motion_event(rdpInput* input, boolean down, uint32 button, uint16 x, uint16 y)
73 input->MouseEvent(input, PTR_FLAGS_MOVE, x, y);
76 boolean xf_event_Expose(xfInfo* xfi, XEvent* event, boolean app)
83 w = event->xexpose.width;
84 h = event->xexpose.height;
88 XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc, x, y, w, h, x, y);
94 rdpRail* rail = ((rdpContext*) xfi->context)->rail;
96 window = window_list_get_by_extra_id(rail->list, (void*) event->xexpose.window);
100 xfw = (xfWindow*) window->extra;
101 xf_UpdateWindowArea(xfi, xfw, x, y, w, h);
108 boolean xf_event_VisibilityNotify(xfInfo* xfi, XEvent* event, boolean app)
110 xfi->unobscured = event->xvisibility.state == VisibilityUnobscured;
114 boolean xf_event_MotionNotify(xfInfo* xfi, XEvent* event, boolean app)
118 input = xfi->instance->input;
122 if (xfi->mouse_motion != true)
124 if ((event->xmotion.state & (Button1Mask | Button2Mask | Button3Mask)) == 0)
128 input->MouseEvent(input, PTR_FLAGS_MOVE, event->xmotion.x, event->xmotion.y);
131 XSetInputFocus(xfi->display, xfi->window->handle, RevertToPointerRoot, CurrentTime);
133 else if (xfi->mouse_motion == true)
136 int x = event->xmotion.x;
137 int y = event->xmotion.y;
138 rdpRail* rail = ((rdpContext*) xfi->context)->rail;
140 window = window_list_get_by_extra_id(rail->list, (void*) event->xmotion.window);
144 x += window->windowOffsetX;
145 y += window->windowOffsetY;
146 input->MouseEvent(input, PTR_FLAGS_MOVE, x, y);
153 boolean xf_event_ButtonPress(xfInfo* xfi, XEvent* event, boolean app)
160 input = xfi->instance->input;
167 switch (event->xbutton.button)
170 x = event->xbutton.x;
171 y = event->xbutton.y;
172 flags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1;
176 x = event->xbutton.x;
177 y = event->xbutton.y;
178 flags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON3;
182 x = event->xbutton.x;
183 y = event->xbutton.y;
184 flags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2;
189 flags = PTR_FLAGS_WHEEL | 0x0078;
194 flags = PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x0088;
208 input->MouseEvent(input, flags, 0, 0);
215 rdpRail* rail = ((rdpContext*) xfi->context)->rail;
217 window = window_list_get_by_extra_id(rail->list, (void*) event->xbutton.window);
221 x += window->windowOffsetX;
222 y += window->windowOffsetY;
226 input->MouseEvent(input, flags, x, y);
233 boolean xf_event_ButtonRelease(xfInfo* xfi, XEvent* event, boolean app)
239 input = xfi->instance->input;
245 switch (event->xbutton.button)
248 x = event->xbutton.x;
249 y = event->xbutton.y;
250 flags = PTR_FLAGS_BUTTON1;
254 x = event->xbutton.x;
255 y = event->xbutton.y;
256 flags = PTR_FLAGS_BUTTON3;
260 x = event->xbutton.x;
261 y = event->xbutton.y;
262 flags = PTR_FLAGS_BUTTON2;
275 rdpRail* rail = ((rdpContext*) xfi->context)->rail;
277 window = window_list_get_by_extra_id(rail->list, (void*) event->xbutton.window);
281 x += window->windowOffsetX;
282 y += window->windowOffsetY;
286 input->MouseEvent(input, flags, x, y);
292 boolean xf_event_KeyPress(xfInfo* xfi, XEvent* event, boolean app)
297 XLookupString((XKeyEvent*) event, str, sizeof(str), &keysym, NULL);
299 xf_kbd_set_keypress(xfi, event->xkey.keycode, keysym);
301 if (xfi->fullscreen_toggle && xf_kbd_handle_special_keys(xfi, keysym))
304 xf_kbd_send_key(xfi, true, event->xkey.keycode);
309 boolean xf_event_KeyRelease(xfInfo* xfi, XEvent* event, boolean app)
313 if (XPending(xfi->display))
315 memset(&next_event, 0, sizeof(next_event));
316 XPeekEvent(xfi->display, &next_event);
318 if (next_event.type == KeyPress)
320 if (next_event.xkey.keycode == event->xkey.keycode)
325 xf_kbd_unset_keypress(xfi, event->xkey.keycode);
326 xf_kbd_send_key(xfi, false, event->xkey.keycode);
331 boolean xf_event_FocusIn(xfInfo* xfi, XEvent* event, boolean app)
333 if (event->xfocus.mode == NotifyGrab)
338 if (xfi->mouse_active && (app != true))
339 XGrabKeyboard(xfi->display, xfi->window->handle, true, GrabModeAsync, GrabModeAsync, CurrentTime);
342 xf_rail_send_activate(xfi, event->xany.window, true);
344 xf_kbd_focus_in(xfi);
347 xf_cliprdr_check_owner(xfi);
352 boolean xf_event_FocusOut(xfInfo* xfi, XEvent* event, boolean app)
354 if (event->xfocus.mode == NotifyUngrab)
357 xfi->focused = false;
359 if (event->xfocus.mode == NotifyWhileGrabbed)
360 XUngrabKeyboard(xfi->display, CurrentTime);
363 xf_rail_send_activate(xfi, event->xany.window, false);
368 boolean xf_event_MappingNotify(xfInfo* xfi, XEvent* event, boolean app)
370 if (event->xmapping.request == MappingModifier)
372 XFreeModifiermap(xfi->modifier_map);
373 xfi->modifier_map = XGetModifierMapping(xfi->display);
379 boolean xf_event_ClientMessage(xfInfo* xfi, XEvent* event, boolean app)
381 if ((event->xclient.message_type == xfi->WM_PROTOCOLS)
382 && ((Atom) event->xclient.data.l[0] == xfi->WM_DELETE_WINDOW))
387 rdpRail* rail = ((rdpContext*) xfi->context)->rail;
389 window = window_list_get_by_extra_id(rail->list, (void*) event->xclient.window);
393 xf_rail_send_client_system_command(xfi, window->windowId, SC_CLOSE);
407 boolean xf_event_EnterNotify(xfInfo* xfi, XEvent* event, boolean app)
411 xfi->mouse_active = true;
414 XSetInputFocus(xfi->display, xfi->window->handle, RevertToPointerRoot, CurrentTime);
417 XGrabKeyboard(xfi->display, xfi->window->handle, true, GrabModeAsync, GrabModeAsync, CurrentTime);
421 /* keep track of which window has focus so that we can apply pointer updates */
425 rdpRail* rail = ((rdpContext*) xfi->context)->rail;
426 window = window_list_get_by_extra_id(rail->list, (void*) event->xexpose.window);
430 xfw = (xfWindow*) window->extra;
438 boolean xf_event_LeaveNotify(xfInfo* xfi, XEvent* event, boolean app)
442 xfi->mouse_active = false;
443 XUngrabKeyboard(xfi->display, CurrentTime);
449 boolean xf_event_ConfigureNotify(xfInfo* xfi, XEvent* event, boolean app)
452 rdpRail* rail = ((rdpContext*) xfi->context)->rail;
454 window = window_list_get_by_extra_id(rail->list, (void*) event->xconfigure.window);
460 xfw = (xfWindow*) window->extra;
463 * ConfigureNotify coordinates are expressed relative to the window parent.
464 * Translate these to root window coordinates.
467 XTranslateCoordinates(xfi->display, xfw->handle,
468 RootWindowOfScreen(xfi->screen),
469 0, 0, &xfw->left, &xfw->top, &childWindow);
471 xfw->width = event->xconfigure.width;
472 xfw->height = event->xconfigure.height;
473 xfw->right = xfw->left + xfw->width - 1;
474 xfw->bottom = xfw->top + xfw->height - 1;
476 DEBUG_X11_LMS("window=0x%X rc={l=%d t=%d r=%d b=%d} w=%u h=%u send_event=%d",
477 (uint32) xfw->handle, xfw->left, xfw->top, xfw->right, xfw->bottom,
478 xfw->width, xfw->height, event->xconfigure.send_event);
480 if (app && ! event->xconfigure.send_event)
481 xf_rail_adjust_position(xfi, window);
487 boolean xf_event_MapNotify(xfInfo* xfi, XEvent* event, boolean app)
490 rdpRail* rail = ((rdpContext*) xfi->context)->rail;
495 window = window_list_get_by_extra_id(rail->list, (void*) event->xany.window);
499 /* local restore event */
500 xf_rail_send_client_system_command(xfi, window->windowId, SC_RESTORE);
501 xfWindow *xfw = (xfWindow*) window->extra;
502 xfw->is_mapped = true;
508 boolean xf_event_UnmapNotify(xfInfo* xfi, XEvent* event, boolean app)
511 rdpRail* rail = ((rdpContext*) xfi->context)->rail;
516 window = window_list_get_by_extra_id(rail->list, (void*) event->xany.window);
520 xfWindow *xfw = (xfWindow*) window->extra;
521 xfw->is_mapped = false;
527 boolean xf_event_SelectionNotify(xfInfo* xfi, XEvent* event, boolean app)
531 if (xf_cliprdr_process_selection_notify(xfi, event))
538 boolean xf_event_SelectionRequest(xfInfo* xfi, XEvent* event, boolean app)
542 if (xf_cliprdr_process_selection_request(xfi, event))
549 boolean xf_event_SelectionClear(xfInfo* xfi, XEvent* event, boolean app)
553 if (xf_cliprdr_process_selection_clear(xfi, event))
560 boolean xf_event_PropertyNotify(xfInfo* xfi, XEvent* event, boolean app)
564 if (xf_cliprdr_process_property_notify(xfi, event))
571 boolean xf_event_suppress_events(xfInfo *xfi, rdpWindow *window, XEvent*event)
573 if (! xfi->remote_app)
576 switch (xfi->window->local_move.state)
579 // No local move in progress, nothing to do
582 // Local move initiated by RDP server, but we
583 // have not yet seen any updates from the X server
586 case ConfigureNotify:
587 // Starting to see move events
588 // from the X server. Local
589 // move is now in progress.
590 xfi->window->local_move.state = LMS_ACTIVE;
592 // Allow these events to be processed during move to keep
593 // our state up to date.
600 // A button release event means the X
601 // window server did not grab the
602 // mouse before the user released it.
603 // In this case we must cancel the
604 // local move. The event will be
605 // processed below as normal, below.
607 case VisibilityNotify:
610 // Allow these events to pass
613 // Eat any other events
619 // Local move is in progress
622 case ConfigureNotify:
623 case VisibilityNotify:
626 // Keep us up to date on position
629 // Any other event terminates move
630 xf_rail_end_local_move(xfi, window);
635 case LMS_TERMINATING:
636 // Already sent RDP end move to sever
637 // Allow events to pass.
645 boolean xf_event_process(freerdp* instance, XEvent* event)
647 boolean status = true;
648 xfInfo* xfi = ((xfContext*) instance->context)->xfi;
649 rdpRail* rail = ((rdpContext*) xfi->context)->rail;
654 window = window_list_get_by_extra_id(
655 rail->list, (void*) event->xexpose.window);
658 // Update "current" window for cursor change orders
659 xfi->window = (xfWindow *) window->extra;
661 if (xf_event_suppress_events(xfi, window, event))
666 if (event->type != MotionNotify)
667 DEBUG_X11("%s Event: wnd=0x%04X", X11_EVENT_STRINGS[event->type], (uint32) event->xany.window);
672 status = xf_event_Expose(xfi, event, xfi->remote_app);
675 case VisibilityNotify:
676 status = xf_event_VisibilityNotify(xfi, event, xfi->remote_app);
680 status = xf_event_MotionNotify(xfi, event, xfi->remote_app);
684 status = xf_event_ButtonPress(xfi, event, xfi->remote_app);
688 status = xf_event_ButtonRelease(xfi, event, xfi->remote_app);
692 status = xf_event_KeyPress(xfi, event, xfi->remote_app);
696 status = xf_event_KeyRelease(xfi, event, xfi->remote_app);
700 status = xf_event_FocusIn(xfi, event, xfi->remote_app);
704 status = xf_event_FocusOut(xfi, event, xfi->remote_app);
708 status = xf_event_EnterNotify(xfi, event, xfi->remote_app);
712 status = xf_event_LeaveNotify(xfi, event, xfi->remote_app);
721 case ConfigureNotify:
722 status = xf_event_ConfigureNotify(xfi, event, xfi->remote_app);
726 status = xf_event_MapNotify(xfi, event, xfi->remote_app);
730 status = xf_event_UnmapNotify(xfi, event, xfi->remote_app);
737 status = xf_event_MappingNotify(xfi, event, xfi->remote_app);
741 status = xf_event_ClientMessage(xfi, event, xfi->remote_app);
744 case SelectionNotify:
745 status = xf_event_SelectionNotify(xfi, event, xfi->remote_app);
748 case SelectionRequest:
749 status = xf_event_SelectionRequest(xfi, event, xfi->remote_app);
753 status = xf_event_SelectionClear(xfi, event, xfi->remote_app);
757 status = xf_event_PropertyNotify(xfi, event, xfi->remote_app);