]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkselection-win32.c
2767ac0e9f094fa9ec9127fa319ec725547298e3
[~andy/gtk] / gdk / win32 / gdkselection-win32.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28
29 #include <string.h>
30
31 #include <gdk/gdk.h>
32 #include "gdkwin32.h"
33
34 /* We emulate the GDK_SELECTION window properties by storing
35  * it's data in a per-window hashtable.
36  */
37
38 typedef struct {
39   guchar *data;
40   gint length;
41   gint format;
42   GdkAtom type;
43 } GdkSelProp;
44
45 static GHashTable *sel_prop_table = NULL;
46
47 void
48 gdk_win32_selection_init (void)
49 {
50   if (sel_prop_table == NULL)
51     sel_prop_table = g_hash_table_new (g_int_hash, g_int_equal);
52 }
53
54 void
55 gdk_sel_prop_store (GdkWindow *owner,
56                     GdkAtom    type,
57                     gint       format,
58                     guchar    *data,
59                     gint       length)
60 {
61   GdkSelProp *prop;
62
63   prop = g_hash_table_lookup (sel_prop_table, &GDK_DRAWABLE_XID (owner));
64   if (prop != NULL)
65     {
66       g_free (prop->data);
67       g_hash_table_remove (sel_prop_table, &GDK_DRAWABLE_XID (owner));
68     }
69   prop = g_new (GdkSelProp, 1);
70   prop->data = data;
71   prop->length = length;
72   prop->format = format;
73   prop->type = type;
74   g_hash_table_insert (sel_prop_table, &GDK_DRAWABLE_XID (owner), prop);
75 }
76
77 gint
78 gdk_selection_owner_set (GdkWindow *owner,
79                          GdkAtom    selection,
80                          guint32    time,
81                          gint       send_event)
82 {
83   gchar *sel_name;
84   HWND xwindow;
85
86   GDK_NOTE (MISC,
87             (sel_name = gdk_atom_name (selection),
88              g_print ("gdk_selection_owner_set: %#x %#x (%s)\n",
89                       (owner ? GDK_DRAWABLE_XID (owner) : 0),
90                       selection, sel_name),
91              g_free (sel_name)));
92
93   if (selection != gdk_clipboard_atom)
94     return FALSE;
95
96   if (owner != NULL)
97     xwindow = GDK_DRAWABLE_XID (owner);
98   else
99     xwindow = NULL;
100
101   GDK_NOTE (MISC, g_print ("...OpenClipboard(%#x)\n", xwindow));
102   if (!OpenClipboard (xwindow))
103     {
104       WIN32_API_FAILED ("OpenClipboard");
105       return FALSE;
106     }
107   GDK_NOTE (MISC, g_print ("...EmptyClipboard()\n"));
108   if (!EmptyClipboard ())
109     {
110       WIN32_API_FAILED ("EmptyClipboard");
111       CloseClipboard ();
112       return FALSE;
113     }
114 #if 0
115   /* No delayed rendering */
116   if (xwindow != NULL)
117     SetClipboardData (CF_TEXT, NULL);
118 #endif
119   GDK_NOTE (MISC, g_print ("...CloseClipboard()\n"));
120   if (!CloseClipboard ())
121     {
122       WIN32_API_FAILED ("CloseClipboard");
123       return FALSE;
124     }
125   if (owner != NULL)
126     {
127       /* Send ourselves an ersatz selection request message so that
128        * gdk_property_change will be called to store the clipboard data.
129        */
130       SendMessage (xwindow, gdk_selection_request_msg,
131                    selection, 0);
132     }
133
134   return TRUE;
135 }
136
137 GdkWindow*
138 gdk_selection_owner_get (GdkAtom selection)
139 {
140   GdkWindow *window;
141   gchar *sel_name;
142
143 #if 1
144   /* XXX Hmm, gtk selections seem to work best with this. This causes
145    * gtk to always get the clipboard contents from Windows, and not
146    * from the editable's own stashed-away copy.
147    */
148   return NULL;
149 #else
150   if (selection != gdk_clipboard_atom)
151     window = NULL;
152   else
153     window = gdk_window_lookup (GetClipboardOwner ());
154
155 #endif
156
157   GDK_NOTE (MISC,
158             (sel_name = gdk_atom_name (selection),
159              g_print ("gdk_selection_owner_get: %#x (%s) = %#x\n",
160                       selection, sel_name,
161                       (window ? GDK_DRAWABLE_XID (window) : 0)),
162              g_free (sel_name)));
163
164   return window;
165 }
166
167 void
168 gdk_selection_convert (GdkWindow *requestor,
169                        GdkAtom    selection,
170                        GdkAtom    target,
171                        guint32    time)
172 {
173   HGLOBAL hdata;
174   GdkSelProp *prop;
175   guchar *ptr, *data, *datap, *p;
176   guint i, length, slength;
177   gchar *sel_name, *tgt_name;
178
179   g_return_if_fail (requestor != NULL);
180   if (GDK_DRAWABLE_DESTROYED (requestor))
181     return;
182
183   GDK_NOTE (MISC,
184             (sel_name = gdk_atom_name (selection),
185              tgt_name = gdk_atom_name (target),
186              g_print ("gdk_selection_convert: %#x %#x (%s) %#x (%s)\n",
187                       GDK_DRAWABLE_XID (requestor), selection, sel_name, target, tgt_name),
188              g_free (sel_name),
189              g_free (tgt_name)));
190
191   if (selection == gdk_clipboard_atom)
192     {
193       /* Converting the CLIPBOARD selection means he wants the
194        * contents of the clipboard. Get the clipboard data,
195        * and store it for later.
196        */
197       GDK_NOTE (MISC, g_print ("...OpenClipboard(%#x)\n",
198                                     GDK_DRAWABLE_XID (requestor)));
199       if (!OpenClipboard (GDK_DRAWABLE_XID (requestor)))
200         {
201           WIN32_API_FAILED ("OpenClipboard");
202           return;
203         }
204
205       GDK_NOTE (MISC, g_print ("...GetClipboardData(CF_TEXT)\n"));
206       if ((hdata = GetClipboardData (CF_TEXT)) != NULL)
207         {
208           if ((ptr = GlobalLock (hdata)) != NULL)
209             {
210               length = GlobalSize (hdata);
211               
212               GDK_NOTE (MISC, g_print ("...got data: %d bytes: %.10s\n",
213                                        length, ptr));
214               
215               slength = 0;
216               p = ptr;
217               for (i = 0; i < length; i++)
218                 {
219                   if (*p == '\0')
220                     break;
221                   else if (*p != '\r')
222                     slength++;
223                   p++;
224                 }
225               
226               data = datap = g_malloc (slength + 1);
227               p = ptr;
228               for (i = 0; i < length; i++)
229                 {
230                   if (*p == '\0')
231                     break;
232                   else if (*p != '\r')
233                     *datap++ = *p;
234                   p++;
235                 }
236               *datap++ = '\0';
237               gdk_sel_prop_store (requestor, GDK_TARGET_STRING, 8,
238                                   data, strlen (data) + 1);
239               
240               GlobalUnlock (hdata);
241             }
242         }
243       GDK_NOTE (MISC, g_print ("...CloseClipboard()\n"));
244       CloseClipboard ();
245
246
247       /* Send ourselves an ersatz selection notify message so that we actually
248        * fetch the data.
249        */
250       SendMessage (GDK_DRAWABLE_XID (requestor), gdk_selection_notify_msg, selection, target);
251     }
252   else if (selection == gdk_win32_dropfiles_atom)
253     {
254       /* This means he wants the names of the dropped files.
255        * gdk_dropfiles_filter already has stored the text/uri-list
256        * data, tempoarily on gdk_root_parent's selection "property".
257        */
258       GdkSelProp *prop;
259
260       prop = g_hash_table_lookup (sel_prop_table,
261                                   &GDK_DRAWABLE_XID (gdk_parent_root));
262
263       if (prop != NULL)
264         {
265           g_hash_table_remove (sel_prop_table,
266                                &GDK_DRAWABLE_XID (gdk_parent_root));
267           gdk_sel_prop_store (requestor, prop->type, prop->format,
268                               prop->data, prop->length);
269           g_free (prop);
270           SendMessage (GDK_DRAWABLE_XID (requestor), gdk_selection_notify_msg, selection, target);
271         }
272     }
273   else
274     {
275       g_warning ("gdk_selection_convert: General case not implemented");
276     }
277 }
278
279 gint
280 gdk_selection_property_get (GdkWindow  *requestor,
281                             guchar    **data,
282                             GdkAtom    *ret_type,
283                             gint       *ret_format)
284 {
285   GdkSelProp *prop;
286
287   g_return_val_if_fail (requestor != NULL, 0);
288   g_return_val_if_fail (GDK_IS_WINDOW (requestor), 0);
289
290   if (GDK_DRAWABLE_DESTROYED (requestor))
291     return 0;
292   
293   GDK_NOTE (MISC, g_print ("gdk_selection_property_get: %#x\n",
294                            GDK_DRAWABLE_XID (requestor)));
295
296   prop = g_hash_table_lookup (sel_prop_table, &GDK_DRAWABLE_XID (requestor));
297
298   if (prop == NULL)
299     {
300       *data = NULL;
301       return 0;
302     }
303   *data = g_malloc (prop->length);
304   if (prop->length > 0)
305     memmove (*data, prop->data, prop->length);
306   if (ret_type)
307     *ret_type = prop->type;
308   if (ret_format)
309     *ret_format = prop->format;
310
311   return prop->length;
312 }
313
314 void
315 gdk_selection_property_delete (GdkWindow *window)
316 {
317   GdkSelProp *prop;
318   
319   prop = g_hash_table_lookup (sel_prop_table, &GDK_DRAWABLE_XID (window));
320   if (prop != NULL)
321     {
322       g_free (prop->data);
323       g_hash_table_remove (sel_prop_table, &GDK_DRAWABLE_XID (window));
324     }
325   else
326     g_warning ("huh?");
327 }
328
329 void
330 gdk_selection_send_notify (guint32  requestor,
331                            GdkAtom  selection,
332                            GdkAtom  target,
333                            GdkAtom  property,
334                            guint32  time)
335 {
336   gchar *sel_name, *tgt_name, *prop_name;
337
338   GDK_NOTE (MISC,
339             (sel_name = gdk_atom_name (selection),
340              tgt_name = gdk_atom_name (target),
341              prop_name = gdk_atom_name (property),
342              g_print ("gdk_selection_send_notify: %#x %#x (%s) %#x (%s) %#x (%s)\n",
343                       requestor,
344                       selection, sel_name,
345                       target, tgt_name,
346                       property, prop_name),
347              g_free (sel_name),
348              g_free (tgt_name),
349              g_free (prop_name)));
350
351   /* Send ourselves a selection clear message so that gtk thinks we don't
352    * have the selection, and will claim it anew when needed, and
353    * we thus get a chance to store data in the Windows clipboard.
354    * Otherwise, if a gtkeditable does a copy to clipboard several times
355    * only the first one actually gets copied to the Windows clipboard,
356    * as only he first one causes a call to gdk_property_change.
357    *
358    * Hmm, there is something fishy with this. Cut and paste inside the
359    * same app didn't work, the gtkeditable immediately forgot the
360    * clipboard contents in gtk_editable_selection_clear as a result of
361    * this message. OTOH, when I changed gdk_selection_owner_get to
362    * always return NULL, it works. Sigh.
363    */
364
365   SendMessage ((HWND) requestor, gdk_selection_clear_msg, selection, 0);
366 }
367
368 gint
369 gdk_text_property_to_text_list (GdkAtom       encoding,
370                                 gint          format, 
371                                 const guchar *text,
372                                 gint          length,
373                                 gchar      ***list)
374 {
375   GDK_NOTE (MISC,
376             g_print ("gdk_text_property_to_text_list not implemented\n"));
377   
378   return 0;
379 }
380
381 void
382 gdk_free_text_list (gchar **list)
383 {
384   g_return_if_fail (list != NULL);
385
386   /* ??? */
387 }
388
389 gint
390 gdk_string_to_compound_text (const gchar *str,
391                              GdkAtom     *encoding,
392                              gint        *format,
393                              guchar     **ctext,
394                              gint        *length)
395 {
396   g_warning ("gdk_string_to_compound_text: Not implemented");
397
398   return 0;
399 }
400
401 void
402 gdk_free_compound_text (guchar *ctext)
403 {
404   g_warning ("gdk_free_compound_text: Not implemented");
405 }