Skip to content

Commit

Permalink
Implement dark mode
Browse files Browse the repository at this point in the history
Add parameter for selecting UI theme
  • Loading branch information
timothytylee committed Oct 11, 2024
1 parent dbb6ee4 commit cca3315
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 17 deletions.
91 changes: 91 additions & 0 deletions vncviewer/OptionsDialog.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "parameters.h"

#include "fltk/layout.h"
#include "fltk/theme.h"
#include "fltk/util.h"
#include "fltk/Fl_Monitor_Arrangement.h"
#include "fltk/Fl_Navigation.h"
Expand Down Expand Up @@ -353,6 +354,15 @@ void OptionsDialog::loadOptions(void)
sharedCheckbox->value(shared);
reconnectCheckbox->value(reconnectOnError);
dotCursorCheckbox->value(dotWhenNoCursor);

/* Theme */
if (!strcasecmp(theme, "light")) {
lightThemeButton->setonly();
} else if (!strcasecmp(theme, "dark")) {
darkThemeButton->setonly();
} else {
autoThemeButton->setonly();
}
}


Expand Down Expand Up @@ -488,6 +498,15 @@ void OptionsDialog::storeOptions(void)
reconnectOnError.setParam(reconnectCheckbox->value());
dotWhenNoCursor.setParam(dotCursorCheckbox->value());

/* Theme */
if (lightThemeButton->value()) {
theme.setParam("Light");
} else if (darkThemeButton->value()) {
theme.setParam("Dark");
} else {
theme.setParam("Auto");
}

std::map<OptionsCallback*, void*>::const_iterator iter;

for (iter = callbacks.begin();iter != callbacks.end();++iter)
Expand Down Expand Up @@ -1028,9 +1047,16 @@ void OptionsDialog::createMiscPage(int tx, int ty, int tw, int th)
{
Fl_Group *group = new Fl_Group(tx, ty, tw, th, _("Miscellaneous"));

int orig_tx;
int width;

tx += OUTER_MARGIN;
ty += OUTER_MARGIN;

width = tw - OUTER_MARGIN * 2;

orig_tx = tx;

sharedCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
CHECK_MIN_WIDTH,
CHECK_HEIGHT,
Expand All @@ -1043,6 +1069,53 @@ void OptionsDialog::createMiscPage(int tx, int ty, int tw, int th)
_("Ask to reconnect on connection errors")));
ty += CHECK_HEIGHT + TIGHT_MARGIN;

/* Theme */
ty += GROUP_LABEL_OFFSET;
themeGroup = new Fl_Group(tx, ty, width, 0, _("Theme"));
themeGroup->labelfont(FL_BOLD);
themeGroup->box(FL_FLAT_BOX);
themeGroup->align(FL_ALIGN_LEFT | FL_ALIGN_TOP);

{
tx += INDENT;
ty += TIGHT_MARGIN;
width -= INDENT;

lightThemeButton = new Fl_Round_Button(LBLRIGHT(tx, ty,
RADIO_MIN_WIDTH,
RADIO_HEIGHT,
_("Light")));
lightThemeButton->type(FL_RADIO_BUTTON);
lightThemeButton->callback(handleTheme, this);
ty += RADIO_HEIGHT + TIGHT_MARGIN;

darkThemeButton = new Fl_Round_Button(LBLRIGHT(tx, ty,
RADIO_MIN_WIDTH,
RADIO_HEIGHT,
_("Dark")));
darkThemeButton->type(FL_RADIO_BUTTON);
darkThemeButton->callback(handleTheme, this);
ty += RADIO_HEIGHT + TIGHT_MARGIN;

autoThemeButton = new Fl_Round_Button(LBLRIGHT(tx, ty,
RADIO_MIN_WIDTH,
RADIO_HEIGHT,
_("Auto")));
autoThemeButton->type(FL_RADIO_BUTTON);
autoThemeButton->callback(handleTheme, this);
ty += RADIO_HEIGHT + TIGHT_MARGIN;
}
ty -= TIGHT_MARGIN;

themeGroup->end();
/* Needed for resize to work sanely */
themeGroup->resizable(nullptr);
themeGroup->size(themeGroup->w(), ty - themeGroup->y());

/* Back to normal */
tx = orig_tx;
ty += INNER_MARGIN;

group->end();
}

Expand Down Expand Up @@ -1140,6 +1213,24 @@ void OptionsDialog::handleFullScreenMode(Fl_Widget* /*widget*/, void *data)
}
}

void OptionsDialog::handleTheme(Fl_Widget* /*widget*/, void *data)
{
OptionsDialog *dialog = (OptionsDialog*)data;

// Update FLTK theme
if (dialog->lightThemeButton->value()) {
init_theme("Light");
} else if (dialog->darkThemeButton->value()) {
init_theme("Dark");
} else {
init_theme("Auto");
}

// Redraw all windows using new theme
for (Fl_Window* wnd = Fl::first_window(); wnd; wnd = Fl::next_window(wnd))
wnd->redraw();
}

void OptionsDialog::handleCancel(Fl_Widget* /*widget*/, void *data)
{
OptionsDialog *dialog = (OptionsDialog*)data;
Expand Down
6 changes: 6 additions & 0 deletions vncviewer/OptionsDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ class OptionsDialog : public Fl_Window {

static void handleFullScreenMode(Fl_Widget *widget, void *data);

static void handleTheme(Fl_Widget *widget, void *data);

static void handleCancel(Fl_Widget *widget, void *data);
static void handleOK(Fl_Widget *widget, void *data);

Expand Down Expand Up @@ -140,6 +142,10 @@ class OptionsDialog : public Fl_Window {
/* Misc. */
Fl_Check_Button *sharedCheckbox;
Fl_Check_Button *reconnectCheckbox;
Fl_Group *themeGroup;
Fl_Round_Button *lightThemeButton;
Fl_Round_Button *darkThemeButton;
Fl_Round_Button *autoThemeButton;

private:
static int fltk_event_handler(int event);
Expand Down
87 changes: 72 additions & 15 deletions vncviewer/fltk/theme.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "theme.h"

const int RADIUS = 4;
static bool dark_mode = false;

/*
* fl_arc() and fl_pie() are broken on Windows, so we need to fudge the
Expand Down Expand Up @@ -165,8 +166,13 @@ static void theme_round_rect(int x, int y, int w, int h, int r,

static void theme_up_box(int x, int y, int w, int h, Fl_Color c)
{
theme_round_rect(x, y, w, h, RADIUS,
fl_color_average(FL_WHITE, c, 0.75));
if (dark_mode) {
theme_round_rect(x, y, w, h, RADIUS,
fl_color_average(FL_WHITE, c, 0.1));
} else {
theme_round_rect(x, y, w, h, RADIUS,
fl_color_average(FL_WHITE, c, 0.75));
}
theme_up_frame(x, y, w, h, c);
}

Expand Down Expand Up @@ -218,8 +224,22 @@ static void theme_round_down_box(int x, int y, int w, int h, Fl_Color c)
fl_arc(x, y, w, h, 180.0, 360.0);
}

void init_theme()
static void set_theme(const char* theme)
{
if (!strcasecmp(theme, "light")) {
dark_mode = false;
} else if (!strcasecmp(theme, "dark")) {
dark_mode = true;
} else {
// FIXME: Determine use of dark mode from the system
dark_mode = false;
}
}

void init_theme(const char* theme)
{
set_theme(theme);

#if defined(WIN32) || defined(__APPLE__)
static char font_name[256];
#endif
Expand All @@ -232,37 +252,74 @@ void init_theme()

// FIXME: Should get these from the system,
// Fl::get_system_colors() is unfortunately not very capable
// FIXME: Should also handle dark mode

#if defined(WIN32)
// Windows 11
Fl::foreground(26, 26, 26);
Fl::background(243, 243, 243);
if (dark_mode) {
Fl::foreground(255, 255, 255);
Fl::background(25, 25, 25);
Fl::background2(32, 32, 32);
} else {
Fl::foreground(26, 26, 26);
Fl::background(243, 243, 243);
Fl::background2(255, 255, 255);
}
#elif defined(__APPLE__)
// FIXME: Text is rendered slightly lighter than what we specify here
// for some odd reason. The target is (38, 38, 38).
Fl::foreground(28, 28, 28);
Fl::background(246, 246, 246);
if (dark_mode) {
Fl::foreground(223, 223, 223);
Fl::background(50, 50, 50);
Fl::background2(23, 23, 23);
} else {
Fl::foreground(28, 28, 28);
Fl::background(246, 246, 246);
Fl::background2(255, 255, 255);
}
#else
// GNOME
Fl::foreground(46, 52, 54);
Fl::background(246, 245, 244);
if (dark_mode) {
Fl::foreground(255, 255, 255);
Fl::background(51, 51, 51);
Fl::background2(45, 45, 45);
} else {
Fl::foreground(46, 52, 54);
Fl::background(246, 245, 244);
Fl::background2(255, 255, 255);
}
#endif

#if defined(WIN32)
// Windows 11 default accent color
Fl::set_color(FL_SELECTION_COLOR, 0, 103, 192);
if (dark_mode) {
Fl::set_color(FL_SELECTION_COLOR, 0, 160, 250);
} else {
Fl::set_color(FL_SELECTION_COLOR, 0, 103, 192);
}
#elif defined(__APPLE__)
Fl::set_color(FL_SELECTION_COLOR, 0, 122, 255);
if (dark_mode) {
Fl::set_color(FL_SELECTION_COLOR, 0, 87, 207);
} else {
Fl::set_color(FL_SELECTION_COLOR, 0, 122, 255);
}
#else
// GNOME
Fl::set_color(FL_SELECTION_COLOR, 53, 132, 228);
if (dark_mode) {
Fl::set_color(FL_SELECTION_COLOR, 21, 83, 158);
} else {
Fl::set_color(FL_SELECTION_COLOR, 53, 132, 228);
}
#endif

// The arrow on Fl_Return_Button gets a invisible, so let's adjust it
// to compensate for our lighter buttons
Fl::set_color(FL_LIGHT3, light_border(fl_color_average(FL_WHITE, FL_BACKGROUND_COLOR, 0.5)));
Fl::set_color(FL_DARK3, dark_border(fl_color_average(FL_WHITE, FL_BACKGROUND_COLOR, 0.5)));
if (dark_mode) {
Fl::set_color(FL_LIGHT3, light_border(fl_color_average(FL_WHITE, FL_BACKGROUND_COLOR, 0.75)));
Fl::set_color(FL_DARK3, dark_border(fl_color_average(FL_WHITE, FL_BACKGROUND_COLOR, 0.75)));
} else {
Fl::set_color(FL_LIGHT3, light_border(fl_color_average(FL_WHITE, FL_BACKGROUND_COLOR, 0.5)));
Fl::set_color(FL_DARK3, dark_border(fl_color_average(FL_WHITE, FL_BACKGROUND_COLOR, 0.5)));
}

// We will override the box types later, but changing scheme affects
// more things than just those, so we still want to switch from the
Expand Down
2 changes: 1 addition & 1 deletion vncviewer/fltk/theme.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,6 @@
#define THEME_ROUND_UP_BOX (Fl_Boxtype)(_THEME_BOX_BASE+8)
#define THEME_ROUND_DOWN_BOX (Fl_Boxtype)(_THEME_BOX_BASE+9)

void init_theme();
void init_theme(const char* theme);

#endif
6 changes: 6 additions & 0 deletions vncviewer/parameters.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ BoolParameter remoteResize("RemoteResize",
"the size of the local client window changes. "
"(Does not work with all servers)", true);

StringParameter theme("Theme",
"UI theme. Should be either Light, Dark "
" or Auto", "Auto");

BoolParameter viewOnly("ViewOnly",
"Don't send any mouse or keyboard events to the server",
false);
Expand Down Expand Up @@ -196,6 +200,8 @@ static VoidParameter* parameterArray[] = {
&fullScreen,
&fullScreenMode,
&fullScreenSelectedMonitors,
/* Theme */
&theme,
/* Input */
&viewOnly,
&emulateMiddleButton,
Expand Down
2 changes: 2 additions & 0 deletions vncviewer/parameters.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ extern rfb::StringParameter desktopSize;
extern rfb::StringParameter geometry;
extern rfb::BoolParameter remoteResize;

extern rfb::StringParameter theme;

extern rfb::BoolParameter listenMode;

extern rfb::BoolParameter viewOnly;
Expand Down
2 changes: 1 addition & 1 deletion vncviewer/vncviewer.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ static const char* getlocaledir()
static void init_fltk()
{
// Adjust look of FLTK
init_theme();
init_theme(theme);

// Proper Gnome Shell integration requires that we set a sensible
// WM_CLASS for the window.
Expand Down

0 comments on commit cca3315

Please sign in to comment.