]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkselection-win32.c
94b66fa5b847b5f126b667904834d2c61e70946e
[~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 "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   GdkWindowPrivate *private = (GdkWindowPrivate *) owner;
62   GdkSelProp *prop;
63
64   prop = g_hash_table_lookup (sel_prop_table, &private->xwindow);
65   if (prop != NULL)
66     {
67       g_free (prop->data);
68       g_hash_table_remove (sel_prop_table, &private->xwindow);
69     }
70   prop = g_new (GdkSelProp, 1);
71   prop->data = data;
72   prop->length = length;
73   prop->format = format;
74   prop->type = type;
75   g_hash_table_insert (sel_prop_table, &private->xwindow, prop);
76 }
77   
78
79 gint
80 gdk_selection_owner_set (GdkWindow *owner,
81                          GdkAtom    selection,
82                          guint32    time,
83                          gint       send_event)
84 {
85   GdkWindowPrivate *private;
86   gchar *sel_name;
87   HWND xwindow;
88
89   private = (GdkWindowPrivate *) owner;
90
91   GDK_NOTE (SELECTION,
92             (sel_name = gdk_atom_name (selection),
93              g_print ("gdk_selection_owner_set: %#x %#x (%s)\n",
94                       (private ? private->xwindow : 0),
95                       selection, sel_name),
96              g_free (sel_name)));
97
98   if (selection != gdk_clipboard_atom)
99     return FALSE;
100
101   if (owner != NULL)
102     xwindow = private->xwindow;
103   else
104     xwindow = NULL;
105
106   if (!OpenClipboard (xwindow))
107     {
108       g_warning ("gdk_selection_owner_set: OpenClipboard failed");
109       return FALSE;
110     }
111   if (!EmptyClipboard ())
112     {
113       g_warning ("gdk_selection_owner_set: EmptyClipboard failed");
114       CloseClipboard ();
115       return FALSE;
116     }
117 #if 0
118   /* No delayed rendering */
119   if (xwindow != NULL)
120     SetClipboardData (CF_TEXT, NULL);
121 #endif
122   if (!CloseClipboard ())
123     {
124       g_warning ("gdk_selection_owner_set: CloseClipboard failed");
125       return FALSE;
126     }
127   if (owner != NULL)
128     {
129       /* Send ourselves an ersatz selection request message so that
130        * gdk_property_change will be called to store the clipboard data.
131        */
132       SendMessage (private->xwindow, gdk_selection_request_msg,
133                    selection, 0);
134     }
135
136   return TRUE;
137 }
138
139 GdkWindow*
140 gdk_selection_owner_get (GdkAtom selection)
141 {
142   GdkWindow *window;
143   GdkWindowPrivate *private;
144   gchar *sel_name;
145
146   if (selection != gdk_clipboard_atom)
147     window = NULL;
148   else
149     window = gdk_window_lookup (GetClipboardOwner ());
150
151   private = (GdkWindowPrivate *) window;
152
153   GDK_NOTE (SELECTION,
154             (sel_name = gdk_atom_name (selection),
155              g_print ("gdk_selection_owner_get: %#x (%s) = %#x\n",
156                       selection, sel_name,
157                       (private ? private->xwindow : 0)),
158              g_free (sel_name)));
159
160   return window;
161 }
162
163 void
164 gdk_selection_convert (GdkWindow *requestor,
165                        GdkAtom    selection,
166                        GdkAtom    target,
167                        guint32    time)
168 {
169   GdkWindowPrivate *private;
170   HGLOBAL hdata;
171   GdkSelProp *prop;
172   guchar *ptr, *data, *datap, *p;
173   guint i, length, slength;
174   gchar *sel_name, *tgt_name;
175
176   g_return_if_fail (requestor != NULL);
177
178   private = (GdkWindowPrivate*) requestor;
179
180   GDK_NOTE (SELECTION,
181             (sel_name = gdk_atom_name (selection),
182              tgt_name = gdk_atom_name (target),
183              g_print ("gdk_selection_convert: %#x %#x (%s) %#x (%s)\n",
184                       private->xwindow, selection, sel_name, target, tgt_name),
185              g_free (sel_name),
186              g_free (tgt_name)));
187
188   if (selection == gdk_clipboard_atom)
189     {
190       /* Converting the CLIPBOARD selection means he wants the
191        * contents of the clipboard. Get the clipboard data,
192        * and store it for later.
193        */
194       if (!OpenClipboard (private->xwindow))
195         {
196           g_warning ("gdk_selection_convert: OpenClipboard failed");
197           return;
198         }
199
200       if ((hdata = GetClipboardData (CF_TEXT)) != NULL)
201         {
202           if ((ptr = GlobalLock (hdata)) != NULL)
203             {
204               length = GlobalSize (hdata);
205               
206               GDK_NOTE (SELECTION, g_print ("...got data: %d bytes: %.10s\n",
207                                             length, ptr));
208               
209               slength = 0;
210               p = ptr;
211               for (i = 0; i < length; i++)
212                 {
213                   if (*p == '\0')
214                     break;
215                   else if (*p != '\r')
216                     slength++;
217                   p++;
218                 }
219               
220               data = datap = g_malloc (slength + 1);
221               p = ptr;
222               for (i = 0; i < length; i++)
223                 {
224                   if (*p == '\0')
225                     break;
226                   else if (*p != '\r')
227                     *datap++ = *p;
228                   p++;
229                 }
230               *datap++ = '\0';
231               gdk_sel_prop_store (requestor, GDK_TARGET_STRING, 8,
232                                   data, strlen (data) + 1);
233               
234               GlobalUnlock (hdata);
235             }
236         }
237       CloseClipboard ();
238
239
240       /* Send ourselves an ersatz selection notify message so that we actually
241        * fetch the data.
242        */
243       SendMessage (private->xwindow, gdk_selection_notify_msg, selection, target);
244     }
245   else if (selection == gdk_win32_dropfiles_atom)
246     {
247       /* This means he wants the names of the dropped files.
248        * gdk_dropfiles_filter already has stored the text/uri-list
249        * data, tempoarily on gdk_root_parent's selection "property".
250        */
251       GdkSelProp *prop;
252
253       prop = g_hash_table_lookup (sel_prop_table, &gdk_root_parent.xwindow);
254
255       if (prop != NULL)
256         {
257           g_hash_table_remove (sel_prop_table, &gdk_root_parent.xwindow);
258           gdk_sel_prop_store (requestor, prop->type, prop->format,
259                               prop->data, prop->length);
260           g_free (prop);
261           SendMessage (private->xwindow, gdk_selection_notify_msg, selection, target);
262         }
263     }
264   else
265     {
266       g_warning ("gdk_selection_convert: General case not implemented");
267     }
268 }
269
270 gint
271 gdk_selection_property_get (GdkWindow  *requestor,
272                             guchar    **data,
273                             GdkAtom    *ret_type,
274                             gint       *ret_format)
275 {
276   GdkWindowPrivate *private;
277   GdkSelProp *prop;
278
279   g_return_val_if_fail (requestor != NULL, 0);
280
281   private = (GdkWindowPrivate*) requestor;
282   if (private->destroyed)
283     return 0;
284   
285   GDK_NOTE (SELECTION, g_print ("gdk_selection_property_get: %#x\n",
286                                 private->xwindow));
287
288   prop = g_hash_table_lookup (sel_prop_table, &private->xwindow);
289
290   if (prop == NULL)
291     {
292       *data = NULL;
293       return 0;
294     }
295   *data = g_malloc (prop->length);
296   if (prop->length > 0)
297     memmove (*data, prop->data, prop->length);
298   if (ret_type)
299     *ret_type = prop->type;
300   if (ret_format)
301     *ret_format = prop->format;
302
303   return prop->length;
304 }
305
306 void
307 gdk_selection_property_delete (GdkWindowPrivate *private)
308 {
309   GdkSelProp *prop;
310   
311   prop = g_hash_table_lookup (sel_prop_table, &private->xwindow);
312   if (prop != NULL)
313     {
314       g_free (prop->data);
315       g_hash_table_remove (sel_prop_table, &private->xwindow);
316     }
317   else
318     g_warning ("huh?");
319 }
320
321 void
322 gdk_selection_send_notify (guint32  requestor,
323                            GdkAtom  selection,
324                            GdkAtom  target,
325                            GdkAtom  property,
326                            guint32  time)
327 {
328   gchar *sel_name, *tgt_name, *prop_name;
329
330   GDK_NOTE (SELECTION,
331             (sel_name = gdk_atom_name (selection),
332              tgt_name = gdk_atom_name (target),
333              prop_name = gdk_atom_name (property),
334              g_print ("gdk_selection_send_notify: %#x %#x (%s) %#x (%s) %#x (%s)\n",
335                       requestor,
336                       selection, sel_name,
337                       target, tgt_name,
338                       property, prop_name),
339              g_free (sel_name),
340              g_free (tgt_name),
341              g_free (prop_name)));
342
343   /* Send ourselves a selection clear message sot that gtk thinks we doen't
344    * have the selection, and will claim it anew when needed, and
345    * we thus get a chance to store data in the Windows clipboard.
346    * Otherwise, if a gtkeditable does a copy to clipboard several times
347    * only the first one actually gets copied to the Windows clipboard,
348    * as only he first one causes a call to gdk_property_change.
349    */
350
351   SendMessage ((HWND) requestor, gdk_selection_clear_msg, selection, 0);
352 }
353
354 gint
355 gdk_text_property_to_text_list (GdkAtom  encoding,
356                                 gint     format, 
357                                 guchar  *text,
358                                 gint     length,
359                                 gchar ***list)
360 {
361   GDK_NOTE (SELECTION,
362             g_print ("gdk_text_property_to_text_list not implemented\n"));
363   
364   return 0;
365 }
366
367 void
368 gdk_free_text_list (gchar **list)
369 {
370   g_return_if_fail (list != NULL);
371
372   /* ??? */
373 }
374
375 gint
376 gdk_string_to_compound_text (gchar   *str,
377                              GdkAtom *encoding,
378                              gint    *format,
379                              guchar **ctext,
380                              gint    *length)
381 {
382   g_warning ("gdk_string_to_compound_text: Not implemented");
383
384   return 0;
385 }
386
387 void
388 gdk_free_compound_text (guchar *ctext)
389 {
390   g_warning ("gdk_free_compound_text: Not implemented");
391 }