| ︙ | | | ︙ | |
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
#define CAT(x,y) CAT2(x,y)
#define ASSERT(x) enum {CAT(assertion_,__LINE__) = 1 / (x)}
#define NCOLOURS (lenof(((Config *)0)->colours))
GdkAtom compound_text_atom, utf8_string_atom;
struct gui_data {
GtkWidget *window, *area, *sbar;
GtkBox *hbox;
GtkAdjustment *sbar_adjust;
GtkWidget *menu, *specialsmenu, *specialsitem1, *specialsitem2;
GdkPixmap *pixmap;
GdkFont *fonts[4]; /* normal, bold, wide, widebold */
struct {
int charset;
int is_wide;
} fontinfo[4];
int xpos, ypos, gotpos, gravity;
|
>
>
>
>
|
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
#define CAT(x,y) CAT2(x,y)
#define ASSERT(x) enum {CAT(assertion_,__LINE__) = 1 / (x)}
#define NCOLOURS (lenof(((Config *)0)->colours))
GdkAtom compound_text_atom, utf8_string_atom;
extern char **pty_argv; /* declared in pty.c */
extern int use_pty_argv;
struct gui_data {
GtkWidget *window, *area, *sbar;
GtkBox *hbox;
GtkAdjustment *sbar_adjust;
GtkWidget *menu, *specialsmenu, *specialsitem1, *specialsitem2;
GtkWidget *sessionsmenu;
GdkPixmap *pixmap;
GdkFont *fonts[4]; /* normal, bold, wide, widebold */
struct {
int charset;
int is_wide;
} fontinfo[4];
int xpos, ypos, gotpos, gravity;
|
| ︙ | | | ︙ | |
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
void *backhandle;
Terminal *term;
void *logctx;
int exited;
struct unicode_data ucsdata;
Config cfg;
void *eventlogstuff;
};
struct draw_ctx {
GdkGC *gc;
struct gui_data *inst;
};
|
>
>
|
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
void *backhandle;
Terminal *term;
void *logctx;
int exited;
struct unicode_data ucsdata;
Config cfg;
void *eventlogstuff;
char *progname, **gtkargvstart;
int ngtkargs;
};
struct draw_ctx {
GdkGC *gc;
struct gui_data *inst;
};
|
| ︙ | | | ︙ | |
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
|
}
}
int do_cmdline(int argc, char **argv, int do_everything,
struct gui_data *inst, Config *cfg)
{
int err = 0;
extern char **pty_argv; /* declared in pty.c */
extern int use_pty_argv;
/*
* Macros to make argument handling easier. Note that because
* they need to call `continue', they cannot be contained in
* the usual do {...} while (0) wrapper to make them
* syntactically single statements; hence it is not legal to
* use one of these macros as an unbraced statement between
* `if' and `else'.
*/
#define EXPECTS_ARG { \
if (--argc <= 0) { \
err = 1; \
fprintf(stderr, "%s: %s expects an argument\n", appname, p); \
continue; \
} else \
val = *++argv; \
}
#define SECOND_PASS_ONLY { if (!do_everything) continue; }
char *val;
while (--argc > 0) {
char *p = *++argv;
int ret;
ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL),
do_everything ? 1 : -1, cfg);
|
|
<
<
|
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
|
}
}
int do_cmdline(int argc, char **argv, int do_everything,
struct gui_data *inst, Config *cfg)
{
int err = 0;
char *val;
/*
* Macros to make argument handling easier. Note that because
* they need to call `continue', they cannot be contained in
* the usual do {...} while (0) wrapper to make them
* syntactically single statements; hence it is not legal to
* use one of these macros as an unbraced statement between
* `if' and `else'.
*/
#define EXPECTS_ARG { \
if (--argc <= 0) { \
err = 1; \
fprintf(stderr, "%s: %s expects an argument\n", appname, p); \
continue; \
} else \
val = *++argv; \
}
#define SECOND_PASS_ONLY { if (!do_everything) continue; }
while (--argc > 0) {
char *p = *++argv;
int ret;
ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL),
do_everything ? 1 : -1, cfg);
|
| ︙ | | | ︙ | |
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
|
cfg2.savelines);
}
term_invalidate(inst->term);
}
sfree(title);
}
void update_specials_menu(void *frontend)
{
struct gui_data *inst = (struct gui_data *)frontend;
const struct telnet_special *specials;
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
|
cfg2.savelines);
}
term_invalidate(inst->term);
}
sfree(title);
}
void fork_and_exec_self(struct gui_data *inst, int fd_to_close, ...)
{
/*
* Re-execing ourself is not an exact science under Unix. I do
* the best I can by using /proc/self/exe if available and by
* assuming argv[0] can be found on $PATH if not.
*
* Note that we also have to reconstruct the elements of the
* original argv which gtk swallowed, since the user wants the
* new session to appear on the same X display as the old one.
*/
char **args;
va_list ap;
int i, n;
int pid;
/*
* Collect the arguments with which to re-exec ourself.
*/
va_start(ap, fd_to_close);
n = 2; /* progname and terminating NULL */
n += inst->ngtkargs;
while (va_arg(ap, char *) != NULL)
n++;
va_end(ap);
args = snewn(n, char *);
args[0] = inst->progname;
args[n-1] = NULL;
for (i = 0; i < inst->ngtkargs; i++)
args[i+1] = inst->gtkargvstart[i];
i++;
va_start(ap, fd_to_close);
while ((args[i++] = va_arg(ap, char *)) != NULL);
va_end(ap);
assert(i == n);
/*
* Do the double fork.
*/
pid = fork();
if (pid < 0) {
perror("fork");
return;
}
if (pid == 0) {
int pid2 = fork();
if (pid2 < 0) {
perror("fork");
_exit(1);
} else if (pid2 > 0) {
/*
* First child has successfully forked second child. My
* Work Here Is Done. Note the use of _exit rather than
* exit: the latter appears to cause destroy messages
* to be sent to the X server. I suspect gtk uses
* atexit.
*/
_exit(0);
}
/*
* If we reach here, we are the second child, so we now
* actually perform the exec.
*/
if (fd_to_close >= 0)
close(fd_to_close);
execv("/proc/self/exe", args);
execvp(inst->progname, args);
perror("exec");
_exit(127);
} else {
int status;
waitpid(pid, &status, 0);
}
}
void dup_session_menuitem(GtkMenuItem *item, gpointer gdata)
{
struct gui_data *inst = (struct gui_data *)gdata;
/*
* For this feature we must marshal cfg and (possibly) pty_argv
* into a byte stream, create a pipe, and send this byte stream
* to the child through the pipe.
*/
int i, ret, size;
char *data;
char option[80];
int pipefd[2];
if (pipe(pipefd) < 0) {
perror("pipe");
return;
}
size = sizeof(inst->cfg);
if (use_pty_argv && pty_argv) {
for (i = 0; pty_argv[i]; i++)
size += strlen(pty_argv[i]) + 1;
}
data = snewn(size, char);
memcpy(data, &inst->cfg, sizeof(inst->cfg));
if (use_pty_argv && pty_argv) {
int p = sizeof(inst->cfg);
for (i = 0; pty_argv[i]; i++) {
strcpy(data + p, pty_argv[i]);
p += strlen(pty_argv[i]) + 1;
}
assert(p == size);
}
sprintf(option, "---[%d,%d]", pipefd[0], size);
fcntl(pipefd[0], F_SETFD, 0);
fork_and_exec_self(inst, pipefd[1], option, NULL);
close(pipefd[0]);
i = 0;
while (i < size && (ret = write(pipefd[1], data + i, size - i)) > 0)
i += ret;
if (ret < 0)
perror("write to pipe");
close(pipefd[1]);
sfree(data);
}
int read_dupsession_data(struct gui_data *inst, Config *cfg, char *arg)
{
int fd, i, ret, size;
char *data;
if (sscanf(arg, "---[%d,%d]", &fd, &size) != 2) {
fprintf(stderr, "%s: malformed magic argument `%s'\n", appname, arg);
exit(1);
}
data = snewn(size, char);
i = 0;
while (i < size && (ret = read(fd, data + i, size - i)) > 0)
i += ret;
if (ret < 0) {
perror("read from pipe");
exit(1);
} else if (i < size) {
fprintf(stderr, "%s: unexpected EOF in Duplicate Session data\n",
appname);
exit(1);
}
memcpy(cfg, data, sizeof(Config));
if (use_pty_argv && size > sizeof(Config)) {
int n = 0;
i = sizeof(Config);
while (i < size) {
while (i < size && data[i]) i++;
if (i >= size) {
fprintf(stderr, "%s: malformed Duplicate Session data\n",
appname);
exit(1);
}
i++;
n++;
}
pty_argv = snewn(n+1, char *);
pty_argv[n] = NULL;
n = 0;
i = sizeof(Config);
while (i < size) {
char *p = data + i;
while (i < size && data[i]) i++;
assert(i < size);
i++;
pty_argv[n++] = dupstr(p);
}
}
return 0;
}
void new_session_menuitem(GtkMenuItem *item, gpointer data)
{
struct gui_data *inst = (struct gui_data *)data;
fork_and_exec_self(inst, -1, NULL);
}
void saved_session_menuitem(GtkMenuItem *item, gpointer data)
{
struct gui_data *inst = (struct gui_data *)data;
char *str = (char *)gtk_object_get_data(GTK_OBJECT(item), "user-data");
fork_and_exec_self(inst, -1, "-load", str, NULL);
}
void saved_session_freedata(GtkMenuItem *item, gpointer data)
{
char *str = (char *)gtk_object_get_data(GTK_OBJECT(item), "user-data");
sfree(str);
}
void update_specials_menu(void *frontend)
{
struct gui_data *inst = (struct gui_data *)frontend;
const struct telnet_special *specials;
|
| ︙ | | | ︙ | |
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
|
int pt_main(int argc, char **argv)
{
extern Backend *select_backend(Config *cfg);
extern int cfgbox(Config *cfg);
struct gui_data *inst;
/* defer any child exit handling until we're ready to deal with
* it */
block_signal(SIGCHLD, 1);
gtk_init(&argc, &argv);
/*
* Create an instance structure and initialise to zeroes
*/
inst = snew(struct gui_data);
memset(inst, 0, sizeof(*inst));
inst->alt_keycode = -1; /* this one needs _not_ to be zero */
if (do_cmdline(argc, argv, 0, inst, &inst->cfg))
exit(1); /* pre-defaults pass to get -class */
do_defaults(NULL, &inst->cfg);
if (do_cmdline(argc, argv, 1, inst, &inst->cfg))
exit(1); /* post-defaults, do everything */
cmdline_run_saved(&inst->cfg);
if (!*inst->cfg.host && !cfgbox(&inst->cfg))
exit(0); /* config box hit Cancel */
if (!compound_text_atom)
compound_text_atom = gdk_atom_intern("COMPOUND_TEXT", FALSE);
if (!utf8_string_atom)
utf8_string_atom = gdk_atom_intern("UTF8_STRING", FALSE);
setup_fonts_ucs(inst);
|
>
>
>
>
>
>
>
<
>
>
>
>
>
>
<
>
>
>
>
|
>
|
>
>
|
|
>
>
>
>
>
>
|
|
|
|
|
|
|
|
>
|
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
|
int pt_main(int argc, char **argv)
{
extern Backend *select_backend(Config *cfg);
extern int cfgbox(Config *cfg);
struct gui_data *inst;
/*
* Create an instance structure and initialise to zeroes
*/
inst = snew(struct gui_data);
memset(inst, 0, sizeof(*inst));
inst->alt_keycode = -1; /* this one needs _not_ to be zero */
/* defer any child exit handling until we're ready to deal with
* it */
block_signal(SIGCHLD, 1);
/*
* SIGPIPE is not something we want to see terminating the
* process.
*/
block_signal(SIGPIPE, 1);
inst->progname = argv[0];
/*
* Copy the original argv before letting gtk_init fiddle with
* it. It will be required later.
*/
{
int i, oldargc;
inst->gtkargvstart = snewn(argc-1, char *);
for (i = 1; i < argc; i++)
inst->gtkargvstart[i-1] = dupstr(argv[i]);
oldargc = argc;
gtk_init(&argc, &argv);
inst->ngtkargs = oldargc - argc;
}
if (argc > 1 && !strncmp(argv[1], "---", 3)) {
read_dupsession_data(inst, &inst->cfg, argv[1]);
/* Splatter this argument so it doesn't clutter a ps listing */
memset(argv[1], 0, strlen(argv[1]));
} else {
if (do_cmdline(argc, argv, 0, inst, &inst->cfg))
exit(1); /* pre-defaults pass to get -class */
do_defaults(NULL, &inst->cfg);
if (do_cmdline(argc, argv, 1, inst, &inst->cfg))
exit(1); /* post-defaults, do everything */
cmdline_run_saved(&inst->cfg);
if (!*inst->cfg.host && !cfgbox(&inst->cfg))
exit(0); /* config box hit Cancel */
}
if (!compound_text_atom)
compound_text_atom = gdk_atom_intern("COMPOUND_TEXT", FALSE);
if (!utf8_string_atom)
utf8_string_atom = gdk_atom_intern("UTF8_STRING", FALSE);
setup_fonts_ucs(inst);
|
| ︙ | | | ︙ | |
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
|
/*
* Set up the Ctrl+rightclick context menu.
*/
{
GtkWidget *menuitem;
char *s;
extern const int use_event_log;
inst->menu = gtk_menu_new();
#define MKMENUITEM(title, func) do { \
menuitem = title ? gtk_menu_item_new_with_label(title) : \
gtk_menu_item_new(); \
gtk_container_add(GTK_CONTAINER(inst->menu), menuitem); \
gtk_widget_show(menuitem); \
if (func != NULL) \
gtk_signal_connect(GTK_OBJECT(menuitem), "activate", \
GTK_SIGNAL_FUNC(func), inst); \
} while (0)
MKMENUITEM("Change Settings", change_settings_menuitem);
MKMENUITEM(NULL, NULL);
if (use_event_log)
MKMENUITEM("Event Log", event_log_menuitem);
MKMENUITEM("Special Commands", NULL);
inst->specialsmenu = gtk_menu_new();
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), inst->specialsmenu);
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
|
/*
* Set up the Ctrl+rightclick context menu.
*/
{
GtkWidget *menuitem;
char *s;
extern const int use_event_log, new_session, saved_sessions;
inst->menu = gtk_menu_new();
#define MKMENUITEM(title, func) do { \
menuitem = title ? gtk_menu_item_new_with_label(title) : \
gtk_menu_item_new(); \
gtk_container_add(GTK_CONTAINER(inst->menu), menuitem); \
gtk_widget_show(menuitem); \
if (func != NULL) \
gtk_signal_connect(GTK_OBJECT(menuitem), "activate", \
GTK_SIGNAL_FUNC(func), inst); \
} while (0)
if (new_session)
MKMENUITEM("New Session", new_session_menuitem);
MKMENUITEM("Duplicate Session", dup_session_menuitem);
if (saved_sessions) {
struct sesslist sesslist;
int i;
inst->sessionsmenu = gtk_menu_new();
get_sesslist(&sesslist, TRUE);
for (i = 1; i < sesslist.nsessions; i++) {
menuitem = gtk_menu_item_new_with_label(sesslist.sessions[i]);
gtk_container_add(GTK_CONTAINER(inst->sessionsmenu), menuitem);
gtk_widget_show(menuitem);
gtk_object_set_data(GTK_OBJECT(menuitem), "user-data",
dupstr(sesslist.sessions[i]));
gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
GTK_SIGNAL_FUNC(saved_session_menuitem),
inst);
gtk_signal_connect(GTK_OBJECT(menuitem), "destroy",
GTK_SIGNAL_FUNC(saved_session_freedata),
inst);
}
get_sesslist(&sesslist, FALSE);
MKMENUITEM("Saved Sessions", NULL);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem),
inst->sessionsmenu);
}
MKMENUITEM(NULL, NULL);
MKMENUITEM("Change Settings", change_settings_menuitem);
MKMENUITEM(NULL, NULL);
if (use_event_log)
MKMENUITEM("Event Log", event_log_menuitem);
MKMENUITEM("Special Commands", NULL);
inst->specialsmenu = gtk_menu_new();
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), inst->specialsmenu);
|
| ︙ | | | ︙ | |