From ab0c6edc63fa0dceac7a847ca276910a03119b12 Mon Sep 17 00:00:00 2001
From: Jiri Kalvoda <jirikalvoda@kam.mff.cuni.cz>
Date: Mon, 8 Feb 2021 19:41:11 +0100
Subject: [PATCH] Add support of alternatives fonts

---
 display.c | 91 +++++++++++++++++++++++++++++++++++++------------------
 osdd-run  |  2 +-
 2 files changed, 63 insertions(+), 30 deletions(-)

diff --git a/display.c b/display.c
index 29426c4..6069b25 100644
--- a/display.c
+++ b/display.c
@@ -39,12 +39,13 @@ struct display_line {
   int slider_unit;
   int slider_space;
   int slider_units;
+  XftFont *font;
 };
 
 struct osd_abstract display_state_new_arg(int argc, char ** argv,Display * dpy);
-struct osd_abstract display_state_new(Display *dpy,int width,int height,int x,int y, char * font_name, double line_spacing);
+struct osd_abstract display_state_new(Display *dpy,int width,int height,int x,int y, char * font_name,VECTOR(char *) alternative_fonts, double line_spacing);
 void display_free(struct display_state *display);
-void display_set_font(struct display_state *display, char *font_name, double line_spacing);
+void display_set_font(struct display_state *display, char *font_name, VECTOR(char *) alternative_fonts_name, double line_spacing);
 struct display_line *display_add_line(struct display_state *display, struct osd_line * line);
 void display_show(struct display_state *display, struct osd_line * lines, int num_lines);
 void display_hide(struct display_state *display);
