47 |
#include "display.h" |
#include "display.h" |
48 |
|
|
49 |
|
|
50 |
|
struct changes |
51 |
|
{ |
52 |
|
struct |
53 |
|
{ |
54 |
|
uint32_t col; |
55 |
|
uint32_t row; |
56 |
|
uint32_t status; |
57 |
|
} cursor; |
58 |
|
struct |
59 |
|
{ |
60 |
|
uint32_t cur_line; |
61 |
|
uint32_t scr_lines; |
62 |
|
} screen; |
63 |
|
off_t start; |
64 |
|
off_t end; |
65 |
|
|
66 |
|
#define DISPLAY_CHANGE_CURSOR_POS 1 |
67 |
|
#define DISPLAY_CHANGE_CURSOR_STATUS 2 |
68 |
|
#define DISPLAY_CHANGE_SCREEN_CUR_LINE 4 |
69 |
|
#define DISPLAY_CHANGE_SCREEN_SCR_LINES 8 |
70 |
|
#define DISPLAY_CHANGE_MATRIX 16 |
71 |
|
int which; |
72 |
|
}; |
73 |
|
|
74 |
struct cursor |
struct cursor |
75 |
{ |
{ |
76 |
uint32_t saved_x; |
uint32_t saved_x; |
139 |
{ |
{ |
140 |
display_t display; |
display_t display; |
141 |
struct pager *p; |
struct pager *p; |
142 |
|
size_t memobj_npages; |
143 |
|
vm_address_t memobj_pages[0]; |
144 |
}; |
}; |
145 |
|
|
146 |
/* Pending directory and file modification requests. */ |
/* Pending directory and file modification requests. */ |
161 |
signal for this virtual console. */ |
signal for this virtual console. */ |
162 |
int owner_id; |
int owner_id; |
163 |
|
|
164 |
|
struct changes changes; |
165 |
|
|
166 |
struct cursor cursor; |
struct cursor cursor; |
167 |
struct output output; |
struct output output; |
168 |
struct attr attr; |
struct attr attr; |
170 |
|
|
171 |
struct user_pager_info *upi; |
struct user_pager_info *upi; |
172 |
memory_object_t memobj; |
memory_object_t memobj; |
|
size_t memobj_size; |
|
173 |
|
|
174 |
/* A list of ports to send file change notifications to. */ |
/* A list of ports to send file change notifications to. */ |
175 |
struct modreq *filemod_reqs; |
struct modreq *filemod_reqs; |
196 |
void |
void |
197 |
pager_clear_user_data (struct user_pager_info *upi) |
pager_clear_user_data (struct user_pager_info *upi) |
198 |
{ |
{ |
199 |
|
int idx; |
200 |
|
|
201 |
|
for (idx = 0; idx < upi->memobj_npages; idx++) |
202 |
|
if (upi->memobj_pages[idx]) |
203 |
|
vm_deallocate (mach_task_self (), upi->memobj_pages[idx], vm_page_size); |
204 |
free (upi); |
free (upi); |
205 |
} |
} |
206 |
|
|
207 |
error_t |
error_t |
208 |
pager_read_page (struct user_pager_info *pager, vm_offset_t page, |
pager_read_page (struct user_pager_info *upi, vm_offset_t page, |
209 |
vm_address_t *buf, int *writelock) |
vm_address_t *buf, int *writelock) |
210 |
{ |
{ |
211 |
|
assert (upi->memobj_pages[page / vm_page_size] == (vm_address_t) NULL); |
212 |
|
|
213 |
/* This is a read-only medium */ |
/* This is a read-only medium */ |
214 |
*writelock = 1; |
*writelock = 1; |
215 |
|
|
216 |
*buf = (vm_address_t) mmap (0, vm_page_size, PROT_READ|PROT_WRITE, |
*buf = (vm_address_t) mmap (0, vm_page_size, PROT_READ|PROT_WRITE, |
217 |
MAP_ANON, 0, 0); |
MAP_ANON, 0, 0); |
218 |
return 0; |
return 0; |
219 |
} |
} |
220 |
|
|
221 |
error_t |
error_t |
222 |
pager_write_page (struct user_pager_info *pager, |
pager_write_page (struct user_pager_info *upi, vm_offset_t page, |
|
vm_offset_t page, |
|
223 |
vm_address_t buf) |
vm_address_t buf) |
224 |
{ |
{ |
225 |
/* XXX Implement me. Just store away the page, and release it when |
assert (upi->memobj_pages[page / vm_page_size] == (vm_address_t) NULL); |
226 |
releasing the pager. */ |
upi->memobj_pages[page / vm_page_size] = buf; |
227 |
assert (0); |
return 0; |
228 |
} |
} |
229 |
|
|
230 |
error_t |
error_t |
242 |
{ |
{ |
243 |
display_t display = upi->display; |
display_t display = upi->display; |
244 |
*offset = 0; |
*offset = 0; |
245 |
*size = display->memobj_size; |
*size = display->upi->memobj_npages * vm_page_size; |
246 |
return 0; |
return 0; |
247 |
} |
} |
248 |
|
|
329 |
} |
} |
330 |
} |
} |
331 |
|
|
332 |
|
static void |
333 |
|
display_flush_filechange (display_t display, int type) |
334 |
|
{ |
335 |
|
struct cons_display *user = display->user; |
336 |
|
|
337 |
|
if (type & DISPLAY_CHANGE_CURSOR_POS |
338 |
|
|| type & DISPLAY_CHANGE_CURSOR_STATUS) |
339 |
|
{ |
340 |
|
off_t start = -1; |
341 |
|
off_t end = -1; |
342 |
|
|
343 |
|
if (type & DISPLAY_CHANGE_CURSOR_POS |
344 |
|
|| display->changes.cursor.col != user->cursor.col |
345 |
|
|| display->changes.cursor.row != user->cursor.row) |
346 |
|
{ |
347 |
|
start = offsetof (struct cons_display, cursor.col); |
348 |
|
end = start + 2 * sizeof (wchar_t) - 1; |
349 |
|
} |
350 |
|
if (type & DISPLAY_CHANGE_CURSOR_STATUS |
351 |
|
|| display->changes.cursor.status != user->cursor.status) |
352 |
|
{ |
353 |
|
if (start == -1) |
354 |
|
start = offsetof (struct cons_display, cursor.status); |
355 |
|
end = start + 1 * sizeof (wchar_t) - 1; |
356 |
|
} |
357 |
|
if (start != -1) |
358 |
|
display_notice_filechange (display, FILE_CHANGED_WRITE, start, end); |
359 |
|
} |
360 |
|
|
361 |
|
if (type & DISPLAY_CHANGE_SCREEN_CUR_LINE |
362 |
|
|| type & DISPLAY_CHANGE_SCREEN_SCR_LINES) |
363 |
|
{ |
364 |
|
off_t start = -1; |
365 |
|
off_t end = -1; |
366 |
|
|
367 |
|
if (type & DISPLAY_CHANGE_SCREEN_CUR_LINE |
368 |
|
|| display->changes.screen.cur_line != user->screen.cur_line) |
369 |
|
{ |
370 |
|
start = offsetof (struct cons_display, screen.cur_line); |
371 |
|
end = start + 1 * sizeof (wchar_t) - 1; |
372 |
|
} |
373 |
|
if (type & DISPLAY_CHANGE_SCREEN_SCR_LINES |
374 |
|
|| display->changes.screen.scr_lines != user->screen.scr_lines) |
375 |
|
{ |
376 |
|
if (start == -1) |
377 |
|
start = offsetof (struct cons_display, screen.scr_lines); |
378 |
|
end = start + 1 * sizeof (wchar_t) - 1; |
379 |
|
} |
380 |
|
if (start != -1) |
381 |
|
display_notice_filechange (display, FILE_CHANGED_WRITE, start, end); |
382 |
|
} |
383 |
|
|
384 |
|
if (type & DISPLAY_CHANGE_MATRIX) |
385 |
|
{ |
386 |
|
display_notice_filechange (display, FILE_CHANGED_WRITE, |
387 |
|
sizeof (struct cons_display) |
388 |
|
+ display->changes.start * sizeof (wchar_t), |
389 |
|
sizeof (struct cons_display) |
390 |
|
+ (display->changes.end + 1) |
391 |
|
* sizeof (wchar_t) - 1); |
392 |
|
type &= ~DISPLAY_CHANGE_MATRIX; |
393 |
|
} |
394 |
|
} |
395 |
|
|
396 |
|
|
397 |
|
/* Record a change in the matrix ringbuffer. */ |
398 |
|
static void |
399 |
|
display_record_filechange (display_t display, off_t start, off_t end) |
400 |
|
{ |
401 |
|
if (!display->changes.which & DISPLAY_CHANGE_MATRIX) |
402 |
|
{ |
403 |
|
display->changes.start = start; |
404 |
|
display->changes.end = end; |
405 |
|
display->changes.which |= DISPLAY_CHANGE_MATRIX; |
406 |
|
} |
407 |
|
else |
408 |
|
{ |
409 |
|
off_t size = display->user->screen.width * display->user->screen.lines; |
410 |
|
off_t rotate = display->changes.start; |
411 |
|
off_t old_end = display->changes.end; |
412 |
|
int disjunct = 0; |
413 |
|
|
414 |
|
/* First rotate the buffer to reduce the number of cases. */ |
415 |
|
old_end -= rotate; |
416 |
|
if (old_end < 0) |
417 |
|
old_end += size; |
418 |
|
start -= rotate; |
419 |
|
if (start < 0) |
420 |
|
start += size; |
421 |
|
end -= rotate; |
422 |
|
if (end < 0) |
423 |
|
end += size; |
424 |
|
|
425 |
|
/* Now the old region starts at 0 and ends at OLD_END. Try to |
426 |
|
merge in the new region if it overlaps or touches the old |
427 |
|
one. */ |
428 |
|
if (start <= end) |
429 |
|
{ |
430 |
|
if (start <= old_end + 1) |
431 |
|
{ |
432 |
|
start = 0; |
433 |
|
if (old_end > end) |
434 |
|
end = old_end; |
435 |
|
} |
436 |
|
else |
437 |
|
{ |
438 |
|
if (end == size - 1) |
439 |
|
end = old_end; |
440 |
|
else |
441 |
|
disjunct = 1; |
442 |
|
} |
443 |
|
} |
444 |
|
else |
445 |
|
{ |
446 |
|
if (start <= old_end + 1) |
447 |
|
{ |
448 |
|
start = 0; |
449 |
|
end = size - 1; |
450 |
|
} |
451 |
|
else |
452 |
|
{ |
453 |
|
if (old_end > end) |
454 |
|
end = old_end; |
455 |
|
} |
456 |
|
} |
457 |
|
/* Now reverse the rotation. */ |
458 |
|
start += rotate; |
459 |
|
if (start > size) |
460 |
|
start -= size; |
461 |
|
end += rotate; |
462 |
|
if (end > size) |
463 |
|
end -= size; |
464 |
|
|
465 |
|
if (disjunct) |
466 |
|
{ |
467 |
|
/* The regions are disjunct, so we have to flush the old |
468 |
|
changes. */ |
469 |
|
display_flush_filechange (display, DISPLAY_CHANGE_MATRIX); |
470 |
|
} |
471 |
|
display->changes.start = start; |
472 |
|
display->changes.end = end; |
473 |
|
} |
474 |
|
} |
475 |
|
|
476 |
|
|
477 |
|
|
478 |
static error_t |
static error_t |
479 |
user_create (display_t display, uint32_t width, uint32_t height, |
user_create (display_t display, uint32_t width, uint32_t height, |
481 |
{ |
{ |
482 |
error_t err; |
error_t err; |
483 |
struct cons_display *user; |
struct cons_display *user; |
484 |
display->memobj_size = round_page (sizeof (struct cons_display) + |
int npages = (round_page (sizeof (struct cons_display) + |
485 |
sizeof (uint32_t) * width * lines); |
sizeof (uint32_t) * width * lines)) / vm_page_size; |
486 |
|
|
487 |
display->upi = malloc (sizeof (struct user_pager_info)); |
display->upi = calloc (1, sizeof (struct user_pager_info) |
488 |
|
+ sizeof (vm_address_t) * npages); |
489 |
if (!display->upi) |
if (!display->upi) |
490 |
return MACH_PORT_NULL; |
return MACH_PORT_NULL; |
491 |
display->upi->display = display; |
display->upi->display = display; |
492 |
|
display->upi->memobj_npages = npages; |
493 |
/* 1 & MOCD correct? */ |
/* 1 & MOCD correct? */ |
494 |
display->upi->p = pager_create (display->upi, pager_bucket, |
display->upi->p = pager_create (display->upi, pager_bucket, |
495 |
1, MEMORY_OBJECT_COPY_DELAY); |
1, MEMORY_OBJECT_COPY_DELAY); |
505 |
MACH_MSG_TYPE_MAKE_SEND); |
MACH_MSG_TYPE_MAKE_SEND); |
506 |
|
|
507 |
err = vm_map (mach_task_self (), |
err = vm_map (mach_task_self (), |
508 |
(vm_address_t *) &user, (vm_size_t) display->memobj_size, |
(vm_address_t *) &user, |
509 |
|
(vm_size_t) display->upi->memobj_npages * vm_page_size, |
510 |
(vm_address_t) 0, |
(vm_address_t) 0, |
511 |
1 /* ! (flags & MAP_FIXED) */, |
1 /* ! (flags & MAP_FIXED) */, |
512 |
display->memobj, 0 /* (vm_offset_t) offset */, |
display->memobj, 0 /* (vm_offset_t) offset */, |
565 |
if (end < size) |
if (end < size) |
566 |
{ |
{ |
567 |
wmemset (user->_matrix + start, chr, end - start + 1); |
wmemset (user->_matrix + start, chr, end - start + 1); |
568 |
display_notice_filechange (display, FILE_CHANGED_WRITE, |
display_record_filechange (display, start, end); |
|
sizeof (struct cons_display) |
|
|
+ start * sizeof (wchar_t), |
|
|
sizeof (struct cons_display) |
|
|
+ (end + 1) * sizeof (wchar_t) - 1); |
|
569 |
} |
} |
570 |
else |
else |
571 |
{ |
{ |
572 |
wmemset (user->_matrix + start, chr, size - start); |
wmemset (user->_matrix + start, chr, size - start); |
573 |
wmemset (user->_matrix, chr, end - size + 1); |
wmemset (user->_matrix, chr, end - size + 1); |
574 |
display_notice_filechange (display, FILE_CHANGED_WRITE, |
display_record_filechange (display, start, end - size); |
|
sizeof (struct cons_display) |
|
|
+ start * sizeof (wchar_t), |
|
|
sizeof (struct cons_display) |
|
|
+ (end - size + 1) * sizeof (wchar_t) - 1); |
|
575 |
} |
} |
576 |
} |
} |
577 |
|
|
602 |
while (dst <= end) |
while (dst <= end) |
603 |
user->_matrix[dst++ % size] = chr; |
user->_matrix[dst++ % size] = chr; |
604 |
|
|
605 |
|
display_flush_filechange (display, DISPLAY_CHANGE_MATRIX); |
606 |
display_notice_filechange (display, FILE_CHANGED_TRUNCATE, |
display_notice_filechange (display, FILE_CHANGED_TRUNCATE, |
607 |
sizeof (struct cons_display) |
sizeof (struct cons_display) |
608 |
+ start * sizeof (wchar_t), |
+ start * sizeof (wchar_t), |
645 |
while (dst >= start) |
while (dst >= start) |
646 |
user->_matrix[dst-- % size] = chr; |
user->_matrix[dst-- % size] = chr; |
647 |
|
|
648 |
|
display_flush_filechange (display, DISPLAY_CHANGE_MATRIX); |
649 |
display_notice_filechange (display, FILE_CHANGED_EXTEND, |
display_notice_filechange (display, FILE_CHANGED_EXTEND, |
650 |
sizeof (struct cons_display) |
sizeof (struct cons_display) |
651 |
+ start * sizeof (wchar_t), |
+ start * sizeof (wchar_t), |
1017 |
struct cons_display *user = display->user; |
struct cons_display *user = display->user; |
1018 |
parse_t parse = &display->output.parse; |
parse_t parse = &display->output.parse; |
1019 |
|
|
|
uint32_t old_cursor_col = user->cursor.col; |
|
|
uint32_t old_cursor_row = user->cursor.row; |
|
|
uint32_t old_cursor_status = user->cursor.status; |
|
|
uint32_t old_cur_line = user->screen.cur_line; |
|
|
uint32_t old_scr_lines = user->screen.scr_lines; |
|
|
|
|
1020 |
void newline (void) |
void newline (void) |
1021 |
{ |
{ |
1022 |
if (user->cursor.row < user->screen.height - 1) |
if (user->cursor.row < user->screen.height - 1) |
1098 |
/* XXX Set attribute flags. */ |
/* XXX Set attribute flags. */ |
1099 |
user->_matrix[idx] = chr; |
user->_matrix[idx] = chr; |
1100 |
|
|
1101 |
display_notice_filechange (display, FILE_CHANGED_WRITE, |
display_record_filechange (display, idx, idx); |
|
sizeof (struct cons_display) |
|
|
+ idx * sizeof (wchar_t), |
|
|
sizeof (struct cons_display) |
|
|
+ (idx + 1) * sizeof (wchar_t) - 1); |
|
|
|
|
1102 |
user->cursor.col++; |
user->cursor.col++; |
1103 |
if (user->cursor.col == user->screen.width) |
if (user->cursor.col == user->screen.width) |
1104 |
{ |
{ |
1166 |
default: |
default: |
1167 |
abort (); |
abort (); |
1168 |
} |
} |
|
|
|
|
if (old_cursor_col != user->cursor.col || old_cursor_row != user->cursor.row) |
|
|
display_notice_filechange (display, FILE_CHANGED_WRITE, |
|
|
offsetof (struct cons_display, cursor.col), |
|
|
(old_cursor_status == user->cursor.status |
|
|
? offsetof (struct cons_display, cursor.row) |
|
|
: offsetof (struct cons_display, cursor.row)) |
|
|
+ sizeof (wchar_t) - 1); |
|
|
else if (old_cursor_status != user->cursor.status) |
|
|
display_notice_filechange (display, FILE_CHANGED_WRITE, |
|
|
offsetof (struct cons_display, cursor.status), |
|
|
offsetof (struct cons_display, cursor.status) |
|
|
+ sizeof (wchar_t) - 1); |
|
|
if (old_cur_line != user->screen.cur_line) |
|
|
display_notice_filechange (display, FILE_CHANGED_WRITE, |
|
|
offsetof (struct cons_display, screen.cur_line), |
|
|
(old_scr_lines == user->screen.scr_lines |
|
|
? offsetof (struct cons_display, |
|
|
screen.cur_line) |
|
|
: offsetof (struct cons_display, |
|
|
screen.scr_lines)) |
|
|
+ sizeof (wchar_t) - 1); |
|
|
else if (old_scr_lines != user->screen.scr_lines) |
|
|
display_notice_filechange (display, FILE_CHANGED_WRITE, |
|
|
offsetof (struct cons_display, |
|
|
screen.scr_lines), |
|
|
offsetof (struct cons_display, |
|
|
screen.scr_lines) |
|
|
+ sizeof (wchar_t) - 1); |
|
1169 |
} |
} |
1170 |
|
|
1171 |
/* Output LENGTH bytes starting from BUFFER in the system encoding. |
/* Output LENGTH bytes starting from BUFFER in the system encoding. |
1177 |
#define CONV_OUTBUF_SIZE 256 |
#define CONV_OUTBUF_SIZE 256 |
1178 |
error_t err = 0; |
error_t err = 0; |
1179 |
|
|
1180 |
|
display->changes.cursor.col = display->user->cursor.col; |
1181 |
|
display->changes.cursor.row = display->user->cursor.row; |
1182 |
|
display->changes.cursor.status = display->user->cursor.status; |
1183 |
|
display->changes.screen.cur_line = display->user->screen.cur_line; |
1184 |
|
display->changes.screen.scr_lines = display->user->screen.scr_lines; |
1185 |
|
display->changes.which = ~DISPLAY_CHANGE_MATRIX; |
1186 |
|
|
1187 |
while (!err && *length > 0) |
while (!err && *length > 0) |
1188 |
{ |
{ |
1189 |
size_t nconv; |
size_t nconv; |
1211 |
err = saved_err; |
err = saved_err; |
1212 |
} |
} |
1213 |
} |
} |
1214 |
|
|
1215 |
|
display_flush_filechange (display, ~0); |
1216 |
return err; |
return err; |
1217 |
} |
} |
1218 |
|
|