[prev in list] [next in list] [prev in thread] [next in thread] 

List:       xine-devel
Subject:    [xine-devel] [PATCH] xine-ui OSD enhancement (color/fontsize/menu)
From:       Richard van Paasen <rvpaasen () t3i ! nl>
Date:       2008-12-09 22:45:32
Message-ID: 493EF50C.7070603 () t3i ! nl
[Download RAW message or body]

Hi,

Note: I submitted this patch last week, but forgot to add the [PATCH] tag in the \
subject line of the email. If this is not the right place to submit xine-ui patches, \
please let me know.

I have implemented some OSD functionality in xine-ui:

  * Added a custom OSD menu to stdctl interface. Available commands are
    "OSDShowCustomMenu" and "OSDHideCustomMenu". This provides clients
    to display a menu with options.
  * Made OSD font sizes and color scheme configurable. New config entries:
    gui.osd.fontsize (range: 8..36)
    gui.osd.fontcolor (range: white, yellow, cyan, green)
    gui.osd.background (range: true, false)
  * Moved many magic numbers of OSD objects (positioning, margins,
indentation
    to constants.

A patch to current xine-ui CVS is attached. I implemented this stuff for
Freevo to add some (osd) interactivity. Maybe this is usefull for others too.

Regards,

Richard.


["xine-ui.patch" (text/plain)]

Index: ChangeLog
===================================================================
RCS file: /cvsroot/xine/xine-ui/ChangeLog,v
retrieving revision 1.121
diff -u -r1.121 ChangeLog
--- ChangeLog	27 Nov 2008 17:55:50 -0000	1.121
+++ ChangeLog	1 Dec 2008 19:34:00 -0000
@@ -1,6 +1,18 @@
 xine-ui (0.99.6) unstable; urgency=low
   (write here, newest entry on top)
 
+  * Added a custom OSD menu to stdctl interface. Available commands are
+    "OSDShowCustomMenu" and "OSDHideCustomMenu". This provides clients
+    to display a menu with options.
+    Contributed by Richard van Paasen.
+  * Made OSD font sizes and color scheme configurable. New config entries:
+    gui.osd.fontsize (range: 8..36)
+    gui.osd.fontcolor (range: white, yellow, cyan, green)
+    gui.osd.background (range: true, false)
+    Contributed by Richard van Paasen.
+  * Moved many magic numbers of OSD objects (positioning, margins, indentation
+    to constants.
+    Contributed by Richard van Paasen.
   * Automatically load opensubtitle-like filenames <name>.*.<subext>
   * New/updated spanish manpage translations from Carlos E. Robinson
   * Fixed possible corruption and overflow of keybindings table
Index: src/xitk/common.h
===================================================================
RCS file: /cvsroot/xine/xine-ui/src/xitk/common.h,v
retrieving revision 1.105
diff -u -r1.105 common.h
--- src/xitk/common.h	12 Mar 2008 12:16:59 -0000	1.105
+++ src/xitk/common.h	1 Dec 2008 19:34:00 -0000
@@ -237,7 +237,7 @@
     osd_object_t            bar;
     osd_object_t            status;
     osd_object_t            info;
-
+    osd_object_t            menu;
   } osd;
 
   int                       experience_level;
Index: src/xitk/event.c
===================================================================
RCS file: /cvsroot/xine/xine-ui/src/xitk/event.c,v
retrieving revision 1.312
diff -u -r1.312 event.c
--- src/xitk/event.c	26 Mar 2008 23:30:39 -0000	1.312
+++ src/xitk/event.c	1 Dec 2008 19:34:01 -0000
@@ -959,6 +959,35 @@
     }
     break;
 
+  case ACTID_OSD_SHOWCUSTOMMENU:
+    if(gGui->alphanum.set) {
+      char *title, *options[OSD_CUSTMENU_MAXOPT];
+      int i;
+
+      title = strtok(gGui->alphanum.arg, "~");
+
+      if (title) {
+        for (i=0; i<OSD_CUSTMENU_MAXOPT; i++) {
+          options[i] = strtok(NULL, "~");
+          if (options[i] == NULL)
+            break;
+        }
+      }
+
+      if (title == NULL || i == 0)
+        osd_display_info(_("No menu to display!"));
+      else
+        osd_display_menu(title, options, i);
+
+    }
+    else
+      osd_display_info(_("No menu to display!"));
+    break;
+
+  case ACTID_OSD_HIDECUSTOMMENU:
+    osd_hide_menu();
+    break;
+
   case ACTID_OSD_MENU:
     oxine_menu();
     break;
Index: src/xitk/kbindings.h
===================================================================
RCS file: /cvsroot/xine/xine-ui/src/xitk/kbindings.h,v
retrieving revision 1.68
diff -u -r1.68 kbindings.h
--- src/xitk/kbindings.h	16 Jan 2008 16:29:42 -0000	1.68
+++ src/xitk/kbindings.h	1 Dec 2008 19:34:01 -0000
@@ -127,6 +127,8 @@
   ACTID_SKINDOWNLOAD,
   ACTID_OSD_SINFOS,
   ACTID_OSD_WTEXT,
+  ACTID_OSD_SHOWCUSTOMMENU,
+  ACTID_OSD_HIDECUSTOMMENU,
   ACTID_FILESELECTOR,
   ACTID_SUBSELECT,
   ACTID_SV_SYNC_p,
Index: src/xitk/kbindings_common.c
===================================================================
RCS file: /cvsroot/xine/xine-ui/src/xitk/kbindings_common.c,v
retrieving revision 1.6
diff -u -r1.6 kbindings_common.c
--- src/xitk/kbindings_common.c	16 Nov 2008 17:06:36 -0000	1.6
+++ src/xitk/kbindings_common.c	1 Dec 2008 19:34:01 -0000
@@ -223,6 +223,10 @@
     "OSDStreamInfos",         ACTID_OSD_SINFOS              , "i",        \
KEYMOD_CONTROL , 0 , 0},  { "display information using OSD",
     "OSDWriteText",           ACTID_OSD_WTEXT               , "VOID",     \
KEYMOD_CONTROL , 0 , 0}, +  { "display custom OSD menu",
+    "OSDShowCustomMenu",      ACTID_OSD_SHOWCUSTOMMENU      , "VOID",     \
KEYMOD_CONTROL , 0 , 0}, +  { "hide custom OSD menu",
+    "OSDHideCustomMenu",      ACTID_OSD_HIDECUSTOMMENU      , "VOID",     \
KEYMOD_CONTROL , 0 , 0},  { "show OSD menu",
     "OSDMenu",                ACTID_OSD_MENU                , "O",        \
KEYMOD_NOMOD   , 0 , 0},  { "enter key binding editor",
Index: src/xitk/osd.c
===================================================================
RCS file: /cvsroot/xine/xine-ui/src/xitk/osd.c,v
retrieving revision 1.48
diff -u -r1.48 osd.c
--- src/xitk/osd.c	12 Mar 2008 11:58:10 -0000	1.48
+++ src/xitk/osd.c	1 Dec 2008 19:34:01 -0000
@@ -43,43 +43,112 @@
 #define CLUT_Y_CR_CB_INIT(_y,_cr,_cb)	{ (_cb), (_cr), (_y) }
 #endif
 
+#define MIN(a, b) ( (a) < (b) ? (a) : (b) )
+#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
+
+/*
+  Xine OSD objects have a 256-entry palette. This pallette is used to
+  render the OSD object. For drawing text, xine needs 11 entries. A block
+  of 11 entires is refered to as a text color. The 11 palette entries that
+  define a text color describe the following:
+
+    0:   not used by font, always transparent
+    1:   font background, usually transparent, may be used to implement
+         translucid boxes where the font will be printed.
+    2-5: transition between background and border (usually only alpha
+         value changes).
+    6:   font border. if the font is to be displayed without border this
+         will probably be adjusted to font background or near.
+    7-9: transition between border and foreground
+    10:  font color (foreground)   
+
+  Each block of 11 entries is refered to as XINE_OSD_TEXT# (where the #
+  stands for 1, 2, 3, ...) The default xine-internal) palette can be
+  restored on a per textcolor (11 entries) basis with the function
+  xine_osd_set_text_palette(). The function xine_osd_set_palette() just
+  installs an entire palette.
+*/
+
 static const struct {         /* CLUT == Color LookUp Table */
   uint8_t cb    : 8;
   uint8_t cr    : 8;
   uint8_t y     : 8;
   uint8_t foo   : 8;
 } __attribute__ ((packed)) textpalettes_color[] = {
-  /* white, no border, translucid */
+
+  /* white palette */
     CLUT_Y_CR_CB_INIT(0x00, 0x00, 0x00), //0
-    CLUT_Y_CR_CB_INIT(0x60, 0x80, 0x80), //1
-    CLUT_Y_CR_CB_INIT(0x70, 0x80, 0x80), //2
-    CLUT_Y_CR_CB_INIT(0x80, 0x80, 0x80), //3
-    CLUT_Y_CR_CB_INIT(0x80, 0x80, 0x80), //4
-    CLUT_Y_CR_CB_INIT(0x80, 0x80, 0x80), //5
+    CLUT_Y_CR_CB_INIT(0x20, 0x80, 0x80), //1
+    CLUT_Y_CR_CB_INIT(0x33, 0x80, 0x80), //2
+    CLUT_Y_CR_CB_INIT(0x46, 0x80, 0x80), //3
+    CLUT_Y_CR_CB_INIT(0x59, 0x80, 0x80), //4
+    CLUT_Y_CR_CB_INIT(0x6c, 0x80, 0x80), //5
     CLUT_Y_CR_CB_INIT(0x80, 0x80, 0x80), //6
-    CLUT_Y_CR_CB_INIT(0xa0, 0x80, 0x80), //7
-    CLUT_Y_CR_CB_INIT(0xc0, 0x80, 0x80), //8
-    CLUT_Y_CR_CB_INIT(0xe0, 0x80, 0x80), //9
+    CLUT_Y_CR_CB_INIT(0x9f, 0x80, 0x80), //7
+    CLUT_Y_CR_CB_INIT(0xbf, 0x80, 0x80), //8
+    CLUT_Y_CR_CB_INIT(0xdf, 0x80, 0x80), //9
     CLUT_Y_CR_CB_INIT(0xff, 0x80, 0x80), //10
-  /* yellow, black border, transparent */
+
+  /* yellow palette */
+    CLUT_Y_CR_CB_INIT(0x00, 0x00, 0x00), //0
+    CLUT_Y_CR_CB_INIT(0x20, 0x80, 0x80), //1
+    CLUT_Y_CR_CB_INIT(0x31, 0x81, 0x76), //2
+    CLUT_Y_CR_CB_INIT(0x42, 0x83, 0x6c), //3
+    CLUT_Y_CR_CB_INIT(0x53, 0x84, 0x63), //4
+    CLUT_Y_CR_CB_INIT(0x64, 0x86, 0x59), //5
+    CLUT_Y_CR_CB_INIT(0x75, 0x87, 0x50), //6
+    CLUT_Y_CR_CB_INIT(0x92, 0x89, 0x44), //7
+    CLUT_Y_CR_CB_INIT(0xaf, 0x8b, 0x38), //8
+    CLUT_Y_CR_CB_INIT(0xcc, 0x8d, 0x2c), //9
+    CLUT_Y_CR_CB_INIT(0xe9, 0x8f, 0x20), //10
+
+  /* cyan palette */
+    CLUT_Y_CR_CB_INIT(0x00, 0x00, 0x00), //0
+    CLUT_Y_CR_CB_INIT(0x23, 0x7d, 0x90), //1
+    CLUT_Y_CR_CB_INIT(0x30, 0x74, 0x90), //2
+    CLUT_Y_CR_CB_INIT(0x3c, 0x6b, 0x90), //3
+    CLUT_Y_CR_CB_INIT(0x49, 0x62, 0x90), //4
+    CLUT_Y_CR_CB_INIT(0x56, 0x59, 0x90), //5
+    CLUT_Y_CR_CB_INIT(0x63, 0x50, 0x90), //6
+    CLUT_Y_CR_CB_INIT(0x79, 0x40, 0x95), //7
+    CLUT_Y_CR_CB_INIT(0x8f, 0x30, 0x9b), //8
+    CLUT_Y_CR_CB_INIT(0xa5, 0x20, 0xa0), //9
+    CLUT_Y_CR_CB_INIT(0xbc, 0x10, 0xa5), //10
+
+  /* green palette */
     CLUT_Y_CR_CB_INIT(0x00, 0x00, 0x00), //0
-    CLUT_Y_CR_CB_INIT(0x80, 0x80, 0xe0), //1
-    CLUT_Y_CR_CB_INIT(0x80, 0x80, 0xc0), //2
-    CLUT_Y_CR_CB_INIT(0x60, 0x80, 0xa0), //3
-    CLUT_Y_CR_CB_INIT(0x40, 0x80, 0x80), //4
-    CLUT_Y_CR_CB_INIT(0x20, 0x80, 0x80), //5
-    CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80), //6
-    CLUT_Y_CR_CB_INIT(0x40, 0x84, 0x60), //7
-    CLUT_Y_CR_CB_INIT(0xd0, 0x88, 0x40), //8
-    CLUT_Y_CR_CB_INIT(0xe0, 0x8a, 0x00), //9
-    CLUT_Y_CR_CB_INIT(0xff, 0x90, 0x00), //10
+    CLUT_Y_CR_CB_INIT(0x20, 0x80, 0x80), //1
+    CLUT_Y_CR_CB_INIT(0x2b, 0x77, 0x79), //2
+    CLUT_Y_CR_CB_INIT(0x36, 0x6f, 0x73), //3
+    CLUT_Y_CR_CB_INIT(0x41, 0x67, 0x6c), //4
+    CLUT_Y_CR_CB_INIT(0x4d, 0x5f, 0x66), //5
+    CLUT_Y_CR_CB_INIT(0x58, 0x57, 0x60), //6
+    CLUT_Y_CR_CB_INIT(0x6b, 0x4a, 0x55), //7
+    CLUT_Y_CR_CB_INIT(0x7e, 0x3d, 0x4b), //8
+    CLUT_Y_CR_CB_INIT(0x90, 0x2f, 0x40), //9
+    CLUT_Y_CR_CB_INIT(0xa3, 0x22, 0x36), //10
 };
 
-static const uint8_t textpalettes_trans[] = {
-  /* white, no border, translucid */
-  0, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15,
-  /* yellow, black border, transparent */
-  0, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15,
+static uint8_t textpalettes_trans[] = {
+  /* white palette */
+  0, 11, 9, 10, 11, 12, 13, 14, 15, 15, 15,
+  /* yellow palette */
+  0, 11, 9, 10, 11, 12, 13, 14, 15, 15, 15,
+  /* cyan palette */
+  0, 11, 9, 10, 11, 12, 13, 14, 15, 15, 15,
+  /* green palette */
+  0, 11, 9, 10, 11, 12, 13, 14, 15, 15, 15,
+};
+
+static uint32_t color[OVL_PALETTE_SIZE];
+static uint8_t trans[OVL_PALETTE_SIZE];
+
+static char *osd_fontcolors[] = {
+  "white",
+  "yellow",
+  "cyan",
+  "green",
+  NULL
 };
 
 static const struct {
@@ -104,16 +173,42 @@
   { ">$$", XINE_SPEED_FAST_4 }
 };
 
+/* minimum width of the stream else
+   osd objects are not shown */
+#define MINIMUM_WIN_WIDTH  300
+
+/* dimensions of the bar */
 #define BAR_WIDTH 336
 #define BAR_HEIGHT 25
 
-#define MINIMUM_WIN_WIDTH  300
-#define FONT_SIZE          20
-#define UNSCALED_FONT_SIZE 24
+/* fontsize range */
+#define DEF_OSD_FONTSIZE  24
+#define MIN_ODS_FONTSIZE  8
+#define MAX_OSD_FONTSIZE  36
+#define MAX_OSD_FONTHEIGHT (MAX_OSD_FONTSIZE + (MAX_OSD_FONTSIZE>>1))
+
+/* margins and indentation */
+#define OSD_MARGIN_W      15
+#define OSD_MARGIN_H      15
+#define OSD_TEXTMARGIN_W  6
+#define OSD_TEXTMARGIN_H  4
+#define OSD_TEXTINDENT "   "
+
+/* font faces */
+#define OSD_FONTFACE_REGULAR "sans"
+#define OSD_FONTFACE_SYMBOLS "cetus"
+
+/* default color and background */
+#define DEF_OSD_BACKGROUND 1
+#define DEF_OSD_FONTCOLOR 0
+
+static int osd_fontsize = DEF_OSD_FONTSIZE;
+static int osd_fontcolor = DEF_OSD_FONTCOLOR;
+static int osd_background = DEF_OSD_BACKGROUND;
 
 static pthread_mutex_t osd_mutex;
 
-static void  _xine_osd_show(xine_osd_t *osd, int64_t vpts) {
+static void _xine_osd_show(xine_osd_t *osd, int64_t vpts) {
   if( gGui->osd.use_unscaled && gGui->osd.unscaled_available )
     xine_osd_show_unscaled(osd, vpts);
   else
@@ -121,10 +216,9 @@
 }
 
 static void _osd_get_output_size(int *w, int *h) {
-  if( gGui->osd.use_unscaled && gGui->osd.unscaled_available )
+  video_window_get_frame_size(w, h);
+  if( (*w==0) || (*h==0) || (gGui->osd.use_unscaled && gGui->osd.unscaled_available) \
)  video_window_get_output_size(w, h);
-  else
-    video_window_get_frame_size(w, h);
 }
 
 static char *_osd_get_speed_sym(int speed) {
@@ -148,34 +242,125 @@
   return NULL;
 }
 
-void osd_init(void) {
-  int fonth = FONT_SIZE;
+static int _get_xine_color(int fontcolor) {
 
-  gGui->osd.sinfo.osd[0] = xine_osd_new(gGui->stream, 0, 0, 900, (fonth * 6) + (5 * \
                3));
-  xine_osd_set_font(gGui->osd.sinfo.osd[0], "sans", fonth);
-  xine_osd_set_text_palette(gGui->osd.sinfo.osd[0], 
-			    XINE_TEXTPALETTE_WHITE_BLACK_TRANSPARENT, XINE_OSD_TEXT1);
+  switch(fontcolor) {
+    case 0:  return XINE_OSD_TEXT1;
+    case 1:  return XINE_OSD_TEXT2;
+    case 2:  return XINE_OSD_TEXT3;
+    case 3:  return XINE_OSD_TEXT4;
+    default: return XINE_OSD_TEXT1;
+  }
+}
 
-  gGui->osd.bar.osd[0] = xine_osd_new(gGui->stream, 0, 0, BAR_WIDTH + 1, BAR_HEIGHT \
                + 1);
-  
-  xine_osd_set_palette(gGui->osd.bar.osd[0], textpalettes_color, \
textpalettes_trans); +static void _osd_ltrim_text(xine_osd_t *osd, char *buf, int \
maxw, int *tw, int *th) {  
-  gGui->osd.bar.osd[1] = xine_osd_new(gGui->stream, 0, 0, BAR_WIDTH + 1, BAR_HEIGHT \
                + 1);
-  xine_osd_set_font(gGui->osd.bar.osd[1], "sans", fonth);
-  xine_osd_set_text_palette(gGui->osd.bar.osd[1], 
-			    XINE_TEXTPALETTE_WHITE_BLACK_TRANSPARENT, XINE_OSD_TEXT1);
-  
-  gGui->osd.status.osd[0] = xine_osd_new(gGui->stream, 0, 0, 300, 2 * fonth);
-  xine_osd_set_text_palette(gGui->osd.status.osd[0], 
-			    XINE_TEXTPALETTE_WHITE_BLACK_TRANSPARENT, XINE_OSD_TEXT1);
-
-  gGui->osd.info.osd[0] = xine_osd_new(gGui->stream, 0, 0, 2048, fonth + (fonth >> \
                1));
-  xine_osd_set_font(gGui->osd.info.osd[0], "sans", fonth);
-  xine_osd_set_text_palette(gGui->osd.info.osd[0], 
-			    XINE_TEXTPALETTE_WHITE_BLACK_TRANSPARENT, XINE_OSD_TEXT1);
+  /* Trim text until it fits in "maxw". The
+     text is cut off at the left side */
+
+  char *p = buf;
+  xine_osd_get_text_size(osd, buf, tw, th);
+
+  while(*tw > maxw) {
+    *(p++) = '\0';
+    *(p)   = '.';
+    *(p+1) = '.';
+    *(p+2) = '.';
+    xine_osd_get_text_size(osd, p, tw, th);
+  }
+
+  if(p > buf) {
+    memmove(buf, p, strlen(p) + 1);
+  }
+}
+
+static void _osd_rtrim_text(xine_osd_t *osd, char *buf, int maxw, int *tw, int *th) \
{ +
+  /* Trim text until it fits in "maxw". The
+     text is cut off at the right side */
+  xine_osd_get_text_size(osd, buf, tw, th);
+
+  while(*tw > maxw) {
+    int i = strlen(buf);
+    buf[i-1] = '\0';
+    buf[i-2]   = '.';
+    buf[i-3]   = '.';
+    buf[i-4]   = '.';
+    xine_osd_get_text_size(osd, buf, tw, th);
+  }
+}
+
+static void _osd_fontsize_cb(void *user_data, xine_cfg_entry_t *entry) {
+
+  osd_fontsize = entry->num_value;
+}
+
+static void _osd_fontcolor_cb(void *user_data, xine_cfg_entry_t *entry) {
+
+  osd_fontcolor = _get_xine_color(entry->num_value);
+}
+
+static void _osd_background_cb(void *user_data, xine_cfg_entry_t *entry) {
+
+  osd_background = entry->num_value;
+}
+
+void osd_init(void) {
+
+  osd_fontsize = xine_config_register_range(
+    __xineui_global_xine_instance, "gui.osd.fontsize",
+    DEF_OSD_FONTSIZE, MIN_ODS_FONTSIZE, MAX_OSD_FONTSIZE,
+    _("font size for OSD text"),
+    CONFIG_NO_HELP, CONFIG_LEVEL_ADV, _osd_fontsize_cb, CONFIG_NO_DATA
+  );
+
+  osd_fontcolor = _get_xine_color(
+    xine_config_register_enum(
+      __xineui_global_xine_instance, "gui.osd.fontcolor",
+      DEF_OSD_FONTCOLOR,
+      osd_fontcolors,
+      _("OSD font colors: white, yellow, green"),
+      CONFIG_NO_HELP, CONFIG_LEVEL_ADV, _osd_fontcolor_cb, CONFIG_NO_DATA
+    )
+  );
+
+  osd_background = xine_config_register_bool(
+    __xineui_global_xine_instance, "gui.osd.background",
+    DEF_OSD_BACKGROUND,
+    _("draw background to increase readibility of text"),
+    CONFIG_NO_HELP, CONFIG_LEVEL_ADV, _osd_background_cb, CONFIG_NO_DATA
+  );
+
+  memcpy(color, textpalettes_color, sizeof(textpalettes_color));
+  memcpy(trans, textpalettes_trans, sizeof(textpalettes_trans));
+
+  /* create STREAM INFO */
+  gGui->osd.sinfo.osd = xine_osd_new(gGui->stream,
+    0, 0, 2048, (MAX_OSD_FONTHEIGHT * 10) + (OSD_TEXTMARGIN_H * 2) + 1);
+  xine_osd_set_palette(gGui->osd.sinfo.osd, color, trans);
+
+  /* create BAR */
+  gGui->osd.bar.osd = xine_osd_new(gGui->stream,
+    0, 0, 2048, MAX_OSD_FONTHEIGHT + BAR_HEIGHT + (OSD_TEXTMARGIN_H * 3) + 1);
+  xine_osd_set_palette(gGui->osd.bar.osd, color, trans);
+
+  /* create STATUS */
+  gGui->osd.status.osd = xine_osd_new(gGui->stream,
+    0, 0, 2048, MAX_OSD_FONTHEIGHT + (OSD_TEXTMARGIN_H * 2) + 1);
+  xine_osd_set_palette(gGui->osd.status.osd, color, trans);
+
+  /* create INFO */
+  gGui->osd.info.osd = xine_osd_new(gGui->stream,
+    0, 0, 2048, MAX_OSD_FONTHEIGHT + (OSD_TEXTMARGIN_H * 2) + 1);
+  xine_osd_set_palette(gGui->osd.info.osd, color, trans);
+
+  /* create MENU */
+  gGui->osd.menu.osd = xine_osd_new(gGui->stream,
+    0, 0, 2048, (MAX_OSD_FONTHEIGHT * 10) + (OSD_TEXTMARGIN_H * 2) + 1);
+  xine_osd_set_palette(gGui->osd.menu.osd, color, trans);
 
   gGui->osd.unscaled_available =
-    (xine_osd_get_capabilities(gGui->osd.status.osd[0]) & XINE_OSD_CAP_UNSCALED );
+    (xine_osd_get_capabilities(gGui->osd.status.osd) & XINE_OSD_CAP_UNSCALED );
 
   pthread_mutex_init(&osd_mutex, NULL);
 }
@@ -185,7 +370,7 @@
   pthread_mutex_lock(&osd_mutex);
   if(gGui->osd.sinfo.visible) {
     gGui->osd.sinfo.visible = 0;
-    xine_osd_hide(gGui->osd.sinfo.osd[0], 0);
+    xine_osd_hide(gGui->osd.sinfo.osd, 0);
   }
   pthread_mutex_unlock(&osd_mutex);
 }
@@ -195,9 +380,8 @@
   pthread_mutex_lock(&osd_mutex);
   if(gGui->osd.bar.visible) {
     gGui->osd.bar.visible = 0;
-    xine_osd_hide(gGui->osd.bar.osd[0], 0);
-    xine_osd_hide(gGui->osd.bar.osd[1], 0);
-  } 
+    xine_osd_hide(gGui->osd.bar.osd, 0);
+  }
   pthread_mutex_unlock(&osd_mutex);
 }
 
