]> git.proxmox.com Git - spiceterm.git/blob - spiceterm.c
delete trailing whitespace
[spiceterm.git] / spiceterm.c
1 /*
2
3 Copyright (C) 2007-2011 Proxmox Server Solutions GmbH
4
5 Copyright: spiceterm is under GNU GPL, the GNU General Public License.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; version 2 dated June, 1991.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA.
20
21 Author: Dietmar Maurer <dietmar@proxmox.com>
22
23 */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <arpa/inet.h>
31 #include <netdb.h>
32 #include <pty.h> /* for openpty and forkpty */
33 #include <string.h>
34 #include <errno.h>
35 #include <sys/ioctl.h>
36 #include <sys/wait.h>
37 #include <signal.h>
38 #include <locale.h>
39
40 #include "spiceterm.h"
41 #include "glyphs.h"
42
43 #include <spice.h>
44 #include <spice/enums.h>
45 #include <spice/macros.h>
46 #include <spice/qxl_dev.h>
47
48 #include "test_display_base.h"
49
50 /* define this for debugging */
51 //#define DEBUG
52
53 #define TERM "xterm"
54
55 #define TERMIDCODE "[?1;2c" // vt100 ID
56
57 #define CHECK_ARGC(argc,argv,i) if (i >= argc-1) { \
58 fprintf (stderr, "ERROR: not enough arguments for: %s\n", argv[i]); \
59 print_usage (NULL); \
60 exit(1); \
61 }
62
63 /* these colours are from linux kernel drivers/char/vt.c */
64
65 static int idle_timeout = 1;
66
67 unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
68 8,12,10,14, 9,13,11,15 };
69
70 /* the default colour table, for VGA+ colour systems */
71 int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
72 0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
73 int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
74 0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
75 int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
76 0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
77
78 static void
79 print_usage (const char *msg)
80 {
81 if (msg) { fprintf (stderr, "ERROR: %s\n", msg); }
82 fprintf (stderr, "USAGE: vncterm [vncopts] [-c command [args]]\n");
83 }
84
85 /* Convert UCS2 to UTF8 sequence, trailing zero */
86 static int
87 ucs2_to_utf8 (unicode c, char *out)
88 {
89 if (c < 0x80) {
90 out[0] = c; // 0*******
91 out[1] = 0;
92 return 1;
93 } else if (c < 0x800) {
94 out[0] = 0xc0 | (c >> 6); // 110***** 10******
95 out[1] = 0x80 | (c & 0x3f);
96 out[2] = 0;
97 return 2;
98 } else {
99 out[0] = 0xe0 | (c >> 12); // 1110**** 10****** 10******
100 out[1] = 0x80 | ((c >> 6) & 0x3f);
101 out[2] = 0x80 | (c & 0x3f);
102 out[3] = 0;
103 return 3;
104 }
105
106 return 0;
107 }
108
109
110 static void
111 draw_char_at (vncTerm *vt, int x, int y, unicode ch, TextAttributes attrib)
112 {
113 if (x < 0 || y < 0 || x >= vt->width || y >= vt->height) {
114 return;
115 }
116
117
118 int ec = vt_fontmap[ch];
119
120 test_draw_update_char(vt->screen, x, y, ec, attrib);
121 }
122
123 static void
124 vncterm_update_xy (vncTerm *vt, int x, int y)
125 {
126 if (x < 0 || y < 0 || x >= vt->width || y >= vt->height) { return; }
127
128 int y1 = (vt->y_base + y) % vt->total_height;
129 int y2 = y1 - vt->y_displ;
130 if (y2 < 0) {
131 y2 += vt->total_height;
132 }
133 if (y2 < vt->height) {
134 TextCell *c = &vt->cells[y1 * vt->width + x];
135 draw_char_at (vt, x, y2, c->ch, c->attrib);
136 }
137 }
138
139 static void
140 vncterm_clear_xy (vncTerm *vt, int x, int y)
141 {
142 if (x < 0 || y < 0 || x >= vt->width || y >= vt->height) { return; }
143
144 int y1 = (vt->y_base + y) % vt->total_height;
145 int y2 = y1 - vt->y_displ;
146 if (y2 < 0) {
147 y2 += vt->total_height;
148 }
149 if (y2 < vt->height) {
150 TextCell *c = &vt->cells[y1 * vt->width + x];
151 c->ch = ' ';
152 c->attrib = vt->default_attrib;
153 c->attrib.fgcol = vt->cur_attrib.fgcol;
154 c->attrib.bgcol = vt->cur_attrib.bgcol;
155
156 draw_char_at (vt, x, y, c->ch, c->attrib);
157 }
158 }
159
160 static void
161 vncterm_show_cursor (vncTerm *vt, int show)
162 {
163 int x = vt->cx;
164 if (x >= vt->width) {
165 x = vt->width - 1;
166 }
167
168 int y1 = (vt->y_base + vt->cy) % vt->total_height;
169 int y = y1 - vt->y_displ;
170 if (y < 0) {
171 y += vt->total_height;
172 }
173
174 if (y < vt->height) {
175
176 TextCell *c = &vt->cells[y1 * vt->width + x];
177
178 if (show) {
179 TextAttributes attrib = vt->default_attrib;
180 attrib.invers = !(attrib.invers); /* invert fg and bg */
181 draw_char_at (vt, x, y, c->ch, attrib);
182 } else {
183 draw_char_at (vt, x, y, c->ch, c->attrib);
184 }
185 }
186 }
187
188 static void
189 vncterm_refresh (vncTerm *vt)
190 {
191 int x, y, y1;
192
193 // rfbFillRect (vt->screen, 0, 0, vt->maxx, vt->maxy, vt->default_attrib.bgcol);
194
195 y1 = vt->y_displ;
196 for(y = 0; y < vt->height; y++) {
197 TextCell *c = vt->cells + y1 * vt->width;
198 for(x = 0; x < vt->width; x++) {
199 draw_char_at (vt, x, y, c->ch, c->attrib);
200 c++;
201 }
202 if (++y1 == vt->total_height)
203 y1 = 0;
204 }
205 //rfbMarkRectAsModified (vt->screen, 0, 0, vt->maxx, vt->maxy);
206
207 vncterm_show_cursor (vt, 1);
208 }
209
210 static void
211 vncterm_scroll_down (vncTerm *vt, int top, int bottom, int lines)
212 {
213 if ((top + lines) >= bottom) {
214 lines = bottom - top -1;
215 }
216
217 if (top < 0 || bottom > vt->height || top >= bottom || lines < 1) {
218 return;
219 }
220
221 g_error("vncterm_scroll_down not implemented");
222
223 /*
224 int h = lines * 16;
225 int y0 = top*16;
226 int y1 = y0 + h;
227 int y2 = bottom*16;
228 int rowstride = vt->screen->paddedWidthInBytes;
229 int rows = (bottom - top - lines)*16;
230
231 char *in = vt->screen->frameBuffer+y0*rowstride;
232 char *out = vt->screen->frameBuffer+y1*rowstride;
233 memmove(out,in, rowstride*rows);
234
235 memset(vt->screen->frameBuffer+y0*rowstride, 0, h*rowstride);
236 rfbMarkRectAsModified (vt->screen, 0, y0, vt->screen->width, y2);
237
238 int i;
239 for(i = bottom - top - lines - 1; i >= 0; i--) {
240 int src = ((vt->y_base + top + i) % vt->total_height)*vt->width;
241 int dst = ((vt->y_base + top + lines + i) % vt->total_height)*vt->width;
242
243 memmove(vt->cells + dst, vt->cells + src, vt->width*sizeof (TextCell));
244 }
245
246 for (i = 0; i < lines; i++) {
247 int j;
248 TextCell *c = vt->cells + ((vt->y_base + top + i) % vt->total_height)*vt->width;
249 for(j = 0; j < vt->width; j++) {
250 c->attrib = vt->default_attrib;
251 c->ch = ' ';
252 c++;
253 }
254 }
255 */
256 }
257
258 static void
259 vncterm_scroll_up (vncTerm *vt, int top, int bottom, int lines, int moveattr)
260 {
261 if ((top + lines) >= bottom) {
262 lines = bottom - top - 1;
263 }
264
265 if (top < 0 || bottom > vt->height || top >= bottom || lines < 1) {
266 return;
267 }
268
269 g_error("vncterm_scroll_down not implemented");
270
271 /*
272 int h = lines * 16;
273 int y0 = top*16;
274 int y1 = (top + lines)*16;
275 int y2 = bottom*16;
276 int rowstride = vt->screen->paddedWidthInBytes;
277 int rows = (bottom - top - lines)*16;
278
279 char *in = vt->screen->frameBuffer+y1*rowstride;
280 char *out = vt->screen->frameBuffer+y0*rowstride;
281 memmove(out,in, rowstride*rows);
282
283 memset(vt->screen->frameBuffer+(y2-h)*rowstride, 0, h*rowstride);
284
285 rfbMarkRectAsModified (vt->screen, 0, y0, vt->screen->width, y2);
286
287 if (!moveattr) return;
288
289 // move attributes
290
291 int i;
292 for(i = 0; i < (bottom - top - lines); i++) {
293 int dst = ((vt->y_base + top + i) % vt->total_height)*vt->width;
294 int src = ((vt->y_base + top + lines + i) % vt->total_height)*vt->width;
295
296 memmove(vt->cells + dst, vt->cells + src, vt->width*sizeof (TextCell));
297 }
298
299 for (i = 1; i <= lines; i++) {
300 int j;
301 TextCell *c = vt->cells + ((vt->y_base + bottom - i) % vt->total_height)*vt->width;
302 for(j = 0; j < vt->width; j++) {
303 c->attrib = vt->default_attrib;
304 c->ch = ' ';
305 c++;
306 }
307 }
308 */
309 }
310
311 static void
312 vncterm_virtual_scroll (vncTerm *vt, int lines)
313 {
314 if (vt->altbuf || lines == 0) return;
315
316 if (lines < 0) {
317 lines = -lines;
318 int i = vt->scroll_height;
319 if (i > vt->total_height - vt->height)
320 i = vt->total_height - vt->height;
321 int y1 = vt->y_base - i;
322 if (y1 < 0)
323 y1 += vt->total_height;
324 for(i = 0; i < lines; i++) {
325 if (vt->y_displ == y1) break;
326 if (--vt->y_displ < 0) {
327 vt->y_displ = vt->total_height - 1;
328 }
329 }
330 } else {
331 int i;
332 for(i = 0; i < lines; i++) {
333 if (vt->y_displ == vt->y_base) break;
334 if (++vt->y_displ == vt->total_height) {
335 vt->y_displ = 0;
336 }
337 }
338
339 }
340
341 vncterm_refresh (vt);
342 }
343 static void
344 vncterm_respond_esc (vncTerm *vt, const char *esc)
345 {
346 int len = strlen (esc);
347 int i;
348
349 if (vt->ibuf_count < (IBUFSIZE - 1 - len)) {
350 vt->ibuf[vt->ibuf_count++] = 27;
351 for (i = 0; i < len; i++) {
352 vt->ibuf[vt->ibuf_count++] = esc[i];
353 }
354 }
355 }
356
357 static void
358 vncterm_put_lf (vncTerm *vt)
359 {
360 if (vt->cy + 1 == vt->region_bottom) {
361
362 if (vt->altbuf || vt->region_top != 0 || vt->region_bottom != vt->height) {
363 vncterm_scroll_up (vt, vt->region_top, vt->region_bottom, 1, 1);
364 return;
365 }
366
367 if (vt->y_displ == vt->y_base) {
368 vncterm_scroll_up (vt, vt->region_top, vt->region_bottom, 1, 0);
369 }
370
371 if (vt->y_displ == vt->y_base) {
372 if (++vt->y_displ == vt->total_height) {
373 vt->y_displ = 0;
374 }
375 }
376
377 if (++vt->y_base == vt->total_height) {
378 vt->y_base = 0;
379 }
380
381 if (vt->scroll_height < vt->total_height) {
382 vt->scroll_height++;
383 }
384
385 int y1 = (vt->y_base + vt->height - 1) % vt->total_height;
386 TextCell *c = &vt->cells[y1 * vt->width];
387 int x;
388 for (x = 0; x < vt->width; x++) {
389 c->ch = ' ';
390 c->attrib = vt->default_attrib;
391 c++;
392 }
393
394 // fprintf (stderr, "BASE: %d DISPLAY %d\n", vt->y_base, vt->y_displ);
395
396 } else if (vt->cy < vt->height - 1) {
397 vt->cy += 1;
398 }
399 }
400
401
402 static void
403 vncterm_csi_m (vncTerm *vt)
404 {
405 int i;
406
407 for (i = 0; i < vt->esc_count; i++) {
408 switch (vt->esc_buf[i]) {
409 case 0: /* reset all console attributes to default */
410 vt->cur_attrib = vt->default_attrib;
411 break;
412 case 1:
413 vt->cur_attrib.bold = 1;
414 break;
415 case 4:
416 vt->cur_attrib.uline = 1;
417 break;
418 case 5:
419 vt->cur_attrib.blink = 1;
420 break;
421 case 7:
422 vt->cur_attrib.invers = 1;
423 break;
424 case 8:
425 vt->cur_attrib.unvisible = 1;
426 break;
427 case 10:
428 vt->cur_enc = LAT1_MAP;
429 // fixme: dispaly controls = 0 ?
430 // fixme: toggle meta = 0 ?
431 break;
432 case 11:
433 vt->cur_enc = IBMPC_MAP;
434 // fixme: dispaly controls = 1 ?
435 // fixme: toggle meta = 0 ?
436 break;
437 case 12:
438 vt->cur_enc = IBMPC_MAP;
439 // fixme: dispaly controls = 1 ?
440 // fixme: toggle meta = 1 ?
441 break;
442 case 22:
443 vt->cur_attrib.bold = 0;
444 break;
445 case 24:
446 vt->cur_attrib.uline = 0;
447 break;
448 case 25:
449 vt->cur_attrib.blink = 0;
450 break;
451 case 27:
452 vt->cur_attrib.invers = 0;
453 break;
454 case 28:
455 vt->cur_attrib.unvisible = 0;
456 break;
457 case 30:
458 case 31:
459 case 32:
460 case 33:
461 case 34:
462 case 35:
463 case 36:
464 case 37:
465 /* set foreground color */
466 vt->cur_attrib.fgcol = color_table [vt->esc_buf[i] - 30];
467 break;
468 case 38:
469 /* reset color to default, enable underline */
470 vt->cur_attrib.fgcol = vt->default_attrib.fgcol;
471 vt->cur_attrib.uline = 1;
472 break;
473 case 39:
474 /* reset color to default, disable underline */
475 vt->cur_attrib.fgcol = vt->default_attrib.fgcol;
476 vt->cur_attrib.uline = 0;
477 break;
478 case 40:
479 case 41:
480 case 42:
481 case 43:
482 case 44:
483 case 45:
484 case 46:
485 case 47:
486 /* set background color */
487 vt->cur_attrib.bgcol = color_table [vt->esc_buf[i] - 40];
488 break;
489 case 49:
490 /* reset background color */
491 vt->cur_attrib.bgcol = vt->default_attrib.bgcol;
492 break;
493 default:
494 fprintf (stderr, "unhandled ESC[%d m code\n",vt->esc_buf[i]);
495 //fixme: implement
496 }
497 }
498 }
499
500 static void
501 vncterm_save_cursor (vncTerm *vt)
502 {
503 vt->cx_saved = vt->cx;
504 vt->cy_saved = vt->cy;
505 vt->cur_attrib_saved = vt->cur_attrib;
506 vt->charset_saved = vt->charset;
507 vt->g0enc_saved = vt->g0enc;
508 vt->g1enc_saved = vt->g1enc;
509 vt->cur_enc_saved = vt->cur_enc;
510 }
511
512 static void
513 vncterm_restore_cursor (vncTerm *vt)
514 {
515 vt->cx = vt->cx_saved;
516 vt->cy = vt->cy_saved;
517 vt->cur_attrib = vt->cur_attrib_saved;
518 vt->charset = vt->charset_saved;
519 vt->g0enc = vt->g0enc_saved;
520 vt->g1enc = vt->g1enc_saved;
521 vt->cur_enc = vt->cur_enc_saved;
522 }
523
524 static void
525 vncterm_set_alternate_buffer (vncTerm *vt, int on_off)
526 {
527 int x, y;
528
529 vt->y_displ = vt->y_base;
530
531 if (on_off) {
532
533 if (vt->altbuf) return;
534
535 vt->altbuf = 1;
536
537 /* alternate buffer & cursor */
538
539 vncterm_save_cursor (vt);
540 /* save screen to altcels */
541 for (y = 0; y < vt->height; y++) {
542 int y1 = (vt->y_base + y) % vt->total_height;
543 for (x = 0; x < vt->width; x++) {
544 vt->altcells[y*vt->width + x] = vt->cells[y1*vt->width + x];
545 }
546 }
547
548 /* clear screen */
549 for (y = 0; y <= vt->height; y++) {
550 for (x = 0; x < vt->width; x++) {
551 vncterm_clear_xy (vt, x, y);
552 }
553 }
554
555 } else {
556
557 if (vt->altbuf == 0) return;
558
559 vt->altbuf = 0;
560
561 /* restore saved data */
562 for (y = 0; y < vt->height; y++) {
563 int y1 = (vt->y_base + y) % vt->total_height;
564 for (x = 0; x < vt->width; x++) {
565 vt->cells[y1*vt->width + x] = vt->altcells[y*vt->width + x];
566 }
567 }
568
569 vncterm_restore_cursor (vt);
570 }
571
572 vncterm_refresh (vt);
573 }
574
575 static void
576 vncterm_set_mode (vncTerm *vt, int on_off)
577 {
578 int i;
579
580 for (i = 0; i <= vt->esc_count; i++) {
581 if (vt->esc_ques) { /* DEC private modes set/reset */
582 switch(vt->esc_buf[i]) {
583 case 10: /* X11 mouse reporting on/off */
584 case 1000:
585 vt->report_mouse = on_off;
586 break;
587 case 1049: /* start/end special app mode (smcup/rmcup) */
588 vncterm_set_alternate_buffer (vt, on_off);
589 break;
590 case 25: /* Cursor on/off */
591 case 9: /* X10 mouse reporting on/off */
592 case 6: /* Origin relative/absolute */
593 case 1: /* Cursor keys in appl mode*/
594 case 5: /* Inverted screen on/off */
595 case 7: /* Autowrap on/off */
596 case 8: /* Autorepeat on/off */
597 break;
598 }
599 } else { /* ANSI modes set/reset */
600 /* fixme: implement me */
601 }
602 }
603 }
604
605 static void
606 vncterm_gotoxy (vncTerm *vt, int x, int y)
607 {
608 /* verify all boundaries */
609
610 if (x < 0) {
611 x = 0;
612 }
613
614 if (x >= vt->width) {
615 x = vt->width - 1;
616 }
617
618 vt->cx = x;
619
620 if (y < 0) {
621 y = 0;
622 }
623
624 if (y >= vt->height) {
625 y = vt->height - 1;
626 }
627
628 vt->cy = y;
629 }
630
631 enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
632 EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
633 ESpalette, ESidquery, ESosc1, ESosc2};
634
635 static void
636 vncterm_putchar (vncTerm *vt, unicode ch)
637 {
638 int x, y, i, c;
639
640 #ifdef DEBUG
641 if (!vt->tty_state)
642 fprintf (stderr, "CHAR:%2d: %4x '%c' (cur_enc %d) %d %d\n", vt->tty_state, ch, ch, vt->cur_enc, vt->cx, vt->cy);
643 #endif
644
645 switch(vt->tty_state) {
646 case ESesc:
647 vt->tty_state = ESnormal;
648 switch (ch) {
649 case '[':
650 vt->tty_state = ESsquare;
651 break;
652 case ']':
653 vt->tty_state = ESnonstd;
654 break;
655 case '%':
656 vt->tty_state = ESpercent;
657 break;
658 case '7':
659 vncterm_save_cursor (vt);
660 break;
661 case '8':
662 vncterm_restore_cursor (vt);
663 break;
664 case '(':
665 vt->tty_state = ESsetG0; // SET G0
666 break;
667 case ')':
668 vt->tty_state = ESsetG1; // SET G1
669 break;
670 case 'M':
671 /* cursor up (ri) */
672 if (vt->cy == vt->region_top)
673 vncterm_scroll_down (vt, vt->region_top, vt->region_bottom, 1);
674 else if (vt->cy > 0) {
675 vt->cy--;
676 }
677 break;
678 case '>':
679 /* numeric keypad - ignored */
680 break;
681 case '=':
682 /* appl. keypad - ignored */
683 break;
684 default:
685 #ifdef DEBUG
686 fprintf(stderr, "got unhandled ESC%c %d\n", ch, ch);
687 #endif
688 break;
689 }
690 break;
691 case ESnonstd: /* Operating System Controls */
692 vt->tty_state = ESnormal;
693
694 switch (ch) {
695 case 'P': /* palette escape sequence */
696 for(i = 0; i < MAX_ESC_PARAMS; i++) {
697 vt->esc_buf[i] = 0;
698 }
699
700 vt->esc_count = 0;
701 vt->tty_state = ESpalette;
702 break;
703 case 'R': /* reset palette */
704 // fixme: reset_palette(vc);
705 break;
706 case '0':
707 case '1':
708 case '2':
709 case '4':
710 vt->osc_cmd = ch;
711 vt->osc_textbuf[0] = 0;
712 vt->tty_state = ESosc1;
713 break;
714 default:
715 #ifdef DEBUG
716 fprintf (stderr, "unhandled OSC %c\n", ch);
717 #endif
718 vt->tty_state = ESnormal;
719 break;
720 }
721 break;
722 case ESosc1:
723 vt->tty_state = ESnormal;
724 if (ch == ';') {
725 vt->tty_state = ESosc2;
726 } else {
727 #ifdef DEBUG
728 fprintf (stderr, "got illegal OSC sequence\n");
729 #endif
730 }
731 break;
732 case ESosc2:
733 if (ch != 0x9c && ch != 7) {
734 int i = 0;
735 while (vt->osc_textbuf[i]) i++;
736 vt->osc_textbuf[i++] = ch;
737 vt->osc_textbuf[i] = 0;
738 } else {
739 #ifdef DEBUG
740 fprintf (stderr, "OSC:%c:%s\n", vt->osc_cmd, vt->osc_textbuf);
741 #endif
742 vt->tty_state = ESnormal;
743 }
744 break;
745 case ESpalette:
746 if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F')
747 || (ch >= 'a' && ch <= 'f')) {
748 vt->esc_buf[vt->esc_count++] = (ch > '9' ? (ch & 0xDF) - 'A' + 10 : ch - '0');
749 if (vt->esc_count == 7) {
750 // fixme: this does not work - please test
751 /*
752 rfbColourMap *cmap =&vt->screen->colourMap;
753
754 int i = color_table[vt->esc_buf[0]] * 3, j = 1;
755 cmap->data.bytes[i] = 16 * vt->esc_buf[j++];
756 cmap->data.bytes[i++] += vt->esc_buf[j++];
757 cmap->data.bytes[i] = 16 * vt->esc_buf[j++];
758 cmap->data.bytes[i++] += vt->esc_buf[j++];
759 cmap->data.bytes[i] = 16 * vt->esc_buf[j++];
760 cmap->data.bytes[i] += vt->esc_buf[j];
761 */
762 //set_palette(vc); ?
763
764 vt->tty_state = ESnormal;
765 }
766 } else
767 vt->tty_state = ESnormal;
768 break;
769 case ESsquare:
770 for(i = 0; i < MAX_ESC_PARAMS; i++) {
771 vt->esc_buf[i] = 0;
772 }
773
774 vt->esc_count = 0;
775 vt->esc_has_par = 0;
776 vt->tty_state = ESgetpars;
777
778 if (ch == '>') {
779 vt->tty_state = ESidquery;
780 break;
781 }
782
783 if ((vt->esc_ques = (ch == '?'))) {
784 break;
785 }
786 case ESgetpars:
787 if (ch >= '0' && ch <= '9') {
788 vt->esc_has_par = 1;
789 if (vt->esc_count < MAX_ESC_PARAMS) {
790 vt->esc_buf[vt->esc_count] = vt->esc_buf[vt->esc_count] * 10 + ch - '0';
791 }
792 break;
793 } else if (ch == ';') {
794 vt->esc_count++;
795 break;
796 } else {
797 if (vt->esc_has_par) {
798 vt->esc_count++;
799 }
800 vt->tty_state = ESgotpars;
801 }
802 case ESgotpars:
803
804 vt->tty_state = ESnormal;
805
806 #ifdef DEBUG
807 char *qes = vt->esc_ques ? "?" : "";
808 if (vt->esc_count == 0) {
809 fprintf(stderr, "ESC[%s%c\n", qes, ch);
810 } else if (vt->esc_count == 1) {
811 fprintf(stderr, "ESC[%s%d%c\n", qes, vt->esc_buf[0], ch);
812 } else {
813 int i;
814 fprintf(stderr, "ESC[%s%d", qes, vt->esc_buf[0]);
815 for (i = 1; i < vt->esc_count; i++) {
816 fprintf(stderr, ";%d", vt->esc_buf[i]);
817 }
818 fprintf (stderr, "%c\n", ch);
819 }
820 #endif
821
822 switch (ch) {
823 case 'h':
824 vncterm_set_mode (vt, 1);
825 break;
826 case 'l':
827 vncterm_set_mode (vt, 0);
828 break;
829 case 'm':
830 if (!vt->esc_count) {
831 vt->esc_count++; // default parameter 0
832 }
833 vncterm_csi_m (vt);
834 break;
835 case 'n':
836 /* report cursor position */
837 /* TODO: send ESC[row;colR */
838 break;
839 case 'A':
840 /* move cursor up */
841 if (vt->esc_buf[0] == 0) {
842 vt->esc_buf[0] = 1;
843 }
844 vt->cy -= vt->esc_buf[0];
845 if (vt->cy < 0) {
846 vt->cy = 0;
847 }
848 break;
849 case 'B':
850 case 'e':
851 /* move cursor down */
852 if (vt->esc_buf[0] == 0) {
853 vt->esc_buf[0] = 1;
854 }
855 vt->cy += vt->esc_buf[0];
856 if (vt->cy >= vt->height) {
857 vt->cy = vt->height - 1;
858 }
859 break;
860 case 'C':
861 case 'a':
862 /* move cursor right */
863 if (vt->esc_buf[0] == 0) {
864 vt->esc_buf[0] = 1;
865 }
866 vt->cx += vt->esc_buf[0];
867 if (vt->cx >= vt->width) {
868 vt->cx = vt->width - 1;
869 }
870 break;
871 case 'D':
872 /* move cursor left */
873 if (vt->esc_buf[0] == 0) {
874 vt->esc_buf[0] = 1;
875 }
876 vt->cx -= vt->esc_buf[0];
877 if (vt->cx < 0) {
878 vt->cx = 0;
879 }
880 break;
881 case 'G':
882 case '`':
883 /* move cursor to column */
884 vncterm_gotoxy (vt, vt->esc_buf[0] - 1, vt->cy);
885 break;
886 case 'd':
887 /* move cursor to row */
888 vncterm_gotoxy (vt, vt->cx , vt->esc_buf[0] - 1);
889 break;
890 case 'f':
891 case 'H':
892 /* move cursor to row, column */
893 vncterm_gotoxy (vt, vt->esc_buf[1] - 1, vt->esc_buf[0] - 1);
894 break;
895 case 'J':
896 switch (vt->esc_buf[0]) {
897 case 0:
898 /* clear to end of screen */
899 for (y = vt->cy; y < vt->height; y++) {
900 for (x = 0; x < vt->width; x++) {
901 if (y == vt->cy && x < vt->cx) {
902 continue;
903 }
904 vncterm_clear_xy (vt, x, y);
905 }
906 }
907 break;
908 case 1:
909 /* clear from beginning of screen */
910 for (y = 0; y <= vt->cy; y++) {
911 for (x = 0; x < vt->width; x++) {
912 if (y == vt->cy && x > vt->cx) {
913 break;
914 }
915 vncterm_clear_xy (vt, x, y);
916 }
917 }
918 break;
919 case 2:
920 /* clear entire screen */
921 for (y = 0; y <= vt->height; y++) {
922 for (x = 0; x < vt->width; x++) {
923 vncterm_clear_xy (vt, x, y);
924 }
925 }
926 break;
927 }
928 break;
929 case 'K':
930 switch (vt->esc_buf[0]) {
931 case 0:
932 /* clear to eol */
933 for(x = vt->cx; x < vt->width; x++) {
934 vncterm_clear_xy (vt, x, vt->cy);
935 }
936 break;
937 case 1:
938 /* clear from beginning of line */
939 for (x = 0; x <= vt->cx; x++) {
940 vncterm_clear_xy (vt, x, vt->cy);
941 }
942 break;
943 case 2:
944 /* clear entire line */
945 for(x = 0; x < vt->width; x++) {
946 vncterm_clear_xy (vt, x, vt->cy);
947 }
948 break;
949 }
950 break;
951 case 'L':
952 /* insert line */
953 c = vt->esc_buf[0];
954
955 if (c > vt->height - vt->cy)
956 c = vt->height - vt->cy;
957 else if (!c)
958 c = 1;
959
960 vncterm_scroll_down (vt, vt->cy, vt->region_bottom, c);
961 break;
962 case 'M':
963 /* delete line */
964 c = vt->esc_buf[0];
965
966 if (c > vt->height - vt->cy)
967 c = vt->height - vt->cy;
968 else if (!c)
969 c = 1;
970
971 vncterm_scroll_up (vt, vt->cy, vt->region_bottom, c, 1);
972 break;
973 case 'T':
974 /* scroll down */
975 c = vt->esc_buf[0];
976 if (!c) c = 1;
977 vncterm_scroll_down (vt, vt->region_top, vt->region_bottom, c);
978 break;
979 case 'S':
980 /* scroll up */
981 c = vt->esc_buf[0];
982 if (!c) c = 1;
983 vncterm_scroll_up (vt, vt->region_top, vt->region_bottom, c, 1);
984 break;
985 case 'P':
986 /* delete c character */
987 c = vt->esc_buf[0];
988
989 if (c > vt->width - vt->cx)
990 c = vt->width - vt->cx;
991 else if (!c)
992 c = 1;
993
994 for (x = vt->cx; x < vt->width - c; x++) {
995 int y1 = (vt->y_base + vt->cy) % vt->total_height;
996 TextCell *dst = &vt->cells[y1 * vt->width + x];
997 TextCell *src = dst + c;
998 *dst = *src;
999 vncterm_update_xy (vt, x + c, vt->cy);
1000 src->ch = ' ';
1001 src->attrib = vt->default_attrib;
1002 vncterm_update_xy (vt, x, vt->cy);
1003 }
1004 break;
1005 case 's':
1006 /* save cursor position */
1007 vncterm_save_cursor (vt);
1008 break;
1009 case 'u':
1010 /* restore cursor position */
1011 vncterm_restore_cursor (vt);
1012 break;
1013 case 'X':
1014 /* erase c characters */
1015 c = vt->esc_buf[0];
1016 if (!c) c = 1;
1017
1018 if (c > (vt->width - vt->cx)) c = vt->width - vt->cx;
1019
1020 for(i = 0; i < c; i++) {
1021 vncterm_clear_xy (vt, vt->cx + i, vt->cy);
1022 }
1023 break;
1024 case '@':
1025 /* insert c character */
1026 c = vt->esc_buf[0];
1027 if (c > (vt->width - vt->cx)) {
1028 c = vt->width - vt->cx;
1029 }
1030 if (!c) c = 1;
1031
1032 for (x = vt->width - c; x >= vt->cx; x--) {
1033 int y1 = (vt->y_base + vt->cy) % vt->total_height;
1034 TextCell *src = &vt->cells[y1 * vt->width + x];
1035 TextCell *dst = src + c;
1036 *dst = *src;
1037 vncterm_update_xy (vt, x + c, vt->cy);
1038 src->ch = ' ';
1039 src->attrib = vt->cur_attrib;
1040 vncterm_update_xy (vt, x, vt->cy);
1041 }
1042
1043 break;
1044 case 'r':
1045 /* set region */
1046 if (!vt->esc_buf[0])
1047 vt->esc_buf[0]++;
1048 if (!vt->esc_buf[1])
1049 vt->esc_buf[1] = vt->height;
1050 /* Minimum allowed region is 2 lines */
1051 if (vt->esc_buf[0] < vt->esc_buf[1] &&
1052 vt->esc_buf[1] <= vt->height) {
1053 vt->region_top = vt->esc_buf[0] - 1;
1054 vt->region_bottom = vt->esc_buf[1];
1055 vt->cx = 0;
1056 vt->cy = vt->region_top;
1057 #ifdef DEBUG
1058 fprintf (stderr, "set region %d %d\n", vt->region_top, vt->region_bottom);
1059 #endif
1060 }
1061
1062 break;
1063 default:
1064 #ifdef DEBUG
1065 if (vt->esc_count == 0) {
1066 fprintf(stderr, "unhandled escape ESC[%s%c\n", qes, ch);
1067 } else if (vt->esc_count == 1) {
1068 fprintf(stderr, "unhandled escape ESC[%s%d%c\n", qes, vt->esc_buf[0], ch);
1069 } else {
1070 int i;
1071 fprintf(stderr, "unhandled escape ESC[%s%d", qes, vt->esc_buf[0]);
1072 for (i = 1; i < vt->esc_count; i++) {
1073 fprintf(stderr, ";%d", vt->esc_buf[i]);
1074 }
1075 fprintf (stderr, "%c\n", ch);
1076 }
1077 #endif
1078 break;
1079 }
1080 vt->esc_ques = 0;
1081 break;
1082 case ESsetG0: // Set G0
1083 vt->tty_state = ESnormal;
1084
1085 if (ch == '0')
1086 vt->g0enc = GRAF_MAP;
1087 else if (ch == 'B')
1088 vt->g0enc = LAT1_MAP;
1089 else if (ch == 'U')
1090 vt->g0enc = IBMPC_MAP;
1091 else if (ch == 'K')
1092 vt->g0enc = USER_MAP;
1093
1094 if (vt->charset == 0)
1095 vt->cur_enc = vt->g0enc;
1096
1097 break;
1098 case ESsetG1: // Set G1
1099 vt->tty_state = ESnormal;
1100
1101 if (ch == '0')
1102 vt->g1enc = GRAF_MAP;
1103 else if (ch == 'B')
1104 vt->g1enc = LAT1_MAP;
1105 else if (ch == 'U')
1106 vt->g1enc = IBMPC_MAP;
1107 else if (ch == 'K')
1108 vt->g1enc = USER_MAP;
1109
1110 if (vt->charset == 1)
1111 vt->cur_enc = vt->g1enc;
1112
1113 break;
1114 case ESidquery: // vt100 query id
1115 vt->tty_state = ESnormal;
1116
1117 if (ch == 'c') {
1118 #ifdef DEBUG
1119 fprintf (stderr, "ESC[>c Query term ID\n");
1120 #endif
1121 vncterm_respond_esc (vt, TERMIDCODE);
1122 }
1123 break;
1124 case ESpercent:
1125 vt->tty_state = ESnormal;
1126 switch (ch) {
1127 case '@': /* defined in ISO 2022 */
1128 vt->utf8 = 0;
1129 break;
1130 case 'G': /* prelim official escape code */
1131 case '8': /* retained for compatibility */
1132 vt->utf8 = 1;
1133 break;
1134 }
1135 break;
1136 default: // ESnormal
1137 vt->tty_state = ESnormal;
1138
1139 switch(ch) {
1140 case 0:
1141 break;
1142 case 7: /* alert aka. bell */
1143 // fixme:
1144 //rfbSendBell(vt->screen);
1145 break;
1146 case 8: /* backspace */
1147 if (vt->cx > 0)
1148 vt->cx--;
1149 break;
1150 case 9: /* tabspace */
1151 if (vt->cx + (8 - (vt->cx % 8)) > vt->width) {
1152 vt->cx = 0;
1153 vncterm_put_lf (vt);
1154 } else {
1155 vt->cx = vt->cx + (8 - (vt->cx % 8));
1156 }
1157 break;
1158 case 10: /* LF,*/
1159 case 11: /* VT */
1160 case 12: /* FF */
1161 vncterm_put_lf (vt);
1162 break;
1163 case 13: /* carriage return */
1164 vt->cx = 0;
1165 break;
1166 case 14:
1167 /* SI (shift in), select character set 1 */
1168 vt->charset = 1;
1169 vt->cur_enc = vt->g1enc;
1170 /* fixme: display controls = 1 */
1171 break;
1172 case 15:
1173 /* SO (shift out), select character set 0 */
1174 vt->charset = 0;
1175 vt->cur_enc = vt->g0enc;
1176 /* fixme: display controls = 0 */
1177 break;
1178 case 27: /* esc */
1179 vt->tty_state = ESesc;
1180 break;
1181 case 127: /* delete */
1182 /* ignore */
1183 break;
1184 case 128+27: /* csi */
1185 vt->tty_state = ESsquare;
1186 break;
1187 default:
1188 if (vt->cx >= vt->width) {
1189 /* line wrap */
1190 vt->cx = 0;
1191 vncterm_put_lf (vt);
1192 }
1193
1194 int y1 = (vt->y_base + vt->cy) % vt->total_height;
1195 TextCell *c = &vt->cells[y1*vt->width + vt->cx];
1196 c->attrib = vt->cur_attrib;
1197 c->ch = ch;
1198 vncterm_update_xy (vt, vt->cx, vt->cy);
1199 vt->cx++;
1200 break;
1201 }
1202 break;
1203 }
1204 }
1205
1206 static int
1207 vncterm_puts (vncTerm *vt, const char *buf, int len)
1208 {
1209 unicode tc;
1210
1211 vncterm_show_cursor (vt, 0);
1212
1213 while (len) {
1214 unsigned char c = *buf;
1215 len--;
1216 buf++;
1217
1218 if (vt->tty_state != ESnormal) {
1219 // never translate escape sequence
1220 tc = c;
1221 } else if (vt->utf8 && !vt->cur_enc) {
1222
1223 if(c & 0x80) { // utf8 multi-byte sequence
1224
1225 if (vt->utf_count > 0 && (c & 0xc0) == 0x80) {
1226 // inside UTF8 sequence
1227 vt->utf_char = (vt->utf_char << 6) | (c & 0x3f);
1228 vt->utf_count--;
1229 if (vt->utf_count == 0) {
1230 tc = vt->utf_char;
1231 } else {
1232 continue;
1233 }
1234 } else {
1235 // first char of a UTF8 sequence
1236 if ((c & 0xe0) == 0xc0) {
1237 vt->utf_count = 1;
1238 vt->utf_char = (c & 0x1f);
1239 } else if ((c & 0xf0) == 0xe0) {
1240 vt->utf_count = 2;
1241 vt->utf_char = (c & 0x0f);
1242 } else if ((c & 0xf8) == 0xf0) {
1243 vt->utf_count = 3;
1244 vt->utf_char = (c & 0x07);
1245 } else if ((c & 0xfc) == 0xf8) {
1246 vt->utf_count = 4;
1247 vt->utf_char = (c & 0x03);
1248 } else if ((c & 0xfe) == 0xfc) {
1249 vt->utf_count = 5;
1250 vt->utf_char = (c & 0x01);
1251 } else
1252 vt->utf_count = 0;
1253
1254 continue;
1255 }
1256 } else {
1257 // utf8 single byte
1258 tc = c;
1259 vt->utf_count = 0;
1260 }
1261
1262 } else {
1263 // never translate controls
1264 if (c >= 32 && c != 127 && c != (128+27)) {
1265 tc = translations[vt->cur_enc][c & 0x0ff];
1266 } else {
1267 tc = c;
1268 }
1269 }
1270
1271 vncterm_putchar (vt, tc);
1272 }
1273
1274 vncterm_show_cursor (vt, 1);
1275
1276 return len;
1277 }
1278
1279 /* fixme:
1280 void
1281 vncterm_set_xcut_text (char* str, int len, struct _rfbClientRec* cl)
1282 {
1283 vncTerm *vt =(vncTerm *)cl->screen->screenData;
1284
1285 // seems str is Latin-1 encoded
1286 if (vt->selection) free (vt->selection);
1287 vt->selection = (unicode *)malloc (len*sizeof (unicode));
1288 int i;
1289 for (i = 0; i < len; i++) {
1290 vt->selection[i] = str[i] & 0xff;
1291 }
1292 vt->selection_len = len;
1293 }
1294 */
1295 static void
1296 mouse_report (vncTerm *vt, int butt, int mrx, int mry)
1297 {
1298 char buf[8];
1299
1300 sprintf (buf, "[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
1301 (char)('!' + mry));
1302
1303 vncterm_respond_esc (vt, buf);
1304 }
1305
1306 void
1307 vncterm_toggle_marked_cell (vncTerm *vt, int pos)
1308 {
1309 int x= (pos%vt->width)*8;
1310 int y= (pos/vt->width)*16;
1311
1312 /* fixme:
1313
1314 int i,j;
1315 rfbScreenInfoPtr s=vt->screen;
1316
1317 char *b = s->frameBuffer+y*s->width+x;
1318
1319 for (j=0; j < 16; j++) {
1320 for(i=0; i < 8; i++) {
1321 b[j*s->width+i] ^= 0x0f;
1322 rfbMarkRectAsModified (s, x, y, x+8, y+16);
1323 }
1324 }
1325 */
1326 }
1327
1328 /* fixme:
1329
1330 void
1331 vncterm_pointer_event (int buttonMask, int x, int y, rfbClientPtr cl)
1332 {
1333
1334 vncTerm *vt =(vncTerm *)cl->screen->screenData;
1335 static int button2_released = 1;
1336 static int last_mask = 0;
1337 static int sel_start_pos = 0;
1338 static int sel_end_pos = 0;
1339 int i;
1340
1341 int cx = x/8;
1342 int cy = y/16;
1343
1344 if (cx < 0) cx = 0;
1345 if (cx >= vt->width) cx = vt->width - 1;
1346 if (cy < 0) cy = 0;
1347 if (cy >= vt->height) cy = vt->height - 1;
1348
1349 if (vt->report_mouse && buttonMask != last_mask) {
1350 last_mask = buttonMask;
1351 if (buttonMask & 1) {
1352 mouse_report (vt, 0, cx, cy);
1353 }
1354 if (buttonMask & 2) {
1355 mouse_report (vt, 1, cx, cy);
1356 }
1357 if (buttonMask & 4) {
1358 mouse_report (vt, 2, cx, cy);
1359 }
1360 if (!buttonMask) {
1361 mouse_report (vt, 3, cx, cy);
1362 }
1363 }
1364
1365 if (buttonMask & 2) {
1366 if(button2_released && vt->selection) {
1367 int i;
1368 for(i = 0; i < vt->selection_len; i++) {
1369 if (vt->ibuf_count < IBUFSIZE - 6) { // uft8 is max 6 characters wide
1370 if (vt->utf8) {
1371 vt->ibuf_count += ucs2_to_utf8 (vt->selection[i], &vt->ibuf[vt->ibuf_count]);
1372 } else {
1373 vt->ibuf[vt->ibuf_count++] = vt->selection[i];
1374 }
1375 }
1376 }
1377 if (vt->y_displ != vt->y_base) {
1378 vt->y_displ = vt->y_base;
1379 vncterm_refresh (vt);
1380 }
1381 }
1382 button2_released = 0;
1383 } else {
1384 button2_released = 1;
1385 }
1386
1387 if (buttonMask & 1) {
1388 int pos = cy*vt->width + cx;
1389
1390 // code borrowed from libvncserver (VNConsole.c)
1391
1392 if (!vt->mark_active) {
1393
1394 vt->mark_active = 1;
1395 sel_start_pos = sel_end_pos = pos;
1396 vncterm_toggle_marked_cell (vt, pos);
1397
1398 } else {
1399
1400 if (pos != sel_end_pos) {
1401
1402 if (pos > sel_end_pos) {
1403 cx = sel_end_pos; cy=pos;
1404 } else {
1405 cx=pos; cy=sel_end_pos;
1406 }
1407
1408 if (cx < sel_start_pos) {
1409 if (cy < sel_start_pos) cy--;
1410 } else {
1411 cx++;
1412 }
1413
1414 while (cx <= cy) {
1415 vncterm_toggle_marked_cell (vt, cx);
1416 cx++;
1417 }
1418
1419 sel_end_pos = pos;
1420 }
1421 }
1422
1423 } else if (vt->mark_active) {
1424 vt->mark_active = 0;
1425
1426 if (sel_start_pos > sel_end_pos) {
1427 int tmp = sel_start_pos - 1;
1428 sel_start_pos = sel_end_pos;
1429 sel_end_pos = tmp;
1430 }
1431
1432 int len = sel_end_pos - sel_start_pos + 1;
1433
1434 if (vt->selection) free (vt->selection);
1435 vt->selection = (unicode *)malloc (len*sizeof (unicode));
1436 vt->selection_len = len;
1437 char *sel_latin1 = (char *)malloc (len + 1);
1438
1439 for (i = 0; i < len; i++) {
1440 int pos = sel_start_pos + i;
1441 int x = pos % vt->width;
1442 int y1 = ((pos / vt->width) + vt->y_displ) % vt->total_height;
1443 TextCell *c = &vt->cells[y1*vt->width + x];
1444 vt->selection[i] = c->ch;
1445 sel_latin1[i] = (char)c->ch;
1446 c++;
1447 }
1448 sel_latin1[len] = 0;
1449 rfbGotXCutText (vt->screen, sel_latin1, len);
1450 free (sel_latin1);
1451
1452 while (sel_start_pos <= sel_end_pos) {
1453 vncterm_toggle_marked_cell (vt, sel_start_pos++);
1454 }
1455
1456 }
1457
1458 rfbDefaultPtrAddEvent (buttonMask, x, y, cl);
1459
1460 }
1461 */
1462
1463 static int client_count = 0;
1464 static int client_connected = 0;
1465 static int last_client = 1;
1466 static time_t last_time = 0;
1467
1468 static void my_kbd_push_key(SpiceKbdInstance *sin, uint8_t frag)
1469 {
1470 vncTerm *vt = SPICE_CONTAINEROF(sin, vncTerm, keyboard_sin);
1471
1472 return;
1473 printf("MYKEYCODE %x\n", frag);
1474
1475 if (vt->ibuf_count < (IBUFSIZE - 32)) {
1476
1477 char keySym = 'A'; // fixme;
1478 vt->ibuf[vt->ibuf_count++] = keySym;
1479
1480 vt->screen->core->watch_update_mask(vt->screen->mwatch, SPICE_WATCH_EVENT_READ|SPICE_WATCH_EVENT_WRITE);
1481 }
1482 }
1483
1484 static void my_kbd_push_unicode(SpiceKbdInstance *sin, uint32_t uc)
1485 {
1486 vncTerm *vt = SPICE_CONTAINEROF(sin, vncTerm, keyboard_sin);
1487
1488 printf("MYKEYVAL %x\n", uc);
1489
1490 if (vt->ibuf_count < (IBUFSIZE - 32)) {
1491 gchar buf[10];
1492 gint len = g_unichar_to_utf8(uc, buf);
1493
1494 if (len > 0) {
1495 int i;
1496 for (i = 0; i < len; i++) {
1497 vt->ibuf[vt->ibuf_count++] = buf[i];
1498 }
1499 }
1500 vt->screen->core->watch_update_mask(vt->screen->mwatch, SPICE_WATCH_EVENT_READ|SPICE_WATCH_EVENT_WRITE);
1501 }
1502 }
1503
1504 static uint8_t my_kbd_get_leds(SpiceKbdInstance *sin)
1505 {
1506 return 0;
1507 }
1508
1509 static SpiceKbdInterface my_keyboard_sif = {
1510 .base.type = SPICE_INTERFACE_KEYBOARD ,
1511 .base.description = "spiceterm keyboard device",
1512 .base.major_version = SPICE_INTERFACE_KEYBOARD_MAJOR,
1513 .base.minor_version = SPICE_INTERFACE_KEYBOARD_MINOR,
1514 .push_unicode = my_kbd_push_unicode,
1515 .push_scan_freg = my_kbd_push_key,
1516 .get_leds = my_kbd_get_leds,
1517 };
1518
1519 vncTerm *
1520 create_vncterm (int argc, char** argv, int maxx, int maxy)
1521 {
1522 int i;
1523
1524 Test *test;
1525
1526 SpiceCoreInterface *core = basic_event_loop_init();
1527 test = test_new(core);
1528 //spice_server_set_image_compression(server, SPICE_IMAGE_COMPRESS_OFF);
1529 test_add_display_interface(test);
1530 test_add_agent_interface(test->server);
1531
1532 vncTerm *vt = (vncTerm *)calloc (sizeof(vncTerm), 1);
1533
1534 vt->keyboard_sin.base.sif = &my_keyboard_sif.base;
1535 spice_server_add_interface(test->server, &vt->keyboard_sin.base);
1536
1537 /*
1538 rfbColourMap *cmap =&screen->colourMap;
1539 cmap->data.bytes = malloc (16*3);
1540 for(i=0;i<16;i++) {
1541 cmap->data.bytes[i*3 + 0] = default_red[color_table[i]];
1542 cmap->data.bytes[i*3 + 1] = default_grn[color_table[i]];
1543 cmap->data.bytes[i*3 + 2] = default_blu[color_table[i]];
1544 }
1545 cmap->count = 16;
1546 cmap->is16 = FALSE;
1547 screen->serverFormat.trueColour = FALSE;
1548
1549 screen->kbdAddEvent = vncterm_kbd_event;
1550
1551 screen->setXCutText = vncterm_set_xcut_text;
1552
1553 screen->ptrAddEvent = vncterm_pointer_event;
1554
1555 screen->desktopName = "VNC Command Terminal";
1556
1557 screen->newClientHook = new_client;
1558
1559 */
1560
1561 vt->maxx = test->width;
1562 vt->maxy = test->height;
1563
1564 vt->width = vt->maxx / 8;
1565 vt->height = vt->maxy / 16;
1566
1567 vt->total_height = vt->height * 20;
1568 vt->scroll_height = 0;
1569 vt->y_base = 0;
1570 vt->y_displ = 0;
1571
1572 vt->region_top = 0;
1573 vt->region_bottom = vt->height;
1574
1575 vt->g0enc = LAT1_MAP;
1576 vt->g1enc = GRAF_MAP;
1577 vt->cur_enc = vt->g0enc;
1578 vt->charset = 0;
1579
1580 /* default text attributes */
1581 vt->default_attrib.bold = 0;
1582 vt->default_attrib.uline = 0;
1583 vt->default_attrib.blink = 0;
1584 vt->default_attrib.invers = 0;
1585 vt->default_attrib.unvisible = 0;
1586 vt->default_attrib.fgcol = 7;
1587 vt->default_attrib.bgcol = 0;
1588
1589 vt->cur_attrib = vt->default_attrib;
1590
1591 vt->cells = (TextCell *)calloc (sizeof (TextCell), vt->width*vt->total_height);
1592
1593 for (i = 0; i < vt->width*vt->total_height; i++) {
1594 vt->cells[i].ch = ' ';
1595 vt->cells[i].attrib = vt->default_attrib;
1596 }
1597
1598 vt->altcells = (TextCell *)calloc (sizeof (TextCell), vt->width*vt->height);
1599
1600 vt->screen = test;
1601
1602 return vt;
1603 }
1604
1605 static void master_watch(int master, int event, void *opaque)
1606 {
1607 vncTerm *vt = (vncTerm *)opaque;
1608
1609 printf("CHANNEL EVENT %d\n", event);
1610
1611 // fixme: if (!vt->mark_active) {
1612
1613 if (event == SPICE_WATCH_EVENT_READ) {
1614 char buffer[1024];
1615 int c;
1616 while ((c = read(master, buffer, 1024)) == -1) {
1617 if (errno != EAGAIN) break;
1618 }
1619 if (c == -1) {
1620 g_error("got read error"); // fixme
1621 }
1622 vncterm_puts (vt, buffer, c);
1623 } else {
1624 if (vt->ibuf_count > 0) {
1625 printf ("DEBUG: WRITE %x %d\n", vt->ibuf[0], vt->ibuf_count);
1626 write (master, vt->ibuf, vt->ibuf_count);
1627 vt->ibuf_count = 0; // fixme: what if not all data written
1628 }
1629 vt->screen->core->watch_update_mask(vt->screen->mwatch, SPICE_WATCH_EVENT_READ);
1630 }
1631 }
1632
1633 int
1634 main (int argc, char** argv)
1635 {
1636 int i;
1637 char **cmdargv = NULL;
1638 char *command = "/bin/bash"; // execute normal shell as default
1639 int pid;
1640 int master;
1641 char ptyname[1024];
1642 fd_set fs, fs1;
1643 struct timeval tv, tv1;
1644 time_t elapsed, cur_time;
1645 struct winsize dimensions;
1646
1647 for (i = 1; i < argc; i++) {
1648 if (!strcmp (argv[i], "-c")) {
1649 command = argv[i+1];
1650 cmdargv = &argv[i+1];
1651 argc = i;
1652 argv[i] = NULL;
1653 break;
1654 }
1655 }
1656
1657 vncTerm *vt = create_vncterm (argc, argv, 745, 400);
1658
1659 setlocale(LC_ALL, ""); // set from environment
1660
1661 char *ctype = setlocale (LC_CTYPE, NULL); // query LC_CTYPE
1662
1663 // fixme: ist there a standard way to detect utf8 mode ?
1664 if (strcasestr (ctype, ".utf-8")||strcasestr (ctype, ".utf8")) {
1665 vt->utf8 = 1;
1666 }
1667
1668 dimensions.ws_col = vt->width;
1669 dimensions.ws_row = vt->height;
1670
1671 setenv ("TERM", TERM, 1);
1672
1673 printf("EXEC: %s\n", command);
1674
1675 pid = forkpty (&master, ptyname, NULL, &dimensions);
1676 if(!pid) {
1677
1678 // install default signal handlers
1679 signal (SIGQUIT, SIG_DFL);
1680 signal (SIGTERM, SIG_DFL);
1681 signal (SIGINT, SIG_DFL);
1682
1683 if (cmdargv) {
1684 execvp (command, cmdargv);
1685 } else {
1686 execlp (command, command, NULL);
1687 }
1688 perror ("Error: exec failed\n");
1689 exit (-1); // should not be reached
1690 } else if (pid == -1) {
1691 perror ("Error: fork failed\n");
1692 exit (-1);
1693 }
1694
1695
1696 vt->screen->mwatch = vt->screen->core->watch_add(
1697 master, SPICE_WATCH_EVENT_READ /* |SPICE_WATCH_EVENT_WRITE */,
1698 master_watch, vt);
1699
1700 basic_event_loop_mainloop();
1701
1702 //rfbProcessEvents (vt->screen, 40000); /* 40 ms */
1703
1704 /*
1705 if (vt->ibuf_count > 0) {
1706 printf ("DEBUG: WRITE %d %d\n", vt->ibuf[0], vt->ibuf_count);
1707 write (master, vt->ibuf, vt->ibuf_count);
1708 vt->ibuf_count = 0;
1709 last_time = time (NULL);
1710 }
1711 */
1712
1713 kill (pid, 9);
1714 int status;
1715 waitpid(pid, &status, 0);
1716
1717 exit (0);
1718 }