OSDN Git Service

* cygerrno.h (__set_errno): Modify debugging output to make searching strace
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / fhandler_clipboard.cc
1 /* fhandler_dev_clipboard: code to access /dev/clipboard
2
3    Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2011 Red Hat, Inc
4
5    Written by Charles Wilson (cwilson@ece.gatech.edu)
6
7 This file is part of Cygwin.
8
9 This software is a copyrighted work licensed under the terms of the
10 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
11 details. */
12
13 #include "winsup.h"
14 #include <wchar.h>
15 #include <wingdi.h>
16 #include <winuser.h>
17 #include "cygerrno.h"
18 #include "path.h"
19 #include "fhandler.h"
20
21 /*
22  * Robert Collins:
23  * FIXME: should we use GetClipboardSequenceNumber to tell if the clipboard has
24  * changed? How does /dev/clipboard operate under (say) linux?
25  */
26
27 static const NO_COPY WCHAR *CYGWIN_NATIVE = L"CYGWIN_NATIVE_CLIPBOARD";
28 /* this is MT safe because windows format id's are atomic */
29 static int cygnativeformat;
30
31 fhandler_dev_clipboard::fhandler_dev_clipboard ()
32   : fhandler_base (), pos (0), membuffer (NULL), msize (0),
33   eof (true)
34 {
35   /* FIXME: check for errors and loop until we can open the clipboard */
36   OpenClipboard (NULL);
37   cygnativeformat = RegisterClipboardFormatW (CYGWIN_NATIVE);
38   CloseClipboard ();
39 }
40
41 /*
42  * Special clipboard dup to duplicate input and output
43  * handles.
44  */
45
46 int
47 fhandler_dev_clipboard::dup (fhandler_base * child, int)
48 {
49   fhandler_dev_clipboard *fhc = (fhandler_dev_clipboard *) child;
50
51   if (!fhc->open (get_flags (), 0))
52     system_printf ("error opening clipboard, %E");
53   return 0;
54 }
55
56 int
57 fhandler_dev_clipboard::open (int flags, mode_t)
58 {
59   set_flags (flags | O_TEXT);
60   eof = false;
61   pos = 0;
62   if (membuffer)
63     free (membuffer);
64   membuffer = NULL;
65   if (!cygnativeformat)
66     cygnativeformat = RegisterClipboardFormatW (CYGWIN_NATIVE);
67   nohandle (true);
68   set_open_status ();
69   return 1;
70 }
71
72 static int
73 set_clipboard (const void *buf, size_t len)
74 {
75   HGLOBAL hmem;
76   void *clipbuf;
77   /* Native CYGWIN format */
78   if (OpenClipboard (NULL))
79     {
80       hmem = GlobalAlloc (GMEM_MOVEABLE, len + sizeof (size_t));
81       if (!hmem)
82         {
83           __seterrno ();
84           CloseClipboard ();
85           return -1;
86         }
87       clipbuf = GlobalLock (hmem);
88       memcpy ((unsigned char *) clipbuf + sizeof (size_t), buf, len);
89       *(size_t *) (clipbuf) = len;
90       GlobalUnlock (hmem);
91       EmptyClipboard ();
92       if (!cygnativeformat)
93         cygnativeformat = RegisterClipboardFormatW (CYGWIN_NATIVE);
94       HANDLE ret = SetClipboardData (cygnativeformat, hmem);
95       CloseClipboard ();
96       /* According to MSDN, hmem must not be free'd after transferring the
97          data to the clipboard via SetClipboardData. */
98       /* GlobalFree (hmem); */
99       if (!ret)
100         {
101           __seterrno ();
102           return -1;
103         }
104     }
105
106   /* CF_TEXT/CF_OEMTEXT for copying to wordpad and the like */
107   len = sys_mbstowcs (NULL, 0, (const char *) buf, len);
108   if (!len)
109     {
110       set_errno (EILSEQ);
111       return -1;
112     }
113   if (OpenClipboard (NULL))
114     {
115       hmem = GlobalAlloc (GMEM_MOVEABLE, (len + 1) * sizeof (WCHAR));
116       if (!hmem)
117         {
118           __seterrno ();
119           CloseClipboard ();
120           return -1;
121         }
122       clipbuf = GlobalLock (hmem);
123       sys_mbstowcs ((PWCHAR) clipbuf, len + 1, (const char *) buf);
124       GlobalUnlock (hmem);
125       HANDLE ret = SetClipboardData (CF_UNICODETEXT, hmem);
126       CloseClipboard ();
127       /* According to MSDN, hmem must not be free'd after transferring the
128          data to the clipboard via SetClipboardData. */
129       /* GlobalFree (hmem); */
130       if (!ret)
131         {
132           __seterrno ();
133           return -1;
134         }
135     }
136   return 0;
137 }
138
139 /* FIXME: arbitrary seeking is not handled */
140 ssize_t __stdcall
141 fhandler_dev_clipboard::write (const void *buf, size_t len)
142 {
143   if (!eof)
144     {
145       /* write to our membuffer */
146       size_t cursize = msize;
147       void *tempbuffer = realloc (membuffer, cursize + len);
148       if (!tempbuffer)
149         {
150           debug_printf ("Couldn't realloc() clipboard buffer for write");
151           return -1;
152         }
153       membuffer = tempbuffer;
154       msize = cursize + len;
155       memcpy ((unsigned char *) membuffer + cursize, buf, len);
156
157       /* now pass to windows */
158       if (set_clipboard (membuffer, msize))
159         {
160           /* FIXME: membuffer is now out of sync with pos, but msize
161                     is used above */
162           return -1;
163         }
164
165       pos = msize;
166
167       eof = false;
168       return len;
169     }
170   else
171     {
172       /* FIXME: return 0 bytes written, file not open */
173       return 0;
174     }
175 }
176
177 void __stdcall
178 fhandler_dev_clipboard::read (void *ptr, size_t& len)
179 {
180   HGLOBAL hglb;
181   size_t ret;
182   UINT formatlist[2];
183   int format;
184   size_t plen = len;
185
186   len = 0;
187   if (eof)
188     return;
189   if (!OpenClipboard (NULL))
190     return;
191   formatlist[0] = cygnativeformat;
192   formatlist[1] = CF_UNICODETEXT;
193   if ((format = GetPriorityClipboardFormat (formatlist, 2)) <= 0)
194     {
195       CloseClipboard ();
196       return;
197     }
198   if (!(hglb = GetClipboardData (format)))
199     {
200       CloseClipboard ();
201       return;
202     }
203   if (format == cygnativeformat)
204     {
205       unsigned char *buf;
206
207       if (!(buf = (unsigned char *) GlobalLock (hglb)))
208         {
209           CloseClipboard ();
210           return;
211         }
212       size_t buflen = (*(size_t *) buf);
213       ret = ((plen > (buflen - pos)) ? (buflen - pos) : plen);
214       memcpy (ptr, buf + sizeof (size_t)+ pos , ret);
215       pos += ret;
216       if (pos + plen - ret >= buflen)
217         eof = true;
218     }
219   else
220     {
221       int wret;
222       PWCHAR buf;
223
224       if (!(buf = (PWCHAR) GlobalLock (hglb)))
225         {
226           CloseClipboard ();
227           return;
228         }
229       size_t glen = GlobalSize (hglb) / sizeof (WCHAR) - 1;
230       /* This loop is necessary because the number of bytes returned by
231          sys_wcstombs does not indicate the number of wide chars used for
232          it, so we could potentially drop wide chars. */
233       if (glen - pos > plen)
234         glen = pos + plen;
235       while ((wret = sys_wcstombs (NULL, 0, buf + pos, glen - pos)) != -1
236              && (size_t) wret > plen)
237         --glen;
238       ret = sys_wcstombs ((char *) ptr, plen, buf + pos, glen - pos);
239       pos += ret;
240       if (pos + plen - ret >= wcslen (buf))
241         eof = true;
242     }
243   GlobalUnlock (hglb);
244   CloseClipboard ();
245   len = ret;
246 }
247
248 _off64_t
249 fhandler_dev_clipboard::lseek (_off64_t offset, int whence)
250 {
251   /* On reads we check this at read time, not seek time.
252    * On writes we use this to decide how to write - empty and write, or open, copy, empty
253    * and write
254    */
255   pos = offset;
256   /* treat seek like rewind */
257   if (membuffer)
258     free (membuffer);
259   msize = 0;
260   return 0;
261 }
262
263 int
264 fhandler_dev_clipboard::close ()
265 {
266   if (!hExeced)
267     {
268       eof = true;
269       pos = 0;
270       if (membuffer)
271         {
272           free (membuffer);
273           membuffer = NULL;
274         }
275       msize = 0;
276     }
277   return 0;
278 }
279
280 void
281 fhandler_dev_clipboard::fixup_after_exec ()
282 {
283   if (!close_on_exec ())
284     {
285       eof = false;
286       pos = msize = 0;
287       membuffer = NULL;
288     }
289 }