@@ -206,7 +390,7 @@
   pthread_mutex_lock(&osd_mutex);
   if(gGui->osd.status.visible) {
     gGui->osd.status.visible = 0;
-    xine_osd_hide(gGui->osd.status.osd[0], 0);
+    xine_osd_hide(gGui->osd.status.osd, 0);
   } 
   pthread_mutex_unlock(&osd_mutex);
 }
@@ -216,7 +400,17 @@
   pthread_mutex_lock(&osd_mutex);
   if(gGui->osd.info.visible) {
     gGui->osd.info.visible = 0;
-    xine_osd_hide(gGui->osd.info.osd[0], 0);
+    xine_osd_hide(gGui->osd.info.osd, 0);
+  } 
+  pthread_mutex_unlock(&osd_mutex);
+}
+
+void osd_hide_menu(void) {
+
+  pthread_mutex_lock(&osd_mutex);
+  if(gGui->osd.menu.visible) {
+    gGui->osd.menu.visible = 0;
+    xine_osd_hide(gGui->osd.menu.osd, 0);
   } 
   pthread_mutex_unlock(&osd_mutex);
 }
@@ -227,17 +421,18 @@
   osd_hide_bar();
   osd_hide_status();
   osd_hide_info();
+  osd_hide_menu();
 }
 
 void osd_deinit(void) {
 
   osd_hide();
 
-  xine_osd_free(gGui->osd.sinfo.osd[0]);
-  xine_osd_free(gGui->osd.bar.osd[0]);
-  xine_osd_free(gGui->osd.bar.osd[1]);
-  xine_osd_free(gGui->osd.status.osd[0]);
-  xine_osd_free(gGui->osd.info.osd[0]);
+  xine_osd_free(gGui->osd.sinfo.osd);
+  xine_osd_free(gGui->osd.bar.osd);
+  xine_osd_free(gGui->osd.status.osd);
+  xine_osd_free(gGui->osd.info.osd);
+  xine_osd_free(gGui->osd.menu.osd);
 
   pthread_mutex_destroy(&osd_mutex);
 }
@@ -249,47 +444,66 @@
   if(gGui->osd.sinfo.visible) {
     gGui->osd.sinfo.visible--;
     if(!gGui->osd.sinfo.visible) {
-      xine_osd_hide(gGui->osd.sinfo.osd[0], 0);
+      xine_osd_hide(gGui->osd.sinfo.osd, 0);
     }
   }
 
   if(gGui->osd.bar.visible) {
     gGui->osd.bar.visible--;
     if(!gGui->osd.bar.visible) {
-      xine_osd_hide(gGui->osd.bar.osd[0], 0);
-      xine_osd_hide(gGui->osd.bar.osd[1], 0);
+      xine_osd_hide(gGui->osd.bar.osd, 0);
     }
   }
 
   if(gGui->osd.status.visible) {
     gGui->osd.status.visible--;
     if(!gGui->osd.status.visible) {
-      xine_osd_hide(gGui->osd.status.osd[0], 0);
+      xine_osd_hide(gGui->osd.status.osd, 0);
     }
   }
 
   if(gGui->osd.info.visible) {
     gGui->osd.info.visible--;
     if(!gGui->osd.info.visible) {
-      xine_osd_hide(gGui->osd.info.osd[0], 0);
+      xine_osd_hide(gGui->osd.info.osd, 0);
     }
   }
-
   pthread_mutex_unlock(&osd_mutex);
 }
 
+static void osd_show_sinfo(int settimer) {
+
+  int x, y, wwidth, wheight;
+  _osd_get_output_size(&wwidth, &wheight);
+
+  x = OSD_MARGIN_W;
+  y = MAX_OSD_FONTHEIGHT + OSD_MARGIN_H + OSD_TEXTMARGIN_H;
+
+  xine_osd_set_position(gGui->osd.sinfo.osd, (x >= 0) ? x : 0, (y >= 0) ? y : 0);
+
+  if( wwidth > MINIMUM_WIN_WIDTH ) {
+    pthread_mutex_lock(&osd_mutex);
+    _xine_osd_show(gGui->osd.sinfo.osd, 0);
+    if (settimer)
+      gGui->osd.sinfo.visible = gGui->osd.timeout;
+    pthread_mutex_unlock(&osd_mutex);
+  }
+}
+
 void osd_stream_infos(void) {
 
   if(gGui->osd.enabled) {
     int         vwidth, vheight, asrate;
     int         wwidth, wheight;
     const char *vcodec, *acodec;
-    char        buffer[256], *p;
-    int         x, y;
-    int         w, h, osdw;
+    int         i, x, y, w, h, tw, th;
     int         playedtime, playeddays, totaltime, pos;
     int         audiochannel, spuchannel, len;
 
+    /* streaminfo has 10 lines */
+    #define     NUMLINES 10
+    char        b[NUMLINES][256];
+
     vcodec       = xine_get_meta_info(gGui->stream, XINE_META_INFO_VIDEOCODEC);
     acodec       = xine_get_meta_info(gGui->stream, XINE_META_INFO_AUDIOCODEC);
     vwidth       = xine_get_stream_info(gGui->stream, XINE_STREAM_INFO_VIDEO_WIDTH);
@@ -304,7 +518,7 @@
     playedtime /= 1000;
     totaltime  /= 1000;
 
-    xine_osd_clear(gGui->osd.sinfo.osd[0]);
+    xine_osd_clear(gGui->osd.sinfo.osd);
 
     /* We're in visual animation mode */
     if((vwidth == 0) && (vheight == 0)) {
@@ -327,114 +541,135 @@
 
     _osd_get_output_size(&wwidth, &wheight);
 
-    y = x = 0;
+    xine_osd_set_font(gGui->osd.sinfo.osd, OSD_FONTFACE_REGULAR, osd_fontsize);
 
-    strlcpy(buffer, (gGui->is_display_mrl) ? gGui->mmk.mrl : gGui->mmk.ident, \
                sizeof(buffer));
-    xine_osd_get_text_size(gGui->osd.sinfo.osd[0], buffer, &osdw, &h);
-    p = buffer;
-    while(osdw > (wwidth - 40)) {
-      *(p++) = '\0';
-      *(p)   = '.';
-      *(p+1) = '.';
-      *(p+2) = '.';
-      xine_osd_get_text_size(gGui->osd.sinfo.osd[0], p, &osdw, &h);
-    }
-    xine_osd_draw_text(gGui->osd.sinfo.osd[0], x, y, p, XINE_OSD_TEXT1);
-    
-    y += h;
-    
+    /* GET MRL */
+    snprintf(b[0], sizeof(b[0]), "%s:", _("Stream MRL"));
+    snprintf(b[1], sizeof(b[1]), OSD_TEXTINDENT "%s", (gGui->is_display_mrl) ? \
gGui->mmk.mrl : gGui->mmk.ident); +    _osd_ltrim_text(
+      gGui->osd.sinfo.osd, b[1], (wwidth - (OSD_MARGIN_W << 1) - (OSD_TEXTMARGIN_W \
<< 1)), &w, &h); +
+    /* GET VCODEC */
+    snprintf(b[2], sizeof(b[2]), "%s:", _("Video Codec"));
     if(vcodec && vwidth && vheight) {
-      snprintf(buffer, sizeof(buffer), "%s: %dX%d", vcodec, vwidth, vheight);
-      xine_osd_draw_text(gGui->osd.sinfo.osd[0], x, y, buffer, XINE_OSD_TEXT1);
-      xine_osd_get_text_size(gGui->osd.sinfo.osd[0], buffer, &w, &h);
-      if(w > osdw)
-	osdw = w;
-      y += h;
+      snprintf(b[3], sizeof(b[3]), OSD_TEXTINDENT "%s, %dX%d", vcodec, vwidth, \
vheight); +    }
+    else {
+      snprintf(b[3], sizeof(b[3]), OSD_TEXTINDENT "%s", _("none"));
     }
 
+    /* GET ACODEC */
+    snprintf(b[4], sizeof(b[4]), "%s:", _("Audio Codec"));
     if(acodec && asrate) {
-      snprintf(buffer, sizeof(buffer), "%s: %d%s", acodec, asrate, "Hz");
-      xine_osd_draw_text(gGui->osd.sinfo.osd[0], x, y, buffer, XINE_OSD_TEXT1);
-      xine_osd_get_text_size(gGui->osd.sinfo.osd[0], buffer, &w, &h);
-      if(w > osdw)
-	osdw = w;
-      y += h;
+      snprintf(b[5], sizeof(b[5]), OSD_TEXTINDENT "%s, %d%s", acodec, asrate, "Hz");
     }
-    
-    strlcpy(buffer, _("Audio: "), sizeof(buffer));
-    len = strlen(buffer);
+    else {
+      snprintf(b[5], sizeof(b[5]), OSD_TEXTINDENT "%s", _("none"));
+    }
+
+    /* GET AUDIO PARMS*/
+    snprintf(b[6], sizeof(b[6]), "%s:", _("Audio Parameters"));
+
+    snprintf(b[7], sizeof(b[7]), OSD_TEXTINDENT "%s: ", _("Audio"));
+    len = strlen(b[7]);
+
     switch(audiochannel) {
     case -2:
-      strlcat(buffer, "off", sizeof(buffer));
+      strlcat(b[7], _("off"), sizeof(b[7]));
       break;
     case -1:
-      if(!xine_get_audio_lang (gGui->stream, audiochannel, &buffer[len]))
-	strlcat(buffer, "auto", sizeof(buffer));
+      if(!xine_get_audio_lang (gGui->stream, audiochannel, &b[7][len]))
+	strlcat(b[7], _("auto"), sizeof(b[7]));
       break;
     default:
-      if(!xine_get_audio_lang (gGui->stream, audiochannel, &buffer[len]))
-	snprintf(buffer+strlen(buffer), sizeof(buffer)-strlen(buffer), "%3d", \
audiochannel); +      if(!xine_get_audio_lang (gGui->stream, audiochannel, \
&b[7][len])) +	snprintf(b[7]+strlen(b[7]), sizeof(b[7])-strlen(b[7]), "%3d", \
audiochannel);  break;
     }
 
-    strlcat(buffer, ", Spu: ", sizeof(buffer));
-    len = strlen(buffer);
+    snprintf(b[7]+strlen(b[7]), sizeof(b[7])-strlen(b[7]), ", %s: ", _("Spu"));
+    len = strlen(b[7]);
     switch (spuchannel) {
     case -2:
-      strlcat(buffer, "off", sizeof(buffer));
+      strlcat(b[7], _("off"), sizeof(b[7]));
       break;
     case -1:
-      if(!xine_get_spu_lang (gGui->stream, spuchannel, &buffer[len]))
-	strlcat(buffer, "auto", sizeof(buffer));
+      if(!xine_get_spu_lang (gGui->stream, spuchannel, &b[7][len]))
+	strlcat(b[7], _("auto"), sizeof(b[7]));
       break;
     default:
-      if(!xine_get_spu_lang (gGui->stream, spuchannel, &buffer[len]))
-        snprintf(buffer+strlen(buffer), sizeof(buffer)-strlen(buffer), "%3d", \
spuchannel); +      if(!xine_get_spu_lang (gGui->stream, spuchannel, &b[7][len]))
+        snprintf(b[7]+strlen(b[7]), sizeof(b[7])-strlen(b[7]), "%3d", spuchannel);
       break;
     }
-    strlcat(buffer, ".", sizeof(buffer));
-    xine_osd_draw_text(gGui->osd.sinfo.osd[0], x, y, buffer, XINE_OSD_TEXT1);
-    xine_osd_get_text_size(gGui->osd.sinfo.osd[0], buffer, &w, &h);
-    if(w > osdw)
-      osdw = w;
-    
-    y += (h);
+    strlcat(b[7], ".", sizeof(b[7]));
 
+    /* GET PLAYTIME */
+    snprintf(b[8], sizeof(b[8]), "%s:", _("Play Time"));
     playeddays = playedtime / (3600 * 24);
-    
+
     if(playeddays > 0)
-      sprintf(buffer, "%d::%02d ", playeddays, playedtime / 3600);
+      sprintf(b[9], OSD_TEXTINDENT "%d::%02d ", playeddays, playedtime / 3600);
     else
-      sprintf(buffer, "%d:%02d:%02d ", playedtime / 3600, (playedtime % 3600) / 60, \
playedtime % 60); +      sprintf(b[9], OSD_TEXTINDENT "%d:%02d:%02d ", playedtime / \
3600, (playedtime % 3600) / 60, playedtime % 60);  
     if(totaltime > 0) {
       int totaldays;
       
       totaldays  = totaltime / (3600 * 24);
-      sprintf(buffer+strlen(buffer), "(%.0f%%) %s ", ((float)playedtime / \
(float)totaltime) * 100, _("of")); +      sprintf(b[9]+strlen(b[9]), "(%.0f%%) %s ", \
((float)playedtime / (float)totaltime) * 100, _("of"));  
       if(totaldays > 0)
-	sprintf(buffer+strlen(buffer), "%d::%02d", totaldays, totaltime / 3600);
+	sprintf(b[9]+strlen(b[9]), "%d::%02d", totaldays, totaltime / 3600);
       else
-	sprintf(buffer+strlen(buffer), "%d:%02d:%02d", totaltime / 3600, (totaltime % 3600) \
/ 60, totaltime % 60); +	sprintf(b[9]+strlen(b[9]), "%d:%02d:%02d", totaltime / 3600, \
(totaltime % 3600) / 60, totaltime % 60);  }
-    
-    xine_osd_draw_text(gGui->osd.sinfo.osd[0], x, y, buffer, XINE_OSD_TEXT1);
-    xine_osd_get_text_size(gGui->osd.sinfo.osd[0], buffer, &w, &h);
-    if(w > osdw)
-      osdw = w;
-    
-    osd_stream_position(pos);
-    
-    x = (wwidth - osdw) - 40;
-    xine_osd_set_position(gGui->osd.sinfo.osd[0], (x >= 0) ? x : 0, 15);
-    gGui->osd.sinfo.x = (x >= 0) ? x : 0;
-    gGui->osd.sinfo.y = 15;
-    gGui->osd.sinfo.w = osdw;
 
+    /* DETERMINE DIMENSIONS */
+    tw = 0;
+    th = 0;
+
+    for(i = 0; i < NUMLINES; i++) {
+      _osd_rtrim_text(
+        gGui->osd.sinfo.osd, b[i], (wwidth - (OSD_MARGIN_W << 1) - (OSD_TEXTMARGIN_W \
<< 1)), &w, &h); +      tw = (tw < w ? w : tw); th = (th < h ? h : th);
+    }
+
+    /* DRAW */
+    h = th;
+    tw = tw + (OSD_TEXTMARGIN_W << 1);
+    th = 10 * (h + OSD_TEXTMARGIN_H) + OSD_TEXTMARGIN_H;
+    x = OSD_TEXTMARGIN_W;
+    y = OSD_TEXTMARGIN_H;
+
+    if (osd_background) {
+      xine_osd_draw_rect(gGui->osd.sinfo.osd, 0, 0, tw + 1, th + 1, osd_fontcolor + \
1, 1); +    }
+
+    for(i = 0; i < NUMLINES; i++) {
+      xine_osd_draw_text(gGui->osd.sinfo.osd, x, y + (h + OSD_TEXTMARGIN_H) * i, \
b[i], osd_fontcolor); +    }
+
+    gGui->osd.sinfo.w = tw;
+    gGui->osd.sinfo.h = th;
+
+    osd_show_sinfo(1);
+  }
+}
+
+static void osd_show_bar(int settimer) {
+
+  int x, wwidth, wheight;
+  _osd_get_output_size(&wwidth, &wheight);
+
+  x = (wwidth - gGui->osd.bar.w) >> 1;
+  xine_osd_set_position(gGui->osd.bar.osd, (x >= 0) ? x : 0, (wheight - \
gGui->osd.bar.h) - (OSD_MARGIN_H * 3)); +
+  if( wwidth > MINIMUM_WIN_WIDTH ) {
     pthread_mutex_lock(&osd_mutex);
-    _xine_osd_show(gGui->osd.sinfo.osd[0], 0);
-    gGui->osd.sinfo.visible = gGui->osd.timeout;
+    _xine_osd_show(gGui->osd.bar.osd, 0);
+    if (settimer)
+      gGui->osd.bar.visible = gGui->osd.timeout;
     pthread_mutex_unlock(&osd_mutex);
   }
 }
@@ -444,10 +679,11 @@
   if(gGui->osd.enabled) {
     int      wwidth, wheight;
     int      bar_color[40];
-    int      i, x;
+    int      i, x, y;
     float    _val = (int) val;
     float    _min = (int) min;
     float    _max = (int) max;
+    int      bw, bh, tw, th, offsetx, offsety;
     int      pos;
     
     if(max <= min)
@@ -461,98 +697,147 @@
     
     pos = (int) (_val + -_min) / ((_max + -_min) / 40);
     
-    _osd_get_output_size(&wwidth, &wheight);
-
-    xine_osd_clear(gGui->osd.bar.osd[0]);
-    xine_osd_clear(gGui->osd.bar.osd[1]);
-    
+    /* initialize the bar color to XINE_OSD_TEXT1 */
     memset(&bar_color, (XINE_OSD_TEXT1 + 7), sizeof(int) * 40);
-    
+
     switch(type) {
     case OSD_BAR_PROGRESS:
     case OSD_BAR_STEPPER:
-      if(pos)
-	memset(bar_color, (XINE_OSD_TEXT1 + 21), sizeof(int) * pos);
+      if(pos) {
+        /* set the first 'pos' entries to osd_fontcolor */
+        memset(bar_color, osd_fontcolor + 7 , sizeof(int) * pos);
+      }
       break;
     case OSD_BAR_POS:
     case OSD_BAR_POS2:
-      if(pos)
-	bar_color[pos - 1] = (XINE_OSD_TEXT1 + 21);
+      if(pos) {
+       /* set the current 'pos' entry to osd_fontcolor */
+	bar_color[pos - 1] = osd_fontcolor + 10;
+      }
       break;
     }
-    
+
+    _osd_get_output_size(&wwidth, &wheight);
+
+    xine_osd_clear(gGui->osd.bar.osd);
+
+    /* bar dimensions */
+    bw = BAR_WIDTH + (OSD_TEXTMARGIN_W << 1);
+    bh = BAR_HEIGHT + (OSD_TEXTMARGIN_H << 1);
+
+    /* DRAW TITLE */
+    if(title) {
+
+      /* prepare for drawing text */      
+      xine_osd_set_font(gGui->osd.bar.osd, OSD_FONTFACE_REGULAR, osd_fontsize);
+      xine_osd_get_text_size(gGui->osd.bar.osd, title, &tw, &th);
+
+      /* text dimensions */
+      tw = tw + (OSD_TEXTMARGIN_W << 1);
+      th = th + OSD_TEXTMARGIN_H;
+
+      if (tw < bw) {
+        /* bar is wider than title */
+        offsetx = ((bw - tw) >> 1) + OSD_TEXTMARGIN_W;
+      }
+      else {
+        offsetx = OSD_TEXTMARGIN_W;
+      }
+
+      offsety = OSD_TEXTMARGIN_H;     
+
+      if (osd_background) {
+        xine_osd_draw_rect(gGui->osd.bar.osd, 0, 0, MAX(tw, bw) + 1, th + 1, \
osd_fontcolor + 1, 1); +      }
+
+      xine_osd_draw_text(gGui->osd.bar.osd, offsetx, offsety, title, osd_fontcolor);
+    }
+    else {
+      th = 0;
+      tw = 0;
+    }
+
+    /* DRAW BAR */
+    if (tw > bw) {
+      /* title is wider than bar */
+      offsetx = ((tw - bw) >> 1) + OSD_TEXTMARGIN_W;
+    }
+    else {
+      offsetx = OSD_TEXTMARGIN_W;
+    }
+
+    /* position bar below title */
+    offsety = th + OSD_TEXTMARGIN_H;
+
+    if (osd_background) {
+      xine_osd_draw_rect(gGui->osd.bar.osd, 0, th, MAX(tw, bw) + 1, th + bh + 1, \
osd_fontcolor + 1, 1); +    }
+
     if((type == OSD_BAR_PROGRESS) || (type == OSD_BAR_POS)) {
-      x = 3;
-      xine_osd_draw_rect(gGui->osd.bar.osd[0], x, 2, x + 3, BAR_HEIGHT - 2, \
XINE_OSD_TEXT1 + 9, 1); +
+      /* draw bar with left size of 
+         'pos' in foreground color */
+
+      x = offsetx + 3;
+      y = offsety;
+      xine_osd_draw_rect(gGui->osd.bar.osd,
+                         x, y + 2, x + 3, y + BAR_HEIGHT - 2, osd_fontcolor + 9, 1);
       x += 8;
-      
+
       for(i = 0; i < 40; i++, x += 8) {
-	xine_osd_draw_rect(gGui->osd.bar.osd[0],
-			   x, 6, x + 3, BAR_HEIGHT - 2, bar_color[i], 1);
+	xine_osd_draw_rect(gGui->osd.bar.osd,
+			   x, y + 6, x + 3, y + BAR_HEIGHT - 2, bar_color[i], 1);
       }
-      
-      xine_osd_draw_rect(gGui->osd.bar.osd[0],
-			 x, 2, x + 3, BAR_HEIGHT - 2, XINE_OSD_TEXT1 + 9, 1);
+
+      xine_osd_draw_rect(gGui->osd.bar.osd,
+			 x, y + 2, x + 3, y + BAR_HEIGHT - 2, osd_fontcolor + 9, 1);
     }
     else if(type == OSD_BAR_POS2) {
-      x = 3;
-      xine_osd_draw_rect(gGui->osd.bar.osd[0], x, 2, x + 3, BAR_HEIGHT - 2, \
XINE_OSD_TEXT1 + 9, 1); +
+      /* draw bar with the current 
+         'pos' in foreground color */
+
+      x = offsetx + 3;
+      y = offsety;
+      xine_osd_draw_rect(gGui->osd.bar.osd,
+                         x, y + 2, x + 3, y + BAR_HEIGHT - 2, osd_fontcolor + 9, 1);
       x += 8;
-      
+
       for(i = 0; i < 40; i++, x += 8) {
 	if(i == (pos - 1))
-	  xine_osd_draw_rect(gGui->osd.bar.osd[0],
-			     x, 2, x + 3, BAR_HEIGHT - 2, bar_color[i], 1);
+	  xine_osd_draw_rect(gGui->osd.bar.osd,
+			     x - 1, y + 2, x + 4, y + BAR_HEIGHT - 2, bar_color[i], 1);
 	else
-	  xine_osd_draw_rect(gGui->osd.bar.osd[0],
-			     x, 6, x + 3, BAR_HEIGHT - 6, bar_color[i], 1);
+	  xine_osd_draw_rect(gGui->osd.bar.osd,
+			     x, y + 6, x + 3, y + BAR_HEIGHT - 6, bar_color[i], 1);
       }
       
-      xine_osd_draw_rect(gGui->osd.bar.osd[0],
-			 x, 2, x + 3, BAR_HEIGHT - 2, XINE_OSD_TEXT1 + 9, 1);
+      xine_osd_draw_rect(gGui->osd.bar.osd,
+			 x, y + 2, x + 3, y + BAR_HEIGHT - 2, osd_fontcolor + 9, 1);
     }
     else if(type == OSD_BAR_STEPPER) {
-      int y = BAR_HEIGHT - 4;
-      int step = y / 20;
-      
-      x = 11;
+
+      /* draw bar with left size of 
+         'pos' in foreground color */
+
+      int step = 0;
+      x = offsetx + 11;
+      y = offsety + BAR_HEIGHT;
       
       for(i = 0; i < 40; i++, x += 8) {
-	xine_osd_draw_rect(gGui->osd.bar.osd[0],
-			   x, y, x + 3, BAR_HEIGHT - 2, bar_color[i], 1);
+	xine_osd_draw_rect(gGui->osd.bar.osd,
+			   x, y - 4 - step, x + 3, offsety + BAR_HEIGHT - 2, bar_color[i], 1);
 	
 	if(!(i % 2))
-	  y -= step;
+	  step += ((BAR_HEIGHT - 4) / 20);
 	
       }
     }
-    
-    if(title) {
-      int  tw, th;
-      
-      gGui->osd.bar.have_text = 1;
-      
-      xine_osd_get_text_size(gGui->osd.bar.osd[1], title, &tw, &th);
-      xine_osd_draw_text(gGui->osd.bar.osd[1], (BAR_WIDTH - tw) >> 1, 0, title, \
                XINE_OSD_TEXT1);
-    }
-    else
-      gGui->osd.bar.have_text = 0;
-    
-    x = (wwidth - BAR_WIDTH) >> 1;
-    xine_osd_set_position(gGui->osd.bar.osd[0], (x >= 0) ? x : 0, (wheight - \
                BAR_HEIGHT) - 40);
-    xine_osd_set_position(gGui->osd.bar.osd[1], (x >= 0) ? x : 0, (wheight - \
                (BAR_HEIGHT * 2)) - 40);
-    
-    /* don't even bother drawing osd over those small streams.
-     * it would look pretty bad.
-     */
-    if( wwidth > MINIMUM_WIN_WIDTH ) {
-      pthread_mutex_lock(&osd_mutex);
-      _xine_osd_show(gGui->osd.bar.osd[0], 0);
-      if(title)
-        _xine_osd_show(gGui->osd.bar.osd[1], 0);
-      gGui->osd.bar.visible = gGui->osd.timeout;
-      pthread_mutex_unlock(&osd_mutex);
-    }
+
+    gGui->osd.bar.w = MAX(tw, bw);
+    gGui->osd.bar.h = th + bh;
+
+    osd_show_bar(1);    
   }
 }
 
@@ -560,16 +845,34 @@
   osd_draw_bar(_("Position in Stream"), 0, 65535, pos, OSD_BAR_POS2);
 }
 
+static void osd_show_info(int settimer) {
+
+  int wwidth, wheight;
+  _osd_get_output_size(&wwidth, &wheight);
+
+  xine_osd_set_position(gGui->osd.info.osd, 0, OSD_MARGIN_H);
+
+  if( wwidth > MINIMUM_WIN_WIDTH ) {
+    pthread_mutex_lock(&osd_mutex);
+    _xine_osd_show(gGui->osd.info.osd, 0);
+    if (settimer)
+      gGui->osd.info.visible = gGui->osd.timeout;
+    pthread_mutex_unlock(&osd_mutex);
+  }
+}
+
 void osd_display_info(char *info, ...) {
 
   if(gGui->osd.enabled && !gGui->on_quit) {
-    va_list   args;
+    va_list  args;
     char     *buf;
-    int       n, size = 100;
+    int      n, size = 100;
+    int      tw, th;
+    int      wwidth, wheight;
     
     if((buf = xine_xmalloc(size)) == NULL) 
       return;
-    
+
     while(1) {
       
       va_start(args, info);
@@ -588,30 +891,164 @@
 	return;
     }
 
-    xine_osd_clear(gGui->osd.info.osd[0]);
+    _osd_get_output_size(&wwidth, &wheight);
+
+    xine_osd_clear(gGui->osd.info.osd);
+    xine_osd_set_font(gGui->osd.info.osd, OSD_FONTFACE_REGULAR, osd_fontsize);
+
+    _osd_rtrim_text(
+      gGui->osd.info.osd, buf, (wwidth - (OSD_MARGIN_W << 1) - (OSD_TEXTMARGIN_W << \
1)), &tw, &th); +
+    tw = tw + (OSD_TEXTMARGIN_W << 1);
+    th = th + (OSD_TEXTMARGIN_H << 1);
 
-    xine_osd_draw_text(gGui->osd.info.osd[0], 0, 0, buf, XINE_OSD_TEXT1);
-    xine_osd_set_position(gGui->osd.info.osd[0], 20, 10 + 30);
+    if (osd_background) {
+      xine_osd_draw_rect(gGui->osd.info.osd, 0, 0, wwidth + 1, th + 1, osd_fontcolor \
+ 1, 1); +    }
+
+    xine_osd_draw_text(gGui->osd.info.osd, OSD_MARGIN_W + OSD_TEXTMARGIN_W, \
OSD_TEXTMARGIN_H, buf, osd_fontcolor);  
+    gGui->osd.info.w = tw;
+    gGui->osd.info.h = th;
+
+    osd_show_info(1);
+    SAFE_FREE(buf);
+  }
+}
+
+static void osd_show_menu() {
+
+  int w, h, wwidth, wheight;
+  _osd_get_output_size(&wwidth, &wheight);
+
+  w = (wwidth - gGui->osd.menu.w) >> 1;
+  h = (wheight - gGui->osd.menu.h) >> 1;
+
+  xine_osd_set_position(gGui->osd.menu.osd, w, h);
+
+  if( wwidth > MINIMUM_WIN_WIDTH ) {
     pthread_mutex_lock(&osd_mutex);
-    _xine_osd_show(gGui->osd.info.osd[0], 0);
-    gGui->osd.info.visible = gGui->osd.timeout;
+    _xine_osd_show(gGui->osd.menu.osd, 0);
+    gGui->osd.menu.visible = 1;
     pthread_mutex_unlock(&osd_mutex);
+  }
+}
 
-    SAFE_FREE(buf);
+void osd_display_menu(char* title, char **items, int n) {
+
+/*
+   Title
+   -----------
+   1. Option A
+   2. Option B
+   3. Option C
+   ...
+*/
+
+  if(gGui->osd.enabled && !gGui->on_quit) {
+    int      tw = 0, th = 0;
+    int      w_title = 0, h_title = 0;
+    int      w_index = 0, h_index = 0;
+    int      w_item = 0, h_item = 0;
+    int      i, w, h, x, y, maxwidth, wwidth, wheight;
+    char     buf[4];
+
+    if (n <= 0)
+      return;
+
+    n = MIN(n, OSD_CUSTMENU_MAXOPT);
+
+    _osd_get_output_size(&wwidth, &wheight);
+
+    xine_osd_clear(gGui->osd.menu.osd);
+    xine_osd_set_font(gGui->osd.menu.osd, OSD_FONTFACE_REGULAR, osd_fontsize);
+
+    /* TITLE DIMENSINS */
+    if (title) {
+      xine_osd_get_text_size(gGui->osd.menu.osd, title, &w_title, &h_title);
+      th += h_title + (OSD_TEXTMARGIN_H << 1);
+    }
+
+    /* INDEX NUMBER DIMENSIONS */
+    for(i = 0; i < n; i++) {
+      sprintf(buf, "%d.", i+1);
+      xine_osd_get_text_size(gGui->osd.menu.osd, buf, &w, &h);
+      w_index = MAX(w, w_index);
+      h_index = MAX(h, h_index);
+    }
+
+    /* DETERMINE ITEM DIMENSIONS */
+    maxwidth = (wwidth - (w_index << 1) - (OSD_MARGIN_W << 1) - (OSD_TEXTMARGIN_W << \
1)); +    for(i = 0; i < n; i++) {
+      xine_osd_get_text_size(gGui->osd.menu.osd, items[i], &w, &h);
+      w_item = MAX(w, w_item);
+      h_item = MAX(h, h_item);
+      th += MAX(h_index, h_item);
+    }
+
+    th += (OSD_TEXTMARGIN_H << 1);
+    tw = MAX(w_title, (w_index << 1) + w_item) + (OSD_TEXTMARGIN_W << 1);
+
+    /* DRAW */
+    x = OSD_TEXTMARGIN_W;
+    y = OSD_TEXTMARGIN_H;
+
+    if (osd_background) {
+      xine_osd_draw_rect(gGui->osd.menu.osd, 0, 0, tw + 1, th + 1, osd_fontcolor + \
1, 1); +      xine_osd_draw_rect(gGui->osd.menu.osd, 0, 0, tw, th, XINE_OSD_TEXT1 + \
10, 0); +    }
+
+    if (title) {
+      xine_osd_draw_text(gGui->osd.menu.osd, x, y, title, osd_fontcolor);
+      xine_osd_draw_line(gGui->osd.menu.osd,
+                         x, y + h_title + OSD_TEXTMARGIN_H,
+                         tw - (OSD_TEXTMARGIN_W << 1) + 1, y + h_title + \
OSD_TEXTMARGIN_H, +                         XINE_OSD_TEXT1 + 10);
+      y += h_title + (OSD_TEXTMARGIN_H << 1);
+    }
+
+    for(i = 0; i < n; i++) {
+      sprintf(buf, "%d.", i + 1);
+      xine_osd_draw_text(gGui->osd.menu.osd, x, y, buf, osd_fontcolor);
+      xine_osd_draw_text(gGui->osd.menu.osd, x + (w_index << 1), y, items[i], \
osd_fontcolor); +      y += h_item;
+    }
+
+    gGui->osd.menu.w = tw;
+    gGui->osd.menu.h = th;
+
+    osd_show_menu();
   }
 }
 
+static void osd_show_status(int settimer) {
+
+  int x, y, wwidth, wheight;
+  _osd_get_output_size(&wwidth, &wheight);
+
+  x = wwidth - gGui->osd.status.w - OSD_MARGIN_W;
+  y = MAX_OSD_FONTHEIGHT + OSD_MARGIN_H + OSD_TEXTMARGIN_H;
+
+  xine_osd_set_position(gGui->osd.status.osd, x, y);
+
+  if( wwidth > MINIMUM_WIN_WIDTH ) {
+    pthread_mutex_lock(&osd_mutex);
+    _xine_osd_show(gGui->osd.status.osd, 0);
+    if (settimer)
+      gGui->osd.status.visible = gGui->osd.timeout;
+    pthread_mutex_unlock(&osd_mutex);
+  }
+}
 void osd_update_status(void) {
 
   if(gGui->osd.enabled) {
     int  status;
     char buffer[256];
-    int wwidth, wheight;
+    int tw, th;
 
     status = xine_get_status(gGui->stream);
     
-    xine_osd_clear(gGui->osd.status.osd[0]);
+    xine_osd_clear(gGui->osd.status.osd);
     
     /*
       { : eject
@@ -655,30 +1092,28 @@
       break;
     }
 
-    if( gGui->osd.use_unscaled && gGui->osd.unscaled_available )
-      xine_osd_set_font(gGui->osd.status.osd[0], "cetus", UNSCALED_FONT_SIZE);
-    else
-      xine_osd_set_font(gGui->osd.status.osd[0], "cetus", FONT_SIZE);
 
     /* set latin1 encoding (NULL) for status text with special characters,
      * then switch back to locale encoding ("") 
      */
-    xine_osd_set_encoding(gGui->osd.status.osd[0], NULL);
-    xine_osd_draw_text(gGui->osd.status.osd[0], 0, 0, buffer, XINE_OSD_TEXT1);
-    xine_osd_set_encoding(gGui->osd.status.osd[0], "");
-    xine_osd_set_position(gGui->osd.status.osd[0], 20, 10);
+    xine_osd_set_font(gGui->osd.status.osd, OSD_FONTFACE_SYMBOLS, osd_fontsize);
+    xine_osd_set_encoding(gGui->osd.status.osd, NULL);
+    xine_osd_get_text_size(gGui->osd.status.osd, buffer, &tw, &th);
 
-    _osd_get_output_size(&wwidth, &wheight);
+    tw = tw + (OSD_TEXTMARGIN_W << 1);
+    th = th + (OSD_TEXTMARGIN_H << 1);
 
-    /* don't even bother drawing osd over those small streams.
-     * it would look pretty bad.
-     */
-    if( wwidth > MINIMUM_WIN_WIDTH ) {
-      pthread_mutex_lock(&osd_mutex);
-      _xine_osd_show(gGui->osd.status.osd[0], 0);
-      gGui->osd.status.visible = gGui->osd.timeout;
-      pthread_mutex_unlock(&osd_mutex);
+    if (osd_background) {
+      xine_osd_draw_rect(gGui->osd.status.osd, 0, 0, tw + 1, th + 1, osd_fontcolor + \
1, 1);  }
+
+    xine_osd_draw_text(gGui->osd.status.osd, OSD_TEXTMARGIN_W, OSD_TEXTMARGIN_H, \
buffer, osd_fontcolor); +    xine_osd_set_encoding(gGui->osd.status.osd, "");
+
+    gGui->osd.status.w = tw;
+    gGui->osd.status.h = th;
+
+    osd_show_status(1);
   }
 }
 
@@ -692,7 +1127,7 @@
 
   switch(channel) {
   case -2:
-    lang = "off";
+     lang = "off";
     break;
   case -1:
     if(!xine_get_spu_lang(gGui->stream, channel, &lang_buffer[0]))
@@ -741,58 +1176,22 @@
 }
 
 void osd_update_osd(void) {
-  int vwidth, vheight, wwidth, wheight;
-  int x;
 
-  if(!gGui->osd.sinfo.visible && !gGui->osd.bar.visible)
-    return;
-  
-  vwidth  = xine_get_stream_info(gGui->stream, XINE_STREAM_INFO_VIDEO_WIDTH);
-  vheight = xine_get_stream_info(gGui->stream, XINE_STREAM_INFO_VIDEO_HEIGHT);
-  
-  if((vwidth == 0) && (vheight == 0)) {
-    if(gGui->visual_anim.running) {
-      if(gGui->visual_anim.enabled == 1)
-	video_window_get_frame_size(&vwidth, &vheight);
-      else if(gGui->visual_anim.enabled == 2)
-	vwidth  = xine_get_stream_info(gGui->visual_anim.stream, \
                XINE_STREAM_INFO_VIDEO_WIDTH);
-    }
-    else
-      video_window_get_frame_size(&vwidth, &vheight);
-    
-  }
-  
-  _osd_get_output_size(&wwidth, &wheight);
-  
-  pthread_mutex_lock(&osd_mutex);
+  /* The info and sinfo objects are aligned relative to
+     the top/left corner and do not need to be repositioned
+     when the window has been resized. The status object
+     is aligned relative to the top/right corner, the
+     bar object is aligned relative to the center/bottom
+     and the menu is centered horizontally and vertically.
+     These thus need to be repositioned [if visible].
+  */
 
-  if(gGui->osd.sinfo.visible) {
-    xine_osd_hide(gGui->osd.sinfo.osd[0], 0);
-    
-    x = (wwidth - gGui->osd.sinfo.w) - 40;
-    xine_osd_set_position(gGui->osd.sinfo.osd[0], (x >= 0) ? x : 0,  \
                gGui->osd.sinfo.y);
-    _xine_osd_show(gGui->osd.sinfo.osd[0], 0);
-  }
+  if(gGui->osd.status.visible)
+    osd_show_sinfo(0);
 
-  if(gGui->osd.bar.visible) {
-    xine_osd_hide(gGui->osd.bar.osd[0], 0);
-    xine_osd_hide(gGui->osd.bar.osd[1], 0);
-    
-    x = (wwidth - BAR_WIDTH) >> 1;
-    xine_osd_set_position(gGui->osd.bar.osd[0], (x >= 0) ? x : 0, (wheight - \
                BAR_HEIGHT) - 40);
-    xine_osd_set_position(gGui->osd.bar.osd[1], (x >= 0) ? x : 0, (wheight - \
                (BAR_HEIGHT * 2)) - 40);
-    
-    /* don't even bother drawing osd over those small streams.
-     * it would look pretty bad.
-     */
-    if(wwidth > MINIMUM_WIN_WIDTH) {
-      _xine_osd_show(gGui->osd.bar.osd[0], 0);
-
-      if(gGui->osd.bar.have_text)
-	_xine_osd_show(gGui->osd.bar.osd[1], 0);
-    }
+  if (gGui->osd.bar.visible)
+    osd_show_bar(0);
 
-  }
-
-  pthread_mutex_unlock(&osd_mutex);
+  if (gGui->osd.menu.visible)
+    osd_show_menu();
 }
Index: src/xitk/osd.h
===================================================================
RCS file: /cvsroot/xine/xine-ui/src/xitk/osd.h,v
retrieving revision 1.16
diff -u -r1.16 osd.h
--- src/xitk/osd.h	13 Nov 2007 21:12:18 -0000	1.16
+++ src/xitk/osd.h	1 Dec 2008 19:34:01 -0000
@@ -27,9 +27,8 @@
 #include <stdarg.h>
 
 typedef struct {
-  xine_osd_t   *osd[2];
+  xine_osd_t   *osd;
   int           visible;
-  int           have_text;
   int           x, y;
   int           w, h;
 } osd_object_t;
@@ -39,11 +38,14 @@
 #define OSD_BAR_POS2     3
 #define OSD_BAR_STEPPER  4
 
+#define OSD_CUSTMENU_MAXOPT 9
+
 void osd_init(void);
 void osd_hide_sinfo(void);
 void osd_hide_bar(void);
 void osd_hide_status(void);
 void osd_hide_info(void);
+void osd_hide_menu(void);
 void osd_hide(void);
 void osd_deinit(void);
 void osd_update(void);
@@ -53,6 +55,7 @@
 void osd_update_status(void);
 void osd_stream_position(int pos);
 void osd_display_info(char *info, ...) __attribute__ ((format (printf, 1, 2)));
+void osd_display_menu(char* title, char **options, int n);
 
 /* see OSD_BAR_* */
 void osd_draw_bar(char *title, int min, int max, int val, int type);
Index: src/xitk/stdctl.c
===================================================================
RCS file: /cvsroot/xine/xine-ui/src/xitk/stdctl.c,v
retrieving revision 1.11
diff -u -r1.11 stdctl.c
--- src/xitk/stdctl.c	12 Mar 2008 11:58:11 -0000	1.11
+++ src/xitk/stdctl.c	1 Dec 2008 19:34:01 -0000
@@ -33,6 +33,9 @@
 #include <unistd.h>
 #include <string.h>
 
+/* input_pvr functionality needs this */
+#define XINE_ENABLE_EXPERIMENTAL_FEATURES
+
 #include "common.h"
 
 #define DEBUG_STDCTL 0
@@ -83,7 +86,7 @@
 	  fprintf(stderr, "Command Received = '%s'\n", c);
 #endif
 
-	  /* Handle optional parameter */
+    /* Handle optional parameter */
 
 	  /* alphanum: separated from the command by a '$'        */
 	  /* syntax:   "command$parameter"                        */
@@ -162,9 +165,8 @@
 	last_secs = secs;
       }
     }
-
   }
-  
+
   pthread_exit(NULL);
 }
 
@@ -196,9 +198,19 @@
 void stdctl_event(const xine_event_t *event)
 {
   switch(event->type) {
-  case XINE_EVENT_UI_PLAYBACK_FINISHED:
-    fprintf(stdctl.fbk, "PlaybackFinished\n");
-    break;
+    case XINE_EVENT_UI_PLAYBACK_FINISHED:
+      fprintf(stdctl.fbk, "PlaybackFinished\n");
+      break;
+
+    case XINE_EVENT_PVR_REPORT_NAME: {
+      xine_pvr_save_data_t *data = (xine_pvr_save_data_t*) event->data;
+      fprintf(stdctl.fbk, "PVRStreamSaved=%s\n", data->name);
+      break;
+    }
+
+    default:
+      //fprintf(stdctl.fbk, "event: %d\n", event->type);
+      break;
   }
 }
 



------------------------------------------------------------------------------


_______________________________________________
xine-devel mailing list
xine-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/xine-devel


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic