| /******************************************************************************* |
| * Copyright (c) 2010, 2017 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Tasktop Technologies - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.swt.widgets; |
| |
| |
| import java.io.*; |
| |
| import org.eclipse.swt.*; |
| import org.eclipse.swt.graphics.*; |
| import org.eclipse.swt.internal.*; |
| import org.eclipse.swt.internal.ole.win32.*; |
| import org.eclipse.swt.internal.win32.*; |
| |
| /** |
| * Instances of this class represent the system task bar. |
| * |
| * <dl> |
| * <dt><b>Styles:</b></dt> |
| * <dd>(none)</dd> |
| * <dt><b>Events:</b></dt> |
| * <dd>(none)</dd> |
| * </dl> |
| * |
| * @see Display#getSystemTaskBar |
| * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> |
| * |
| * @since 3.6 |
| * |
| * @noextend This class is not intended to be subclassed by clients. |
| */ |
| public class TaskBar extends Widget { |
| int itemCount; |
| TaskItem [] items = new TaskItem [4]; |
| ITaskbarList3 mTaskbarList3; |
| String iconsDir; |
| |
| static final char [] EXE_PATH; |
| static final PROPERTYKEY PKEY_Title = new PROPERTYKEY (); |
| static final PROPERTYKEY PKEY_AppUserModel_IsDestListSeparator = new PROPERTYKEY (); |
| static final String EXE_PATH_KEY = "org.eclipse.swt.win32.taskbar.executable"; //$NON-NLS-1$ |
| static final String EXE_ARGS_KEY = "org.eclipse.swt.win32.taskbar.arguments"; //$NON-NLS-1$ |
| static final String ICON_KEY = "org.eclipse.swt.win32.taskbar.icon"; //$NON-NLS-1$ |
| static final String ICON_INDEX_KEY = "org.eclipse.swt.win32.taskbar.icon.index"; //$NON-NLS-1$ |
| static { |
| OS.PSPropertyKeyFromString ("{F29F85E0-4FF9-1068-AB91-08002B27B3D9} 2\0".toCharArray (), PKEY_Title); //$NON-NLS-1$ |
| OS.PSPropertyKeyFromString ("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}, 6\0".toCharArray (), PKEY_AppUserModel_IsDestListSeparator); //$NON-NLS-1$ |
| char [] buffer = new char [OS.MAX_PATH]; |
| while (OS.GetModuleFileName (0, buffer, buffer.length) == buffer.length) { |
| buffer = new char [buffer.length + OS.MAX_PATH]; |
| } |
| EXE_PATH = buffer; |
| } |
| |
| TaskBar (Display display, int style) { |
| this.display = display; |
| createHandle (); |
| reskinWidget (); |
| } |
| |
| void createHandle () { |
| long[] ppv = new long [1]; |
| int hr = COM.CoCreateInstance (COM.CLSID_TaskbarList, 0, COM.CLSCTX_INPROC_SERVER, COM.IID_ITaskbarList3, ppv); |
| if (hr == COM.REGDB_E_CLASSNOTREG) error (SWT.ERROR_NOT_IMPLEMENTED); |
| if (hr != OS.S_OK) error (SWT.ERROR_NO_HANDLES); |
| mTaskbarList3 = new ITaskbarList3 (ppv [0]); |
| } |
| |
| void createItem (TaskItem item, int index) { |
| if (index == -1) index = itemCount; |
| if (!(0 <= index && index <= itemCount)) error (SWT.ERROR_INVALID_RANGE); |
| if (itemCount == items.length) { |
| TaskItem [] newItems = new TaskItem [items.length + 4]; |
| System.arraycopy (items, 0, newItems, 0, items.length); |
| items = newItems; |
| } |
| System.arraycopy (items, index, items, index + 1, itemCount++ - index); |
| items [index] = item; |
| } |
| |
| void createItems () { |
| for (Shell shell : display.getShells ()) { |
| getItem (shell); |
| } |
| getItem (null); |
| } |
| |
| IShellLink createShellLink (MenuItem item) { |
| int style = item.getStyle (); |
| if ((style & SWT.CASCADE) != 0) return null; |
| long [] ppv = new long [1]; |
| int hr = COM.CoCreateInstance (COM.CLSID_ShellLink, 0, COM.CLSCTX_INPROC_SERVER, COM.IID_IShellLinkW, ppv); |
| if (hr != OS.S_OK) error (SWT.ERROR_NO_HANDLES); |
| IShellLink pLink = new IShellLink (ppv [0]); |
| |
| long hHeap = OS.GetProcessHeap (); |
| long pv = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, OS.PROPVARIANT_sizeof()); |
| long titlePtr = 0; |
| PROPERTYKEY key; |
| if ((style & SWT.SEPARATOR) != 0) { |
| OS.MoveMemory (pv, new short [] {OS.VT_BOOL}, 2); |
| OS.MoveMemory (pv + 8, new short [] {OS.VARIANT_TRUE}, 2); |
| key = PKEY_AppUserModel_IsDestListSeparator; |
| } else { |
| String text = item.getText (); |
| int length = text.length (); |
| char [] buffer = new char [length + 1]; |
| text.getChars (0, length, buffer, 0); |
| titlePtr = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, buffer.length * 2); |
| OS.MoveMemory (titlePtr, buffer, buffer.length * 2); |
| OS.MoveMemory (pv, new short [] {OS.VT_LPWSTR}, 2); |
| OS.MoveMemory (pv + 8, new long [] {titlePtr}, C.PTR_SIZEOF); |
| key = PKEY_Title; |
| |
| String exePath = (String)item.getData (EXE_PATH_KEY); |
| if (exePath != null) { |
| length = exePath.length (); |
| buffer = new char [length + 1]; |
| exePath.getChars (0, length, buffer, 0); |
| } else { |
| buffer = EXE_PATH; |
| } |
| hr = pLink.SetPath(buffer); |
| if (hr != OS.S_OK) error (SWT.ERROR_INVALID_ARGUMENT); |
| |
| text = (String)item.getData (EXE_ARGS_KEY); |
| if (text == null) text = Display.LAUNCHER_PREFIX + Display.TASKBAR_EVENT + item.id; |
| length = text.length (); |
| buffer = new char [length + 1]; |
| text.getChars (0, length, buffer, 0); |
| hr = pLink.SetArguments(buffer); |
| if (hr != OS.S_OK) error (SWT.ERROR_INVALID_ARGUMENT); |
| |
| /* This code is intentionally commented */ |
| // String tooltip = item.tooltip; |
| // if (tooltip != null) { |
| // length = tooltip.length (); |
| // buffer = new char [length + 1]; |
| // tooltip.getChars (0, length, buffer, 0); |
| // hr = pLink.SetDescription (buffer); |
| // if (hr != OS.S_OK) error (SWT.ERROR_INVALID_ARGUMENT); |
| // } |
| |
| String icon = (String)item.getData (ICON_KEY); |
| int index = 0; |
| if (icon != null) { |
| text = (String)item.getData (ICON_INDEX_KEY); |
| if (text != null) index = Integer.parseInt (text); |
| } else { |
| String directory = null; |
| Image image = item.getImage (); |
| if (image != null) directory = getIconsDir (); |
| if (directory != null) { |
| icon = directory + "\\" + "menu" + item.id + ".ico"; |
| ImageData data; |
| if (item.hBitmap != 0) { |
| Image image2 = Image.win32_new (display, SWT.BITMAP, item.hBitmap); |
| data = image2.getImageData (DPIUtil.getDeviceZoom ()); |
| } else { |
| data = image.getImageData (DPIUtil.getDeviceZoom ()); |
| } |
| ImageLoader loader = new ImageLoader (); |
| loader.data = new ImageData [] {data}; |
| loader.save (icon, SWT.IMAGE_ICO); |
| } |
| } |
| if (icon != null) { |
| length = icon.length (); |
| buffer = new char [length + 1]; |
| icon.getChars (0, length, buffer, 0); |
| hr = pLink.SetIconLocation(buffer, index); |
| if (hr != OS.S_OK) error (SWT.ERROR_INVALID_ARGUMENT); |
| } |
| } |
| |
| hr = pLink.QueryInterface(COM.IID_IPropertyStore, ppv); |
| if (hr != OS.S_OK) error (SWT.ERROR_NO_HANDLES); |
| IPropertyStore pPropStore = new IPropertyStore (ppv [0]); |
| hr = pPropStore.SetValue(key, pv); |
| if (hr != OS.S_OK) error (SWT.ERROR_INVALID_ARGUMENT); |
| pPropStore.Commit(); |
| pPropStore.Release(); |
| |
| OS.HeapFree (hHeap, 0, pv); |
| if (titlePtr != 0) OS.HeapFree (hHeap, 0, titlePtr); |
| return pLink; |
| } |
| |
| IObjectArray createShellLinkArray (MenuItem [] items) { |
| if (items == null) return null; |
| if (items.length == 0) return null; |
| long [] ppv = new long [1]; |
| int hr = COM.CoCreateInstance (COM.CLSID_EnumerableObjectCollection, 0, COM.CLSCTX_INPROC_SERVER, COM.IID_IObjectCollection, ppv); |
| if (hr != OS.S_OK) error (SWT.ERROR_NO_HANDLES); |
| IObjectCollection pObjColl = new IObjectCollection (ppv [0]); |
| for (MenuItem item : items) { |
| IShellLink pLink = createShellLink (item); |
| if (pLink != null) { |
| pObjColl.AddObject (pLink); |
| if (hr != OS.S_OK) error (SWT.ERROR_INVALID_ARGUMENT); |
| pLink.Release (); |
| } |
| } |
| hr = pObjColl.QueryInterface(COM.IID_IObjectArray, ppv); |
| if (hr != OS.S_OK) error (SWT.ERROR_NO_HANDLES); |
| IObjectArray poa = new IObjectArray (ppv [0]); |
| pObjColl.Release (); |
| return poa; |
| } |
| |
| void destroyItem (TaskItem item) { |
| int index = 0; |
| while (index < itemCount) { |
| if (items [index] == item) break; |
| index++; |
| } |
| if (index == itemCount) return; |
| System.arraycopy (items, index + 1, items, index, --itemCount - index); |
| items [itemCount] = null; |
| } |
| |
| String getIconsDir() { |
| if (iconsDir != null) return iconsDir; |
| File dir = new File(display.appLocalDir + "\\ico_dir"); |
| if (dir.exists()) { |
| // remove old icons |
| for (File file : dir.listFiles()) file.delete(); |
| } else if (!dir.mkdirs()) { |
| return null; |
| } |
| return iconsDir = dir.getPath(); |
| } |
| |
| /** |
| * Returns the item at the given, zero-relative index in the |
| * receiver. Throws an exception if the index is out of range. |
| * |
| * @param index the index of the item to return |
| * @return the item at the given index |
| * |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li> |
| * </ul> |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| */ |
| public TaskItem getItem (int index) { |
| checkWidget (); |
| createItems (); |
| if (!(0 <= index && index < itemCount)) error (SWT.ERROR_INVALID_RANGE); |
| return items [index]; |
| } |
| |
| /** |
| * Returns the <code>TaskItem</code> for the given <code>Shell</code> or the <code>TaskItem</code> |
| * for the application if the <code>Shell</code> parameter is <code>null</code>. |
| * If the requested item is not supported by the platform it returns <code>null</code>. |
| * |
| * @param shell the shell for which the task item is requested, or null to request the application item |
| * @return the task item for the given shell or the application |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| */ |
| public TaskItem getItem (Shell shell) { |
| checkWidget (); |
| for (TaskItem item : items) { |
| if (item != null && item.shell == shell) { |
| return item; |
| } |
| } |
| TaskItem item = new TaskItem (this, SWT.NONE); |
| if (shell != null) item.setShell (shell); |
| return item; |
| } |
| |
| /** |
| * Returns the number of items contained in the receiver. |
| * |
| * @return the number of items |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| */ |
| public int getItemCount () { |
| checkWidget (); |
| createItems (); |
| return itemCount; |
| } |
| |
| /** |
| * Returns an array of <code>TaskItem</code>s which are the items |
| * in the receiver. |
| * <p> |
| * Note: This is not the actual structure used by the receiver |
| * to maintain its list of items, so modifying the array will |
| * not affect the receiver. |
| * </p> |
| * |
| * @return the items in the receiver |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| */ |
| public TaskItem [] getItems () { |
| checkWidget (); |
| createItems (); |
| TaskItem [] result = new TaskItem [itemCount]; |
| System.arraycopy (items, 0, result, 0, result.length); |
| return result; |
| } |
| |
| @Override |
| void releaseChildren (boolean destroy) { |
| if (items != null) { |
| for (TaskItem item : items) { |
| if (item != null && !item.isDisposed ()) { |
| item.release (false); |
| } |
| } |
| items = null; |
| } |
| super.releaseChildren (destroy); |
| } |
| |
| @Override |
| void releaseParent () { |
| super.releaseParent (); |
| if (display.taskBar == this) display.taskBar = null; |
| } |
| |
| @Override |
| void releaseWidget () { |
| super.releaseWidget (); |
| mTaskbarList3.Release(); |
| mTaskbarList3 = null; |
| } |
| |
| @Override |
| void reskinChildren (int flags) { |
| if (items != null) { |
| for (TaskItem item : items) { |
| if (item != null) item.reskin (flags); |
| } |
| } |
| super.reskinChildren (flags); |
| } |
| |
| void setMenu (Menu menu) { |
| long [] ppv = new long [1]; |
| int hr = COM.CoCreateInstance (COM.CLSID_DestinationList, 0, COM.CLSCTX_INPROC_SERVER, COM.IID_ICustomDestinationList, ppv); |
| if (hr != OS.S_OK) error (SWT.ERROR_NO_HANDLES); |
| ICustomDestinationList pDestList = new ICustomDestinationList (ppv [0]); |
| String appName = Display.APP_NAME; |
| char [] buffer = {'S', 'W', 'T', '\0'}; |
| if (appName != null && appName.length () > 0) { |
| int length = appName.length (); |
| buffer = new char [length + 1]; |
| appName.getChars (0, length, buffer, 0); |
| } |
| MenuItem [] items = null; |
| if (menu != null && (items = menu.getItems ()).length != 0) { |
| IObjectArray poa = createShellLinkArray (items); |
| if (poa != null) { |
| hr = pDestList.SetAppID (buffer); |
| if (hr != OS.S_OK) error (SWT.ERROR_INVALID_ARGUMENT); |
| |
| int [] cMaxSlots = new int [1]; |
| pDestList.BeginList(cMaxSlots, COM.IID_IObjectArray, ppv); |
| if (hr != OS.S_OK) error (SWT.ERROR_INVALID_ARGUMENT); |
| IObjectArray pRemovedItems = new IObjectArray (ppv [0]); |
| |
| int [] count = new int [1]; |
| poa.GetCount (count); |
| if (count [0] != 0) { |
| hr = pDestList.AddUserTasks (poa); |
| if (hr != OS.S_OK) error (SWT.ERROR_INVALID_ARGUMENT); |
| } |
| |
| for (MenuItem item : items) { |
| if ((item.getStyle () & SWT.CASCADE) != 0) { |
| Menu subMenu = item.getMenu (); |
| if (subMenu != null) { |
| MenuItem [] subItems = subMenu.getItems (); |
| IObjectArray poa2 = createShellLinkArray (subItems); |
| if (poa2 != null) { |
| poa2.GetCount (count); |
| if (count [0] != 0) { |
| String text = item.getText (); |
| int length = text.length (); |
| char [] buffer2 = new char [length + 1]; |
| text.getChars (0, length, buffer2, 0); |
| hr = pDestList.AppendCategory (buffer2, poa2); |
| if (hr != OS.S_OK) error (SWT.ERROR_INVALID_ARGUMENT); |
| } |
| poa2.Release (); |
| } |
| } |
| } |
| } |
| poa.Release(); |
| hr = pDestList.CommitList (); |
| if (hr != OS.S_OK) error (SWT.ERROR_INVALID_ARGUMENT); |
| pRemovedItems.Release (); |
| } |
| } else { |
| hr = pDestList.DeleteList (buffer); |
| if (hr != OS.S_OK) error (SWT.ERROR_INVALID_ARGUMENT); |
| } |
| pDestList.Release (); |
| } |
| |
| } |