📄 pterm.c
字号:
/* Ensure that all the cut buffers exist - according to the ICCCM, we must
* do this before we start using cut buffers.
*/
void init_cutbuffers()
{
XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
XA_CUT_BUFFER0, XA_STRING, 8, PropModeAppend, "", 0);
XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
XA_CUT_BUFFER1, XA_STRING, 8, PropModeAppend, "", 0);
XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
XA_CUT_BUFFER2, XA_STRING, 8, PropModeAppend, "", 0);
XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
XA_CUT_BUFFER3, XA_STRING, 8, PropModeAppend, "", 0);
XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
XA_CUT_BUFFER4, XA_STRING, 8, PropModeAppend, "", 0);
XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
XA_CUT_BUFFER5, XA_STRING, 8, PropModeAppend, "", 0);
XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
XA_CUT_BUFFER6, XA_STRING, 8, PropModeAppend, "", 0);
XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
XA_CUT_BUFFER7, XA_STRING, 8, PropModeAppend, "", 0);
}
/* Store the data in a cut-buffer. */
void store_cutbuffer(char * ptr, int len)
{
/* ICCCM says we must rotate the buffers before storing to buffer 0. */
XRotateBuffers(GDK_DISPLAY(), 1);
XStoreBytes(GDK_DISPLAY(), ptr, len);
}
/* Retrieve data from a cut-buffer.
* Returned data needs to be freed with XFree().
*/
char * retrieve_cutbuffer(int * nbytes)
{
char * ptr;
ptr = XFetchBytes(GDK_DISPLAY(), nbytes);
if (*nbytes <= 0 && ptr != 0) {
XFree(ptr);
ptr = 0;
}
return ptr;
}
void write_clip(void *frontend, wchar_t * data, int len, int must_deselect)
{
struct gui_data *inst = (struct gui_data *)frontend;
if (inst->pasteout_data)
sfree(inst->pasteout_data);
if (inst->pasteout_data_ctext)
sfree(inst->pasteout_data_ctext);
if (inst->pasteout_data_utf8)
sfree(inst->pasteout_data_utf8);
/*
* Set up UTF-8 and compound text paste data. This only happens
* if we aren't in direct-to-font mode using the D800 hack.
*/
if (!inst->direct_to_font) {
wchar_t *tmp = data;
int tmplen = len;
XTextProperty tp;
char *list[1];
inst->pasteout_data_utf8 = snewn(len*6, char);
inst->pasteout_data_utf8_len = len*6;
inst->pasteout_data_utf8_len =
charset_from_unicode(&tmp, &tmplen, inst->pasteout_data_utf8,
inst->pasteout_data_utf8_len,
CS_UTF8, NULL, NULL, 0);
if (inst->pasteout_data_utf8_len == 0) {
sfree(inst->pasteout_data_utf8);
inst->pasteout_data_utf8 = NULL;
} else {
inst->pasteout_data_utf8 =
sresize(inst->pasteout_data_utf8,
inst->pasteout_data_utf8_len + 1, char);
inst->pasteout_data_utf8[inst->pasteout_data_utf8_len] = '\0';
}
/*
* Now let Xlib convert our UTF-8 data into compound text.
*/
list[0] = inst->pasteout_data_utf8;
if (Xutf8TextListToTextProperty(GDK_DISPLAY(), list, 1,
XCompoundTextStyle, &tp) == 0) {
inst->pasteout_data_ctext = snewn(tp.nitems+1, char);
memcpy(inst->pasteout_data_ctext, tp.value, tp.nitems);
inst->pasteout_data_ctext_len = tp.nitems;
XFree(tp.value);
} else {
inst->pasteout_data_ctext = NULL;
inst->pasteout_data_ctext_len = 0;
}
} else {
inst->pasteout_data_utf8 = NULL;
inst->pasteout_data_utf8_len = 0;
inst->pasteout_data_ctext = NULL;
inst->pasteout_data_ctext_len = 0;
}
inst->pasteout_data = snewn(len*6, char);
inst->pasteout_data_len = len*6;
inst->pasteout_data_len = wc_to_mb(inst->ucsdata.line_codepage, 0,
data, len, inst->pasteout_data,
inst->pasteout_data_len,
NULL, NULL, NULL);
if (inst->pasteout_data_len == 0) {
sfree(inst->pasteout_data);
inst->pasteout_data = NULL;
} else {
inst->pasteout_data =
sresize(inst->pasteout_data, inst->pasteout_data_len, char);
}
store_cutbuffer(inst->pasteout_data, inst->pasteout_data_len);
if (gtk_selection_owner_set(inst->area, GDK_SELECTION_PRIMARY,
inst->input_event_time)) {
gtk_selection_add_target(inst->area, GDK_SELECTION_PRIMARY,
GDK_SELECTION_TYPE_STRING, 1);
if (inst->pasteout_data_ctext)
gtk_selection_add_target(inst->area, GDK_SELECTION_PRIMARY,
compound_text_atom, 1);
if (inst->pasteout_data_utf8)
gtk_selection_add_target(inst->area, GDK_SELECTION_PRIMARY,
utf8_string_atom, 1);
}
if (must_deselect)
term_deselect(inst->term);
}
void selection_get(GtkWidget *widget, GtkSelectionData *seldata,
guint info, guint time_stamp, gpointer data)
{
struct gui_data *inst = (struct gui_data *)data;
if (seldata->target == utf8_string_atom)
gtk_selection_data_set(seldata, seldata->target, 8,
inst->pasteout_data_utf8,
inst->pasteout_data_utf8_len);
else if (seldata->target == compound_text_atom)
gtk_selection_data_set(seldata, seldata->target, 8,
inst->pasteout_data_ctext,
inst->pasteout_data_ctext_len);
else
gtk_selection_data_set(seldata, seldata->target, 8,
inst->pasteout_data, inst->pasteout_data_len);
}
gint selection_clear(GtkWidget *widget, GdkEventSelection *seldata,
gpointer data)
{
struct gui_data *inst = (struct gui_data *)data;
term_deselect(inst->term);
if (inst->pasteout_data)
sfree(inst->pasteout_data);
if (inst->pasteout_data_ctext)
sfree(inst->pasteout_data_ctext);
if (inst->pasteout_data_utf8)
sfree(inst->pasteout_data_utf8);
inst->pasteout_data = NULL;
inst->pasteout_data_len = 0;
inst->pasteout_data_ctext = NULL;
inst->pasteout_data_ctext_len = 0;
inst->pasteout_data_utf8 = NULL;
inst->pasteout_data_utf8_len = 0;
return TRUE;
}
void request_paste(void *frontend)
{
struct gui_data *inst = (struct gui_data *)frontend;
/*
* 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().
*/
if (!inst->direct_to_font) {
/*
* First we attempt to retrieve the selection as a UTF-8
* string (which we will convert to the correct code page
* before sending to the session, of course). If that
* fails, selection_received() will be informed and will
* fall back to an ordinary string.
*/
gtk_selection_convert(inst->area, GDK_SELECTION_PRIMARY,
utf8_string_atom,
inst->input_event_time);
} else {
/*
* If we're in direct-to-font mode, we disable UTF-8
* pasting, and go straight to ordinary string data.
*/
gtk_selection_convert(inst->area, GDK_SELECTION_PRIMARY,
GDK_SELECTION_TYPE_STRING,
inst->input_event_time);
}
}
gint idle_paste_func(gpointer data); /* forward ref */
void selection_received(GtkWidget *widget, GtkSelectionData *seldata,
guint time, gpointer data)
{
struct gui_data *inst = (struct gui_data *)data;
XTextProperty tp;
char **list;
char *text;
int length, count, ret;
int free_list_required = 0;
int free_required = 0;
int charset;
if (seldata->target == utf8_string_atom && seldata->length <= 0) {
/*
* Failed to get a UTF-8 selection string. Try compound
* text next.
*/
gtk_selection_convert(inst->area, GDK_SELECTION_PRIMARY,
compound_text_atom,
inst->input_event_time);
return;
}
if (seldata->target == compound_text_atom && seldata->length <= 0) {
/*
* Failed to get UTF-8 or compound text. Try an ordinary
* string.
*/
gtk_selection_convert(inst->area, GDK_SELECTION_PRIMARY,
GDK_SELECTION_TYPE_STRING,
inst->input_event_time);
return;
}
/*
* If we have data, but it's not of a type we can deal with,
* we have to ignore the data.
*/
if (seldata->length > 0 &&
seldata->type != GDK_SELECTION_TYPE_STRING &&
seldata->type != compound_text_atom &&
seldata->type != utf8_string_atom)
return;
/*
* If we have no data, try looking in a cut buffer.
*/
if (seldata->length <= 0) {
text = retrieve_cutbuffer(&length);
if (length == 0)
return;
/* Xterm is rumoured to expect Latin-1, though I havn't checked the
* source, so use that as a de-facto standard. */
charset = CS_ISO8859_1;
free_required = 1;
} else {
/*
* Convert COMPOUND_TEXT into UTF-8.
*/
if (seldata->type == compound_text_atom) {
tp.value = seldata->data;
tp.encoding = (Atom) seldata->type;
tp.format = seldata->format;
tp.nitems = seldata->length;
ret = Xutf8TextPropertyToTextList(GDK_DISPLAY(), &tp,
&list, &count);
if (ret != 0 || count != 1) {
/*
* Compound text failed; fall back to STRING.
*/
gtk_selection_convert(inst->area, GDK_SELECTION_PRIMARY,
GDK_SELECTION_TYPE_STRING,
inst->input_event_time);
return;
}
text = list[0];
length = strlen(list[0]);
charset = CS_UTF8;
free_list_required = 1;
} else {
text = (char *)seldata->data;
length = seldata->length;
charset = (seldata->type == utf8_string_atom ?
CS_UTF8 : inst->ucsdata.line_codepage);
}
}
if (inst->pastein_data)
sfree(inst->pastein_data);
inst->pastein_data = snewn(length, wchar_t);
inst->pastein_data_len = length;
inst->pastein_data_len =
mb_to_wc(charset, 0, text, length,
inst->pastein_data, inst->pastein_data_len);
term_do_paste(inst->term);
if (term_paste_pending(inst->term))
inst->term_paste_idle_id = gtk_idle_add(idle_paste_func, inst);
if (free_list_required)
XFreeStringList(list);
if (free_required)
XFree(text);
}
gint idle_paste_func(gpointer data)
{
struct gui_data *inst = (struct gui_data *)data;
if (term_paste_pending(inst->term))
term_paste(inst->term);
else
gtk_idle_remove(inst->term_paste_idle_id);
return TRUE;
}
void get_clip(void *frontend, wchar_t ** p, int *len)
{
struct gui_data *inst = (struct gui_data *)frontend;
if (p) {
*p = inst->pastein_data;
*len = inst->pastein_data_len;
}
}
static void set_window_titles(struct gui_data *inst)
{
/*
* We must always call set_icon_name after calling set_title,
* since set_title will write both names. Irritating, but such
* is life.
*/
gtk_window_set_title(GTK_WINDOW(inst->window), inst->wintitle);
if (!inst->cfg.win_name_always)
gdk_window_set_icon_name(inst->window->window, inst->icontitle);
}
void set_title(void *frontend, char *title)
{
struct gui_data *inst = (struct gui_data *)frontend;
strncpy(inst->wintitle, title, lenof(inst->wintitle));
inst->wintitle[lenof(inst->wintitle)-1] = '\0';
set_window_titles(inst);
}
void set_icon(void *frontend, char *title)
{
struct gui_data *inst = (struct gui_data *)frontend;
strncpy(inst->icontitle, title, lenof(inst->icontitle));
inst->icontitle[lenof(inst->icontitle)-1] = '\0';
set_window_titles(inst);
}
void set_sbar(void *frontend, int total, int start, int page)
{
struct gui_data *inst = (struct gui_data *)frontend;
if (!inst->cfg.scrollbar)
return;
inst->sbar_adjust->lower = 0;
inst->sbar_adjust->upper = total;
inst->sbar_adjust->value = start;
inst->sbar_adjust->page_size = page;
inst->sbar_adjust->step_increment = 1;
inst->sbar_adjust->page_increment = page/2;
inst->ignore_sbar = TRUE;
gtk_adjustment_changed(inst->sbar_adjust);
inst->ignore_sbar = FALSE;
}
void scrollbar_moved(GtkAdjustment *adj, gpointer data)
{
struct gui_data *inst = (struct gui_data *)data;
if (!inst->cfg.scrollbar)
return;
if (!inst->ignore_sbar)
term_scroll(inst->term, 1, (int)adj->value);
}
void sys_cursor(void *frontend, int x, int y)
{
/*
* This is meaningless under X.
*/
}
/*
* This is still called when mode==BELL_VISUAL, even though the
* visual bell is handled entirely within terminal.c, because we
* may want to perform additional actions on any kind of bell (for
* example, taskbar flashing in Windows).
*/
void beep(void *frontend, int mode)
{
if (mode != BELL_VISUAL)
gdk_beep();
}
int char_width(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 *frontend)
{
struct gui_data *inst = (struct gui_data *)frontend;
struct draw_ctx *dctx;
if (!inst->area->window)
return NULL;
dctx = snew(struct draw_ctx);
dctx->inst = inst;
dctx->gc = gdk_gc_new(inst->area->window);
return dctx;
}
void free_ctx(Context ctx)
{
struct draw_ctx *dctx = (struct draw_ctx *)ctx;
/* struct gui_data *inst = dctx->inst; */
GdkGC *gc = dctx->gc;
gdk_gc_unref(gc);
sfree(dctx);
}
/*
* Draw a line of text in the window, at given character
* coordinates, in given attributes.
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -