n = cmdbuf_ptr - cmdbuf_base;
s = cmdbuf_base + BUFSIZ - 1 - cmdbuf_endp;
+
if (n > 0 && s < count)
{
MEMMOVE (cmdbuf_base, cmdbuf_ptr,
cmdbuf_endp -= n;
s += n;
}
+
if (count > s)
{
rxvt_print_error ("data loss: cmd_write too large");
count = s;
}
+
for (; count--;)
*cmdbuf_endp++ = *str++;
+
+ cmd_parse ();
+
return 0;
}
#endif /* MENUBAR_MAX */
}
else if (n < 0 && errno != EAGAIN)
destroy ();
-
+
return false;
}
tt_winch ();
}
- uint32_t ch = NOCHAR;
+ if (cmd_parse ())
+ break;
+ }
+ }
+}
+
+bool
+rxvt_term::cmd_parse ()
+{
+ bool flag = false;
+ uint32_t ch = NOCHAR;
+
+ for (;;)
+ {
+ if (ch == NOCHAR)
+ ch = next_char ();
+
+ if (ch == NOCHAR) // TODO: improve
+ break;
+
+ if (ch >= ' ' || ch == '\t' || ch == '\n' || ch == '\r')
+ {
+ /* Read a text string from the input buffer */
+ uint32_t buf[BUFSIZ];
+ bool refreshnow = false;
+ int nlines = 0;
+ uint32_t *str = buf;
+
+ *str++ = ch;
for (;;)
{
- if (ch == NOCHAR)
- ch = next_char ();
+ ch = next_char ();
- if (ch == NOCHAR) // TODO: improve
+ if (ch == NOCHAR || (ch < ' ' && ch != '\t' && ch != '\n' && ch != '\r'))
break;
-
- if (ch >= ' ' || ch == '\t' || ch == '\n' || ch == '\r')
+ else
{
- /* Read a text string from the input buffer */
- uint32_t buf[BUFSIZ];
- bool refreshnow = false;
- int nlines = 0;
- uint32_t *str = buf;
-
*str++ = ch;
- for (;;)
+ if (ch == '\n')
{
- ch = next_char ();
+ nlines++;
+ refresh_count++;
- if (ch == NOCHAR || (ch < ' ' && ch != '\t' && ch != '\n' && ch != '\r'))
- break;
- else
+ if (! (Options & Opt_jumpScroll)
+ || (refresh_count >= (refresh_limit * (TermWin.nrow - 1))))
{
- *str++ = ch;
-
- if (ch == '\n')
- {
- nlines++;
- refresh_count++;
-
- if (! (Options & Opt_jumpScroll)
- || (refresh_count >= (refresh_limit * (TermWin.nrow - 1))))
- {
- refreshnow = true;
- flag = false;
- ch = NOCHAR;
- break;
- }
-
- // scr_add_lines only works for nlines < TermWin.nrow - 1.
- if (nlines >= TermWin.nrow - 1)
- {
- scr_add_lines (buf, nlines, str - buf);
- nlines = 0;
- str = buf;
- }
- }
-
- if (str >= buf + BUFSIZ)
- {
- ch = NOCHAR;
- break;
- }
+ refreshnow = true;
+ flag = false;
+ ch = NOCHAR;
+ break;
}
- }
- scr_add_lines (buf, nlines, str - buf);
-
- /*
- * If there have been a lot of new lines, then update the screen
- * What the heck I'll cheat and only refresh less than every page-full.
- * the number of pages between refreshes is refresh_limit, which
- * is incremented here because we must be doing flat-out scrolling.
- *
- * refreshing should be correct for small scrolls, because of the
- * time-out
- */
- if (refreshnow)
- {
- if ((Options & Opt_jumpScroll) && refresh_limit < REFRESH_PERIOD)
- refresh_limit++;
-
- scr_refresh (refresh_type);
+ // scr_add_lines only works for nlines < TermWin.nrow - 1.
+ if (nlines >= TermWin.nrow - 1)
+ {
+ scr_add_lines (buf, nlines, str - buf);
+ nlines = 0;
+ str = buf;
+ }
}
- }
- else
- {
- switch (ch)
+ if (str >= buf + BUFSIZ)
{
- default:
- process_nonprinting (ch);
- break;
- case C0_ESC: /* escape char */
- process_escape_seq ();
- break;
- /*case 0x9b: */ /* CSI */
- /* process_csi_seq (); */
+ ch = NOCHAR;
+ break;
}
-
- ch = NOCHAR;
}
}
+
+ scr_add_lines (buf, nlines, str - buf);
+
+ /*
+ * If there have been a lot of new lines, then update the screen
+ * What the heck I'll cheat and only refresh less than every page-full.
+ * the number of pages between refreshes is refresh_limit, which
+ * is incremented here because we must be doing flat-out scrolling.
+ *
+ * refreshing should be correct for small scrolls, because of the
+ * time-out
+ */
+ if (refreshnow)
+ {
+ if ((Options & Opt_jumpScroll) && refresh_limit < REFRESH_PERIOD)
+ refresh_limit++;
+
+ scr_refresh (refresh_type);
+ }
+
+ }
+ else
+ {
+ switch (ch)
+ {
+ default:
+ process_nonprinting (ch);
+ break;
+ case C0_ESC: /* escape char */
+ process_escape_seq ();
+ break;
+ /*case 0x9b: */ /* CSI */
+ /* process_csi_seq (); */
+ }
+
+ ch = NOCHAR;
}
}
+
+ return flag;
}
// read the next character, currently handles UTF-8
*----------------------------------------------------------------------*/
#include "../config.h" /* NECESSARY */
+
+#include <stdlib.h>
+
#include "rxvt.h" /* NECESSARY */
#ifdef MENUBAR
#include "version.h"
/*}}} */
+static void
+draw_string (rxvt_drawable &d, GC gc, rxvt_fontset *fs, int x, int y, char *str, int len)
+{
+ mbstate mbs;
+
+ while (len)
+ {
+ wchar_t w;
+ int l = mbrtowc (&w, str, len, mbs);
+
+ if (l <= 0)
+ break;
+
+ len -= l;
+ str += l;
+
+ rxvt_font *font = (*fs)[fs->find_font (w)];
+ text_t ch = w;
+ font->draw (d, x, y, &ch, 1, Color_bg, Color_scroll);
+
+ x += font->width * wcwidth (w);
+ }
+}
+
/*
* find an item called NAME in MENU
*/
if (*p == '/')
path = p;
}
+
if (path[0] == '/')
{
path++;
*menu = NULL;
}
+
while ((p = STRCHR (path, '/')) != NULL)
{
p[0] = '\0';
if (path[0] == '\0')
return NULL;
+
if (!STRCMP (path, DOT))
{
/* nothing to do */
path = (p + 1);
}
}
+
if (!STRCMP (path, DOTS))
{
path += STRLEN (DOTS);
*menu = (*menu)->parent;
return path;
}
+
/* find this menu */
if (*menu == NULL)
{
for (m = CurrentBar->tail; m != NULL; m = m->prev)
- {
- if (!STRCMP (path, m->name))
- break;
- }
+ if (!STRCMP (path, m->name))
+ break;
}
else
{
}
}
}
+
if (m != NULL)
{
*menu = m;
path += STRLEN (path);
}
+
return path;
}
{
menu_t *parent = NULL, *prev, *next;
menuitem_t *item;
- bar_t *CurrentBar = CurrentBar;
#ifdef DEBUG_STRICT
assert (CurrentBar != NULL);
item = menu->tail;
while (item != NULL)
{
- menuitem_t *p = item->prev;
+ menuitem_t *p = item->prev;
menuitem_free (menu, item);
item = p;
}
- if (menu->name != NULL)
- free (menu->name);
+ free (menu->name);
free (menu);
return parent;
menu_t *
rxvt_term::menu_add (menu_t *parent, char *path)
{
- menu_t *menu;
- bar_t *CurrentBar = CurrentBar;
+ menu_t *menu;
#ifdef DEBUG_STRICT
assert (CurrentBar != NULL);
if (STRCHR (path, '/') != NULL)
{
- char *p;
+ char *p;
if (path[0] == '/')
{
menu->prev = menu->next = NULL;
menu->win = None;
+ menu->drawable = 0;
menu->x = menu->y = menu->w = menu->h = 0;
menu->item = NULL;
x -= SHADOW + (3 * w / 2);
y += SHADOW * 3;
- rxvt_Draw_Triangle (display->display, ActiveMenu->win, top, bot, x, y, w,
- 'r');
+ rxvt_Draw_Triangle (display->display, ActiveMenu->win, top, bot, x, y, w, 'r');
}
void
fprintf (stderr, "Top Level menu\n");
return;
}
+
fprintf (stderr, "menu %s ", menu->name);
if (menu->parent != NULL)
{
break;
}
}
+
if (item == NULL)
{
fprintf (stderr, "is an orphan!\n");
return;
}
}
+
fprintf (stderr, "\n");
rxvt_print_menu_ancestors (menu->parent);
}
void
rxvt_term::menu_show ()
{
- int x, y, xright;
- menu_t *ActiveMenu = ActiveMenu;
- menuitem_t *item;
+ int x, y, xright;
+ menuitem_t *item;
if (ActiveMenu == NULL)
return;
: HEIGHT_TEXT + 2 * SHADOW;
ActiveMenu->h = h + 2 * SHADOW;
}
+
if (ActiveMenu->win == None)
{
ActiveMenu->win = XCreateSimpleWindow (display->display, TermWin.vt,
0,
PixColors[Color_fg],
PixColors[Color_scroll]);
+ ActiveMenu->drawable = new rxvt_drawable (display, ActiveMenu->win);
XMapWindow (display->display, ActiveMenu->win);
}
+
rxvt_Draw_Shadow (display->display, ActiveMenu->win,
topShadowGC, botShadowGC,
0, 0, ActiveMenu->w, ActiveMenu->h);
for (y = 0, item = ActiveMenu->head; item != NULL; item = item->next)
{
- const int xoff = (SHADOW + Width2Pixel (HSPACE) / 2);
- register int h;
- GC gc = menubarGC;
+ const int xoff = (SHADOW + Width2Pixel (HSPACE) / 2);
+ register int h;
+ GC gc = menubarGC;
if (isSeparator (item->name))
{
int len = item->len;
if (item->entry.type == MenuLabel)
- {
- gc = botShadowGC;
- }
+ gc = botShadowGC;
else if (item->entry.type == MenuSubMenu)
{
int x1, y1;
name = NULL;
if (len && name)
- draw_string (display->display, ActiveMenu->win, gc, xoff,
- 2 * SHADOW + y + TermWin.font->ascent + 1,
- name, len);
+ draw_string (*ActiveMenu->drawable, gc, TermWin.fontset,
+ xoff, 2 * SHADOW + y, name, len);
len = item->len2;
name = item->name2;
if (len && name)
- draw_string (display->display, ActiveMenu->win, gc,
- ActiveMenu->w - (xoff + Width2Pixel (xright)),
- 2 * SHADOW + y + TermWin.font->ascent + 1,
- name, len);
+ draw_string (*ActiveMenu->drawable, gc, TermWin.fontset,
+ ActiveMenu->w - (xoff + Width2Pixel (xright)), 2 * SHADOW + y, name, len);
h = HEIGHT_TEXT + 2 * SHADOW;
}
void
rxvt_term::menu_display (void (rxvt_term::*update) ())
{
- menu_t *ActiveMenu = ActiveMenu;
-
if (ActiveMenu == NULL)
return;
+
+ delete ActiveMenu->drawable;
if (ActiveMenu->win != None)
XDestroyWindow (display->display, ActiveMenu->win);
ActiveMenu->win = None;
if (ActiveMenu->parent == NULL)
drawbox_menubar (ActiveMenu->x, ActiveMenu->len, +1);
+
ActiveMenu = ActiveMenu->parent;
(this->*update) ();
}
{
if (menu != NULL)
{
- menuitem_t *item = menu->tail;
+ menuitem_t *item = menu->tail;
while (item != NULL)
{
void
rxvt_term::menubar_clear ()
{
- bar_t *CurrentBar = CurrentBar;
-
if (CurrentBar != NULL)
{
- menu_t *menu = CurrentBar->tail;
+ menu_t *menu = CurrentBar->tail;
while (menu != NULL)
{
- menu_t *prev = menu->prev;
+ menu_t *prev = menu->prev;
menu_delete (menu);
menu = prev;
free (CurrentBar->title);
CurrentBar->title = NULL;
}
+
menuarrow_free (0); /* remove all arrow functions */
}
+
ActiveMenu = NULL;
}
bar_t *
rxvt_term::menubar_find (const char *name)
{
- bar_t *bar = CurrentBar;
+ bar_t *bar = CurrentBar;
#ifdef DEBUG_MENUBAR_STACKING
fprintf (stderr, "looking for [menu:%s] ...", name ? name : " (nil)");
int
rxvt_term::menubar_push (const char *name)
{
- int ret = 1;
- bar_t *bar;
+ int ret = 1;
+ bar_t *bar;
if (CurrentBar == NULL)
{
CurrentBar = bar;
}
+
menubar_clear ();
}
}
void
rxvt_action_decode (FILE *fp, action_t *act)
{
- unsigned char *str;
- short len;
+ unsigned char *str;
+ short len;
if (act == NULL || (len = act->len) == 0 || (str = act->str) == NULL)
return;
break;
}
}
+
/*
* control character form is preferred, since backslash-escaping
* can be really ugly looking when the backslashes themselves also
fprintf (fp, "%c", ch);
break;
}
+
len--;
}
+
fprintf (fp, "\n");
}
file = (char *)rxvt_File_find (filename, ".menu", rs[Rs_path]);
if (file == NULL)
return;
+
fp = fopen (file, "rb");
free (file);
if (fp == NULL)
void
rxvt_term::menubar_dispatch (char *str)
{
- int n, cmd;
- char *path, *name, *name2;
+ int n, cmd;
+ char *path, *name, *name2;
if (menubar_visible () && ActiveMenu != NULL)
menubar_expose ();
for (i = 0; i < NARROWS; i++)
{
- const int w = Width2Pixel (1);
- const int y = (menuBar_TotalHeight () - w) / 2;
- int x = Arrows_x + (5 * Width2Pixel (i)) / 4;
+ const int w = Width2Pixel (1);
+ const int y = (menuBar_TotalHeight () - w) / 2;
+ int x = Arrows_x + (5 * Width2Pixel (i)) / 4;
if (!name || name == Arrows[i].name)
rxvt_Draw_Triangle (display->display, menuBar.win, top, bot, x, y, w,
void
rxvt_term::menubar_expose ()
{
- menu_t *menu;
- int x;
+ menu_t *menu;
+ int x;
if (!menubar_visible () || menuBar.win == 0)
return;
/* Create the graphics context */
XGCValues gcvalue;
- gcvalue.font = TermWin.font->fid;
-
gcvalue.foreground = (XDEPTH <= 2 ? PixColors[Color_fg]
: PixColors[Color_Black]);
menubarGC = XCreateGC (display->display, menuBar.win,
- GCForeground | GCFont, &gcvalue);
+ GCForeground, &gcvalue);
}
/* make sure the font is correct */
- XSetFont (display->display, menubarGC, TermWin.font->fid);
- XSetFont (display->display, botShadowGC, TermWin.font->fid);
XClearWindow (display->display, menuBar.win);
menu_hide_all ();
len = (TermWin.ncol - (menu->x + HSPACE));
drawbox_menubar (menu->x, len, +1);
- draw_string (display->display, menuBar.win, menubarGC,
+ draw_string (*menuBar.drawable, menubarGC, TermWin.fontset,
(Width2Pixel (menu->x) + Width2Pixel (HSPACE) / 2),
- menuBar_height () - SHADOW, menu->name, len);
+ SHADOW, menu->name, len);
if (x >= TermWin.ncol)
break;
ncol -= (x + len + HSPACE);
if (len > 0 && ncol >= 0)
- draw_string (display->display, menuBar.win, menubarGC,
+ draw_string (*menuBar.drawable, menubarGC, TermWin.fontset,
Width2Pixel (x) + Width2Pixel (ncol + HSPACE) / 2,
- menuBar_height () - SHADOW, title, len);
+ SHADOW, title, len);
}
}
int
rxvt_term::menu_select (XButtonEvent &ev)
{
- menuitem_t *thisitem, *item = NULL;
- int this_y, y;
- menu_t *ActiveMenu = ActiveMenu;
+ menuitem_t *thisitem, *item = NULL;
+ int this_y, y;
- Window unused_root, unused_child;
- int unused_root_x, unused_root_y;
- unsigned int unused_mask;
+ Window unused_root, unused_child;
+ int unused_root_x, unused_root_y;
+ unsigned int unused_mask;
if (ActiveMenu == NULL)
return 0;
XQueryPointer (display->display, ActiveMenu->win,
- &unused_root, &unused_child,
- &unused_root_x, &unused_root_y,
- &ev.x, &ev.y, &unused_mask);
+ &unused_root, &unused_child,
+ &unused_root_x, &unused_root_y,
+ &ev.x, &ev.y, &unused_mask);
if (ActiveMenu->parent != NULL && (ev.x < 0 || ev.y < 0))
{
menu_hide ();
return 1;
}
+
/* determine the menu item corresponding to the Y index */
y = SHADOW;
if (ev.x >= 0 && ev.x <= (ActiveMenu->w - SHADOW))
{
for (item = ActiveMenu->head; item != NULL; item = item->next)
{
- int h = HEIGHT_TEXT + 2 * SHADOW;
+ int h = HEIGHT_TEXT + 2 * SHADOW;
if (isSeparator (item->name))
h = HEIGHT_SEPARATOR;
else if (ev.y >= y && ev.y < (y + h))
break;
+
y += h;
}
}
+
if (item == NULL && ev.type == ButtonRelease)
{
menu_hide_all ();
return 0;
}
+
thisitem = item;
this_y = y - SHADOW;
{
if (ActiveMenu->item != thisitem)
{
- for (y = 0, item = ActiveMenu->head; item != NULL;
- item = item->next)
+ for (y = 0, item = ActiveMenu->head; item != NULL; item = item->next)
{
- int h;
+ int h;
if (isSeparator (item->name))
h = HEIGHT_SEPARATOR;
drawbox_menuitem (y, 0); /* No Shadow */
if (item->entry.type == MenuSubMenu)
drawtriangle (ActiveMenu->w, y, +1);
+
break;
}
else
h = HEIGHT_TEXT + 2 * SHADOW;
+
y += h;
}
}
case MenuAction:
case MenuTerminalAction:
drawbox_menuitem (this_y, -1);
- {
#ifdef HAVE_NANOSLEEP
- struct timespec rqt;
+ struct timespec rqt;
- rqt.tv_sec = 0;
- rqt.tv_nsec = MENU_DELAY_USEC * 1000;
- nanosleep (&rqt, NULL);
+ rqt.tv_sec = 0;
+ rqt.tv_nsec = MENU_DELAY_USEC * 1000;
+ nanosleep (&rqt, NULL);
#else
- /* use select for timing */
- struct timeval tv;
+ /* use select for timing */
+ struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = MENU_DELAY_USEC;
- select (0, NULL, NULL, NULL, &tv);
+ tv.tv_sec = 0;
+ tv.tv_usec = MENU_DELAY_USEC;
+ select (0, NULL, NULL, NULL, &tv);
#endif
-
- }
/* remove menu before sending keys to the application */
menu_hide_all ();
#ifndef DEBUG_MENU
return 0;
}
}
+
DoMenu:
ActiveMenu->item = thisitem;
y = this_y;
- if (item != NULL)
+
+ if (thisitem != NULL)
{
item = ActiveMenu->item;
if (item->entry.type != MenuLabel)
drawbox_menuitem (y, +1);
+
if (item->entry.type == MenuSubMenu)
{
- int x;
+ int x;
drawtriangle (ActiveMenu->w, y, -1);
void
rxvt_term::menubar_select (XButtonEvent &ev)
{
- menu_t *menu = NULL;
+ menu_t *menu = NULL;
/* determine the pulldown menu corresponding to the X index */
if (ev.y >= 0 && ev.y <= menuBar_height () && CurrentBar != NULL)
{
for (menu = CurrentBar->head; menu != NULL; menu = menu->next)
{
- int x = Width2Pixel (menu->x);
- int w = Width2Pixel (menu->len + HSPACE);
+ int x = Width2Pixel (menu->x);
+ int w = Width2Pixel (menu->len + HSPACE);
if ((ev.x >= x && ev.x < x + w))
break;
case MotionNotify:
while (XCheckTypedWindowEvent (display->display, TermWin.parent[0],
- MotionNotify, (XEvent *)&ev)) ;
+ MotionNotify, (XEvent *)&ev)) ;
if (ActiveMenu)
while (menu_select (ev)) ;