Initial framework for dynamic color support
- Fl_Dynamic_Color enum - Fl::dynamic_color() APIs - Fl_System_Driver::dynamic_color() API - FL_DYNAMIC_COLOR_CHANGED event - Add method for querying dark mode to macOS system and screen drivers. - Check/update mode whenever we get a layout change from macOS. - Add detection of dark mode on macOS by using the effectiveAppearance property. - Force redraw of all windows when changing the mode. - Update Cocoa set_system_colors method to override colors when dynamic mode isn't off. - Add (temporary) support for FL_DYNAMIC_COLOR environment variable to override default "off" mode for testing. To do: add dark mode detection on other platforms than macOS. Note: Branch 'darkmode' rebased, squashed, and extended by Albrecht-S on Dec 17, 2023.
This commit is contained in:
parent
469d3ef3d5
commit
4ab861aae2
@ -407,7 +407,11 @@ enum Fl_Event { // events
|
|||||||
/** A zoom event (ctrl/+/-/0/ or cmd/+/-/0/) was processed.
|
/** A zoom event (ctrl/+/-/0/ or cmd/+/-/0/) was processed.
|
||||||
Use Fl::add_handler() to be notified of this event.
|
Use Fl::add_handler() to be notified of this event.
|
||||||
*/
|
*/
|
||||||
FL_ZOOM_EVENT = 27
|
FL_ZOOM_EVENT = 27,
|
||||||
|
/** The current dynamic color mode has changed.
|
||||||
|
Call Fl::dynamic_color() to get the new mode.
|
||||||
|
*/
|
||||||
|
FL_DYNAMIC_COLOR_CHANGED = 28
|
||||||
// DEV NOTE: Keep this list in sync with FL/names.h
|
// DEV NOTE: Keep this list in sync with FL/names.h
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1380,4 +1384,26 @@ enum Fl_Orientation {
|
|||||||
FL_ORIENT_SE = 0x07 ///< GUI element pointing SE (315°)
|
FL_ORIENT_SE = 0x07 ///< GUI element pointing SE (315°)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Modern operating systems provide a pair of color themes suitable for use in
|
||||||
|
light and dark ambient lighting. Automatic switching is normally provided
|
||||||
|
either using the current time of day or with ambient lighting sensors.
|
||||||
|
This enumeration lists the values for the Fl::dynamic_color() API, allowing
|
||||||
|
applications to opt in to automatic color theme switching or specify that
|
||||||
|
color switching is not desired.
|
||||||
|
|
||||||
|
\see Fl::dynamic_color()
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum Fl_Dynamic_Color { // dynamic color values
|
||||||
|
/** Dynamic color themes are off/not supported/disabled */
|
||||||
|
FL_DYNAMIC_COLOR_OFF,
|
||||||
|
/** Automatically change color themes */
|
||||||
|
FL_DYNAMIC_COLOR_AUTO,
|
||||||
|
/** Use the light color theme */
|
||||||
|
FL_DYNAMIC_COLOR_LIGHT,
|
||||||
|
/** Use the dark color theme */
|
||||||
|
FL_DYNAMIC_COLOR_DARK
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
23
FL/Fl.H
23
FL/Fl.H
@ -148,6 +148,8 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
static Fl_Dynamic_Color dynamic_color_;
|
||||||
|
|
||||||
static Fl_Screen_Driver *screen_driver();
|
static Fl_Screen_Driver *screen_driver();
|
||||||
static Fl_System_Driver *system_driver();
|
static Fl_System_Driver *system_driver();
|
||||||
#ifdef __APPLE__ // deprecated in 1.4 - only for compatibility with 1.3
|
#ifdef __APPLE__ // deprecated in 1.4 - only for compatibility with 1.3
|
||||||
@ -392,6 +394,27 @@ public:
|
|||||||
static void background(uchar, uchar, uchar);
|
static void background(uchar, uchar, uchar);
|
||||||
static void background2(uchar, uchar, uchar);
|
static void background2(uchar, uchar, uchar);
|
||||||
|
|
||||||
|
// dynamic color:
|
||||||
|
/** Set the dynamic color theme mode.
|
||||||
|
|
||||||
|
Most applications should just call Fl::dynamic_color(FL_DYNAMIC_COLOR_AUTO)
|
||||||
|
to use the user's preferred color theme. The default value is
|
||||||
|
FL_DYNAMIC_COLOR_OFF for compatibility with prior versions of FLTK.
|
||||||
|
|
||||||
|
When set to FL_DYNAMIC_COLOR_AUTO, FLTK will monitor for appearance/theme
|
||||||
|
changes. When the color theme changes, a FL_DYNAMIC_COLOR_CHANGED event is
|
||||||
|
sent to allow widgets to update their colors as needed.
|
||||||
|
*/
|
||||||
|
static void dynamic_color(Fl_Dynamic_Color mode);
|
||||||
|
/** Gets the current dynamic color theme.
|
||||||
|
|
||||||
|
Returns FL_DYNAMIC_COLOR_OFF if dynamic color themes are off or disabled
|
||||||
|
(the default), FL_DYNAMIC_COLOR_LIGHT if the current color theme is for use
|
||||||
|
in bright ambient light, or FL_DYNAMIC_COLOR_DARK is the current color
|
||||||
|
theme is for use in dark ambient light.
|
||||||
|
*/
|
||||||
|
static Fl_Dynamic_Color dynamic_color();
|
||||||
|
|
||||||
// schemes:
|
// schemes:
|
||||||
static int scheme(const char *name);
|
static int scheme(const char *name);
|
||||||
/** See void scheme(const char *name) */
|
/** See void scheme(const char *name) */
|
||||||
|
@ -73,7 +73,7 @@ const char * const fl_eventnames[] =
|
|||||||
"FL_FULLSCREEN",
|
"FL_FULLSCREEN",
|
||||||
"FL_ZOOM_GESTURE",
|
"FL_ZOOM_GESTURE",
|
||||||
"FL_ZOOM_EVENT",
|
"FL_ZOOM_EVENT",
|
||||||
"FL_EVENT_28", // not yet defined, just in case it /will/ be defined ...
|
"FL_DYNAMIC_COLOR_CHANGED",
|
||||||
"FL_EVENT_29", // not yet defined, just in case it /will/ be defined ...
|
"FL_EVENT_29", // not yet defined, just in case it /will/ be defined ...
|
||||||
"FL_EVENT_30" // not yet defined, just in case it /will/ be defined ...
|
"FL_EVENT_30" // not yet defined, just in case it /will/ be defined ...
|
||||||
};
|
};
|
||||||
|
@ -222,6 +222,7 @@ public:
|
|||||||
virtual const char *alt_name() { return "Alt"; }
|
virtual const char *alt_name() { return "Alt"; }
|
||||||
virtual const char *control_name() { return "Ctrl"; }
|
virtual const char *control_name() { return "Ctrl"; }
|
||||||
virtual Fl_Sys_Menu_Bar_Driver *sys_menu_bar_driver() { return NULL; }
|
virtual Fl_Sys_Menu_Bar_Driver *sys_menu_bar_driver() { return NULL; }
|
||||||
|
virtual Fl_Dynamic_Color dynamic_color() { return FL_DYNAMIC_COLOR_LIGHT; }
|
||||||
virtual void lock_ring() {}
|
virtual void lock_ring() {}
|
||||||
virtual void unlock_ring() {}
|
virtual void unlock_ring() {}
|
||||||
virtual double wait(double); // must FL_OVERRIDE
|
virtual double wait(double); // must FL_OVERRIDE
|
||||||
|
@ -580,6 +580,7 @@ void Fl_Cocoa_Screen_Driver::breakMacEventLoop()
|
|||||||
- (BOOL)process_keydown:(NSEvent*)theEvent;
|
- (BOOL)process_keydown:(NSEvent*)theEvent;
|
||||||
- (id)initWithFrame:(NSRect)frameRect;
|
- (id)initWithFrame:(NSRect)frameRect;
|
||||||
- (void)drawRect:(NSRect)rect;
|
- (void)drawRect:(NSRect)rect;
|
||||||
|
- (void)layout;
|
||||||
- (BOOL)acceptsFirstResponder;
|
- (BOOL)acceptsFirstResponder;
|
||||||
- (BOOL)acceptsFirstMouse:(NSEvent*)theEvent;
|
- (BOOL)acceptsFirstMouse:(NSEvent*)theEvent;
|
||||||
- (void)resetCursorRects;
|
- (void)resetCursorRects;
|
||||||
@ -2415,6 +2416,38 @@ static FLTextInputContext* fltextinputcontext_instance = nil;
|
|||||||
fl_unlock_function();
|
fl_unlock_function();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)layout
|
||||||
|
{
|
||||||
|
// Check to see whether the system appearance has changed...
|
||||||
|
if (Fl::dynamic_color_ == FL_DYNAMIC_COLOR_AUTO) {
|
||||||
|
Fl_Dynamic_Color mode = FL_DYNAMIC_COLOR_LIGHT;
|
||||||
|
|
||||||
|
if (@available(macOS 10.14, *)) {
|
||||||
|
NSAppearanceName temp = [self.effectiveAppearance bestMatchFromAppearancesWithNames:@[
|
||||||
|
NSAppearanceNameAqua,
|
||||||
|
NSAppearanceNameDarkAqua
|
||||||
|
]];
|
||||||
|
|
||||||
|
if ([temp isEqualToString:NSAppearanceNameDarkAqua])
|
||||||
|
mode = FL_DYNAMIC_COLOR_DARK;
|
||||||
|
}
|
||||||
|
|
||||||
|
Fl_Darwin_System_Driver *s = (Fl_Darwin_System_Driver *)Fl::system_driver();
|
||||||
|
if (s->dynamic_color() != mode) {
|
||||||
|
// Change the color mode and force all windows to redraw...
|
||||||
|
s->dynamic_color(mode);
|
||||||
|
Fl::get_system_colors();
|
||||||
|
|
||||||
|
Fl_Window *window;
|
||||||
|
for (window = Fl::first_window(); window; window = Fl::next_window(window))
|
||||||
|
window->redraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[super layout];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
- (BOOL)acceptsFirstResponder
|
- (BOOL)acceptsFirstResponder
|
||||||
{
|
{
|
||||||
return [[self window] parentWindow] ? NO : YES; // 10.2
|
return [[self window] parentWindow] ? NO : YES; // 10.2
|
||||||
|
@ -106,6 +106,27 @@ void Fl::get_system_colors()
|
|||||||
Fl::screen_driver()->get_system_colors();
|
Fl::screen_driver()->get_system_colors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef FL_DOXYGEN
|
||||||
|
Fl_Dynamic_Color Fl::dynamic_color_ = FL_DYNAMIC_COLOR_OFF;
|
||||||
|
#endif // !FL_DOXYGEN
|
||||||
|
|
||||||
|
void Fl::dynamic_color(Fl_Dynamic_Color mode)
|
||||||
|
{
|
||||||
|
dynamic_color_ = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
Fl_Dynamic_Color Fl::dynamic_color()
|
||||||
|
{
|
||||||
|
// TODO: Remove this
|
||||||
|
if (getenv("FL_DYNAMIC_COLOR") && dynamic_color_ == FL_DYNAMIC_COLOR_OFF)
|
||||||
|
dynamic_color_ = FL_DYNAMIC_COLOR_AUTO;
|
||||||
|
|
||||||
|
if (dynamic_color_ == FL_DYNAMIC_COLOR_AUTO)
|
||||||
|
return Fl::system_driver()->dynamic_color();
|
||||||
|
else
|
||||||
|
return dynamic_color_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//// Simple implementation of 2.0 Fl::scheme() interface...
|
//// Simple implementation of 2.0 Fl::scheme() interface...
|
||||||
#define D1 BORDER_WIDTH
|
#define D1 BORDER_WIDTH
|
||||||
|
@ -201,7 +201,11 @@ static void set_selection_color(uchar r, uchar g, uchar b)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MacOS X currently supports two color schemes - Blue and Graphite.
|
// macOS supports two basic color schemes - Light and Dark - with accent and
|
||||||
|
// highlight colors. Older versions limited the accent colors to Blue and
|
||||||
|
// Graphite but now you can pick from a rainbow of colors plus the old Graphite
|
||||||
|
// gray.
|
||||||
|
//
|
||||||
// Since we aren't emulating the Aqua interface (even if Apple would
|
// Since we aren't emulating the Aqua interface (even if Apple would
|
||||||
// let us), we use some defaults that are similar to both. The
|
// let us), we use some defaults that are similar to both. The
|
||||||
// Fl::scheme("plastic") color/box scheme provides a usable Aqua-like
|
// Fl::scheme("plastic") color/box scheme provides a usable Aqua-like
|
||||||
@ -212,13 +216,30 @@ void Fl_Cocoa_Screen_Driver::get_system_colors()
|
|||||||
|
|
||||||
Fl_Screen_Driver::get_system_colors();
|
Fl_Screen_Driver::get_system_colors();
|
||||||
|
|
||||||
if (!bg2_set) Fl::background2(0xff, 0xff, 0xff);
|
Fl_Dynamic_Color mode = Fl::dynamic_color();
|
||||||
if (!fg_set) Fl::foreground(0, 0, 0);
|
|
||||||
if (!bg_set) Fl::background(0xd8, 0xd8, 0xd8);
|
if (!bg2_set || mode != FL_DYNAMIC_COLOR_OFF) {
|
||||||
|
if (mode == FL_DYNAMIC_COLOR_DARK)
|
||||||
|
Fl::background2(23, 23, 23);
|
||||||
|
else
|
||||||
|
Fl::background2(0xff, 0xff, 0xff);
|
||||||
|
}
|
||||||
|
if (!fg_set || mode != FL_DYNAMIC_COLOR_OFF) {
|
||||||
|
if (mode == FL_DYNAMIC_COLOR_DARK)
|
||||||
|
Fl::foreground(223, 223, 223);
|
||||||
|
else
|
||||||
|
Fl::foreground(0, 0, 0);
|
||||||
|
}
|
||||||
|
if (!bg_set || mode != FL_DYNAMIC_COLOR_OFF) {
|
||||||
|
if (mode == FL_DYNAMIC_COLOR_DARK)
|
||||||
|
Fl::background(50, 50, 50);
|
||||||
|
else
|
||||||
|
Fl::background(0xd8, 0xd8, 0xd8);
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// this would be the correct code, but it does not run on all versions
|
// this would be the correct code, but it does not run on all versions
|
||||||
// of OS X. Also, setting a bright selection color would require
|
// of macOS. Also, setting a bright selection color would require
|
||||||
// some updates in Fl_Adjuster and Fl_Help_Browser
|
// some updates in Fl_Adjuster and Fl_Help_Browser
|
||||||
OSStatus err;
|
OSStatus err;
|
||||||
RGBColor c;
|
RGBColor c;
|
||||||
@ -229,6 +250,7 @@ void Fl_Cocoa_Screen_Driver::get_system_colors()
|
|||||||
set_selection_color(c.red, c.green, c.blue);
|
set_selection_color(c.red, c.green, c.blue);
|
||||||
#else
|
#else
|
||||||
set_selection_color(0x00, 0x00, 0x80);
|
set_selection_color(0x00, 0x00, 0x80);
|
||||||
|
//set_selection_color(0, 87, 207);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +40,8 @@
|
|||||||
|
|
||||||
class Fl_Darwin_System_Driver : public Fl_Posix_System_Driver
|
class Fl_Darwin_System_Driver : public Fl_Posix_System_Driver
|
||||||
{
|
{
|
||||||
|
Fl_Dynamic_Color dynamic_color_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Fl_Darwin_System_Driver();
|
Fl_Darwin_System_Driver();
|
||||||
int single_arg(const char *arg) FL_OVERRIDE;
|
int single_arg(const char *arg) FL_OVERRIDE;
|
||||||
@ -82,6 +84,8 @@ public:
|
|||||||
Fl_Sys_Menu_Bar_Driver *sys_menu_bar_driver() FL_OVERRIDE;
|
Fl_Sys_Menu_Bar_Driver *sys_menu_bar_driver() FL_OVERRIDE;
|
||||||
double wait(double time_to_wait) FL_OVERRIDE;
|
double wait(double time_to_wait) FL_OVERRIDE;
|
||||||
int ready() FL_OVERRIDE;
|
int ready() FL_OVERRIDE;
|
||||||
|
Fl_Dynamic_Color dynamic_color() FL_OVERRIDE;
|
||||||
|
void dynamic_color(Fl_Dynamic_Color mode) { dynamic_color_ = mode; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FL_DARWIN_SYSTEM_DRIVER_H
|
#endif // FL_DARWIN_SYSTEM_DRIVER_H
|
||||||
|
@ -51,8 +51,9 @@ const char *Fl_Darwin_System_Driver::control_name() {
|
|||||||
|
|
||||||
Fl_Darwin_System_Driver::Fl_Darwin_System_Driver() : Fl_Posix_System_Driver() {
|
Fl_Darwin_System_Driver::Fl_Darwin_System_Driver() : Fl_Posix_System_Driver() {
|
||||||
if (fl_mac_os_version == 0) fl_mac_os_version = calc_mac_os_version();
|
if (fl_mac_os_version == 0) fl_mac_os_version = calc_mac_os_version();
|
||||||
command_key = FL_META;
|
command_key = FL_META;
|
||||||
control_key = FL_CTRL;
|
control_key = FL_CTRL;
|
||||||
|
dynamic_color_ = FL_DYNAMIC_COLOR_LIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Fl_Darwin_System_Driver::single_arg(const char *arg) {
|
int Fl_Darwin_System_Driver::single_arg(const char *arg) {
|
||||||
@ -404,3 +405,7 @@ Fl_Pixmap *Fl_Darwin_System_Driver::tree_closepixmap() {
|
|||||||
int Fl_Darwin_System_Driver::tree_connector_style() {
|
int Fl_Darwin_System_Driver::tree_connector_style() {
|
||||||
return FL_TREE_CONNECTOR_NONE;
|
return FL_TREE_CONNECTOR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Fl_Dynamic_Color Fl_Darwin_System_Driver::dynamic_color() {
|
||||||
|
return dynamic_color_;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user