Skip to content

Instantly share code, notes, and snippets.

@hchbaw
Created September 1, 2011 14:11
Show Gist options
  • Save hchbaw/1186247 to your computer and use it in GitHub Desktop.
Save hchbaw/1186247 to your computer and use it in GitHub Desktop.
rxvt-unicodeとuim-ximでtutcode.scmの後置型変換を楽しむためのパッチ等です。
.
├── Gif.gif -- デモ動画です
├── README -- このファイル
├── libX11.patch -- libX11へのパッチです
├── rxvt-unicode.patch -- rxvt-unicodeへのパッチです
├── uim-xim.patch -- uimへのパッチですuim/xim以下だけ手を加えました
└── xim-strconv -- rxvt-unicodeがperlを通して呼び出すスクリプト
3つのパッチは、それぞれに当てて下さいね。
最後のxim-strconvは、環境によりカスタマイズが必要だと思います。
(今のところ自分用でしかないですね、ごめんなさい。)
.Xdefaultsにこんなふうに書いてます。
>
URxvt.perl-lib: /c/c/experiment/perl/
URxvt.perl-ext-common: default,xim-strconv
<
diff --git a/modules/im/ximcp/imCallbk.c b/modules/im/ximcp/imCallbk.c
index 6275bbf..0a9b05d 100644
--- a/modules/im/ximcp/imCallbk.c
+++ b/modules/im/ximcp/imCallbk.c
@@ -347,7 +347,7 @@ _XimStrConversionCallback(Xim im,
*(CARD16*)&buf[p] = (CARD16)im->private.proto.imid; p += sz_CARD16;
*(CARD16*)&buf[p] = (CARD16)ic->private.proto.icid; p += sz_CARD16;
*(CARD16*)&buf[p] = (CARD16)cbrec.text->length; p += sz_CARD16;
- memcpy(&buf[p],&cbrec.text->string.mbs,length_in_bytes);
+ memcpy(&buf[p],cbrec.text->string.mbs,length_in_bytes);
p += length_in_bytes;
*(CARD16*)&buf[p] = (CARD16)(sz_CARD32*cbrec.text->length);
p += XIM_PAD(2);
diff --git a/src/hookinc.h b/src/hookinc.h
index 18b5c89..f593375 100644
--- a/src/hookinc.h
+++ b/src/hookinc.h
@@ -49,6 +49,7 @@
def (XIM_PREEDIT_DONE)
def (XIM_PREEDIT_DRAW)
def (XIM_PREEDIT_CARET)
+ def (XIM_STR_CONVERSION)
def (CUSTOM_REND) // hovering over custom rendition, generate enter/leave maybe?
diff --git a/src/main.C b/src/main.C
index 03a00d5..4d652b0 100644
--- a/src/main.C
+++ b/src/main.C
@@ -1288,6 +1288,8 @@ xim_preedit_caret (XIC ic, XPointer client_data, XIMPreeditCaretCallbackStruct *
#endif
+static void xim_str_conversion(XIC ic, XPointer client_data, XPointer call_data);
+
/*
* Try to open a XIM with the current modifiers, then see if we can
* open a suitable preedit type
@@ -1502,11 +1504,114 @@ foundpet:
vt_select_input ();
#endif
+ XIMValuesList *ic_values = NULL;
+ if (!XGetIMValues(xim, XNQueryICValuesList, &ic_values, NULL))
+ {
+ int i;
+ for (i = 0; i < ic_values->count_values; i++)
+ {
+ if (strcmp(ic_values->supported_values[i],
+ XNStringConversionCallback) == 0)
+ {
+ XICCallback cb;
+ cb.client_data = (XPointer)this; cb.callback = (XICProc)&xim_str_conversion;
+ XSetICValues(Input_Context,
+ XNStringConversionCallback,
+ (XPointer)&cb,
+ NULL);
+ printf("SCCB registered\n");
+ break;
+ }
+ }
+ }
+
IMSetPosition ();
return true;
}
+struct xim_str_conv_buffer
+{
+ XIMStringConversionText *text;
+ XIMFeedback *feedback;
+ unsigned int size;
+ char *buffer;
+
+ xim_str_conv_buffer ();
+ ~xim_str_conv_buffer ();
+
+ XIMStringConversionText *get_text(const char *ptr, unsigned int len);
+};
+
+xim_str_conv_buffer::xim_str_conv_buffer ()
+{
+ text = (XIMStringConversionText *)malloc (sizeof (XIMStringConversionText));
+ size = 1024;
+ buffer = (char *)malloc (size * sizeof (char));
+ feedback = (XIMFeedback *)malloc (size * sizeof (XIMFeedback));
+ for (int i = 0; i < size; i++) feedback[i] = XIMPrimary;;
+}
+
+xim_str_conv_buffer::~xim_str_conv_buffer ()
+{
+ if (feedback != NULL) free(feedback);
+ if (buffer != NULL) free(buffer);
+ if (text != NULL) free(text);
+}
+
+XIMStringConversionText *
+xim_str_conv_buffer::get_text(const char *ptr, unsigned int len)
+{
+ if (text == NULL || feedback == NULL || buffer == NULL) return NULL;
+ if (len >= size)
+ {
+ buffer = (char *)realloc (buffer, (len + 1) * sizeof (char));
+ feedback = (XIMFeedback *)
+ realloc (feedback, (len + 1) * sizeof (XIMFeedback));
+ }
+ if (buffer == NULL || feedback == NULL) return NULL;
+
+ size = len;
+ text->length = len;
+ feedback[len] = 0;
+ memcpy(buffer, ptr, len);
+ buffer[len] = 0;
+
+ text->string.mbs = buffer;
+ text->encoding_is_wchar = False;
+ text->length = size;
+ text->feedback = feedback;
+ return text;
+}
+
+static xim_str_conv_buffer *ximscbuffer = new xim_str_conv_buffer ();
+
+static void
+xim_str_conversion (XIC ic, XPointer client_data, XPointer call_data)
+{
+ XIMStringConversionCallbackStruct *conv_data;
+ conv_data = (XIMStringConversionCallbackStruct *)call_data;
+
+ ((rxvt_term *)client_data)->make_current ();
+ HOOK_INVOKE(((rxvt_term *)client_data, HOOK_XIM_STR_CONVERSION,
+ DT_INT, conv_data->position,
+ DT_INT, conv_data->direction,
+ DT_INT, conv_data->operation,
+ DT_INT, conv_data->factor,
+ DT_END));
+
+ unsigned int len = 0;
+ XIMStringConversionText *t = NULL;
+ char *p = rxvt_perl_get_str ("urxvt::ext::xim_strconv::BUFFER", &len);
+
+ if (p != NULL)
+ t = ximscbuffer->get_text (p, len);
+ if (t == NULL)
+ printf("********fatal!!!\n");
+
+ conv_data->text = t;
+}
+
void
rxvt_term::im_cb ()
{
diff --git a/src/rxvtperl.h b/src/rxvtperl.h
index 58ed4b2..a080c3a 100644
--- a/src/rxvtperl.h
+++ b/src/rxvtperl.h
@@ -54,6 +54,8 @@ struct rxvt_perl_interp
extern struct rxvt_perl_interp rxvt_perl;
+char * rxvt_perl_get_str (const char *name, unsigned int *len);
+
#else
#define SHOULD_INVOKE(htype) false
diff --git a/src/rxvtperl.xs b/src/rxvtperl.xs
index f450350..26defd3 100644
--- a/src/rxvtperl.xs
+++ b/src/rxvtperl.xs
@@ -48,6 +48,22 @@
#undef ROW
#define ROW(n) THIS->row_buf [LINENO (n)]
+char *
+rxvt_perl_get_str (const char *name, unsigned int *len)
+{
+ SV *s;
+ char *p;
+ STRLEN l;
+ s = get_sv(name, 0);
+ if (s == NULL) return NULL;
+
+ //p = SvPV_nolen(s);
+ p = SvPV(s, l);
+ *len = l;
+
+ return p;
+}
+
/////////////////////////////////////////////////////////////////////////////
static wchar_t *
@@ -787,6 +803,8 @@ BOOT:
const_iv (XIMAbsolutePosition),
const_iv (XIMDontChange),
# endif
+ const_iv (XIMStringConversionSubstitution),
+ const_iv (XIMStringConversionRetrieval),
# endif
};
diff --git a/xim/connection.cpp b/xim/connection.cpp
index 2963e80..265e534 100644
--- a/xim/connection.cpp
+++ b/xim/connection.cpp
@@ -61,7 +61,7 @@ extern char *xim_packet_name[];
static std::map<Window, XConnection *> gXConnections;
static Atom xim_xconnect;
-static Atom xim_protocol;
+Atom xim_protocol;
static Atom xim_moredata;
static Atom uim_comm;
@@ -216,6 +216,11 @@ bool XConnection::checkByteorder()
bool XConnection::readToBuf(XClientMessageEvent *ev)
{
+ return readBuf(ev, &mBuf);
+}
+
+bool XConnection::readBuf(XClientMessageEvent *ev, XBuf *b)
+{
if (ev->format == 32 && ev->message_type == xim_protocol) {
// indirect
int offset = 0;
@@ -225,13 +230,13 @@ bool XConnection::readToBuf(XClientMessageEvent *ev)
unsigned long remain;
char *data;
- while (ev->data.l[0] >= mBuf.size) {
- mBuf.size += 1024;
- mBuf.buf = (char *)realloc(mBuf.buf, mBuf.size);
+ while (ev->data.l[0] >= b->size) {
+ b->size += 1024;
+ b->buf = (char *)realloc(b->buf, b->size);
}
do {
XGetWindowProperty(XimServer::gDpy, ev->window, ev->data.l[1],
- offset, mBuf.size - mBuf.len, True,
+ offset, b->size - b->len, True,
AnyPropertyType,
&type, &format, &nrItems, &remain,
(unsigned char **)(uintptr_t)&data);
@@ -239,20 +244,20 @@ bool XConnection::readToBuf(XClientMessageEvent *ev)
return false;
if (format == 8) {
- memcpy(&mBuf.buf[mBuf.len], data, nrItems);
- mBuf.len += static_cast<int>(nrItems);
+ memcpy(&b->buf[b->len], data, nrItems);
+ b->len += static_cast<int>(nrItems);
} else
return false;
XFree(data);
} while (remain > 0);
} else if (ev->format == 8) {
// direct
- if ((mBuf.len + TRANSPORT_UNIT) >= mBuf.size) {
- mBuf.size += TRANSPORT_UNIT;
- mBuf.buf = (char *)realloc(mBuf.buf, mBuf.size);
+ if ((b->len + TRANSPORT_UNIT) >= b->size) {
+ b->size += TRANSPORT_UNIT;
+ b->buf = (char *)realloc(b->buf, b->size);
}
- memcpy(&mBuf.buf[mBuf.len], ev->data.b, TRANSPORT_UNIT);
- mBuf.len += TRANSPORT_UNIT;
+ memcpy(&b->buf[b->len], ev->data.b, TRANSPORT_UNIT);
+ b->len += TRANSPORT_UNIT;
} else
return false;
diff --git a/xim/connection.h b/xim/connection.h
index 95a6518..de06e77 100644
--- a/xim/connection.h
+++ b/xim/connection.h
@@ -38,6 +38,12 @@
int connection_setup();
+typedef struct _XBuf {
+ char *buf;
+ int len;
+ long size;
+} XBuf;
+
class XConnection: public Connection, public WindowIf {
public:
XConnection(XimServer *svr, Window clientWin, Window commWin);
@@ -51,19 +57,17 @@ public:
void writePassivePacket();
void writeNormalPacket();
bool isValid() {return mIsValid;};
+ Window mCommWin;
+ bool readBuf(XClientMessageEvent *, XBuf *);
private:
bool readToBuf(XClientMessageEvent *);
bool checkByteorder();
void shiftBuffer(int);
void doSend(TxPacket *t, bool is_passive);
- Window mClientWin, mCommWin;
+ Window mClientWin;
bool mIsValid;
- struct {
- char *buf;
- int len;
- long size;
- } mBuf;
+ XBuf mBuf;
};
#endif
diff --git a/xim/xim.h b/xim/xim.h
index 58054e2..51b848e 100644
--- a/xim/xim.h
+++ b/xim/xim.h
@@ -292,6 +292,8 @@ public:
void changeContext(const char *engine);
const char *get_encoding();
const char *get_lang_region();
+ bool str_conversion_retrieval(int len, char **dest);
+ bool str_conversion_substitution(int len);
public:
static XimIC *get_current_ic();
diff --git a/xim/ximic.cpp b/xim/ximic.cpp
index e0ea36b..a3756ae 100644
--- a/xim/ximic.cpp
+++ b/xim/ximic.cpp
@@ -42,6 +42,8 @@
#include <cstdlib>
#include <cstring>
+#include <X11/Xutil.h>
+
#include "xim.h"
#include "convdisp.h"
#include "ximserver.h"
@@ -684,6 +686,114 @@ const char *XimIC::get_lang_region()
return im->get_lang_region();
}
+extern Atom xim_protocol;
+static Bool client_message_event_p(Display *dpy, XEvent *ev, XPointer data);
+static bool str_conversion(XConnection *xc, bool (*fn)(RxPacket *p, void *data), void *data);
+static bool str_conversion_retrieval_aux(RxPacket *p, void *data);
+static bool str_conversion_substitution_aux(RxPacket *p, void *data);
+
+#define INIT_BUF_SIZE 1024
+
+static bool str_conversion(XConnection *xc, bool (*fn)(RxPacket *p, void *data), void *data)
+{
+ XEvent ev;
+ XBuf b;
+
+ b.buf = (char *)malloc(INIT_BUF_SIZE);
+ b.len = 0;
+ b.size = INIT_BUF_SIZE;
+
+ for (;;) {
+ XIfEvent(XimServer::gDpy,
+ &ev,
+ client_message_event_p,
+ NULL);
+ if (ev.xclient.window == xc->mCommWin) {
+ if (xc->readBuf(&(ev.xclient), &b)) {
+ RxPacket *p = createRxPacket((unsigned char *)b.buf,
+ xc->byte_order());
+ free(b.buf);
+ if (p->getMajor() == XIM_STR_CONVERSION_REPLY)
+ return (*fn)(p, data);
+ }
+ }
+ return false; // XXX:
+ }
+}
+
+static Bool client_message_event_p(Display *dpy, XEvent *ev, XPointer data)
+{
+ if ((ev->type == ClientMessage)
+ &&
+ (ev->xclient.message_type == xim_protocol)) {
+ return True;
+ }
+ return False;
+}
+
+bool XimIC::str_conversion_retrieval(int len, char** dest)
+{
+ TxPacket *t;
+ t = createTxPacket(XIM_STR_CONVERSION, 0);
+ t->pushC16(mIMid);
+ t->pushC16(mICid);
+ t->pushC32(0); /* XXX: badness */
+ t->pushC32((XIMStringConversionPosition)0);
+ t->pushC32(XIMBackwardChar);
+ t->pushC32(XIMStringConversionRetrieval);
+ t->pushC32(1*len);
+ mConn->push_packet(t);
+ force_send_packet();
+ return str_conversion((dynamic_cast<XConnection *>(mConn)),
+ str_conversion_retrieval_aux,
+ (void *)dest);
+}
+
+static bool str_conversion_retrieval_aux(RxPacket *p, void *data)
+{
+ int len;
+ char *buf = NULL;
+ char **dest = (char **)data;
+
+ //p->dump();
+
+ p->getC16();
+ p->getC16();
+
+ len = p->getStrLen();
+ buf = (char *)malloc(len + 1);
+ buf[len] = 0;
+ p->getStr(buf);
+
+ *dest = strdup(buf);
+ free(buf);
+
+ return true;
+}
+
+bool XimIC::str_conversion_substitution(int len)
+{
+ TxPacket *t;
+ t = createTxPacket(XIM_STR_CONVERSION, 0);
+ t->pushC16(mIMid);
+ t->pushC16(mICid);
+ t->pushC32(0); /* XXX: badness */
+ t->pushC32((XIMStringConversionPosition)0);
+ t->pushC32(XIMBackwardChar);
+ t->pushC32(XIMStringConversionSubstitution);
+ t->pushC32(1*len);
+ mConn->push_packet(t);
+ force_send_packet();
+ return str_conversion((dynamic_cast<XConnection *>(mConn)),
+ str_conversion_substitution_aux,
+ NULL);
+}
+
+static bool str_conversion_substitution_aux(RxPacket *p, void *data)
+{
+ return true;
+}
+
XimIC *create_ic(Connection *c, RxPacket *p, C16 imid, C16 icid, const char *engine)
{
XimIC *ic;
diff --git a/xim/ximpn.h b/xim/ximpn.h
index 28d1e95..ceff489 100644
--- a/xim/ximpn.h
+++ b/xim/ximpn.h
@@ -136,6 +136,7 @@
#define ICA_BackgroundPixmap 14
#define ICA_Cursor 15
#define ICA_FilterEvents 16
+#define ICA_StringConversionCallback 17
// Style (Input Style)
#define IS_INVALID 0
diff --git a/xim/ximserver.cpp b/xim/ximserver.cpp
index 6d7c1b7..63fd2ad 100644
--- a/xim/ximserver.cpp
+++ b/xim/ximserver.cpp
@@ -438,6 +438,10 @@ InputContext::createUimContext(const char *engine)
uim_set_im_switch_request_cb(uc,
InputContext::switch_app_global_im_cb,
InputContext::switch_system_global_im_cb);
+ uim_set_text_acquisition_cb(uc,
+ InputContext::acquire_text_cb,
+ InputContext::delete_text_cb);
+
if (mFocusedContext == this)
uim_prop_list_update(uc);
@@ -1488,6 +1492,29 @@ check_candwin_pos_type()
free(candwin_pos_type);
}
+int
+InputContext::acquire_text_cb(void *ptr, enum UTextArea text_id, enum UTextOrigin origin, int former_req_len, int latter_req_len, char **former, char **latter)
+{
+ InputContext *ic = (InputContext *)ptr;
+ XimIC *xic = ic->get_ic();
+ if (xic->str_conversion_retrieval(former_req_len, former)) {
+ *latter = strdup("");
+ printf("***'%s'\n", *former);
+ return 0;
+ }
+ return -1;
+}
+
+int
+InputContext::delete_text_cb(void *ptr, enum UTextArea text_id, enum UTextOrigin origin, int former_req_len, int latter_req_len)
+{
+ InputContext *ic = (InputContext *)ptr;
+ XimIC *xic = ic->get_ic();
+ if (xic->str_conversion_substitution(former_req_len))
+ return 0;
+ return -1;
+}
+
/*
* Local variables:
* c-indent-level: 4
diff --git a/xim/ximserver.h b/xim/ximserver.h
index 977c6b8..78a4e00 100644
--- a/xim/ximserver.h
+++ b/xim/ximserver.h
@@ -211,6 +211,8 @@ public:
static void configuration_changed_cb(void *ptr);
static void switch_app_global_im_cb(void *ptr, const char *name);
static void switch_system_global_im_cb(void *ptr, const char *name);
+ static int acquire_text_cb(void *ptr, enum UTextArea text_id, enum UTextOrigin origin, int former_req_len, int latter_req_len, char **former, char **latter);
+ static int delete_text_cb(void *ptr, enum UTextArea text_id, enum UTextOrigin origin, int former_req_len, int latter_req_len);
static InputContext *focusedContext();
static void deletefocusedContext();
private:
diff --git a/xim/ximtrans.cpp b/xim/ximtrans.cpp
index bc7570b..b858dc9 100644
--- a/xim/ximtrans.cpp
+++ b/xim/ximtrans.cpp
@@ -157,6 +157,7 @@ static struct XICATTRIBUTE {
XICATTRIBUTE(XNBackgroundPixmap, TYPE_LONG),
XICATTRIBUTE(XNCursor, TYPE_WORD),
XICATTRIBUTE(XNFilterEvents, TYPE_WORD),
+ XICATTRIBUTE(XNStringConversionCallback, TYPE_WORD),
XICATTRIBUTE(XNSeparatorofNestedList, TYPE_SEPARATOR),
};
#!perl
our $BUFFER;
sub retrieve {
my ($term, $len, $nocharp, $k) = @_;
my $loop; $loop = sub {
my ($n, $y, $x, $a) = @_;
if (($n == 0) or ($y == 0) && ($x == 0)) {
$k->($term->special_decode ($a));
}
else {
my ($y2, $x2) = ($x == 0) ? ($y - 1, $term->ncol) : ($y, $x);
my $c = substr ($term->ROW_t ($y2), $x2 - 1, 1);
if ($nocharp->($term, $c, $term->ROW_r ($y2), $y2, $x2)) {
$loop->($n, $y2, $x2 - 1, $a);
}
else {
$loop->($n - 1, $y2, $x2 - 1, $c . $a);
}
}
};
$loop->($len, $term->screen_cur (), "");
}
sub d {
local *STDOUT = sub {
open my $o, ">> /tmp/ximstrconv.log" or do {
urxvt::warn "can't open log: $!";
return ();
};
$o;
}->();
my ($term, $c, $r, $row, $col) = @_;
print "===($col x $row)\n";
print ' c:"' . $c . '"' . ' r:' . $r->[$col - 1] . "\n";
print 'fg:' . urxvt::GET_BASEFG ($r->[$col - 1]) . "\n";
print 'bg:' . urxvt::GET_BASEFG ($r->[$col - 1]) . "\n";
print 'cu:' . urxvt::GET_CUSTOM ($r->[$col - 1]) . "\n";
}
sub padcharp {
my ($term, $c, $r, $row, $col) = @_;
$ENV{URXVT_PERL_VERBOSITY} and d @_;
($c eq $urxvt::NOCHAR)
or # zsh and vim
($term->ROW_is_longer ($row) and $col == $term->ncol and
($c eq ' ' and ($r->[$col - 1] & urxvt::RS_RVid)) or
($c eq '>' and urxvt::GET_BASEFG $r->[$col - 1]))
or # emacs
(($col == $term->ncol || $col == $term->ncol - 1) and
($c eq "\\" and ($r->[$col - 1] & urxvt::RS_Bold)))
}
sub substitute {
my ($term, $n) = @_;
$term->tt_write ("\b" x $n)
}
sub on_xim_str_conversion {
my ($term, $position, $direction, $operation, $factor) = @_;
if ($operation == urxvt::XIMStringConversionRetrieval) {
retrieve ($term, 1*$factor, \&padcharp, sub { $BUFFER = shift; });
}
elsif ($operation == urxvt::XIMStringConversionSubstitution) {
substitute ($term, 1*$factor);
}
else {
urxvt::warn "unknown operation: $operation";
}
();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment