Proper support for icons in FLTK (upstream STR 2816).
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4898 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/common/fltk/src/Fl_win32.cxx b/common/fltk/src/Fl_win32.cxx
index 7fc639e..eaae51d 100644
--- a/common/fltk/src/Fl_win32.cxx
+++ b/common/fltk/src/Fl_win32.cxx
@@ -1802,6 +1802,8 @@
);
if (lab) free(lab);
+ x->set_icons();
+
if (w->flags() & Fl_Widget::FULLSCREEN) {
/* We need to make sure that the fullscreen is created on the
default monitor, ie the desktop where the shortcut is located
@@ -2028,6 +2030,210 @@
////////////////////////////////////////////////////////////////
+static HICON image_to_icon(const Fl_RGB_Image *image, bool is_icon=true,
+ int hotx = 0, int hoty = 0) {
+ BITMAPV5HEADER bi;
+ HBITMAP bitmap, mask;
+ DWORD *bits;
+ HICON icon;
+
+ if (!is_icon) {
+ if ((hotx < 0) || (hotx >= image->w()))
+ return NULL;
+ if ((hoty < 0) || (hoty >= image->h()))
+ return NULL;
+ }
+
+ memset(&bi, 0, sizeof(BITMAPV5HEADER));
+
+ bi.bV5Size = sizeof(BITMAPV5HEADER);
+ bi.bV5Width = image->w();
+ bi.bV5Height = -image->h(); // Negative for top-down
+ bi.bV5Planes = 1;
+ bi.bV5BitCount = 32;
+ bi.bV5Compression = BI_BITFIELDS;
+ bi.bV5RedMask = 0x00FF0000;
+ bi.bV5GreenMask = 0x0000FF00;
+ bi.bV5BlueMask = 0x000000FF;
+ bi.bV5AlphaMask = 0xFF000000;
+
+ HDC hdc;
+
+ hdc = GetDC(NULL);
+ bitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+ ReleaseDC(NULL, hdc);
+
+ if (bits == NULL)
+ return NULL;
+
+ const uchar *i = (const uchar*)*image->data();
+ for (int y = 0;y < image->h();y++) {
+ for (int x = 0;x < image->w();x++) {
+ switch (image->d()) {
+ case 1:
+ *bits = (0xff<<24) | (i[0]<<16) | (i[0]<<8) | i[0];
+ break;
+ case 2:
+ *bits = (i[1]<<24) | (i[0]<<16) | (i[0]<<8) | i[0];
+ break;
+ case 3:
+ *bits = (0xff<<24) | (i[0]<<16) | (i[1]<<8) | i[2];
+ break;
+ case 4:
+ *bits = (i[3]<<24) | (i[0]<<16) | (i[1]<<8) | i[2];
+ break;
+ }
+ i += image->d();
+ bits++;
+ }
+ i += image->ld();
+ }
+
+ // A mask bitmap is still needed even though it isn't used
+ mask = CreateBitmap(image->w(),image->h(),1,1,NULL);
+ if (mask == NULL) {
+ DeleteObject(bitmap);
+ return NULL;
+ }
+
+ ICONINFO ii;
+
+ ii.fIcon = is_icon;
+ ii.xHotspot = hotx;
+ ii.yHotspot = hoty;
+ ii.hbmMask = mask;
+ ii.hbmColor = bitmap;
+
+ icon = CreateIconIndirect(&ii);
+
+ DeleteObject(bitmap);
+ DeleteObject(mask);
+
+ if (icon == NULL)
+ return NULL;
+
+ return icon;
+}
+
+////////////////////////////////////////////////////////////////
+
+static HICON default_big_icon = NULL;
+static HICON default_small_icon = NULL;
+
+const Fl_RGB_Image *find_best_icon(int ideal_width,
+ const Fl_RGB_Image *icons[], int count) {
+ const Fl_RGB_Image *best;
+
+ best = NULL;
+
+ for (int i = 0;i < count;i++) {
+ if (best == NULL)
+ best = icons[i];
+ else {
+ if (best->w() < ideal_width) {
+ if (icons[i]->w() > best->w())
+ best = icons[i];
+ } else {
+ if ((icons[i]->w() >= ideal_width) &&
+ (icons[i]->w() < best->w()))
+ best = icons[i];
+ }
+ }
+ }
+
+ return best;
+}
+
+void Fl_X::set_default_icons(const Fl_RGB_Image *icons[], int count) {
+ const Fl_RGB_Image *best_big, *best_small;
+
+ if (default_big_icon != NULL)
+ DestroyIcon(default_big_icon);
+ if (default_small_icon != NULL)
+ DestroyIcon(default_small_icon);
+
+ best_big = find_best_icon(GetSystemMetrics(SM_CXICON), icons, count);
+ best_small = find_best_icon(GetSystemMetrics(SM_CXSMICON), icons, count);
+
+ if (best_big != NULL)
+ default_big_icon = image_to_icon(best_big);
+ else
+ default_big_icon = NULL;
+
+ if (best_small != NULL)
+ default_small_icon = image_to_icon(best_small);
+ else
+ default_small_icon = NULL;
+}
+
+void Fl_X::set_default_icons(HICON big_icon, HICON small_icon) {
+ if (default_big_icon != NULL)
+ DestroyIcon(default_big_icon);
+ if (default_small_icon != NULL)
+ DestroyIcon(default_small_icon);
+
+ if (big_icon != NULL)
+ default_big_icon = CopyIcon(big_icon);
+ if (small_icon != NULL)
+ default_small_icon = CopyIcon(small_icon);
+}
+
+void Fl_X::set_icons() {
+ HICON big_icon, small_icon;
+
+ big_icon = NULL;
+ small_icon = NULL;
+
+ if (w->icon_->count) {
+ const Fl_RGB_Image *best_big, *best_small;
+
+ best_big = find_best_icon(GetSystemMetrics(SM_CXICON),
+ (const Fl_RGB_Image **)w->icon_->icons,
+ w->icon_->count);
+ best_small = find_best_icon(GetSystemMetrics(SM_CXSMICON),
+ (const Fl_RGB_Image **)w->icon_->icons,
+ w->icon_->count);
+
+ if (best_big != NULL)
+ big_icon = image_to_icon(best_big);
+ if (best_small != NULL)
+ small_icon = image_to_icon(best_small);
+ } else {
+ big_icon = default_big_icon;
+ small_icon = default_small_icon;
+ }
+
+ if (big_icon != NULL)
+ SendMessage(xid, WM_SETICON, ICON_BIG, (LPARAM)big_icon);
+ if (small_icon != NULL)
+ SendMessage(xid, WM_SETICON, ICON_SMALL, (LPARAM)small_icon);
+
+ if (w->icon_->count) {
+ if (big_icon != NULL)
+ DestroyIcon(big_icon);
+ if (small_icon != NULL)
+ DestroyIcon(small_icon);
+ }
+}
+
+void Fl_Window::default_icons(HICON big_icon, HICON small_icon) {
+ Fl_X::set_default_icons(big_icon, small_icon);
+}
+
+void Fl_Window::icons(HICON big_icon, HICON small_icon) {
+ free_icons();
+
+ if (big_icon != NULL)
+ icon_->big_icon = CopyIcon(big_icon);
+ if (small_icon != NULL)
+ icon_->small_icon = CopyIcon(small_icon);
+
+ if (i)
+ i->set_icons();
+}
+
+////////////////////////////////////////////////////////////////
+
#ifndef IDC_HAND
# define IDC_HAND MAKEINTRESOURCE(32649)
#endif // !IDC_HAND
@@ -2084,81 +2290,9 @@
}
int Fl_X::set_cursor(const Fl_RGB_Image *image, int hotx, int hoty) {
- BITMAPV5HEADER bi;
- HBITMAP bitmap, mask;
- DWORD *bits;
HCURSOR new_cursor;
- if ((hotx < 0) || (hotx >= image->w()))
- return 0;
- if ((hoty < 0) || (hoty >= image->h()))
- return 0;
-
- memset(&bi, 0, sizeof(BITMAPV5HEADER));
-
- bi.bV5Size = sizeof(BITMAPV5HEADER);
- bi.bV5Width = image->w();
- bi.bV5Height = -image->h(); // Negative for top-down
- bi.bV5Planes = 1;
- bi.bV5BitCount = 32;
- bi.bV5Compression = BI_BITFIELDS;
- bi.bV5RedMask = 0x00FF0000;
- bi.bV5GreenMask = 0x0000FF00;
- bi.bV5BlueMask = 0x000000FF;
- bi.bV5AlphaMask = 0xFF000000;
-
- HDC hdc;
-
- hdc = GetDC(NULL);
- bitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
- ReleaseDC(NULL, hdc);
-
- if (bits == NULL)
- return 0;
-
- const uchar *i = (const uchar*)*image->data();
- for (int y = 0;y < image->h();y++) {
- for (int x = 0;x < image->w();x++) {
- switch (image->d()) {
- case 1:
- *bits = (0xff<<24) | (i[0]<<16) | (i[0]<<8) | i[0];
- break;
- case 2:
- *bits = (i[1]<<24) | (i[0]<<16) | (i[0]<<8) | i[0];
- break;
- case 3:
- *bits = (0xff<<24) | (i[0]<<16) | (i[1]<<8) | i[2];
- break;
- case 4:
- *bits = (i[3]<<24) | (i[0]<<16) | (i[1]<<8) | i[2];
- break;
- }
- i += image->d();
- bits++;
- }
- i += image->ld();
- }
-
- // A mask bitmap is still needed even though it isn't used
- mask = CreateBitmap(image->w(),image->h(),1,1,NULL);
- if (mask == NULL) {
- DeleteObject(bitmap);
- return 0;
- }
-
- ICONINFO ii;
-
- ii.fIcon = FALSE;
- ii.xHotspot = hotx;
- ii.yHotspot = hoty;
- ii.hbmMask = mask;
- ii.hbmColor = bitmap;
-
- new_cursor = CreateIconIndirect(&ii);
-
- DeleteObject(bitmap);
- DeleteObject(mask);
-
+ new_cursor = image_to_icon(image, false, hotx, hoty);
if (new_cursor == NULL)
return 0;