From d582ce5ea5bd8e9f7c6e8e18ebec22017e3d884d Mon Sep 17 00:00:00 2001 From: Charlie Gordon Date: Fri, 7 Feb 2014 07:54:27 +0000 Subject: [PATCH] add support for wm_delete_window and utf8 clipboard in x11 (Francois Revol) --- x11.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 82 insertions(+), 5 deletions(-) diff --git a/x11.c b/x11.c index 502e84f..81e182f 100644 --- a/x11.c +++ b/x11.c @@ -55,6 +55,7 @@ static void x11_handle_event(void *opaque); static Display *display; static int xscreen; static Window window; +static Atom wm_delete_window; static GC gc, gc_pixmap; static XWindowAttributes attr; static int event_mask; @@ -319,6 +320,9 @@ static int term_init(QEditScreen *s, int w, int h) XNFocusWindow, window, NULL); + wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False); + XSetWMProtocols(display, window, &wm_delete_window, 1); + gc = XCreateGC(display, window, 0, NULL); #ifdef CONFIG_XFT renderDraw = XftDrawCreate(display, window, attr.visual, @@ -1074,6 +1078,7 @@ static void term_selection_request(__unused__ QEditScreen *s) QEmacsState *qs = &qe_state; Window w; Atom prop; + Atom utf8; long nread; unsigned char *data; Atom actual_type; @@ -1089,7 +1094,8 @@ static void term_selection_request(__unused__ QEditScreen *s) /* use X11 selection (Will be pasted when receiving SelectionNotify event) */ prop = XInternAtom(display, "VT_SELECTION", False); - XConvertSelection(display, XA_PRIMARY, XA_STRING, + utf8 = XInternAtom(display, "UTF8_STRING", False); + XConvertSelection(display, XA_PRIMARY, utf8, prop, window, CurrentTime); /* XXX: add timeout too if the target application is not well @@ -1110,7 +1116,7 @@ static void term_selection_request(__unused__ QEditScreen *s) AnyPropertyType, &actual_type, &actual_fmt, &nitems, &bytes_after, &data) != Success) || - (actual_type != XA_STRING)) { + (actual_type != utf8)) { XFree(data); break; } @@ -1129,6 +1135,7 @@ static void term_selection_request(__unused__ QEditScreen *s) static void selection_send(XSelectionRequestEvent *rq) { static Atom xa_targets = None; + static Atom xa_formats[] = { None, None, None, None }; QEmacsState *qs = &qe_state; unsigned char *buf; XEvent ev; @@ -1136,21 +1143,29 @@ static void selection_send(XSelectionRequestEvent *rq) if (xa_targets == None) xa_targets = XInternAtom(display, "TARGETS", False); + if (xa_formats[0] == None) { + xa_formats[0] = XInternAtom(display, "UTF8_STRING", False); + xa_formats[1] = XInternAtom(display, "text/plain;charset=UTF-8", False); + xa_formats[2] = XInternAtom(display, "text/plain;charset=utf-8", False); + xa_formats[3] = XA_STRING; + } ev.xselection.type = SelectionNotify; ev.xselection.property = None; ev.xselection.display = rq->display; ev.xselection.requestor = rq->requestor; ev.xselection.selection = rq->selection; - ev.xselection.target = rq->target; + ev.xselection.target = rq->target; ev.xselection.time = rq->time; if (rq->target == xa_targets) { - unsigned int target_list[2]; + unsigned int target_list[1 + countof(xa_formats)]; + int i; /* indicate which are supported types */ target_list[0] = xa_targets; - target_list[1] = XA_STRING; + for (i = 0; i < countof(xa_formats); i++) + target_list[i + 1] = xa_formats[i]; XChangeProperty(display, rq->requestor, rq->property, xa_targets, 8*sizeof(target_list[0]), PropModeReplace, @@ -1171,6 +1186,52 @@ static void selection_send(XSelectionRequestEvent *rq) XA_STRING, 8, PropModeReplace, buf, b->total_size); qe_free(&buf); + } else + if (rq->target == xa_formats[0] + || rq->target == xa_formats[1] + || rq->target == xa_formats[2]) { + int len; + /* get qemacs yank buffer */ + + b = qs->yank_buffers[qs->yank_current]; + if (!b) + return; + buf = qe_malloc_array(unsigned char, b->total_size); + if (!buf) + return; + eb_read(b, 0, buf, b->total_size); + len = b->total_size; + + /* if not UTF-8 we must convert to it */ + if (!(b->flags & BF_UTF8)) { + struct CharsetDecodeState st; + unsigned char *utf_buf, *p; + + utf_buf = qe_malloc_array(unsigned char, b->total_size * 6); + if (!utf_buf) { + qe_free(&buf); + return; + } + + charset_decode_init(&st, b->charset, b->eol_type); + st.p = buf; + p = utf_buf; + for (;;) { + int c = st.decode_func(&st); + if (c == 0) + break; + p += utf8_encode((char *)p, c); + } + + qe_free(&buf); + len = p - utf_buf; + buf = utf_buf; + } + + XChangeProperty(display, rq->requestor, rq->property, + rq->target, 8, PropModeReplace, + buf, len); + qe_free(&buf); } ev.xselection.property = rq->property; XSendEvent(display, rq->requestor, False, 0, &ev); @@ -1255,6 +1316,22 @@ static void x11_handle_event(void *opaque) while (XPending(display)) { XNextEvent(display, &xev); switch (xev.type) { + case ClientMessage: + if ((Atom)xev.xclient.data.l[0] == wm_delete_window) { + // cancel pending operation + ev->key_event.type = QE_KEY_EVENT; + ev->key_event.key = KEY_CTRL('g'); + qe_handle_event(ev); + + // simulate C-x C-c + ev->key_event.type = QE_KEY_EVENT; + ev->key_event.key = KEY_CTRL('x'); + qe_handle_event(ev); + ev->key_event.type = QE_KEY_EVENT; + ev->key_event.key = KEY_CTRL('c'); + qe_handle_event(ev); + } + break; case ConfigureNotify: if (term_resize(s, xev.xconfigure.width, xev.xconfigure.height)) { qe_expose_set(s, rgn, 0, 0, s->width, s->height);