⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pterm.c

📁 远程登陆工具软件源码 用于远程登陆unix
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * pterm - a fusion of the PuTTY terminal emulator with a Unix pty
 * back end, all running as a GTK application. Wish me luck.
 */

#define _GNU_SOURCE

#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <gdk/gdkx.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>

#define PUTTY_DO_GLOBALS	       /* actually _define_ globals */

#include "putty.h"
#include "terminal.h"

#define CAT2(x,y) x ## y
#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;
    GdkCursor *rawcursor, *textcursor, *blankcursor, *currcursor;
    GdkColor cols[NCOLOURS];
    GdkColormap *colmap;
    wchar_t *pastein_data;
    int direct_to_font;
    int pastein_data_len;
    char *pasteout_data, *pasteout_data_ctext, *pasteout_data_utf8;
    int pasteout_data_len, pasteout_data_ctext_len, pasteout_data_utf8_len;
    int font_width, font_height;
    int width, height;
    int ignore_sbar;
    int mouseptr_visible;
    guint term_paste_idle_id;
    int alt_keycode;
    int alt_digits;
    char wintitle[sizeof(((Config *)0)->wintitle)];
    char icontitle[sizeof(((Config *)0)->wintitle)];
    int master_fd, master_func_id;
    void *ldisc;
    Backend *back;
    void *backhandle;
    Terminal *term;
    void *logctx;
    int exited;
    struct unicode_data ucsdata;
    Config cfg;
    void *eventlogstuff;
    char *progname, **gtkargvstart;
    int ngtkargs;
    guint32 input_event_time; /* Timestamp of the most recent input event. */
};

struct draw_ctx {
    GdkGC *gc;
    struct gui_data *inst;
};

static int send_raw_mouse;

static char *app_name = "pterm";

char *x_get_default(const char *key)
{
    return XGetDefault(GDK_DISPLAY(), app_name, key);
}

void connection_fatal(void *frontend, char *p, ...)
{
    struct gui_data *inst = (struct gui_data *)frontend;

    va_list ap;
    char *msg;
    va_start(ap, p);
    msg = dupvprintf(p, ap);
    va_end(ap);
    inst->exited = TRUE;
    fatal_message_box(inst->window, msg);
    sfree(msg);
    if (inst->cfg.close_on_exit == FORCE_ON)
        cleanup_exit(1);
}

/*
 * Default settings that are specific to pterm.
 */
FontSpec platform_default_fontspec(const char *name)
{
    FontSpec ret;
    if (!strcmp(name, "Font"))
	strcpy(ret.name, "fixed");
    else
	*ret.name = '\0';
    return ret;
}

Filename platform_default_filename(const char *name)
{
    Filename ret;
    if (!strcmp(name, "LogFileName"))
	strcpy(ret.path, "putty.log");
    else
	*ret.path = '\0';
    return ret;
}

char *platform_default_s(const char *name)
{
    return NULL;
}

int platform_default_i(const char *name, int def)
{
    if (!strcmp(name, "CloseOnExit"))
	return 2;  /* maps to FORCE_ON after painful rearrangement :-( */
    if (!strcmp(name, "WinNameAlways"))
	return 0;  /* X natively supports icon titles, so use 'em by default */
    return def;
}

void ldisc_update(void *frontend, int echo, int edit)
{
    /*
     * This is a stub in pterm. If I ever produce a Unix
     * command-line ssh/telnet/rlogin client (i.e. a port of plink)
     * then it will require some termios manoeuvring analogous to
     * that in the Windows plink.c, but here it's meaningless.
     */
}

int from_backend(void *frontend, int is_stderr, const char *data, int len)
{
    struct gui_data *inst = (struct gui_data *)frontend;
    return term_data(inst->term, is_stderr, data, len);
}

void logevent(void *frontend, const char *string)
{
    struct gui_data *inst = (struct gui_data *)frontend;

    log_eventlog(inst->logctx, string);

    logevent_dlg(inst->eventlogstuff, string);
}

