4d0fac9d11b92a67ae15d390896ef693c8b12fc5
[xboard.git] / winboard / wclipbrd.c
1 /*\r
2  * wclipbrd.c -- Clipboard routines for WinBoard\r
3  *\r
4  * Copyright 2000,2009 Free Software Foundation, Inc.\r
5  *\r
6  * Enhancements Copyright 2005 Alessandro Scotti\r
7  *\r
8  * ------------------------------------------------------------------------\r
9  *\r
10  * GNU XBoard is free software: you can redistribute it and/or modify\r
11  * it under the terms of the GNU General Public License as published by\r
12  * the Free Software Foundation, either version 3 of the License, or (at\r
13  * your option) any later version.\r
14  *\r
15  * GNU XBoard is distributed in the hope that it will be useful, but\r
16  * WITHOUT ANY WARRANTY; without even the implied warranty of\r
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
18  * General Public License for more details.\r
19  *\r
20  * You should have received a copy of the GNU General Public License\r
21  * along with this program. If not, see http://www.gnu.org/licenses/.  *\r
22  *\r
23  *------------------------------------------------------------------------\r
24  ** See the file ChangeLog for a revision history.  */\r
25 \r
26 #include "config.h"\r
27 \r
28 #include <windows.h>   /* required for all Windows applications */\r
29 #include <stdio.h>\r
30 #include <stdlib.h>\r
31 #include <malloc.h>\r
32 #include <sys/stat.h>\r
33 \r
34 #include "common.h"\r
35 #include "winboard.h"\r
36 #include "frontend.h"\r
37 #include "backend.h"\r
38 #include "wclipbrd.h"\r
39 \r
40 /* Imports from winboard.c */\r
41 extern HWND hwndMain;\r
42 Boolean ParseFEN(Board b, int *stm, char *FEN);\r
43 \r
44 /* File globals */\r
45 static char *copyTemp;\r
46 static char *pasteTemp;\r
47 \r
48 VOID \r
49 CopyFENToClipboard()\r
50 {\r
51   char *fen = NULL;\r
52 \r
53   fen = PositionToFEN(currentMove, NULL);\r
54   if (!fen) {\r
55     DisplayError("Unable to convert position to FEN.", 0);\r
56     return;\r
57   }\r
58   if (!CopyTextToClipboard(fen))\r
59       DisplayError("Unable to copy FEN to clipboard.", 0);\r
60   free(fen);\r
61 }\r
62 \r
63 /* [AS] */\r
64 HGLOBAL ExportGameListAsText();\r
65 \r
66 VOID CopyGameListToClipboard()\r
67 {\r
68     HGLOBAL hMem = ExportGameListAsText();\r
69     \r
70     if( hMem != NULL ) {\r
71         /* Assign memory block to clipboard */\r
72         BOOL ok = OpenClipboard( hwndMain );\r
73 \r
74         if( ok ) {\r
75             ok = EmptyClipboard();\r
76 \r
77             if( ok ) {\r
78                 if( hMem != SetClipboardData( CF_TEXT, hMem ) ) {\r
79                     ok = FALSE;\r
80                 }\r
81             }\r
82 \r
83             CloseClipboard();\r
84 \r
85             if( ! ok ) {\r
86                 GlobalFree( hMem );\r
87             }\r
88         }\r
89 \r
90         if( ! ok ) {\r
91             DisplayError( "Cannot copy list to clipboard.", 0 );\r
92         }\r
93     }\r
94 }\r
95 \r
96 VOID\r
97 CopyGameToClipboard()\r
98 {\r
99   /* A rather cheesy hack here. Write the game to a file, then read from the\r
100    * file into the clipboard.\r
101    */\r
102   char *buf = NULL;\r
103   FILE *f;\r
104   unsigned long size;\r
105   size_t len;\r
106   struct stat st;\r
107 \r
108   if (!copyTemp) {\r
109     copyTemp = tempnam(NULL, "wbcp");\r
110   }\r
111   if (!copyTemp) {\r
112       DisplayError("Cannot create temporary file name.",0);\r
113       return;\r
114   }\r
115   f = fopen(copyTemp, "w");\r
116   if (!f) {\r
117     DisplayError("Cannot open temporary file.", 0);\r
118     return;\r
119   }\r
120   if (!SaveGame(f,0,"")) {                      /* call into backend */\r
121     DisplayError("Cannot write to temporary file.", 0);\r
122     goto copy_game_to_clipboard_cleanup;\r
123   }\r
124   f = fopen(copyTemp, "rb");\r
125   if (!f) {\r
126     DisplayError("Cannot reopen temporary file.", 0);\r
127     goto copy_game_to_clipboard_cleanup;\r
128   }\r
129   if (fstat(fileno(f), &st) < 0) {\r
130     DisplayError("Cannot determine size of file.", 0);\r
131     goto copy_game_to_clipboard_cleanup;\r
132   }\r
133   size = st.st_size;\r
134   if (size == -1) {\r
135     DisplayError("Cannot determine size of file.", 0);\r
136     goto copy_game_to_clipboard_cleanup;\r
137   }\r
138   rewind(f);\r
139   buf = (char*)malloc(size+1);\r
140   if (!buf) {\r
141     DisplayError("Cannot allocate clipboard buffer.", 0);\r
142     goto copy_game_to_clipboard_cleanup;\r
143   }\r
144   len = fread(buf, sizeof(char), size, f);\r
145   if (len == -1) {\r
146     DisplayError("Cannot read from temporary file.", 0);\r
147     goto copy_game_to_clipboard_cleanup;\r
148   }\r
149   if ((unsigned long)size != (unsigned long)len) { /* sigh */ \r
150       DisplayError("Error reading from temporary file.", 0);\r
151       goto copy_game_to_clipboard_cleanup;\r
152   }\r
153   buf[size] = 0;\r
154   if (!CopyTextToClipboard(buf)) {\r
155       DisplayError("Cannot copy text to clipboard", 0);\r
156   }\r
157 \r
158 copy_game_to_clipboard_cleanup:\r
159   if (buf) free(buf);\r
160   if (f) fclose(f);\r
161 }\r
162 \r
163 \r
164 int \r
165 CopyTextToClipboard(char *text)\r
166 {\r
167   /* some (most?) of the error checking may be overkill, \r
168    * but hey, this is Windows \r
169    */\r
170   HGLOBAL hGlobalMem;\r
171   LPVOID lpGlobalMem;\r
172   BOOL locked;\r
173   UINT lockCount;\r
174   DWORD err;\r
175 \r
176   hGlobalMem = GlobalAlloc(GHND, (DWORD)lstrlen(text)+1);\r
177   if (hGlobalMem == NULL) {\r
178     DisplayError("Unable to allocate memory for clipboard.", 0);\r
179     return FALSE;\r
180   }\r
181   lpGlobalMem = GlobalLock(hGlobalMem);\r
182   if (lpGlobalMem == NULL) {\r
183     DisplayError("Unable to lock clipboard memory.", 0);\r
184     GlobalFree(hGlobalMem);\r
185     return FALSE;\r
186   }\r
187   lstrcpy(lpGlobalMem, text);\r
188   if (appData.debugMode) {\r
189     lockCount = GlobalFlags(hGlobalMem) & GMEM_LOCKCOUNT;\r
190     fprintf(debugFP, "CopyTextToClipboard(): lock count %d\n", lockCount);\r
191   }\r
192   SetLastError(NO_ERROR);\r
193   locked = GlobalUnlock(hGlobalMem);\r
194   err = GetLastError();\r
195   if (appData.debugMode) {\r
196     lockCount = GlobalFlags(hGlobalMem) & GMEM_LOCKCOUNT;\r
197     fprintf(debugFP, "CopyTextToClipboard(): lock count %d\n", lockCount);\r
198   }\r
199   if (!locked) {\r
200     locked = !((err == NO_ERROR) || (err == ERROR_NOT_LOCKED));\r
201     if (appData.debugMode) {\r
202       fprintf(debugFP, \r
203               "CopyTextToClipboard(): err %d locked %d\n", (int)err, locked);\r
204     }\r
205   }\r
206   if (locked) {\r
207     DisplayError("Cannot unlock clipboard memory.", 0);\r
208     GlobalFree(hGlobalMem);\r
209     return FALSE;\r
210   }\r
211   if (!OpenClipboard(hwndMain)) {\r
212     DisplayError("Cannot open clipboard.", 0);\r
213     GlobalFree(hGlobalMem);\r
214     return FALSE;\r
215   }\r
216   if (!EmptyClipboard()) {\r
217     DisplayError("Cannot empty clipboard.", 0);\r
218     return FALSE;\r
219   }\r
220   if (hGlobalMem != SetClipboardData(CF_TEXT, hGlobalMem)) {\r
221     DisplayError("Cannot copy text to clipboard.", 0);\r
222     CloseClipboard();\r
223     GlobalFree(hGlobalMem);\r
224     return FALSE;\r
225   }\r
226   if (!CloseClipboard())\r
227     DisplayError("Cannot close clipboard.", 0);\r
228   \r
229   return TRUE;\r
230 }\r
231 \r
232 /* [AS] Reworked paste functions so they can work with strings too */\r
233 \r
234 VOID PasteFENFromString( char * fen )\r
235 {\r
236   if (appData.debugMode) {\r
237     fprintf(debugFP, "PasteFenFromString(): fen '%s'\n", fen);\r
238   }\r
239   EditPositionPasteFEN(fen); /* call into backend */\r
240   free(fen);\r
241 }\r
242 \r
243 \r
244 VOID\r
245 PasteFENFromClipboard()\r
246 {\r
247   char *fen = NULL;\r
248   if (!PasteTextFromClipboard(&fen)) {\r
249       DisplayError("Unable to paste FEN from clipboard.", 0);\r
250       return;\r
251   }\r
252   PasteFENFromString( fen );\r
253 }\r
254 \r
255 VOID PasteGameFromString( char * buf )\r
256 {\r
257   FILE *f;\r
258   size_t len;\r
259   if (!pasteTemp) {\r
260     pasteTemp = tempnam(NULL, "wbpt");\r
261   }\r
262   f = fopen(pasteTemp, "w");\r
263   if (!f) {\r
264     DisplayError("Unable to create temporary file.", 0);\r
265     free(buf); /* [AS] */\r
266     return;\r
267   }\r
268   len = fwrite(buf, sizeof(char), strlen(buf), f);\r
269   fclose(f);\r
270   if (len != strlen(buf)) {\r
271     DisplayError("Error writing to temporary file.", 0);\r
272     free(buf); /* [AS] */\r
273     return;\r
274   }\r
275   LoadGameFromFile(pasteTemp, 0, "Clipboard", TRUE);\r
276   free( buf ); /* [AS] */\r
277 }\r
278 \r
279 \r
280 VOID\r
281 PasteGameFromClipboard()\r
282 {\r
283   /* Write the clipboard to a temp file, then let LoadGameFromFile()\r
284    * do all the work.  */\r
285   char *buf;\r
286   if (!PasteTextFromClipboard(&buf)) {\r
287     return;\r
288   }\r
289   PasteGameFromString( buf );\r
290 }\r
291 \r
292 /* [AS] Try to detect whether the clipboard contains FEN or PGN data */\r
293 VOID PasteGameOrFENFromClipboard()\r
294 {\r
295   char *buf;\r
296 //  char *tmp;\r
297   Board dummyBoard; int dummy; // [HGM] paste any\r
298 \r
299   if (!PasteTextFromClipboard(&buf)) {\r
300     return;\r
301   }\r
302 \r
303 #if 0\r
304   tmp = buf;\r
305   while( *tmp == ' ' || *tmp == '\t' || *tmp == '\r' || *tmp == '\n' ) {\r
306       tmp++;\r
307   }\r
308 \r
309   if( *tmp == '[' ) {\r
310 #else\r
311   // [HGM] paste any: make still smarter, to allow pasting of games without tags, recognize FEN in stead\r
312   if(!ParseFEN(dummyBoard, &dummy, buf) ) {\r
313 #endif\r
314       PasteGameFromString( buf );\r
315   }\r
316   else {\r
317       PasteFENFromString( buf );\r
318   }\r
319 }\r
320 \r
321 int \r
322 PasteTextFromClipboard(char **text)\r
323 {\r
324   /* some (most?) of the error checking may be overkill, \r
325    * but hey, this is Windows \r
326    */\r
327   HANDLE hClipMem;\r
328   LPVOID lpClipMem;\r
329   BOOL locked = FALSE;\r
330   DWORD err;\r
331   UINT lockCount;\r
332 \r
333   if (!OpenClipboard(hwndMain)) {\r
334     DisplayError("Unable to open clipboard.", 0);\r
335     return FALSE;\r
336   }\r
337   hClipMem = GetClipboardData(CF_TEXT);\r
338   if (hClipMem == NULL) {\r
339     CloseClipboard();\r
340     DisplayError("No text in clipboard.", 0);\r
341     return FALSE;\r
342   }\r
343   lpClipMem = GlobalLock(hClipMem);\r
344   if (lpClipMem == NULL) {\r
345     CloseClipboard();\r
346     DisplayError("Unable to lock clipboard memory.", 0);\r
347     return FALSE;\r
348   }\r
349   *text = (char *) malloc(GlobalSize(hClipMem)+1);\r
350   if (!*text) {\r
351     DisplayError("Unable to allocate memory for text string.", 0);\r
352     CloseClipboard();\r
353     return FALSE;\r
354   }\r
355   lstrcpy(*text, lpClipMem);\r
356   if (appData.debugMode) {\r
357     lockCount = GlobalFlags(hClipMem) & GMEM_LOCKCOUNT;\r
358     fprintf(debugFP, "PasteTextFromClipboard(): lock count %d\n", lockCount);\r
359   }\r
360   SetLastError(NO_ERROR);\r
361 #if 1\r
362   /*suggested by Wilkin Ng*/\r
363   lockCount = GlobalFlags(hClipMem) & GMEM_LOCKCOUNT;\r
364   if (lockCount) {\r
365     locked = GlobalUnlock(hClipMem);\r
366   }\r
367 #else\r
368   locked = GlobalUnlock(hClipMem);\r
369 #endif\r
370   err = GetLastError();\r
371   if (appData.debugMode) {\r
372     lockCount = GlobalFlags(hClipMem) & GMEM_LOCKCOUNT;\r
373     fprintf(debugFP, "PasteTextFromClipboard(): lock count %d\n", lockCount);\r
374   }\r
375   if (!locked) {\r
376     locked = !((err == NO_ERROR) || (err == ERROR_NOT_LOCKED));\r
377     if (appData.debugMode) {\r
378       fprintf(debugFP, \r
379               "PasteTextFromClipboard(): err %d locked %d\n", (int)err, locked);\r
380     }\r
381   }\r
382   if (locked) \r
383     DisplayError("Unable to unlock clipboard memory.", 0);\r
384   \r
385   if (!CloseClipboard())\r
386     DisplayError("Unable to close clipboard.", 0);\r
387   \r
388   return TRUE;\r
389 }\r
390 \r
391 VOID\r
392 DeleteClipboardTempFiles()\r
393 {\r
394   if (copyTemp) remove(copyTemp);\r
395   if (pasteTemp) remove(pasteTemp);\r
396 }\r