diff options
Diffstat (limited to 'libcons/file-changed.c')
-rw-r--r-- | libcons/file-changed.c | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/libcons/file-changed.c b/libcons/file-changed.c new file mode 100644 index 00000000..b12a6f10 --- /dev/null +++ b/libcons/file-changed.c @@ -0,0 +1,366 @@ +/* file-changed.c - Handling file changed notifications. + Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Written by Marcus Brinkmann. + + This file is part of the GNU Hurd. + + The GNU Hurd 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, or (at + your option) any later version. + + The GNU Hurd 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, USA. */ + +#include <errno.h> +#include <assert.h> + +#include <mach.h> + +#include "cons.h" +#include "fs_notify_S.h" + +kern_return_t +cons_S_file_changed (cons_notify_t notify, natural_t tickno, + file_changed_type_t change, + off_t start, off_t end) +{ + error_t err = 0; + vcons_t vcons = (vcons_t) notify; + + if (!notify || notify->cons) + return EOPNOTSUPP; + + mutex_lock (&vcons->lock); + switch (change) + { + case FILE_CHANGED_NULL: + /* Always sent first for sync. */ + cons_vcons_refresh (vcons); + break; + case FILE_CHANGED_WRITE: + /* File data has been written. */ + while (vcons->state.changes.written < vcons->display->changes.written) + { + cons_change_t change; + + if (vcons->display->changes.written - vcons->state.changes.written + > vcons->cons->slack) + { + cons_vcons_refresh (vcons); + continue; + } + change = vcons->state.changes.buffer[vcons->state.changes.written + % vcons->state.changes.length]; + if (vcons->display->changes.written - vcons->state.changes.written + > vcons->state.changes.length - 1) + { + /* While we were reading the entry, the server might + have overwritten it. */ + cons_vcons_refresh (vcons); + continue; + } + vcons->state.changes.written++; + + if (change.what.not_matrix) + { + if (change.what.cursor_pos) + { + uint32_t old_row = vcons->state.cursor.row; + uint32_t height = vcons->state.screen.height; + uint32_t row; + + vcons->state.cursor.col = vcons->display->cursor.col; + row = vcons->state.cursor.row = vcons->display->cursor.row; + + if (row + vcons->scrolling < height) + { + cons_vcons_set_cursor_pos (vcons, + vcons->state.cursor.col, + row + vcons->scrolling); + if (old_row + vcons->scrolling >= height) + /* The cursor was invisible before. */ + cons_vcons_set_cursor_status (vcons, + vcons->state.cursor.status); + } + else if (old_row + vcons->scrolling < height) + /* The cursor was visible before. */ + cons_vcons_set_cursor_status (vcons, CONS_CURSOR_INVISIBLE); + + _cons_vcons_console_event (vcons, CONS_EVT_OUTPUT); + cons_vcons_update (vcons); + } + if (change.what.cursor_status) + { + vcons->state.cursor.status = vcons->display->cursor.status; + cons_vcons_set_cursor_status (vcons, + vcons->state.cursor.status); + cons_vcons_update (vcons); + } + if (change.what.screen_cur_line) + { + uint32_t new_cur_line; + + new_cur_line = vcons->display->screen.cur_line; + + if (new_cur_line != vcons->state.screen.cur_line) + { + off_t size = vcons->state.screen.width + * vcons->state.screen.lines; + off_t vis_start; + uint32_t scrolling; + off_t start; + off_t end; + + if (new_cur_line > vcons->state.screen.cur_line) + scrolling = new_cur_line + - vcons->state.screen.cur_line; + else + scrolling = UINT32_MAX - vcons->state.screen.cur_line + + 1 + new_cur_line; + + /* If we are scrolling back, defer scrolling + until absolutely necessary. */ + if (vcons->scrolling) + { + if (_cons_jump_down_on_output) + _cons_vcons_scrollback + (vcons, CONS_SCROLL_ABSOLUTE_LINE, 0); + else + { + if (vcons->scrolling + scrolling + <= vcons->state.screen.scr_lines) + { + vcons->scrolling += scrolling; + scrolling = 0; + } + else + { + scrolling -= vcons->state.screen.scr_lines + - vcons->scrolling; + vcons->scrolling + = vcons->state.screen.scr_lines; + } + } + } + + if (scrolling) + { + uint32_t cur_disp_line; + + if (new_cur_line >= vcons->scrolling) + cur_disp_line = new_cur_line - vcons->scrolling; + else + cur_disp_line = (UINT32_MAX - (vcons->scrolling - new_cur_line)) + 1; + + if (scrolling > vcons->state.screen.height) + scrolling = vcons->state.screen.height; + if (scrolling < vcons->state.screen.height) + cons_vcons_scroll (vcons, scrolling); + else + cons_vcons_clear (vcons, vcons->state.screen.width + * vcons->state.screen.height, + 0, 0); + vis_start = vcons->state.screen.width + * (cur_disp_line % vcons->state.screen.lines); + start = (((cur_disp_line % vcons->state.screen.lines) + + vcons->state.screen.height - scrolling) + * vcons->state.screen.width) % size; + end = start + scrolling * vcons->state.screen.width - 1; + cons_vcons_write (vcons, + vcons->state.screen.matrix + start, + end < size + ? end - start + 1 + : size - start, + 0, vcons->state.screen.height + - scrolling); + if (end >= size) + cons_vcons_write (vcons, + vcons->state.screen.matrix, + end - size + 1, + 0, (size - vis_start) + / vcons->state.screen.width); + _cons_vcons_console_event (vcons, CONS_EVT_OUTPUT); + cons_vcons_update (vcons); + } + vcons->state.screen.cur_line = new_cur_line; + } + } + if (change.what.screen_scr_lines) + { + vcons->state.screen.scr_lines + = vcons->display->screen.scr_lines; + if (vcons->state.screen.scr_lines < vcons->scrolling) + assert (!"Implement shrinking scrollback buffer! XXX"); + } + if (change.what.bell_audible) + { + while (vcons->state.bell.audible + < vcons->display->bell.audible) + { + if (_cons_audible_bell == BELL_AUDIBLE) + cons_vcons_beep (vcons); + else if (_cons_audible_bell == BELL_VISUAL) + cons_vcons_flash (vcons); + vcons->state.bell.audible++; + } + } + if (change.what.bell_visible) + { + while (vcons->state.bell.visible + < vcons->display->bell.visible) + { + if (_cons_visual_bell == BELL_VISUAL) + cons_vcons_flash (vcons); + else if (_cons_visual_bell == BELL_AUDIBLE) + cons_vcons_beep (vcons); + vcons->state.bell.visible++; + } + } + if (change.what.flags) + { + uint32_t flags = vcons->display->flags; + + if ((flags & CONS_FLAGS_SCROLL_LOCK) + != (vcons->state.flags & CONS_FLAGS_SCROLL_LOCK)) + cons_vcons_set_scroll_lock (vcons, flags + & CONS_FLAGS_SCROLL_LOCK); + vcons->state.flags = flags; + } + } + else + { + /* For clipping. */ + off_t size = vcons->state.screen.width*vcons->state.screen.lines; + off_t rotate; + off_t vis_end = vcons->state.screen.height + * vcons->state.screen.width - 1; + off_t end2 = -1; + off_t start_rel = 0; /* start relative to visible start. */ + off_t start = change.matrix.start; + off_t end = change.matrix.end; + + if (vcons->scrolling && _cons_jump_down_on_output) + _cons_vcons_scrollback (vcons, CONS_SCROLL_ABSOLUTE_LINE, 0); + + if (vcons->state.screen.cur_line >= vcons->scrolling) + rotate = vcons->state.screen.cur_line - vcons->scrolling; + else + rotate = (UINT32_MAX - (vcons->scrolling - vcons->state.screen.cur_line)) + 1; + rotate = vcons->state.screen.width * (rotate % vcons->state.screen.lines); + + /* Rotate the buffer. */ + start -= rotate; + if (start < 0) + start += size; + end -= rotate; + if (end < 0) + end += size; + + /* Find the intersection. */ + if (start > vis_end) + { + if (end < start) + { + start = 0; + if (vis_end < end) + end = vis_end; + } + else + start = -1; + } + else + { + if (end >= start) + { + if (end > vis_end) + end = vis_end; + } + else + { + end2 = end; + end = vis_end; + } + } + /* We now have three cases: No intersection if start == + -1, one intersection [start;end] if end2 == -1, and + two intersections [start;end] and [0;end2] if end2 != + -1. However, we still have to undo the buffer + rotation. */ + if (start != -1) + { + start_rel = start; + start += rotate; + if (start >= size) + start -= size; + end += rotate; + if (end >= size) + end -= size; + if (start > end) + end += size; + } + if (end2 != -1) + /* The interval should be [vis_start:end2]. */ + end2 += rotate; + + if (start != -1) + { + cons_vcons_clear (vcons, end - start + 1, + start_rel % vcons->state.screen.width, + start_rel / vcons->state.screen.width); + cons_vcons_write (vcons, vcons->state.screen.matrix + start, + end < size + ? end - start + 1 + : size - start, + start_rel % vcons->state.screen.width, + start_rel / vcons->state.screen.width); + if (end >= size) + cons_vcons_write (vcons, vcons->state.screen.matrix, + end - size + 1, + (size - rotate) + % vcons->state.screen.width, + (size - rotate) + / vcons->state.screen.width); + if (end2 != -1) + { + cons_vcons_clear (vcons, end2 - rotate + 1, 0, 0); + cons_vcons_write (vcons, + vcons->state.screen.matrix + rotate, + end2 < size + ? end2 - rotate + 1 + : size - rotate, + 0, 0); + if (end2 >= size) + cons_vcons_write (vcons, vcons->state.screen.matrix, + end2 - size + 1, + (size - rotate) + % vcons->state.screen.width, + (size - rotate) + / vcons->state.screen.width); + } + _cons_vcons_console_event (vcons, CONS_EVT_OUTPUT); + cons_vcons_update (vcons); + } + } + } + break; + case FILE_CHANGED_EXTEND: + /* File has grown. */ + case FILE_CHANGED_TRUNCATE: + /* File has been truncated. */ + case FILE_CHANGED_META: + /* Stat information has changed, and none of the previous three + apply. Not sent for changes in node times. */ + default: + err = EINVAL; + }; + + mutex_unlock (&vcons->lock); + return err; +} |