Mercurial > projects > dwt-win
annotate dwt/ole/win32/OleFrame.d @ 212:ab60f3309436
reverted the char[] to String and use the an alias.
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Mon, 05 May 2008 00:12:38 +0200 |
parents | 619faee45ef6 |
children | fd9c62a2998e |
rev | line source |
---|---|
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 | |
212
ab60f3309436
reverted the char[] to String and use the an alias.
Frank Benoit <benoit@tionex.de>
parents:
162
diff
changeset
|
76 private static String CHECK_FOCUS = "OLE_CHECK_FOCUS"; //$NON-NLS-1$ |
ab60f3309436
reverted the char[] to String and use the an alias.
Frank Benoit <benoit@tionex.de>
parents:
162
diff
changeset
|
77 private static String HHOOK = "OLE_HHOOK"; //$NON-NLS-1$ |
ab60f3309436
reverted the char[] to String and use the an alias.
Frank Benoit <benoit@tionex.de>
parents:
162
diff
changeset
|
78 private static String HHOOKMSG = "OLE_HHOOK_MSG"; //$NON-NLS-1$ |
98 | 79 |
80 private static bool ignoreNextKey; | |
81 private static const short [] ACCENTS = [ cast(short)'~', '`', '\'', '^', '"']; | |
82 | |
212
ab60f3309436
reverted the char[] to String and use the an alias.
Frank Benoit <benoit@tionex.de>
parents:
162
diff
changeset
|
83 private static const String CONSUME_KEY = "org.eclipse.swt.OleFrame.ConsumeKey"; //$NON-NLS-1$ |
98 | 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 } | |
128
07e8963537b7
removed tango_sys_win32 and added all necessary bindings to the dwt.internal.win32 WINTYPES and WINAPI modules
Frank Benoit <benoit@tionex.de>
parents:
117
diff
changeset
|
205 static extern(Windows) int getMsgProc(int code, uint wParam, int lParam) { |
98 | 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: { | |
117 | 246 static if (!OS.IsWinCE) { |
98 | 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 } | |
162
619faee45ef6
add missing default cases
Thomas Graber <d4rkdragon@gmail.com>
parents:
128
diff
changeset
|
285 default: |
98 | 286 } |
287 /* Allow OleClientSite to process key events before activeX control */ | |
288 if (!consumed && !accentKey && !ignoreNextKey) { | |
289 auto hwndOld = msg.hwnd; | |
290 msg.hwnd = site.handle; | |
291 consumed = OS.DispatchMessage (msg) is 1; | |
292 msg.hwnd = hwndOld; | |
293 } | |
294 switch (msg.message) { | |
295 case OS.WM_KEYDOWN: | |
296 case OS.WM_SYSKEYDOWN: { | |
297 switch (msg.wParam) { | |
298 case OS.VK_SHIFT: | |
299 case OS.VK_MENU: | |
300 case OS.VK_CONTROL: | |
301 case OS.VK_CAPITAL: | |
302 case OS.VK_NUMLOCK: | |
303 case OS.VK_SCROLL: | |
304 break; | |
305 default: { | |
306 ignoreNextKey = accentKey; | |
307 break; | |
308 } | |
309 } | |
310 } | |
162
619faee45ef6
add missing default cases
Thomas Graber <d4rkdragon@gmail.com>
parents:
128
diff
changeset
|
311 default: |
98 | 312 } |
313 | |
314 if (consumed) { | |
315 // In order to prevent this message from also being processed | |
316 // by the application, zero out message, wParam and lParam | |
317 msg.message = OS.WM_NULL; | |
318 msg.wParam = msg.lParam = 0; | |
319 OS.MoveMemory(lParam, msg, MSG.sizeof); | |
320 return 0; | |
321 } | |
322 } | |
323 } | |
324 } | |
325 } | |
326 return OS.CallNextHookEx( hHook.value, code, wParam, lParam); | |
327 } | |
328 /** | |
329 * Increment the count of references to this instance | |
330 * | |
331 * @return the current reference count | |
332 */ | |
333 int AddRef() { | |
334 refCount++; | |
335 return refCount; | |
336 } | |
337 private int ContextSensitiveHelp(int fEnterMode) { | |
338 return COM.S_OK; | |
339 } | |
340 private void createCOMInterfaces() { | |
341 iOleInPlaceFrame = new _IOleInPlaceFrameImpl(this); | |
342 } | |
343 private void disposeCOMInterfaces () { | |
344 iOleInPlaceFrame = null; | |
345 } | |
346 private HRESULT GetBorder(LPRECT lprectBorder) { | |
347 /* | |
348 The IOleInPlaceUIWindow::GetBorder function, when called on a document or frame window | |
349 object, returns the outer rectangle (relative to the window) where the object can put | |
350 toolbars or similar controls. | |
351 */ | |
352 if (lprectBorder is null) return COM.E_INVALIDARG; | |
353 RECT* rectBorder = new RECT(); | |
354 // Coordinates must be relative to the window | |
355 OS.GetClientRect(handle, lprectBorder); | |
356 return COM.S_OK; | |
357 } | |
358 /** | |
359 * | |
360 * Returns the application menu items that will appear in the Container location when an OLE Document | |
361 * is in-place activated. | |
362 * | |
363 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application | |
364 * is given the opportunity to merge some of its menus into the menubar. The application | |
365 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window | |
366 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help | |
367 * menu locations. Note that an application can insert more than one menu into a single location. | |
368 * | |
369 * @return the application menu items that will appear in the Container location when an OLE Document | |
370 * is in-place activated. | |
371 * | |
372 */ | |
373 public MenuItem[] getContainerMenus(){ | |
374 return containerMenuItems; | |
375 } | |
376 /** | |
377 * | |
378 * Returns the application menu items that will appear in the File location when an OLE Document | |
379 * is in-place activated. | |
380 * | |
381 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application | |
382 * is given the opportunity to merge some of its menus into the menubar. The application | |
383 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window | |
384 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help | |
385 * menu locations. Note that an application can insert more than one menu into a single location. | |
386 * | |
387 * @return the application menu items that will appear in the File location when an OLE Document | |
388 * is in-place activated. | |
389 * | |
390 */ | |
391 public MenuItem[] getFileMenus(){ | |
392 return fileMenuItems; | |
393 } | |
394 IOleInPlaceFrame getIOleInPlaceFrame() { | |
395 return iOleInPlaceFrame; | |
396 } | |
397 private int getMenuItemID(HMENU hMenu, int index) { | |
398 int id = 0; | |
399 MENUITEMINFO lpmii; | |
400 lpmii.cbSize = MENUITEMINFO.sizeof; | |
401 lpmii.fMask = OS.MIIM_STATE | OS.MIIM_SUBMENU | OS.MIIM_ID; | |
402 OS.GetMenuItemInfo(hMenu, index, true, &lpmii); | |
403 if ((lpmii.fState & OS.MF_POPUP) is OS.MF_POPUP) { | |
404 id = cast(int)lpmii.hSubMenu; | |
405 } else { | |
406 id = lpmii.wID; | |
407 } | |
408 return id; | |
409 } | |
410 private int GetWindow(HWND* phwnd) { | |
411 if (phwnd !is null) { | |
412 *phwnd = handle; | |
413 } | |
414 return COM.S_OK; | |
415 } | |
416 /** | |
417 * | |
418 * Returns the application menu items that will appear in the Window location when an OLE Document | |
419 * is in-place activated. | |
420 * | |
421 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application | |
422 * is given the opportunity to merge some of its menus into the menubar. The application | |
423 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window | |
424 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help | |
425 * menu locations. Note that an application can insert more than one menu into a single location. | |
426 * | |
427 * @return the application menu items that will appear in the Window location when an OLE Document | |
428 * is in-place activated. | |
429 * | |
430 */ | |
431 public MenuItem[] getWindowMenus(){ | |
432 return windowMenuItems; | |
433 } | |
434 private HRESULT InsertMenus( HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths ) { | |
435 // locate menu bar | |
436 Menu menubar = getShell().getMenuBar(); | |
437 if (menubar is null || menubar.isDisposed()) { | |
438 int temp = 0; | |
439 COM.MoveMemory(lpMenuWidths, &temp, 4); | |
440 return COM.S_OK; | |
441 } | |
442 HMENU hMenu = menubar.handle; | |
443 | |
444 // Create a holder for menu information. This will be passed down to | |
445 // the OS and the OS will fill in the requested information for each menu. | |
446 MENUITEMINFO lpmii; | |
447 auto hHeap = OS.GetProcessHeap(); | |
448 int cch = 128; | |
449 int byteCount = cch * TCHAR.sizeof; | |
450 auto pszText = cast(TCHAR*) OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount); | |
451 lpmii.cbSize = MENUITEMINFO.sizeof; | |
452 lpmii.fMask = OS.MIIM_STATE | OS.MIIM_ID | OS.MIIM_TYPE | OS.MIIM_SUBMENU | OS.MIIM_DATA; | |
453 lpmii.dwTypeData = pszText; | |
454 lpmii.cch = cch; | |
455 | |
456 // Loop over all "File-like" menus in the menubar and get information about the | |
457 // item from the OS. | |
458 int fileMenuCount = 0; | |
459 int newindex = 0; | |
460 if (this.fileMenuItems !is null) { | |
461 for (int i = 0; i < this.fileMenuItems.length; i++) { | |
462 MenuItem item = this.fileMenuItems[i]; | |
463 if (item !is null) { | |
464 int index = item.getParent().indexOf(item); | |
465 lpmii.cch = cch; // lpmii.cch gets updated by GetMenuItemInfo to indicate the | |
466 // exact number of characters in name. Reset it to our max size | |
467 // before each call. | |
468 if (OS.GetMenuItemInfo(hMenu, index, true, &lpmii)) { | |
469 if (OS.InsertMenuItem(hmenuShared, newindex, true, &lpmii)) { | |
470 // keep track of the number of items | |
471 fileMenuCount++; | |
472 newindex++; | |
473 } | |
474 } | |
475 } | |
476 } | |
477 } | |
478 | |
479 // copy the menu item count information to the pointer | |
480 COM.MoveMemory(lpMenuWidths, &fileMenuCount, 4); | |
481 | |
482 // Loop over all "Container-like" menus in the menubar and get information about the | |
483 // item from the OS. | |
484 int containerMenuCount = 0; | |
485 if (this.containerMenuItems !is null) { | |
486 for (int i = 0; i < this.containerMenuItems.length; i++) { | |
487 MenuItem item = this.containerMenuItems[i]; | |
488 if (item !is null) { | |
489 int index = item.getParent().indexOf(item); | |
490 lpmii.cch = cch; // lpmii.cch gets updated by GetMenuItemInfo to indicate the | |
491 // exact number of characters in name. Reset it to a large number | |
492 // before each call. | |
493 if (OS.GetMenuItemInfo(hMenu, index, true, &lpmii)) { | |
494 if (OS.InsertMenuItem(hmenuShared, newindex, true, &lpmii)) { | |
495 // keep track of the number of items | |
496 containerMenuCount++; | |
497 newindex++; | |
498 } | |
499 } | |
500 } | |
501 } | |
502 } | |
503 | |
504 // copy the menu item count information to the pointer | |
505 COM.MoveMemory(lpMenuWidths + 8, &containerMenuCount, 4); | |
506 | |
507 // Loop over all "Window-like" menus in the menubar and get information about the | |
508 // item from the OS. | |
509 int windowMenuCount = 0; | |
510 if (this.windowMenuItems !is null) { | |
511 for (int i = 0; i < this.windowMenuItems.length; i++) { | |
512 MenuItem item = this.windowMenuItems[i]; | |
513 if (item !is null) { | |
514 int index = item.getParent().indexOf(item); | |
515 lpmii.cch = cch; // lpmii.cch gets updated by GetMenuItemInfo to indicate the | |
516 // exact number of characters in name. Reset it to a large number | |
517 // before each call. | |
518 if (OS.GetMenuItemInfo(hMenu, index, true, &lpmii)) { | |
519 if (OS.InsertMenuItem(hmenuShared, newindex, true, &lpmii)) { | |
520 // keep track of the number of items | |
521 windowMenuCount++; | |
522 newindex++; | |
523 } | |
524 } | |
525 } | |
526 } | |
527 } | |
528 | |
529 // copy the menu item count information to the pointer | |
530 COM.MoveMemory(lpMenuWidths + 16, &windowMenuCount, 4); | |
531 | |
532 // free resources used in querying the OS | |
533 if (pszText !is null) | |
534 OS.HeapFree(hHeap, 0, pszText); | |
535 return COM.S_OK; | |
536 } | |
537 void onActivate(Event e) { | |
538 if (objIOleInPlaceActiveObject !is null) { | |
539 objIOleInPlaceActiveObject.OnFrameWindowActivate(true); | |
540 } | |
541 if (objIOleInPlaceActiveObject !is null) { | |
542 objIOleInPlaceActiveObject.OnDocWindowActivate(true); | |
543 } | |
544 } | |
545 void onDeactivate(Event e) { | |
546 if (objIOleInPlaceActiveObject !is null) { | |
547 objIOleInPlaceActiveObject.OnFrameWindowActivate(false); | |
548 } | |
549 if (objIOleInPlaceActiveObject !is null) { | |
550 objIOleInPlaceActiveObject.OnDocWindowActivate(false); | |
551 } | |
552 } | |
553 private void onDispose(Event e) { | |
554 | |
555 releaseObjectInterfaces(); | |
556 currentdoc = null; | |
557 | |
558 this.Release(); | |
559 removeListener(DWT.Activate, listener); | |
560 removeListener(DWT.Deactivate, listener); | |
561 removeListener(DWT.Dispose, listener); | |
562 removeListener(DWT.Resize, listener); | |
563 removeListener(DWT.Move, listener); | |
564 } | |
565 private void onResize(Event e) { | |
566 if (objIOleInPlaceActiveObject !is null) { | |
567 RECT lpRect; | |
568 OS.GetClientRect(handle, &lpRect); | |
569 objIOleInPlaceActiveObject.ResizeBorder(&lpRect, iOleInPlaceFrame, true); | |
570 } | |
571 } | |
572 private HRESULT QueryInterface(REFIID riid, void** ppvObject) { | |
573 // implements IUnknown, IOleInPlaceFrame, IOleContainer, IOleInPlaceUIWindow | |
574 if (riid is null || ppvObject is null) | |
575 return COM.E_INVALIDARG; | |
576 | |
577 if (COM.IsEqualGUID(riid, &COM.IIDIUnknown) || COM.IsEqualGUID(riid, &COM.IIDIOleInPlaceFrame) ) { | |
578 *ppvObject = cast(void*)iOleInPlaceFrame; | |
579 AddRef(); | |
580 return COM.S_OK; | |
581 } | |
582 | |
583 *ppvObject = null; | |
584 return COM.E_NOINTERFACE; | |
585 } | |
586 /** | |
587 * Decrement the count of references to this instance | |
588 * | |
589 * @return the current reference count | |
590 */ | |
591 int Release() { | |
592 refCount--; | |
593 if (refCount is 0){ | |
594 disposeCOMInterfaces(); | |
595 COM.CoFreeUnusedLibraries(); | |
596 } | |
597 return refCount; | |
598 } | |
599 private void releaseObjectInterfaces() { | |
600 if (objIOleInPlaceActiveObject !is null) { | |
601 objIOleInPlaceActiveObject.Release(); | |
602 } | |
603 objIOleInPlaceActiveObject = null; | |
604 } | |
605 private int RemoveMenus(HMENU hmenuShared) { | |
606 | |
607 Menu menubar = getShell().getMenuBar(); | |
608 if (menubar is null || menubar.isDisposed()) return COM.S_FALSE; | |
609 | |
610 auto hMenu = menubar.handle; | |
611 | |
612 int[] ids; | |
613 if (this.fileMenuItems !is null) { | |
614 for (int i = 0; i < this.fileMenuItems.length; i++) { | |
615 MenuItem item = this.fileMenuItems[i]; | |
616 if (item !is null && !item.isDisposed()) { | |
617 int index = item.getParent().indexOf(item); | |
618 // get Id from original menubar | |
619 int id = getMenuItemID(hMenu, index); | |
620 ids ~= id; | |
621 } | |
622 } | |
623 } | |
624 if (this.containerMenuItems !is null) { | |
625 for (int i = 0; i < this.containerMenuItems.length; i++) { | |
626 MenuItem item = this.containerMenuItems[i]; | |
627 if (item !is null && !item.isDisposed()) { | |
628 int index = item.getParent().indexOf(item); | |
629 int id = getMenuItemID(hMenu, index); | |
630 ids ~= id; | |
631 } | |
632 } | |
633 } | |
634 if (this.windowMenuItems !is null) { | |
635 for (int i = 0; i < this.windowMenuItems.length; i++) { | |
636 MenuItem item = this.windowMenuItems[i]; | |
637 if (item !is null && !item.isDisposed()) { | |
638 int index = item.getParent().indexOf(item); | |
639 int id = getMenuItemID(hMenu, index); | |
640 ids ~= id; | |
641 } | |
642 } | |
643 } | |
644 int index = OS.GetMenuItemCount(hmenuShared) - 1; | |
645 for (int i = index; i >= 0; i--) { | |
646 int id = getMenuItemID(hmenuShared, i); | |
647 if ( ids.contains(id)){ | |
648 OS.RemoveMenu(hmenuShared, i, OS.MF_BYPOSITION); | |
649 } | |
650 } | |
651 return COM.S_OK; | |
652 } | |
653 private int RequestBorderSpace(LPCBORDERWIDTHS pborderwidths) { | |
654 return COM.S_OK; | |
655 } | |
656 HRESULT SetActiveObject( LPOLEINPLACEACTIVEOBJECT pActiveObject, LPCOLESTR pszObjName ) { | |
657 if (objIOleInPlaceActiveObject !is null) { | |
658 objIOleInPlaceActiveObject.Release(); | |
659 objIOleInPlaceActiveObject = null; | |
660 } | |
661 if (pActiveObject !is null) { | |
662 objIOleInPlaceActiveObject = pActiveObject; | |
663 objIOleInPlaceActiveObject.AddRef(); | |
664 } | |
665 | |
666 return COM.S_OK; | |
667 } | |
668 | |
669 private HRESULT SetBorderSpace( LPCBORDERWIDTHS pborderwidths ) { | |
670 // A Control/Document can : | |
671 // Use its own toolbars, requesting border space of a specific size, or, | |
672 // Use no toolbars, but force the container to remove its toolbars by passing a | |
673 // valid BORDERWIDTHS structure containing nothing but zeros in the pborderwidths parameter, or, | |
674 // Use no toolbars but allow the in-place container to leave its toolbars up by | |
675 // passing NULL as the pborderwidths parameter. | |
676 if (objIOleInPlaceActiveObject is null) return COM.S_OK; | |
677 RECT* borderwidth = new RECT(); | |
678 if (pborderwidths is null || currentdoc is null ) return COM.S_OK; | |
679 | |
680 COM.MoveMemory(borderwidth, pborderwidths, RECT.sizeof); | |
681 currentdoc.setBorderSpace(borderwidth); | |
682 | |
683 return COM.S_OK; | |
684 } | |
685 /** | |
686 * | |
687 * Specify the menu items that should appear in the Container location when an OLE Document | |
688 * is in-place activated. | |
689 * | |
690 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application | |
691 * is given the opportunity to merge some of its menus into the menubar. The application | |
692 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window | |
693 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help | |
694 * menu locations. Note that an application can insert more than one menu into a single location. | |
695 * | |
696 * <p>This method must be called before in place activation of the OLE Document. After the Document | |
697 * is activated, the menu bar will not be modified until a subsequent activation. | |
698 * | |
699 * @param containerMenus an array of top level MenuItems to be inserted into the Container location of | |
700 * the menubar | |
701 */ | |
702 public void setContainerMenus(MenuItem[] containerMenus){ | |
703 containerMenuItems = containerMenus; | |
704 } | |
705 OleClientSite getCurrentDocument() { | |
706 return currentdoc; | |
707 } | |
708 void setCurrentDocument(OleClientSite doc) { | |
709 currentdoc = doc; | |
710 | |
711 if (currentdoc !is null && objIOleInPlaceActiveObject !is null) { | |
712 RECT lpRect; | |
713 OS.GetClientRect(handle, &lpRect); | |
714 objIOleInPlaceActiveObject.ResizeBorder(&lpRect, iOleInPlaceFrame, true); | |
715 } | |
716 } | |
717 /** | |
718 * | |
719 * Specify the menu items that should appear in the File location when an OLE Document | |
720 * is in-place activated. | |
721 * | |
722 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application | |
723 * is given the opportunity to merge some of its menus into the menubar. The application | |
724 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window | |
725 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help | |
726 * menu locations. Note that an application can insert more than one menu into a single location. | |
727 * | |
728 * <p>This method must be called before in place activation of the OLE Document. After the Document | |
729 * is activated, the menu bar will not be modified until a subsequent activation. | |
730 * | |
731 * @param fileMenus an array of top level MenuItems to be inserted into the File location of | |
732 * the menubar | |
733 */ | |
734 public void setFileMenus(MenuItem[] fileMenus){ | |
735 fileMenuItems = fileMenus; | |
736 } | |
737 HRESULT SetMenu( HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject ) { | |
738 IOleInPlaceActiveObject inPlaceActiveObject; | |
739 if (objIOleInPlaceActiveObject !is null) | |
740 inPlaceActiveObject = objIOleInPlaceActiveObject; | |
741 | |
742 Menu menubar = getShell().getMenuBar(); | |
743 if (menubar is null || menubar.isDisposed()){ | |
744 return COM.OleSetMenuDescriptor(null, getShell().handle, hwndActiveObject, iOleInPlaceFrame, inPlaceActiveObject); | |
745 } | |
746 | |
747 HWND handle = menubar.getShell().handle; | |
748 | |
749 if (hmenuShared is null && holemenu is null) { | |
750 // re-instate the original menu - this occurs on deactivation | |
751 hmenuShared = menubar.handle; | |
752 } | |
753 if (hmenuShared is null) return COM.E_FAIL; | |
754 | |
755 OS.SetMenu(handle, hmenuShared); | |
756 OS.DrawMenuBar(handle); | |
757 | |
758 return COM.OleSetMenuDescriptor(holemenu, handle, hwndActiveObject, iOleInPlaceFrame, inPlaceActiveObject); | |
759 } | |
760 | |
761 /** | |
762 * | |
763 * Set the menu items that should appear in the Window location when an OLE Document | |
764 * is in-place activated. | |
765 * | |
766 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application | |
767 * is given the opportunity to merge some of its menus into the menubar. The application | |
768 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window | |
769 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help | |
770 * menu locations. Note that an application can insert more than one menu into a single location. | |
771 * | |
772 * <p>This method must be called before in place activation of the OLE Document. After the Document | |
773 * is activated, the menu bar will not be modified until a subsequent activation. | |
774 * | |
775 * @param windowMenus an array of top level MenuItems to be inserted into the Window location of | |
776 * the menubar | |
777 */ | |
778 public void setWindowMenus(MenuItem[] windowMenus){ | |
779 windowMenuItems = windowMenus; | |
780 } | |
781 private bool translateOleAccelerator(MSG* msg) { | |
782 if (objIOleInPlaceActiveObject is null) return false; | |
783 int result = objIOleInPlaceActiveObject.TranslateAccelerator(msg); | |
784 return (result != COM.S_FALSE && result != COM.E_NOTIMPL); | |
785 } | |
786 | |
787 HRESULT TranslateAccelerator( LPMSG lpmsg, WORD wID ){ | |
788 Menu menubar = getShell().getMenuBar(); | |
789 if (menubar is null || menubar.isDisposed() || !menubar.isEnabled()) return COM.S_FALSE; | |
790 if (wID < 0) return COM.S_FALSE; | |
791 | |
792 Shell shell = menubar.getShell(); | |
793 HWND hwnd = shell.handle; | |
794 HACCEL hAccel = cast(HACCEL)OS.SendMessage(hwnd, OS.WM_APP+1, 0, 0); | |
795 if (hAccel is null) return COM.S_FALSE; | |
796 | |
797 MSG msg = *lpmsg; | |
798 int result = OS.TranslateAccelerator(hwnd, hAccel, &msg); | |
799 return result == 0 ? COM.S_FALSE : COM.S_OK; | |
800 } | |
801 } | |
802 | |
803 // implements IOleInPlaceFrame, IOleInPlaceUIWindow, IOleWindow, IUnknown | |
804 class _IOleInPlaceFrameImpl : IOleInPlaceFrame { | |
805 | |
806 OleFrame parent; | |
807 this(OleFrame p) { parent = p; } | |
808 extern (Windows) : | |
809 // interface of IUnknown | |
810 HRESULT QueryInterface(REFIID riid, void ** ppvObject) { return parent.QueryInterface(riid, ppvObject); } | |
811 ULONG AddRef() { return parent.AddRef(); } | |
812 ULONG Release() { return parent.Release(); } | |
813 | |
814 // interface IOleWindow | |
815 HRESULT GetWindow( HWND * phwnd ) { return parent.GetWindow(phwnd); } | |
816 HRESULT ContextSensitiveHelp( BOOL fEnterMode ){ return COM.S_OK; } | |
817 | |
818 //interface IOleInPlaceUIWindow | |
819 HRESULT GetBorder( LPRECT lprectBorder ) { return parent.GetBorder(lprectBorder); } | |
820 HRESULT RequestBorderSpace( LPCBORDERWIDTHS pborderwidths ){ return COM.S_OK; } | |
821 HRESULT SetBorderSpace( LPCBORDERWIDTHS pborderwidths ) { return parent.SetBorderSpace(pborderwidths); } | |
822 HRESULT SetActiveObject( LPOLEINPLACEACTIVEOBJECT pActiveObject, LPCOLESTR pszObjName ) { | |
823 return parent.SetActiveObject(pActiveObject, pszObjName); | |
824 } | |
825 | |
826 // interface IOleInPlaceFrame : IOleInPlaceUIWindow | |
827 HRESULT InsertMenus( HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths ){ | |
828 return parent.InsertMenus(hmenuShared, lpMenuWidths); | |
829 } | |
830 HRESULT SetMenu( HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject ){ | |
831 return parent.SetMenu(hmenuShared, holemenu, hwndActiveObject); | |
832 } | |
833 HRESULT RemoveMenus( HMENU hmenuShared ) { | |
834 return parent.RemoveMenus(hmenuShared); | |
835 } | |
836 HRESULT SetStatusText( LPCOLESTR pszStatusText ) { return COM.E_NOTIMPL; } | |
837 HRESULT EnableModeless( BOOL fEnable ) { return COM.E_NOTIMPL; } | |
838 HRESULT TranslateAccelerator( LPMSG lpmsg, WORD wID ) { | |
839 return parent.TranslateAccelerator(lpmsg, wID); | |
840 } | |
841 | |
842 } | |
843 |