int font_dimension(void *frontend, int which)/* 0 for width, 1 for height */
{
    struct gui_data *inst = (struct gui_data *)frontend;

    if (which)
	return inst->font_height;
    else
	return inst->font_width;
}

/*
 * Translate a raw mouse button designation (LEFT, MIDDLE, RIGHT)
 * into a cooked one (SELECT, EXTEND, PASTE).
 * 
 * In Unix, this is not configurable; the X button arrangement is
 * rock-solid across all applications, everyone has a three-button
 * mouse or a means of faking it, and there is no need to switch
 * buttons around at all.
 */
static Mouse_Button translate_button(Mouse_Button button)
{
    /* struct gui_data *inst = (struct gui_data *)frontend; */

    if (button == MBT_LEFT)
	return MBT_SELECT;
    if (button == MBT_MIDDLE)
	return MBT_PASTE;
    if (button == MBT_RIGHT)
	return MBT_EXTEND;
    return 0;			       /* shouldn't happen */
}

/*
 * Return the top-level GtkWindow associated with a particular
 * front end instance.
 */
void *get_window(void *frontend)
{
    struct gui_data *inst = (struct gui_data *)frontend;
    return inst->window;
}

/*
 * Minimise or restore the window in response to a server-side
 * request.
 */
void set_iconic(void *frontend, int iconic)
{
    /*
     * GTK 1.2 doesn't know how to do this.
     */
#if GTK_CHECK_VERSION(2,0,0)
    struct gui_data *inst = (struct gui_data *)frontend;
    if (iconic)
	gtk_window_iconify(GTK_WINDOW(inst->window));
    else
	gtk_window_deiconify(GTK_WINDOW(inst->window));
#endif
}

/*
 * Move the window in response to a server-side request.
 */
void move_window(void *frontend, int x, int y)
{
    struct gui_data *inst = (struct gui_data *)frontend;
    /*
     * I assume that when the GTK version of this call is available
     * we should use it. Not sure how it differs from the GDK one,
     * though.
     */
#if GTK_CHECK_VERSION(2,0,0)
    gtk_window_move(GTK_WINDOW(inst->window), x, y);
#else
    gdk_window_move(inst->window->window, x, y);
#endif
}

/*
 * Move the window to the top or bottom of the z-order in response
 * to a server-side request.
 */
void set_zorder(void *frontend, int top)
{
    struct gui_data *inst = (struct gui_data *)frontend;
    if (top)
	gdk_window_raise(inst->window->window);
    else
	gdk_window_lower(inst->window->window);
}

/*
 * Refresh the window in response to a server-side request.
 */
void refresh_window(void *frontend)
{
    struct gui_data *inst = (struct gui_data *)frontend;
    term_invalidate(inst->term);
}

/*
 * Maximise or restore the window in response to a server-side
 * request.
 */
void set_zoomed(void *frontend, int zoomed)
{
    /*
     * GTK 1.2 doesn't know how to do this.
     */
#if GTK_CHECK_VERSION(2,0,0)
    struct gui_data *inst = (struct gui_data *)frontend;
    if (iconic)
	gtk_window_maximize(GTK_WINDOW(inst->window));
    else
	gtk_window_unmaximize(GTK_WINDOW(inst->window));
#endif
}

/*
 * Report whether the window is iconic, for terminal reports.
 */
int is_iconic(void *frontend)
{
    struct gui_data *inst = (struct gui_data *)frontend;
    return !gdk_window_is_viewable(inst->window->window);
}

/*
 * Report the window's position, for terminal reports.
 */
void get_window_pos(void *frontend, int *x, int *y)
{
    struct gui_data *inst = (struct gui_data *)frontend;
    /*
     * I assume that when the GTK version of this call is available
     * we should use it. Not sure how it differs from the GDK one,
     * though.
     */
#if GTK_CHECK_VERSION(2,0,0)
    gtk_window_get_position(GTK_WINDOW(inst->window), x, y);
#else
    gdk_window_get_position(inst->window->window, x, y);
#endif
}

/*
 * Report the window's pixel size, for terminal reports.
 */
void get_window_pixels(void *frontend, int *x, int *y)
{
    struct gui_data *inst = (struct gui_data *)frontend;
    /*
     * I assume that when the GTK version of this call is available
     * we should use it. Not sure how it differs from the GDK one,
     * though.
     */
#if GTK_CHECK_VERSION(2,0,0)
    gtk_window_get_size(GTK_WINDOW(inst->window), x, y);
#else
    gdk_window_get_size(inst->window->window, x, y);
#endif
}

/*
 * Return the window or icon title.
 */
char *get_window_title(void *frontend, int icon)
{
    struct gui_data *inst = (struct gui_data *)frontend;
    return icon ? inst->icontitle : inst->wintitle;
}

gint delete_window(GtkWidget *widget, GdkEvent *event, gpointer data)
{
    struct gui_data *inst = (struct gui_data *)data;
    if (!inst->exited && inst->cfg.warn_on_close) {
	if (!reallyclose(inst))
	    return TRUE;
    }
    return FALSE;
}

static void show_mouseptr(struct gui_data *inst, int show)
{
    if (!inst->cfg.hide_mouseptr)
	show = 1;
    if (show)
	gdk_window_set_cursor(inst->area->window, inst->currcursor);
    else
	gdk_window_set_cursor(inst->area->window, inst->blankcursor);
    inst->mouseptr_visible = show;
}

void draw_backing_rect(struct gui_data *inst)
{
    GdkGC *gc = gdk_gc_new(inst->area->window);
    gdk_gc_set_foreground(gc, &inst->cols[18]);   /* default background */
    gdk_draw_rectangle(inst->pixmap, gc, 1, 0, 0,
		       inst->cfg.width * inst->font_width + 2*inst->cfg.window_border,
		       inst->cfg.height * inst->font_height + 2*inst->cfg.window_border);
    gdk_gc_unref(gc);
}

gint configure_area(GtkWidget *widget, GdkEventConfigure *event, gpointer data)
{
    struct gui_data *inst = (struct gui_data *)data;
    int w, h, need_size = 0;

    /*
     * See if the terminal size has changed, in which case we must
     * let the terminal know.
     */
    w = (event->width - 2*inst->cfg.window_border) / inst->font_width;
    h = (event->height - 2*inst->cfg.window_border) / inst->font_height;
    if (w != inst->width || h != inst->height) {
	inst->cfg.width = inst->width = w;
	inst->cfg.height = inst->height = h;
	need_size = 1;
    }

    if (inst->pixmap) {
	gdk_pixmap_unref(inst->pixmap);
	inst->pixmap = NULL;
    }

    inst->pixmap = gdk_pixmap_new(widget->window,
				  (inst->cfg.width * inst->font_width +
				   2*inst->cfg.window_border),
				  (inst->cfg.height * inst->font_height +
				   2*inst->cfg.window_border), -1);

    draw_backing_rect(inst);

    if (need_size && inst->term) {
	term_size(inst->term, h, w, inst->cfg.savelines);
    }

    if (inst->term)
	term_invalidate(inst->term);

    return TRUE;
}

gint expose_area(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
    struct gui_data *inst = (struct gui_data *)data;

    /*
     * Pass the exposed rectangle to terminal.c, which will call us
     * back to do the actual painting.
     */
    if (inst->pixmap) {
	gdk_draw_pixmap(widget->window,
			widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
			inst->pixmap,
			event->area.x, event->area.y,
			event->area.x, event->area.y,
			event->area.width, event->area.height);
    }
    return TRUE;
}

#define KEY_PRESSED(k) \
    (inst->keystate[(k) / 32] & (1 << ((k) % 32)))

gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -