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

📄 xclip.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 3 页
字号:
#endif
		}
		else if (event->target == This->xclip.format_unicode_atom)
		{
			/* Assuming text/unicode to be UTF-16 */
			format = CF_UNICODETEXT;
		}
		else
		{
			DEBUG_CLIPBOARD(("Requested target unavailable. (It was not in TARGETS, so why did you ask for it?!)\n"));
			xclip_refuse_selection(This, event);
			return;
		}

		cliprdr_send_data_request(This, format);
		This->xclip.selection_request = *event;
		This->xclip.has_selection_request = True;
		return;		/* wait for data */
	}
}

/* While this rdesktop holds ownership over the clipboard, it means the clipboard data
   is offered by the RDP server (and when it is pasted inside RDP, there's no network
   roundtrip).

   This event (SelectionClear) symbolizes this rdesktop lost onwership of the clipboard
   to some other X client. We should find out what clipboard formats this other
   client offers and announce that to RDP. */
void
xclip_handle_SelectionClear(RDPCLIENT * This)
{
	DEBUG_CLIPBOARD(("xclip_handle_SelectionClear\n"));
	xclip_notify_change(This);
	xclip_probe_selections(This);
}

/* Called when any property changes in our window or the root window. */
void
xclip_handle_PropertyNotify(RDPCLIENT * This, XPropertyEvent * event)
{
	unsigned long nitems;
	unsigned long offset = 0;
	unsigned long bytes_left = 1;
	int format;
	XWindowAttributes wa;
	uint8 *data;
	Atom type;

	if (event->state == PropertyNewValue && This->xclip.waiting_for_INCR)
	{
		DEBUG_CLIPBOARD(("x_clip_handle_PropertyNotify: This->xclip.waiting_for_INCR != 0\n"));

		while (bytes_left > 0)
		{
			/* Unlike the specification, we don't set the 'delete' arugment to True
			   since we slurp the INCR's chunks in even-smaller chunks of 4096 bytes. */
			if ((XGetWindowProperty
			     (This->display, This->wnd, This->xclip.rdesktop_clipboard_target_atom, offset, 4096L,
			      False, AnyPropertyType, &type, &format, &nitems, &bytes_left,
			      &data) != Success))
			{
				XFree(data);
				return;
			}

			if (nitems == 0)
			{
				/* INCR transfer finished */
				XGetWindowAttributes(This->display, This->wnd, &wa);
				XSelectInput(This->display, This->wnd,
					     (wa.your_event_mask ^ PropertyChangeMask));
				XFree(data);
				This->xclip.waiting_for_INCR = 0;

				if (This->xclip.clip_buflen > 0)
				{
					if (!xclip_send_data_with_convert
					    (This, This->xclip.clip_buffer, This->xclip.clip_buflen, This->xclip.incr_target))
					{
						helper_cliprdr_send_empty_response(This);
					}
					xfree(This->xclip.clip_buffer);
					This->xclip.clip_buffer = NULL;
					This->xclip.clip_buflen = 0;
				}
			}
			else
			{
				/* Another chunk in the INCR transfer */
				offset += (nitems / 4);	/* offset at which to begin the next slurp */
				This->xclip.clip_buffer = xrealloc(This->xclip.clip_buffer, This->xclip.clip_buflen + nitems);
				memcpy(This->xclip.clip_buffer + This->xclip.clip_buflen, data, nitems);
				This->xclip.clip_buflen += nitems;

				XFree(data);
			}
		}
		XDeleteProperty(This->display, This->wnd, This->xclip.rdesktop_clipboard_target_atom);
		return;
	}

	if ((event->atom == This->xclip.rdesktop_selection_notify_atom) &&
	    (event->window == DefaultRootWindow(This->display)))
		xclip_probe_selections(This);
}
#endif


/* Called when the RDP server announces new clipboard data formats.
   In response, we:
   - take ownership over the clipboard
   - declare those formats in their Windows native form
     to other rdesktop instances on this X server */
void
ui_clip_format_announce(RDPCLIENT * This, uint8 * data, uint32 length)
{
	This->xclip.acquire_time = This->last_gesturetime;

	XSetSelectionOwner(This->display, This->xclip.primary_atom, This->wnd, This->xclip.acquire_time);
	if (XGetSelectionOwner(This->display, This->xclip.primary_atom) != This->wnd)
		warning("Failed to aquire ownership of PRIMARY clipboard\n");

	XSetSelectionOwner(This->display, This->xclip.clipboard_atom, This->wnd, This->xclip.acquire_time);
	if (XGetSelectionOwner(This->display, This->xclip.clipboard_atom) != This->wnd)
		warning("Failed to aquire ownership of CLIPBOARD clipboard\n");

	if (This->xclip.formats_data)
		xfree(This->xclip.formats_data);
	This->xclip.formats_data = xmalloc(length);
	memcpy(This->xclip.formats_data, data, length);
	This->xclip.formats_data_length = length;

	xclip_notify_change(This);
}

/* Called when the RDP server responds with clipboard data (after we've requested it). */
void
ui_clip_handle_data(RDPCLIENT * This, uint8 * data, uint32 length)
{
	BOOL free_data = False;

	if (length == 0)
	{
		xclip_refuse_selection(This, &This->xclip.selection_request);
		This->xclip.has_selection_request = False;
		return;
	}

	if (This->xclip.selection_request.target == This->xclip.format_string_atom || This->xclip.selection_request.target == XA_STRING)
	{
		/* We're expecting a CF_TEXT response */
		uint8 *firstnull;

		/* translate linebreaks */
		crlf2lf(data, &length);

		/* Only send data up to null byte, if any */
		firstnull = (uint8 *) strchr((char *) data, '\0');
		if (firstnull)
		{
			length = firstnull - data + 1;
		}
	}
#ifdef USE_UNICODE_CLIPBOARD
	else if (This->xclip.selection_request.target == This->xclip.format_utf8_string_atom)
	{
		/* We're expecting a CF_UNICODETEXT response */
		iconv_t cd = iconv_open("UTF-8", WINDOWS_CODEPAGE);
		if (cd != (iconv_t) - 1)
		{
			size_t utf8_length = length * 2;
			char *utf8_data = malloc(utf8_length);
			size_t utf8_length_remaining = utf8_length;
			char *utf8_data_remaining = utf8_data;
			char *data_remaining = (char *) data;
			size_t length_remaining = (size_t) length;
			if (utf8_data == NULL)
			{
				iconv_close(cd);
				return;
			}
			iconv(cd, (ICONV_CONST char **) &data_remaining, &length_remaining,
			      &utf8_data_remaining, &utf8_length_remaining);
			iconv_close(cd);
			free_data = True;
			data = (uint8 *) utf8_data;
			length = utf8_length - utf8_length_remaining;
		}
	}
	else if (This->xclip.selection_request.target == This->xclip.format_unicode_atom)
	{
		/* We're expecting a CF_UNICODETEXT response, so what we're
		   receiving matches our requirements and there's no need
		   for further conversions. */
	}
#endif
	else if (This->xclip.selection_request.target == This->xclip.rdesktop_native_atom)
	{
		/* Pass as-is */
	}
	else
	{
		DEBUG_CLIPBOARD(("ui_clip_handle_data: BUG! I don't know how to convert selection target %s!\n", XGetAtomName(This->display, This->xclip.selection_request.target)));
		xclip_refuse_selection(This, &This->xclip.selection_request);
		This->xclip.has_selection_request = False;
		return;
	}

	xclip_provide_selection(This, &This->xclip.selection_request, This->xclip.selection_request.target, 8, data, length - 1);
	This->xclip.has_selection_request = False;

	if (free_data)
		free(data);
}

void
ui_clip_request_failed(RDPCLIENT * This)
{
	xclip_refuse_selection(This, &This->xclip.selection_request);
	This->xclip.has_selection_request = False;
}

void
ui_clip_request_data(RDPCLIENT * This, uint32 format)
{
	Window primary_owner, clipboard_owner;

	DEBUG_CLIPBOARD(("Request from server for format %d\n", format));
	This->xclip.rdp_clipboard_request_format = format;

	if (This->xclip.probing_selections)
	{
		DEBUG_CLIPBOARD(("ui_clip_request_data: Selection probe in progress. Cannot handle request.\n"));
		helper_cliprdr_send_empty_response(This);
		return;
	}

	xclip_clear_target_props(This);

	if (This->xclip.rdesktop_is_selection_owner)
	{
		XChangeProperty(This->display, This->wnd, This->xclip.rdesktop_clipboard_target_atom,
				XA_INTEGER, 32, PropModeReplace, (unsigned char *) &format, 1);

		XConvertSelection(This->display, This->xclip.primary_atom, This->xclip.rdesktop_native_atom,
				  This->xclip.rdesktop_clipboard_target_atom, This->wnd, CurrentTime);
		return;
	}

	if (This->xclip.auto_mode)
		primary_owner = XGetSelectionOwner(This->display, This->xclip.primary_atom);
	else
		primary_owner = None;

	clipboard_owner = XGetSelectionOwner(This->display, This->xclip.clipboard_atom);

	/* Both available */
	if ((primary_owner != None) && (clipboard_owner != None))
	{
		This->xclip.primary_timestamp = 0;
		This->xclip.clipboard_timestamp = 0;
		XConvertSelection(This->display, This->xclip.primary_atom, This->xclip.timestamp_atom,
				  This->xclip.rdesktop_primary_timestamp_target_atom, This->wnd, CurrentTime);
		XConvertSelection(This->display, This->xclip.clipboard_atom, This->xclip.timestamp_atom,
				  This->xclip.rdesktop_clipboard_timestamp_target_atom, This->wnd, CurrentTime);
		return;
	}

	/* Just PRIMARY */
	if (primary_owner != None)
	{
		XConvertSelection(This->display, This->xclip.primary_atom, This->xclip.targets_atom,
				  This->xclip.rdesktop_clipboard_target_atom, This->wnd, CurrentTime);
		return;
	}

	/* Just CLIPBOARD */
	if (clipboard_owner != None)
	{
		XConvertSelection(This->display, This->xclip.clipboard_atom, This->xclip.targets_atom,
				  This->xclip.rdesktop_clipboard_target_atom, This->wnd, CurrentTime);
		return;
	}

	/* No data available */
	helper_cliprdr_send_empty_response(This);
}

void
ui_clip_sync(RDPCLIENT * This)
{
	xclip_probe_selections(This);
}

void
ui_clip_set_mode(RDPCLIENT * This, const char *optarg)
{
	This->rdpclip = True;

	if (str_startswith(optarg, "PRIMARYCLIPBOARD"))
		This->xclip.auto_mode = True;
	else if (str_startswith(optarg, "CLIPBOARD"))
		This->xclip.auto_mode = False;
	else
	{
		warning("Invalid clipboard mode '%s'.\n", optarg);
		This->rdpclip = False;
	}
}

void
xclip_init(RDPCLIENT * This)
{
	if (!This->rdpclip)
		return;

	if (!cliprdr_init(This))
		return;

	This->xclip.primary_atom = XInternAtom(This->display, "PRIMARY", False);
	This->xclip.clipboard_atom = XInternAtom(This->display, "CLIPBOARD", False);
	This->xclip.targets_atom = XInternAtom(This->display, "TARGETS", False);
	This->xclip.timestamp_atom = XInternAtom(This->display, "TIMESTAMP", False);
	This->xclip.rdesktop_clipboard_target_atom =
		XInternAtom(This->display, "_RDESKTOP_CLIPBOARD_TARGET", False);
	This->xclip.rdesktop_primary_timestamp_target_atom =
		XInternAtom(This->display, "_RDESKTOP_PRIMARY_TIMESTAMP_TARGET", False);
	This->xclip.rdesktop_clipboard_timestamp_target_atom =
		XInternAtom(This->display, "_RDESKTOP_CLIPBOARD_TIMESTAMP_TARGET", False);
	This->xclip.incr_atom = XInternAtom(This->display, "INCR", False);
	This->xclip.format_string_atom = XInternAtom(This->display, "STRING", False);
	This->xclip.format_utf8_string_atom = XInternAtom(This->display, "UTF8_STRING", False);
	This->xclip.format_unicode_atom = XInternAtom(This->display, "text/unicode", False);

	/* rdesktop sets _RDESKTOP_SELECTION_NOTIFY on the root window when acquiring the clipboard.
	   Other interested rdesktops can use this to notify their server of the available formats. */
	This->xclip.rdesktop_selection_notify_atom =
		XInternAtom(This->display, "_RDESKTOP_SELECTION_NOTIFY", False);
	XSelectInput(This->display, DefaultRootWindow(This->display), PropertyChangeMask);
	This->xclip.probing_selections = False;

	This->xclip.rdesktop_native_atom = XInternAtom(This->display, "_RDESKTOP_NATIVE", False);
	This->xclip.rdesktop_clipboard_formats_atom =
		XInternAtom(This->display, "_RDESKTOP_CLIPBOARD_FORMATS", False);
	This->xclip.rdesktop_primary_owner_atom = XInternAtom(This->display, "_RDESKTOP_PRIMARY_OWNER", False);
	This->xclip.rdesktop_clipboard_owner_atom = XInternAtom(This->display, "_RDESKTOP_CLIPBOARD_OWNER", False);

	This->xclip.num_targets = 0;
	This->xclip.targets[This->xclip.num_targets++] = This->xclip.targets_atom;
	This->xclip.targets[This->xclip.num_targets++] = This->xclip.timestamp_atom;
	This->xclip.targets[This->xclip.num_targets++] = This->xclip.rdesktop_native_atom;
	This->xclip.targets[This->xclip.num_targets++] = This->xclip.rdesktop_clipboard_formats_atom;
#ifdef USE_UNICODE_CLIPBOARD
	This->xclip.targets[This->xclip.num_targets++] = This->xclip.format_utf8_string_atom;
#endif
	This->xclip.targets[This->xclip.num_targets++] = This->xclip.format_unicode_atom;
	This->xclip.targets[This->xclip.num_targets++] = This->xclip.format_string_atom;
	This->xclip.targets[This->xclip.num_targets++] = XA_STRING;
}

void
xclip_deinit(RDPCLIENT * This)
{
	if (XGetSelectionOwner(This->display, This->xclip.primary_atom) == This->wnd)
		XSetSelectionOwner(This->display, This->xclip.primary_atom, None, This->xclip.acquire_time);
	if (XGetSelectionOwner(This->display, This->xclip.clipboard_atom) == This->wnd)
		XSetSelectionOwner(This->display, This->xclip.clipboard_atom, None, This->xclip.acquire_time);
	xclip_notify_change(This);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -