Java tutorial
/******************************************************************************* * 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(), //$NON-NLS-1$ PKEY_AppUserModel_IsDestListSeparator); 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 != 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() { Shell[] shells = display.getShells(); for (int i = 0; i < shells.length; i++) { getItem(shells[i]); } 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 (int i = 0; i < items.length; i++) { IShellLink pLink = createShellLink(items[i]); if (pLink != null) { /*IObjectCollection::AddObject*/ pObjColl.AddObject(pLink); if (hr != OS.S_OK) error(SWT.ERROR_INVALID_ARGUMENT); pLink.Release(); } } /*IUnknown::QueryInterface*/ 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; String appData = System.getenv("LOCALAPPDATA"); String appName = Display.APP_NAME; if (appData == null || appName == null) return null; appName = appName.replaceAll("[\\\\/:*?\"<>|]", "_"); File dir = new File(appData + "\\" + appName + "\\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 (int i = 0; i < items.length; i++) { if (items[i] != null && items[i].shell == shell) { return items[i]; } } 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 (int i = 0; i < items.length; i++) { TaskItem item = items[i]; 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 (int i = 0; i < items.length; i++) { TaskItem item = items[i]; 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 (int i = 0; i < items.length; i++) { MenuItem item = items[i]; 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); } /*IUnknown::Release*/ 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(); } }