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