/* Tk Viewer stuff. Copyright (C) 1995 Miguel de Icaza 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., 675 Mass Ave, Cambridge, MA 02139, USA. ----- This module is here so that I can learn to shut up my mouth. I know, Jakub is enjoying this moment, anyways, this code is still smaller than a complete tkview.c program, and it's just interface code so that the code knows about the window resize. */ #include #define WANT_WIDGETS #include "dlg.h" #include "view.h" #include "tkmain.h" void x_init_view (WView *view) { view->status_shown = 0; view->current_line = 1; view->cache_len = 80; view->last_col = 0; view->cache = xmalloc (81, "view->cache"); view->color_cache = xmalloc (81, "view->cache"); view->direction = 1; bzero (view->cache, 81); view->dest = 0; } void x_destroy_view (WView *view) { free (view->cache); free (view->color_cache); } /* Accepts the dim command with the width and the height in characters */ static int tk_viewer_callback (ClientData cd, Tcl_Interp *interp, int ac, char *av[]) { WView *view = (WView *) cd; if (av [1][0] != 'd') return TCL_OK; view->widget.cols = atoi (av [2]); view->widget.lines = atoi (av [3]); return TCL_OK; } void x_create_viewer (WView *view) { char *cmd; widget_data parent; /* First, check if our parent is ".", if this is the case, then * create a stand alone viewer, otherwise, we create a paneled * version of the viewer */ if (view->have_frame){ parent = view->widget.wcontainer; } else { parent = view->widget.parent->wdata; } cmd = tk_new_command (parent, view, tk_viewer_callback, 'v'); tk_evalf ("newview %d %s %s %s", view->have_frame, view->have_frame ? (char *) view->widget.wcontainer : "{}", cmd+1, cmd); } void x_focus_view (WView *view) { tk_evalf ("focus %s.v.view", wtk_win (view->widget)); } void view_status (WView *view) { char *window = wtk_win (view->widget); if (!view->status_shown){ view->status_shown = 0; tk_evalf ("view_update_info %s {%s} {%d} {%s} {%s}", window, name_trunc (view->filename ? view->filename: view->command ? view->command:"", 20), -view->start_col, size_trunc (view->s.st_size), view->growing_buffer ? "[grow]":"[]"); } } void view_percent (WView *view, int p, int w) { fprintf (stderr, "Missing tk view_percent\n"); } /* The major part of the Tk code deals with caching a line (the * current one) of text to avoid expensive calls to the Tk text widget * callback. * * We cache all this information on view->cache and the colors on * view->color_cache. * * FIXME: the cache does not know about the contents of the physical * text widget (depends on your concept of physical), so if we happen * to hit the case where row is decremented in the void display () routine, * we will end up with a clean line. */ static int current_color; void view_set_color (WView *view, int font) { current_color = font; } void view_display_clean(WView *view, int h, int w) { char *win = wtk_win (view->widget); tk_evalf ("cleanview %s.v.view", win); } void view_add_character (WView *view, int c) { view->cache [view->dest] = c; view->color_cache [view->dest] = current_color; } void view_add_string (WView *view, char *s) { while (*s) view_add_character (view, *s++); } static char * get_tk_tag_name (int color) { /* Those names are the names of the tags in the Tk source */ static char *color_tag_names [] = { "normal", "bold", "underline", "mark" }; return color_tag_names [color]; } /* * Tk: Flushes the contents of view->cache to the Tk text widget * * We get the command information and call the command directly * to avoid escaping the view->cache contents. */ static void flush_line (WView *view) { char *win = wtk_win (view->widget); int row = view->current_line; char *text_name; Tcl_CmdInfo info; int i, prev_color; char str_row [30]; char *av [5]; int len = strlen (view->cache); /* Fetch the address and clientData for the view */ text_name = copy_strings (win, ".v.view", 0); Tcl_GetCommandInfo (interp, text_name, &info); /* Setup arguments to the command: * $win.v.view insert @$row,0 $view->cache */ sprintf (str_row, "%d.0", row); i = 0; av [i++] = text_name; av [i++] = "insert"; av [i++] = str_row; av [i++] = view->cache; /* Call the callback :-) */ (*info.proc) (info.clientData, interp, i, av); bzero (view->cache, view->cache_len); /* Colorize the line */ for (prev_color = 0, i = 0; i < len; i++){ int new_color_start; char *color_name; if (view->color_cache [i] == prev_color) continue; new_color_start = i; prev_color = view->color_cache [i]; for (;i < len && view->color_cache [i] == prev_color; i++) ; color_name = get_tk_tag_name (prev_color); tk_evalf ("%s tag add %s %d.%d %d.%d", text_name, color_name, row, new_color_start-1, row, i); } bzero (view->color_cache, view->cache_len); view->last_col = 0; free (text_name); } /* Tk: Mantains the line cache */ void view_gotoyx (WView *view, int row, int col) { if (row != view->current_line){ flush_line (view); } view->current_line = row; /* In case the user has resized the viewer */ if (col > view->cache_len){ char *new; new = xmalloc (col + 1, "cache"); strcpy (new, view->cache); free (view->cache); view->cache = new; new = xmalloc (col + 1, "cache"); strcpy (new, view->color_cache); free (view->color_cache); view->color_cache = new; view->cache_len = col; } view->dest = col; for (; view->last_col+1 < col; view->last_col++){ view->cache [view->last_col] = ' '; view->color_cache [view->last_col] = current_color; } view->last_col = col; }