Skip to content

Commit

Permalink
Apply custom theme to FLTK
Browse files Browse the repository at this point in the history
Try to match GNOME's default theme a bit better.
  • Loading branch information
CendioOssman committed Jun 17, 2022
1 parent dcfc94a commit 33fd25a
Show file tree
Hide file tree
Showing 4 changed files with 253 additions and 32 deletions.
1 change: 1 addition & 0 deletions vncviewer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ add_executable(vncviewer
parameters.cxx
keysym2ucs.c
touch.cxx
theme.cxx
MonitorArrangement.cxx
MonitorIndicesParameter.cxx
Notebook.cxx
Expand Down
205 changes: 205 additions & 0 deletions vncviewer/theme.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
/* Copyright 2022 Pierre Ossman for Cendio AB
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <FL/Fl.H>
#include <FL/Fl_Widget.H>
#include <FL/fl_ask.H>
#include <FL/fl_draw.H>

#include "theme.h"

// FIXME: Antialiased pie/arc

// 4px on Windows, 5px in GNOME
const int RADIUS = 5;

static Fl_Color border_color(Fl_Color c)
{
return fl_color_average(FL_BLACK, c, 0.17);
}

static void theme_up_frame(int x, int y, int w, int h, Fl_Color c)
{
Fl::set_box_color(c);
fl_arc(x, y, RADIUS*2, RADIUS*2, 90.0, 180.0);
fl_xyline(x+RADIUS, y, x+w-RADIUS-1);
fl_arc(x+w-(RADIUS*2), y, RADIUS*2, RADIUS*2, 0, 90.0);
fl_yxline(x, y+RADIUS, y+h-RADIUS-1);
fl_yxline(x+w-1, y+RADIUS, y+h-RADIUS-1);
fl_arc(x, y+h-(RADIUS*2), RADIUS*2, RADIUS*2, 180, 270.0);
fl_xyline(x+RADIUS, y+h-1, x+w-RADIUS-1);
fl_arc(x+w-(RADIUS*2), y+h-(RADIUS*2), RADIUS*2, RADIUS*2, 270, 360.0);
}

static void theme_down_frame(int x, int y, int w, int h, Fl_Color c)
{
theme_up_frame(x, y, w, h, c);
}

static void theme_thin_up_frame(int x, int y, int w, int h, Fl_Color c)
{
theme_up_frame(x, y, w, h, c);
}

static void theme_thin_down_frame(int x, int y, int w, int h, Fl_Color c)
{
theme_down_frame(x, y, w, h, c);
}

static void theme_up_box(int x, int y, int w, int h, Fl_Color c)
{
int steps;

Fl::set_box_color(c);

fl_pie(x, y, RADIUS*2, RADIUS*2, 90.0, 180.0);
fl_rectf(x+RADIUS, y, w-(RADIUS*2), RADIUS);
fl_pie(x+w-(RADIUS*2), y, RADIUS*2, RADIUS*2, 0, 90.0);

steps = h - RADIUS*2;
for (int i = 0; i < steps; i++) {
Fl::set_box_color(fl_color_average(FL_BLACK, c, 0.04*i/steps));
fl_xyline(x, y+RADIUS+i, x+w-1);
}

Fl::set_box_color(fl_color_average(FL_BLACK, c, 0.04));

fl_pie(x, y+h-(RADIUS*2), RADIUS*2, RADIUS*2, 180, 270.0);
fl_rectf(x+RADIUS, y+h-RADIUS, w-(RADIUS*2), RADIUS);
fl_pie(x+w-(RADIUS*2), y+h-(RADIUS*2), RADIUS*2, RADIUS*2, 270, 360.0);

theme_up_frame(x, y, w, h, border_color(c));
}

static void theme_down_box(int x, int y, int w, int h, Fl_Color c)
{
Fl::set_box_color(c);
fl_pie(x, y, RADIUS*2, RADIUS*2, 90.0, 180.0);
fl_rectf(x+RADIUS, y, w-(RADIUS*2), RADIUS);
fl_pie(x+w-(RADIUS*2), y, RADIUS*2, RADIUS*2, 0, 90.0);
fl_rectf(x, y+RADIUS, w, h-RADIUS*2);
fl_pie(x, y+h-(RADIUS*2), RADIUS*2, RADIUS*2, 180, 270.0);
fl_rectf(x+RADIUS, y+h-RADIUS, w-(RADIUS*2), RADIUS);
fl_pie(x+w-(RADIUS*2), y+h-(RADIUS*2), RADIUS*2, RADIUS*2, 270, 360.0);

theme_down_frame(x, y, w, h, border_color(c));
}

static void theme_thin_up_box(int x, int y, int w, int h, Fl_Color c)
{
Fl::set_box_color(c);
fl_pie(x, y, RADIUS*2, RADIUS*2, 90.0, 180.0);
fl_rectf(x+RADIUS, y, w-(RADIUS*2), RADIUS);
fl_pie(x+w-(RADIUS*2), y, RADIUS*2, RADIUS*2, 0, 90.0);
fl_rectf(x, y+RADIUS, w, h-(RADIUS*2));
fl_pie(x, y+h-(RADIUS*2), RADIUS*2, RADIUS*2, 180, 270.0);
fl_rectf(x+RADIUS, y+h-RADIUS, w-(RADIUS*2), RADIUS);
fl_pie(x+w-(RADIUS*2), y+h-(RADIUS*2), RADIUS*2, RADIUS*2, 270, 360.0);
}

static void theme_thin_down_box(int x, int y, int w, int h, Fl_Color c)
{
theme_thin_up_box(x, y, w, h, c);
}

static void theme_round_up_box(int x, int y, int w, int h, Fl_Color c)
{
Fl::set_box_color(c);
fl_pie(x, y, w, h, 0.0, 360.0);

Fl::set_box_color(border_color(c));
fl_arc(x, y, w, h, 0.0, 360.0);
}

static void theme_round_down_box(int x, int y, int w, int h, Fl_Color c)
{
theme_round_up_box(x, y, w, h, c);
}

void init_theme()
{
// Basic text size (11pt @ 96 dpi => 14.666...px)
// FIXME: This is rounded down since there are some issues scaling
// fonts up in FLTK:
// https://github.com/fltk/fltk/issues/371
// FIXME: macOS/Windows
FL_NORMAL_SIZE = 14;

// FIXME: Base theme
Fl::scheme("gtk+");

// Define our box types
Fl::set_boxtype(THEME_UP_FRAME, theme_up_frame, 3, 3, 6, 6);
Fl::set_boxtype(THEME_DOWN_FRAME, theme_down_frame, 3, 3, 6, 6);
Fl::set_boxtype(THEME_THIN_UP_FRAME, theme_thin_up_frame, 3, 3, 6, 6);
Fl::set_boxtype(THEME_THIN_DOWN_FRAME, theme_thin_down_frame, 3, 3, 6, 6);

Fl::set_boxtype(THEME_UP_BOX, theme_up_box, 3, 3, 6, 6);
Fl::set_boxtype(THEME_DOWN_BOX, theme_down_box, 3, 3, 6, 6);
Fl::set_boxtype(THEME_THIN_UP_BOX, theme_thin_up_box, 3, 3, 6, 6);
Fl::set_boxtype(THEME_THIN_DOWN_BOX, theme_thin_down_box, 3, 3, 6, 6);
Fl::set_boxtype(THEME_ROUND_UP_BOX, theme_round_up_box, 3, 3, 6, 6);
Fl::set_boxtype(THEME_ROUND_DOWN_BOX, theme_round_down_box, 3, 3, 6, 6);

// Make them the default
Fl::set_boxtype(FL_UP_FRAME, THEME_UP_FRAME);
Fl::set_boxtype(FL_DOWN_FRAME, THEME_UP_FRAME);
Fl::set_boxtype(FL_THIN_UP_FRAME, THEME_THIN_UP_FRAME);
Fl::set_boxtype(FL_THIN_DOWN_FRAME, THEME_THIN_DOWN_FRAME);

Fl::set_boxtype(FL_UP_BOX, THEME_UP_BOX);
Fl::set_boxtype(FL_DOWN_BOX, THEME_DOWN_BOX);
Fl::set_boxtype(FL_THIN_UP_BOX, THEME_THIN_UP_BOX);
Fl::set_boxtype(FL_THIN_DOWN_BOX, THEME_THIN_DOWN_BOX);
Fl::set_boxtype(_FL_ROUND_UP_BOX, THEME_ROUND_UP_BOX);
Fl::set_boxtype(_FL_ROUND_DOWN_BOX, THEME_ROUND_DOWN_BOX);

// FIXME: Should get these from the system,
// Fl::get_system_colors() is unfortunately not very capable
// FIXME: Should also handle dark mode
// FIXME: fl_contrast() also sucks since its calculations are utterly
// wrong as they fail to account for sRGB curves. And even with
// that fixed we get odd results with dark backgrounds, so
// APCA should probably be used.
// https://github.com/fltk/fltk/issues/370
Fl::foreground(46, 52, 54);
Fl::background(246, 245, 244);
// GNOME uses (53,132,228), macOS (0, 122, 255), this is the lightest
// version of GNOME's that fl_contrast() won't screw up
Fl::set_color(FL_SELECTION_COLOR, 29, 113, 215);

// This makes the "icon" in dialogs rounded, which fits better
// with the above schemes.
fl_message_icon()->box(FL_UP_BOX);

#ifdef WIN32
// Most "normal" Windows apps use this font for UI elements.
// FIXME: Segoi UI
Fl::set_font(FL_HELVETICA, "Tahoma");
#endif
// FIXME: macOS / Linux
}
45 changes: 45 additions & 0 deletions vncviewer/theme.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/* Copyright 2022 Pierre Ossman for Cendio AB
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#ifndef __THEME_H__
#define __THEME_H__

#include <FL/Enumerations.H>

#define _THEME_BOX_BASE (FL_FREE_BOXTYPE+1000)

#define THEME_UP_FRAME (Fl_Boxtype)(_THEME_BOX_BASE+0)
#define THEME_DOWN_FRAME (Fl_Boxtype)(_THEME_BOX_BASE+1)
#define THEME_THIN_UP_FRAME (Fl_Boxtype)(_THEME_BOX_BASE+2)
#define THEME_THIN_DOWN_FRAME (Fl_Boxtype)(_THEME_BOX_BASE+3)

#define THEME_UP_BOX (Fl_Boxtype)(_THEME_BOX_BASE+4)
#define THEME_DOWN_BOX (Fl_Boxtype)(_THEME_BOX_BASE+5)
#define THEME_THIN_UP_BOX (Fl_Boxtype)(_THEME_BOX_BASE+6)
#define THEME_THIN_DOWN_BOX (Fl_Boxtype)(_THEME_BOX_BASE+7)
#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();

#endif
34 changes: 2 additions & 32 deletions vncviewer/vncviewer.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
#include "ServerDialog.h"
#include "UserDialog.h"
#include "touch.h"
#include "theme.h"
#include "vncviewer.h"
#include "fltk_layout.h"

Expand Down Expand Up @@ -324,29 +325,7 @@ static const char* getlocaledir()

static void init_fltk()
{
// Basic text size (11pt @ 96 dpi => 14.666...px)
// FIXME: This is rounded down since there are some issues scaling
// fonts up in FLTK:
// https://github.com/fltk/fltk/issues/371
FL_NORMAL_SIZE = 14;

// Select a FLTK scheme and background color that looks somewhat
// close to modern systems
Fl::scheme("gtk+");

// FIXME: Should get these from the system,
// Fl::get_system_colors() is unfortunately not very capable
// FIXME: Should also handle dark mode
// FIXME: fl_contrast() also sucks since its calculations are utterly
// wrong as they fail to account for sRGB curves. And even with
// that fixed we get odd results with dark backgrounds, so
// APCA should probably be used.
// https://github.com/fltk/fltk/issues/370
Fl::foreground(46, 52, 54);
Fl::background(246, 245, 244);
// GNOME uses (53,132,228), macOS (0, 122, 255), this is the lightest
// version of GNOME's that fl_contrast() won't screw up
Fl::set_color(FL_SELECTION_COLOR, 29, 113, 215);
init_theme();

// Proper Gnome Shell integration requires that we set a sensible
// WM_CLASS for the window.
Expand Down Expand Up @@ -407,21 +386,12 @@ static void init_fltk()
delete icons[i];
#endif

// This makes the "icon" in dialogs rounded, which fits better
// with the above schemes.
fl_message_icon()->box(FL_UP_BOX);

// Turn off the annoying behaviour where popups track the mouse.
fl_message_hotspot(false);

// Avoid empty titles for popups
fl_message_title_default(_("TigerVNC Viewer"));

#ifdef WIN32
// Most "normal" Windows apps use this font for UI elements.
Fl::set_font(FL_HELVETICA, "Tahoma");
#endif

// FLTK exposes these so that we can translate them.
fl_no = _("No");
fl_yes = _("Yes");
Expand Down

0 comments on commit 33fd25a

Please sign in to comment.