📄 xwin.c
字号:
if (This->fullscreen || This->grab_keyboard)
*input_mask |= EnterWindowMask;
if (This->grab_keyboard)
*input_mask |= LeaveWindowMask;
}
BOOL
ui_create_window(RDPCLIENT * This)
{
uint8 null_pointer_mask[1] = { 0x80 };
uint8 null_pointer_data[24] = { 0x00 };
XSetWindowAttributes attribs;
XClassHint *classhints;
XSizeHints *sizehints;
int wndwidth, wndheight;
long input_mask, ic_input_mask;
XEvent xevent;
wndwidth = This->fullscreen ? WidthOfScreen(This->xwin.screen) : This->width;
wndheight = This->fullscreen ? HeightOfScreen(This->xwin.screen) : This->height;
/* Handle -x-y portion of geometry string */
if (This->xpos < 0 || (This->xpos == 0 && (This->pos & 2)))
This->xpos = WidthOfScreen(This->xwin.screen) + This->xpos - This->width;
if (This->ypos < 0 || (This->ypos == 0 && (This->pos & 4)))
This->ypos = HeightOfScreen(This->xwin.screen) + This->ypos - This->height;
get_window_attribs(This, &attribs);
This->wnd = XCreateWindow(This->display, RootWindowOfScreen(This->xwin.screen), This->xpos, This->ypos, wndwidth,
wndheight, 0, This->xwin.depth, InputOutput, This->xwin.visual,
CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
CWBorderPixel, &attribs);
if (This->xwin.gc == NULL)
{
This->xwin.gc = XCreateGC(This->display, This->wnd, 0, NULL);
ui_reset_clip(This);
}
if (This->xwin.create_bitmap_gc == NULL)
This->xwin.create_bitmap_gc = XCreateGC(This->display, This->wnd, 0, NULL);
if ((This->ownbackstore) && (This->xwin.backstore == 0))
{
This->xwin.backstore = XCreatePixmap(This->display, This->wnd, This->width, This->height, This->xwin.depth);
/* clear to prevent rubbish being exposed at startup */
XSetForeground(This->display, This->xwin.gc, BlackPixelOfScreen(This->xwin.screen));
XFillRectangle(This->display, This->xwin.backstore, This->xwin.gc, 0, 0, This->width, This->height);
}
XStoreName(This->display, This->wnd, This->title);
if (This->hide_decorations)
mwm_hide_decorations(This, This->wnd);
classhints = XAllocClassHint();
if (classhints != NULL)
{
classhints->res_name = classhints->res_class = "rdesktop";
XSetClassHint(This->display, This->wnd, classhints);
XFree(classhints);
}
sizehints = XAllocSizeHints();
if (sizehints)
{
sizehints->flags = PMinSize | PMaxSize;
if (This->pos)
sizehints->flags |= PPosition;
sizehints->min_width = sizehints->max_width = This->width;
sizehints->min_height = sizehints->max_height = This->height;
XSetWMNormalHints(This->display, This->wnd, sizehints);
XFree(sizehints);
}
if (This->embed_wnd)
{
XReparentWindow(This->display, This->wnd, (Window) This->embed_wnd, 0, 0);
}
get_input_mask(This, &input_mask);
if (This->xwin.IM != NULL)
{
This->xwin.IC = XCreateIC(This->xwin.IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
XNClientWindow, This->wnd, XNFocusWindow, This->wnd, NULL);
if ((This->xwin.IC != NULL)
&& (XGetICValues(This->xwin.IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
input_mask |= ic_input_mask;
}
XSelectInput(This->display, This->wnd, input_mask);
XMapWindow(This->display, This->wnd);
/* wait for VisibilityNotify */
do
{
XMaskEvent(This->display, VisibilityChangeMask, &xevent);
}
while (xevent.type != VisibilityNotify);
This->Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
This->xwin.focused = False;
This->xwin.mouse_in_wnd = False;
/* handle the WM_DELETE_WINDOW protocol */
This->xwin.protocol_atom = XInternAtom(This->display, "WM_PROTOCOLS", True);
This->xwin.kill_atom = XInternAtom(This->display, "WM_DELETE_WINDOW", True);
XSetWMProtocols(This->display, This->wnd, &This->xwin.kill_atom, 1);
/* create invisible 1x1 cursor to be used as null cursor */
if (This->xwin.null_cursor == NULL)
This->xwin.null_cursor = ui_create_cursor(This, 0, 0, 1, 1, null_pointer_mask, null_pointer_data);
return True;
}
void
ui_resize_window(RDPCLIENT * This)
{
XSizeHints *sizehints;
Pixmap bs;
sizehints = XAllocSizeHints();
if (sizehints)
{
sizehints->flags = PMinSize | PMaxSize;
sizehints->min_width = sizehints->max_width = This->width;
sizehints->min_height = sizehints->max_height = This->height;
XSetWMNormalHints(This->display, This->wnd, sizehints);
XFree(sizehints);
}
if (!(This->fullscreen || This->embed_wnd))
{
XResizeWindow(This->display, This->wnd, This->width, This->height);
}
/* create new backstore pixmap */
if (This->xwin.backstore != 0)
{
bs = XCreatePixmap(This->display, This->wnd, This->width, This->height, This->xwin.depth);
XSetForeground(This->display, This->xwin.gc, BlackPixelOfScreen(This->xwin.screen));
XFillRectangle(This->display, bs, This->xwin.gc, 0, 0, This->width, This->height);
XCopyArea(This->display, This->xwin.backstore, bs, This->xwin.gc, 0, 0, This->width, This->height, 0, 0);
XFreePixmap(This->display, This->xwin.backstore);
This->xwin.backstore = bs;
}
}
void
ui_destroy_window(RDPCLIENT * This)
{
if (This->xwin.IC != NULL)
XDestroyIC(This->xwin.IC);
XDestroyWindow(This->display, This->wnd);
}
void
xwin_toggle_fullscreen(RDPCLIENT * This)
{
Pixmap contents = 0;
if (This->xwin.seamless_active)
/* Turn off SeamlessRDP mode */
ui_seamless_toggle(This);
if (!This->ownbackstore)
{
/* need to save contents of window */
contents = XCreatePixmap(This->display, This->wnd, This->width, This->height, This->xwin.depth);
XCopyArea(This->display, This->wnd, contents, This->xwin.gc, 0, 0, This->width, This->height, 0, 0);
}
ui_destroy_window(This);
This->fullscreen = !This->fullscreen;
ui_create_window(This);
XDefineCursor(This->display, This->wnd, This->xwin.current_cursor);
if (!This->ownbackstore)
{
XCopyArea(This->display, contents, This->wnd, This->xwin.gc, 0, 0, This->width, This->height, 0, 0);
XFreePixmap(This->display, contents);
}
}
static void
handle_button_event(RDPCLIENT * This, XEvent xevent, BOOL down)
{
uint16 button, flags = 0;
This->last_gesturetime = xevent.xbutton.time;
button = xkeymap_translate_button(xevent.xbutton.button);
if (button == 0)
return;
if (down)
flags = MOUSE_FLAG_DOWN;
/* Stop moving window when button is released, regardless of cursor position */
if (This->xwin.moving_wnd && (xevent.type == ButtonRelease))
This->xwin.moving_wnd = False;
/* If win_button_sizee is nonzero, enable single app mode */
if (xevent.xbutton.y < This->win_button_size)
{
/* Check from right to left: */
if (xevent.xbutton.x >= This->width - This->win_button_size)
{
/* The close button, continue */
;
}
else if (xevent.xbutton.x >= This->width - This->win_button_size * 2)
{
/* The maximize/restore button. Do not send to
server. It might be a good idea to change the
cursor or give some other visible indication
that rdesktop inhibited this click */
if (xevent.type == ButtonPress)
return;
}
else if (xevent.xbutton.x >= This->width - This->win_button_size * 3)
{
/* The minimize button. Iconify window. */
if (xevent.type == ButtonRelease)
{
/* Release the mouse button outside the minimize button, to prevent the
actual minimazation to happen */
rdp_send_input(This, time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
XIconifyWindow(This->display, This->wnd, DefaultScreen(This->display));
return;
}
}
else if (xevent.xbutton.x <= This->win_button_size)
{
/* The system menu. Ignore. */
if (xevent.type == ButtonPress)
return;
}
else
{
/* The title bar. */
if (xevent.type == ButtonPress)
{
if (!This->fullscreen && This->hide_decorations && !This->xwin.using_full_workarea)
{
This->xwin.moving_wnd = True;
This->xwin.move_x_offset = xevent.xbutton.x;
This->xwin.move_y_offset = xevent.xbutton.y;
}
return;
}
}
}
if (xevent.xmotion.window == This->wnd)
{
rdp_send_input(This, time(NULL), RDP_INPUT_MOUSE,
flags | button, xevent.xbutton.x, xevent.xbutton.y);
}
else
{
/* SeamlessRDP */
rdp_send_input(This, time(NULL), RDP_INPUT_MOUSE,
flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
}
}
/* Process events in Xlib queue
Returns 0 after user quit, 1 otherwise */
static int
xwin_process_events(RDPCLIENT * This)
{
XEvent xevent;
KeySym keysym;
uint32 ev_time;
char str[256];
Status status;
int events = 0;
seamless_window *sw;
while ((XPending(This->display) > 0) && events++ < 20)
{
XNextEvent(This->display, &xevent);
if ((This->xwin.IC != NULL) && (XFilterEvent(&xevent, None) == True))
{
DEBUG_KBD(("Filtering event\n"));
continue;
}
switch (xevent.type)
{
case VisibilityNotify:
if (xevent.xvisibility.window == This->wnd)
This->Unobscured =
xevent.xvisibility.state == VisibilityUnobscured;
break;
case ClientMessage:
/* the window manager told us to quit */
if ((xevent.xclient.message_type == This->xwin.protocol_atom)
&& ((Atom) xevent.xclient.data.l[0] == This->xwin.kill_atom))
/* Quit */
return 0;
break;
case KeyPress:
This->last_gesturetime = xevent.xkey.time;
if (This->xwin.IC != NULL)
/* Multi_key compatible version */
{
XmbLookupString(This->xwin.IC,
&xevent.xkey, str, sizeof(str), &keysym,
&status);
if (!((status == XLookupKeySym) || (status == XLookupBoth)))
{
error("XmbLookupString failed with status 0x%x\n",
status);
break;
}
}
else
{
/* Plain old XLookupString */
DEBUG_KBD(("\nNo input context, using XLookupString\n"));
XLookupString((XKeyEvent *) & xevent,
str, sizeof(str), &keysym, NULL);
}
DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
get_ksname(keysym)));
ev_time = time(NULL);
if (handle_special_keys(This, keysym, xevent.xkey.state, ev_time, True))
break;
xkeymap_send_keys(This, keysym, xevent.xkey.keycode, xevent.xkey.state,
ev_time, True, 0);
break;
case KeyRelease:
This->last_gesturetime = xevent.xkey.time;
XLookupString((XKeyEvent *) & xevent, str,
sizeof(str), &keysym, NULL);
DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
get_ksname(keysym)));
ev_time = time(NULL);
if (handle_special_keys(This, keysym, xevent.xkey.state, ev_time, False))
break;
xkeymap_send_keys(This, keysym, xevent.xkey.keycode, xevent.xkey.state,
ev_time, False, 0);
break;
case ButtonPress:
handle_button_event(This, xevent, True);
break;
case ButtonRelease:
handle_button_event(This, xevent, False);
break;
case MotionNotify:
if (This->xwin.moving_wnd)
{
XMoveWindow(This->display, This->wnd,
xevent.xmotion.x_root - This->xwin.move_x_offset,
xevent.xmotion.y_root - This->xwin.move_y_offset);
break;
}
if (This->fullscreen && !This->xwin.focused)
XSetInputFocus(This->display, This->wnd, RevertToPointerRoot,
CurrentTime);
if (xevent.xmotion.window == This->wnd)
{
rdp_send_input(This, time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
xevent.xmotion.x, xevent.xmotion.y);
}
else
{
/* SeamlessRDP */
rdp_send_input(This, time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
xevent.xmotion.x_root,
xevent.xmotion.y_root);
}
break;
case FocusIn:
if (xevent.xfocus.mode == NotifyGrab)
break;
This->xwin.focused = True;
reset_modifier_keys(This);
if (This->grab_keyboard && This->xwin.mouse_in_wnd)
XGrabKeyboard(This->display, This->wnd, True,
GrabModeAsync, GrabModeAsync, CurrentTime);
sw = sw_get_window_by_wnd(This, xevent.xfocus.window);
if (!sw)
break;
if (sw->id != This->xwin.seamless_focused)
{
seamless_send_focus(This, sw->id, 0);
This->xwin.seamless_focused = sw->id;
}
break;
case FocusOut:
if (xevent.xfocus.mode == NotifyUngrab)
break;
This->xwin.focused = False;
if (xevent.xfocus.mode == NotifyWhileGrabbed)
XUngrabKeyboard(This->display, CurrentTime);
break;
case EnterNotify:
/* we only register for this event when in fullscreen mode */
/* or grab_keyboard */
This->xwin.mouse_in_wnd = True;
if (This->fullscreen)
{
XSetInputFocus(This->display, This->wnd, RevertToPointerRoot,
CurrentTime);
break;
}
if (This->xwin.focused)
XGrabKeyboard(This->display, This->wnd, True,
GrabModeAsync, GrabModeAsync, CurrentTime);
break;
case LeaveNotify:
/* we only register for this event when grab_keyboard */
This->xwin.mouse_in_wnd = False;
XUngrabKeyboard(This->display, CurrentTime);
break;
case Expose:
if (xevent.xexpose.window == This->wnd)
{
XCopyArea(This->display, This->xwin.backstore, xevent.xexpose.window,
This->xwin.gc,
xevent.xexpose.x, xevent.xexpose.y,
xevent.xexpose.width, xevent.xexpose.height,
xevent.xexpose.x, xevent.xexpose.y);
}
else
{
sw = sw_get_window_by_wnd(This, xevent.xexpose.window);
if (!sw)
break;
XCopyArea(This->display, This->xwin.backstore,
xevent.xexpose.window, This->xwin.gc,
xevent.xexpose.x + sw->xoffset,
xevent.xexpose.y + sw->yoffset,
xevent.xexpose.width,
xevent.xexpose.height, xevent.xexpose.x,
xevent.xexpose.y);
}
break;
case MappingNotify:
/* Refresh keyboard mapping if it has changed. This is important for
Xvnc, since it allocates keycodes dynamically */
if (xevent.xmapping.request == MappingKeyboard
|| xevent.xmapping.request == MappingModifier)
XRefreshKeyboardMapping(&xevent.xmapping);
if (xevent.xmapping.request == MappingModifier)
{
XFreeModifiermap(This->xwin.mod_map);
This->xwin.mod_map = XGetModifierMapping(This->display);
}
break;
/* clipboard stuff */
case SelectionNotify:
xclip_handle_SelectionNotify(This, &xevent.xselection);
break;
case SelectionRequest:
xclip_handle_SelectionRequest(This, &xevent.xselectionrequest);
break;
case SelectionClear:
xclip_handle_SelectionClear(This);
break;
case PropertyNotify:
xclip_handle_PropertyNotify(This, &xevent.xproperty);
if (xevent.xproperty.window == This->wnd)
break;
if (xevent.xproperty.window == DefaultRootWindow(This->display))
break;
/* seamless */
sw = sw_get_window_by_wnd(This, xevent.xproperty.window);
if (!sw)
break;
if ((xevent.xproperty.atom == This->net_wm_state_atom)
&& (xevent.xproperty.state == PropertyNewValue))
{
sw->state = ewmh_get_window_state(This, sw->wnd);
seamless_send_state(This, sw->id, sw->state, 0);
}
if ((xevent.xproperty.atom == This->net_wm_desktop_atom)
&& (xevent.xproperty.state == PropertyNewValue))
{
sw->desktop = ewmh_get_window_desktop(This, sw->wnd);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -