// DeskIcons: send any window to the desktop as a draggable icon. // Shift+click a minimize button, or press Ctrl+Alt+I, to iconify the window. // Double-click the icon to bring the window back. #ifndef UNICODE #define UNICODE #endif #ifndef _UNICODE #define _UNICODE #endif #define WIN32_LEAN_AND_MEAN #define _WIN32_WINNT 0x0A00 #include #include #include #include #include #include #include #define APP_NAME L"DeskIcons" #define WM_TRAY (WM_APP + 1) #define WM_ICONIFY (WM_APP + 2) #define WM_RESTOREIDX (WM_APP + 3) #define WM_CLOSEIDX (WM_APP + 4) #define HOTKEY_ID 1 #define MAX_ITEMS 256 #define TIMER_CHECK 1 #define IDM_RESTOREALL 100 #define IDM_ONTOP 101 #define IDM_STARTUP 102 #define IDM_HELP 103 #define IDM_EXIT 104 #define IDM_SHOWICONS 105 #define IDM_I_RESTORE 200 #define IDM_I_CLOSE 201 typedef struct { BOOL used; HWND target; HWND iconWnd; DWORD pid; HICON hIcon; BOOL hover; WCHAR title[256]; } Item; static Item g_items[MAX_ITEMS]; static HINSTANCE g_inst; static HWND g_main; static HHOOK g_mouseHook; static volatile BOOL g_swallowUp; static BOOL g_onTop; static BOOL g_showIcons; static BOOL g_hotkeyOk; static NOTIFYICONDATAW g_nid; static HFONT g_font; static int g_dpi = 96; static UINT g_taskbarCreated; static WCHAR g_stateFile[MAX_PATH]; static HWND g_lastFg; // drag state static BOOL g_pressed, g_dragging; static POINT g_dragStart, g_dragOrig; static int S(int v) { return MulDiv(v, g_dpi, 96); } static int ItemW(void) { return g_showIcons ? S(88) : S(120); } static int ItemH(void) { return g_showIcons ? S(96) : S(58); } /* ---------------- settings ---------------- */ static DWORD RegGetDword(const WCHAR *name, DWORD def) { DWORD v = def, sz = sizeof(v); if (RegGetValueW(HKEY_CURRENT_USER, L"Software\\DeskIcons", name, RRF_RT_REG_DWORD, NULL, &v, &sz) != ERROR_SUCCESS) return def; return v; } static void RegSetDword(const WCHAR *name, DWORD v) { HKEY k; if (RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\DeskIcons", 0, NULL, 0, KEY_WRITE, NULL, &k, NULL) == ERROR_SUCCESS) { RegSetValueExW(k, name, 0, REG_DWORD, (BYTE *)&v, sizeof(v)); RegCloseKey(k); } } static const WCHAR *RUN_KEY = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"; static BOOL StartupEnabled(void) { WCHAR buf[MAX_PATH * 2]; DWORD sz = sizeof(buf); return RegGetValueW(HKEY_CURRENT_USER, RUN_KEY, APP_NAME, RRF_RT_REG_SZ, NULL, buf, &sz) == ERROR_SUCCESS; } static void SetStartup(BOOL on) { HKEY k; if (RegOpenKeyExW(HKEY_CURRENT_USER, RUN_KEY, 0, KEY_WRITE, &k) != ERROR_SUCCESS) return; if (on) { WCHAR exe[MAX_PATH], val[MAX_PATH + 4]; GetModuleFileNameW(NULL, exe, MAX_PATH); swprintf(val, MAX_PATH + 4, L"\"%ls\"", exe); RegSetValueExW(k, APP_NAME, 0, REG_SZ, (BYTE *)val, (DWORD)((wcslen(val) + 1) * sizeof(WCHAR))); } else { RegDeleteValueW(k, APP_NAME); } RegCloseKey(k); } /* ---------------- state file (crash recovery) ---------------- */ static void SaveState(void) { FILE *f = _wfopen(g_stateFile, L"w"); if (!f) return; for (int i = 0; i < MAX_ITEMS; i++) { Item *it = &g_items[i]; if (!it->used) continue; RECT r; GetWindowRect(it->iconWnd, &r); fprintf(f, "%llx %lu %ld %ld\n", (unsigned long long)(ULONG_PTR)it->target, (unsigned long)it->pid, r.left, r.top); } fclose(f); } /* ---------------- helpers ---------------- */ static int CountItems(void) { int n = 0; for (int i = 0; i < MAX_ITEMS; i++) if (g_items[i].used) n++; return n; } static void UpdateTrayTip(void) { int n = CountItems(); if (n == 0) swprintf(g_nid.szTip, 128, L"DeskIcons"); else swprintf(g_nid.szTip, 128, L"DeskIcons (%d window%ls on the desktop)", n, n == 1 ? L"" : L"s"); g_nid.uFlags = NIF_TIP; Shell_NotifyIconW(NIM_MODIFY, &g_nid); } static void Balloon(const WCHAR *title, const WCHAR *text) { g_nid.uFlags = NIF_INFO; wcsncpy(g_nid.szInfoTitle, title, 63); g_nid.szInfoTitle[63] = 0; wcsncpy(g_nid.szInfo, text, 255); g_nid.szInfo[255] = 0; g_nid.dwInfoFlags = NIIF_INFO; Shell_NotifyIconW(NIM_MODIFY, &g_nid); } static Item *FindItemByTarget(HWND t) { for (int i = 0; i < MAX_ITEMS; i++) if (g_items[i].used && g_items[i].target == t) return &g_items[i]; return NULL; } static BOOL IsOurIconWindow(HWND h) { for (int i = 0; i < MAX_ITEMS; i++) if (g_items[i].used && g_items[i].iconWnd == h) return TRUE; return FALSE; } static HWND FindDesktopHost(void) { HWND p = FindWindowW(L"Progman", NULL); if (p && FindWindowExW(p, NULL, L"SHELLDLL_DefView", NULL)) return p; HWND w = NULL; while ((w = FindWindowExW(NULL, w, L"WorkerW", NULL)) != NULL) if (FindWindowExW(w, NULL, L"SHELLDLL_DefView", NULL)) return w; return p; } static BOOL IsDesktopClass(HWND h) { WCHAR cls[64]; if (!h || !GetClassNameW(h, cls, 64)) return FALSE; return !wcscmp(cls, L"Progman") || !wcscmp(cls, L"WorkerW"); } static BOOL CanIconify(HWND h) { if (!h || !IsWindow(h) || !IsWindowVisible(h)) return FALSE; DWORD pid = 0; GetWindowThreadProcessId(h, &pid); if (pid == GetCurrentProcessId()) return FALSE; WCHAR cls[64]; GetClassNameW(h, cls, 64); if (!wcscmp(cls, L"Progman") || !wcscmp(cls, L"WorkerW") || !wcscmp(cls, L"Shell_TrayWnd") || !wcscmp(cls, L"Shell_SecondaryTrayWnd") || !wcscmp(cls, L"Windows.UI.Core.CoreWindow")) return FALSE; if (GetWindowLongW(h, GWL_EXSTYLE) & WS_EX_TOOLWINDOW) return FALSE; if (FindItemByTarget(h)) return FALSE; return TRUE; } static HICON GetTargetIcon(HWND h) { int sz = S(48); HICON hi = NULL; DWORD pid = 0; GetWindowThreadProcessId(h, &pid); HANDLE p = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); if (p) { WCHAR path[MAX_PATH]; DWORD n = MAX_PATH; if (QueryFullProcessImageNameW(p, 0, path, &n)) { const WCHAR *base = wcsrchr(path, L'\\'); base = base ? base + 1 : path; if (_wcsicmp(base, L"ApplicationFrameHost.exe") != 0) { HICON large = NULL; if (SHDefExtractIconW(path, 0, 0, &large, NULL, MAKELONG(sz, 16)) == S_OK && large) hi = large; } } CloseHandle(p); } if (!hi) { DWORD_PTR r = 0; if (SendMessageTimeoutW(h, WM_GETICON, ICON_BIG, 0, SMTO_ABORTIFHUNG, 200, &r) && r) hi = CopyIcon((HICON)r); if (!hi) { HICON c = (HICON)GetClassLongPtrW(h, GCLP_HICON); if (c) hi = CopyIcon(c); } if (!hi && SendMessageTimeoutW(h, WM_GETICON, ICON_SMALL2, 0, SMTO_ABORTIFHUNG, 200, &r) && r) hi = CopyIcon((HICON)r); if (!hi) hi = CopyIcon(LoadIconW(NULL, IDI_APPLICATION)); } return hi; } /* ---------------- rendering ---------------- */ static void DrawContent(HDC dc, Item *it, int W, int H) { SelectObject(dc, g_font); SetBkMode(dc, TRANSPARENT); UINT fmt = DT_CENTER | DT_WORDBREAK | DT_END_ELLIPSIS | DT_EDITCONTROL | DT_NOPREFIX; WCHAR title[256]; wcscpy(title, it->title[0] ? it->title : L"(untitled)"); RECT tr; if (g_showIcons) { int isz = S(48); int ix = (W - isz) / 2, iy = S(6); DrawIconEx(dc, ix, iy, it->hIcon, isz, isz, 0, NULL, DI_NORMAL); SetRect(&tr, S(3), iy + isz + S(4), W - S(3), H - S(3)); } else { // text only: center the (up to 3 line) label vertically in the tile RECT box = { S(5), S(4), W - S(5), H - S(4) }; RECT calc = box; DrawTextW(dc, title, -1, &calc, fmt | DT_CALCRECT); int th = calc.bottom - calc.top, bh = box.bottom - box.top; if (th > bh) th = bh; tr = box; tr.top = box.top + (bh - th) / 2; tr.bottom = tr.top + th; } RECT sr = tr; OffsetRect(&sr, 1, 1); SetTextColor(dc, RGB(0, 0, 0)); DrawTextW(dc, title, -1, &sr, fmt); SetTextColor(dc, RGB(255, 255, 255)); DrawTextW(dc, title, -1, &tr, fmt); } static void RenderItem(Item *it) { int W = ItemW(), H = ItemH(); HDC screen = GetDC(NULL); BITMAPINFO bi; ZeroMemory(&bi, sizeof(bi)); bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bi.bmiHeader.biWidth = W; bi.bmiHeader.biHeight = -H; bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = 32; bi.bmiHeader.biCompression = BI_RGB; BYTE *pb = NULL, *pw = NULL, *po = NULL; HDC db = CreateCompatibleDC(screen), dw = CreateCompatibleDC(screen), dout = CreateCompatibleDC(screen); HBITMAP bb = CreateDIBSection(screen, &bi, DIB_RGB_COLORS, (void **)&pb, NULL, 0); HBITMAP bw = CreateDIBSection(screen, &bi, DIB_RGB_COLORS, (void **)&pw, NULL, 0); HBITMAP bo = CreateDIBSection(screen, &bi, DIB_RGB_COLORS, (void **)&po, NULL, 0); if (!bb || !bw || !bo) goto done; HGDIOBJ ob = SelectObject(db, bb), ow = SelectObject(dw, bw), oo = SelectObject(dout, bo); RECT all = { 0, 0, W, H }; FillRect(db, &all, (HBRUSH)GetStockObject(BLACK_BRUSH)); FillRect(dw, &all, (HBRUSH)GetStockObject(WHITE_BRUSH)); DrawContent(db, it, W, H); DrawContent(dw, it, W, H); GdiFlush(); // Recover per-pixel alpha by comparing the render over black and over white. int hx0 = S(2), hy0 = S(2), hx1 = W - S(2), hy1 = H - S(2); for (int y = 0; y < H; y++) { for (int x = 0; x < W; x++) { int i = (y * W + x) * 4; int d = ((pw[i] - pb[i]) + (pw[i + 1] - pb[i + 1]) + (pw[i + 2] - pb[i + 2])) / 3; int a = 255 - d; if (a < 0) a = 0; if (a > 255) a = 255; int c0 = pb[i], c1 = pb[i + 1], c2 = pb[i + 2]; if (c0 > a) c0 = a; if (c1 > a) c1 = a; if (c2 > a) c2 = a; if (it->hover && x >= hx0 && x < hx1 && y >= hy0 && y < hy1) { BOOL edge = (x == hx0 || x == hx1 - 1 || y == hy0 || y == hy1 - 1); int ha = edge ? 150 : 70; // highlight alpha int hr = 153, hg = 209, hb = 255; // light blue, like Explorer selection int inv = 255 - a; c0 += (hb * ha / 255) * inv / 255; c1 += (hg * ha / 255) * inv / 255; c2 += (hr * ha / 255) * inv / 255; a += ha * inv / 255; } if (a < 1) a = 1; // keep the whole tile clickable po[i] = (BYTE)c0; po[i + 1] = (BYTE)c1; po[i + 2] = (BYTE)c2; po[i + 3] = (BYTE)a; } } { SIZE sz = { W, H }; POINT src = { 0, 0 }; BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; UpdateLayeredWindow(it->iconWnd, screen, NULL, &sz, dout, &src, 0, &bf, ULW_ALPHA); } SelectObject(db, ob); SelectObject(dw, ow); SelectObject(dout, oo); done: if (bb) DeleteObject(bb); if (bw) DeleteObject(bw); if (bo) DeleteObject(bo); DeleteDC(db); DeleteDC(dw); DeleteDC(dout); ReleaseDC(NULL, screen); } /* ---------------- placement and z-order ---------------- */ static void ApplyZOrder(HWND h) { if (g_onTop) SetWindowPos(h, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); else { SetWindowPos(h, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); SetWindowPos(h, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); // adjusted in WM_WINDOWPOSCHANGING } } static POINT FindFreeSlot(void) { RECT wa; SystemParametersInfoW(SPI_GETWORKAREA, 0, &wa, 0); int W = ItemW(), H = ItemH(), gap = S(4), m = S(10); int rows = (wa.bottom - wa.top - m) / (H + gap); if (rows < 1) rows = 1; int cols = (wa.right - wa.left - m) / (W + gap); if (cols < 1) cols = 1; for (int c = 0; c < cols; c++) { for (int r = 0; r < rows; r++) { RECT slot; slot.left = wa.right - m - (c + 1) * W - c * gap; slot.top = wa.top + m + r * (H + gap); slot.right = slot.left + W; slot.bottom = slot.top + H; BOOL free = TRUE; for (int i = 0; i < MAX_ITEMS && free; i++) { if (!g_items[i].used) continue; RECT ir, x; GetWindowRect(g_items[i].iconWnd, &ir); if (IntersectRect(&x, &ir, &slot)) free = FALSE; } if (free) { POINT p = { slot.left, slot.top }; return p; } } } POINT p = { wa.right - m - W, wa.top + m }; return p; } /* ---------------- items ---------------- */ static Item *CreateItem(HWND target, int x, int y, BOOL useXY) { Item *it = NULL; for (int i = 0; i < MAX_ITEMS; i++) if (!g_items[i].used) { it = &g_items[i]; break; } if (!it) return NULL; ZeroMemory(it, sizeof(*it)); it->target = target; GetWindowThreadProcessId(target, &it->pid); GetWindowTextW(target, it->title, 256); it->hIcon = GetTargetIcon(target); if (!useXY) { POINT p = FindFreeSlot(); x = p.x; y = p.y; } it->iconWnd = CreateWindowExW(WS_EX_LAYERED | WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE, L"DeskIconsItem", it->title, WS_POPUP, x, y, ItemW(), ItemH(), NULL, NULL, g_inst, it); if (!it->iconWnd) { if (it->hIcon) DestroyIcon(it->hIcon); return NULL; } it->used = TRUE; RenderItem(it); ShowWindow(it->iconWnd, SW_SHOWNOACTIVATE); ApplyZOrder(it->iconWnd); return it; } static void RemoveItem(Item *it) { if (!it->used) return; it->used = FALSE; if (it->iconWnd) DestroyWindow(it->iconWnd); if (it->hIcon) DestroyIcon(it->hIcon); it->iconWnd = NULL; it->hIcon = NULL; SaveState(); UpdateTrayTip(); } static void Iconify(HWND h) { h = GetAncestor(h, GA_ROOT); if (!CanIconify(h)) return; ShowWindow(h, SW_MINIMIZE); ShowWindow(h, SW_HIDE); if (IsWindowVisible(h)) { Balloon(L"DeskIcons", L"That window could not be hidden. It probably belongs to a program running as administrator."); return; } CreateItem(h, 0, 0, FALSE); SaveState(); UpdateTrayTip(); } static void RestoreItem(Item *it, BOOL activate) { if (!it->used) return; HWND t = it->target; if (IsWindow(t)) { if (activate) { ShowWindow(t, SW_SHOWMINNOACTIVE); ShowWindow(t, SW_RESTORE); SetForegroundWindow(t); } else { ShowWindow(t, SW_SHOWMINNOACTIVE); // back on the taskbar, still minimized } } RemoveItem(it); } static void RestoreAll(BOOL activate) { for (int i = 0; i < MAX_ITEMS; i++) if (g_items[i].used) RestoreItem(&g_items[i], activate); } static void RecoverFromStateFile(void) { FILE *f = _wfopen(g_stateFile, L"r"); if (!f) return; unsigned long long h; unsigned long pid; long x, y; while (fscanf(f, "%llx %lu %ld %ld", &h, &pid, &x, &y) == 4) { HWND hw = (HWND)(ULONG_PTR)h; DWORD realPid = 0; if (!IsWindow(hw)) continue; GetWindowThreadProcessId(hw, &realPid); if (realPid != pid || IsWindowVisible(hw) || FindItemByTarget(hw)) continue; CreateItem(hw, x, y, TRUE); } fclose(f); SaveState(); } /* ---------------- menus ---------------- */ static void ShowTrayMenu(void) { HMENU m = CreatePopupMenu(); AppendMenuW(m, MF_STRING | MF_GRAYED, 0, L"DeskIcons"); AppendMenuW(m, MF_SEPARATOR, 0, NULL); AppendMenuW(m, MF_STRING | (CountItems() ? 0 : MF_GRAYED), IDM_RESTOREALL, L"Restore all windows"); AppendMenuW(m, MF_STRING | (g_showIcons ? MF_CHECKED : 0), IDM_SHOWICONS, L"Show program icons"); AppendMenuW(m, MF_STRING | (g_onTop ? MF_CHECKED : 0), IDM_ONTOP, L"Keep icons on top of windows"); AppendMenuW(m, MF_STRING | (StartupEnabled() ? MF_CHECKED : 0), IDM_STARTUP, L"Start with Windows"); AppendMenuW(m, MF_STRING, IDM_HELP, L"How to use"); AppendMenuW(m, MF_SEPARATOR, 0, NULL); AppendMenuW(m, MF_STRING, IDM_EXIT, L"Exit (brings windows back)"); POINT p; GetCursorPos(&p); SetForegroundWindow(g_main); TrackPopupMenu(m, TPM_RIGHTBUTTON | TPM_BOTTOMALIGN, p.x, p.y, 0, g_main, NULL); PostMessageW(g_main, WM_NULL, 0, 0); DestroyMenu(m); } static void ShowHelp(void) { MessageBoxW(NULL, L"Send a window to the desktop:\n" L" Hold Shift and click the window's minimize button,\n" L" or press Ctrl+Alt+I while the window is active.\n\n" L"The window leaves the taskbar and shows up as an icon on your desktop.\n\n" L"Drag icons anywhere you like.\n" L"Double-click an icon to bring its window back.\n" L"Right-click an icon to restore or close that window.\n\n" L"Exiting DeskIcons brings back every window it was holding.", L"How to use DeskIcons", MB_OK | MB_ICONINFORMATION); } /* ---------------- window procs ---------------- */ static LRESULT CALLBACK ItemProc(HWND h, UINT msg, WPARAM wp, LPARAM lp) { Item *it = (Item *)GetWindowLongPtrW(h, GWLP_USERDATA); switch (msg) { case WM_NCCREATE: { CREATESTRUCTW *cs = (CREATESTRUCTW *)lp; SetWindowLongPtrW(h, GWLP_USERDATA, (LONG_PTR)cs->lpCreateParams); break; } case WM_MOUSEACTIVATE: return MA_NOACTIVATE; case WM_WINDOWPOSCHANGING: if (!g_onTop) { WINDOWPOS *pos = (WINDOWPOS *)lp; if (!(pos->flags & SWP_NOZORDER)) { HWND host = FindDesktopHost(); if (host) { HWND above = GetWindow(host, GW_HWNDPREV); if (above == h) pos->flags |= SWP_NOZORDER; else pos->hwndInsertAfter = above ? above : HWND_TOP; } } } break; case WM_LBUTTONDOWN: { RECT r; GetWindowRect(h, &r); g_dragOrig.x = r.left; g_dragOrig.y = r.top; GetCursorPos(&g_dragStart); g_pressed = TRUE; g_dragging = FALSE; SetCapture(h); return 0; } case WM_MOUSEMOVE: { if (it && !it->hover) { it->hover = TRUE; TRACKMOUSEEVENT t = { sizeof(t), TME_LEAVE, h, 0 }; TrackMouseEvent(&t); RenderItem(it); } if (g_pressed && GetCapture() == h) { POINT p; GetCursorPos(&p); int dx = p.x - g_dragStart.x, dy = p.y - g_dragStart.y; if (!g_dragging && (abs(dx) > GetSystemMetrics(SM_CXDRAG) || abs(dy) > GetSystemMetrics(SM_CYDRAG))) g_dragging = TRUE; if (g_dragging) SetWindowPos(h, NULL, g_dragOrig.x + dx, g_dragOrig.y + dy, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); } return 0; } case WM_LBUTTONUP: { BOOL wasDrag = g_dragging; g_pressed = FALSE; g_dragging = FALSE; if (GetCapture() == h) ReleaseCapture(); if (wasDrag) SaveState(); return 0; } case WM_CAPTURECHANGED: g_pressed = FALSE; g_dragging = FALSE; return 0; case WM_LBUTTONDBLCLK: if (it) PostMessageW(g_main, WM_RESTOREIDX, (WPARAM)(it - g_items), 0); return 0; case WM_MOUSELEAVE: if (it && it->hover) { it->hover = FALSE; RenderItem(it); } return 0; case WM_RBUTTONUP: { if (!it) return 0; HMENU m = CreatePopupMenu(); AppendMenuW(m, MF_STRING | MF_DEFAULT, IDM_I_RESTORE, L"Restore"); AppendMenuW(m, MF_STRING, IDM_I_CLOSE, L"Close window"); POINT p; GetCursorPos(&p); SetForegroundWindow(g_main); int cmd = TrackPopupMenu(m, TPM_RIGHTBUTTON | TPM_RETURNCMD, p.x, p.y, 0, g_main, NULL); PostMessageW(g_main, WM_NULL, 0, 0); DestroyMenu(m); if (cmd == IDM_I_RESTORE) PostMessageW(g_main, WM_RESTOREIDX, (WPARAM)(it - g_items), 0); else if (cmd == IDM_I_CLOSE) PostMessageW(g_main, WM_CLOSEIDX, (WPARAM)(it - g_items), 0); return 0; } } return DefWindowProcW(h, msg, wp, lp); } static void AddTrayIcon(void) { ZeroMemory(&g_nid, sizeof(g_nid)); g_nid.cbSize = sizeof(g_nid); g_nid.hWnd = g_main; g_nid.uID = 1; g_nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; g_nid.uCallbackMessage = WM_TRAY; g_nid.hIcon = (HICON)LoadImageW(g_inst, MAKEINTRESOURCEW(1), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0); wcscpy(g_nid.szTip, L"DeskIcons"); Shell_NotifyIconW(NIM_ADD, &g_nid); UpdateTrayTip(); } static LRESULT CALLBACK MainProc(HWND h, UINT msg, WPARAM wp, LPARAM lp) { if (msg == g_taskbarCreated && g_taskbarCreated) { AddTrayIcon(); return 0; } switch (msg) { case WM_TRAY: if (LOWORD(lp) == WM_RBUTTONUP || LOWORD(lp) == WM_LBUTTONUP) ShowTrayMenu(); return 0; case WM_HOTKEY: if (wp == HOTKEY_ID) Iconify(GetForegroundWindow()); return 0; case WM_ICONIFY: Iconify((HWND)wp); return 0; case WM_RESTOREIDX: if (wp < MAX_ITEMS) RestoreItem(&g_items[wp], TRUE); return 0; case WM_CLOSEIDX: if (wp < MAX_ITEMS && g_items[wp].used) { HWND t = g_items[wp].target; RestoreItem(&g_items[wp], TRUE); if (IsWindow(t)) PostMessageW(t, WM_SYSCOMMAND, SC_CLOSE, 0); } return 0; case WM_TIMER: if (wp == TIMER_CHECK) { for (int i = 0; i < MAX_ITEMS; i++) { Item *it = &g_items[i]; if (!it->used) continue; if (!IsWindow(it->target) || IsWindowVisible(it->target)) { RemoveItem(it); continue; } WCHAR t[256]; GetWindowTextW(it->target, t, 256); if (wcscmp(t, it->title)) { wcscpy(it->title, t); RenderItem(it); } if (IsIconic(it->iconWnd) || !IsWindowVisible(it->iconWnd)) ShowWindow(it->iconWnd, SW_SHOWNOACTIVATE); } // When the desktop gets focus (Win+D, clicking the wallpaper), make sure icons sit above it. HWND fg = GetForegroundWindow(); if (fg != g_lastFg) { g_lastFg = fg; if (IsDesktopClass(fg)) for (int i = 0; i < MAX_ITEMS; i++) if (g_items[i].used) ApplyZOrder(g_items[i].iconWnd); } } return 0; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_RESTOREALL: RestoreAll(FALSE); break; case IDM_ONTOP: g_onTop = !g_onTop; RegSetDword(L"OnTop", g_onTop); for (int i = 0; i < MAX_ITEMS; i++) if (g_items[i].used) ApplyZOrder(g_items[i].iconWnd); break; case IDM_SHOWICONS: g_showIcons = !g_showIcons; RegSetDword(L"ShowIcons", g_showIcons); for (int i = 0; i < MAX_ITEMS; i++) { if (!g_items[i].used) continue; SetWindowPos(g_items[i].iconWnd, NULL, 0, 0, ItemW(), ItemH(), SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); RenderItem(&g_items[i]); } SaveState(); break; case IDM_STARTUP: SetStartup(!StartupEnabled()); break; case IDM_HELP: ShowHelp(); break; case IDM_EXIT: DestroyWindow(h); break; } return 0; case WM_QUERYENDSESSION: RestoreAll(FALSE); return TRUE; case WM_DESTROY: RestoreAll(FALSE); DeleteFileW(g_stateFile); KillTimer(h, TIMER_CHECK); if (g_hotkeyOk) UnregisterHotKey(h, HOTKEY_ID); if (g_mouseHook) UnhookWindowsHookEx(g_mouseHook); Shell_NotifyIconW(NIM_DELETE, &g_nid); PostQuitMessage(0); return 0; } return DefWindowProcW(h, msg, wp, lp); } /* ---------------- shift+click on minimize button ---------------- */ static LRESULT CALLBACK MouseLL(int code, WPARAM wp, LPARAM lp) { if (code == HC_ACTION) { MSLLHOOKSTRUCT *m = (MSLLHOOKSTRUCT *)lp; if (wp == WM_LBUTTONDOWN && (GetAsyncKeyState(VK_SHIFT) & 0x8000) && !(m->flags & LLMHF_INJECTED)) { HWND hit = WindowFromPoint(m->pt); if (hit) { HWND root = GetAncestor(hit, GA_ROOT); LPARAM pt = MAKELPARAM((WORD)(SHORT)m->pt.x, (WORD)(SHORT)m->pt.y); DWORD_PTR r = 0; BOOL isMin = FALSE; if (SendMessageTimeoutW(hit, WM_NCHITTEST, 0, pt, SMTO_ABORTIFHUNG, 150, &r) && r == HTMINBUTTON) isMin = TRUE; else if (root && root != hit && SendMessageTimeoutW(root, WM_NCHITTEST, 0, pt, SMTO_ABORTIFHUNG, 150, &r) && r == HTMINBUTTON) isMin = TRUE; if (isMin && root && !IsOurIconWindow(root)) { g_swallowUp = TRUE; PostMessageW(g_main, WM_ICONIFY, (WPARAM)root, 0); return 1; } } } else if (wp == WM_LBUTTONUP && g_swallowUp) { g_swallowUp = FALSE; return 1; } } return CallNextHookEx(g_mouseHook, code, wp, lp); } /* ---------------- entry ---------------- */ typedef BOOL (WINAPI *SetDpiCtxFn)(HANDLE); int WINAPI wWinMain(HINSTANCE inst, HINSTANCE prev, PWSTR cmd, int show) { (void)prev; (void)cmd; (void)show; g_inst = inst; HANDLE mutex = CreateMutexW(NULL, TRUE, L"DeskIcons_SingleInstance_Mutex"); if (GetLastError() == ERROR_ALREADY_EXISTS) { MessageBoxW(NULL, L"DeskIcons is already running. Look for its icon in the system tray.", APP_NAME, MB_OK | MB_ICONINFORMATION); return 0; } SetDpiCtxFn setCtx = (SetDpiCtxFn)GetProcAddress(GetModuleHandleW(L"user32.dll"), "SetProcessDpiAwarenessContext"); if (!setCtx || !setCtx((HANDLE)-4)) SetProcessDPIAware(); HDC sdc = GetDC(NULL); g_dpi = GetDeviceCaps(sdc, LOGPIXELSY); ReleaseDC(NULL, sdc); if (g_dpi < 96) g_dpi = 96; g_font = CreateFontW(-MulDiv(9, g_dpi, 72), 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, L"Segoe UI"); WCHAR dir[MAX_PATH]; if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, dir))) { wcscat(dir, L"\\DeskIcons"); CreateDirectoryW(dir, NULL); swprintf(g_stateFile, MAX_PATH, L"%ls\\state.txt", dir); } else { GetTempPathW(MAX_PATH, dir); swprintf(g_stateFile, MAX_PATH, L"%lsDeskIcons_state.txt", dir); } g_onTop = RegGetDword(L"OnTop", 0) != 0; g_showIcons = RegGetDword(L"ShowIcons", 0) != 0; WNDCLASSEXW wc = { sizeof(wc) }; wc.lpfnWndProc = MainProc; wc.hInstance = inst; wc.lpszClassName = L"DeskIconsMain"; wc.hIcon = LoadIconW(inst, MAKEINTRESOURCEW(1)); RegisterClassExW(&wc); WNDCLASSEXW ic = { sizeof(ic) }; ic.style = CS_DBLCLKS; ic.lpfnWndProc = ItemProc; ic.hInstance = inst; ic.hCursor = LoadCursorW(NULL, IDC_ARROW); ic.lpszClassName = L"DeskIconsItem"; RegisterClassExW(&ic); g_main = CreateWindowExW(0, L"DeskIconsMain", APP_NAME, 0, 0, 0, 0, 0, NULL, NULL, inst, NULL); g_taskbarCreated = RegisterWindowMessageW(L"TaskbarCreated"); AddTrayIcon(); g_hotkeyOk = RegisterHotKey(g_main, HOTKEY_ID, MOD_CONTROL | MOD_ALT | MOD_NOREPEAT, 'I'); g_mouseHook = SetWindowsHookExW(WH_MOUSE_LL, MouseLL, inst, 0); SetTimer(g_main, TIMER_CHECK, 1000, NULL); RecoverFromStateFile(); UpdateTrayTip(); if (!RegGetDword(L"Welcomed", 0)) { RegSetDword(L"Welcomed", 1); Balloon(L"DeskIcons is running", L"Shift+click any minimize button (or press Ctrl+Alt+I) to send that window to the desktop as an icon."); } else if (!g_hotkeyOk) { Balloon(L"DeskIcons", L"Ctrl+Alt+I is already taken by another program. Shift+click on minimize buttons still works."); } MSG m; while (GetMessageW(&m, NULL, 0, 0) > 0) { TranslateMessage(&m); DispatchMessageW(&m); } if (g_font) DeleteObject(g_font); if (mutex) { ReleaseMutex(mutex); CloseHandle(mutex); } return 0; }