X-Git-Url: https://git.danieliu.xyz/?a=blobdiff_plain;f=st.c;h=37c404877f78f4f7d3db8e614636d0de7905157d;hb=e4bf56ae1a9e2612ec9a6faf2aaecd6eadcccaa7;hp=99ab085f173aa1e064880b2aa65b25394ab7202b;hpb=6faedce53a8de8a81da1ba045ffbc2b7603128cd;p=st.git diff --git a/st.c b/st.c index 99ab085..37c4048 100644 --- a/st.c +++ b/st.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -107,6 +108,8 @@ typedef struct { Colormap cmap; Window win; Pixmap buf; + XIM xim; + XIC xic; int scr; int w; /* window width */ int h; /* window height */ @@ -197,7 +200,8 @@ static void focus(XEvent *); static void brelease(XEvent *); static void bpress(XEvent *); static void bmotion(XEvent *); - +static void selection_notify(XEvent *); +static void selection_request(XEvent *); static void (*handler[LASTEvent])(XEvent *) = { [KeyPress] = kpress, @@ -210,6 +214,8 @@ static void (*handler[LASTEvent])(XEvent *) = { [MotionNotify] = bmotion, [ButtonPress] = bpress, [ButtonRelease] = brelease, + [SelectionNotify] = selection_notify, + [SelectionRequest] = selection_request, }; /* Globals */ @@ -241,8 +247,9 @@ static inline int selected(int x, int y) { } static void getbuttoninfo(XEvent *e, int *b, int *x, int *y) { - if(b) *b = e->xbutton.state, - *b=*b==4096?5:*b==2048?4:*b==1024?3:*b==512?2:*b==256?1:-1; + if(b) + *b = e->xbutton.button; + *x = e->xbutton.x/xw.cw; *y = e->xbutton.y/xw.ch; sel.b.x = sel.by < sel.ey ? sel.bx : sel.ex; @@ -275,15 +282,129 @@ static char *getseltext() { return str; } -/* TODO: use X11 clipboard */ +static void selection_notify(XEvent *e) { + unsigned long nitems; + unsigned long length; + int format, res; + unsigned char *data; + Atom type; + + res = XGetWindowProperty(xw.dis, xw.win, XA_PRIMARY, 0, 0, False, + AnyPropertyType, &type, &format, &nitems, &length, &data); + switch(res) { + case BadAtom: + case BadValue: + case BadWindow: + fprintf(stderr, "Invalid paste, XGetWindowProperty0"); + return; + } + + res = XGetWindowProperty(xw.dis, xw.win, XA_PRIMARY, 0, length, False, + AnyPropertyType, &type, &format, &nitems, &length, &data); + switch(res) { + case BadAtom: + case BadValue: + case BadWindow: + fprintf(stderr, "Invalid paste, XGetWindowProperty0"); + return; + } + + if(data) { + ttywrite((const char *) data, nitems * format / 8); + XFree(data); + } +} + +static void selpaste() { + XConvertSelection(xw.dis, XA_PRIMARY, XA_STRING, XA_PRIMARY, xw.win, CurrentTime); +} + +static void selection_request(XEvent *e) +{ + XSelectionRequestEvent *xsre; + XSelectionEvent xev; + int res; + Atom xa_targets; + + xsre = (XSelectionRequestEvent *) e; + xev.type = SelectionNotify; + xev.requestor = xsre->requestor; + xev.selection = xsre->selection; + xev.target = xsre->target; + xev.time = xsre->time; + /* reject */ + xev.property = None; + + xa_targets = XInternAtom(xw.dis, "TARGETS", 0); + if(xsre->target == xa_targets) { + /* respond with the supported type */ + Atom string = XA_STRING; + res = XChangeProperty(xsre->display, xsre->requestor, xsre->property, XA_ATOM, 32, + PropModeReplace, (unsigned char *) &string, 1); + switch(res) { + case BadAlloc: + case BadAtom: + case BadMatch: + case BadValue: + case BadWindow: + fprintf(stderr, "Error in selection_request, TARGETS"); + break; + default: + xev.property = xsre->property; + } + } else if(xsre->target == XA_STRING) { + res = XChangeProperty(xsre->display, xsre->requestor, xsre->property, + xsre->target, 8, PropModeReplace, (unsigned char *) sel.clip, + strlen(sel.clip)); + switch(res) { + case BadAlloc: + case BadAtom: + case BadMatch: + case BadValue: + case BadWindow: + fprintf(stderr, "Error in selection_request, XA_STRING"); + break; + default: + xev.property = xsre->property; + } + } + + /* all done, send a notification to the listener */ + res = XSendEvent(xsre->display, xsre->requestor, True, 0, (XEvent *) &xev); + switch(res) { + case 0: + case BadValue: + case BadWindow: + fprintf(stderr, "Error in selection_requested, XSendEvent"); + } +} + static void selcopy(char *str) { + /* register the selection for both the clipboard and the primary */ + Atom clipboard; + int res; + free(sel.clip); sel.clip = str; -} -static void selpaste() { - if(sel.clip) - ttywrite(sel.clip, strlen(sel.clip)); + res = XSetSelectionOwner(xw.dis, XA_PRIMARY, xw.win, CurrentTime); + switch(res) { + case BadAtom: + case BadWindow: + fprintf(stderr, "Invalid copy, XSetSelectionOwner"); + return; + } + + clipboard = XInternAtom(xw.dis, "CLIPBOARD", 0); + res = XSetSelectionOwner(xw.dis, clipboard, xw.win, CurrentTime); + switch(res) { + case BadAtom: + case BadWindow: + fprintf(stderr, "Invalid copy, XSetSelectionOwner"); + return; + } + + XFlush(xw.dis); } /* TODO: doubleclick to select word */ @@ -1228,6 +1349,13 @@ xinit(void) { | CWColormap, &attrs); xw.buf = XCreatePixmap(xw.dis, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dis, xw.scr)); + + + /* input methods */ + xw.xim = XOpenIM(xw.dis, NULL, NULL, NULL); + xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing + | XIMStatusNothing, XNClientWindow, xw.win, + XNFocusWindow, xw.win, NULL); /* gc */ dc.gc = XCreateGC(xw.dis, xw.win, 0, NULL); @@ -1411,10 +1539,11 @@ kpress(XEvent *ev) { int len; int meta; int shift; + Status status; meta = e->state & Mod1Mask; shift = e->state & ShiftMask; - len = XLookupString(e, buf, sizeof(buf), &ksym, NULL); + len = XmbLookupString(xw.xic, e, buf, sizeof(buf), &ksym, &status); if((customkey = kmap(ksym))) ttywrite(customkey, strlen(customkey)); @@ -1434,7 +1563,7 @@ kpress(XEvent *ev) { break; case XK_Insert: if(shift) - selpaste(), draw(1); + selpaste(); break; default: fprintf(stderr, "errkey: %d\n", (int)ksym); @@ -1484,6 +1613,8 @@ run(void) { } while(XPending(xw.dis)) { XNextEvent(xw.dis, &ev); + if (XFilterEvent(&ev, xw.win)) + continue; if(handler[ev.type]) (handler[ev.type])(&ev); }