⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xwin.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 + -