|
65 | 65 | postQuitMessage = user32.NewProc("PostQuitMessage") |
66 | 66 | loadIcon = user32.NewProc("LoadIconW") |
67 | 67 | loadImage = user32.NewProc("LoadImageW") |
| 68 | + createIconFromResourceEx = user32.NewProc("CreateIconFromResourceEx") |
68 | 69 | getModuleHandle = kernel32.NewProc("GetModuleHandleW") |
69 | 70 | ) |
70 | 71 |
|
@@ -162,28 +163,60 @@ func initializeSystemTray() { |
162 | 163 | } |
163 | 164 |
|
164 | 165 | func createIconFromData(data []byte) syscall.Handle { |
165 | | - // Create icon from embedded ICO data |
166 | | - // For now, we'll use different system icons to represent light/dark modes |
167 | | - // This should be enhanced to properly load the embedded .ico files |
| 166 | + // ICO files start with an ICONDIR structure, but for CreateIconFromResourceEx |
| 167 | + // we need to skip the ICO header and pass just the icon image data |
| 168 | + // ICO format: ICONDIR (6 bytes) + ICONDIRENTRY array + actual icon data |
168 | 169 |
|
169 | | - if len(data) > 0 { |
170 | | - // In a full implementation, we'd parse the ICO format and use: |
171 | | - // CreateIconFromResource or CreateIconFromResourceEx |
172 | | - |
173 | | - // For demo purposes, use different system icons: |
174 | | - if len(data) == len(light_mode) { |
175 | | - // Light mode icon - use sun-like icon |
176 | | - icon, _, _ := loadIcon.Call(0, 32516) // IDI_WARNING (triangle, yellowish) |
177 | | - return syscall.Handle(icon) |
178 | | - } else { |
179 | | - // Dark mode icon - use moon-like icon |
180 | | - icon, _, _ := loadIcon.Call(0, 32513) // IDI_QUESTION (blue) |
181 | | - return syscall.Handle(icon) |
182 | | - } |
| 170 | + if len(data) < 6 { |
| 171 | + // Fallback to system icon if data is invalid |
| 172 | + icon, _, _ := loadIcon.Call(0, 32512) // IDI_APPLICATION |
| 173 | + return syscall.Handle(icon) |
| 174 | + } |
| 175 | + |
| 176 | + // Parse ICO header to find the first icon entry |
| 177 | + // ICONDIR: Reserved(2) + Type(2) + Count(2) |
| 178 | + iconCount := uint16(data[4]) | (uint16(data[5]) << 8) |
| 179 | + if iconCount == 0 || len(data) < 6 + int(iconCount)*16 { |
| 180 | + // Fallback to system icon if structure is invalid |
| 181 | + icon, _, _ := loadIcon.Call(0, 32512) // IDI_APPLICATION |
| 182 | + return syscall.Handle(icon) |
| 183 | + } |
| 184 | + |
| 185 | + // Get first ICONDIRENTRY (16 bytes starting at offset 6) |
| 186 | + entryOffset := 6 |
| 187 | + imageOffset := uint32(data[entryOffset+12]) | (uint32(data[entryOffset+13]) << 8) | |
| 188 | + (uint32(data[entryOffset+14]) << 16) | (uint32(data[entryOffset+15]) << 24) |
| 189 | + imageSize := uint32(data[entryOffset+8]) | (uint32(data[entryOffset+9]) << 8) | |
| 190 | + (uint32(data[entryOffset+10]) << 16) | (uint32(data[entryOffset+11]) << 24) |
| 191 | + |
| 192 | + // Validate image offset and size |
| 193 | + if imageOffset >= uint32(len(data)) || imageOffset+imageSize > uint32(len(data)) { |
| 194 | + // Fallback to system icon if offset/size is invalid |
| 195 | + icon, _, _ := loadIcon.Call(0, 32512) // IDI_APPLICATION |
| 196 | + return syscall.Handle(icon) |
| 197 | + } |
| 198 | + |
| 199 | + // Extract the actual icon image data (skip ICO header) |
| 200 | + imageData := data[imageOffset:imageOffset+imageSize] |
| 201 | + |
| 202 | + // Create icon from the image data |
| 203 | + icon, _, _ := createIconFromResourceEx.Call( |
| 204 | + uintptr(unsafe.Pointer(&imageData[0])), // pointer to icon data |
| 205 | + uintptr(imageSize), // size of icon data |
| 206 | + 1, // fIcon = TRUE (this is an icon, not cursor) |
| 207 | + 0x00030000, // dwVersion = 0x00030000 |
| 208 | + 0, // cxDesired = 0 (use default) |
| 209 | + 0, // cyDesired = 0 (use default) |
| 210 | + 0, // Flags = 0 (default behavior) |
| 211 | + ) |
| 212 | + |
| 213 | + if icon != 0 { |
| 214 | + return syscall.Handle(icon) |
183 | 215 | } |
184 | 216 |
|
185 | | - icon, _, _ := loadIcon.Call(0, 32512) // IDI_APPLICATION (default) |
186 | | - return syscall.Handle(icon) |
| 217 | + // Final fallback to system icon if CreateIconFromResourceEx failed |
| 218 | + fallbackIcon, _, _ := loadIcon.Call(0, 32512) // IDI_APPLICATION |
| 219 | + return syscall.Handle(fallbackIcon) |
187 | 220 | } |
188 | 221 |
|
189 | 222 | func createTrayIcon() { |
|
0 commit comments