1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-06-30 11:02:48 -05:00

First phase of porting. pterm now compiles and runs under Linux+gtk.

The current pty.c backend is temporarily a loopback device for
terminal emulator testing, the display handling is only just enough
to show that terminal.c is functioning, the keyboard handling is
laughable, and most features are absent. Next step: bring output and
input up to a plausibly working state, and put a real pty on the
back to create a vaguely usable prototype. Oh, and a scrollbar would
be nice too.
In _theory_ the Windows builds should still work fine after this...

[originally from svn r2010]
This commit is contained in:
Simon Tatham
2002-10-09 18:09:42 +00:00
parent 268213483c
commit 6d0e9b205d
24 changed files with 774 additions and 56 deletions

View File

@ -5,14 +5,137 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <gtk/gtk.h>
#define PUTTY_DO_GLOBALS /* actually _define_ globals */
#include "putty.h"
#define CAT2(x,y) x ## y
#define CAT(x,y) CAT2(x,y)
#define ASSERT(x) enum {CAT(assertion_,__LINE__) = 1 / (x)}
#define lenof(x) (sizeof((x))/sizeof(*(x)))
void ldisc_update(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 askappend(char *filename)
{
/*
* FIXME: for the moment we just wipe the log file. Since I
* haven't yet enabled logging, this shouldn't matter yet!
*/
return 2;
}
void logevent(char *string)
{
/*
* FIXME: event log entries are currently ignored.
*/
}
/*
* 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.
*/
Mouse_Button translate_button(Mouse_Button button)
{
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 */
}
/*
* Minimise or restore the window in response to a server-side
* request.
*/
void set_iconic(int iconic)
{
/* FIXME: currently ignored */
}
/*
* Move the window in response to a server-side request.
*/
void move_window(int x, int y)
{
/* FIXME: currently ignored */
}
/*
* Move the window to the top or bottom of the z-order in response
* to a server-side request.
*/
void set_zorder(int top)
{
/* FIXME: currently ignored */
}
/*
* Refresh the window in response to a server-side request.
*/
void refresh_window(void)
{
/* FIXME: currently ignored */
}
/*
* Maximise or restore the window in response to a server-side
* request.
*/
void set_zoomed(int zoomed)
{
/* FIXME: currently ignored */
}
/*
* Report whether the window is iconic, for terminal reports.
*/
int is_iconic(void)
{
return 0; /* FIXME */
}
/*
* Report the window's position, for terminal reports.
*/
void get_window_pos(int *x, int *y)
{
*x = 3; *y = 4; /* FIXME */
}
/*
* Report the window's pixel size, for terminal reports.
*/
void get_window_pixels(int *x, int *y)
{
*x = 1; *y = 2; /* FIXME */
}
/*
* Return the window or icon title.
*/
char *get_window_title(int icon)
{
return "FIXME: window title retrieval not yet implemented";
}
struct gui_data {
GtkWidget *area;
@ -20,6 +143,9 @@ struct gui_data {
GdkGC *black_gc, *white_gc;
};
static struct gui_data the_inst;
static struct gui_data *inst = &the_inst; /* so we always write `inst->' */
gint delete_window(GtkWidget *widget, GdkEvent *event, gpointer data)
{
/*
@ -86,13 +212,17 @@ gint configure_area(GtkWidget *widget, GdkEventConfigure *event, gpointer data)
gint expose_area(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
struct gui_data *inst = (struct gui_data *)data;
/* struct gui_data *inst = (struct gui_data *)data; */
/*
* FIXME: pass the exposed rect to terminal.c which will call
* us back to do the actual painting.
* Pass the exposed rectangle to terminal.c, which will call us
* back to do the actual painting.
*/
return FALSE;
term_paint(NULL,
event->area.x / 9, event->area.y / 15,
(event->area.x + event->area.width - 1) / 9,
(event->area.y + event->area.height - 1) / 15);
return TRUE;
}
#define KEY_PRESSED(k) \
@ -100,20 +230,23 @@ gint expose_area(GtkWidget *widget, GdkEventExpose *event, gpointer data)
gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
{
struct gui_data *inst = (struct gui_data *)data;
/* struct gui_data *inst = (struct gui_data *)data; */
/*
* FIXME: all sorts of fun keyboard handling required here.
*/
if (event->type == GDK_KEY_PRESS) {
char c[1];
c[0] = event->keyval;
ldisc_send(c, 1, 1);
term_out();
}
return TRUE;
}
gint timer_func(gpointer data)
{
struct gui_data *inst = (struct gui_data *)data;
/* struct gui_data *inst = (struct gui_data *)data; */
/*
* FIXME: we're bound to need this sooner or later!
*/
term_update();
return TRUE;
}
@ -127,16 +260,150 @@ gint focus_event(GtkWidget *widget, GdkEventFocus *event, gpointer data)
/*
* FIXME: need to faff with the cursor shape.
*/
return FALSE;
}
/*
* set or clear the "raw mouse message" mode
*/
void set_raw_mouse_mode(int activate)
{
/* FIXME: currently ignored */
}
void request_resize(int w, int h)
{
/* FIXME: currently ignored */
}
void palette_set(int n, int r, int g, int b)
{
/* FIXME: currently ignored */
}
void palette_reset(void)
{
/* FIXME: currently ignored */
}
void write_clip(wchar_t * data, int len, int must_deselect)
{
/* FIXME: currently ignored */
}
void get_clip(wchar_t ** p, int *len)
{
if (p) {
/* FIXME: currently nonfunctional */
*p = NULL;
*len = 0;
}
}
void set_title(char *title)
{
/* FIXME: currently ignored */
}
void set_icon(char *title)
{
/* FIXME: currently ignored */
}
void set_sbar(int total, int start, int page)
{
/* FIXME: currently ignored */
}
void sys_cursor(int x, int y)
{
/*
* This is meaningless under X.
*/
}
void beep(int mode)
{
gdk_beep();
}
int CharWidth(Context ctx, int uc)
{
/*
* Under X, any fixed-width font really _is_ fixed-width.
* Double-width characters will be dealt with using a separate
* font. For the moment we can simply return 1.
*/
return 1;
}
Context get_ctx(void)
{
GdkGC *gc = gdk_gc_new(inst->area->window);
return gc;
}
void free_ctx(Context ctx)
{
GdkGC *gc = (GdkGC *)ctx;
gdk_gc_unref(gc);
}
/*
* Draw a line of text in the window, at given character
* coordinates, in given attributes.
*
* We are allowed to fiddle with the contents of `text'.
*/
void do_text(Context ctx, int x, int y, char *text, int len,
unsigned long attr, int lattr)
{
GdkColor fg, bg;
GdkGC *gc = (GdkGC *)ctx;
fg.red = fg.green = fg.blue = 65535;
bg.red = bg.green = bg.blue = 65535;
gdk_gc_set_foreground(gc, &fg);
gdk_gc_set_background(gc, &bg);
gdk_draw_text(inst->area->window, inst->fonts[0], inst->white_gc,
x*9, y*15 + inst->fonts[0]->ascent, text, len);
}
void do_cursor(Context ctx, int x, int y, char *text, int len,
unsigned long attr, int lattr)
{
/* FIXME: passive cursor NYI */
if (attr & TATTR_PASCURS) {
attr &= ~TATTR_PASCURS;
attr |= TATTR_ACTCURS;
}
do_text(ctx, x, y, text, len, attr, lattr);
}
void modalfatalbox(char *p, ...)
{
va_list ap;
fprintf(stderr, "FATAL ERROR: ");
va_start(ap, p);
vfprintf(stderr, p, ap);
va_end(ap);
fputc('\n', stderr);
exit(1);
}
int main(int argc, char **argv)
{
GtkWidget *window;
struct gui_data the_inst;
struct gui_data *inst = &the_inst; /* so we always write `inst->' */
gtk_init(&argc, &argv);
do_defaults(NULL, &cfg);
init_ucs();
back = &pty_backend;
back->init(NULL, 0, NULL, 0);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
inst->area = gtk_drawing_area_new();
gtk_drawing_area_size(GTK_DRAWING_AREA(inst->area),
@ -167,6 +434,9 @@ int main(int argc, char **argv)
gtk_widget_show(inst->area);
gtk_widget_show(window);
term_init();
term_size(24, 80, 2000);
gtk_main();
return 0;

107
unix/pty.c Normal file
View File

@ -0,0 +1,107 @@
#include <stdio.h>
#include <stdlib.h>
#include "putty.h"
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
static void pty_size(void);
static void c_write(char *buf, int len)
{
from_backend(0, buf, len);
}
/*
* Called to set up the pty.
*
* Returns an error message, or NULL on success.
*
* Also places the canonical host name into `realhost'. It must be
* freed by the caller.
*/
static char *pty_init(char *host, int port, char **realhost, int nodelay)
{
/* FIXME: do nothing for now */
return NULL;
}
/*
* Called to send data down the pty.
*/
static int pty_send(char *buf, int len)
{
c_write(buf, len); /* FIXME: diagnostic thingy */
return 0;
}
/*
* Called to query the current socket sendability status.
*/
static int pty_sendbuffer(void)
{
return 0;
}
/*
* Called to set the size of the window
*/
static void pty_size(void)
{
/* FIXME: will need to do TIOCSWINSZ or whatever. */
return;
}
/*
* Send special codes.
*/
static void pty_special(Telnet_Special code)
{
/* Do nothing! */
return;
}
static Socket pty_socket(void)
{
return NULL; /* shouldn't ever be needed */
}
static int pty_sendok(void)
{
return 1;
}
static void pty_unthrottle(int backlog)
{
/* do nothing */
}
static int pty_ldisc(int option)
{
return 0; /* neither editing nor echoing */
}
static int pty_exitcode(void)
{
/* Shouldn't ever be required */
return 0;
}
Backend pty_backend = {
pty_init,
pty_send,
pty_sendbuffer,
pty_size,
pty_special,
pty_socket,
pty_exitcode,
pty_sendok,
pty_ldisc,
pty_unthrottle,
1
};

View File

@ -3,6 +3,8 @@
typedef void *Context; /* FIXME: probably needs changing */
extern Backend pty_backend;
/* Simple wraparound timer function */
unsigned long getticks(void); /* based on gettimeofday(2) */
#define GETTICKCOUNT getticks
@ -12,6 +14,10 @@ unsigned long getticks(void); /* based on gettimeofday(2) */
#define WCHAR wchar_t
#define BYTE unsigned char
int is_dbcs_leadbyte(int codepage, char byte);
int mb_to_wc(int codepage, int flags, char *mbstr, int mblen,
wchar_t *wcstr, int wclen);
void init_ucs(void);
#define DEFAULT_CODEPAGE 0 /* FIXME: no idea how to do this */

24
unix/uxprint.c Normal file
View File

@ -0,0 +1,24 @@
/*
* Printing interface for PuTTY.
*/
#include <assert.h>
#include "putty.h"
printer_job *printer_start_job(char *printer)
{
/* FIXME: open pipe to lpr */
return NULL;
}
void printer_job_data(printer_job *pj, void *data, int len)
{
/* FIXME: receive a pipe to lpr, write things to it */
assert(!"We shouldn't get here");
}
void printer_finish_job(printer_job *pj)
{
/* FIXME: receive a pipe to lpr, close it */
assert(!"We shouldn't get here either");
}

86
unix/uxstore.c Normal file
View File

@ -0,0 +1,86 @@
/*
* uxstore.c: Unix-specific implementation of the interface defined
* in storage.h.
*/
#include <stdio.h>
#include <stdlib.h>
#include "putty.h"
#include "storage.h"
/* FIXME. For the moment, we do nothing at all here. */
void *open_settings_w(char *sessionname)
{
return NULL;
}
void write_setting_s(void *handle, char *key, char *value)
{
}
void write_setting_i(void *handle, char *key, int value)
{
}
void close_settings_w(void *handle)
{
}
void *open_settings_r(char *sessionname)
{
return NULL;
}
char *read_setting_s(void *handle, char *key, char *buffer, int buflen)
{
return NULL;
}
int read_setting_i(void *handle, char *key, int defvalue)
{
return defvalue;
}
void close_settings_r(void *handle)
{
}
void del_settings(char *sessionname)
{
}
void *enum_settings_start(void)
{
return NULL;
}
char *enum_settings_next(void *handle, char *buffer, int buflen)
{
return NULL;
}
void enum_settings_finish(void *handle)
{
}
int verify_host_key(char *hostname, int port, char *keytype, char *key)
{
return 1; /* key does not exist in registry */
}
void store_host_key(char *hostname, int port, char *keytype, char *key)
{
}
void read_random_seed(noise_consumer_t consumer)
{
}
void write_random_seed(void *data, int len)
{
}
void cleanup_all(void)
{
}

114
unix/uxucs.c Normal file
View File

@ -0,0 +1,114 @@
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#include "putty.h"
#include "misc.h"
/*
* Unix Unicode-handling routines.
*
* FIXME: currently trivial stub versions assuming all codepages
* are ISO8859-1.
*/
void lpage_send(int codepage, char *buf, int len, int interactive)
{
ldisc_send(buf, len, interactive);
}
void luni_send(wchar_t * widebuf, int len, int interactive)
{
static char *linebuffer = 0;
static int linesize = 0;
int ratio = (in_utf)?6:1;
int i;
char *p;
if (len * ratio > linesize) {
sfree(linebuffer);
linebuffer = smalloc(len * ratio * 2 * sizeof(wchar_t));
linesize = len * ratio * 2;
}
if (in_utf) {
/* UTF is a simple algorithm */
for (p = linebuffer, i = 0; i < len; i++) {
wchar_t ch = widebuf[i];
if ((ch&0xF800) == 0xD800) ch = '.';
if (ch < 0x80) {
*p++ = (char) (ch);
} else if (ch < 0x800) {
*p++ = (0xC0 | (ch >> 6));
*p++ = (0x80 | (ch & 0x3F));
} else if (ch < 0x10000) {
*p++ = (0xE0 | (ch >> 12));
*p++ = (0x80 | ((ch >> 6) & 0x3F));
*p++ = (0x80 | (ch & 0x3F));
} else if (ch < 0x200000) {
*p++ = (0xF0 | (ch >> 18));
*p++ = (0x80 | ((ch >> 12) & 0x3F));
*p++ = (0x80 | ((ch >> 6) & 0x3F));
*p++ = (0x80 | (ch & 0x3F));
} else if (ch < 0x4000000) {
*p++ = (0xF8 | (ch >> 24));
*p++ = (0x80 | ((ch >> 18) & 0x3F));
*p++ = (0x80 | ((ch >> 12) & 0x3F));
*p++ = (0x80 | ((ch >> 6) & 0x3F));
*p++ = (0x80 | (ch & 0x3F));
} else {
*p++ = (0xFC | (ch >> 30));
*p++ = (0x80 | ((ch >> 24) & 0x3F));
*p++ = (0x80 | ((ch >> 18) & 0x3F));
*p++ = (0x80 | ((ch >> 12) & 0x3F));
*p++ = (0x80 | ((ch >> 6) & 0x3F));
*p++ = (0x80 | (ch & 0x3F));
}
}
} else {
for (p = linebuffer, i = 0; i < len; i++) {
wchar_t ch = widebuf[i];
if (ch < 0x100)
*p++ = (char) ch;
else
*p++ = '.';
}
}
if (p > linebuffer)
ldisc_send(linebuffer, p - linebuffer, interactive);
}
int is_dbcs_leadbyte(int codepage, char byte)
{
return 0; /* we don't do DBCS */
}
int mb_to_wc(int codepage, int flags, char *mbstr, int mblen,
wchar_t *wcstr, int wclen)
{
int ret = 0;
while (mblen > 0 && wclen > 0) {
*wcstr++ = (unsigned char) *mbstr++;
ret++;
}
return ret; /* FIXME: check error codes! */
}
void init_ucs(void)
{
int i;
/* Find the line control characters. FIXME: this is not right. */
for (i = 0; i < 256; i++)
if (i < ' ' || (i >= 0x7F && i < 0xA0))
unitab_ctrl[i] = i;
else
unitab_ctrl[i] = 0xFF;
for (i = 0; i < 256; i++) {
unitab_line[i] = unitab_scoacs[i] = i;
unitab_xterm[i] = i & 0x1F;
}
}