@@ -78,7 +79,8 @@ struct display_state {
   GC mask_gc;
 
   // Xft state
-  XftFont *font;
+  XftFont **font;
+  int num_font;
   XftDraw *mask_draw;
   XftDraw *image_draw;
 
@@ -154,6 +156,7 @@ void display_state_new_arg_help(FILE * f)
 {
 	fprintf(f,"Module DISPLAY help:\n\
 -f, --font=<f>\t\tFont to use for the OSD\n\
+-F, --alternative-font=<f>\tFont to use when line is too big\n\
 -s, --line-spacing=<n>\tSet line spacing factor (decimal fraction, default=0.2)\n\
 -x, --x=<px>\t\tLeft up corner positing (move right, default=0)\n\
 -y, --y=<px>\t\tLeft up corner positing (move down, default=0)\n\
@@ -164,9 +167,10 @@ void display_state_new_arg_help(FILE * f)
 
 struct osd_abstract display_state_new_arg(int argc, char ** argv,Display *dpy)
 {
-static const char short_opts[] = "f:s:x:y:h:w:";
+static const char short_opts[] = "f:F:s:x:y:h:w:";
 static const struct option long_opts[] = {
   { "font",		required_argument,	NULL,	'f' },
+  { "alternative-font",		required_argument,	NULL,	'F' },
   { "line-spacing",	required_argument,	NULL,	's' },
   { "x",	required_argument,	NULL,	'x' },
   { "y",	required_argument,	NULL,	'y' },
@@ -177,6 +181,7 @@ static const struct option long_opts[] = {
 	//fprintf(stderr,"NEW DISPLAY:\n");
 	//for(int i=0;i<argc;i++) fprintf(stderr,"\t%s\n",argv[i]);
 	char *font_name = "times-64:bold";
+	VECTOR(char *) alternative_fonts = 0;
 	double line_spacing = 0.2;
 	int opt;
 	int x=0,y=0;
@@ -189,7 +194,9 @@ static const struct option long_opts[] = {
 		{
 			case 'f':
 				font_name = optarg;
-				fprintf(stderr,"FONT SET\n");
+				break;
+			case 'F':
+				VPB(alternative_fonts, optarg);
 				break;
 			case 's':
 				line_spacing = atof(optarg);
@@ -211,7 +218,7 @@ static const struct option long_opts[] = {
 				exit(0);
 		}
 	}
-	return display_state_new(dpy,width,height,x,y,font_name,line_spacing);
+	return display_state_new(dpy,width,height,x,y,font_name,alternative_fonts,line_spacing);
 }
 
 struct osd_creator_abstract display_creator_new(void)
@@ -233,6 +240,7 @@ void display_state_new_by_outputs_help(FILE * f)
 {
 	fprintf(f,"Module DISPLAY_BY_OUTPUTS help:\n\
 -f, --font=<f>\t\tFont to use for the OSD\n\
+-F, --alternative-font=<f>\tFont to use when line is too big\n\
 -s, --line-spacing=<n>\tSet line spacing factor (decimal fraction, default=0.2)\n\
 -n, --name=<s>\t\tname with expansion %%d to display number (expanded by printf)\n\
 \n");
@@ -241,9 +249,10 @@ void display_state_new_by_outputs_help(FILE * f)
 static
 void display_state_new_by_outputs(struct osd_set *set, int argc, char ** argv,Display *dpy,int names_len, char ** names)
 {
-static const char short_opts[] = "f:s:n:";
+static const char short_opts[] = "f:F:s:n:";
 static const struct option long_opts[] = {
   { "font",		required_argument,	NULL,	'f' },
+  { "alternative-font",		required_argument,	NULL,	'F' },
   { "line-spacing",	required_argument,	NULL,	's' },
   { "name",	required_argument,	NULL,	'n' },
   { NULL,		0,			NULL,	0   },
@@ -252,6 +261,7 @@ static const struct option long_opts[] = {
 	//for(int i=0;i<argc;i++) fprintf(stderr,"\t%s\n",argv[i]);
 	char  * expanding_name = "";
 	char *font_name = "times-64:bold";
+	VECTOR(char *) alternative_fonts = 0;
 	double line_spacing = 0.2;
 	int opt;
 	optind = 0;
@@ -261,7 +271,9 @@ static const struct option long_opts[] = {
 		{
 			case 'f':
 				font_name = optarg;
-				fprintf(stderr,"FONT SET\n");
+				break;
+			case 'F':
+				VPB(alternative_fonts, optarg);
 				break;
 			case 's':
 				line_spacing = atof(optarg);
@@ -291,7 +303,7 @@ static const struct option long_opts[] = {
 
 			    DBG("ADD screen %dx%d on %d,%d\n",width,height,x,y);
 				sprintf(new_names[names_len],expanding_name,i,i,i,i,i,i);
-				osd_set_add(set,display_state_new(dpy,width,height,x,y,font_name,line_spacing),names_len+(bool)expanding_name[0],new_names);
+				osd_set_add(set,display_state_new(dpy,width,height,x,y,font_name,alternative_fonts,line_spacing),names_len+(bool)expanding_name[0],new_names);
 				i++;
 			}
   }
@@ -312,7 +324,7 @@ struct osd_creator_abstract display_by_outputs_creator_new(void)
 
 // ****************************************************************************************
 
-struct osd_abstract display_state_new(Display *dpy,int width,int height,int x,int y, char * font_name, double line_spacing)
+struct osd_abstract display_state_new(Display *dpy,int width,int height,int x,int y, char * font_name, VECTOR(char *) alternative_fonts, double line_spacing)
 {
   struct display_state *display = xmalloc(sizeof(*display));
   memset(display, 0, sizeof(*display));
@@ -339,7 +351,7 @@ struct osd_abstract display_state_new(Display *dpy,int width,int height,int x,in
   display->num_lines = 0;
   display->lines = xmalloc(sizeof(struct display_line) * display->max_lines);
 
-  display_set_font(display, font_name, line_spacing);
+  display_set_font(display, font_name, alternative_fonts, line_spacing);
 
   struct osd_abstract r;
   memset(&r, 0, sizeof(r));
@@ -357,26 +369,41 @@ void display_free(struct display_state *display)
 {
   display_hide(display);
 
-  if (display->font)
-    XftFontClose(display->dpy, display->font);
+  if(display->font)
+  {
+    for(int i=0;i<display->num_font;i++)
+      if (display->font[i])
+        XftFontClose(display->dpy, display->font[i]);
+    free(display->font);
+  }
 
   free(display->lines);
   free(display);
 }
 
-void display_set_font(struct display_state *display, char *font_name, double line_spacing)
+void display_set_font(struct display_state *display, char *font_name, VECTOR(char *) alternative_fonts_name, double line_spacing)
 {
-  if (display->font)
-    XftFontClose(display->dpy, display->font);
+  if(display->font)
+  {
+    for(int i=0;i<display->num_font;i++)
+      if (display->font[i])
+        XftFontClose(display->dpy, display->font[i]);
+    free(display->font);
+  }
 
   DBG("Using font %s\n", font_name);
-  display->font = XftFontOpenName(display->dpy, display->screen, font_name);
-  if (!display->font)
-    die("Cannot open font %s", font_name);
-  DBG("Font: asc=%d desc=%d ht=%d\n", display->font->ascent, display->font->descent, display->font->height);
+  display->num_font = 1 + VSIZE(alternative_fonts_name);
+  display->font = malloc(sizeof(display->font[0])*display->num_font);
+  for(int i=0;i<display->num_font;i++)
+  {
+	  display->font[i] = XftFontOpenName(display->dpy, display->screen, i?alternative_fonts_name[i-1]:font_name);
+	  if (!display->font[0])
+		die("Cannot open font %s", font_name);
+	  DBG("Font: asc=%d desc=%d ht=%d\n", display->font->ascent, display->font->descent, display->font->height);
+  }
 
-  display->line_distance = display->font->height;
-  display->line_height = display->font->ascent;
+  display->line_distance = display->font[0]->height;
+  display->line_height = display->font[0]->ascent;
   display->line_skip = display->line_distance * line_spacing;
   DBG("Line: distance=%d height=%d skip=%d\n", display->line_distance, display->line_height, display->line_skip);
 }
@@ -402,11 +429,17 @@ static void display_prepare_line(struct display_state *display, int i)
     {
     case OSD_TYPE_TEXT:
       {
-	XGlyphInfo gi;
-	XftTextExtentsUtf8(display->dpy, display->font, (unsigned char *) line->line->u.text, strlen(line->line->u.text), &gi);
-	DBG("Line #%d: Glyph info: (%d,%d)+(%d,%d) off (%d,%d)\n", i, gi.x, gi.y, gi.width, gi.height, gi.xOff, gi.yOff);
-	line->width = gi.width + 2*line->line->outline_width;
-	line->height = display->line_distance + 2*line->line->outline_width;
+    for(int j=0;j<display->num_font;j++)
+	{
+	  XGlyphInfo gi;
+	  XftTextExtentsUtf8(display->dpy, display->font[j], (unsigned char *) line->line->u.text, strlen(line->line->u.text), &gi);
+	  DBG("Line #%d: Glyph info: (%d,%d)+(%d,%d) off (%d,%d)\n", i, gi.x, gi.y, gi.width, gi.height, gi.xOff, gi.yOff);
+	  line->width = gi.width + 2*line->line->outline_width;
+	  line->height = display->line_distance + 2*line->line->outline_width;
+	  line->font = display->font[j];
+	  //fprintf(stderr,"i%d j%d L %d S %d\n", i,j, line->width, display->screen_width);
+	  if(line->width < display->screen_width - 10) break;
+	}
 	break;
       }
     case OSD_TYPE_PERCENTAGE:
@@ -510,14 +543,14 @@ static void display_draw_line(struct display_state *display, int i)
 
 	unsigned char *text = (unsigned char *) line->line->u.text;
 	int text_len = strlen(line->line->u.text);
-	XftDrawStringUtf8(display->image_draw, &display->fg_color, display->font, x, y, text, text_len);
+	XftDrawStringUtf8(display->image_draw, &display->fg_color, line->font, x, y, text, text_len);
 
 	// This is slow, but unlike the method used by libxosd, the result isn't ugly.
 	int outline = line->line->outline_width;
 	for (int dx = -outline; dx <= outline; dx++)
 	  for (int dy = -outline; dy <= outline; dy++)
 	    if (dx*dx + dy*dy <= outline*outline)
-	      XftDrawStringUtf8(display->mask_draw, &display->mask_color, display->font, x + dx, y + dy, text, text_len);
+	      XftDrawStringUtf8(display->mask_draw, &display->mask_color, line->font, x + dx, y + dy, text, text_len);
 
 	break;
       }
diff --git a/osdd-run b/osdd-run
index fd179e7..aa31d48 100755
--- a/osdd-run
+++ b/osdd-run
@@ -8,7 +8,7 @@ tmp=$(mktemp)
 echo "Xft.render: False" > $tmp
 XENVIRONMENT=$tmp \
 	./osdd -D \
-	DISPLAY_BY_OUTPUTS default nolog display [ -n d%d ] \
+	DISPLAY_BY_OUTPUTS default nolog display [ -n d%d -Ftimes-48:bold -Ftimes-32:bold ] \
 	FILE default log loglog [ -b -l' ' -m'\n' -T' ' -tiso -cterm ~/.osdd_log  ] \
 	FILE default log loglast [ -l'\n' -tunix -T'\n' -crgbHEX -r ~/.osdd_last ] \
 	FILE stdout [ -A -l' ' -m'\n' /dev/stdout ] \
-- 
GitLab