Add ability to set custom icons for windows. STR #2816.

git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@10197 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Pierre Ossman 2014-06-16 11:39:32 +00:00
parent 332dc1b7ac
commit f58b1a91b3
11 changed files with 553 additions and 82 deletions

View File

@ -22,6 +22,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
@ -89,9 +93,19 @@ class FL_EXPORT Fl_Window : public Fl_Group {
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;
@ -141,6 +155,8 @@ protected:
*/
int force_position() const { return ((flags() & FORCE_POSITION)?1:0); }
void free_icons();
public:
/**
@ -370,6 +386,18 @@ public:
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);

View File

@ -142,6 +142,9 @@ public:
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);

View File

@ -85,6 +85,9 @@ public:
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*);

2
FL/x.H
View File

@ -150,6 +150,8 @@ public:
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);

View File

@ -1489,6 +1489,8 @@ void Fl_Window::hide() {
handle(FL_HIDE);
#if defined(WIN32)
// make sure any custom icons get freed
icons(NULL, 0);
// this little trick keeps the current clipboard alive, even if we are about
// to destroy the window that owns the selection.
if (GetClipboardOwner()==ip->xid)
@ -1553,6 +1555,8 @@ Fl_Window::~Fl_Window() {
if (xclass_) {
free(xclass_);
}
free_icons();
delete icon_;
}
// FL_SHOW and FL_HIDE are called whenever the visibility of this widget

View File

@ -23,6 +23,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"
@ -45,7 +46,8 @@ void Fl_Window::_Fl_Window() {
}
i = 0;
xclass_ = 0;
icon_ = 0;
icon_ = new icon_data;
memset(icon_, 0, sizeof(*icon_));
iconlabel_ = 0;
resizable(0);
size_range_set = 0;
@ -301,14 +303,118 @@ const char *Fl_Window::xclass() const
}
}
/** Gets the current icon window target dependent data. */
const void *Fl_Window::icon() const {
return icon_;
/** Sets a single default window icon.
\param[in] icon default icon for all windows subsequently created
\see Fl_Window::default_icons(const Fl_RGB_Image *[], int)
\see Fl_Window::icon(const Fl_RGB_Image *)
\see Fl_Window::icons(const Fl_RGB_Image *[], int)
*/
void Fl_Window::default_icon(const Fl_RGB_Image *icon) {
default_icons(&icon, 1);
}
/** Sets the current icon window target dependent data. */
/** Sets the default window icons.
The default icons are used for all windows that don't have their
own icons set before show() is called. You can change the default
icons whenever you want, but this only affects windows that are
created (and shown) after this call.
The given images in \p icons are copied. You can use a local
variable or free the images immediately after this call.
\param[in] icons default icons for all windows subsequently created
\param[in] count number of images in \p icons. set to 0 to remove
the current default icons
\see Fl_Window::default_icon(const Fl_RGB_Image *)
\see Fl_Window::icon(const Fl_RGB_Image *)
\see Fl_Window::icons(const Fl_RGB_Image *[], int)
*/
void Fl_Window::default_icons(const Fl_RGB_Image *icons[], int count) {
Fl_X::set_default_icons(icons, count);
}
/** Sets a single window icon.
\param[in] icon icon for this window
\see Fl_Window::default_icon(const Fl_RGB_Image *)
\see Fl_Window::default_icons(const Fl_RGB_Image *[], int)
\see Fl_Window::icons(const Fl_RGB_Image *[], int)
*/
void Fl_Window::icon(const Fl_RGB_Image *icon) {
icons(&icon, 1);
}
/** Sets the window icons.
The given images in \p icons are copied. You can use a local
variable or free the images immediately after this call.
\param[in] icons icons for this window
\param[in] count number of images in \p icons. set to 0 to remove
the current icons
\see Fl_Window::default_icon(const Fl_RGB_Image *)
\see Fl_Window::default_icons(const Fl_RGB_Image *[], int)
\see Fl_Window::icon(const Fl_RGB_Image *)
*/
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.
\deprecated in 1.3.3
*/
const void *Fl_Window::icon() const {
return icon_->legacy_icon;
}
/** Sets the current icon window target dependent data.
\deprecated in 1.3.3
*/
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
}
//

View File

@ -1820,6 +1820,8 @@ Fl_X* Fl_X::make(Fl_Window* w) {
);
if (lab) free(lab);
x->set_icons();
if (w->fullscreen_active()) {
/* We need to make sure that the fullscreen is created on the
default monitor, ie the desktop where the shortcut is located
@ -2053,6 +2055,254 @@ void Fl_Window::label(const char *name,const char *iname) {
////////////////////////////////////////////////////////////////
static HICON image_to_icon(const Fl_RGB_Image *image, bool is_icon,
int hotx, int hoty) {
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;
static 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);
default_big_icon = NULL;
default_small_icon = NULL;
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, true, 0, 0);
if (best_small != NULL)
default_small_icon = image_to_icon(best_small, true, 0, 0);
}
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);
default_big_icon = NULL;
default_small_icon = NULL;
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;
// Windows doesn't copy the icons, so we have to "leak" them when
// setting, and clean up when we change to some other icons.
big_icon = (HICON)SendMessage(xid, WM_GETICON, ICON_BIG, 0);
if ((big_icon != NULL) && (big_icon != default_big_icon))
DestroyIcon(big_icon);
small_icon = (HICON)SendMessage(xid, WM_GETICON, ICON_SMALL, 0);
if ((small_icon != NULL) && (small_icon != default_small_icon))
DestroyIcon(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, true, 0, 0);
if (best_small != NULL)
small_icon = image_to_icon(best_small, true, 0, 0);
} else {
if ((w->icon_->big_icon != NULL) || (w->icon_->small_icon != NULL)) {
big_icon = w->icon_->big_icon;
small_icon = w->icon_->small_icon;
} else {
big_icon = default_big_icon;
small_icon = default_small_icon;
}
}
SendMessage(xid, WM_SETICON, ICON_BIG, (LPARAM)big_icon);
SendMessage(xid, WM_SETICON, ICON_SMALL, (LPARAM)small_icon);
}
/** Sets the default window icons.
Convenience function to set the default icons using Windows'
native HICON icon handles.
The given icons are copied. You can free the icons immediately after
this call.
\param[in] big_icon default large icon for all windows
subsequently created
\param[in] small_icon default small icon for all windows
subsequently created
\see Fl_Window::default_icon(const Fl_RGB_Image *)
\see Fl_Window::default_icons(const Fl_RGB_Image *[], int)
\see Fl_Window::icon(const Fl_RGB_Image *)
\see Fl_Window::icons(const Fl_RGB_Image *[], int)
\see Fl_Window::icons(HICON, HICON)
*/
void Fl_Window::default_icons(HICON big_icon, HICON small_icon) {
Fl_X::set_default_icons(big_icon, small_icon);
}
/** Sets the window icons.
Convenience function to set this window's icons using Windows'
native HICON icon handles.
The given icons are copied. You can free the icons immediately after
this call.
\param[in] big_icon large icon for this window
\param[in] small_icon small icon for this windows
\see Fl_Window::default_icon(const Fl_RGB_Image *)
\see Fl_Window::default_icons(const Fl_RGB_Image *[], int)
\see Fl_Window::default_icons(HICON, HICON)
\see Fl_Window::icon(const Fl_RGB_Image *)
\see Fl_Window::icons(const Fl_RGB_Image *[], int)
*/
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
@ -2109,81 +2359,9 @@ int Fl_X::set_cursor(Fl_Cursor c) {
}
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;

View File

@ -352,6 +352,7 @@ Atom fl_NET_WM_STATE;
Atom fl_NET_WM_STATE_FULLSCREEN;
Atom fl_NET_WM_FULLSCREEN_MONITORS;
Atom fl_NET_WORKAREA;
Atom fl_NET_WM_ICON;
/*
X defines 32-bit-entities to have a format value of max. 32,
@ -662,6 +663,7 @@ void fl_open_display(Display* d) {
fl_NET_WM_STATE_FULLSCREEN = XInternAtom(d, "_NET_WM_STATE_FULLSCREEN", 0);
fl_NET_WM_FULLSCREEN_MONITORS = XInternAtom(d, "_NET_WM_FULLSCREEN_MONITORS", 0);
fl_NET_WORKAREA = XInternAtom(d, "_NET_WORKAREA", 0);
fl_NET_WM_ICON = XInternAtom(d, "_NET_WM_ICON", 0);
if (sizeof(Atom) < 4)
atom_bits = sizeof(Atom) * 8;
@ -2480,12 +2482,14 @@ void Fl_X::make_xid(Fl_Window* win, XVisualInfo *visual, Colormap colormap)
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)
@ -2605,6 +2609,93 @@ void Fl_Window::size_range_() {
////////////////////////////////////////////////////////////////
static unsigned long *default_net_wm_icons = 0L;
static size_t default_net_wm_icons_size = 0;
static 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;

View File

@ -82,6 +82,7 @@ CREATE_EXAMPLE(fonts fonts.cxx fltk)
CREATE_EXAMPLE(forms forms.cxx "fltk;fltk_forms")
CREATE_EXAMPLE(hello hello.cxx fltk)
CREATE_EXAMPLE(help help.cxx "fltk;fltk_images")
CREATE_EXAMPLE(icon icon.cxx fltk)
CREATE_EXAMPLE(iconize iconize.cxx fltk)
CREATE_EXAMPLE(image image.cxx fltk)
CREATE_EXAMPLE(inactive inactive.fl fltk)

View File

@ -53,6 +53,7 @@ CPPFILES =\
glpuzzle.cxx \
hello.cxx \
help.cxx \
icon.cxx \
iconize.cxx \
image.cxx \
inactive.cxx \
@ -121,6 +122,7 @@ ALL = \
forms$(EXEEXT) \
hello$(EXEEXT) \
help$(EXEEXT) \
icon$(EXEEXT) \
iconize$(EXEEXT) \
image$(EXEEXT) \
inactive$(EXEEXT) \
@ -355,6 +357,8 @@ help$(EXEEXT): help.o $(IMGLIBNAME)
$(CXX) $(ARCHFLAGS) $(CXXFLAGS) $(LDFLAGS) help.o -o $@ $(LINKFLTKIMG) $(LDLIBS)
$(OSX_ONLY) ../fltk-config --post $@
icon$(EXEEXT): icon.o
iconize$(EXEEXT): iconize.o
image$(EXEEXT): image.o

51
test/icon.cxx Normal file
View File

@ -0,0 +1,51 @@
//
// Icon test program for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2010 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
// file is missing or damaged, see the license at:
//
// http://www.fltk.org/COPYING.php
//
// Please report all bugs and problems on the following page:
//
// http://www.fltk.org/str.php
//
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Choice.H>
#include <FL/Fl_RGB_Image.H>
static Fl_Double_Window *win;
void choice_cb(Fl_Widget *, void *v) {
Fl_Color c = (Fl_Color)(fl_intptr_t)v;
uchar buffer[32*32*3];
Fl_RGB_Image icon(buffer, 32, 32, 3);
icon.color_average(c, 0.0);
win->icon(&icon);
}
Fl_Menu_Item choices[] = {
{"Red",0,choice_cb,(void*)FL_RED},
{"Green",0,choice_cb,(void*)FL_GREEN},
{"Blue",0,choice_cb,(void*)FL_BLUE},
{0}
};
int main(int argc, char **argv) {
Fl_Double_Window window(400,300);
win = &window;
Fl_Choice choice(80,100,200,25,"Colour:");
choice.menu(choices);
choice.callback(choice_cb);
choice.when(FL_WHEN_RELEASE|FL_WHEN_NOT_CHANGED);
window.end();
window.show(argc,argv);
return Fl::run();
}