Mon Jun 11 17:49:55 PDT 2001 Michael Jennings <mej@eterm.org>

Okay, first off, I removed 3 scaled backgrounds.  See www.kainx.org or
	my post to enlightenment-devel for details.

	Second, I redid the default bindings for the mouse wheel.  Basically,
	the wheel alone will scroll by pages.  Ctrl+wheel will scroll by pages
	in groups of 5.  Shift+wheel will scroll by a single line.  If you
	hold down the Alt key, the same combinations will work the same way,
	but instead of scrolling within Eterm, they'll scroll the application
	in the terminal (by sending PgUp/PgDn and up/down arrows).  This works
	in less, bash, and any other application which groks those keys.

	I also added a --without-mousewheel option to configure that will turn
	off the default scrollwheel bindings.  Of course, you can always use
	action bindings in the config file to bind/rebind these any way you
	like.

	While I was at it, I found and fixed a bug in the handling of the
	Alt and Meta keys.

	I added a scroll() function to the script stuff which allows you to
	bind keys/buttons to scroll up and down.  While I was at it, I added
	comments to script.c for each function you can use.

	And finally, the config file parser was moved to libast.


SVN revision: 4806
This commit is contained in:
Michael Jennings 2001-06-12 01:04:45 +00:00
parent d6cf164837
commit c3f775c1b5
20 changed files with 386 additions and 1204 deletions

View File

@ -4166,3 +4166,31 @@ Thu May 24 00:14:54 PDT 2001 Michael Jennings <mej@eterm.org>
broken in Emacs (*grumble*). Works in gvim though.
-------------------------------------------------------------------------------
Mon Jun 11 17:49:55 PDT 2001 Michael Jennings <mej@eterm.org>
Okay, first off, I removed 3 scaled backgrounds. See www.kainx.org or
my post to enlightenment-devel for details.
Second, I redid the default bindings for the mouse wheel. Basically,
the wheel alone will scroll by pages. Ctrl+wheel will scroll by pages
in groups of 5. Shift+wheel will scroll by a single line. If you
hold down the Alt key, the same combinations will work the same way,
but instead of scrolling within Eterm, they'll scroll the application
in the terminal (by sending PgUp/PgDn and up/down arrows). This works
in less, bash, and any other application which groks those keys.
I also added a --without-mousewheel option to configure that will turn
off the default scrollwheel bindings. Of course, you can always use
action bindings in the config file to bind/rebind these any way you
like.
While I was at it, I found and fixed a bug in the handling of the
Alt and Meta keys.
I added a scroll() function to the script stuff which allows you to
bind keys/buttons to scroll up and down. While I was at it, I added
comments to script.c for each function you can use.
And finally, the config file parser was moved to libast.
-------------------------------------------------------------------------------

View File

