From bd1ed42760df07eaec4d99188fb05e3e5e41f7b2 Mon Sep 17 00:00:00 2001 From: Michael Jennings Date: Sat, 19 May 2001 06:56:45 +0000 Subject: This is work in progress, cleaning up the selection stuff. Still more to do, though. SVN revision: 4777 --- doc/Eterm.tcap | 2 +- src/actions.c | 61 +++++++++++--------- src/events.c | 4 +- src/screen.c | 172 ++++++++++++++++++++++----------------------------------- src/screen.h | 13 ++--- src/script.c | 58 +++++++++++++++++++ src/script.h | 2 + src/term.c | 14 ++--- 8 files changed, 175 insertions(+), 151 deletions(-) diff --git a/doc/Eterm.tcap b/doc/Eterm.tcap index d854640..4e7a57a 100644 --- a/doc/Eterm.tcap +++ b/doc/Eterm.tcap @@ -7,7 +7,7 @@ Eterm|Eterm-color|Eterm with xterm-style color support (X Window System):\ :ce=\E[K:cl=\E[H\E[2J:cm=\E[%i%d;%dH:cr=^M:\ :cs=\E[%i%d;%dr:ct=\E[3g:dc=\E[P:dl=\E[M:do=\E[B:\ :ec=\E[%dX:ei=\E[4l:ho=\E[H:i1=\E[?47l\E>\E[?1l:ic=\E[@:\ - :im=\E[4h:is=\E[r\E[m\E[2J\E[H\E[?7h\E[?1;3;4;6l:\ + :im=\E[4h:is=\E[r\E[m\E[2J\E[H\E[?7h\E[?1;3;4;6l\E[4l:\ :k1=\E[11~:k2=\E[12~:k3=\E[13~:k4=\E[14~:k5=\E[15~:\ :k6=\E[17~:k7=\E[18~:k8=\E[19~:k9=\E[20~:kD=\E[3~:\ :kI=\E[2~:kN=\E[6~:kP=\E[5~:kb=^H:kd=\E[B:ke=:kh=\E[7~:\ diff --git a/src/actions.c b/src/actions.c index 9b99c5b..aca6d46 100644 --- a/src/actions.c +++ b/src/actions.c @@ -46,41 +46,43 @@ static const char cvs_ident[] = "$Id$"; action_t *action_list = NULL; unsigned char -action_handle_string(event_t *ev, action_t *action) { - +action_handle_string(event_t *ev, action_t *action) +{ + USE_VAR(ev); REQUIRE_RVAL(action->param.string != NULL, 0); cmd_write((unsigned char *) action->param.string, strlen(action->param.string)); return 1; - ev = NULL; } unsigned char -action_handle_echo(event_t *ev, action_t *action) { - +action_handle_echo(event_t *ev, action_t *action) +{ + USE_VAR(ev); REQUIRE_RVAL(action->param.string != NULL, 0); tt_write((unsigned char *) action->param.string, strlen(action->param.string)); return 1; - ev = NULL; } unsigned char -action_handle_script(event_t *ev, action_t *action) { +action_handle_script(event_t *ev, action_t *action) +{ + USE_VAR(ev); REQUIRE_RVAL(action->param.script != NULL, 0); script_parse(action->param.script); return 1; - ev = NULL; } unsigned char -action_handle_menu(event_t *ev, action_t *action) { +action_handle_menu(event_t *ev, action_t *action) +{ REQUIRE_RVAL(action->param.menu != NULL, 0); menu_invoke(ev->xbutton.x, ev->xbutton.y, TermWin.parent, action->param.menu, ev->xbutton.time); return 1; } action_t * -action_find_match(unsigned short mod, unsigned char button, KeySym keysym) { - +action_find_match(unsigned short mod, unsigned char button, KeySym keysym) +{ action_t *action; D_ACTIONS(("mod == 0x%08x, button == %d, keysym == 0x%08x\n", mod, button, keysym)); @@ -95,37 +97,49 @@ action_find_match(unsigned short mod, unsigned char button, KeySym keysym) { } unsigned char -action_dispatch(event_t *ev, KeySym keysym) { - +action_dispatch(event_t *ev, KeySym keysym) +{ action_t *action; unsigned int m = (AltMask | MetaMask | NumLockMask); - ASSERT(ev != NULL); + 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)); 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 if (action->button != BUTTON_NONE) { - 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; + } } - D_ACTIONS(("Button passed.\n")); + D_ACTIONS(("Button/key passed.\n")); if (action->mod != MOD_ANY) { - if (LOGICAL_XOR((action->mod & MOD_SHIFT), (ev->xkey.state & ShiftMask))) { + /* 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_CTRL), (ev->xkey.state & ControlMask))) { + if (LOGICAL_XOR((action->mod & MOD_SHIFT), (ev->xkey.state & ShiftMask))) { continue; } - if (LOGICAL_XOR((action->mod & MOD_LOCK), (ev->xkey.state & LockMask))) { + 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_ALT), (ev->xkey.state & AltMask))) { + 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))) { @@ -144,16 +158,11 @@ action_dispatch(event_t *ev, KeySym keysym) { continue; } } - D_ACTIONS(("Modifiers passed. keysym == 0x%08x, action->keysym == 0x%08x\n", keysym, action->keysym)); - if ((ev->xany.type == KeyPress) && (action->keysym) && (keysym != action->keysym)) { - 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); - } void diff --git a/src/events.c b/src/events.c index 7bcf9a4..829d57d 100644 --- a/src/events.c +++ b/src/events.c @@ -538,7 +538,7 @@ handle_selection_notify(event_t *ev) D_EVENTS(("handle_selection_notify(ev [%8p] on window 0x%08x)\n", ev, ev->xany.window)); - selection_paste(ev->xselection.requestor, ev->xselection.property, True); + selection_fetch(ev->xselection.requestor, ev->xselection.property, True); return 1; } @@ -708,7 +708,7 @@ handle_button_release(event_t *ev) break; case Button2: - selection_request(ev->xbutton.time, ev->xbutton.x, ev->xbutton.y); + selection_paste(XA_PRIMARY, XA_CUT_BUFFER0); break; default: break; } diff --git a/src/screen.c b/src/screen.c index e8aee26..a762a68 100644 --- a/src/screen.c +++ b/src/screen.c @@ -2358,35 +2358,34 @@ selection_check(void) } } -/* - * Paste a selection direct to the command - */ +/* Write the selection out to the tty. */ void -PasteIt(unsigned char *data, unsigned int nitems) +selection_write(unsigned char *data, size_t len) { - int num; - unsigned char *p, cr; + size_t num; + unsigned char *p, *cr = "\r"; - cr = '\r'; - for (p = data, num = 0; nitems--; p++) - if (*p != '\n') + D_SELECT(("Writing %lu characters of selection data to tty.\n", len)); + for (p = data, num = 0; len--; p++) { + /* Write out each line, replacing newlines with carriage returns. */ + if (*p != '\n') { num++; - else { + } else { tt_write(data, num); - tt_write(&cr, 1); - data += (num + 1); + tt_write(cr, 1); + data += num + 1; num = 0; } - if (num) + } + /* If there's anything left, write it out too. */ + if (num) { tt_write(data, num); + } } -/* - * Respond to a notification that a primary selection has been sent - * EXT: SelectionNotify - */ +/* Fetch the selection from the specified property and write it to the tty. */ void -selection_paste(Window win, unsigned prop, int delete) +selection_fetch(Window win, unsigned prop, int delete) { long nread; unsigned long bytes_after, nitems; @@ -2394,10 +2393,13 @@ selection_paste(Window win, unsigned prop, int delete) Atom actual_type; int actual_fmt; - if (prop == None) + D_SELECT(("Fetching selection in property %d from window 0x%08x\n", (int) prop, (int) win)); + if (prop == None) { return; + } for (nread = 0, bytes_after = 1; bytes_after > 0;) { if ((XGetWindowProperty(Xdisplay, win, prop, (nread / 4), PROP_SIZE, delete, AnyPropertyType, &actual_type, &actual_fmt, &nitems, &bytes_after, &data) != Success)) { + D_SELECT(("Unable to fetch the value of property %d from window 0x%08x\n", (int) prop, (int) win)); if (data != NULL) { XFree(data); } @@ -2406,12 +2408,14 @@ selection_paste(Window win, unsigned prop, int delete) nread += nitems; if (actual_type == XA_STRING) { - PasteIt(data, nitems); + /* We can handle strings directly. */ + selection_write(data, nitems); } else { int size, i; XTextProperty xtextp; char **cl = NULL; + /* It's not a string, so convert it to one (or more). */ xtextp.value = data; xtextp.encoding = actual_type; xtextp.format = actual_fmt; @@ -2421,7 +2425,7 @@ selection_paste(Window win, unsigned prop, int delete) if (cl) { for (i = 0 ; i < size ; i ++) { if (cl[i]) { - PasteIt(cl[i], strlen(cl[i])); + selection_write(cl[i], strlen(cl[i])); } } XFreeStringList(cl); @@ -2433,79 +2437,64 @@ selection_paste(Window win, unsigned prop, int delete) } } -/* - * Request the current primary selection - * EXT: button 2 release - */ +/* Copy a specific string of a given length to the buffer specified. */ void -selection_request(Time tm, int x, int y) +selection_copy_string(Atom selection_atom, Atom prop, char *str, size_t len) { - Atom prop; - - if (x < 0 || x >= TermWin.width || y < 0 || y >= TermWin.height) - return; /* outside window */ - - if (selection.text != NULL) { - PasteIt(selection.text, selection.len); /* internal selection */ - } else if (XGetSelectionOwner(Xdisplay, XA_PRIMARY) == None) { - selection_paste(Xroot, XA_CUT_BUFFER0, False); - } else { - prop = XInternAtom(Xdisplay, "VT_SELECTION", False); -#if defined(MULTI_CHARSET) && defined(HAVE_X11_XMU_ATOMS_H) - if (encoding_method != LATIN1) { - XConvertSelection(Xdisplay, XA_PRIMARY, XA_COMPOUND_TEXT(Xdisplay), prop, TermWin.vt, tm); - } else { - XConvertSelection(Xdisplay, XA_PRIMARY, XA_STRING, prop, TermWin.vt, tm); - } -#else - XConvertSelection(Xdisplay, XA_PRIMARY, XA_STRING, prop, TermWin.vt, tm); -#endif + if (str == NULL || len == 0) { + return; } -} - -void -selection_copy(Atom selection, Atom prop, char *str, size_t len) -{ - XSetSelectionOwner(Xdisplay, selection, TermWin.vt, CurrentTime); - if (XGetSelectionOwner(Xdisplay, XA_PRIMARY) != TermWin.vt) { - print_error("Can't take ownership of primary selection\n"); + D_SELECT(("Copying selection to selection %d, buffer %d\n", (int) selection_atom, (int) prop)); + XSetSelectionOwner(Xdisplay, selection_atom, TermWin.vt, CurrentTime); + if (XGetSelectionOwner(Xdisplay, selection_atom) != TermWin.vt) { + print_error("Can't take ownership of selection\n"); } XChangeProperty(Xdisplay, Xroot, prop, XA_STRING, 8, PropModeReplace, str, len); } +/* Copy the currently-selected text to the buffer specified. */ void -selection_copy_to_clipboard(void) +selection_copy(Atom selection_atom, Atom prop) { - if (selection.text) { - selection_copy(X_CLIPBOARD_SELECTION, X_CLIPBOARD_PROP, selection.text, selection.len); - } + selection_copy_string(selection_atom, prop, selection.text, selection.len); } +/* Paste the specified selection from the specified buffer. */ void -selection_paste_from_clipboard(void) +selection_paste(Atom selection_atom, Atom prop) { - Atom select, type; + static Atom dest_prop = None; + + if (dest_prop == None) { + dest_prop = XInternAtom(Xdisplay, "VT_SELECTION", False); + } - select = X_CLIPBOARD_SELECTION; - if (XGetSelectionOwner(Xdisplay, select) == None) { - selection_paste(Xroot, X_CLIPBOARD_PROP, False); + if (selection.text != NULL) { + /* If we have a selection of our own, paste it. */ + D_SELECT(("Pasting my current selection of length %lu\n", selection.len)); + selection_write(selection.text, selection.len); + } else if (XGetSelectionOwner(Xdisplay, selection_atom) == None) { + /* If nobody owns the current selection, just try to paste it ourselves. */ + D_SELECT(("Pasting un-owned current selection %d\n", (int) prop)); + selection_fetch(Xroot, prop, False); } else { - type = XInternAtom(Xdisplay, "VT_SELECTION", False); + /* If someone owns the current selection, send a request to that client to + convert the selection to the appropriate form (usually XA_STRING) and + save it for us in the VT_SELECTION property. We'll then get a SelectionNotify. */ + D_SELECT(("Requesting current selection (%d) -> VT_SELECTION (%d)\n", selection_atom, dest_prop)); #if defined(MULTI_CHARSET) && defined(HAVE_X11_XMU_ATOMS_H) if (encoding_method != LATIN1) { - XConvertSelection(Xdisplay, select, XA_COMPOUND_TEXT(Xdisplay), type, TermWin.vt, CurrentTime); + XConvertSelection(Xdisplay, selection_atom, XA_COMPOUND_TEXT(Xdisplay), dest_prop, TermWin.vt, CurrentTime); } else { - XConvertSelection(Xdisplay, select, XA_STRING, type, TermWin.vt, CurrentTime); + XConvertSelection(Xdisplay, selection_atom, XA_STRING, dest_prop, TermWin.vt, CurrentTime); } #else - XConvertSelection(Xdisplay, select, XA_STRING, type, TermWin.vt, CurrentTime); + XConvertSelection(Xdisplay, selection_atom, XA_STRING, dest_prop, TermWin.vt, CurrentTime); #endif } } -/* - * Clear the current selection from the screen rendition list - */ +/* Clear the selected state of all selected text. */ void selection_reset(void) { @@ -2526,24 +2515,20 @@ selection_reset(void) } } } -/* - * Clear all selected text - * EXT: - */ +/* Delete the current selection. */ void selection_clear(void) { D_SELECT(("selection_clear()\n")); - if (selection.text) + if (selection.text) { FREE(selection.text); - selection.text = NULL; + } selection.len = 0; selection_reset(); } -/* - * Set or clear between selected points (inclusive) - */ + +/* Set or clear between selected points (inclusive) */ void selection_setclr(int set, int startr, int startc, int endr, int endc) { @@ -2726,7 +2711,7 @@ selection_make(Time tm) selection.text = new_selection_text; selection.screen = current_screen; - selection_copy(XA_PRIMARY, XA_CUT_BUFFER0, selection.text, selection.len); + selection_copy(XA_PRIMARY, XA_CUT_BUFFER0); D_SELECT(("selection.len=%d\n", selection.len)); return; tm = 0; @@ -3298,33 +3283,6 @@ mouse_report(XButtonEvent * ev) (32 + Pixel2Row(ev->y) + 1)); } - -void -mouse_tracking(int report, int x, int y, int firstrow, int lastrow) -{ - report = 0; - x = 0; - y = 0; - firstrow = 0; - lastrow = 0; -/* TODO */ -} - -void -debug_PasteIt(unsigned char *data, int nitems) -{ - data = NULL; - nitems = 0; -/* TODO */ -} - -int -debug_selection(void) -{ -/* TODO */ - return 0; -} - void debug_colors(void) { diff --git a/src/screen.h b/src/screen.h index 8dc07db..7d98bd0 100644 --- a/src/screen.h +++ b/src/screen.h @@ -284,12 +284,11 @@ extern void scr_search_scrollback(char *); extern void scr_dump(void); extern void scr_dump_to_file(const char *); extern void selection_check(void); -extern void PasteIt(unsigned char *, unsigned int); -extern void selection_paste(Window, unsigned, int); -extern void selection_request(Time, int, int); -extern void selection_copy(Atom, Atom, char *, size_t); -extern void selection_copy_to_clipboard(void); -extern void selection_paste_from_clipboard(void); +extern void selection_write(unsigned char *, size_t); +extern void selection_fetch(Window, unsigned, int); +extern void selection_copy_string(Atom, Atom, char *, size_t); +extern void selection_copy(Atom, Atom); +extern void selection_paste(Atom, Atom); extern void selection_reset(void); extern void selection_clear(void); extern void selection_setclr(int, int, int, int, int); @@ -304,8 +303,6 @@ extern void selection_rotate(int, int); extern void selection_send(XSelectionRequestEvent *); extern void mouse_report(XButtonEvent *); extern void mouse_tracking(int, int, int, int, int); -extern void debug_PasteIt(unsigned char *, int); -extern int debug_selection(void); extern void debug_colors(void); #ifdef MULTI_CHARSET extern int scr_multi2(void); diff --git a/src/script.c b/src/script.c index 91fec73..2c0613d 100644 --- a/src/script.c +++ b/src/script.c @@ -43,9 +43,11 @@ static const char cvs_ident[] = "$Id$"; static eterm_script_handler_t script_handlers[] = { + { "copy", script_handler_copy }, { "die", script_handler_exit }, { "exec", script_handler_spawn }, { "exit", script_handler_exit }, + { "paste", script_handler_paste }, { "quit", script_handler_exit }, { "save", script_handler_save }, { "search", script_handler_search }, @@ -120,6 +122,34 @@ eterm_handle_winop(char *action) #endif /********* HANDLERS **********/ +void +script_handler_copy(char **params) +{ + unsigned char i; + char *buffer_id; + Atom sel = XA_PRIMARY, buf = XA_CUT_BUFFER0; + + if (params) { + for (i = 0; (buffer_id = params[i]) != NULL; i++) { + if (*buffer_id) { + if (*buffer_id >= '0' && *buffer_id <= '7') { + buf = (Atom) ((int) XA_CUT_BUFFER0 + (int) *buffer_id); + } else if (!BEG_STRCASECMP(buffer_id, "clipboard")) { + buf = X_CLIPBOARD_PROP; + sel = X_CLIPBOARD_SELECTION; + } else if (!BEG_STRCASECMP(buffer_id, "primary")) { + sel = XA_PRIMARY; + } else if (!BEG_STRCASECMP(buffer_id, "secondary")) { + sel = XA_SECONDARY; + } else { + print_error("Invalid parameter to copy(): \"%s\"\n", buffer_id); + } + } + } + } + selection_copy(sel, buf); +} + void script_handler_exit(char **params) { @@ -138,6 +168,34 @@ script_handler_exit(char **params) exit(code); } +void +script_handler_paste(char **params) +{ + unsigned char i; + char *buffer_id; + Atom sel = XA_PRIMARY, buf = XA_CUT_BUFFER0; + + if (params) { + for (i = 0; (buffer_id = params[i]) != NULL; i++) { + if (*buffer_id) { + if (*buffer_id >= '0' && *buffer_id <= '7') { + buf = (Atom) ((int) XA_CUT_BUFFER0 + (int) *buffer_id); + } else if (!BEG_STRCASECMP(buffer_id, "clipboard")) { + buf = X_CLIPBOARD_PROP; + sel = X_CLIPBOARD_SELECTION; + } else if (!BEG_STRCASECMP(buffer_id, "primary")) { + sel = XA_PRIMARY; + } else if (!BEG_STRCASECMP(buffer_id, "secondary")) { + sel = XA_SECONDARY; + } else { + print_error("Invalid parameter to paste(): \"%s\"\n", buffer_id); + } + } + } + } + selection_paste(sel, buf); +} + void script_handler_save(char **params) { diff --git a/src/script.h b/src/script.h index 5fc0c9b..f4c9ea9 100644 --- a/src/script.h +++ b/src/script.h @@ -43,7 +43,9 @@ typedef struct { _XFUNCPROTOBEGIN /* Handlers */ +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_search(char **); extern void script_handler_spawn(char **); diff --git a/src/term.c b/src/term.c index 4bffcd1..7c98d3c 100644 --- a/src/term.c +++ b/src/term.c @@ -300,11 +300,11 @@ lookup_key(XEvent * ev) switch (keysym) { case SunXK_Copy: case SunXK_Cut: - selection_copy_to_clipboard(); + selection_copy(X_CLIPBOARD_SELECTION, X_CLIPBOARD_PROP); LK_RET(); break; case SunXK_Paste: - selection_paste_from_clipboard(); + selection_paste(X_CLIPBOARD_SELECTION, X_CLIPBOARD_PROP); LK_RET(); break; case SunXK_Front: @@ -338,7 +338,7 @@ lookup_key(XEvent * ev) break; case XK_Insert: /* Shift-Ins pastes the current selection. */ - selection_request(ev->xkey.time, ev->xkey.x, ev->xkey.y); + selection_paste(XA_PRIMARY, XA_CUT_BUFFER0); LK_RET(); break; @@ -379,13 +379,13 @@ lookup_key(XEvent * ev) case XK_Print: /* Print the screen contents out to the print pipe */ #if DEBUG >= DEBUG_SELECTION if (DEBUG_LEVEL >= DEBUG_SELECTION) { - debug_selection(); - } + scr_dump_to_file("/tmp/Eterm_screen_dump.log"); + } else #endif #ifdef PRINTPIPE - scr_printscreen(ctrl | shft); - LK_RET(); + scr_printscreen(ctrl | shft); #endif + LK_RET(); break; case XK_Mode_switch: -- cgit v1.2.1