1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  * Port to the D programming language:
11  *     Frank Benoit <benoit@tionex.de>
12  *******************************************************************************/
13 module org.eclipse.swt.dnd.ClipboardProxy;
14 
15 import java.lang.all;
16 
17 
18 
19 import org.eclipse.swt.SWT;
20 import org.eclipse.swt.internal.gtk.OS;
21 import org.eclipse.swt.widgets.Display;
22 import org.eclipse.swt.widgets.Event;
23 import org.eclipse.swt.widgets.Listener;
24 import org.eclipse.swt.dnd.Transfer;
25 import org.eclipse.swt.dnd.Clipboard;
26 import org.eclipse.swt.dnd.DND;
27 import org.eclipse.swt.dnd.TransferData;
28 
29 version(Tango){
30 static import tango.stdc..string;
31 } else { // Phobos
32 }
33 
34 
35 class ClipboardProxy {
36     /* Data is not flushed to the clipboard immediately.
37      * This class will remember the data and provide it when requested.
38      */
39     Object[] clipboardData;
40     Transfer[] clipboardDataTypes;
41     Object[] primaryClipboardData;
42     Transfer[] primaryClipboardDataTypes;
43 
44     Display display;
45     Clipboard activeClipboard = null;
46     Clipboard activePrimaryClipboard = null;
47 
48     static String ID = "CLIPBOARD PROXY OBJECT"; //$NON-NLS-1$
49 
50 static ClipboardProxy _getInstance(Display display) {
51     ClipboardProxy proxy = cast(ClipboardProxy) display.getData(ID);
52     if (proxy !is null) return proxy;
53     proxy = new ClipboardProxy(display);
54     display.setData(ID, proxy);
55     display.addListener(SWT.Dispose, new class( display ) Listener {
56         Display disp;
57         this( Display disp ){ this.disp = disp; }
58         public void handleEvent(Event event) {
59             ClipboardProxy clipbordProxy = cast(ClipboardProxy)disp.getData(ID);
60             if (clipbordProxy is null) return;
61             disp.setData(ID, null);
62             clipbordProxy.dispose();
63         }
64     });
65     return proxy;
66 }
67 
68 this(Display display) {
69     this.display = display;
70 }
71 
72 void clear (Clipboard owner, int clipboards) {
73     if ((clipboards & DND.CLIPBOARD) !is 0 && activeClipboard is owner) {
74         OS.gtk_clipboard_clear(Clipboard.GTKCLIPBOARD);
75     }
76     if ((clipboards & DND.SELECTION_CLIPBOARD) !is 0 && activePrimaryClipboard is owner) {
77         OS.gtk_clipboard_clear(Clipboard.GTKPRIMARYCLIPBOARD);
78     }
79 }
80 
81 private static extern(C) void clearFuncFunc(GtkClipboard *clipboard, void* user_data_or_owner){
82     auto obj = cast(ClipboardProxy)user_data_or_owner;
83     obj.clearFunc( clipboard );
84 }
85 void clearFunc(GtkClipboard *clipboard ){
86     if (clipboard is Clipboard.GTKCLIPBOARD) {
87         activeClipboard = null;
88         clipboardData = null;
89         clipboardDataTypes = null;
90     }
91     if (clipboard is Clipboard.GTKPRIMARYCLIPBOARD) {
92         activePrimaryClipboard = null;
93         primaryClipboardData = null;
94         primaryClipboardDataTypes = null;
95     }
96 }
97 
98 void dispose () {
99     if (display is null) return;
100     if (activeClipboard !is null) OS.gtk_clipboard_clear(Clipboard.GTKCLIPBOARD);
101     if (activePrimaryClipboard !is null) OS.gtk_clipboard_clear(Clipboard.GTKPRIMARYCLIPBOARD);
102     display = null;
103     clipboardData = null;
104     clipboardDataTypes = null;
105     primaryClipboardData = null;
106     primaryClipboardDataTypes = null;
107 }
108 
109 private static extern(C) void getFuncFunc(
110     GtkClipboard *clipboard,
111     GtkSelectionData *selection_data,
112     uint info,
113     void* user_data_or_owner)
114 {
115     auto obj = cast(ClipboardProxy)user_data_or_owner;
116     obj.getFunc( clipboard, selection_data, info );
117 }
118 /**
119  * This function provides the data to the clipboard on request.
120  * When this clipboard is disposed, the data will no longer be available.
121  */
122 int getFunc(
123     GtkClipboard *clipboard,
124     GtkSelectionData *selectionData,
125     uint info)
126 {
127     if (selectionData is null) return 0;
128     TransferData tdata = new TransferData();
129     tdata.type = selectionData.target;
130     Transfer[] types = (clipboard is Clipboard.GTKCLIPBOARD) ? clipboardDataTypes : primaryClipboardDataTypes;
131     ptrdiff_t index = -1;
132     for (int i = 0; i < types.length; i++) {
133         if (types[i].isSupportedType(tdata)) {
134             index = i;
135             break;
136         }
137     }
138     if (index is -1) return 0;
139     Object[] data = (clipboard is Clipboard.GTKCLIPBOARD) ? clipboardData : primaryClipboardData;
140     types[index].javaToNative(data[index], tdata);
141     if (tdata.format < 8 || tdata.format % 8 !is 0) {
142         return 0;
143     }
144     OS.gtk_selection_data_set(selectionData, tdata.type, tdata.format, tdata.pValue, tdata.length);
145     OS.g_free(tdata.pValue);
146     return 1;
147 }
148 
149 bool setData(Clipboard owner, Object[] data, Transfer[] dataTypes, int clipboards) { 
150     GtkTargetEntry*[] entries;
151     GtkTargetEntry* pTargetsList;
152     try {
153         for (int i = 0; i < dataTypes.length; i++) {
154             Transfer transfer = dataTypes[i];
155             int[] typeIds = transfer.getTypeIds();
156             String[] typeNames = transfer.getTypeNames();
157             for (int j = 0; j < typeIds.length; j++) {
158                 GtkTargetEntry*  entry = new GtkTargetEntry();
159                 entry.info = typeIds[j];
160                 char* pName = cast(char*)
161                     OS.g_malloc(typeNames[j].length+1);
162                 pName[ 0 .. typeNames[j].length ] = typeNames[j];
163                 pName[ typeNames[j].length ] = '\0';
164                 entry.target = pName;
165                 GtkTargetEntry*[] tmp = new GtkTargetEntry*[entries.length + 1];
166                 SimpleType!(GtkTargetEntry*)
167                     .arraycopy(entries, 0, tmp, 0, entries.length);
168                 tmp[entries.length] = entry;
169                 entries = tmp;
170             }
171         }
172 
173         pTargetsList = cast(GtkTargetEntry*)
174             OS.g_malloc(GtkTargetEntry.sizeof * entries.length);
175         int offset = 0;
176         for (int i = 0; i < entries.length; i++) {
177             OS.memmove(pTargetsList + i, entries[i], GtkTargetEntry.sizeof);
178             offset += GtkTargetEntry.sizeof;
179         }
180         if ((clipboards & DND.CLIPBOARD) !is 0) {
181             if (activeClipboard !is null) OS.gtk_clipboard_clear(Clipboard.GTKCLIPBOARD);
182             clipboardData = data;
183             clipboardDataTypes = dataTypes;
184             if (!OS.gtk_clipboard_set_with_data(Clipboard.GTKCLIPBOARD,
185                         pTargetsList, cast(int)/*64bit*/entries.length, &getFuncFunc,
186                         &clearFuncFunc, cast(void*)this )) {
187                 return false;
188             }
189             activeClipboard = owner;
190         }
191         if ((clipboards & DND.SELECTION_CLIPBOARD) !is 0) {
192             if (activePrimaryClipboard !is null) OS.gtk_clipboard_clear(Clipboard.GTKPRIMARYCLIPBOARD);
193             primaryClipboardData = data;
194             primaryClipboardDataTypes = dataTypes;
195             if (!OS.gtk_clipboard_set_with_data(Clipboard.GTKPRIMARYCLIPBOARD,
196                         pTargetsList, cast(int)/*64bit*/entries.length, &getFuncFunc,
197                         &clearFuncFunc, cast(void*)this )) {
198                 return false;
199             }
200             activePrimaryClipboard = owner;
201         }
202     } finally {
203         for (int i = 0; i < entries.length; i++) {
204             GtkTargetEntry* entry = entries[i];
205             if( entry.target !is null) OS.g_free(entry.target);
206         }
207         if (pTargetsList !is null) OS.g_free(pTargetsList);
208     }
209 
210     return true;
211 }
212 }