@ -361,6 +361,7 @@
#undef UTMP_IDENT
#undef WINDOWS_IDENT
#undef HAVE_SAVED_UIDS
#undef MOUSEWHEEL
/* Leave that blank line there!! Autoheader needs it.

View File

@ -2,7 +2,7 @@
DIRS = tile scale
EXTRA_DIST = tile/014.jpg tile/circuit.jpg tile/giger1.jpg tile/40.jpg tile/blackstone.jpg \
tile/nebula.jpg scale/fourthday.jpg scale/gaia.jpg scale/galleon.jpg scale/Dragon.jpg \
tile/nebula.jpg scale/Dragon.jpg \
README.backgrounds
pixmapdir = $(pkgdatadir)/pix
themedir = $(pkgdatadir)/themes

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

View File

@ -571,6 +571,17 @@ AC_ARG_WITH(end,
AC_MSG_RESULT(default vt102)
fi, AC_MSG_RESULT(default)
)
AC_MSG_CHECKING(if mousewheel support should be enabled)
AC_ARG_WITH(mousewheel,
[ --without-mousewheel disable built-in mousewheel support],
if test "$withval" = "no"; then
AC_MSG_RESULT(no)
else
AC_MSG_RESULT(yes)
AC_DEFINE(MOUSEWHEEL)
fi, AC_MSG_RESULT(yes)
AC_DEFINE(MOUSEWHEEL)
)
MULTICHAR_ENCODING=""
AC_MSG_CHECKING(for multi-charset support)
AC_ARG_ENABLE(multi-charset,

View File

@ -96,71 +96,117 @@ action_find_match(unsigned short mod, unsigned char button, KeySym keysym)
return NULL;
}
unsigned char
action_check_button(unsigned char button, int x_button)
{
/* The event we're looking at is a button press. Make sure the
current action is also, and that it matches. Continue if not. */
D_ACTIONS(("Checking button %d vs x_button %d\n", button, x_button));
if (button == BUTTON_NONE) {
/* It was a button press, and this action is not a button action. */
return FALSE;
}
if ((button != BUTTON_ANY) && (button != x_button)) {
/* It's a specific button, and the two don't match. */
return FALSE;
}
D_ACTIONS(("Button match confirmed.\n"));
return TRUE;
}
unsigned char
action_check_keysym(KeySym keysym, KeySym x_keysym)
{
/* The event we're looking at is a key press. Make sure the
current action is also, and that it matches. Continue if not. */
D_ACTIONS(("Checking keysym 0x%08x vs x_keysym 0x%08x\n", keysym, x_keysym));
if (keysym == None) {
return FALSE;
} else if (keysym != x_keysym) {
return FALSE;
}
D_ACTIONS(("Keysym match confirmed.\n"));
return TRUE;
}
unsigned char
action_check_modifiers(unsigned short mod, int x_mod)
{
unsigned int m = (AltMask | MetaMask | NumLockMask);
/* When we do have to check the modifiers, we do so in this order to eliminate the
most popular choices first. If any test fails, we return FALSE. */
D_ACTIONS(("Checking modifier set 0x%08x (" MOD_FMT ") vs. X modifier set 0x%08x (" MOD_FMT ")\n",
mod, SHOW_MODS(mod), x_mod, SHOW_X_MODS(x_mod)));
if (mod != MOD_ANY) {
/* LOGICAL_XOR() returns true if either the first parameter or the second parameter
is true, but not both...just like XOR. If the mask we're looking for is set in
mod but not in x_mod, or set in x_mod but not in mod, we don't have a match. */
if (LOGICAL_XOR((mod & MOD_CTRL), (x_mod & ControlMask))) {
return FALSE;
}
if (LOGICAL_XOR((mod & MOD_SHIFT), (x_mod & ShiftMask))) {
return FALSE;
}
if (MetaMask != AltMask) {
if (LOGICAL_XOR((mod & MOD_ALT), (x_mod & AltMask))) {
return FALSE;
}
if (LOGICAL_XOR((mod & MOD_META), (x_mod & MetaMask))) {
return FALSE;
}
} else {
if (LOGICAL_XOR((mod & (MOD_META | MOD_ALT)), (x_mod & (MetaMask | AltMask)))) {
return FALSE;
}
}
if (LOGICAL_XOR((mod & MOD_LOCK), (x_mod & LockMask))) {
return FALSE;
}
/* These tests can't use LOGICAL_XOR because the second test has an additional
restriction that the Mod?Mask cannot be set in m; i.e., we want to ignore
any Mod?Mask assigned to Alt, Meta, or the NumLock On state. */
if (((mod & MOD_MOD1) && !(x_mod & Mod1Mask)) || (!(mod & MOD_MOD1) && (x_mod & Mod1Mask) && !(Mod1Mask & m))) {
return FALSE;
}
if (((mod & MOD_MOD2) && !(x_mod & Mod2Mask)) || (!(mod & MOD_MOD2) && (x_mod & Mod2Mask) && !(Mod2Mask & m))) {
return FALSE;
}
if (((mod & MOD_MOD3) && !(x_mod & Mod3Mask)) || (!(mod & MOD_MOD3) && (x_mod & Mod3Mask) && !(Mod3Mask & m))) {
return FALSE;
}
if (((mod & MOD_MOD4) && !(x_mod & Mod4Mask)) || (!(mod & MOD_MOD4) && (x_mod & Mod4Mask) && !(Mod4Mask & m))) {
return FALSE;
}
if (((mod & MOD_MOD5) && !(x_mod & Mod5Mask)) || (!(mod & MOD_MOD5) && (x_mod & Mod5Mask) && !(Mod5Mask & m))) {
return FALSE;
}
}
D_ACTIONS(("Modifier match confirmed.\n"));
return TRUE;
}
unsigned char
action_dispatch(event_t *ev, KeySym keysym)
{
action_t *action;
unsigned int m = (AltMask | MetaMask | NumLockMask);
ASSERT_RVAL(ev != NULL, 0);
ASSERT_RVAL(ev->xany.type == ButtonPress || ev->xany.type == KeyPress, 0);
D_ACTIONS(("Event %8p: Button %d, Keysym 0x%08x, Key State 0x%08x\n", ev, ev->xbutton.button, keysym, ev->xkey.state));
D_ACTIONS(("Event %8p: Button %d, Keysym 0x%08x, Key State 0x%08x (modifiers " MOD_FMT ")\n",
ev, ev->xbutton.button, keysym, ev->xkey.state, SHOW_X_MODS(ev->xkey.state)));
for (action = action_list; action; action = action->next) {
D_ACTIONS(("Checking action. mod == 0x%08x, button == %d, keysym == 0x%08x\n", action->mod, action->button, action->keysym));
/* The very first thing we do is match the event type to the type
of the current action. This means that we'll only run through
the modifier checks below if we absolutely have to. */
if (ev->xany.type == ButtonPress) {
/* The event we're looking at is a button press. Make sure the
current action is also, and that it matches. Continue if not. */
if ((action->button == BUTTON_NONE) || ((action->button != BUTTON_ANY) && (action->button != ev->xbutton.button))) {
continue;
}
} else {
/* The event we're looking at is a key press. Make sure the
current action is also, and that it matches. Continue if not. */
if (!(action->keysym) || (keysym != action->keysym)) {
continue;
if ((ev->xany.type == ButtonPress && action_check_button(action->button, ev->xbutton.button))
|| (ev->xany.type == KeyPress && action_check_keysym(action->keysym, action->keysym))) {
if (action_check_modifiers(action->mod, ev->xkey.state)) {
D_ACTIONS(("Match found.\n"));
/* If we've passed all the above tests, it's a match. Dispatch the handler. */
return ((action->handler)(ev, action));
}
}
D_ACTIONS(("Button/key passed.\n"));
if (action->mod != MOD_ANY) {
/* When we do have to check the modifiers, we do so in
this order to eliminate the most popular choices first. */
if (LOGICAL_XOR((action->mod & MOD_CTRL), (ev->xkey.state & ControlMask))) {
continue;
}
if (LOGICAL_XOR((action->mod & MOD_SHIFT), (ev->xkey.state & ShiftMask))) {
continue;
}
if (LOGICAL_XOR((action->mod & MOD_ALT), (ev->xkey.state & AltMask))) {
continue;
}
if (LOGICAL_XOR((action->mod & MOD_META), (ev->xkey.state & MetaMask))) {
continue;
}
if (LOGICAL_XOR((action->mod & MOD_LOCK), (ev->xkey.state & LockMask))) {
continue;
}
if (((action->mod & MOD_MOD1) && !(ev->xkey.state & Mod1Mask)) || (!(action->mod & MOD_MOD1) && (ev->xkey.state & Mod1Mask) && !(Mod1Mask & m))) {
continue;
}
if (((action->mod & MOD_MOD2) && !(ev->xkey.state & Mod2Mask)) || (!(action->mod & MOD_MOD2) && (ev->xkey.state & Mod2Mask) && !(Mod2Mask & m))) {
continue;
}
if (((action->mod & MOD_MOD3) && !(ev->xkey.state & Mod3Mask)) || (!(action->mod & MOD_MOD3) && (ev->xkey.state & Mod3Mask) && !(Mod3Mask & m))) {
continue;
}
if (((action->mod & MOD_MOD4) && !(ev->xkey.state & Mod4Mask)) || (!(action->mod & MOD_MOD4) && (ev->xkey.state & Mod4Mask) && !(Mod4Mask & m))) {
continue;
}
if (((action->mod & MOD_MOD5) && !(ev->xkey.state & Mod5Mask)) || (!(action->mod & MOD_MOD5) && (ev->xkey.state & Mod5Mask) && !(Mod5Mask & m))) {
continue;
}
}
D_ACTIONS(("Match found.\n"));
/* If we've passed all the above tests, it's a match. Dispatch the handler. */
return ((action->handler)(ev, action));
}
return (0);
}

View File

@ -41,24 +41,28 @@ typedef enum {
#define KEYSYM_NONE (0UL)
#define MOD_NONE (0UL)
#define MOD_CTRL (1UL << 0)
#define MOD_SHIFT (1UL << 1)
#define MOD_LOCK (1UL << 2)
#define MOD_META (1UL << 3)
#define MOD_ALT (1UL << 4)
#define MOD_MOD1 (1UL << 5)
#define MOD_MOD2 (1UL << 6)
#define MOD_MOD3 (1UL << 7)
#define MOD_MOD4 (1UL << 8)
#define MOD_MOD5 (1UL << 9)
#define MOD_ANY (1UL << 10)
#define MOD_NONE (0UL)
#define MOD_CTRL (1UL << 0)
#define MOD_SHIFT (1UL << 1)
#define MOD_LOCK (1UL << 2)
#define MOD_META (1UL << 3)
#define MOD_ALT (1UL << 4)
#define MOD_MOD1 (1UL << 5)
#define MOD_MOD2 (1UL << 6)
#define MOD_MOD3 (1UL << 7)
#define MOD_MOD4 (1UL << 8)
#define MOD_MOD5 (1UL << 9)
#define MOD_ANY (1UL << 10)
#define BUTTON_NONE (0)
#define BUTTON_ANY (0xff)
#define BUTTON_NONE (0)
#define BUTTON_ANY (0xff)
#define LOGICAL_XOR(a, b) !(((a) && (b)) || (!(a) && !(b)))
#define SHOW_MODS(m) ((m & MOD_CTRL) ? 'C' : 'c'), ((m & MOD_SHIFT) ? 'S' : 's'), ((m & MOD_META) ? 'M' : 'm'), ((m & MOD_ALT) ? 'A' : 'a')
#define SHOW_X_MODS(m) ((m & ControlMask) ? 'C' : 'c'), ((m & ShiftMask) ? 'S' : 's'), ((m & MetaMask) ? 'M' : 'm'), ((m & AltMask) ? 'A' : 'a')
#define MOD_FMT "%c%c%c%c"
/************ Structures ************/
typedef struct action_struct action_t;
typedef unsigned char (*action_handler_t) (event_t *, action_t *);
@ -87,6 +91,9 @@ extern unsigned char action_handle_echo(event_t *ev, action_t *action);
extern unsigned char action_handle_script(event_t *ev, action_t *action);
extern unsigned char action_handle_menu(event_t *ev, action_t *action);
extern action_t *action_find_match(unsigned short mod, unsigned char button, KeySym keysym);
extern unsigned char action_check_button(unsigned char button, int x_button);
extern unsigned char action_check_keysym(KeySym keysym, KeySym x_keysym);
extern unsigned char action_check_modifiers(unsigned short mod, int x_mod);
extern unsigned char action_dispatch(event_t *ev, KeySym keysym);
extern void action_add(unsigned short mod, unsigned char button, KeySym keysym, action_type_t type, void *param);

View File

@ -80,7 +80,4 @@
# define DEBUG_X 9
# define DEBUG_PARSE 9999
# define D_PARSE(x) D_NEVER(x)
#endif /* _ETERM_DEBUG_H */

View File

@ -640,24 +640,65 @@ handle_button_press(event_t *ev)
}
button_state.last_button_press = 3;
break;
#ifdef MOUSEWHEEL
/* This section activates the following bindings:
*
* Mousewheel Up -- Scroll up 1 page
* Ctrl + Mousewheel Up -- Scroll up 5 pages
* Shift + Mousewheel Up -- Scroll up 1 line
* Alt + Mousewheel Up -- Send PgUp to tty
* Alt + Ctrl + Mousewheel Up -- Send 5 PgUp's to tty
* Alt + Shift + Mousewheel Up -- Send Up Arrow to tty
*
* Mousewheel Down -- Scroll down 1 page
* Ctrl + Mousewheel Down -- Scroll down 5 pages
* Shift + Mousewheel Down -- Scroll down 1 line
* Alt + Mousewheel Down -- Send PgDn to tty
* Alt + Ctrl + Mousewheel Down -- Send 5 PgDn's to tty
* Alt + Shift + Mousewheel Down -- Send Down Arrow to tty
*
* Note that the number of lines which constitute a "page" is equal to the number
* of text rows in the terminal window. The context lines are subtracted out *after*
* the conversion is done. In other words, scrolling 5 pages means scrolling
* (5 * LINES_PER_PAGE) - CONTEXT_LINES
* _not_
* (LINES_PER_PAGE - CONTEXT_LINES) * 5
*
* This is also true for the scroll() function in script.c.
*/
case Button4:
if ((button_state.last_button_press == 4) && (ev->xbutton.time - button_state.button_press < MULTICLICK_TIME)) {
button_state.clicks++;
} else {
button_state.clicks = 1;
if (action_check_modifiers(MOD_CTRL, ev->xbutton.state)) {
scr_page(UP, (TermWin.nrow * 5) - CONTEXT_LINES);
} else if (action_check_modifiers(MOD_SHIFT, ev->xbutton.state)) {
scr_page(UP, 1);
} else if (action_check_modifiers(MOD_ALT, ev->xbutton.state)) {
tt_write("\033[5~", 4);
} else if (action_check_modifiers((MOD_ALT | MOD_SHIFT), ev->xbutton.state)) {
tt_write("\033[A", 3);
} else if (action_check_modifiers((MOD_ALT | MOD_CTRL), ev->xbutton.state)) {
tt_write("\033[5~\033[5~\033[5~\033[5~\033[5~", 20);
} else {
scr_page(UP, TermWin.nrow - CONTEXT_LINES);
}
button_state.last_button_press = 4;
scr_page(UP, ((ev->xbutton.state & ShiftMask) ? (1) : (TermWin.nrow - CONTEXT_LINES)) * ((button_state.clicks > 1) ? 3 : 1));
break;
case Button5:
if ((button_state.last_button_press == 5) && (ev->xbutton.time - button_state.button_press < MULTICLICK_TIME)) {
button_state.clicks++;
} else {
button_state.clicks = 1;
if (action_check_modifiers(MOD_CTRL, ev->xbutton.state)) {
scr_page(DN, (TermWin.nrow * 5) - CONTEXT_LINES);
} else if (action_check_modifiers(MOD_SHIFT, ev->xbutton.state)) {
scr_page(DN, 1);
} else if (action_check_modifiers(MOD_ALT, ev->xbutton.state)) {
tt_write("\033[6~", 4);
} else if (action_check_modifiers((MOD_ALT | MOD_SHIFT), ev->xbutton.state)) {
tt_write("\033[B", 3);
} else if (action_check_modifiers((MOD_ALT | MOD_CTRL), ev->xbutton.state)) {
tt_write("\033[6~\033[6~\033[6~\033[6~\033[6~", 20);
} else {
scr_page(DN, TermWin.nrow - CONTEXT_LINES);
}
button_state.last_button_press = 5;
scr_page(DN, ((ev->xbutton.state & ShiftMask) ? (1) : (TermWin.nrow - CONTEXT_LINES)) * ((button_state.clicks > 1) ? 3 : 1));
break;
#endif
default: break;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -28,21 +28,6 @@
#include <X11/Intrinsic.h> /* Xlib, Xutil, Xresource, Xfuncproto */
/************ Macros and Definitions ************/
#if defined(PATH_MAX) && (PATH_MAX < 255)
# undef PATH_MAX
#endif
#ifndef PATH_MAX
# define PATH_MAX 255
#endif
#define CONF_BEGIN_CHAR ((char) 1)
#define CONF_END_CHAR ((char) 2)
#define PARSE_TRY_USER_THEME ((unsigned char) 0x01)
#define PARSE_TRY_DEFAULT_THEME ((unsigned char) 0x02)
#define PARSE_TRY_NO_THEME ((unsigned char) 0x04)
#define PARSE_TRY_ALL ((unsigned char) 0x07)
#define OPT_BOOLEAN 0x0001
#define OPT_INTEGER 0x0002
#define OPT_STRING 0x0004
@ -92,10 +77,10 @@
# define SAVE_THEME_CONFIG ((unsigned char) 1)
# define SAVE_USER_CONFIG ((unsigned char) 0)
#define BOOL_OPT_ISTRUE(s) (!strcasecmp((s), true_vals[0]) || !strcasecmp((s), true_vals[1]) \
|| !strcasecmp((s), true_vals[2]) || !strcasecmp((s), true_vals[3]))
#define BOOL_OPT_ISFALSE(s) (!strcasecmp((s), false_vals[0]) || !strcasecmp((s), false_vals[1]) \
|| !strcasecmp((s), false_vals[2]) || !strcasecmp((s), false_vals[3]))
#define PARSE_TRY_USER_THEME ((unsigned char) 0x01)
#define PARSE_TRY_DEFAULT_THEME ((unsigned char) 0x02)
#define PARSE_TRY_NO_THEME ((unsigned char) 0x04)
#define PARSE_TRY_ALL ((unsigned char) 0x07)
/* This defines how many mistakes to allow before giving up
and printing the usage -- mej */
@ -109,54 +94,6 @@
} \
} while(0)
/* The context table */
#define ctx_name_to_id(the_id, n, i) do { \
for ((i)=0; (i) <= ctx_idx; (i)++) { \
if (!strcasecmp((n), context[(i)].name)) { \
(the_id) = (i); \
break; \
} \
} \
if ((i) > ctx_idx) (the_id) = 0; \
} while (0)
#define ctx_id_to_name(id) (context[(id)].name)
#define ctx_id_to_func(id) (context[(id)].handler)
/* The context state stack. This keeps track of the current context and each previous one. */
#define ctx_push(ctx) conf_register_context_state(ctx)
#define ctx_pop() (ctx_state_idx--)
#define ctx_peek() (ctx_state[ctx_state_idx])
#define ctx_peek_id() (ctx_state[ctx_state_idx].ctx_id)
#define ctx_peek_state() (ctx_state[ctx_state_idx].state)
#define ctx_peek_last_id() (ctx_state[(ctx_state_idx?ctx_state_idx-1:0)].ctx_id)
#define ctx_peek_last_state() (ctx_state[(ctx_state_idx?ctx_state_idx-1:0)].state)
#define ctx_poke_state(q) ((ctx_state[ctx_state_idx].state) = (q))
#define ctx_get_depth() (ctx_state_idx)
/* The file state stack */
#define FILE_SKIP_TO_END (0x01)
#define FILE_PREPROC (0x02)
#define file_push(f, p, o, l, fl) conf_register_fstate(f, p, o, l, fl)
#define file_pop() (fstate_idx--)
#define file_peek() (fstate[fstate_idx])
#define file_peek_fp() (fstate[fstate_idx].fp)
#define file_peek_path() (fstate[fstate_idx].path)
#define file_peek_outfile() (fstate[fstate_idx].outfile)
#define file_peek_line() (fstate[fstate_idx].line)
#define file_peek_skip() (fstate[fstate_idx].flags & FILE_SKIP_TO_END)
#define file_peek_preproc() (fstate[fstate_idx].flags & FILE_PREPROC)
#define file_poke_fp(f) ((fstate[fstate_idx].fp) = (f))
#define file_poke_path(p) ((fstate[fstate_idx].path) = (p))
#define file_poke_outfile(o) ((fstate[fstate_idx].outfile) = (o))
#define file_poke_line(l) ((fstate[fstate_idx].line) = (l))
#define file_skip_to_end() ((fstate[fstate_idx].flags) |= (FILE_SKIP_TO_END))
#define file_poke_skip(s) do {if (s) {fstate[fstate_idx].flags |= FILE_SKIP_TO_END;} else {fstate[fstate_idx].flags &= ~(FILE_SKIP_TO_END);} } while (0)
#define file_poke_preproc(s) do {if (s) {fstate[fstate_idx].flags |= FILE_PREPROC;} else {fstate[fstate_idx].flags &= ~(FILE_PREPROC);} } while (0)
#define file_poke(f, p, o, l, fl) do {file_poke_fp(f); file_poke_path(p); file_poke_outfile(o); file_poke_line(l); fstate[fstate_idx].flags = (fl);} while (0)
#define file_inc_line() (fstate[fstate_idx].line++)
#define to_keysym(p,s) do { KeySym sym; \
if (s && ((sym = XStringToKeysym(s)) != 0)) *p = sym; \
} while (0)
@ -165,40 +102,8 @@
#define RESET_AND_ASSIGN(var, val) do {if ((var) != NULL) FREE(var); (var) = (val);} while (0)
/************ Structures ************/
/* Contexts */
typedef void * (*ctx_handler_t)(char *, void *);
typedef struct context_struct {
char *name;
ctx_handler_t handler;
} ctx_t;
typedef struct ctx_state_struct {
unsigned char ctx_id;
void *state;
} ctx_state_t;
/* Parser states */
typedef struct file_state_struct {
FILE *fp;
char *path, *outfile;
unsigned long line;
unsigned char flags;
} fstate_t;
/* Built-in functions */
typedef char * (*eterm_func_ptr_t) (char *);
typedef struct eterm_func_struct {
char *name;
eterm_func_ptr_t ptr;
} eterm_func_t;
typedef struct conf_var_struct {
char *var, *value;
struct conf_var_struct *next;
} conf_var_t;
/************ Variables ************/
extern fstate_t *fstate;
extern unsigned char fstate_idx;
extern unsigned long Options, image_toggles;
extern char *theme_dir, *user_dir;
extern char **rs_exec_args; /* Args to exec (-e or --exec) */
@ -255,16 +160,6 @@ _XFUNCPROTOBEGIN
unsigned long num_words(const char *str);
extern void get_initial_options(int, char **);
extern void get_options(int, char **);
extern void conf_init_subsystem(void);
extern unsigned char conf_register_context(char *name, ctx_handler_t handler);
extern unsigned char conf_register_fstate(FILE *fp, char *path, char *outfile, unsigned long line, unsigned char flags);
extern unsigned char conf_register_builtin(char *name, eterm_func_ptr_t ptr);
extern unsigned char conf_register_context_state(unsigned char ctx_id);
extern void conf_free_subsystem(void);
extern char *shell_expand(char *);
extern char *conf_find_file(const char *file, const char *dir, const char *pathlist);
extern FILE *open_config_file(char *name);
extern char *conf_parse(char *conf_name, const char *dir, const char *path);
extern char *conf_parse_theme(char **theme, char *conf_name, unsigned char fallback);
extern void init_defaults(void);
extern void post_parse(void);

View File

@ -225,7 +225,7 @@ scr_reset(void)
D_SCREEN(("screen.text == %8p, screen.rend == %8p, swap.text == %8p, swap.rend == %8p\n", screen.text, screen.rend, swap.text, swap.rend));
/* we have fewer rows so fix up number of scrolled lines */
MIN_IT(screen.row, TermWin.nrow - 1);
UPPER_BOUND(screen.row, TermWin.nrow - 1);
} else if (TermWin.nrow > prev_nrow) {
/* add rows */
@ -583,7 +583,7 @@ scroll_text(int row1, int row2, int count, int spec)
return 0;
if ((count > 0) && (row1 == 0) && (current_screen == PRIMARY)) {
TermWin.nscrolled += count;
MIN_IT(TermWin.nscrolled, TermWin.saveLines);
UPPER_BOUND(TermWin.nscrolled, TermWin.saveLines);
} else if (!spec)
row1 += TermWin.saveLines;
row2 += TermWin.saveLines;
@ -612,7 +612,7 @@ scroll_text(int row1, int row2, int count, int spec)
/* A: scroll up */
MIN_IT(count, row2 - row1 + 1);
UPPER_BOUND(count, row2 - row1 + 1);
/* A1: Copy and blank out lines that will get clobbered by the rotation */
for (i = 0, j = row1; i < count; i++, j++) {
@ -708,10 +708,8 @@ scr_add_lines(const unsigned char *str, int nlines, int len)
screen.row -= nlines;
}
}
MIN_IT(screen.col, last_col - 1);
MIN_IT(screen.row, TermWin.nrow - 1);
/*MAX_IT(screen.row, 0); */
MAX_IT(screen.row, -TermWin.nscrolled);
UPPER_BOUND(screen.col, last_col - 1);
BOUND(screen.row, -TermWin.nscrolled, TermWin.nrow - 1);
row = screen.row + TermWin.saveLines;
if (screen.text[row] == NULL) {
@ -755,7 +753,7 @@ scr_add_lines(const unsigned char *str, int nlines, int len)
scr_tab(1);
continue;
case '\n':
MAX_IT(stp[last_col], screen.col);
LOWER_BOUND(stp[last_col], screen.col);
screen.flags &= ~Screen_WrapNext;
if (screen.row == screen.bscroll) {
scroll_text(screen.tscroll, screen.bscroll, 1, 0);
@ -769,7 +767,7 @@ scr_add_lines(const unsigned char *str, int nlines, int len)
srp = screen.rend[row]; /* _must_ refresh */
continue;
case '\r':
MAX_IT(stp[last_col], screen.col);
LOWER_BOUND(stp[last_col], screen.col);
screen.flags &= ~Screen_WrapNext;
screen.col = 0;
continue;
@ -813,7 +811,7 @@ scr_add_lines(const unsigned char *str, int nlines, int len)
screen.flags &= ~Screen_WrapNext;
}
}
MAX_IT(stp[last_col], screen.col);
LOWER_BOUND(stp[last_col], screen.col);
if (screen.col == 0) {
end.col = last_col - 1;
end.row = screen.row - 1;
@ -889,14 +887,11 @@ scr_tab(int count)
void
scr_gotorc(int row, int col, int relative)
{
D_SCREEN(("scr_gotorc(r:%d,c:%d,%d): from (r:%d,c:%d)\n", row, col, relative, screen.row, screen.col));
ZERO_SCROLLBACK;
RESET_CHSTAT;
screen.col = ((relative & C_RELATIVE) ? (screen.col + col) : col);
MAX_IT(screen.col, 0);
MIN_IT(screen.col, TermWin.ncol - 1);
BOUND(screen.col, 0, TermWin.ncol - 1);
if (screen.flags & Screen_WrapNext) {
screen.flags &= ~Screen_WrapNext;
@ -918,12 +913,11 @@ scr_gotorc(int row, int col, int relative)
} else {
if (screen.flags & Screen_Relative) { /* relative origin mode */
screen.row = row + screen.tscroll;
MIN_IT(screen.row, screen.bscroll);
UPPER_BOUND(screen.row, screen.bscroll);
} else
screen.row = row;
}
MAX_IT(screen.row, 0);
MIN_IT(screen.row, TermWin.nrow - 1);
BOUND(screen.row, 0, TermWin.nrow - 1);
}
/*
@ -953,8 +947,7 @@ scr_index(int direction)
blank_screen_mem(screen.text, screen.rend, dirn, rstyle);
} else
screen.row += dirn;
MAX_IT(screen.row, 0);
MIN_IT(screen.row, TermWin.nrow - 1);
BOUND(screen.row, 0, TermWin.nrow - 1);
CHECK_SELECTION;
}
@ -982,7 +975,7 @@ scr_erase_line(int mode)
case 0: /* erase to end of line */
col = screen.col;
num = TermWin.ncol - col;
MIN_IT(screen.text[row][TermWin.ncol], col);
UPPER_BOUND(screen.text[row][TermWin.ncol], col);
break;
case 1: /* erase to beginning of line */
col = 0;
@ -1050,7 +1043,7 @@ scr_erase_screen(int mode)
return;
}
if (row >= 0 && row <= TermWin.nrow) { /* check OOB */
MIN_IT(num, (TermWin.nrow - row));
UPPER_BOUND(num, (TermWin.nrow - row));
if (rstyle & RS_RVid || rstyle & RS_Uline)
ren = -1;
else {
@ -1152,7 +1145,7 @@ scr_insdel_chars(int count, int insdel)
return;
CHECK_SELECTION;
MIN_IT(count, (TermWin.ncol - screen.col));
UPPER_BOUND(count, (TermWin.ncol - screen.col));
row = screen.row + TermWin.saveLines;
screen.flags &= ~Screen_WrapNext;
@ -1164,7 +1157,7 @@ scr_insdel_chars(int count, int insdel)
screen.rend[row][col] = screen.rend[row][col - count];
}
screen.text[row][TermWin.ncol] += count;
MIN_IT(screen.text[row][TermWin.ncol], TermWin.ncol);
UPPER_BOUND(screen.text[row][TermWin.ncol], TermWin.ncol);
/* FALLTHROUGH */
case ERASE:
blank_line(&(screen.text[row][screen.col]),
@ -1203,8 +1196,8 @@ scr_insdel_chars(int count, int insdel)
void
scr_scroll_region(int top, int bot)
{
MAX_IT(top, 0);
MIN_IT(bot, TermWin.nrow - 1);
LOWER_BOUND(top, 0);
UPPER_BOUND(bot, TermWin.nrow - 1);
if (top > bot)
return;
screen.tscroll = top;
@ -1502,8 +1495,7 @@ scr_move_to(int y, int len)
/ (len)) - (TermWin.nrow - 1);
D_SCREEN(("scr_move_to(%d, %d) view_start:%d\n", y, len, TermWin.view_start));
MAX_IT(TermWin.view_start, 0);
MIN_IT(TermWin.view_start, TermWin.nscrolled);
BOUND(TermWin.view_start, 0, TermWin.nscrolled);
return (TermWin.view_start - start);
}
@ -2224,8 +2216,7 @@ scr_search_scrollback(char *str)
} else {
if (lrow != rows) {
TermWin.view_start = rows - lrow - TermWin.nrow;
LOWER_BOUND(TermWin.view_start, 0);
UPPER_BOUND(TermWin.view_start, TermWin.nscrolled);
BOUND(TermWin.view_start, 0, TermWin.nscrolled);
D_SCREEN(("New view start is %d\n", TermWin.view_start));
}
}
@ -2562,12 +2553,10 @@ selection_setclr(int set, int startr, int startc, int endr, int endc)
}
last_col = TermWin.ncol - 1;
MIN_IT(endc, last_col);
MIN_IT(startr, TermWin.nrow - 1);
MAX_IT(startr, -TermWin.nscrolled);
MIN_IT(endr, TermWin.nrow - 1);
MAX_IT(endr, -TermWin.nscrolled);
MAX_IT(startc, 0);
LOWER_BOUND(startc, 0);
UPPER_BOUND(endc, last_col);
BOUND(startr, -TermWin.nscrolled, TermWin.nrow - 1);
BOUND(endr, -TermWin.nscrolled, TermWin.nrow - 1);
startr += TermWin.saveLines;
endr += TermWin.saveLines;
@ -2627,8 +2616,7 @@ selection_start_colrow(int col, int row)
selection.end.row, selection.end.col);
}
selection.op = SELECTION_INIT;
MAX_IT(row, 0);
MIN_IT(row, TermWin.nrow - 1);
BOUND(row, 0, TermWin.nrow - 1);
row -= TermWin.view_start;
end_col = screen.text[row + TermWin.saveLines][TermWin.ncol];
@ -2710,7 +2698,7 @@ selection_make(Time tm)
end_col = selection.end.col + 1;
} else
i = 1;
MIN_IT(end_col, TermWin.ncol);
UPPER_BOUND(end_col, TermWin.ncol);
for (; col < end_col; col++)
*str++ = *t++;
if (!(Options & Opt_select_trailing_spaces)) {
@ -2971,8 +2959,7 @@ selection_extend(int x, int y, int flag)
*/
col = Pixel2Col(x);
row = Pixel2Row(y);
MAX_IT(row, 0);
MIN_IT(row, TermWin.nrow - 1);
BOUND(row, 0, TermWin.nrow - 1);
if (((selection.clicks % 3) == 1) && !flag && (col == selection.mark.col && (row == selection.mark.row + TermWin.view_start))) {
/* select nothing */
selection_setclr(0, selection.beg.row, selection.beg.col,
@ -3033,8 +3020,7 @@ selection_extend_colrow(int col, int row, int flag, int cont)
return;
}
old_col = col;
MAX_IT(col, -1);
MIN_IT(col, TermWin.ncol);
BOUND(col, -1, TermWin.ncol);
old_beg.col = selection.beg.col;
old_beg.row = selection.beg.row;
old_end.col = selection.end.col;

View File

@ -29,11 +29,9 @@
#define IS_CUT_BUFFER(a) (((a) >= XA_CUT_BUFFER0) && ((a) <= XA_CUT_BUFFER7))
#define ZERO_SCROLLBACK do { \
D_SCREEN(("ZERO_SCROLLBACK()\n")); \
if (Options & Opt_home_on_output) TermWin.view_start = 0; \
} while (0)
#define REFRESH_ZERO_SCROLLBACK do { \
D_SCREEN(("REFRESH_ZERO_SCROLLBACK()\n")); \
if (Options & Opt_home_on_output) TermWin.view_start = 0; \
} while (0)
#define CHECK_SELECTION do { \

View File

@ -50,6 +50,7 @@ static eterm_script_handler_t script_handlers[] =
{ "paste", script_handler_paste },
{ "quit", script_handler_exit },
{ "save", script_handler_save },
{ "scroll", script_handler_scroll },
{ "search", script_handler_search },
{ "spawn", script_handler_spawn },
@ -122,6 +123,18 @@ eterm_handle_winop(char *action)
#endif
/********* HANDLERS **********/
/* copy(): Copy the current selection to the specified clipboard or cut
* buffer
*
* Syntax: copy([ <buffer> ])
*
* <buffer> is either a number 0-7, in which case the selection is copied to
* the the cut buffer specified, or one of the words "clipboard," "primary,"
* or "secondary" (or any initial substring thereof), in which case the
* selection is copied to the specified clipboard. The default buffer is
* the "primary" buffer (XA_PRIMARY in Xlib-speak).
*/
void
script_handler_copy(char **params)
{
@ -149,6 +162,15 @@ script_handler_copy(char **params)
selection_copy(sel);
}
/* exit(): Exit Eterm with an optional message or return code
*
* Syntax: exit([ { <msg> | <code> } ])
*
* <msg> is an optional exit message. <code> is a positive or
* negative integer return code. Either one may be specified, but not
* both. If neither is specified, Eterm exits with a return code of 0
* and no message.
*/
void
script_handler_exit(char **params)
{
@ -167,6 +189,17 @@ script_handler_exit(char **params)
exit(code);
}
/* paste(): Paste the contents of the specified clipboard or cut buffer
* into the terminal window
*
* Syntax: paste([ <buffer> ])
*
* <buffer> is either a number 0-7, in which case the contents of the cut
* buffer specified are pasted, or one of the words "clipboard," "primary,"
* or "secondary" (or any initial substring thereof), in which case the
* contents of the specified clipboard are pasted. The default buffer is
* the "primary" buffer (XA_PRIMARY in Xlib-speak).
*/
void
script_handler_paste(char **params)
{
@ -194,6 +227,16 @@ script_handler_paste(char **params)
selection_paste(sel);
}
/* save(): Save the current theme/user configuration
*
* Syntax: save([ { theme | user } ,] [ <filename> ])
*
* The "user" settings are saved by default, and the default
* filename is user.cfg. So save() by itself will save the
* current user settings to user.cfg. save(theme) will save
* the theme settings instead; the default filename in that case
* will be theme.cfg.
*/
void
script_handler_save(char **params)
{
@ -208,12 +251,80 @@ script_handler_save(char **params)
}
}
/* scroll(): Scroll backward or forward in the scrollback buffer
*
* Syntax: scroll(N) or scroll(Nl) -- Scroll N lines
* scroll(Np) -- Scroll N pages/screensful
* scroll(Nb) -- Scroll N buffers
*
* N is a floating point number. Use a negative number to scroll
* up and a positive number to scroll down. Fractions can be used
* also (e.g., to scroll one half page, use scroll(0.5p)). It is
* possible to spell out "lines," "pages," and "buffers" as well,
* and the type may be passed as a second parameter if you wish.
*/
void
script_handler_scroll(char **params)
{
char *type;
double cnt_float;
long count;
int direction = DN;
if (params && *params) {
cnt_float = strtod(params[0], &type);
if (cnt_float == 0.0) {
return;
} else if (cnt_float < 0.0) {
cnt_float = -cnt_float;
direction = UP;
}
if (!type) {
type = params[1];
}
if (type && *type) {
for (; *type && !isalpha(*type); type++);
if (str_leading_match("lines", type)) {
count = (long) cnt_float;
} else if (str_leading_match("pages", type) || str_leading_match("screens", type)) {
count = (long) ((cnt_float * TermWin.nrow) - CONTEXT_LINES);
} else if (str_leading_match("buffers", type)) {
count = (long) (cnt_float * (TermWin.nrow + TermWin.saveLines));
} else {
print_error("Invalid modifier \"%s\" in scroll()\n", type);
return;
}
} else {
count = (long) cnt_float;
}
if (count <= 0) {
return;
}
scr_page(direction, count);
}
}
/* search(): Search the scrollback buffer for a string and highlight
* any occurances of it.
*
* Syntax: search([ <str> ])
*
* <str> is an optional search string to highlight. If none is given,
* search() will clear the previously-highlighted search term.
*/
void
script_handler_search(char **params)
{
scr_search_scrollback(params ? params[0] : NULL);
}
/* spawn(): Spawns a child process to execute a sub-command
*
* Syntax: spawn([ <command> ])
*
* If no command is specified, the default is to execute another Eterm.
*/
void
script_handler_spawn(char **params)
{
@ -228,6 +339,12 @@ script_handler_spawn(char **params)
}
}
/* nop(): Do nothing
*
* Syntax: nop()
*
* This function can be used to cancel undesired default behavior.
*/
void
script_handler_nop(char **params)
{

View File

@ -47,6 +47,7 @@ extern void script_handler_copy(char **);
extern void script_handler_exit(char **);
extern void script_handler_paste(char **);
extern void script_handler_save(char **);
extern void script_handler_scroll(char **);
extern void script_handler_search(char **);
extern void script_handler_spawn(char **);
extern void script_handler_nop(char **);

View File

@ -258,10 +258,10 @@ sb_handle_button_press(event_t *ev)
if (scrollbar.type == SCROLLBAR_MOTIF || scrollbar.type == SCROLLBAR_NEXT) {
if (scrollbar_is_above_anchor(ev->xany.window, ev->xbutton.y)) {
scrollbar_draw_trough(IMAGE_STATE_CLICKED, 0);
scr_page(UP, TermWin.nrow - 1);
scr_page(UP, TermWin.nrow - CONTEXT_LINES);
} else if (scrollbar_is_below_anchor(ev->xany.window, ev->xbutton.y)) {
scrollbar_draw_trough(IMAGE_STATE_CLICKED, 0);
scr_page(DN, TermWin.nrow - 1);
scr_page(DN, TermWin.nrow - CONTEXT_LINES);
} else {
scrollbar_set_motion(1);
}
@ -270,7 +270,7 @@ sb_handle_button_press(event_t *ev)
#ifdef XTERM_SCROLLBAR
if (scrollbar.type == SCROLLBAR_XTERM) {
scr_page((ev->xbutton.button == Button1 ? DN : UP), TermWin.nrow - 1);
scr_page((ev->xbutton.button == Button1 ? DN : UP), TermWin.nrow - CONTEXT_LINES);
}
#endif /* XTERM_SCROLLBAR */
break;

View File

@ -146,9 +146,6 @@ eterm_bootstrap(int argc, char *argv[])
props[PROP_DND_PROTOCOL] = XInternAtom(Xdisplay, "DndProtocol", False);
props[PROP_DND_SELECTION] = XInternAtom(Xdisplay, "DndSelection", False);
/* Initialize the parser */
conf_init_subsystem();
if ((theme_dir = conf_parse_theme(&rs_theme, THEME_CFG, PARSE_TRY_ALL)) != NULL) {
char *tmp;

View File

@ -44,38 +44,6 @@
#define MAX_COLS 250
#define MAX_ROWS 128
#ifdef MIN
# undef MIN
#endif
#ifdef MAX
# undef MAX
#endif
#ifdef __GNUC__
# define MIN(a,b) __extension__ ({__typeof__(a) aa = (a); __typeof__(b) bb = (b); (aa < bb) ? (aa) : (bb);})
# define MAX(a,b) __extension__ ({__typeof__(a) aa = (a); __typeof__(b) bb = (b); (aa > bb) ? (aa) : (bb);})
# define LOWER_BOUND(current, other) __extension__ ({__typeof__(other) o = (other); ((current) < o) ? ((current) = o) : (current);})
# define AT_LEAST(current, other) LOWER_BOUND(current, other)
# define MAX_IT(current, other) LOWER_BOUND(current, other)
# define UPPER_BOUND(current, other) __extension__ ({__typeof__(other) o = (other); ((current) > o) ? ((current) = o) : (current);})
# define AT_MOST(current, other) UPPER_BOUND(current, other)
# define MIN_IT(current, other) UPPER_BOUND(current, other)
# define BOUND(val, min, max) __extension__ ({__typeof__(min) m1 = (min); __typeof__(max) m2 = (max); ((val) < m1) ? ((val) = m1) : (((val) > m2) ? ((val) = m2) : (val));})
# define CONTAIN(val, min, max) BOUND(val, min, max)
# define SWAP_IT(one, two, tmp) do {(tmp) = (one); (one) = (two); (two) = (tmp);} while (0)
#else
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
# define MAX(a,b) (((a) > (b)) ? (a) : (b))
# define LOWER_BOUND(current, other) (((current) < (other)) ? ((current) = (other)) : (current))
# define AT_LEAST(current, other) LOWER_BOUND(current, other)
# define MAX_IT(current, other) LOWER_BOUND(current, other)
# define UPPER_BOUND(current, other) (((current) > (other)) ? ((current) = (other)) : (current))
# define AT_MOST(current, other) UPPER_BOUND(current, other)
# define MIN_IT(current, other) UPPER_BOUND(current, other)
# define BOUND(val, min, max) (((val) < (min)) ? ((val) = (min)) : (((val) > (max)) ? ((val) = (max)) : (val)))
# define CONTAIN(val, min, max) BOUND(val, min, max)
# define SWAP_IT(one, two, tmp) do {(tmp) = (one); (one) = (two); (two) = (tmp);} while (0)
#endif
#define SHADOW 2
/* convert pixel dimensions to row/column values */