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