Skip to content

Commit 33fd25a

Browse files
committed
Apply custom theme to FLTK
Try to match GNOME's default theme a bit better.
1 parent dcfc94a commit 33fd25a

File tree

4 files changed

+253
-32
lines changed

4 files changed

+253
-32
lines changed

vncviewer/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ add_executable(vncviewer
1818
parameters.cxx
1919
keysym2ucs.c
2020
touch.cxx
21+
theme.cxx
2122
MonitorArrangement.cxx
2223
MonitorIndicesParameter.cxx
2324
Notebook.cxx

vncviewer/theme.cxx

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/* Copyright 2022 Pierre Ossman for Cendio AB
2+
*
3+
* Permission is hereby granted, free of charge, to any person obtaining
4+
* a copy of this software and associated documentation files (the
5+
* "Software"), to deal in the Software without restriction, including
6+
* without limitation the rights to use, copy, modify, merge, publish,
7+
* distribute, sublicense, and/or sell copies of the Software, and to
8+
* permit persons to whom the Software is furnished to do so, subject to
9+
* the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be
12+
* included in all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
18+
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19+
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
* SOFTWARE.
22+
*/
23+
24+
#ifdef HAVE_CONFIG_H
25+
#include <config.h>
26+
#endif
27+
28+
#include <FL/Fl.H>
29+
#include <FL/Fl_Widget.H>
30+
#include <FL/fl_ask.H>
31+
#include <FL/fl_draw.H>
32+
33+
#include "theme.h"
34+
35+
// FIXME: Antialiased pie/arc
36+
37+
// 4px on Windows, 5px in GNOME
38+
const int RADIUS = 5;
39+
40+
static Fl_Color border_color(Fl_Color c)
41+
{
42+
return fl_color_average(FL_BLACK, c, 0.17);
43+
}
44+
45+
static void theme_up_frame(int x, int y, int w, int h, Fl_Color c)
46+
{
47+
Fl::set_box_color(c);
48+
fl_arc(x, y, RADIUS*2, RADIUS*2, 90.0, 180.0);
49+
fl_xyline(x+RADIUS, y, x+w-RADIUS-1);
50+
fl_arc(x+w-(RADIUS*2), y, RADIUS*2, RADIUS*2, 0, 90.0);
51+
fl_yxline(x, y+RADIUS, y+h-RADIUS-1);
52+
fl_yxline(x+w-1, y+RADIUS, y+h-RADIUS-1);
53+
fl_arc(x, y+h-(RADIUS*2), RADIUS*2, RADIUS*2, 180, 270.0);
54+
fl_xyline(x+RADIUS, y+h-1, x+w-RADIUS-1);
55+
fl_arc(x+w-(RADIUS*2), y+h-(RADIUS*2), RADIUS*2, RADIUS*2, 270, 360.0);
56+
}
57+
58+
static void theme_down_frame(int x, int y, int w, int h, Fl_Color c)
59+
{
60+
theme_up_frame(x, y, w, h, c);
61+
}
62+
63+
static void theme_thin_up_frame(int x, int y, int w, int h, Fl_Color c)
64+
{
65+
theme_up_frame(x, y, w, h, c);
66+
}
67+
68+
static void theme_thin_down_frame(int x, int y, int w, int h, Fl_Color c)
69+
{
70+
theme_down_frame(x, y, w, h, c);
71+
}
72+
73+
static void theme_up_box(int x, int y, int w, int h, Fl_Color c)
74+
{
75+
int steps;
76+
77+
Fl::set_box_color(c);
78+
79+
fl_pie(x, y, RADIUS*2, RADIUS*2, 90.0, 180.0);
80+
fl_rectf(x+RADIUS, y, w-(RADIUS*2), RADIUS);
81+
fl_pie(x+w-(RADIUS*2), y, RADIUS*2, RADIUS*2, 0, 90.0);
82+
83+
steps = h - RADIUS*2;
84+
for (int i = 0; i < steps; i++) {
85+
Fl::set_box_color(fl_color_average(FL_BLACK, c, 0.04*i/steps));
86+
fl_xyline(x, y+RADIUS+i, x+w-1);
87+
}
88+
89+
Fl::set_box_color(fl_color_average(FL_BLACK, c, 0.04));
90+
91+
fl_pie(x, y+h-(RADIUS*2), RADIUS*2, RADIUS*2, 180, 270.0);
92+
fl_rectf(x+RADIUS, y+h-RADIUS, w-(RADIUS*2), RADIUS);
93+
fl_pie(x+w-(RADIUS*2), y+h-(RADIUS*2), RADIUS*2, RADIUS*2, 270, 360.0);
94+
95+
theme_up_frame(x, y, w, h, border_color(c));
96+
}
97+
98+
static void theme_down_box(int x, int y, int w, int h, Fl_Color c)
99+
{
100+
Fl::set_box_color(c);
101+
fl_pie(x, y, RADIUS*2, RADIUS*2, 90.0, 180.0);
102+
fl_rectf(x+RADIUS, y, w-(RADIUS*2), RADIUS);
103+
fl_pie(x+w-(RADIUS*2), y, RADIUS*2, RADIUS*2, 0, 90.0);
104+
fl_rectf(x, y+RADIUS, w, h-RADIUS*2);
105+
fl_pie(x, y+h-(RADIUS*2), RADIUS*2, RADIUS*2, 180, 270.0);
106+
fl_rectf(x+RADIUS, y+h-RADIUS, w-(RADIUS*2), RADIUS);
107+
fl_pie(x+w-(RADIUS*2), y+h-(RADIUS*2), RADIUS*2, RADIUS*2, 270, 360.0);
108+
109+
theme_down_frame(x, y, w, h, border_color(c));
110+
}
111+
112+
static void theme_thin_up_box(int x, int y, int w, int h, Fl_Color c)
113+
{
114+
Fl::set_box_color(c);
115+
fl_pie(x, y, RADIUS*2, RADIUS*2, 90.0, 180.0);
116+
fl_rectf(x+RADIUS, y, w-(RADIUS*2), RADIUS);
117+
fl_pie(x+w-(RADIUS*2), y, RADIUS*2, RADIUS*2, 0, 90.0);
118+
fl_rectf(x, y+RADIUS, w, h-(RADIUS*2));
119+
fl_pie(x, y+h-(RADIUS*2), RADIUS*2, RADIUS*2, 180, 270.0);
120+
fl_rectf(x+RADIUS, y+h-RADIUS, w-(RADIUS*2), RADIUS);
121+
fl_pie(x+w-(RADIUS*2), y+h-(RADIUS*2), RADIUS*2, RADIUS*2, 270, 360.0);
122+
}
123+
124+
static void theme_thin_down_box(int x, int y, int w, int h, Fl_Color c)
125+
{
126+
theme_thin_up_box(x, y, w, h, c);
127+
}
128+
129+
static void theme_round_up_box(int x, int y, int w, int h, Fl_Color c)
130+
{
131+
Fl::set_box_color(c);
132+
fl_pie(x, y, w, h, 0.0, 360.0);
133+
134+
Fl::set_box_color(border_color(c));
135+
fl_arc(x, y, w, h, 0.0, 360.0);
136+
}
137+
138+
static void theme_round_down_box(int x, int y, int w, int h, Fl_Color c)
139+
{
140+
theme_round_up_box(x, y, w, h, c);
141+
}
142+
143+
void init_theme()
144+
{
145+
// Basic text size (11pt @ 96 dpi => 14.666...px)
146+
// FIXME: This is rounded down since there are some issues scaling
147+
// fonts up in FLTK:
148+
// https://github.com/fltk/fltk/issues/371
149+
// FIXME: macOS/Windows
150+
FL_NORMAL_SIZE = 14;
151+
152+
// FIXME: Base theme
153+
Fl::scheme("gtk+");
154+
155+
// Define our box types
156+
Fl::set_boxtype(THEME_UP_FRAME, theme_up_frame, 3, 3, 6, 6);
157+
Fl::set_boxtype(THEME_DOWN_FRAME, theme_down_frame, 3, 3, 6, 6);
158+
Fl::set_boxtype(THEME_THIN_UP_FRAME, theme_thin_up_frame, 3, 3, 6, 6);
159+
Fl::set_boxtype(THEME_THIN_DOWN_FRAME, theme_thin_down_frame, 3, 3, 6, 6);
160+
161+
Fl::set_boxtype(THEME_UP_BOX, theme_up_box, 3, 3, 6, 6);
162+
Fl::set_boxtype(THEME_DOWN_BOX, theme_down_box, 3, 3, 6, 6);
163+
Fl::set_boxtype(THEME_THIN_UP_BOX, theme_thin_up_box, 3, 3, 6, 6);
164+
Fl::set_boxtype(THEME_THIN_DOWN_BOX, theme_thin_down_box, 3, 3, 6, 6);
165+
Fl::set_boxtype(THEME_ROUND_UP_BOX, theme_round_up_box, 3, 3, 6, 6);
166+
Fl::set_boxtype(THEME_ROUND_DOWN_BOX, theme_round_down_box, 3, 3, 6, 6);
167+
168+
// Make them the default
169+
Fl::set_boxtype(FL_UP_FRAME, THEME_UP_FRAME);
170+
Fl::set_boxtype(FL_DOWN_FRAME, THEME_UP_FRAME);
171+
Fl::set_boxtype(FL_THIN_UP_FRAME, THEME_THIN_UP_FRAME);
172+
Fl::set_boxtype(FL_THIN_DOWN_FRAME, THEME_THIN_DOWN_FRAME);
173+
174+
Fl::set_boxtype(FL_UP_BOX, THEME_UP_BOX);
175+
Fl::set_boxtype(FL_DOWN_BOX, THEME_DOWN_BOX);
176+
Fl::set_boxtype(FL_THIN_UP_BOX, THEME_THIN_UP_BOX);
177+
Fl::set_boxtype(FL_THIN_DOWN_BOX, THEME_THIN_DOWN_BOX);
178+
Fl::set_boxtype(_FL_ROUND_UP_BOX, THEME_ROUND_UP_BOX);
179+
Fl::set_boxtype(_FL_ROUND_DOWN_BOX, THEME_ROUND_DOWN_BOX);
180+
181+
// FIXME: Should get these from the system,
182+
// Fl::get_system_colors() is unfortunately not very capable
183+
// FIXME: Should also handle dark mode
184+
// FIXME: fl_contrast() also sucks since its calculations are utterly
185+
// wrong as they fail to account for sRGB curves. And even with
186+
// that fixed we get odd results with dark backgrounds, so
187+
// APCA should probably be used.
188+
// https://github.com/fltk/fltk/issues/370
189+
Fl::foreground(46, 52, 54);
190+
Fl::background(246, 245, 244);
191+
// GNOME uses (53,132,228), macOS (0, 122, 255), this is the lightest
192+
// version of GNOME's that fl_contrast() won't screw up
193+
Fl::set_color(FL_SELECTION_COLOR, 29, 113, 215);
194+
195+
// This makes the "icon" in dialogs rounded, which fits better
196+
// with the above schemes.
197+
fl_message_icon()->box(FL_UP_BOX);
198+
199+
#ifdef WIN32
200+
// Most "normal" Windows apps use this font for UI elements.
201+
// FIXME: Segoi UI
202+
Fl::set_font(FL_HELVETICA, "Tahoma");
203+
#endif
204+
// FIXME: macOS / Linux
205+
}

vncviewer/theme.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/* Copyright 2022 Pierre Ossman for Cendio AB
2+
*
3+
* Permission is hereby granted, free of charge, to any person obtaining
4+
* a copy of this software and associated documentation files (the
5+
* "Software"), to deal in the Software without restriction, including
6+
* without limitation the rights to use, copy, modify, merge, publish,
7+
* distribute, sublicense, and/or sell copies of the Software, and to
8+
* permit persons to whom the Software is furnished to do so, subject to
9+
* the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be
12+
* included in all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
18+
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19+
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
* SOFTWARE.
22+
*/
23+
24+
#ifndef __THEME_H__
25+
#define __THEME_H__
26+
27+
#include <FL/Enumerations.H>
28+
29+
#define _THEME_BOX_BASE (FL_FREE_BOXTYPE+1000)
30+
31+
#define THEME_UP_FRAME (Fl_Boxtype)(_THEME_BOX_BASE+0)
32+
#define THEME_DOWN_FRAME (Fl_Boxtype)(_THEME_BOX_BASE+1)
33+
#define THEME_THIN_UP_FRAME (Fl_Boxtype)(_THEME_BOX_BASE+2)
34+
#define THEME_THIN_DOWN_FRAME (Fl_Boxtype)(_THEME_BOX_BASE+3)
35+
36+
#define THEME_UP_BOX (Fl_Boxtype)(_THEME_BOX_BASE+4)
37+
#define THEME_DOWN_BOX (Fl_Boxtype)(_THEME_BOX_BASE+5)
38+
#define THEME_THIN_UP_BOX (Fl_Boxtype)(_THEME_BOX_BASE+6)
39+
#define THEME_THIN_DOWN_BOX (Fl_Boxtype)(_THEME_BOX_BASE+7)
40+
#define THEME_ROUND_UP_BOX (Fl_Boxtype)(_THEME_BOX_BASE+8)
41+
#define THEME_ROUND_DOWN_BOX (Fl_Boxtype)(_THEME_BOX_BASE+9)
42+
43+
void init_theme();
44+
45+
#endif

vncviewer/vncviewer.cxx

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
#include "ServerDialog.h"
7474
#include "UserDialog.h"
7575
#include "touch.h"
76+
#include "theme.h"
7677
#include "vncviewer.h"
7778
#include "fltk_layout.h"
7879

@@ -324,29 +325,7 @@ static const char* getlocaledir()
324325

325326
static void init_fltk()
326327
{
327-
// Basic text size (11pt @ 96 dpi => 14.666...px)
328-
// FIXME: This is rounded down since there are some issues scaling
329-
// fonts up in FLTK:
330-
// https://github.com/fltk/fltk/issues/371
331-
FL_NORMAL_SIZE = 14;
332-
333-
// Select a FLTK scheme and background color that looks somewhat
334-
// close to modern systems
335-
Fl::scheme("gtk+");
336-
337-
// FIXME: Should get these from the system,
338-
// Fl::get_system_colors() is unfortunately not very capable
339-
// FIXME: Should also handle dark mode
340-
// FIXME: fl_contrast() also sucks since its calculations are utterly
341-
// wrong as they fail to account for sRGB curves. And even with
342-
// that fixed we get odd results with dark backgrounds, so
343-
// APCA should probably be used.
344-
// https://github.com/fltk/fltk/issues/370
345-
Fl::foreground(46, 52, 54);
346-
Fl::background(246, 245, 244);
347-
// GNOME uses (53,132,228), macOS (0, 122, 255), this is the lightest
348-
// version of GNOME's that fl_contrast() won't screw up
349-
Fl::set_color(FL_SELECTION_COLOR, 29, 113, 215);
328+
init_theme();
350329

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

410-
// This makes the "icon" in dialogs rounded, which fits better
411-
// with the above schemes.
412-
fl_message_icon()->box(FL_UP_BOX);
413-
414389
// Turn off the annoying behaviour where popups track the mouse.
415390
fl_message_hotspot(false);
416391

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

420-
#ifdef WIN32
421-
// Most "normal" Windows apps use this font for UI elements.
422-
Fl::set_font(FL_HELVETICA, "Tahoma");
423-
#endif
424-
425395
// FLTK exposes these so that we can translate them.
426396
fl_no = _("No");
427397
fl_yes = _("Yes");

0 commit comments

Comments
 (0)