]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkselection.c
re-adding for manual rename of repository files.
[~andy/gtk] / gdk / win32 / gdkselection.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 "gdkx.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_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 (SELECTION,
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 (SELECTION, g_print ("...OpenClipboard(%#x)\n", xwindow));
102   if (!OpenClipboard (xwindow))
103     {
104       g_warning ("gdk_selection_owner_set: OpenClipboard failed");
105       return FALSE;
106     }
107   GDK_NOTE (SELECTION, g_print ("...EmptyClipboard()\n"));
108   if (!EmptyClipboard ())
109     {
110       g_warning ("gdk_selection_owner_set: EmptyClipboard failed");
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 (SELECTION, g_print ("...CloseClipboard()\n"));
120   if (!CloseClipboard ())
121     {
122       g_warning ("gdk_selection_owner_set: CloseClipboard failed");
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 (SELECTION,
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 (SELECTION,
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 (SELECTION, g_print ("...OpenClipboard(%#x)\n",
198                                     GDK_DRAWABLE_XID (requestor)));
199       if (!OpenClipboard (GDK_DRAWABLE_XID (requestor)))
200         {
201           g_warning ("gdk_selection_convert: OpenClipboard failed");
202           return;
203         }
204
205       GDK_NOTE (SELECTION, 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 (SELECTION, 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 (SELECTION, 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, &gdk_root_parent->drawable.xwindow);
261
262       if (prop != NULL)
263         {
264           g_hash_table_remove (sel_prop_table, &gdk_root_parent->drawable.xwindow);
265           gdk_sel_prop_store (requestor, prop->type, prop->format,
266                               prop->data, prop->length);
267           g_free (prop);
268           SendMessage (GDK_DRAWABLE_XID (requestor), gdk_selection_notify_msg, selection, target);
269         }
270     }
271   else
272     {
273       g_warning ("gdk_selection_convert: General case not implemented");
274     }
275 }
276
277 gint
278 gdk_selection_property_get (GdkWindow  *requestor,
279                             guchar    **data,
280                             GdkAtom    *ret_type,
281                             gint       *ret_format)
282 {
283   GdkSelProp *prop;
284
285   g_return_val_if_fail (requestor != NULL, 0);
286   g_return_val_if_fail (GDK_IS_WINDOW (requestor), 0);
287
288   if (GDK_DRAWABLE_DESTROYED (requestor))
289     return 0;
290   
291   GDK_NOTE (SELECTION, g_print ("gdk_selection_property_get: %#x\n",
292                                 GDK_DRAWABLE_XID (requestor)));
293
294   prop = g_hash_table_lookup (sel_prop_table, &GDK_DRAWABLE_XID (requestor));
295
296   if (prop == NULL)
297     {
298       *data = NULL;
299       return 0;
300     }
301   *data = g_malloc (prop->length);
302   if (prop->length > 0)
303     memmove (*data, prop->data, prop->length);
304   if (ret_type)
305     *ret_type = prop->type;
306   if (ret_format)
307     *ret_format = prop->format;
308
309   return prop->length;
310 }
311
312 void
313 gdk_selection_property_delete (GdkWindow *window)
314 {
315   GdkSelProp *prop;
316   
317   prop = g_hash_table_lookup (sel_prop_table, &GDK_DRAWABLE_XID (window));
318   if (prop != NULL)
319     {
320       g_free (prop->data);
321       g_hash_table_remove (sel_prop_table, &GDK_DRAWABLE_XID (window));
322     }
323   else
324     g_warning ("huh?");
325 }
326
327 void
328 gdk_selection_send_notify (guint32  requestor,
329                            GdkAtom  selection,
330                            GdkAtom  target,
331                            GdkAtom  property,
332                            guint32  time)
333 {
334   gchar *sel_name, *tgt_name, *prop_name;
335
336   GDK_NOTE (SELECTION,
337             (sel_name = gdk_atom_name (selection),
338              tgt_name = gdk_atom_name (target),
339              prop_name = gdk_atom_name (property),
340              g_print ("gdk_selection_send_notify: %#x %#x (%s) %#x (%s) %#x (%s)\n",
341                       requestor,
342                       selection, sel_name,
343                       target, tgt_name,
344                       property, prop_name),
345              g_free (sel_name),
346              g_free (tgt_name),
347              g_free (prop_name)));
348
349   /* Send ourselves a selection clear message so that gtk thinks we don't
350    * have the selection, and will claim it anew when needed, and
351    * we thus get a chance to store data in the Windows clipboard.
352    * Otherwise, if a gtkeditable does a copy to clipboard several times
353    * only the first one actually gets copied to the Windows clipboard,
354    * as only he first one causes a call to gdk_property_change.
355    *
356    * Hmm, there is something fishy with this. Cut and paste inside the
357    * same app didn't work, the gtkeditable immediately forgot the
358    * clipboard contents in gtk_editable_selection_clear as a result of
359    * this message. OTOH, when I changed gdk_selection_owner_get to
360    * always return NULL, it works. Sigh.
361    */
362
363   SendMessage ((HWND) requestor, gdk_selection_clear_msg, selection, 0);
364 }
365
366 gint
367 gdk_text_property_to_text_list (GdkAtom  encoding,
368                                 gint     format, 
369                                 guchar  *text,
370                                 gint     length,
371                                 gchar ***list)
372 {
373   GDK_NOTE (SELECTION,
374             g_print ("gdk_text_property_to_text_list not implemented\n"));
375   
376   return 0;
377 }
378
379 void
380 gdk_free_text_list (gchar **list)
381 {
382   g_return_if_fail (list != NULL);
383
384   /* ??? */
385 }
386
387 gint
388 gdk_string_to_compound_text (gchar   *str,
389                              GdkAtom *encoding,
390                              gint    *format,
391                              guchar **ctext,
392                              gint    *length)
393 {
394   g_warning ("gdk_string_to_compound_text: Not implemented");
395
396   return 0;
397 }
398
399 void
400 gdk_free_compound_text (guchar *ctext)
401 {
402   g_warning ("gdk_free_compound_text: Not implemented");
403 }