📄 xwin.c
字号:
if (g_create_bitmap_gc == NULL) g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL); if ((g_ownbackstore) && (g_backstore == 0)) { g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth); /* clear to prevent rubbish being exposed at startup */ XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen)); XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height); } XStoreName(g_display, g_wnd, g_title); if (g_hide_decorations) mwm_hide_decorations(g_wnd); classhints = XAllocClassHint(); if (classhints != NULL) { classhints->res_name = classhints->res_class = "rdesktop"; XSetClassHint(g_display, g_wnd, classhints); XFree(classhints); } sizehints = XAllocSizeHints(); if (sizehints) { sizehints->flags = PMinSize | PMaxSize; if (g_pos) sizehints->flags |= PPosition; sizehints->min_width = sizehints->max_width = g_width; sizehints->min_height = sizehints->max_height = g_height; XSetWMNormalHints(g_display, g_wnd, sizehints); XFree(sizehints); } if (g_embed_wnd) { XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0); } get_input_mask(&input_mask); if (g_IM != NULL) { g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing), XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL); if ((g_IC != NULL) && (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL)) input_mask |= ic_input_mask; } XSelectInput(g_display, g_wnd, input_mask); XMapWindow(g_display, g_wnd); /* wait for VisibilityNotify */ do { XMaskEvent(g_display, VisibilityChangeMask, &xevent); } while (xevent.type != VisibilityNotify); g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured; g_focused = False; g_mouse_in_wnd = False; /* handle the WM_DELETE_WINDOW protocol */ g_protocol_atom = XInternAtom(g_display, "WM_PROTOCOLS", True); g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True); XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1); /* create invisible 1x1 cursor to be used as null cursor */ if (g_null_cursor == NULL) g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data); return True;}voidui_resize_window(){ XSizeHints *sizehints; Pixmap bs; sizehints = XAllocSizeHints(); if (sizehints) { sizehints->flags = PMinSize | PMaxSize; sizehints->min_width = sizehints->max_width = g_width; sizehints->min_height = sizehints->max_height = g_height; XSetWMNormalHints(g_display, g_wnd, sizehints); XFree(sizehints); } if (!(g_fullscreen || g_embed_wnd)) { XResizeWindow(g_display, g_wnd, g_width, g_height); } /* create new backstore pixmap */ if (g_backstore != 0) { bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth); XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen)); XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height); XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0); XFreePixmap(g_display, g_backstore); g_backstore = bs; }}voidui_destroy_window(void){ if (g_IC != NULL) XDestroyIC(g_IC); XDestroyWindow(g_display, g_wnd);}voidxwin_toggle_fullscreen(void){ Pixmap contents = 0; if (g_seamless_active) /* Turn off SeamlessRDP mode */ ui_seamless_toggle(); if (!g_ownbackstore) { /* need to save contents of window */ contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth); XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0); } ui_destroy_window(); g_fullscreen = !g_fullscreen; ui_create_window(); XDefineCursor(g_display, g_wnd, g_current_cursor); if (!g_ownbackstore) { XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0); XFreePixmap(g_display, contents); }}static voidhandle_button_event(XEvent xevent, BOOL down){ uint16 button, flags = 0; g_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 (g_moving_wnd && (xevent.type == ButtonRelease)) g_moving_wnd = False; /* If win_button_size is nonzero, enable single app mode */ if (xevent.xbutton.y < g_win_button_size) { /* Check from right to left: */ if (xevent.xbutton.x >= g_width - g_win_button_size) { /* The close button, continue */ ; } else if (xevent.xbutton.x >= g_width - g_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 >= g_width - g_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(time(NULL), RDP_INPUT_MOUSE, button, 1, 1); XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display)); return; } } else if (xevent.xbutton.x <= g_win_button_size) { /* The system menu. Ignore. */ if (xevent.type == ButtonPress) return; } else { /* The title bar. */ if (xevent.type == ButtonPress) { if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea) { g_moving_wnd = True; g_move_x_offset = xevent.xbutton.x; g_move_y_offset = xevent.xbutton.y; } return; } } } if (xevent.xmotion.window == g_wnd) { rdp_send_input(time(NULL), RDP_INPUT_MOUSE, flags | button, xevent.xbutton.x, xevent.xbutton.y); } else { /* SeamlessRDP */ rdp_send_input(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 intxwin_process_events(void){ XEvent xevent; KeySym keysym; uint32 ev_time; char str[256]; Status status; int events = 0; seamless_window *sw; while ((XPending(g_display) > 0) && events++ < 20) { XNextEvent(g_display, &xevent); if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True)) { DEBUG_KBD(("Filtering event\n")); continue; } switch (xevent.type) { case VisibilityNotify: if (xevent.xvisibility.window == g_wnd) g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured; break; case ClientMessage: /* the window manager told us to quit */ if ((xevent.xclient.message_type == g_protocol_atom) && ((Atom) xevent.xclient.data.l[0] == g_kill_atom)) /* Quit */ return 0; break; case KeyPress: g_last_gesturetime = xevent.xkey.time; if (g_IC != NULL) /* Multi_key compatible version */ { XmbLookupString(g_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(keysym, xevent.xkey.state, ev_time, True)) break; xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state, ev_time, True, 0); break; case KeyRelease: g_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(keysym, xevent.xkey.state, ev_time, False)) break; xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state, ev_time, False, 0); break; case ButtonPress: handle_button_event(xevent, True); break; case ButtonRelease: handle_button_event(xevent, False); break; case MotionNotify: if (g_moving_wnd) { XMoveWindow(g_display, g_wnd, xevent.xmotion.x_root - g_move_x_offset, xevent.xmotion.y_root - g_move_y_offset); break; } if (g_fullscreen && !g_focused) XSetInputFocus(g_display, g_wnd, RevertToPointerRoot, CurrentTime); if (xevent.xmotion.window == g_wnd) { rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y); } else { /* SeamlessRDP */ rdp_send_input(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; g_focused = True; reset_modifier_keys(); if (g_grab_keyboard && g_mouse_in_wnd) XGrabKeyboard(g_display, g_wnd, True, GrabModeAsync, GrabModeAsync, CurrentTime); sw = sw_get_window_by_wnd(xevent.xfocus.window); if (!sw) break; if (sw->id != g_seamless_focused) { seamless_send_focus(sw->id, 0); g_seamless_focused = sw->id; } break; case FocusOut: if (xevent.xfocus.mode == NotifyUngrab) break; g_focused = False; if (xevent.xfocus.mode == NotifyWhileGrabbed) XUngrabKeyboard(g_display, CurrentTime); break; case EnterNotify: /* we only register for this event when in fullscreen mode */ /* or grab_keyboard */ g_mouse_in_wnd = True; if (g_fullscreen) { XSetInputFocus(g_display, g_wnd, RevertToPointerRoot, CurrentTime); break; } if (g_focused) XGrabKeyboard(g_display, g_wnd, True, GrabModeAsync, GrabModeAsync, CurrentTime); break; case LeaveNotify: /* we only register for this event when grab_keyboard */ g_mouse_in_wnd = False; XUngrabKeyboard(g_display, CurrentTime); break; case Expose: if (xevent.xexpose.window == g_wnd) { XCopyArea(g_display, g_backstore, xevent.xexpose.window, g_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(xevent.xexpose.window); if (!sw) break; XCopyArea(g_display, g_backstore, xevent.xexpose.window, g_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(g_mod_map); g_mod_map = XGetModifierMapping(g_display); } break; /* clipboard stuff */ case SelectionNotify: xclip_handle_SelectionNotify(&xevent.xselection); break; case SelectionRequest: xclip_handle_SelectionRequest(&xevent.xselectionrequest); break; case SelectionClear: xclip_handle_SelectionClear(); break; case PropertyNotify: xclip_handle_PropertyNotify(&xevent.xproperty); if (xevent.xproperty.window == g_wnd) break; if (xevent.xproperty.window == DefaultRootWindow(g_display)) break; /* seamless */ sw = sw_get_window_by_wnd(xevent.xproperty.window); if (!sw) break; if ((xevent.xproperty.atom == g_net_wm_state_atom) && (xevent.xproperty.state == PropertyNewValue)) { sw->state = ewmh_get_window_state(sw->wnd); seamless_send_state(sw->id, sw->state, 0); } if ((xevent.xproperty.atom == g_net_wm_desktop_atom) && (xevent.xproperty.state == PropertyNewValue)) { sw->desktop = ewmh_get_window_desktop(sw->wnd); sw_all_to_desktop(sw->wnd, sw->desktop); } break; case MapNotify: if (!g_seamless_active) rdp_send_client_window_status(1); break; case UnmapNotify: if (!g_seamless_active) rdp_send_client_window_status(0); break; case ConfigureNotify: if (!g_seamless_active) break; sw = sw_get_window_by_wnd(xevent.xconfigure.window); if (!sw) break; gettimeofday(sw->position_timer, NULL); if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >= 1000000) { sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER - 1000000; sw->position_timer->tv_sec += 1; } else { sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER; } sw_handle_restack(sw); break; } } /* Keep going */ return 1;}/* Returns 0 after user quit, 1 otherwise */intui_select(int rdp_socket){ int n; fd_set rfds, wfds; struct timeval tv; BOOL s_timeout = False; while (True) { n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket; /* Process any events already waiting */ if (!xwin_process_events()) /* User quit */ return 0; if (g_seamless_active) sw_check_timers(); FD_ZERO(&rfds); FD_ZERO(&wfds); FD_SET(rdp_socket, &rfds); FD_SET(g_x_socket, &rfds);#ifdef WITH_RDPSND /* FIXME: there should be an API for registering fds */ if (g_dsp_busy) { FD_SET(g_dsp_fd, &wfds); n = (g_dsp_fd > n) ? g_dsp_fd : n; }#endif /* default timeout */ tv.tv_sec = 60; tv.tv_usec = 0; /* add redirection handles */ rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout); seamless_select_timeout(&tv); n++; switch (select(n, &rfds, &wfds, NULL, &tv)) { case -1: error("select: %s\n", strerror(errno)); case 0: /* Abort serial read calls */ if (s_timeout) rdpdr_check_fds(&rfds, &wfds, (BOOL) True); continue; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -