@@ -122,11 +122,81 @@ void jwm::WindowWin32::setTitlebarVisible(bool isVisible) {
122122 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED );
123123}
124124
125+ void jwm::WindowWin32::_setIconsInternal (HICON hSmall, HICON hBig) {
126+ // Apply small icon (title bar / taskbar)
127+ if (hSmall) {
128+ if (_hIconSmall)
129+ DestroyIcon (_hIconSmall);
130+ _hIconSmall = hSmall;
131+ SendMessage (_hWnd, WM_SETICON , ICON_SMALL , (LPARAM )hSmall);
132+ } else {
133+ JWM_VERBOSE (" Failed to create small icon" );
134+ }
135+ // Apply big icon (Alt-Tab / task switcher)
136+ if (hBig) {
137+ if (_hIconBig)
138+ DestroyIcon (_hIconBig);
139+ _hIconBig = hBig;
140+ SendMessage (_hWnd, WM_SETICON , ICON_BIG , (LPARAM )hBig);
141+ } else {
142+ JWM_VERBOSE (" Failed to create big icon" );
143+ }
144+ }
145+
125146void jwm::WindowWin32::setIcon (const std::wstring& iconPath) {
126147 JWM_VERBOSE (" Set window icon '" << iconPath << " '" );
127- // width / height of 0 along with LR_DEFAULTSIZE tells windows to load the default icon size.
128- HICON hicon = (HICON )LoadImage (NULL , iconPath.c_str (), IMAGE_ICON , 0 , 0 , LR_LOADFROMFILE | LR_DEFAULTSIZE );
129- SendMessage (_hWnd, WM_SETICON , ICON_SMALL , (LPARAM )hicon);
148+ int cxS = GetSystemMetrics (SM_CXSMICON ), cyS = GetSystemMetrics (SM_CYSMICON );
149+ int cxB = GetSystemMetrics (SM_CXICON ), cyB = GetSystemMetrics (SM_CYICON );
150+ HICON hSmall = (HICON )LoadImage (NULL , iconPath.c_str (), IMAGE_ICON , cxS, cyS, LR_LOADFROMFILE );
151+ HICON hBig = (HICON )LoadImage (NULL , iconPath.c_str (), IMAGE_ICON , cxB, cyB, LR_LOADFROMFILE );
152+ _setIconsInternal (hSmall, hBig);
153+ }
154+
155+ HICON jwm::WindowWin32::_createIconFromPixels (int width, int height, const unsigned char * argb) {
156+ // The incoming bytes are in B, G, R, A order per pixel (matching the Linux
157+ // setIconData layout), which is exactly a Windows 32bpp BGRA DIB, so we can
158+ // copy them straight into a top-down DIB section.
159+ BITMAPV5HEADER bi = {};
160+ bi.bV5Size = sizeof (BITMAPV5HEADER );
161+ bi.bV5Width = width;
162+ bi.bV5Height = -height; // negative -> top-down
163+ bi.bV5Planes = 1 ;
164+ bi.bV5BitCount = 32 ;
165+ bi.bV5Compression = BI_BITFIELDS ;
166+ bi.bV5RedMask = 0x00FF0000 ;
167+ bi.bV5GreenMask = 0x0000FF00 ;
168+ bi.bV5BlueMask = 0x000000FF ;
169+ bi.bV5AlphaMask = 0xFF000000 ;
170+
171+ HDC hdc = GetDC (NULL );
172+ void * bits = nullptr ;
173+ HBITMAP hbmColor = CreateDIBSection (hdc, reinterpret_cast <BITMAPINFO *>(&bi), DIB_RGB_COLORS , &bits, NULL , 0 );
174+ ReleaseDC (NULL , hdc);
175+ if (!hbmColor || !bits)
176+ return nullptr ;
177+ memcpy (bits, argb, static_cast <size_t >(width) * height * 4 );
178+
179+ // Monochrome mask is required but unused for 32bpp icons (alpha is honored).
180+ HBITMAP hbmMask = CreateBitmap (width, height, 1 , 1 , NULL );
181+
182+ ICONINFO ii = {};
183+ ii.fIcon = TRUE ;
184+ ii.hbmColor = hbmColor;
185+ ii.hbmMask = hbmMask;
186+ HICON hIcon = CreateIconIndirect (&ii);
187+
188+ DeleteObject (hbmColor);
189+ DeleteObject (hbmMask);
190+ return hIcon;
191+ }
192+
193+ void jwm::WindowWin32::setIconPixels (int width, int height, const unsigned char * argb) {
194+ JWM_VERBOSE (" Set window icon from raw image data " << width << " x" << height);
195+ // A single source image is used for both icon slots; Windows scales it to
196+ // the small (title bar / taskbar) and big (Alt-Tab) metrics as needed.
197+ HICON hSmall = _createIconFromPixels (width, height, argb);
198+ HICON hBig = _createIconFromPixels (width, height, argb);
199+ _setIconsInternal (hSmall, hBig);
130200}
131201
132202void jwm::WindowWin32::setOpacity (float opacity) {
@@ -896,6 +966,16 @@ void jwm::WindowWin32::_destroyInternal() {
896966 _hMouseCursor = nullptr ;
897967 }
898968
969+ if (_hIconSmall) {
970+ DestroyIcon (_hIconSmall);
971+ _hIconSmall = nullptr ;
972+ }
973+
974+ if (_hIconBig) {
975+ DestroyIcon (_hIconBig);
976+ _hIconBig = nullptr ;
977+ }
978+
899979 if (_hWnd) {
900980 DestroyWindow (_hWnd);
901981 _hWnd = nullptr ;
@@ -1103,6 +1183,14 @@ extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWin32__1nSet
11031183 env->ReleaseStringChars (iconPath, iconPathStr);
11041184}
11051185
1186+ extern " C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWin32__1nSetIconPixels
1187+ (JNIEnv* env, jobject obj, jint width, jint height, jbyteArray pixelsArr) {
1188+ jwm::WindowWin32* instance = reinterpret_cast <jwm::WindowWin32*>(jwm::classes::Native::fromJava (env, obj));
1189+ jbyte* pixels = env->GetByteArrayElements (pixelsArr, nullptr );
1190+ instance->setIconPixels (width, height, reinterpret_cast <const unsigned char *>(pixels));
1191+ env->ReleaseByteArrayElements (pixelsArr, pixels, 0 );
1192+ }
1193+
11061194extern " C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWin32__1nSetVisible
11071195 (JNIEnv* env, jobject obj, jboolean isVisible) {
11081196 jwm::WindowWin32* instance = reinterpret_cast <jwm::WindowWin32*>(jwm::classes::Native::fromJava (env, obj));
0 commit comments