98
|
1 /*******************************************************************************
|
|
2 * Copyright (c) 2000, 2007 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 dwt.ole.win32.OleFrame;
|
|
14
|
|
15 import dwt.DWT;
|
|
16 import dwt.DWTException;
|
|
17 import dwt.internal.ole.win32.COM;
|
|
18 import dwt.internal.ole.win32.OLEIDL;
|
|
19 import dwt.internal.ole.win32.extras;
|
|
20 import dwt.internal.win32.OS;
|
|
21 import dwt.widgets.Composite;
|
|
22 import dwt.widgets.Control;
|
|
23 import dwt.widgets.Display;
|
|
24 import dwt.widgets.Event;
|
|
25 import dwt.widgets.Listener;
|
|
26 import dwt.widgets.Menu;
|
|
27 import dwt.widgets.MenuItem;
|
|
28 import dwt.widgets.Shell;
|
|
29 import dwt.widgets.Widget;
|
|
30
|
|
31 import dwt.ole.win32.OleClientSite;
|
|
32 import dwt.ole.win32.OLE;
|
|
33
|
|
34 import dwt.dwthelper.utils;
|
|
35 import dwt.dwthelper.Runnable;
|
|
36 import tango.core.Array;
|
|
37
|
|
38 /**
|
|
39 *
|
|
40 * OleFrame is an OLE Container's top level frame.
|
|
41 *
|
|
42 * <p>This object implements the OLE Interfaces IUnknown and IOleInPlaceFrame
|
|
43 *
|
|
44 * <p>OleFrame allows the container to do the following: <ul>
|
|
45 * <li>position and size the ActiveX Control or OLE Document within the application
|
|
46 * <li>insert menu items from the application into the OLE Document's menu
|
|
47 * <li>activate and deactivate the OLE Document's menus
|
|
48 * <li>position the OLE Document's menu in the application
|
|
49 * <li>translate accelerator keystrokes intended for the container's frame</ul>
|
|
50 *
|
|
51 * <dl>
|
|
52 * <dt><b>Styles</b> <dd>BORDER
|
|
53 * <dt><b>Events</b> <dd>Dispose, Move, Resize
|
|
54 * </dl>
|
|
55 *
|
|
56 */
|
|
57 final public class OleFrame : Composite
|
|
58 {
|
|
59 // Interfaces for this Ole Client Container
|
|
60 //private COMObject iUnknown;
|
|
61 private _IOleInPlaceFrameImpl iOleInPlaceFrame;
|
|
62
|
|
63 // Access to the embedded/linked Ole Object
|
|
64 private IOleInPlaceActiveObject objIOleInPlaceActiveObject;
|
|
65
|
|
66 private OleClientSite currentdoc;
|
|
67
|
|
68 private int refCount = 0;
|
|
69
|
|
70 private MenuItem[] fileMenuItems;
|
|
71 private MenuItem[] containerMenuItems;
|
|
72 private MenuItem[] windowMenuItems;
|
|
73
|
|
74 private Listener listener;
|
|
75
|
|
76 private static char[] CHECK_FOCUS = "OLE_CHECK_FOCUS"; //$NON-NLS-1$
|
|
77 private static char[] HHOOK = "OLE_HHOOK"; //$NON-NLS-1$
|
|
78 private static char[] HHOOKMSG = "OLE_HHOOK_MSG"; //$NON-NLS-1$
|
|
79
|
|
80 private static bool ignoreNextKey;
|
|
81 private static const short [] ACCENTS = [ cast(short)'~', '`', '\'', '^', '"'];
|
|
82
|
|
83 private static const char[] CONSUME_KEY = "org.eclipse.swt.OleFrame.ConsumeKey"; //$NON-NLS-1$
|
|
84
|
|
85 /**
|
|
86 * Create an OleFrame child widget using style bits
|
|
87 * to select a particular look or set of properties.
|
|
88 *
|
|
89 * @param parent a composite widget (cannot be null)
|
|
90 * @param style the bitwise OR'ing of widget styles
|
|
91 *
|
|
92 * @exception IllegalArgumentException <ul>
|
|
93 * <li>ERROR_NULL_ARGUMENT when the parent is null
|
|
94 * </ul>
|
|
95 * @exception DWTException <ul>
|
|
96 * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
|
|
97 * </ul>
|
|
98 *
|
|
99 */
|
|
100 public this(Composite parent, int style) {
|
|
101 super(parent, style);
|
|
102
|
|
103 createCOMInterfaces();
|
|
104
|
|
105 // setup cleanup proc
|
|
106 listener = new class() Listener {
|
|
107 public void handleEvent(Event e) {
|
|
108 switch (e.type) {
|
|
109 case DWT.Activate : onActivate(e); break;
|
|
110 case DWT.Deactivate : onDeactivate(e); break;
|
|
111 case DWT.Dispose : onDispose(e); break;
|
|
112 case DWT.Resize :
|
|
113 case DWT.Move : onResize(e); break;
|
|
114 default :
|
|
115 OLE.error(DWT.ERROR_NOT_IMPLEMENTED);
|
|
116 }
|
|
117 }
|
|
118 };
|
|
119
|
|
120
|
|
121 addListener(DWT.Activate, listener);
|
|
122 addListener(DWT.Deactivate, listener);
|
|
123 addListener(DWT.Dispose, listener);
|
|
124
|
|
125 // inform inplaceactiveobject whenever frame resizes
|
|
126 addListener(DWT.Resize, listener);
|
|
127
|
|
128 // inform inplaceactiveobject whenever frame moves
|
|
129 addListener(DWT.Move, listener);
|
|
130
|
|
131 // Maintain a reference to yourself so that when
|
|
132 // ClientSites close, they don't take the frame away
|
|
133 // with them.
|
|
134 this.AddRef();
|
|
135
|
|
136 // Check for focus change
|
|
137 Display display = getDisplay();
|
|
138 initCheckFocus(display);
|
|
139 initMsgHook(display);
|
|
140 }
|
|
141 private static void initCheckFocus (Display display_) {
|
|
142 if (display_.getData(CHECK_FOCUS) !is null) return;
|
|
143 display_.setData(CHECK_FOCUS, new ArrayWrapperString(CHECK_FOCUS));
|
|
144 static const int time = 50;
|
|
145 auto timer = new class(display_) Runnable {
|
|
146 Display display;
|
|
147 Control[1] lastFocus;
|
|
148 this( Display display){ this.display = display; }
|
|
149 public void run() {
|
|
150 if (( null !is cast(OleClientSite)lastFocus[0] ) && !lastFocus[0].isDisposed()) {
|
|
151 // ignore popup menus and dialogs
|
|
152 auto hwnd = OS.GetFocus();
|
|
153 while (hwnd !is null) {
|
|
154 auto ownerHwnd = OS.GetWindow(hwnd, OS.GW_OWNER);
|
|
155 if (ownerHwnd !is null) {
|
|
156 display.timerExec(time, this);
|
|
157 return;
|
|
158 }
|
|
159 hwnd = OS.GetParent(hwnd);
|
|
160 }
|
|
161 }
|
|
162 if (lastFocus[0] is null || lastFocus[0].isDisposed() || !lastFocus[0].isFocusControl()) {
|
|
163 Control currentFocus = display.getFocusControl();
|
|
164 if ( auto frame = cast(OleFrame)currentFocus ) {
|
|
165 currentFocus = frame.getCurrentDocument();
|
|
166 }
|
|
167 if (lastFocus[0] !is currentFocus) {
|
|
168 Event event = new Event();
|
|
169 if (( null !is cast(OleClientSite)lastFocus[0] ) && !lastFocus[0].isDisposed()) {
|
|
170 lastFocus[0].notifyListeners (DWT.FocusOut, event);
|
|
171 }
|
|
172 if (( null !is cast(OleClientSite)currentFocus ) && !currentFocus.isDisposed()) {
|
|
173 currentFocus.notifyListeners(DWT.FocusIn, event);
|
|
174 }
|
|
175 }
|
|
176 lastFocus[0] = currentFocus;
|
|
177 }
|
|
178 display.timerExec(time, this);
|
|
179 }
|
|
180 };
|
|
181 display_.timerExec(time, timer);
|
|
182 }
|
|
183 private static void initMsgHook(Display display) {
|
|
184 if (display.getData(HHOOK) !is null) return;
|
|
185 //final Callback callback = new Callback(OleFrame.class, "getMsgProc", 3); //$NON-NLS-1$
|
|
186 //int address = callback.getAddress();
|
|
187 //if (address is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS);
|
|
188 int threadId = OS.GetCurrentThreadId();
|
|
189 auto hHook_ = OS.SetWindowsHookEx(OS.WH_GETMESSAGE, &getMsgProc, null, threadId);
|
|
190 if (hHook_ is null) {
|
|
191 //callback.dispose();
|
|
192 return;
|
|
193 }
|
|
194 display.setData(HHOOK, new ValueWrapperT!(void*)(hHook_));
|
|
195 display.setData(HHOOKMSG, new ValueWrapperT!(MSG*)(new MSG()));
|
|
196 display.disposeExec(new class(hHook_) Runnable {
|
|
197 void* hHook;
|
|
198 this( void* hHook ){ this.hHook = hHook; }
|
|
199 public void run() {
|
|
200 if (hHook !is null) OS.UnhookWindowsHookEx(hHook);
|
|
201 //if (callback !is null) callback.dispose();
|
|
202 }
|
|
203 });
|
|
204 }
|
|
205 static extern(Windows) int getMsgProc(int code, int wParam, int lParam) {
|
|
206 Display display = Display.getCurrent();
|
|
207 if (display is null) return 0;
|
|
208 auto hHook = cast(ValueWrapperT!(void*))display.getData(HHOOK);
|
|
209 if (hHook is null) return 0;
|
|
210 if (code < 0) {
|
|
211 return OS.CallNextHookEx(hHook.value, code, wParam, lParam);
|
|
212 }
|
|
213 MSG* msg = cast(MSG*)(cast(ValueWrapperT!(MSG*))display.getData(HHOOKMSG)).value;
|
|
214 OS.MoveMemory(msg, lParam, MSG.sizeof);
|
|
215 int message = msg.message;
|
|
216 if (OS.WM_KEYFIRST <= message && message <= OS.WM_KEYLAST) {
|
|
217 if (display !is null) {
|
|
218 Widget widget = null;
|
|
219 auto hwnd = msg.hwnd;
|
|
220 while (hwnd !is null) {
|
|
221 widget = display.findWidget (hwnd);
|
|
222 if (widget !is null) break;
|
|
223 hwnd = OS.GetParent (hwnd);
|
|
224 }
|
|
225 if (widget !is null && (null !is cast(OleClientSite)widget )) {
|
|
226 OleClientSite site = cast(OleClientSite)widget;
|
|
227 if (site.handle is hwnd) {
|
|
228 bool consumed = false;
|
|
229 /* Allow activeX control to translate accelerators except when a menu is active. */
|
|
230 int thread = OS.GetWindowThreadProcessId(msg.hwnd, null);
|
|
231 GUITHREADINFO* lpgui = new GUITHREADINFO();
|
|
232 lpgui.cbSize = GUITHREADINFO.sizeof;
|
|
233 bool rc = cast(bool) OS.GetGUIThreadInfo(thread, lpgui);
|
|
234 int mask = OS.GUI_INMENUMODE | OS.GUI_INMOVESIZE | OS.GUI_POPUPMENUMODE | OS.GUI_SYSTEMMENUMODE;
|
|
235 if (!rc || (lpgui.flags & mask) is 0) {
|
|
236 OleFrame frame = site.frame;
|
|
237 frame.setData(CONSUME_KEY, null);
|
|
238 consumed = frame.translateOleAccelerator(msg);
|
|
239 if (frame.getData(CONSUME_KEY) !is null) consumed = false;
|
|
240 frame.setData(CONSUME_KEY, null);
|
|
241 }
|
|
242 bool accentKey = false;
|
|
243 switch (msg.message) {
|
|
244 case OS.WM_KEYDOWN:
|
|
245 case OS.WM_SYSKEYDOWN: {
|
|
246 if (!OS.IsWinCE) {
|
|
247 switch (msg.wParam) {
|
|
248 case OS.VK_SHIFT:
|
|
249 case OS.VK_MENU:
|
|
250 case OS.VK_CONTROL:
|
|
251 case OS.VK_CAPITAL:
|
|
252 case OS.VK_NUMLOCK:
|
|
253 case OS.VK_SCROLL:
|
|
254 break;
|
|
255 default: {
|
|
256 /*
|
|
257 * Bug in Windows. The high bit in the result of MapVirtualKey() on
|
|
258 * Windows NT is bit 32 while the high bit on Windows 95 is bit 16.
|
|
259 * They should both be bit 32. The fix is to test the right bit.
|
|
260 */
|
|
261 int mapKey = OS.MapVirtualKey (msg.wParam, 2);
|
|
262 if (mapKey !is 0) {
|
|
263 accentKey = (mapKey & (OS.IsWinNT ? 0x80000000 : 0x8000)) !is 0;
|
|
264 if (!accentKey) {
|
|
265 for (int i=0; i<ACCENTS.length; i++) {
|
|
266 int value = OS.VkKeyScan (ACCENTS [i]);
|
|
267 if (value !is -1 && (value & 0xFF) is msg.wParam) {
|
|
268 int state = value >> 8;
|
|
269 if ((OS.GetKeyState (OS.VK_SHIFT) < 0) is ((state & 0x1) !is 0) &&
|
|
270 (OS.GetKeyState (OS.VK_CONTROL) < 0) is ((state & 0x2) !is 0) &&
|
|
271 (OS.GetKeyState (OS.VK_MENU) < 0) is ((state & 0x4) !is 0)) {
|
|
272 if ((state & 0x7) !is 0) accentKey = true;
|
|
273 break;
|
|
274 }
|
|
275 }
|
|
276 }
|
|
277 }
|
|
278 }
|
|
279 break;
|
|
280 }
|
|
281 }
|
|
282 }
|
|
283 break;
|
|
284 }
|
|
285 }
|
|
286 /* Allow OleClientSite to process key events before activeX control */
|
|
287 if (!consumed && !accentKey && !ignoreNextKey) {
|
|
288 auto hwndOld = msg.hwnd;
|
|
289 msg.hwnd = site.handle;
|
|
290 consumed = OS.DispatchMessage (msg) is 1;
|
|
291 msg.hwnd = hwndOld;
|
|
292 }
|
|
293 switch (msg.message) {
|
|
294 case OS.WM_KEYDOWN:
|
|
295 case OS.WM_SYSKEYDOWN: {
|
|
296 switch (msg.wParam) {
|
|
297 case OS.VK_SHIFT:
|
|
298 case OS.VK_MENU:
|
|
299 case OS.VK_CONTROL:
|
|
300 case OS.VK_CAPITAL:
|
|
301 case OS.VK_NUMLOCK:
|
|
302 case OS.VK_SCROLL:
|
|
303 break;
|
|
304 default: {
|
|
305 ignoreNextKey = accentKey;
|
|
306 break;
|
|
307 }
|
|
308 }
|
|
309 }
|
|
310 }
|
|
311
|
|
312 if (consumed) {
|
|
313 // In order to prevent this message from also being processed
|
|
314 // by the application, zero out message, wParam and lParam
|
|
315 msg.message = OS.WM_NULL;
|
|
316 msg.wParam = msg.lParam = 0;
|
|
317 OS.MoveMemory(lParam, msg, MSG.sizeof);
|
|
318 return 0;
|
|
319 }
|
|
320 }
|
|
321 }
|
|
322 }
|
|
323 }
|
|
324 return OS.CallNextHookEx( hHook.value, code, wParam, lParam);
|
|
325 }
|
|
326 /**
|
|
327 * Increment the count of references to this instance
|
|
328 *
|
|
329 * @return the current reference count
|
|
330 */
|
|
331 int AddRef() {
|
|
332 refCount++;
|
|
333 return refCount;
|
|
334 }
|
|
335 private int ContextSensitiveHelp(int fEnterMode) {
|
|
336 return COM.S_OK;
|
|
337 }
|
|
338 private void createCOMInterfaces() {
|
|
339 iOleInPlaceFrame = new _IOleInPlaceFrameImpl(this);
|
|
340 }
|
|
341 private void disposeCOMInterfaces () {
|
|
342 iOleInPlaceFrame = null;
|
|
343 }
|
|
344 private HRESULT GetBorder(LPRECT lprectBorder) {
|
|
345 /*
|
|
346 The IOleInPlaceUIWindow::GetBorder function, when called on a document or frame window
|
|
347 object, returns the outer rectangle (relative to the window) where the object can put
|
|
348 toolbars or similar controls.
|
|
349 */
|
|
350 if (lprectBorder is null) return COM.E_INVALIDARG;
|
|
351 RECT* rectBorder = new RECT();
|
|
352 // Coordinates must be relative to the window
|
|
353 OS.GetClientRect(handle, lprectBorder);
|
|
354 return COM.S_OK;
|
|
355 }
|
|
356 /**
|
|
357 *
|
|
358 * Returns the application menu items that will appear in the Container location when an OLE Document
|
|
359 * is in-place activated.
|
|
360 *
|
|
361 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application
|
|
362 * is given the opportunity to merge some of its menus into the menubar. The application
|
|
363 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window
|
|
364 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help
|
|
365 * menu locations. Note that an application can insert more than one menu into a single location.
|
|
366 *
|
|
367 * @return the application menu items that will appear in the Container location when an OLE Document
|
|
368 * is in-place activated.
|
|
369 *
|
|
370 */
|
|
371 public MenuItem[] getContainerMenus(){
|
|
372 return containerMenuItems;
|
|
373 }
|
|
374 /**
|
|
375 *
|
|
376 * Returns the application menu items that will appear in the File location when an OLE Document
|
|
377 * is in-place activated.
|
|
378 *
|
|
379 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application
|
|
380 * is given the opportunity to merge some of its menus into the menubar. The application
|
|
381 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window
|
|
382 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help
|
|
383 * menu locations. Note that an application can insert more than one menu into a single location.
|
|
384 *
|
|
385 * @return the application menu items that will appear in the File location when an OLE Document
|
|
386 * is in-place activated.
|
|
387 *
|
|
388 */
|
|
389 public MenuItem[] getFileMenus(){
|
|
390 return fileMenuItems;
|
|
391 }
|
|
392 IOleInPlaceFrame getIOleInPlaceFrame() {
|
|
393 return iOleInPlaceFrame;
|
|
394 }
|
|
395 private int getMenuItemID(HMENU hMenu, int index) {
|
|
396 int id = 0;
|
|
397 MENUITEMINFO lpmii;
|
|
398 lpmii.cbSize = MENUITEMINFO.sizeof;
|
|
399 lpmii.fMask = OS.MIIM_STATE | OS.MIIM_SUBMENU | OS.MIIM_ID;
|
|
400 OS.GetMenuItemInfo(hMenu, index, true, &lpmii);
|
|
401 if ((lpmii.fState & OS.MF_POPUP) is OS.MF_POPUP) {
|
|
402 id = cast(int)lpmii.hSubMenu;
|
|
403 } else {
|
|
404 id = lpmii.wID;
|
|
405 }
|
|
406 return id;
|
|
407 }
|
|
408 private int GetWindow(HWND* phwnd) {
|
|
409 if (phwnd !is null) {
|
|
410 *phwnd = handle;
|
|
411 }
|
|
412 return COM.S_OK;
|
|
413 }
|
|
414 /**
|
|
415 *
|
|
416 * Returns the application menu items that will appear in the Window location when an OLE Document
|
|
417 * is in-place activated.
|
|
418 *
|
|
419 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application
|
|
420 * is given the opportunity to merge some of its menus into the menubar. The application
|
|
421 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window
|
|
422 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help
|
|
423 * menu locations. Note that an application can insert more than one menu into a single location.
|
|
424 *
|
|
425 * @return the application menu items that will appear in the Window location when an OLE Document
|
|
426 * is in-place activated.
|
|
427 *
|
|
428 */
|
|
429 public MenuItem[] getWindowMenus(){
|
|
430 return windowMenuItems;
|
|
431 }
|
|
432 private HRESULT InsertMenus( HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths ) {
|
|
433 // locate menu bar
|
|
434 Menu menubar = getShell().getMenuBar();
|
|
435 if (menubar is null || menubar.isDisposed()) {
|
|
436 int temp = 0;
|
|
437 COM.MoveMemory(lpMenuWidths, &temp, 4);
|
|
438 return COM.S_OK;
|
|
439 }
|
|
440 HMENU hMenu = menubar.handle;
|
|
441
|
|
442 // Create a holder for menu information. This will be passed down to
|
|
443 // the OS and the OS will fill in the requested information for each menu.
|
|
444 MENUITEMINFO lpmii;
|
|
445 auto hHeap = OS.GetProcessHeap();
|
|
446 int cch = 128;
|
|
447 int byteCount = cch * TCHAR.sizeof;
|
|
448 auto pszText = cast(TCHAR*) OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
|
|
449 lpmii.cbSize = MENUITEMINFO.sizeof;
|
|
450 lpmii.fMask = OS.MIIM_STATE | OS.MIIM_ID | OS.MIIM_TYPE | OS.MIIM_SUBMENU | OS.MIIM_DATA;
|
|
451 lpmii.dwTypeData = pszText;
|
|
452 lpmii.cch = cch;
|
|
453
|
|
454 // Loop over all "File-like" menus in the menubar and get information about the
|
|
455 // item from the OS.
|
|
456 int fileMenuCount = 0;
|
|
457 int newindex = 0;
|
|
458 if (this.fileMenuItems !is null) {
|
|
459 for (int i = 0; i < this.fileMenuItems.length; i++) {
|
|
460 MenuItem item = this.fileMenuItems[i];
|
|
461 if (item !is null) {
|
|
462 int index = item.getParent().indexOf(item);
|
|
463 lpmii.cch = cch; // lpmii.cch gets updated by GetMenuItemInfo to indicate the
|
|
464 // exact number of characters in name. Reset it to our max size
|
|
465 // before each call.
|
|
466 if (OS.GetMenuItemInfo(hMenu, index, true, &lpmii)) {
|
|
467 if (OS.InsertMenuItem(hmenuShared, newindex, true, &lpmii)) {
|
|
468 // keep track of the number of items
|
|
469 fileMenuCount++;
|
|
470 newindex++;
|
|
471 }
|
|
472 }
|
|
473 }
|
|
474 }
|
|
475 }
|
|
476
|
|
477 // copy the menu item count information to the pointer
|
|
478 COM.MoveMemory(lpMenuWidths, &fileMenuCount, 4);
|
|
479
|
|
480 // Loop over all "Container-like" menus in the menubar and get information about the
|
|
481 // item from the OS.
|
|
482 int containerMenuCount = 0;
|
|
483 if (this.containerMenuItems !is null) {
|
|
484 for (int i = 0; i < this.containerMenuItems.length; i++) {
|
|
485 MenuItem item = this.containerMenuItems[i];
|
|
486 if (item !is null) {
|
|
487 int index = item.getParent().indexOf(item);
|
|
488 lpmii.cch = cch; // lpmii.cch gets updated by GetMenuItemInfo to indicate the
|
|
489 // exact number of characters in name. Reset it to a large number
|
|
490 // before each call.
|
|
491 if (OS.GetMenuItemInfo(hMenu, index, true, &lpmii)) {
|
|
492 if (OS.InsertMenuItem(hmenuShared, newindex, true, &lpmii)) {
|
|
493 // keep track of the number of items
|
|
494 containerMenuCount++;
|
|
495 newindex++;
|
|
496 }
|
|
497 }
|
|
498 }
|
|
499 }
|
|
500 }
|
|
501
|
|
502 // copy the menu item count information to the pointer
|
|
503 COM.MoveMemory(lpMenuWidths + 8, &containerMenuCount, 4);
|
|
504
|
|
505 // Loop over all "Window-like" menus in the menubar and get information about the
|
|
506 // item from the OS.
|
|
507 int windowMenuCount = 0;
|
|
508 if (this.windowMenuItems !is null) {
|
|
509 for (int i = 0; i < this.windowMenuItems.length; i++) {
|
|
510 MenuItem item = this.windowMenuItems[i];
|
|
511 if (item !is null) {
|
|
512 int index = item.getParent().indexOf(item);
|
|
513 lpmii.cch = cch; // lpmii.cch gets updated by GetMenuItemInfo to indicate the
|
|
514 // exact number of characters in name. Reset it to a large number
|
|
515 // before each call.
|
|
516 if (OS.GetMenuItemInfo(hMenu, index, true, &lpmii)) {
|
|
517 if (OS.InsertMenuItem(hmenuShared, newindex, true, &lpmii)) {
|
|
518 // keep track of the number of items
|
|
519 windowMenuCount++;
|
|
520 newindex++;
|
|
521 }
|
|
522 }
|
|
523 }
|
|
524 }
|
|
525 }
|
|
526
|
|
527 // copy the menu item count information to the pointer
|
|
528 COM.MoveMemory(lpMenuWidths + 16, &windowMenuCount, 4);
|
|
529
|
|
530 // free resources used in querying the OS
|
|
531 if (pszText !is null)
|
|
532 OS.HeapFree(hHeap, 0, pszText);
|
|
533 return COM.S_OK;
|
|
534 }
|
|
535 void onActivate(Event e) {
|
|
536 if (objIOleInPlaceActiveObject !is null) {
|
|
537 objIOleInPlaceActiveObject.OnFrameWindowActivate(true);
|
|
538 }
|
|
539 if (objIOleInPlaceActiveObject !is null) {
|
|
540 objIOleInPlaceActiveObject.OnDocWindowActivate(true);
|
|
541 }
|
|
542 }
|
|
543 void onDeactivate(Event e) {
|
|
544 if (objIOleInPlaceActiveObject !is null) {
|
|
545 objIOleInPlaceActiveObject.OnFrameWindowActivate(false);
|
|
546 }
|
|
547 if (objIOleInPlaceActiveObject !is null) {
|
|
548 objIOleInPlaceActiveObject.OnDocWindowActivate(false);
|
|
549 }
|
|
550 }
|
|
551 private void onDispose(Event e) {
|
|
552
|
|
553 releaseObjectInterfaces();
|
|
554 currentdoc = null;
|
|
555
|
|
556 this.Release();
|
|
557 removeListener(DWT.Activate, listener);
|
|
558 removeListener(DWT.Deactivate, listener);
|
|
559 removeListener(DWT.Dispose, listener);
|
|
560 removeListener(DWT.Resize, listener);
|
|
561 removeListener(DWT.Move, listener);
|
|
562 }
|
|
563 private void onResize(Event e) {
|
|
564 if (objIOleInPlaceActiveObject !is null) {
|
|
565 RECT lpRect;
|
|
566 OS.GetClientRect(handle, &lpRect);
|
|
567 objIOleInPlaceActiveObject.ResizeBorder(&lpRect, iOleInPlaceFrame, true);
|
|
568 }
|
|
569 }
|
|
570 private HRESULT QueryInterface(REFIID riid, void** ppvObject) {
|
|
571 // implements IUnknown, IOleInPlaceFrame, IOleContainer, IOleInPlaceUIWindow
|
|
572 if (riid is null || ppvObject is null)
|
|
573 return COM.E_INVALIDARG;
|
|
574
|
|
575 if (COM.IsEqualGUID(riid, &COM.IIDIUnknown) || COM.IsEqualGUID(riid, &COM.IIDIOleInPlaceFrame) ) {
|
|
576 *ppvObject = cast(void*)iOleInPlaceFrame;
|
|
577 AddRef();
|
|
578 return COM.S_OK;
|
|
579 }
|
|
580
|
|
581 *ppvObject = null;
|
|
582 return COM.E_NOINTERFACE;
|
|
583 }
|
|
584 /**
|
|
585 * Decrement the count of references to this instance
|
|
586 *
|
|
587 * @return the current reference count
|
|
588 */
|
|
589 int Release() {
|
|
590 refCount--;
|
|
591 if (refCount is 0){
|
|
592 disposeCOMInterfaces();
|
|
593 COM.CoFreeUnusedLibraries();
|
|
594 }
|
|
595 return refCount;
|
|
596 }
|
|
597 private void releaseObjectInterfaces() {
|
|
598 if (objIOleInPlaceActiveObject !is null) {
|
|
599 objIOleInPlaceActiveObject.Release();
|
|
600 }
|
|
601 objIOleInPlaceActiveObject = null;
|
|
602 }
|
|
603 private int RemoveMenus(HMENU hmenuShared) {
|
|
604
|
|
605 Menu menubar = getShell().getMenuBar();
|
|
606 if (menubar is null || menubar.isDisposed()) return COM.S_FALSE;
|
|
607
|
|
608 auto hMenu = menubar.handle;
|
|
609
|
|
610 int[] ids;
|
|
611 if (this.fileMenuItems !is null) {
|
|
612 for (int i = 0; i < this.fileMenuItems.length; i++) {
|
|
613 MenuItem item = this.fileMenuItems[i];
|
|
614 if (item !is null && !item.isDisposed()) {
|
|
615 int index = item.getParent().indexOf(item);
|
|
616 // get Id from original menubar
|
|
617 int id = getMenuItemID(hMenu, index);
|
|
618 ids ~= id;
|
|
619 }
|
|
620 }
|
|
621 }
|
|
622 if (this.containerMenuItems !is null) {
|
|
623 for (int i = 0; i < this.containerMenuItems.length; i++) {
|
|
624 MenuItem item = this.containerMenuItems[i];
|
|
625 if (item !is null && !item.isDisposed()) {
|
|
626 int index = item.getParent().indexOf(item);
|
|
627 int id = getMenuItemID(hMenu, index);
|
|
628 ids ~= id;
|
|
629 }
|
|
630 }
|
|
631 }
|
|
632 if (this.windowMenuItems !is null) {
|
|
633 for (int i = 0; i < this.windowMenuItems.length; i++) {
|
|
634 MenuItem item = this.windowMenuItems[i];
|
|
635 if (item !is null && !item.isDisposed()) {
|
|
636 int index = item.getParent().indexOf(item);
|
|
637 int id = getMenuItemID(hMenu, index);
|
|
638 ids ~= id;
|
|
639 }
|
|
640 }
|
|
641 }
|
|
642 int index = OS.GetMenuItemCount(hmenuShared) - 1;
|
|
643 for (int i = index; i >= 0; i--) {
|
|
644 int id = getMenuItemID(hmenuShared, i);
|
|
645 if ( ids.contains(id)){
|
|
646 OS.RemoveMenu(hmenuShared, i, OS.MF_BYPOSITION);
|
|
647 }
|
|
648 }
|
|
649 return COM.S_OK;
|
|
650 }
|
|
651 private int RequestBorderSpace(LPCBORDERWIDTHS pborderwidths) {
|
|
652 return COM.S_OK;
|
|
653 }
|
|
654 HRESULT SetActiveObject( LPOLEINPLACEACTIVEOBJECT pActiveObject, LPCOLESTR pszObjName ) {
|
|
655 if (objIOleInPlaceActiveObject !is null) {
|
|
656 objIOleInPlaceActiveObject.Release();
|
|
657 objIOleInPlaceActiveObject = null;
|
|
658 }
|
|
659 if (pActiveObject !is null) {
|
|
660 objIOleInPlaceActiveObject = pActiveObject;
|
|
661 objIOleInPlaceActiveObject.AddRef();
|
|
662 }
|
|
663
|
|
664 return COM.S_OK;
|
|
665 }
|
|
666
|
|
667 private HRESULT SetBorderSpace( LPCBORDERWIDTHS pborderwidths ) {
|
|
668 // A Control/Document can :
|
|
669 // Use its own toolbars, requesting border space of a specific size, or,
|
|
670 // Use no toolbars, but force the container to remove its toolbars by passing a
|
|
671 // valid BORDERWIDTHS structure containing nothing but zeros in the pborderwidths parameter, or,
|
|
672 // Use no toolbars but allow the in-place container to leave its toolbars up by
|
|
673 // passing NULL as the pborderwidths parameter.
|
|
674 if (objIOleInPlaceActiveObject is null) return COM.S_OK;
|
|
675 RECT* borderwidth = new RECT();
|
|
676 if (pborderwidths is null || currentdoc is null ) return COM.S_OK;
|
|
677
|
|
678 COM.MoveMemory(borderwidth, pborderwidths, RECT.sizeof);
|
|
679 currentdoc.setBorderSpace(borderwidth);
|
|
680
|
|
681 return COM.S_OK;
|
|
682 }
|
|
683 /**
|
|
684 *
|
|
685 * Specify the menu items that should appear in the Container location when an OLE Document
|
|
686 * is in-place activated.
|
|
687 *
|
|
688 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application
|
|
689 * is given the opportunity to merge some of its menus into the menubar. The application
|
|
690 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window
|
|
691 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help
|
|
692 * menu locations. Note that an application can insert more than one menu into a single location.
|
|
693 *
|
|
694 * <p>This method must be called before in place activation of the OLE Document. After the Document
|
|
695 * is activated, the menu bar will not be modified until a subsequent activation.
|
|
696 *
|
|
697 * @param containerMenus an array of top level MenuItems to be inserted into the Container location of
|
|
698 * the menubar
|
|
699 */
|
|
700 public void setContainerMenus(MenuItem[] containerMenus){
|
|
701 containerMenuItems = containerMenus;
|
|
702 }
|
|
703 OleClientSite getCurrentDocument() {
|
|
704 return currentdoc;
|
|
705 }
|
|
706 void setCurrentDocument(OleClientSite doc) {
|
|
707 currentdoc = doc;
|
|
708
|
|
709 if (currentdoc !is null && objIOleInPlaceActiveObject !is null) {
|
|
710 RECT lpRect;
|
|
711 OS.GetClientRect(handle, &lpRect);
|
|
712 objIOleInPlaceActiveObject.ResizeBorder(&lpRect, iOleInPlaceFrame, true);
|
|
713 }
|
|
714 }
|
|
715 /**
|
|
716 *
|
|
717 * Specify the menu items that should appear in the File location when an OLE Document
|
|
718 * is in-place activated.
|
|
719 *
|
|
720 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application
|
|
721 * is given the opportunity to merge some of its menus into the menubar. The application
|
|
722 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window
|
|
723 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help
|
|
724 * menu locations. Note that an application can insert more than one menu into a single location.
|
|
725 *
|
|
726 * <p>This method must be called before in place activation of the OLE Document. After the Document
|
|
727 * is activated, the menu bar will not be modified until a subsequent activation.
|
|
728 *
|
|
729 * @param fileMenus an array of top level MenuItems to be inserted into the File location of
|
|
730 * the menubar
|
|
731 */
|
|
732 public void setFileMenus(MenuItem[] fileMenus){
|
|
733 fileMenuItems = fileMenus;
|
|
734 }
|
|
735 HRESULT SetMenu( HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject ) {
|
|
736 IOleInPlaceActiveObject inPlaceActiveObject;
|
|
737 if (objIOleInPlaceActiveObject !is null)
|
|
738 inPlaceActiveObject = objIOleInPlaceActiveObject;
|
|
739
|
|
740 Menu menubar = getShell().getMenuBar();
|
|
741 if (menubar is null || menubar.isDisposed()){
|
|
742 return COM.OleSetMenuDescriptor(null, getShell().handle, hwndActiveObject, iOleInPlaceFrame, inPlaceActiveObject);
|
|
743 }
|
|
744
|
|
745 HWND handle = menubar.getShell().handle;
|
|
746
|
|
747 if (hmenuShared is null && holemenu is null) {
|
|
748 // re-instate the original menu - this occurs on deactivation
|
|
749 hmenuShared = menubar.handle;
|
|
750 }
|
|
751 if (hmenuShared is null) return COM.E_FAIL;
|
|
752
|
|
753 OS.SetMenu(handle, hmenuShared);
|
|
754 OS.DrawMenuBar(handle);
|
|
755
|
|
756 return COM.OleSetMenuDescriptor(holemenu, handle, hwndActiveObject, iOleInPlaceFrame, inPlaceActiveObject);
|
|
757 }
|
|
758
|
|
759 /**
|
|
760 *
|
|
761 * Set the menu items that should appear in the Window location when an OLE Document
|
|
762 * is in-place activated.
|
|
763 *
|
|
764 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application
|
|
765 * is given the opportunity to merge some of its menus into the menubar. The application
|
|
766 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window
|
|
767 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help
|
|
768 * menu locations. Note that an application can insert more than one menu into a single location.
|
|
769 *
|
|
770 * <p>This method must be called before in place activation of the OLE Document. After the Document
|
|
771 * is activated, the menu bar will not be modified until a subsequent activation.
|
|
772 *
|
|
773 * @param windowMenus an array of top level MenuItems to be inserted into the Window location of
|
|
774 * the menubar
|
|
775 */
|
|
776 public void setWindowMenus(MenuItem[] windowMenus){
|
|
777 windowMenuItems = windowMenus;
|
|
778 }
|
|
779 private bool translateOleAccelerator(MSG* msg) {
|
|
780 if (objIOleInPlaceActiveObject is null) return false;
|
|
781 int result = objIOleInPlaceActiveObject.TranslateAccelerator(msg);
|
|
782 return (result != COM.S_FALSE && result != COM.E_NOTIMPL);
|
|
783 }
|
|
784
|
|
785 HRESULT TranslateAccelerator( LPMSG lpmsg, WORD wID ){
|
|
786 Menu menubar = getShell().getMenuBar();
|
|
787 if (menubar is null || menubar.isDisposed() || !menubar.isEnabled()) return COM.S_FALSE;
|
|
788 if (wID < 0) return COM.S_FALSE;
|
|
789
|
|
790 Shell shell = menubar.getShell();
|
|
791 HWND hwnd = shell.handle;
|
|
792 HACCEL hAccel = cast(HACCEL)OS.SendMessage(hwnd, OS.WM_APP+1, 0, 0);
|
|
793 if (hAccel is null) return COM.S_FALSE;
|
|
794
|
|
795 MSG msg = *lpmsg;
|
|
796 int result = OS.TranslateAccelerator(hwnd, hAccel, &msg);
|
|
797 return result == 0 ? COM.S_FALSE : COM.S_OK;
|
|
798 }
|
|
799 }
|
|
800
|
|
801 // implements IOleInPlaceFrame, IOleInPlaceUIWindow, IOleWindow, IUnknown
|
|
802 class _IOleInPlaceFrameImpl : IOleInPlaceFrame {
|
|
803
|
|
804 OleFrame parent;
|
|
805 this(OleFrame p) { parent = p; }
|
|
806 extern (Windows) :
|
|
807 // interface of IUnknown
|
|
808 HRESULT QueryInterface(REFIID riid, void ** ppvObject) { return parent.QueryInterface(riid, ppvObject); }
|
|
809 ULONG AddRef() { return parent.AddRef(); }
|
|
810 ULONG Release() { return parent.Release(); }
|
|
811
|
|
812 // interface IOleWindow
|
|
813 HRESULT GetWindow( HWND * phwnd ) { return parent.GetWindow(phwnd); }
|
|
814 HRESULT ContextSensitiveHelp( BOOL fEnterMode ){ return COM.S_OK; }
|
|
815
|
|
816 //interface IOleInPlaceUIWindow
|
|
817 HRESULT GetBorder( LPRECT lprectBorder ) { return parent.GetBorder(lprectBorder); }
|
|
818 HRESULT RequestBorderSpace( LPCBORDERWIDTHS pborderwidths ){ return COM.S_OK; }
|
|
819 HRESULT SetBorderSpace( LPCBORDERWIDTHS pborderwidths ) { return parent.SetBorderSpace(pborderwidths); }
|
|
820 HRESULT SetActiveObject( LPOLEINPLACEACTIVEOBJECT pActiveObject, LPCOLESTR pszObjName ) {
|
|
821 return parent.SetActiveObject(pActiveObject, pszObjName);
|
|
822 }
|
|
823
|
|
824 // interface IOleInPlaceFrame : IOleInPlaceUIWindow
|
|
825 HRESULT InsertMenus( HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths ){
|
|
826 return parent.InsertMenus(hmenuShared, lpMenuWidths);
|
|
827 }
|
|
828 HRESULT SetMenu( HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject ){
|
|
829 return parent.SetMenu(hmenuShared, holemenu, hwndActiveObject);
|
|
830 }
|
|
831 HRESULT RemoveMenus( HMENU hmenuShared ) {
|
|
832 return parent.RemoveMenus(hmenuShared);
|
|
833 }
|
|
834 HRESULT SetStatusText( LPCOLESTR pszStatusText ) { return COM.E_NOTIMPL; }
|
|
835 HRESULT EnableModeless( BOOL fEnable ) { return COM.E_NOTIMPL; }
|
|
836 HRESULT TranslateAccelerator( LPMSG lpmsg, WORD wID ) {
|
|
837 return parent.TranslateAccelerator(lpmsg, wID);
|
|
838 }
|
|
839
|
|
840 }
|
|
841
|