]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/gtkutil/clipboard.cpp
reformat code! now the code is only ugly on the *inside*
[xonotic/netradiant.git] / libs / gtkutil / clipboard.cpp
1 /*
2    Copyright (C) 2001-2006, William Joseph.
3    All Rights Reserved.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 #include "clipboard.h"
23
24 #include "globaldefs.h"
25 #include "stream/memstream.h"
26 #include "stream/textstream.h"
27
28
29 /// \file
30 /// \brief Platform-independent GTK clipboard support.
31 /// \todo Using GDK_SELECTION_CLIPBOARD fails on win32, so we use the win32 API directly for now.
32 #if GDEF_OS_WINDOWS
33
34 const char* c_clipboard_format = "RadiantClippings";
35
36 #include <windows.h>
37
38 void clipboard_copy( ClipboardCopyFunc copy ){
39     BufferOutputStream ostream;
40     copy( ostream );
41
42     bool bClipped = false;
43     UINT nClipboard = ::RegisterClipboardFormat( c_clipboard_format );
44     if ( nClipboard > 0 ) {
45         if ( ::OpenClipboard( 0 ) ) {
46             EmptyClipboard();
47             std::size_t length = ostream.size();
48             HANDLE h = ::GlobalAlloc( GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, length + sizeof( std::size_t ) );
49             if ( h != 0 ) {
50                 char *buffer = reinterpret_cast<char*>( ::GlobalLock( h ) );
51                 *reinterpret_cast<std::size_t*>( buffer ) = length;
52                 buffer += sizeof( std::size_t );
53                 memcpy( buffer, ostream.data(), length );
54                 ::GlobalUnlock( h );
55                 ::SetClipboardData( nClipboard, h );
56                 ::CloseClipboard();
57                 bClipped = true;
58             }
59         }
60     }
61
62     if ( !bClipped ) {
63         globalOutputStream() << "Unable to register Windows clipboard formats, copy/paste between editors will not be possible\n";
64     }
65 }
66
67 void clipboard_paste( ClipboardPasteFunc paste ){
68     UINT nClipboard = ::RegisterClipboardFormat( c_clipboard_format );
69     if ( nClipboard > 0 && ::OpenClipboard( 0 ) ) {
70         if ( IsClipboardFormatAvailable( nClipboard ) ) {
71             HANDLE h = ::GetClipboardData( nClipboard );
72             if ( h ) {
73                 const char *buffer = reinterpret_cast<const char*>( ::GlobalLock( h ) );
74                 std::size_t length = *reinterpret_cast<const std::size_t*>( buffer );
75                 buffer += sizeof( std::size_t );
76                 BufferInputStream istream( buffer, length );
77                 paste( istream );
78                 ::GlobalUnlock( h );
79             }
80         }
81         ::CloseClipboard();
82     }
83 }
84
85 #else
86
87 #include <gtk/gtk.h>
88
89 enum {
90     RADIANT_CLIPPINGS = 23,
91 };
92
93 static char RADIANT_CLIPPINGS_STR[] = "RADIANT_CLIPPINGS";
94
95 static const GtkTargetEntry clipboard_targets[] = {
96         {RADIANT_CLIPPINGS_STR, 0, RADIANT_CLIPPINGS,},
97 };
98
99 static void clipboard_get(GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, gpointer data)
100 {
101     std::size_t len = *reinterpret_cast<std::size_t *>( data );
102     const char *buffer = (len != 0) ? reinterpret_cast<const char *>( data ) + sizeof(std::size_t) : 0;
103
104     GdkAtom type = GDK_NONE;
105     if (info == clipboard_targets[0].info) {
106         type = gdk_atom_intern(clipboard_targets[0].target, FALSE);
107     }
108
109     gtk_selection_data_set(selection_data, type, 8, reinterpret_cast<const guchar *>( buffer ),
110                            static_cast<gint>( len ));
111 }
112
113 static void clipboard_clear(GtkClipboard *clipboard, gpointer data)
114 {
115     delete[] reinterpret_cast<const char *>( data );
116 }
117
118 static void clipboard_received(GtkClipboard *clipboard, GtkSelectionData *data, gpointer user_data)
119 {
120     if (gtk_selection_data_get_length(data) < 0) {
121         globalErrorStream() << "Error retrieving selection\n";
122     } else if (strcmp(gdk_atom_name(gtk_selection_data_get_data_type(data)), clipboard_targets[0].target) == 0) {
123         BufferInputStream istream(reinterpret_cast<const char *>( gtk_selection_data_get_data(data)),
124                                   gtk_selection_data_get_length(data));
125         (*reinterpret_cast<ClipboardPasteFunc *>( user_data ))(istream);
126     }
127 }
128
129 void clipboard_copy(ClipboardCopyFunc copy)
130 {
131     GtkClipboard *clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
132
133     BufferOutputStream ostream;
134     copy(ostream);
135     std::size_t length = ostream.size();
136     char *data = new char[length + sizeof(std::size_t)];
137     *reinterpret_cast<std::size_t *>( data ) = length;
138     memcpy(data + sizeof(std::size_t), ostream.data(), length);
139
140     gtk_clipboard_set_with_data(clipboard, clipboard_targets, 1, clipboard_get, clipboard_clear, data);
141 }
142
143 ClipboardPasteFunc g_clipboardPasteFunc = 0;
144
145 void clipboard_paste(ClipboardPasteFunc paste)
146 {
147     GtkClipboard *clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
148
149     g_clipboardPasteFunc = paste;
150     gtk_clipboard_request_contents(clipboard, gdk_atom_intern(clipboard_targets[0].target, FALSE), clipboard_received,
151                                    &g_clipboardPasteFunc);
152 }
153
154
155 #endif