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/FL/Fl_Window.H b/common/fltk/FL/Fl_Window.H
index 02ba688..9632895 100644
--- a/common/fltk/FL/Fl_Window.H
+++ b/common/fltk/FL/Fl_Window.H
@@ -31,6 +31,10 @@
#ifndef Fl_Window_H
#define Fl_Window_H
+#ifdef WIN32
+#include <windows.h>
+#endif
+
#include "Fl_Group.H"
#define FL_WINDOW 0xF0 ///< window type id all subclasses have type() >= this
@@ -63,9 +67,19 @@
friend class Fl_X;
Fl_X *i; // points at the system-specific stuff
+ struct icon_data {
+ const void *legacy_icon;
+ Fl_RGB_Image **icons;
+ int count;
+#ifdef WIN32
+ HICON big_icon;
+ HICON small_icon;
+#endif
+ };
+
const char* iconlabel_;
char* xclass_;
- const void* icon_;
+ struct icon_data *icon_;
// size_range stuff:
int minw, minh, maxw, maxh;
int dw, dh, aspect;
@@ -110,6 +124,8 @@
*/
int force_position() const { return ((flags() & FORCE_POSITION)?1:0); }
+ void free_icons();
+
public:
/**
@@ -331,6 +347,18 @@
static const char *default_xclass();
const char* xclass() const;
void xclass(const char* c);
+
+ static void default_icon(const Fl_RGB_Image*);
+ static void default_icons(const Fl_RGB_Image*[], int);
+ void icon(const Fl_RGB_Image*);
+ void icons(const Fl_RGB_Image*[], int);
+
+#ifdef WIN32
+ static void default_icons(HICON big_icon, HICON small_icon);
+ void icons(HICON big_icon, HICON small_icon);
+#endif
+
+ /* for legacy compatibility */
const void* icon() const;
void icon(const void * ic);
diff --git a/common/fltk/FL/mac.H b/common/fltk/FL/mac.H
index f23dc8e..97eefd8 100644
--- a/common/fltk/FL/mac.H
+++ b/common/fltk/FL/mac.H
@@ -141,6 +141,9 @@
void collapse(void);
WindowRef window_ref(void);
void set_key_window(void);
+ // OS X doesn't have per window icons
+ static void set_default_icons(const Fl_RGB_Image*[], int) {};
+ void set_icons() {};
int set_cursor(Fl_Cursor);
int set_cursor(const Fl_RGB_Image*, int, int);
static CGImageRef CGImage_from_window_rect(Fl_Window *win, int x, int y, int w, int h);
diff --git a/common/fltk/FL/win32.H b/common/fltk/FL/win32.H
index 9297e9f..858fe5b 100644
--- a/common/fltk/FL/win32.H
+++ b/common/fltk/FL/win32.H
@@ -93,6 +93,9 @@
void flush() {w->flush();}
void set_minmax(LPMINMAXINFO minmax);
void mapraise();
+ static void set_default_icons(const Fl_RGB_Image*[], int);
+ static void set_default_icons(HICON, HICON);
+ void set_icons();
int set_cursor(Fl_Cursor);
int set_cursor(const Fl_RGB_Image*, int, int);
static Fl_X* make(Fl_Window*);
diff --git a/common/fltk/FL/x.H b/common/fltk/FL/x.H
index a520286..c2eb46e 100644
--- a/common/fltk/FL/x.H
+++ b/common/fltk/FL/x.H
@@ -163,6 +163,8 @@
static Fl_X* i(const Fl_Window* wi) {return wi->i;}
void setwindow(Fl_Window* wi) {w=wi; wi->i=this;}
void sendxjunk();
+ static void set_default_icons(const Fl_RGB_Image*[], int);
+ void set_icons();
int set_cursor(Fl_Cursor);
int set_cursor(const Fl_RGB_Image*, int, int);
static void make_xid(Fl_Window*,XVisualInfo* =fl_visual, Colormap=fl_colormap);
diff --git a/common/fltk/src/Fl.cxx b/common/fltk/src/Fl.cxx
index 134e4d0..887c11f 100644
--- a/common/fltk/src/Fl.cxx
+++ b/common/fltk/src/Fl.cxx
@@ -1535,6 +1535,8 @@
if (xclass_) {
free(xclass_);
}
+ free_icons();
+ delete icon_;
}
// FL_SHOW and FL_HIDE are called whenever the visibility of this widget
diff --git a/common/fltk/src/Fl_Window.cxx b/common/fltk/src/Fl_Window.cxx
index 1ece624..fe872ec 100644
--- a/common/fltk/src/Fl_Window.cxx
+++ b/common/fltk/src/Fl_Window.cxx
@@ -32,6 +32,7 @@
#include <config.h>
#include <FL/Fl.H>
#include <FL/x.H>
+#include <FL/Fl_RGB_Image.H>
#include <FL/Fl_Window.H>
#include <stdlib.h>
#include "flstring.h"
@@ -54,7 +55,8 @@
}
i = 0;
xclass_ = 0;
- icon_ = 0;
+ icon_ = new icon_data;
+ memset(icon_, 0, sizeof(*icon_));
iconlabel_ = 0;
resizable(0);
size_range_set = 0;
@@ -277,16 +279,68 @@
}
}
+void Fl_Window::default_icon(const Fl_RGB_Image *icon) {
+ default_icons(&icon, 1);
+}
+
+void Fl_Window::default_icons(const Fl_RGB_Image **icons, int count) {
+ Fl_X::set_default_icons(icons, count);
+}
+
+void Fl_Window::icon(const Fl_RGB_Image *icon) {
+ icons(&icon, 1);
+}
+
+void Fl_Window::icons(const Fl_RGB_Image **icons, int count) {
+ free_icons();
+
+ if (count > 0) {
+ icon_->icons = new Fl_RGB_Image*[count];
+ icon_->count = count;
+ // FIXME: Fl_RGB_Image lacks const modifiers on methods
+ for (int i = 0;i < count;i++)
+ icon_->icons[i] = (Fl_RGB_Image*)((Fl_RGB_Image*)icons[i])->copy();
+ }
+
+ if (i)
+ i->set_icons();
+}
+
/** Gets the current icon window target dependent data. */
const void *Fl_Window::icon() const {
- return icon_;
+ return icon_->legacy_icon;
}
/** Sets the current icon window target dependent data. */
void Fl_Window::icon(const void * ic) {
- icon_ = ic;
+ free_icons();
+ icon_->legacy_icon = ic;
}
+void Fl_Window::free_icons() {
+ int i;
+
+ icon_->legacy_icon = 0L;
+
+ if (icon_->icons) {
+ for (i = 0;i < icon_->count;i++)
+ delete icon_->icons[i];
+ delete [] icon_->icons;
+ icon_->icons = 0L;
+ }
+
+ icon_->count = 0;
+
+#ifdef WIN32
+ if (icon_->big_icon)
+ DestroyIcon(icon_->big_icon);
+ if (icon_->small_icon)
+ DestroyIcon(icon_->small_icon);
+
+ icon_->big_icon = NULL;
+ icon_->small_icon = NULL;
+#endif
+}
//
// End of "$Id: Fl_Window.cxx 8472 2011-02-25 08:44:47Z AlbrechtS $".
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;
diff --git a/common/fltk/src/Fl_x.cxx b/common/fltk/src/Fl_x.cxx
index 8c72dba..f95cf80 100644
--- a/common/fltk/src/Fl_x.cxx
+++ b/common/fltk/src/Fl_x.cxx
@@ -346,6 +346,7 @@
Atom fl_NET_SUPPORTING_WM_CHECK;
Atom fl_NET_WM_STATE;
Atom fl_NET_WM_STATE_FULLSCREEN;
+Atom fl_NET_WM_ICON;
/*
X defines 32-bit-entities to have a format value of max. 32,
@@ -708,6 +709,7 @@
fl_NET_SUPPORTING_WM_CHECK = XInternAtom(d, "_NET_SUPPORTING_WM_CHECK", 0);
fl_NET_WM_STATE = XInternAtom(d, "_NET_WM_STATE", 0);
fl_NET_WM_STATE_FULLSCREEN = XInternAtom(d, "_NET_WM_STATE_FULLSCREEN", 0);
+ fl_NET_WM_ICON = XInternAtom(d, "_NET_WM_ICON", 0);
if (sizeof(Atom) < 4)
atom_bits = sizeof(Atom) * 8;
@@ -2095,12 +2097,14 @@
fl_show_iconic = 0;
showit = 0;
}
- if (win->icon()) {
- hints->icon_pixmap = (Pixmap)win->icon();
+ if (win->icon_->legacy_icon) {
+ hints->icon_pixmap = (Pixmap)win->icon_->legacy_icon;
hints->flags |= IconPixmapHint;
}
XSetWMHints(fl_display, xp->xid, hints);
XFree(hints);
+
+ xp->set_icons();
}
// set the window type for menu and tooltip windows to avoid animations (compiz)
@@ -2220,6 +2224,93 @@
////////////////////////////////////////////////////////////////
+static unsigned long *default_net_wm_icons = 0L;
+static size_t default_net_wm_icons_size = 0;
+
+void icons_to_property(const Fl_RGB_Image *icons[], int count,
+ unsigned long **property, size_t *len) {
+ size_t sz;
+ unsigned long *data;
+
+ sz = 0;
+ for (int i = 0;i < count;i++)
+ sz += 2 + icons[i]->w() * icons[i]->h();
+
+ // FIXME: Might want to sort the icons
+
+ *property = data = new unsigned long[sz];
+ *len = sz;
+
+ for (int i = 0;i < count;i++) {
+ const Fl_RGB_Image *image;
+
+ image = icons[i];
+
+ data[0] = image->w();
+ data[1] = image->h();
+ data += 2;
+
+ const uchar *in = (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:
+ *data = ( 0xff<<24) | (in[0]<<16) | (in[0]<<8) | in[0];
+ break;
+ case 2:
+ *data = (in[1]<<24) | (in[0]<<16) | (in[0]<<8) | in[0];
+ break;
+ case 3:
+ *data = ( 0xff<<24) | (in[0]<<16) | (in[1]<<8) | in[2];
+ break;
+ case 4:
+ *data = (in[3]<<24) | (in[0]<<16) | (in[1]<<8) | in[2];
+ break;
+ }
+ in += image->d();
+ data++;
+ }
+ in += image->ld();
+ }
+ }
+}
+
+void Fl_X::set_default_icons(const Fl_RGB_Image *icons[], int count) {
+ if (default_net_wm_icons) {
+ delete [] default_net_wm_icons;
+ default_net_wm_icons = 0L;
+ default_net_wm_icons_size = 0;
+ }
+
+ if (count > 0)
+ icons_to_property(icons, count,
+ &default_net_wm_icons, &default_net_wm_icons_size);
+}
+
+void Fl_X::set_icons() {
+ unsigned long *net_wm_icons;
+ size_t net_wm_icons_size;
+
+ if (w->icon_->count) {
+ icons_to_property((const Fl_RGB_Image **)w->icon_->icons, w->icon_->count,
+ &net_wm_icons, &net_wm_icons_size);
+ } else {
+ net_wm_icons = default_net_wm_icons;
+ net_wm_icons_size = default_net_wm_icons_size;
+ }
+
+ XChangeProperty (fl_display, xid, fl_NET_WM_ICON, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char*) net_wm_icons, net_wm_icons_size);
+
+ if (w->icon_->count) {
+ delete [] net_wm_icons;
+ net_wm_icons = 0L;
+ net_wm_icons_size = 0;
+ }
+}
+
+////////////////////////////////////////////////////////////////
+
int Fl_X::set_cursor(Fl_Cursor c) {
unsigned int shape;
Cursor xc;