📄 gtkwin.c
字号:
case GDK_Home: case GDK_KP_Home:
code = 1;
break;
case GDK_Insert: case GDK_KP_Insert:
code = 2;
break;
case GDK_Delete: case GDK_KP_Delete:
code = 3;
break;
case GDK_End: case GDK_KP_End:
code = 4;
break;
case GDK_Page_Up: case GDK_KP_Page_Up:
code = 5;
break;
case GDK_Page_Down: case GDK_KP_Page_Down:
code = 6;
break;
}
/* Reorder edit keys to physical order */
if (inst->cfg.funky_type == FUNKY_VT400 && code <= 6)
code = "\0\2\1\4\5\3\6"[code];
if (inst->term->vt52_mode && code > 0 && code <= 6) {
end = 1 + sprintf(output+1, "\x1B%c", " HLMEIG"[code]);
use_ucsoutput = FALSE;
goto done;
}
if (inst->cfg.funky_type == FUNKY_SCO && /* SCO function keys */
code >= 11 && code <= 34) {
char codes[] = "MNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@[\\]^_`{";
int index = 0;
switch (event->keyval) {
case GDK_F1: index = 0; break;
case GDK_F2: index = 1; break;
case GDK_F3: index = 2; break;
case GDK_F4: index = 3; break;
case GDK_F5: index = 4; break;
case GDK_F6: index = 5; break;
case GDK_F7: index = 6; break;
case GDK_F8: index = 7; break;
case GDK_F9: index = 8; break;
case GDK_F10: index = 9; break;
case GDK_F11: index = 10; break;
case GDK_F12: index = 11; break;
}
if (event->state & GDK_SHIFT_MASK) index += 12;
if (event->state & GDK_CONTROL_MASK) index += 24;
end = 1 + sprintf(output+1, "\x1B[%c", codes[index]);
use_ucsoutput = FALSE;
goto done;
}
if (inst->cfg.funky_type == FUNKY_SCO && /* SCO small keypad */
code >= 1 && code <= 6) {
char codes[] = "HL.FIG";
if (code == 3) {
output[1] = '\x7F';
end = 2;
} else {
end = 1 + sprintf(output+1, "\x1B[%c", codes[code-1]);
}
use_ucsoutput = FALSE;
goto done;
}
if ((inst->term->vt52_mode || inst->cfg.funky_type == FUNKY_VT100P) &&
code >= 11 && code <= 24) {
int offt = 0;
if (code > 15)
offt++;
if (code > 21)
offt++;
if (inst->term->vt52_mode)
end = 1 + sprintf(output+1,
"\x1B%c", code + 'P' - 11 - offt);
else
end = 1 + sprintf(output+1,
"\x1BO%c", code + 'P' - 11 - offt);
use_ucsoutput = FALSE;
goto done;
}
if (inst->cfg.funky_type == FUNKY_LINUX && code >= 11 && code <= 15) {
end = 1 + sprintf(output+1, "\x1B[[%c", code + 'A' - 11);
use_ucsoutput = FALSE;
goto done;
}
if (inst->cfg.funky_type == FUNKY_XTERM && code >= 11 && code <= 14) {
if (inst->term->vt52_mode)
end = 1 + sprintf(output+1, "\x1B%c", code + 'P' - 11);
else
end = 1 + sprintf(output+1, "\x1BO%c", code + 'P' - 11);
use_ucsoutput = FALSE;
goto done;
}
if (inst->cfg.rxvt_homeend && (code == 1 || code == 4)) {
end = 1 + sprintf(output+1, code == 1 ? "\x1B[H" : "\x1BOw");
use_ucsoutput = FALSE;
goto done;
}
if (code) {
end = 1 + sprintf(output+1, "\x1B[%d~", code);
use_ucsoutput = FALSE;
goto done;
}
}
/*
* Cursor keys. (This includes the numberpad cursor keys,
* if we haven't already done them due to app keypad mode.)
*
* Here we also process un-numlocked un-appkeypadded KP5,
* which sends ESC [ G.
*/
{
int xkey = 0;
switch (event->keyval) {
case GDK_Up: case GDK_KP_Up: xkey = 'A'; break;
case GDK_Down: case GDK_KP_Down: xkey = 'B'; break;
case GDK_Right: case GDK_KP_Right: xkey = 'C'; break;
case GDK_Left: case GDK_KP_Left: xkey = 'D'; break;
case GDK_Begin: case GDK_KP_Begin: xkey = 'G'; break;
}
if (xkey) {
/*
* The arrow keys normally do ESC [ A and so on. In
* app cursor keys mode they do ESC O A instead.
* Ctrl toggles the two modes.
*/
if (inst->term->vt52_mode) {
end = 1 + sprintf(output+1, "\033%c", xkey);
} else if (!inst->term->app_cursor_keys ^
!(event->state & GDK_CONTROL_MASK)) {
end = 1 + sprintf(output+1, "\033O%c", xkey);
} else {
end = 1 + sprintf(output+1, "\033[%c", xkey);
}
use_ucsoutput = FALSE;
goto done;
}
}
goto done;
}
done:
if (end-start > 0) {
#ifdef KEY_DEBUGGING
int i;
printf("generating sequence:");
for (i = start; i < end; i++)
printf(" %02x", (unsigned char) output[i]);
printf("\n");
#endif
if (special) {
/*
* For special control characters, the character set
* should never matter.
*/
output[end] = '\0'; /* NUL-terminate */
if (inst->ldisc)
ldisc_send(inst->ldisc, output+start, -2, 1);
} else if (!inst->direct_to_font) {
if (!use_ucsoutput) {
/*
* The stuff we've just generated is assumed to be
* ISO-8859-1! This sounds insane, but `man
* XLookupString' agrees: strings of this type
* returned from the X server are hardcoded to
* 8859-1. Strictly speaking we should be doing
* this using some sort of GtkIMContext, which (if
* we're lucky) would give us our data directly in
* Unicode; but that's not supported in GTK 1.2 as
* far as I can tell, and it's poorly documented
* even in 2.0, so it'll have to wait.
*/
if (inst->ldisc)
lpage_send(inst->ldisc, CS_ISO8859_1, output+start,
end-start, 1);
} else {
/*
* We generated our own Unicode key data from the
* keysym, so use that instead.
*/
if (inst->ldisc)
luni_send(inst->ldisc, ucsoutput+start, end-start, 1);
}
} else {
/*
* In direct-to-font mode, we just send the string
* exactly as we received it.
*/
if (inst->ldisc)
ldisc_send(inst->ldisc, output+start, end-start, 1);
}
show_mouseptr(inst, 0);
term_seen_key_event(inst->term);
}
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;
/* Remember the timestamp. */
inst->input_event_time = event->time;
show_mouseptr(inst, 1);
if (event->button == 4 && event->type == GDK_BUTTON_PRESS) {
term_scroll(inst->term, 0, -5);
return TRUE;
}
if (event->button == 5 && event->type == GDK_BUTTON_PRESS) {
term_scroll(inst->term, 0, +5);
return TRUE;
}
shift = event->state & GDK_SHIFT_MASK;
ctrl = event->state & GDK_CONTROL_MASK;
alt = event->state & GDK_MOD1_MASK;
if (event->button == 3 && ctrl) {
gtk_menu_popup(GTK_MENU(inst->menu), NULL, NULL, NULL, NULL,
event->button, event->time);
return TRUE;
}
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 && !(inst->cfg.mouse_override && shift) &&
act != MA_CLICK && act != MA_RELEASE)
return TRUE; /* we ignore these in raw mouse mode */
x = (event->x - inst->cfg.window_border) / inst->font_width;
y = (event->y - inst->cfg.window_border) / inst->font_height;
term_mouse(inst->term, button, translate_button(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;
/* Remember the timestamp. */
inst->input_event_time = event->time;
show_mouseptr(inst, 1);
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 - inst->cfg.window_border) / inst->font_width;
y = (event->y - inst->cfg.window_border) / inst->font_height;
term_mouse(inst->term, button, translate_button(button), MA_DRAG,
x, y, shift, ctrl, alt);
return TRUE;
}
void frontend_keypress(void *handle)
{
struct gui_data *inst = (struct gui_data *)handle;
/*
* If our child process has exited but not closed, terminate on
* any keypress.
*/
if (inst->exited)
exit(0);
}
void notify_remote_exit(void *frontend)
{
struct gui_data *inst = (struct gui_data *)frontend;
int exitcode;
if (!inst->exited &&
(exitcode = inst->back->exitcode(inst->backhandle)) >= 0) {
inst->exited = TRUE;
if (inst->cfg.close_on_exit == FORCE_ON ||
(inst->cfg.close_on_exit == AUTO && exitcode == 0))
gtk_main_quit(); /* just go */
if (inst->ldisc) {
ldisc_free(inst->ldisc);
inst->ldisc = NULL;
}
if (inst->back) {
inst->back->free(inst->backhandle);
inst->backhandle = NULL;
inst->back = NULL;
term_provide_resize_fn(inst->term, NULL, NULL);
update_specials_menu(inst);
}
gtk_widget_show(inst->restartitem);
}
}
static gint timer_trigger(gpointer data)
{
long now = GPOINTER_TO_INT(data);
long next;
long ticks;
if (run_timers(now, &next)) {
ticks = next - GETTICKCOUNT();
timer_id = gtk_timeout_add(ticks > 0 ? ticks : 1, timer_trigger,
GINT_TO_POINTER(next));
}
/*
* Never let a timer resume. If we need another one, we've
* asked for it explicitly above.
*/
return FALSE;
}
void timer_change_notify(long next)
{
long ticks;
if (timer_id)
gtk_timeout_remove(timer_id);
ticks = next - GETTICKCOUNT();
if (ticks <= 0)
ticks = 1; /* just in case */
timer_id = gtk_timeout_add(ticks, timer_trigger,
GINT_TO_POINTER(next));
}
void fd_input_func(gpointer data, gint sourcefd, GdkInputCondition condition)
{
/*
* We must process exceptional notifications before ordinary
* readability ones, or we may go straight past the urgent
* marker.
*/
if (condition & GDK_INPUT_EXCEPTION)
select_result(sourcefd, 4);
if (condition & GDK_INPUT_READ)
select_result(sourcefd, 1);
if (condition & GDK_INPUT_WRITE)
select_result(sourcefd, 2);
}
void destroy(GtkWidget *widget, gpointer data)
{
gtk_main_quit();
}
gint focus_event(GtkWidget *widget, GdkEventFocus *event, gpointer data)
{
struct gui_data *inst = (struct gui_data *)data;
term_set_focus(inst->term, event->in);
term_update(inst->term);
show_mouseptr(inst, 1);
return FALSE;
}
void set_busy_status(void *frontend, int status)
{
struct gui_data *inst = (struct gui_data *)frontend;
inst->busy_status = status;
update_mouseptr(inst);
}
/*
* set or clear the "raw mouse message" mode
*/
void set_raw_mouse_mode(void *frontend, int activate)
{
struct gui_data *inst = (struct gui_data *)frontend;
activate = activate && !inst->cfg.no_mouse_rep;
send_raw_mouse = activate;
update_mouseptr(inst);
}
void request_resize(void *frontend, int w, int h)
{
struct gui_data *inst = (struct gui_data *)frontend;
int large_x, large_y;
int offset_x, offset_y;
int area_x, area_y;
GtkRequisition inner, outer;
/*
* This is a heinous hack dreamed up by the gnome-terminal
* people to get around a limitation in gtk. The problem is
* that in order to set the size correctly we really need to be
* calling gtk_window_resize - but that needs to know the size
* of the _whole window_, not the drawing area. So what we do
* is to set an artificially huge size request on the drawing
* area, recompute the resulting size request on the window,
* and look at the difference between the two. That gives us
* the x and y offsets we need to translate drawing area size
* into window size for real, and then we call
* gtk_window_resize.
*/
/*
* We start by retrieving the current size of the whole window.
* Adding a bit to _that_ will give us a value we can use as a
* bogus size request which guarantees to be bigger than the
* current size of the drawing area.
*/
get_window_pixels(inst, &large_x, &large_y);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -