Implement font-use-system-font on Haiku

* doc/emacs/frames.texi (Fonts): Update documentation to say
what font-use-system-font really does and where it can be used.
* src/haiku_font_support.cc (language_code_points): Fix coding
style.
(font_style_to_flags, be_font_style_to_flags): Accept const char
*.
(be_send_font_settings, be_listen_font_settings)
(be_lock_font_defaults, be_unlock_font_defaults)
(be_get_font_default, be_get_font_size): New functions used to
retrieve default font data.

* src/haiku_io.c (haiku_len): Handle FONT_CHANGE_EVENT.
* src/haiku_support.h (enum haiku_event_type): New event type
FONT_CHANGE_EVENT.
(enum haiku_what_font): New enum.
(struct haiku_font_change_event): New struct.

* src/haikufont.c (Ffont_get_system_normal_font)
(Ffont_get_system_font, haiku_handle_font_change_event): New
functions.
(syms_of_haikufont): Provide `dynamic-setting' and define new
variables and subrs.

* src/haikuterm.c (haiku_default_font_parameter): Use system font.
(haiku_read_socket): Handle FONT_CHANGE_EVENTS.
(haiku_term_init): Start listening for font configuration changes.
* src/haikuterm.h: Update prototypes.

* src/xsettings.c (Ffont_get_system_normal_font)
(Ffont_get_system_font): Update doc string.
(syms_of_xsettings): Replace calls to intern with a static
string.
This commit is contained in:
Po Lu 2022-09-25 13:22:45 +00:00
parent 3502fd9831
commit 568920a5b7
8 changed files with 449 additions and 30 deletions

View file

@ -652,14 +652,15 @@ resources file to take effect. @xref{Resources}. Do not quote
font names in X resource files.
@item
If you are running Emacs on the GNOME desktop, you can tell Emacs to
use the default system font by setting the variable
If you are running Emacs on the GNOME desktop or Haiku, you can tell
Emacs to adjust the frame's default font along with changes to the
default system font by setting the variable
@code{font-use-system-font} to @code{t} (the default is @code{nil}).
For this to work, Emacs must have been compiled with support for
Gsettings (or the older Gconf). (To be specific, the Gsettings
configuration names used are
@samp{org.gnome.desktop.interface monospace-font-name} and
@samp{org.gnome.desktop.interface font-name}.)
configuration names used are @samp{org.gnome.desktop.interface
monospace-font-name} and @samp{org.gnome.desktop.interface
font-name}.)
@item
Use the command line option @samp{-fn} (or @samp{--font}). @xref{Font

View file

@ -21,6 +21,14 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <Font.h>
#include <Rect.h>
#include <AffineTransform.h>
#include <FindDirectory.h>
#include <Path.h>
#include <File.h>
#include <Message.h>
#include <OS.h>
#include <Locker.h>
#include <NodeMonitor.h>
#include <Looper.h>
#include <cstring>
#include <cmath>
@ -39,15 +47,57 @@ struct font_object_cache_bucket
static struct font_object_cache_bucket *font_object_cache[2048];
/* The current global monospace family and style. */
static char *fixed_family, *fixed_style;
/* The current global variable-width family and style. */
static char *default_family, *default_style;
/* The sizes of each of those fonts. */
static float default_size, fixed_size;
/* The locker controlling access to those variables. */
static BLocker default_locker;
/* Haiku doesn't expose font language data in BFont objects. Thus, we
select a few representative characters for each supported `:lang'
(currently Chinese, Korean and Japanese,) and test for those
instead. */
static int language_code_points[MAX_LANGUAGE][3] =
{{20154, 20754, 22996}, /* Chinese. */
{51312, 49440, 44544}, /* Korean. */
{26085, 26412, 12371}, /* Japanese. */};
{
{20154, 20754, 22996}, /* Chinese. */
{51312, 49440, 44544}, /* Korean. */
{26085, 26412, 12371}, /* Japanese. */
};
static void be_send_font_settings (void);
/* Looper used to track changes to system-wide font settings. */
class EmacsFontMonitorLooper : public BLooper
{
void
MessageReceived (BMessage *msg)
{
int32 opcode;
if (msg->what != B_NODE_MONITOR)
return;
if (msg->FindInt32 ("opcode", &opcode) != B_OK)
return;
if (opcode != B_STAT_CHANGED)
return;
/* Wait a little for any message to be completely written after
the file's modification time changes. */
snooze (10000);
/* Read and apply font settings. */
be_send_font_settings ();
}
};
static unsigned int
hash_string (const char *name_or_style)
@ -288,12 +338,15 @@ BFont_nchar_bounds (void *font, const char *mb_str, int *advance,
}
static void
font_style_to_flags (char *st, struct haiku_font_pattern *pattern)
font_style_to_flags (const char *style_string,
struct haiku_font_pattern *pattern)
{
char *style = strdup (st);
char *style;
char *token;
int tok = 0;
style = strdup (style_string);
if (!style)
return;
@ -385,7 +438,8 @@ font_style_to_flags (char *st, struct haiku_font_pattern *pattern)
pattern->specified &= ~FSPEC_WEIGHT;
pattern->specified &= ~FSPEC_WIDTH;
pattern->specified |= FSPEC_STYLE;
std::strncpy ((char *) &pattern->style, st,
std::strncpy ((char *) &pattern->style,
style_string,
sizeof pattern->style - 1);
pattern->style[sizeof pattern->style - 1] = '\0';
}
@ -887,7 +941,7 @@ be_evict_font_cache (void)
}
void
be_font_style_to_flags (char *style, struct haiku_font_pattern *pattern)
be_font_style_to_flags (const char *style, struct haiku_font_pattern *pattern)
{
pattern->specified = 0;
@ -939,3 +993,217 @@ be_set_font_antialiasing (void *font, bool antialias_p)
? B_FORCE_ANTIALIASING
: B_DISABLE_ANTIALIASING);
}
static void
be_send_font_settings (void)
{
struct haiku_font_change_event rq;
BFile file;
BPath path;
status_t rc;
BMessage message;
font_family family;
font_style style;
const char *new_family, *new_style;
float new_size;
rc = find_directory (B_USER_SETTINGS_DIRECTORY, &path);
if (rc < B_OK)
return;
rc = path.Append ("system/app_server/fonts");
if (rc < B_OK)
return;
if (file.SetTo (path.Path (), B_READ_ONLY) != B_OK)
return;
if (message.Unflatten (&file) != B_OK)
return;
/* Now, populate with new values. */
if (!default_locker.Lock ())
gui_abort ("Failed to lock font data locker");
/* Obtain default values. */
be_fixed_font->GetFamilyAndStyle (&family, &style);
default_size = be_fixed_font->Size ();
/* And the new values. */
new_family = message.GetString ("fixed family", family);
new_style = message.GetString ("fixed style", style);
new_size = message.GetFloat ("fixed size", default_size);
/* If it turns out the fixed family changed, send the new family and
style. */
if (!fixed_family || !fixed_style
|| new_size != fixed_size
|| strcmp (new_family, fixed_family)
|| strcmp (new_style, fixed_style))
{
memset (&rq, 0, sizeof rq);
strncpy (rq.new_family, (char *) new_family,
sizeof rq.new_family - 1);
strncpy (rq.new_style, (char *) new_style,
sizeof rq.new_style - 1);
rq.new_size = new_size;
rq.what = FIXED_FAMILY;
haiku_write (FONT_CHANGE_EVENT, &rq);
}
if (fixed_family)
free (fixed_family);
if (fixed_style)
free (fixed_style);
fixed_family = strdup (new_family);
fixed_style = strdup (new_style);
fixed_size = new_size;
/* Obtain default values. */
be_plain_font->GetFamilyAndStyle (&family, &style);
default_size = be_plain_font->Size ();
/* And the new values. */
new_family = message.GetString ("plain family", family);
new_style = message.GetString ("plain style", style);
new_size = message.GetFloat ("plain style", default_size);
if (!default_family || !default_style
|| new_size != default_size
|| strcmp (new_family, default_family)
|| strcmp (new_style, default_style))
{
memset (&rq, 0, sizeof rq);
strncpy (rq.new_family, (char *) new_family,
sizeof rq.new_family - 1);
strncpy (rq.new_style, (char *) new_style,
sizeof rq.new_style - 1);
rq.new_size = new_size;
rq.what = DEFAULT_FAMILY;
haiku_write (FONT_CHANGE_EVENT, &rq);
}
if (default_family)
free (default_family);
if (default_style)
free (default_style);
default_family = strdup (new_family);
default_style = strdup (new_style);
default_size = new_size;
default_locker.Unlock ();
}
/* Begin listening to font settings changes, by installing a node
watcher. This relies on the settings file already being present
and has several inherent race conditions, but users shouldn't be
changing font settings very quickly. */
void
be_listen_font_settings (void)
{
BPath path;
status_t rc;
BNode node;
node_ref node_ref;
EmacsFontMonitorLooper *looper;
font_family family;
font_style style;
/* Set up initial values. */
be_fixed_font->GetFamilyAndStyle (&family, &style);
fixed_family = strdup (family);
fixed_style = strdup (style);
fixed_size = be_fixed_font->Size ();
be_plain_font->GetFamilyAndStyle (&family, &style);
default_family = strdup (family);
default_style = strdup (style);
default_size = be_plain_font->Size ();
rc = find_directory (B_USER_SETTINGS_DIRECTORY, &path);
if (rc < B_OK)
return;
rc = path.Append ("system/app_server/fonts");
if (rc < B_OK)
return;
rc = node.SetTo (path.Path ());
if (rc < B_OK)
return;
if (node.GetNodeRef (&node_ref) < B_OK)
return;
looper = new EmacsFontMonitorLooper;
if (watch_node (&node_ref, B_WATCH_STAT, looper) < B_OK)
{
delete looper;
return;
}
looper->Run ();
}
bool
be_lock_font_defaults (void)
{
return default_locker.Lock ();
}
void
be_unlock_font_defaults (void)
{
return default_locker.Unlock ();
}
const char *
be_get_font_default (enum haiku_what_font what)
{
switch (what)
{
case FIXED_FAMILY:
return fixed_family;
case FIXED_STYLE:
return fixed_style;
case DEFAULT_FAMILY:
return default_family;
case DEFAULT_STYLE:
return default_style;
}
return NULL;
}
int
be_get_font_size (enum haiku_what_font what)
{
switch (what)
{
case FIXED_FAMILY:
return fixed_size;
case DEFAULT_FAMILY:
return default_size;
default:
return 0;
}
}

View file

@ -109,6 +109,8 @@ haiku_len (enum haiku_event_type type)
return sizeof (struct haiku_screen_changed_event);
case CLIPBOARD_CHANGED_EVENT:
return sizeof (struct haiku_clipboard_changed_event);
case FONT_CHANGE_EVENT:
return sizeof (struct haiku_font_change_event);
}
emacs_abort ();

View file

@ -115,6 +115,7 @@ enum haiku_event_type
SCREEN_CHANGED_EVENT,
MENU_BAR_LEFT,
CLIPBOARD_CHANGED_EVENT,
FONT_CHANGE_EVENT,
};
struct haiku_clipboard_changed_event
@ -442,6 +443,27 @@ struct haiku_menu_bar_state_event
void *window;
};
enum haiku_what_font
{
FIXED_FAMILY,
FIXED_STYLE,
DEFAULT_FAMILY,
DEFAULT_STYLE,
};
struct haiku_font_change_event
{
/* New family, style and size of the font. */
haiku_font_family_or_style new_family;
haiku_font_family_or_style new_style;
int new_size;
/* What changed. FIXED_FAMILY means this is the new fixed font.
DEFAULT_FAMILY means this is the new plain font. The other enums
have no meaning. */
enum haiku_what_font what;
};
struct haiku_session_manager_reply
{
bool quit_reply;
@ -697,7 +719,7 @@ extern int be_get_display_screens (void);
extern bool be_use_subpixel_antialiasing (void);
extern const char *be_find_setting (const char *);
extern haiku_font_family_or_style *be_list_font_families (size_t *);
extern void be_font_style_to_flags (char *, struct haiku_font_pattern *);
extern void be_font_style_to_flags (const char *, struct haiku_font_pattern *);
extern void *be_open_font_at_index (int, int, float);
extern void be_set_font_antialiasing (void *, bool);
extern int be_get_ui_color (const char *, uint32_t *);
@ -732,6 +754,13 @@ extern void be_unlock_window (void *);
extern bool be_get_explicit_workarea (int *, int *, int *, int *);
extern void be_clear_grab_view (void);
extern void be_set_use_frame_synchronization (void *, bool);
extern void be_listen_font_settings (void);
extern bool be_lock_font_defaults (void);
extern const char *be_get_font_default (enum haiku_what_font);
extern int be_get_font_size (enum haiku_what_font);
extern void be_unlock_font_defaults (void);
#ifdef __cplusplus
}

View file

@ -1311,6 +1311,98 @@ in the font selection dialog. */)
QCsize, lsize);
}
DEFUN ("font-get-system-normal-font", Ffont_get_system_normal_font,
Sfont_get_system_normal_font, 0, 0, 0,
doc: /* SKIP: real doc in xsettings.c. */)
(void)
{
Lisp_Object value;
const char *name, *style;
struct haiku_font_pattern pattern;
Lisp_Object lfamily, lweight, lslant, lwidth, ladstyle;
int size;
if (!be_lock_font_defaults ())
return Qnil;
name = be_get_font_default (DEFAULT_FAMILY);
style = be_get_font_default (DEFAULT_STYLE);
size = be_get_font_size (DEFAULT_FAMILY);
be_font_style_to_flags (style, &pattern);
lfamily = build_string_from_utf8 (name);
lweight = (pattern.specified & FSPEC_WEIGHT
? haikufont_weight_to_lisp (pattern.weight) : Qnil);
lslant = (pattern.specified & FSPEC_SLANT
? haikufont_slant_to_lisp (pattern.slant) : Qnil);
lwidth = (pattern.specified & FSPEC_WIDTH
? haikufont_width_to_lisp (pattern.width) : Qnil);
ladstyle = (pattern.specified & FSPEC_STYLE
? intern (pattern.style) : Qnil);
value = CALLN (Ffont_spec, QCfamily, lfamily,
QCweight, lweight, QCslant, lslant,
QCwidth, lwidth, QCadstyle, ladstyle,
QCsize, make_fixnum (size));
be_unlock_font_defaults ();
return value;
}
DEFUN ("font-get-system-font", Ffont_get_system_font,
Sfont_get_system_font, 0, 0, 0,
doc: /* SKIP: real doc in xsettings.c. */)
(void)
{
Lisp_Object value;
const char *name, *style;
struct haiku_font_pattern pattern;
Lisp_Object lfamily, lweight, lslant, lwidth, ladstyle;
int size;
if (!be_lock_font_defaults ())
return Qnil;
name = be_get_font_default (FIXED_FAMILY);
style = be_get_font_default (FIXED_STYLE);
size = be_get_font_size (FIXED_FAMILY);
be_font_style_to_flags (style, &pattern);
lfamily = build_string_from_utf8 (name);
lweight = (pattern.specified & FSPEC_WEIGHT
? haikufont_weight_to_lisp (pattern.weight) : Qnil);
lslant = (pattern.specified & FSPEC_SLANT
? haikufont_slant_to_lisp (pattern.slant) : Qnil);
lwidth = (pattern.specified & FSPEC_WIDTH
? haikufont_width_to_lisp (pattern.width) : Qnil);
ladstyle = (pattern.specified & FSPEC_STYLE
? intern (pattern.style) : Qnil);
value = CALLN (Ffont_spec, QCfamily, lfamily,
QCweight, lweight, QCslant, lslant,
QCwidth, lwidth, QCadstyle, ladstyle,
QCsize, make_fixnum (size));
be_unlock_font_defaults ();
return value;
}
void
haiku_handle_font_change_event (struct haiku_font_change_event *event,
struct input_event *ie)
{
ie->kind = CONFIG_CHANGED_EVENT;
/* This is the name of the display. */
ie->frame_or_window = XCAR (x_display_list->name_list_element);
/* And this is the font that changed. */
ie->arg = (event->what == FIXED_FAMILY
? Qmonospace_font_name : Qfont_name);
}
static void
syms_of_haikufont_for_pdumper (void)
{
@ -1344,6 +1436,14 @@ syms_of_haikufont (void)
DEFSYM (QCindices, ":indices");
DEFSYM (Qmonospace_font_name, "monospace-font-name");
DEFSYM (Qfont_name, "font-name");
DEFSYM (Qdynamic_setting, "dynamic-setting");
DEFVAR_BOOL ("font-use-system-font", use_system_font,
doc: /* SKIP: real doc in xsettings.c. */);
use_system_font = false;
#ifdef USE_BE_CAIRO
Fput (Qhaiku, Qfont_driver_superseded_by, Qftcr);
#endif
@ -1353,6 +1453,12 @@ syms_of_haikufont (void)
staticpro (&font_cache);
defsubr (&Sx_select_font);
defsubr (&Sfont_get_system_normal_font);
defsubr (&Sfont_get_system_font);
be_init_font_data ();
/* This tells loadup to load dynamic-setting.el, which handles
config-changed events. */
Fprovide (Qdynamic_setting, Qnil);
}

View file

@ -2988,18 +2988,11 @@ haiku_default_font_parameter (struct frame *f, Lisp_Object parms)
font_param = Qnil;
if (NILP (font_param))
{
/* System font should take precedence over X resources. We suggest this
regardless of font-use-system-font because .emacs may not have been
read yet. */
struct haiku_font_pattern ptn;
ptn.specified = 0;
BFont_populate_fixed_family (&ptn);
if (ptn.specified & FSPEC_FAMILY)
font = font_open_by_name (f, build_unibyte_string (ptn.family));
}
/* System font should take precedence over X resources. We
suggest this regardless of font-use-system-font because .emacs
may not have been read yet. Returning a font-spec is Haiku
specific behavior. */
font = font_open_by_spec (f, Ffont_get_system_font ());
if (NILP (font))
font = !NILP (font_param) ? font_param
@ -4027,6 +4020,11 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
inev.kind = SAVE_SESSION_EVENT;
inev.arg = Qt;
break;
case FONT_CHANGE_EVENT:
/* This generates CONFIG_CHANGED_EVENTs, which are then
handled in Lisp. */
haiku_handle_font_change_event (buf, &inev);
break;
case KEY_UP:
case DUMMY_EVENT:
default:
@ -4417,6 +4415,9 @@ haiku_term_init (void)
dpyinfo->default_name = build_string ("GNU Emacs");
haiku_start_watching_selections ();
/* Start listening for font configuration changes. */
be_listen_font_settings ();
unblock_input ();
return dpyinfo;

View file

@ -34,6 +34,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#define HAVE_CHAR_CACHE_MAX 65535
/* This is really defined in haiku_support.h. */
struct haiku_font_change_event;
extern int popup_activated_p;
struct haikufont_info
@ -361,4 +364,7 @@ extern void haiku_merge_cursor_foreground (struct glyph_string *, unsigned long
unsigned long *);
extern void haiku_handle_selection_clear (struct input_event *);
extern void haiku_start_watching_selections (void);
extern void haiku_handle_font_change_event (struct haiku_font_change_event *,
struct input_event *);
#endif /* _HAIKU_TERM_H_ */

View file

@ -1225,7 +1225,8 @@ xsettings_get_font_options (void)
DEFUN ("font-get-system-normal-font", Ffont_get_system_normal_font,
Sfont_get_system_normal_font,
0, 0, 0,
doc: /* Get the system default application font. */)
doc: /* Get the system default application font.
The font is returned as either a font-spec or font name. */)
(void)
{
return current_font ? build_string (current_font) : Qnil;
@ -1233,7 +1234,8 @@ DEFUN ("font-get-system-normal-font", Ffont_get_system_normal_font,
DEFUN ("font-get-system-font", Ffont_get_system_font, Sfont_get_system_font,
0, 0, 0,
doc: /* Get the system default fixed width font. */)
doc: /* Get the system default fixed width font.
The font is returned as either a font-spec or font name. */)
(void)
{
return current_mono_font ? build_string (current_mono_font) : Qnil;
@ -1282,6 +1284,10 @@ syms_of_xsettings (void)
DEFSYM (Qmonospace_font_name, "monospace-font-name");
DEFSYM (Qfont_name, "font-name");
DEFSYM (Qfont_render, "font-render");
DEFSYM (Qdynamic_setting, "dynamic-setting");
DEFSYM (Qfont_render_setting, "font-render-setting");
DEFSYM (Qsystem_font_setting, "system-font-setting");
defsubr (&Sfont_get_system_font);
defsubr (&Sfont_get_system_normal_font);
@ -1297,9 +1303,9 @@ If this variable is nil, Emacs ignores system font changes. */);
Vxft_settings = empty_unibyte_string;
#if defined USE_CAIRO || defined HAVE_XFT
Fprovide (intern_c_string ("font-render-setting"), Qnil);
Fprovide (Qfont_render_setting, Qnil);
#if defined (HAVE_GCONF) || defined (HAVE_GSETTINGS)
Fprovide (intern_c_string ("system-font-setting"), Qnil);
Fprovide (Qsystem_font_setting, Qnil);
#endif
#endif
@ -1307,5 +1313,5 @@ If this variable is nil, Emacs ignores system font changes. */);
DEFSYM (Qtool_bar_style, "tool-bar-style");
defsubr (&Stool_bar_get_system_style);
Fprovide (intern_c_string ("dynamic-setting"), Qnil);
Fprovide (Qdynamic_setting, Qnil);
}