mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
Selection now supported in pterm. Required small modifications
outside the unix subdir, owing to more things needing to become platform-dependent. [originally from svn r2033]
This commit is contained in:
parent
b65b4e36f5
commit
ffff6f32c7
1
putty.h
1
putty.h
@ -435,6 +435,7 @@ void modalfatalbox(char *, ...);
|
||||
void beep(int);
|
||||
void begin_session(void);
|
||||
void sys_cursor(int x, int y);
|
||||
void request_paste(void);
|
||||
#define OPTIMISE_IS_SCROLL 1
|
||||
|
||||
void set_iconic(int iconic);
|
||||
|
10
terminal.c
10
terminal.c
@ -3221,8 +3221,10 @@ static void clipme(pos top, pos bottom, int rect)
|
||||
top.y++;
|
||||
top.x = rect ? old_top_x : 0;
|
||||
}
|
||||
#if SELECTION_NUL_TERMINATED
|
||||
wblen++;
|
||||
*wbptr++ = 0;
|
||||
#endif
|
||||
write_clip(workbuf, wblen, FALSE); /* transfer to clipboard */
|
||||
if (buflen > 0) /* indicates we allocated this buffer */
|
||||
sfree(workbuf);
|
||||
@ -3686,8 +3688,12 @@ void term_mouse(Mouse_Button b, Mouse_Action a, int x, int y,
|
||||
} else
|
||||
selstate = NO_SELECTION;
|
||||
} else if (b == MBT_PASTE
|
||||
&& (a == MA_CLICK || a == MA_2CLK || a == MA_3CLK)) {
|
||||
term_do_paste();
|
||||
&& (a == MA_CLICK
|
||||
#if MULTICLICK_ONLY_EVENT
|
||||
|| a == MA_2CLK || a == MA_3CLK
|
||||
#endif
|
||||
)) {
|
||||
request_paste();
|
||||
}
|
||||
|
||||
term_update();
|
||||
|
152
unix/pterm.c
152
unix/pterm.c
@ -32,6 +32,10 @@ struct gui_data {
|
||||
GdkCursor *rawcursor, *textcursor;
|
||||
GdkColor cols[NCOLOURS];
|
||||
GdkColormap *colmap;
|
||||
wchar_t *pastein_data;
|
||||
int pastein_data_len;
|
||||
char *pasteout_data;
|
||||
int pasteout_data_len;
|
||||
int font_width, font_height;
|
||||
};
|
||||
|
||||
@ -616,6 +620,68 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gint button_event(GtkWidget *widget, GdkEventButton *event, gpointer data)
|
||||
{
|
||||
struct gui_data *inst = (struct gui_data *)data;
|
||||
int shift, ctrl, alt, x, y, button, act;
|
||||
|
||||
shift = event->state & GDK_SHIFT_MASK;
|
||||
ctrl = event->state & GDK_CONTROL_MASK;
|
||||
alt = event->state & GDK_MOD1_MASK;
|
||||
if (event->button == 1)
|
||||
button = MBT_LEFT;
|
||||
else if (event->button == 2)
|
||||
button = MBT_MIDDLE;
|
||||
else if (event->button == 3)
|
||||
button = MBT_RIGHT;
|
||||
else
|
||||
return FALSE; /* don't even know what button! */
|
||||
|
||||
switch (event->type) {
|
||||
case GDK_BUTTON_PRESS: act = MA_CLICK; break;
|
||||
case GDK_BUTTON_RELEASE: act = MA_RELEASE; break;
|
||||
case GDK_2BUTTON_PRESS: act = MA_2CLK; break;
|
||||
case GDK_3BUTTON_PRESS: act = MA_3CLK; break;
|
||||
default: return FALSE; /* don't know this event type */
|
||||
}
|
||||
|
||||
if (send_raw_mouse && !(cfg.mouse_override && shift) &&
|
||||
act != MA_CLICK && act != MA_RELEASE)
|
||||
return TRUE; /* we ignore these in raw mouse mode */
|
||||
|
||||
x = (event->x - cfg.window_border) / inst->font_width;
|
||||
y = (event->y - cfg.window_border) / inst->font_height;
|
||||
|
||||
term_mouse(button, act, x, y, shift, ctrl, alt);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gint motion_event(GtkWidget *widget, GdkEventMotion *event, gpointer data)
|
||||
{
|
||||
struct gui_data *inst = (struct gui_data *)data;
|
||||
int shift, ctrl, alt, x, y, button;
|
||||
|
||||
shift = event->state & GDK_SHIFT_MASK;
|
||||
ctrl = event->state & GDK_CONTROL_MASK;
|
||||
alt = event->state & GDK_MOD1_MASK;
|
||||
if (event->state & GDK_BUTTON1_MASK)
|
||||
button = MBT_LEFT;
|
||||
else if (event->state & GDK_BUTTON2_MASK)
|
||||
button = MBT_MIDDLE;
|
||||
else if (event->state & GDK_BUTTON3_MASK)
|
||||
button = MBT_RIGHT;
|
||||
else
|
||||
return FALSE; /* don't even know what button! */
|
||||
|
||||
x = (event->x - cfg.window_border) / inst->font_width;
|
||||
y = (event->y - cfg.window_border) / inst->font_height;
|
||||
|
||||
term_mouse(button, MA_DRAG, x, y, shift, ctrl, alt);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gint timer_func(gpointer data)
|
||||
{
|
||||
/* struct gui_data *inst = (struct gui_data *)data; */
|
||||
@ -692,15 +758,72 @@ void palette_reset(void)
|
||||
|
||||
void write_clip(wchar_t * data, int len, int must_deselect)
|
||||
{
|
||||
/* FIXME: currently ignored */
|
||||
if (inst->pasteout_data)
|
||||
sfree(inst->pasteout_data);
|
||||
inst->pasteout_data = smalloc(len);
|
||||
inst->pasteout_data_len = len;
|
||||
wc_to_mb(0, 0, data, len, inst->pasteout_data, inst->pasteout_data_len,
|
||||
NULL, NULL);
|
||||
|
||||
if (gtk_selection_owner_set(inst->area, GDK_SELECTION_PRIMARY,
|
||||
GDK_CURRENT_TIME)) {
|
||||
gtk_selection_add_target(inst->area, GDK_SELECTION_PRIMARY,
|
||||
GDK_SELECTION_TYPE_STRING, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void selection_get(GtkWidget *widget, GtkSelectionData *seldata,
|
||||
guint info, guint time_stamp, gpointer data)
|
||||
{
|
||||
gtk_selection_data_set(seldata, GDK_SELECTION_TYPE_STRING, 8,
|
||||
inst->pasteout_data, inst->pasteout_data_len);
|
||||
}
|
||||
|
||||
gint selection_clear(GtkWidget *widget, GdkEventSelection *seldata,
|
||||
gpointer data)
|
||||
{
|
||||
term_deselect();
|
||||
if (inst->pasteout_data)
|
||||
sfree(inst->pasteout_data);
|
||||
inst->pasteout_data = NULL;
|
||||
inst->pasteout_data_len = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void request_paste(void)
|
||||
{
|
||||
/*
|
||||
* In Unix, pasting is asynchronous: all we can do at the
|
||||
* moment is to call gtk_selection_convert(), and when the data
|
||||
* comes back _then_ we can call term_do_paste().
|
||||
*/
|
||||
gtk_selection_convert(inst->area, GDK_SELECTION_PRIMARY,
|
||||
GDK_SELECTION_TYPE_STRING, GDK_CURRENT_TIME);
|
||||
}
|
||||
|
||||
void selection_received(GtkWidget *widget, GtkSelectionData *seldata,
|
||||
gpointer data)
|
||||
{
|
||||
if (seldata->length <= 0 ||
|
||||
seldata->type != GDK_SELECTION_TYPE_STRING)
|
||||
return; /* Nothing happens. */
|
||||
|
||||
if (inst->pastein_data)
|
||||
sfree(inst->pastein_data);
|
||||
|
||||
inst->pastein_data = smalloc(seldata->length * sizeof(wchar_t));
|
||||
inst->pastein_data_len = seldata->length;
|
||||
mb_to_wc(0, 0, seldata->data, seldata->length,
|
||||
inst->pastein_data, inst->pastein_data_len);
|
||||
|
||||
term_do_paste();
|
||||
}
|
||||
|
||||
void get_clip(wchar_t ** p, int *len)
|
||||
{
|
||||
if (p) {
|
||||
/* FIXME: currently nonfunctional */
|
||||
*p = NULL;
|
||||
*len = 0;
|
||||
*p = inst->pastein_data;
|
||||
*len = inst->pastein_data_len;
|
||||
}
|
||||
}
|
||||
|
||||
@ -907,7 +1030,6 @@ int main(int argc, char **argv)
|
||||
gtk_box_pack_start(inst->hbox, inst->sbar, FALSE, FALSE, 0);
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(inst->hbox));
|
||||
// gtk_container_add(GTK_CONTAINER(window), inst->sbar);
|
||||
|
||||
{
|
||||
GdkGeometry geom;
|
||||
@ -922,10 +1044,6 @@ int main(int argc, char **argv)
|
||||
gtk_window_set_geometry_hints(GTK_WINDOW(window), inst->area, &geom,
|
||||
GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE |
|
||||
GDK_HINT_RESIZE_INC);
|
||||
// FIXME: base_width and base_height don't seem to work properly.
|
||||
// Wonder if this is because base of _zero_ is deprecated, and we
|
||||
// need a nonzero base size? Will it help if I put in the scrollbar?
|
||||
// FIXME also: the scrollbar is not working, find out why.
|
||||
}
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(window), "destroy",
|
||||
@ -942,12 +1060,26 @@ int main(int argc, char **argv)
|
||||
GTK_SIGNAL_FUNC(configure_area), inst);
|
||||
gtk_signal_connect(GTK_OBJECT(inst->area), "expose_event",
|
||||
GTK_SIGNAL_FUNC(expose_area), inst);
|
||||
gtk_signal_connect(GTK_OBJECT(inst->area), "button_press_event",
|
||||
GTK_SIGNAL_FUNC(button_event), inst);
|
||||
gtk_signal_connect(GTK_OBJECT(inst->area), "button_release_event",
|
||||
GTK_SIGNAL_FUNC(button_event), inst);
|
||||
gtk_signal_connect(GTK_OBJECT(inst->area), "motion_notify_event",
|
||||
GTK_SIGNAL_FUNC(motion_event), inst);
|
||||
gtk_signal_connect(GTK_OBJECT(inst->area), "selection_received",
|
||||
GTK_SIGNAL_FUNC(selection_received), inst);
|
||||
gtk_signal_connect(GTK_OBJECT(inst->area), "selection_get",
|
||||
GTK_SIGNAL_FUNC(selection_get), inst);
|
||||
gtk_signal_connect(GTK_OBJECT(inst->area), "selection_clear_event",
|
||||
GTK_SIGNAL_FUNC(selection_clear), inst);
|
||||
gtk_signal_connect(GTK_OBJECT(inst->sbar_adjust), "value_changed",
|
||||
GTK_SIGNAL_FUNC(scrollbar_moved), inst);
|
||||
gtk_timeout_add(20, timer_func, inst);
|
||||
gdk_input_add(pty_master_fd, GDK_INPUT_READ, pty_input_func, inst);
|
||||
gtk_widget_add_events(GTK_WIDGET(inst->area),
|
||||
GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
|
||||
GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |
|
||||
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
|
||||
GDK_BUTTON_MOTION_MASK);
|
||||
|
||||
gtk_widget_show(inst->area);
|
||||
gtk_widget_show(inst->sbar);
|
||||
|
13
unix/unix.h
13
unix/unix.h
@ -5,6 +5,17 @@ typedef void *Context; /* FIXME: probably needs changing */
|
||||
|
||||
extern Backend pty_backend;
|
||||
|
||||
/*
|
||||
* Under GTK, we send MA_CLICK _and_ MA_2CLK, or MA_CLICK _and_
|
||||
* MA_3CLK, when a button is pressed for the second or third time.
|
||||
*/
|
||||
#define MULTICLICK_ONLY_EVENT 0
|
||||
|
||||
/*
|
||||
* Under X, selection data must not be NUL-terminated.
|
||||
*/
|
||||
#define SELECTION_NUL_TERMINATED 0
|
||||
|
||||
/* Simple wraparound timer function */
|
||||
unsigned long getticks(void); /* based on gettimeofday(2) */
|
||||
#define GETTICKCOUNT getticks
|
||||
@ -17,6 +28,8 @@ unsigned long getticks(void); /* based on gettimeofday(2) */
|
||||
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);
|
||||
int wc_to_mb(int codepage, int flags, wchar_t *wcstr, int wclen,
|
||||
char *mbstr, int mblen, char *defchr, int *defused);
|
||||
void init_ucs(void);
|
||||
|
||||
#define DEFAULT_CODEPAGE 0 /* FIXME: no idea how to do this */
|
||||
|
24
unix/uxucs.c
24
unix/uxucs.c
@ -92,7 +92,29 @@ int mb_to_wc(int codepage, int flags, char *mbstr, int mblen,
|
||||
int ret = 0;
|
||||
while (mblen > 0 && wclen > 0) {
|
||||
*wcstr++ = (unsigned char) *mbstr++;
|
||||
ret++;
|
||||
mblen--, wclen--, ret++;
|
||||
}
|
||||
return ret; /* FIXME: check error codes! */
|
||||
}
|
||||
|
||||
int wc_to_mb(int codepage, int flags, wchar_t *wcstr, int wclen,
|
||||
char *mbstr, int mblen, char *defchr, int *defused)
|
||||
{
|
||||
int ret = 0;
|
||||
if (defused)
|
||||
*defused = 0;
|
||||
while (mblen > 0 && wclen > 0) {
|
||||
if (*wcstr >= 0x100) {
|
||||
if (defchr)
|
||||
*mbstr++ = *defchr;
|
||||
else
|
||||
*mbstr++ = '\xBF';
|
||||
if (defused)
|
||||
*defused = 1;
|
||||
} else
|
||||
*mbstr++ = (unsigned char) *wcstr;
|
||||
wcstr++;
|
||||
mblen--, wclen--, ret++;
|
||||
}
|
||||
return ret; /* FIXME: check error codes! */
|
||||
}
|
||||
|
10
window.c
10
window.c
@ -3817,6 +3817,16 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
|
||||
return -1;
|
||||
}
|
||||
|
||||
void request_paste(void)
|
||||
{
|
||||
/*
|
||||
* In Windows, pasting is synchronous: we can read the
|
||||
* clipboard with no difficulty, so request_paste() can just go
|
||||
* ahead and paste.
|
||||
*/
|
||||
term_do_paste();
|
||||
}
|
||||
|
||||
void set_title(char *title)
|
||||
{
|
||||
sfree(window_name);
|
||||
|
11
winstuff.h
11
winstuff.h
@ -53,6 +53,17 @@ GLOBAL HINSTANCE hinst;
|
||||
#define WM_XUSER (WM_USER + 0x2000)
|
||||
#define WM_NETEVENT (WM_XUSER + 5)
|
||||
|
||||
/*
|
||||
* On Windows, we send MA_2CLK as the only event marking the second
|
||||
* press of a mouse button. Compare unix.h.
|
||||
*/
|
||||
#define MULTICLICK_ONLY_EVENT 1
|
||||
|
||||
/*
|
||||
* On Windows, data written to the clipboard must be NUL-terminated.
|
||||
*/
|
||||
#define SELECTION_NUL_TERMINATED 1
|
||||
|
||||
/*
|
||||
* Exports from winctrls.c.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user