diff src/gui.c @ 251:677f6a0ee643 r20-5b24

Import from CVS: tag r20-5b24
author cvs
date Mon, 13 Aug 2007 10:19:59 +0200
parents 557eaa0339bf
children 11cf20601dec
line wrap: on
line diff
--- a/src/gui.c	Mon Aug 13 10:19:12 2007 +0200
+++ b/src/gui.c	Mon Aug 13 10:19:59 2007 +0200
@@ -23,8 +23,8 @@
 /* Synched up with: Not in FSF. */
 
 #include <config.h>
+#include "lisp.h"
 #include "gui.h"
-#include "lisp.h"
 
 Lisp_Object Q_active, Q_suffix, Q_keys, Q_style, Q_selected;
 Lisp_Object Q_filter, Q_config, Q_included;
@@ -63,6 +63,237 @@
   return 0;
 }
 
+/* 
+ * Initialize the gui_item structure by setting all (GC-protected)
+ * fields to their default values. The defaults are t for :active and
+ * :included values, and nil for others.
+ */
+void
+gui_item_init (struct gui_item *pgui_item)
+{
+  pgui_item->name = Qnil;
+  pgui_item->callback = Qnil;
+  pgui_item->suffix = Qnil;
+  pgui_item->active = Qt;
+  pgui_item->included = Qt;
+  pgui_item->config = Qunbound;
+  pgui_item->filter = Qnil;
+  pgui_item->style = Qnil;
+  pgui_item->selected = Qnil;
+  pgui_item->keys = Qnil;
+}
+
+/*
+ * Add a value VAL associated with keyword KEY into PGUI_ITEM
+ * structure. If KEY is not a keyword, or is an unknown keyword, then
+ * error is signaled.
+ */
+void 
+gui_item_add_keyval_pair (struct gui_item *pgui_item,
+			  Lisp_Object key, Lisp_Object val)
+{
+  if (!KEYWORDP (key))
+    error ("Not a keyword %S in gui item %S", key, pgui_item->name);
+
+  if (EQ (key, Q_suffix))
+    pgui_item->suffix = val;
+  else if (EQ (key, Q_active))
+    pgui_item->active = val;
+  else if (EQ (key, Q_included))
+    pgui_item->included = val;
+  else if (EQ (key, Q_config))
+    pgui_item->config = val;
+  else if (EQ (key, Q_filter))
+    pgui_item->filter = val;
+  else if (EQ (key, Q_style))
+    pgui_item->style = val;
+  else if (EQ (key, Q_selected))
+    pgui_item->selected = val;
+  else if (EQ (key, Q_keys))
+    pgui_item->keys = val;
+  else
+    error ("Unknown keyword %S in gui item %S", key, pgui_item->name);
+}
+
+/*
+ * ITEM is a lisp vector, describing a menu item or a button. The
+ * function extracts the description of the item into the PGUI_ITEM
+ * structure.
+ */
+void
+gui_parse_item_keywords (Lisp_Object item, struct gui_item *pgui_item)
+{
+  int length, plist_p;
+  Lisp_Object *contents;
+
+  CHECK_VECTOR (item);
+  length = XVECTOR_LENGTH (item);
+  contents = XVECTOR_DATA (item);
+
+  if (length < 3)
+    signal_simple_error ("GUI item descriptors must be at least 3 elts long", item);
+
+  /* length 3:		[ "name" callback active-p ]
+     length 4:		[ "name" callback active-p suffix ]
+     		   or	[ "name" callback keyword  value  ]
+     length 5+:		[ "name" callback [ keyword value ]+ ]
+  */
+  plist_p = (length >= 5 || KEYWORDP (contents [2]));
+
+  pgui_item->name = contents [0];
+  pgui_item->callback = contents [1];
+
+  if (!plist_p)
+    /* the old way */
+    {
+      pgui_item->active = contents [2];
+      if (length == 4)
+	pgui_item->suffix = contents [3];
+    }
+  else
+    /* the new way */
+    {
+      int i;
+      if (length & 1)
+	signal_simple_error (
+		"GUI item descriptor has an odd number of keywords and values",
+			     item);
+
+      for (i = 2; i < length;)
+	{
+	  Lisp_Object key = contents [i++];
+	  Lisp_Object val = contents [i++];
+	  gui_item_add_keyval_pair (pgui_item, key, val);
+	}
+    }    
+}
+
+/*
+ * Decide whether a GUI item is active by evaluating its :active form
+ * if any
+ */
+int
+gui_item_active_p (CONST struct gui_item *pgui_item)
+{
+  /* This function can call lisp */
+  
+  /* Shortcut to avoid evaluating Qt each time */
+  return (EQ (pgui_item->active, Qt)
+	  || !NILP (Feval (pgui_item->active)));
+}
+
+/*
+ * Decide whether a GUI item is included by evaluating its :included
+ * form if given, and testing its :config form against supplied CONFLIST
+ * configuration variable
+ */
+int
+gui_item_included_p (CONST struct gui_item *pgui_item, Lisp_Object conflist)
+{
+  /* This function can call lisp */
+
+  /* Evaluate :included first. Shortcut to avoid evaluating Qt each time */
+  if (!EQ (pgui_item->included, Qt)
+      && NILP (Feval (pgui_item->included)))
+    return 0;
+
+  /* Do :config if conflist is given */
+  if (!NILP (conflist) && !NILP (pgui_item->config)
+      && NILP (Fmemq (pgui_item->config, conflist)))
+    return 0;
+
+  return 1;
+}
+
+static DOESNT_RETURN
+signal_too_long_error (Lisp_Object name)
+{
+  error ("GUI item %s produces too long displayable string", name);
+}
+
+/*
+ * Format "left flush" display portion of an item into BUF, guarded by 
+ * maximum buffer size BUF_LEN. BUF_LEN does not count for terminating 
+ * null character, so actual maximum size of buffer consumed is
+ * BUF_LEN + 1 bytes. If buffer is not big enough, then error is
+ * signaled.
+ * Return value is the offset to the terminating null character into the
+ * buffer.
+ */
+unsigned int
+gui_item_display_flush_left  (CONST struct gui_item *pgui_item,
+			      char* buf, unsigned int buf_len)
+{
+  unsigned int consumed;
+
+  /* Copy item name first */
+  CHECK_STRING (pgui_item->name);
+  if (XSTRING_LENGTH (pgui_item->name) > buf_len)
+    signal_too_long_error (pgui_item->name);
+  strcpy (buf, XSTRING_DATA (pgui_item->name));
+  buf += (consumed = XSTRING_LENGTH (pgui_item->name));
+  buf_len -= consumed;
+
+  /* Add space and suffix text, if there is a suffix */
+  if (!NILP (pgui_item->suffix))
+    {
+      if (XSTRING_LENGTH (pgui_item->suffix) + 1 > buf_len)
+	signal_too_long_error (pgui_item->name);
+      *(buf++) = ' ';
+      strcpy (buf, XSTRING_DATA (pgui_item->suffix));
+      consumed += XSTRING_LENGTH (pgui_item->suffix) + 1;
+    }
+
+  return consumed;
+}
+
+/*
+ * Format "right flush" display portion of an item into BUF, guarded by 
+ * maximum buffer size BUF_LEN. BUF_LEN does not count for terminating 
+ * null character, so actual maximum size of buffer consumed is
+ * BUF_LEN + 1 bytes. If buffer is not big enough, then error is
+ * signaled.
+ * Return value is the offset to the terminating null character into the
+ * buffer.
+ */
+unsigned int
+gui_item_display_flush_right (CONST struct gui_item *pgui_item,
+			      char* buf, unsigned int buf_len)
+{
+  *buf = 0;
+
+  /* Have keys? */
+  if (!menubar_show_keybindings)
+    return 0;
+
+  /* Try :keys first */
+  if (!NILP (pgui_item->keys))
+    {
+      CHECK_STRING (pgui_item->keys);
+      if (XSTRING_LENGTH (pgui_item->keys) > buf_len)
+	signal_too_long_error (pgui_item->name);
+      strcpy (buf, XSTRING_DATA (pgui_item->keys));
+      return XSTRING_LENGTH (pgui_item->keys);
+    }
+
+  /* See if we can derive keys out of callback symbol */
+  if (SYMBOLP (pgui_item->callback))
+    {
+      char buf2 [1024];
+      unsigned int len;
+
+      where_is_to_char (pgui_item->callback, buf2);
+      len = strlen (buf2);
+      if (len > buf_len)
+	signal_too_long_error (pgui_item->name);
+      strcpy (buf, buf2);
+      return len;
+    }
+
+  /* No keys - no right flush display */
+  return 0;
+}
+
 #endif /* HAVE_POPUPS */
 
 void