📄 editwidget.c
字号:
/* editor initialisation and callback handler. Copyright (C) 1996-2000 the Free Software Foundation Authors: 1996, 1997 Paul Sheer This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */#include <config.h>#include "edit.h"#ifndef MIDNIGHT#include <X11/Xmd.h> /* CARD32 */#include <X11/Xatom.h>#include "app_glob.c"#include "coollocal.h"#include "editcmddef.h"#include "mousemark.h"#endif#if defined (HAVE_MAD) && ! defined (MIDNIGHT) && ! defined (GTK)#include "mad.h"#endif#ifndef MIDNIGHTextern int EditExposeRedraw;CWidget *wedit = 0;void shell_output_kill_jobs (WEdit * edit);void shell_output_kill_job (WEdit * edit, pid_t pid);void edit_destroy_callback (CWidget * w){ if (w) { shell_output_kill_jobs (w->editor); edit_clean (w->editor); if (w->editor) free (w->editor); w->editor = NULL; } else/* NLS ? */ CError ("Trying to destroy non-existing editor widget.\n");}#define CLOSE_ON_NO_DATA#define SHELL_INPUT_BUF_SIZE 1024static void shell_output_write_callback (int fd, fd_set * reading, fd_set * writing, fd_set * error, void *data){ unsigned char s[SHELL_INPUT_BUF_SIZE]; int i; WEdit *edit; long start_mark, end_mark; edit = (WEdit *) data;/* if the process is available for reading, and there is not selected text, then remove the watch on the process's stdin, and close the stdin */ if (eval_marks (edit, &start_mark, &end_mark)) { struct shell_job *j; CRemoveWatch (fd, shell_output_write_callback, WATCH_WRITING); for (j = edit->jobs; j; j = j->next) if (j->in == fd) { if (j->close_on_error) close (fd); break; } return; } for (i = 0; i < SHELL_INPUT_BUF_SIZE && start_mark + i < end_mark; i++) s[i] = edit_get_byte (edit, start_mark + i); while ((i = write (fd, s, i)) < 0 && errno == EINTR); if (i <= 0) { struct shell_job *j; for (j = edit->jobs; j; j = j->next) if (j->in == fd || j->out == fd) { if (CChildExitted (j->pid, 0)) shell_output_kill_job (edit, j->pid); break; } return; } edit_cursor_move (edit, start_mark - edit->curs1); while (i--) edit_delete (edit); edit->force |= REDRAW_PAGE; edit_update_screen (edit);}#define SHELL_OUTPUT_BUF_SIZE 16384static void shell_output_read_callback (int fd, fd_set * reading, fd_set * writing, fd_set * error, void *data){ WEdit *edit; unsigned char s[SHELL_OUTPUT_BUF_SIZE]; int i, n, move_mark; long start_mark, end_mark; edit = (WEdit *) data; if (!eval_marks (edit, &start_mark, &end_mark)) move_mark = (start_mark == edit->curs1); while ((i = read (fd, s, SHELL_OUTPUT_BUF_SIZE)) < 0 && errno == EINTR); if (i <= 0) { struct shell_job *j; for (j = edit->jobs; j; j = j->next) if (j->in == fd || j->out == fd) { if (CChildExitted (j->pid, 0)) shell_output_kill_job (edit, j->pid); break; } return; } for (n = 0; n < i; n++) edit_insert (edit, s[n]);/* must insert BEFORE and not INTO the selection */ if (move_mark) edit_set_markers (edit, start_mark + i, end_mark + i, -1, -1); edit->force |= REDRAW_PAGE; edit_update_screen (edit);}void shell_output_add_job (WEdit * edit, int in, int out, pid_t pid, char *name, int close_on_error){ struct shell_job *j; long start_mark, end_mark; CAddWatch (out, shell_output_read_callback, WATCH_READING, edit); if (!eval_marks (edit, &start_mark, &end_mark)) CAddWatch (in, shell_output_write_callback, WATCH_WRITING, edit); else if (close_on_error) { close (in); in = -1; } j = malloc (sizeof (*j)); memset (j, 0, sizeof (*j)); j->next = edit->jobs; j->in = in; j->out = out; j->close_on_error = close_on_error; j->name = (char *) strdup (name); j->pid = pid; edit->jobs = j;}static void shell_output_destroy_job (struct shell_job *j){ if (j->out >= 0) { CRemoveWatch (j->out, shell_output_read_callback, WATCH_READING); close (j->out); } if (j->in >= 0) { CRemoveWatch (j->in, shell_output_write_callback, WATCH_WRITING); close (j->in); } if (j->pid > 0) kill (j->pid, SIGTERM); free (j->name); memset (j, 0, sizeof (*j)); free (j);}void shell_output_kill_jobs (WEdit * edit){ struct shell_job *j, *n; if (!edit) return; for (j = edit->jobs; j; j = n) { n = j->next; shell_output_destroy_job (j); } edit->jobs = 0;}void shell_output_kill_job (WEdit * edit, pid_t pid){ struct shell_job *j, *p; int done; do { done = 1; p = edit->jobs; for (j = edit->jobs; j; j = j->next) { if (j->pid == pid) { if ((unsigned long) j == (unsigned long) edit->jobs) { edit->jobs = edit->jobs->next; shell_output_destroy_job (j); done = 0; break; } else { p->next = j->next; shell_output_destroy_job (j); done = 0; break; } } p = j; } } while (!done);}void link_hscrollbar_to_editor (CWidget * scrollbar, CWidget * editor, XEvent * xevent, CEvent * cwevent, int whichscrbutton);/* returns the position in the edit buffer of a window click */long edit_get_click_pos (WEdit * edit, int x, int y){ long click;/* (1) goto to left margin */ click = edit_bol (edit, edit->curs1);/* (1) move up or down */ if (y > (edit->curs_row + 1)) click = edit_move_forward (edit, click, y - (edit->curs_row + 1), 0); if (y < (edit->curs_row + 1)) click = edit_move_backward (edit, click, (edit->curs_row + 1) - y);/* (3) move right to x pos */ click = edit_move_forward3 (edit, click, x - edit->start_col - 1, 0); return click;}void edit_translate_xy (int xs, int ys, int *x, int *y){ *x = xs - EDIT_TEXT_HORIZONTAL_OFFSET; *y = (ys - EDIT_TEXT_VERTICAL_OFFSET - option_text_line_spacing / 2 - 1) / FONT_PIX_PER_LINE + 1;}extern int just_dropped_something;void mouse_redraw (WEdit * edit, long click){ edit->force |= REDRAW_PAGE | REDRAW_LINE; edit_update_curs_row (edit); edit_update_curs_col (edit); edit->prev_col = edit_get_col (edit); edit_update_screen (edit); edit->search_start = click;}static void xy (int x, int y, int *x_return, int *y_return){ edit_translate_xy (x, y, x_return, y_return);}static long cp (WEdit * edit, int x, int y){ return edit_get_click_pos (edit, x, y);}/* return 1 if not marked */static int marks (WEdit * edit, long *start, long *end){ return eval_marks (edit, start, end);}int column_highlighting = 0;static int erange (WEdit * edit, long start, long end, int click){ if (column_highlighting) { int x; x = edit_move_forward3 (edit, edit_bol (edit, click), 0, click); if ((x >= edit->column1 && x < edit->column2) || (x > edit->column2 && x <= edit->column1)) return (start <= click && click < end); else return 0; } return (start <= click && click < end);}static void fin_mark (WEdit * edit){ if (edit->mark2 < 0) edit_mark_cmd (edit, 0);}static void move_mark (WEdit * edit){ edit_mark_cmd (edit, 1); edit_mark_cmd (edit, 0);}static void release_mark (WEdit * edit, XEvent * event){ if (edit->mark2 < 0) edit_mark_cmd (edit, 0); else edit_mark_cmd (edit, 1); if (edit->mark1 != edit->mark2 && event) { edit_get_selection (edit); XSetSelectionOwner (CDisplay, XA_PRIMARY, CWindowOf (edit->widget), event->xbutton.time); }#ifdef GTK else { edit->widget->editable.has_selection = TRUE; }#endif}static char *get_block (WEdit * edit, long start_mark, long end_mark, int *type, int *l){ char *t; t = (char *) edit_get_block (edit, start_mark, end_mark, l); if (strlen (t) < *l) *type = DndRawData; /* if there are nulls in the data, send as raw */ else *type = DndText; /* else send as text */ return t;}static void move (WEdit * edit, long click, int y){ edit_cursor_move (edit, click - edit->curs1);}static void dclick (WEdit * edit, XEvent * event){ edit_mark_cmd (edit, 1); edit_right_word_move (edit, 1); edit_mark_cmd (edit, 0); edit_left_word_move (edit, 1); release_mark (edit, event);}static void redraw (WEdit * edit, long click){ mouse_redraw (edit, click);}void edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width);/* strips out the first i chars and returns a null terminated string, result must be free'd */char *filename_from_url (char *data, int size, int i){ char *p, *f; int l; for (p = data + i; (unsigned long) p - (unsigned long) data < size && *p && *p != '\n'; p++); l = (unsigned long) p - (unsigned long) data - i; f = malloc (l + 1); memcpy (f, data + i, l); f[l] = '\0'; return f;}static int insert_drop (WEdit * e, Window from, unsigned char *data, int size, int xs, int ys, Atom type, Atom action){ long start_mark = 0, end_mark = 0; int x, y; edit_translate_xy (xs, ys, &x, &y);/* musn't be able to drop into a block, otherwise a single click will copy a block: */ if (eval_marks (e, &start_mark, &end_mark)) goto fine; if (start_mark > e->curs1 || e->curs1 >= end_mark) goto fine; if (column_highlighting) { if (!((x >= e->column1 && x < e->column2) || (x > e->column2 && x <= e->column1))) goto fine; } return 1; fine: if (from == e->widget->winid && action == CDndClass->XdndActionMove) { edit_block_move_cmd (e); edit_mark_cmd (e, 1); return 0; } else if (from == e->widget->winid) { edit_block_copy_cmd (e); return 0; } else { /* data from another widget, or from another application */ edit_push_action (e, KEY_PRESS + e->start_display); if (type == XInternAtom (CDisplay, "url/url", False)) { if (!strncmp ((char *) data, "file:/", 6)) { char *f; edit_insert_file (e, f = filename_from_url ((char *) data, size, strlen ("file:"))); free (f); } else { while (size--) edit_insert_ahead (e, data[size]); } } else { if (column_highlighting) { edit_insert_column_of_text (e, data, size, abs (e->column2 - e->column1)); } else { while (size--) edit_insert_ahead (e, data[size]); } } } CExpose (e->widget->ident); return 0;}static char *mime_majors[2] ={"text", 0};struct mouse_funcs edit_mouse_funcs ={ 0, (void (*)(int, int, int *, int *)) xy, (long (*)(void *, int, int)) cp, (int (*)(void *, long *, long *)) marks, (int (*)(void *, long, long, long)) erange, (void (*)(void *)) fin_mark, (void (*)(void *)) move_mark, (void (*)(void *, XEvent *)) release_mark, (char *(*)(void *, long, long, int *, int *)) get_block, (void (*)(void *, long, int)) move, 0, (void (*)(void *, XEvent *)) dclick, (void (*)(void *, long)) redraw, (int (*)(void *, Window, unsigned char *, int, int, int, Atom, Atom)) insert_drop, (void (*)(void *)) edit_block_delete, DndText, mime_majors};static void render_book_marks (CWidget * w);extern int option_editor_bg_normal;void edit_tri_cursor (Window win);/* starting_directory is for the filebrowser */CWidget *CDrawEditor (const char *identifier, Window parent, int x, int y, int width, int height, const char *text, const char *filename, const char *starting_directory, unsigned int options, unsigned long text_size){ static int made_directory = 0; int extra_space_for_hscroll = 0; int max_x = 0; CWidget *w; WEdit *e; CPushFont ("editor", 0); if (options & EDITOR_HORIZ_SCROLL) extra_space_for_hscroll = 8; wedit = w = CSetupWidget (identifier, parent, x, y, width + EDIT_FRAME_W, height + EDIT_FRAME_H, C_EDITOR_WIDGET, INPUT_KEY, color_palette (option_editor_bg_normal), 1); xdnd_set_dnd_aware (CDndClass, w->winid, 0); xdnd_set_type_list (CDndClass, w->winid, xdnd_typelist_send[DndText]); edit_tri_cursor (w->winid); w->options = options | WIDGET_TAKES_SELECTION; w->destroy = edit_destroy_callback; if (filename) w->label = (char *) strdup (filename); else w->label = (char *) strdup (""); if (!made_directory) { mkdir (catstrs (home_dir, EDIT_DIR, 0), 0700); made_directory = 1; } e = w->editor = CMalloc (sizeof (WEdit)); w->funcs = mouse_funcs_new (w->editor, &edit_mouse_funcs); if (!w->editor) {/* Not essential to translate */ CError (_("Error initialising editor.\n")); CPopFont (); return 0; } w->editor->widget = w;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -