📄 gdkselection-win32.c
字号:
/* GDK - The GIMP Drawing Kit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * Copyright (C) 1998-2002 Tor Lillqvist * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. *//* * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS * file for a list of people on the GTK+ Team. See the ChangeLog * files for a list of changes. These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */#include <config.h>#include <string.h>#include <stdlib.h>#include "gdkproperty.h"#include "gdkselection.h"#include "gdkdisplay.h"#include "gdkprivate-win32.h"/* We emulate the GDK_SELECTION window properties of windows (as used * in the X11 backend) by using a hash table from GdkWindows to * GdkSelProp structs. */typedef struct { guchar *data; gsize length; gint format; GdkAtom type;} GdkSelProp;static GHashTable *sel_prop_table = NULL;static GdkSelProp *dropfiles_prop = NULL;/* We store the owner of each selection in this table. Obviously, this only * is valid intra-app, and in fact it is necessary for the intra-app DND to work. */static GHashTable *sel_owner_table = NULL;void_gdk_win32_selection_init (void){ sel_prop_table = g_hash_table_new (NULL, NULL); sel_owner_table = g_hash_table_new (NULL, NULL); _format_atom_table = g_hash_table_new (NULL, NULL);}/* The specifications for COMPOUND_TEXT and STRING specify that C0 and * C1 are not allowed except for \n and \t, however the X conversions * routines for COMPOUND_TEXT only enforce this in one direction, * causing cut-and-paste of \r and \r\n separated text to fail. * This routine strips out all non-allowed C0 and C1 characters * from the input string and also canonicalizes \r, and \r\n to \n */static gchar * sanitize_utf8 (const gchar *src, gint length){ GString *result = g_string_sized_new (length + 1); const gchar *p = src; const gchar *endp = src + length; while (p < endp) { if (*p == '\r') { p++; if (*p == '\n') p++; g_string_append_c (result, '\n'); } else { gunichar ch = g_utf8_get_char (p); char buf[7]; gint buflen; if (!((ch < 0x20 && ch != '\t' && ch != '\n') || (ch >= 0x7f && ch < 0xa0))) { buflen = g_unichar_to_utf8 (ch, buf); g_string_append_len (result, buf, buflen); } p = g_utf8_next_char (p); } } g_string_append_c (result, '\0'); return g_string_free (result, FALSE);}static gchar *_gdk_utf8_to_string_target_internal (const gchar *str, gint length){ GError *error = NULL; gchar *tmp_str = sanitize_utf8 (str, length); gchar *result = g_convert_with_fallback (tmp_str, -1, "ISO-8859-1", "UTF-8", NULL, NULL, NULL, &error); if (!result) { g_warning ("Error converting from UTF-8 to STRING: %s", error->message); g_error_free (error); } g_free (tmp_str); return result;}static void_gdk_selection_property_store (GdkWindow *owner, GdkAtom type, gint format, guchar *data, gint length){ GdkSelProp *prop; GSList *prop_list; prop = g_new (GdkSelProp, 1); if (type == GDK_TARGET_STRING) { /* We know that data is UTF-8 */ prop->data = _gdk_utf8_to_string_target_internal (data, length); g_free (data); if (!prop->data) { g_free (prop); return; } else prop->length = strlen (prop->data) + 1; } else { prop->data = data; prop->length = length; } prop->format = format; prop->type = type; prop_list = g_hash_table_lookup (sel_prop_table, GDK_WINDOW_HWND (owner)); prop_list = g_slist_append (prop_list, prop); g_hash_table_insert (sel_prop_table, GDK_WINDOW_HWND (owner), prop_list);}void_gdk_dropfiles_store (gchar *data){ if (data != NULL) { g_assert (dropfiles_prop == NULL); dropfiles_prop = g_new (GdkSelProp, 1); dropfiles_prop->data = data; dropfiles_prop->length = strlen (data) + 1; dropfiles_prop->format = 8; dropfiles_prop->type = _text_uri_list; } else { if (dropfiles_prop != NULL) { g_free (dropfiles_prop->data); g_free (dropfiles_prop); } dropfiles_prop = NULL; }}gbooleangdk_selection_owner_set_for_display (GdkDisplay *display, GdkWindow *owner, GdkAtom selection, guint32 time, gboolean send_event){ HWND hwnd; GdkEvent tmp_event; gchar *sel_name; g_return_val_if_fail (display == _gdk_display, FALSE); g_return_val_if_fail (selection != GDK_NONE, FALSE); GDK_NOTE (DND, (sel_name = gdk_atom_name (selection), g_print ("gdk_selection_owner_set: %p %#x (%s)\n", (owner ? GDK_WINDOW_HWND (owner) : NULL), (guint) selection, sel_name), g_free (sel_name))); if (selection != GDK_SELECTION_CLIPBOARD) { if (owner != NULL) g_hash_table_insert (sel_owner_table, selection, GDK_WINDOW_HWND (owner)); else g_hash_table_remove (sel_owner_table, selection); return TRUE; } /* Rest of this function handles the CLIPBOARD selection */ if (owner != NULL) { if (GDK_WINDOW_DESTROYED (owner)) return FALSE; hwnd = GDK_WINDOW_HWND (owner); } else hwnd = NULL; if (!API_CALL (OpenClipboard, (hwnd))) return FALSE; _ignore_destroy_clipboard = TRUE; if (!API_CALL (EmptyClipboard, ())) { _ignore_destroy_clipboard = FALSE; API_CALL (CloseClipboard, ()); return FALSE; } _ignore_destroy_clipboard = FALSE; if (!API_CALL (CloseClipboard, ())) return FALSE; if (owner != NULL) { /* Send ourselves a selection request message so that * gdk_property_change will be called to store the clipboard * data. */ GDK_NOTE (DND, g_print ("...sending GDK_SELECTION_REQUEST to ourselves\n")); tmp_event.selection.type = GDK_SELECTION_REQUEST; tmp_event.selection.window = owner; tmp_event.selection.send_event = FALSE; tmp_event.selection.selection = selection; tmp_event.selection.target = _utf8_string; tmp_event.selection.property = _gdk_selection_property; tmp_event.selection.requestor = (guint32) hwnd; tmp_event.selection.time = time; gdk_event_put (&tmp_event); } return TRUE;}GdkWindow*gdk_selection_owner_get_for_display (GdkDisplay *display, GdkAtom selection){ GdkWindow *window; gchar *sel_name; g_return_val_if_fail (display == _gdk_display, NULL); g_return_val_if_fail (selection != GDK_NONE, NULL); /* Return NULL for CLIPBOARD, because otherwise cut&paste inside the * same application doesn't work. We must pretend to gtk that we * don't have the selection, so that we always fetch it from the * Windows clipboard. See also comments in * gdk_selection_send_notify(). */ if (selection == GDK_SELECTION_CLIPBOARD) return NULL; window = gdk_window_lookup ((GdkNativeWindow) g_hash_table_lookup (sel_owner_table, selection)); GDK_NOTE (DND, (sel_name = gdk_atom_name (selection), g_print ("gdk_selection_owner_get: %#x (%s) = %p\n", (guint) selection, sel_name, (window ? GDK_WINDOW_HWND (window) : NULL)), g_free (sel_name))); return window;}static voidgenerate_selection_notify (GdkWindow *requestor, GdkAtom selection, GdkAtom target, GdkAtom property, guint32 time){ GdkEvent tmp_event; tmp_event.selection.type = GDK_SELECTION_NOTIFY; tmp_event.selection.window = requestor; tmp_event.selection.send_event = FALSE; tmp_event.selection.selection = selection; tmp_event.selection.target = target; tmp_event.selection.property = property; tmp_event.selection.requestor = 0; tmp_event.selection.time = time; gdk_event_put (&tmp_event);}voidgdk_selection_convert (GdkWindow *requestor, GdkAtom selection, GdkAtom target, guint32 time){ HGLOBAL hdata; GdkAtom property = _gdk_selection_property; gchar *sel_name, *tgt_name; GError *error = NULL; g_return_if_fail (selection != GDK_NONE); g_return_if_fail (requestor != NULL); if (GDK_WINDOW_DESTROYED (requestor)) return; GDK_NOTE (DND, (sel_name = gdk_atom_name (selection), tgt_name = gdk_atom_name (target), g_print ("gdk_selection_convert: %p %#x (%s) %#x (%s)\n", GDK_WINDOW_HWND (requestor), (guint) selection, sel_name, (guint) target, tgt_name), g_free (sel_name), g_free (tgt_name))); if (selection == GDK_SELECTION_CLIPBOARD && target == _targets) { gint formats_cnt, i, fmt; GdkAtom *data; gboolean has_bmp = FALSE; /* He wants to know what formats are on the clipboard. If there * is some kind of text, tell him so. */ if (!API_CALL (OpenClipboard, (GDK_WINDOW_HWND (requestor)))) return; formats_cnt = CountClipboardFormats (); data = g_new (GdkAtom, formats_cnt + 2); i = 0; if (IsClipboardFormatAvailable (CF_UNICODETEXT) || IsClipboardFormatAvailable (_cf_utf8_string) || IsClipboardFormatAvailable (CF_TEXT)) { data[i++] = _utf8_string; } if (formats_cnt > 0) { /* If there is anything else in the clipboard, enum it all * although we don't offer special conversion services. */ for (fmt = 0; 0 != (fmt = EnumClipboardFormats (fmt)); ) { gchar sFormat[80]; if (GetClipboardFormatName (fmt, sFormat, 80) > 0 && strcmp (sFormat, "UTF8_STRING")) { GdkAtom atom; if (!has_bmp && (!strcmp (sFormat, "image/bmp") || !strcmp (sFormat, "image/x-bmp") || !strcmp (sFormat, "image/x-MS-bmp"))) has_bmp = TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -