return;
}
- /* see if we can connect yet */
- rxvt_IMInstantiateCallback (display->display, NULL, NULL);
+ im_ev.start (display);
- /* To avoid Segmentation Fault in C locale: Solaris only? */
- if (STRCMP (locale, "C"))
- XRegisterIMInstantiateCallback (display->display, NULL, NULL, NULL,
- rxvt_IMInstantiateCallback, NULL);
+ /* see if we can connect already */
+ im_cb ();
}
#endif
}
check_ev (this, &rxvt_term::check_cb),
destroy_ev (this, &rxvt_term::destroy_cb),
pty_ev (this, &rxvt_term::pty_cb),
- incr_ev (this, &rxvt_term::incr_cb)
+ incr_ev (this, &rxvt_term::incr_cb),
+#ifdef USE_XIM
+ im_ev (this, &rxvt_term::im_cb)
+#endif
{
cmdbuf_ptr = cmdbuf_endp = cmdbuf_base;
}
rxvt_term::~rxvt_term ()
{
+ if (cmd_fd >= 0)
+ close (cmd_fd);
+
scr_release ();
free (locale);
#ifdef UTMP_SUPPORT
privileged_utmp (RESTORE);
#endif
-#ifdef USE_XIM
- if (Input_Context)
- {
- XDestroyIC (Input_Context);
- Input_Context = NULL;
- }
-#endif
-
- if (TermWin.parent[0])
- XDestroyWindow (display->display, TermWin.parent[0]);
// TODO: free pixcolours, colours should become part of rxvt_display
delete PixColors;
- if (cmd_fd >= 0)
- close (cmd_fd);
-
- if (display)
- displays.release (display);
+ displays.put (display);
}
void
{
if (display)
{
+ if (TermWin.parent[0])
+ XDestroyWindow (display->display, TermWin.parent[0]);
+
termwin_ev.stop (display);
vt_ev.stop (display);
+
+#ifdef USE_XIM
+ im_destroy ();
+ im_ev.stop (display);
+#endif
#ifdef HAVE_SCROLLBARS
scrollbar_ev.stop (display);
#endif
* - X INPUT METHOD ROUTINES - *
* -------------------------------------------------------------------- */
#ifdef USE_XIM
+
void
-rxvt_term::set_size (XRectangle *size)
+rxvt_term::im_set_size (XRectangle *size)
{
size->x = TermWin.int_bwidth;
size->y = TermWin.int_bwidth;
}
void
-rxvt_term::set_color (unsigned long *fg, unsigned long *bg)
+rxvt_term::im_set_color (unsigned long *fg, unsigned long *bg)
{
*fg = PixColors[Color_fg];
*bg = PixColors[Color_bg];
|| !IMisRunning ())
return;
- set_position (&spot);
+ im_set_position (&spot);
preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL);
XSetICValues(Input_Context, XNPreeditAttributes, preedit_attr, NULL);
}
void
-rxvt_term::set_preedit_area (XRectangle * preedit_rect, XRectangle * status_rect,
- XRectangle * needed_rect)
+rxvt_term::im_set_preedit_area (XRectangle * preedit_rect, XRectangle * status_rect,
+ XRectangle * needed_rect)
{
int mbh, vtx = 0;
status_rect->height = Height2Pixel(1);
}
-/* ARGSUSED */
-/* EXTPROTO */
void
-rxvt_IMDestroyCallback(XIM xim __attribute__ ((unused)), XPointer client_data
- __attribute__ ((unused)), XPointer call_data
- __attribute__ ((unused)))
+rxvt_term::im_destroy ()
{
- GET_R->Input_Context = NULL;
- /* To avoid Segmentation Fault in C locale: Solaris only? */
- if (STRCMP (GET_R->locale, "C"))
- XRegisterIMInstantiateCallback(GET_R->display->display, NULL, NULL, NULL,
- rxvt_IMInstantiateCallback, NULL);
+ if (Input_Context)
+ {
+ XDestroyIC (Input_Context);
+ Input_Context = NULL;
+ }
+
+ if (input_method)
+ {
+ display->put_xim (input_method);
+ input_method = 0;
+ }
}
/*
* open a suitable preedit type
*/
bool
-rxvt_term::IM_get_IC ()
+rxvt_term::IM_get_IC (const char *modifiers)
{
int i, j, found;
XIM xim;
char **s;
XIMStyles *xim_styles;
XVaNestedList preedit_attr, status_attr;
- XIMCallback ximcallback;
+
+ if (!((p = XSetLocaleModifiers (modifiers)) && *p))
+ return false;
D_MAIN((stderr, "rxvt_IM_get_IC()"));
- xim = XOpenIM (display->display, NULL, NULL, NULL);
- if (xim == NULL)
- return False;
+ input_method = display->get_xim (locale, modifiers);
+ if (input_method == NULL)
+ return false;
+
+ xim = input_method->xim;
xim_styles = NULL;
if (XGetIMValues (xim, XNQueryInputStyle, &xim_styles, NULL)
|| !xim_styles || !xim_styles->count_styles)
{
- XCloseIM(xim);
- return False;
+ display->put_xim (input_method);
+ return false;
}
- p = rs[Rs_preeditType] ? rs[Rs_preeditType]
- : "OverTheSpot,OffTheSpot,Root";
+ p = rs[Rs_preeditType] ? rs[Rs_preeditType] : "OverTheSpot,OffTheSpot,Root";
s = rxvt_splitcommastring(p);
for (i = found = 0; !found && s[i]; i++)
{
break;
}
}
+
for (i = 0; s[i]; i++)
- free(s[i]);
- free(s);
- XFree(xim_styles);
+ free (s[i]);
+
+ free (s);
+ XFree (xim_styles);
if (!found)
{
- XCloseIM(xim);
- return False;
+ display->put_xim (input_method);
+ return false;
}
- ximcallback.callback = rxvt_IMDestroyCallback;
-
- /* XXX: not sure why we need this (as well as IC one below) */
- XSetIMValues(xim, XNDestroyCallback, &ximcallback, NULL);
-
preedit_attr = status_attr = NULL;
if (input_style & XIMPreeditPosition)
{
- set_size (&rect);
- set_position (&spot);
- set_color (&fg, &bg);
+ im_set_size (&rect);
+ im_set_position (&spot);
+ im_set_color (&fg, &bg);
preedit_attr = XVaCreateNestedList(0, XNArea, &rect,
XNSpotLocation, &spot,
}
else if (input_style & XIMPreeditArea)
{
- set_color (&fg, &bg);
+ im_set_color (&fg, &bg);
/*
* The necessary width of preedit area is unknown
*/
needed_rect.width = 0;
- set_preedit_area(&rect, &status_rect, &needed_rect);
+ im_set_preedit_area (&rect, &status_rect, &needed_rect);
preedit_attr = XVaCreateNestedList(0, XNArea, &rect,
XNForeground, fg, XNBackground, bg,
//XNFontSet, TermWin.fontset,
NULL);
}
+
Input_Context = XCreateIC(xim, XNInputStyle, input_style,
XNClientWindow, TermWin.parent[0],
XNFocusWindow, TermWin.parent[0],
- XNDestroyCallback, &ximcallback,
preedit_attr ? XNPreeditAttributes : NULL,
preedit_attr,
status_attr ? XNStatusAttributes : NULL,
status_attr, NULL);
- if (preedit_attr)
- XFree(preedit_attr);
- if (status_attr)
- XFree(status_attr);
+ if (preedit_attr) XFree(preedit_attr);
+ if (status_attr) XFree(status_attr);
+
if (Input_Context == NULL)
{
rxvt_print_error("failed to create input context");
- XCloseIM(xim);
- return False;
+ display->put_xim (input_method);
+ return false;
}
+
if (input_style & XIMPreeditArea)
IMSetStatusPosition ();
+
D_MAIN((stderr, "rxvt_IM_get_IC() - successful connection"));
- return True;
+ return true;
}
-/*
- * X manual pages and include files don't match on some systems:
- * some think this is an XIDProc and others an XIMProc so we can't
- * use the first argument - need to update this to be nice for
- * both types via some sort of configure detection
- */
-/* ARGSUSED */
-/* EXTPROTO */
void
-rxvt_IMInstantiateCallback(Display * unused
- __attribute__ ((unused)), XPointer client_data
- __attribute__ ((unused)), XPointer call_data
- __attribute__ ((unused)))
+rxvt_term::im_cb ()
{
int i, found, had_im;
const char *p;
char **s;
char buf[IMBUFSIZ];
+ im_destroy ();
+
D_MAIN((stderr, "rxvt_IMInstantiateCallback()"));
- if (GET_R->Input_Context)
+ if (Input_Context)
return;
#if defined(HAVE_XSETLOCALE) || defined(HAVE_SETLOCALE)
- if (GET_R->rs[Rs_imLocale])
- setlocale (LC_CTYPE, GET_R->rs[Rs_imLocale]);
+ if (rs[Rs_imLocale])
+ setlocale (LC_CTYPE, rs[Rs_imLocale]);
#endif
- p = GET_R->rs[Rs_inputMethod];
+ p = rs[Rs_inputMethod];
if (p && *p)
{
bool found = false;
{
STRCPY (buf, "@im=");
STRNCAT (buf, s[i], IMBUFSIZ - 5);
- if ((p = XSetLocaleModifiers (buf)) && *p && GET_R->IM_get_IC ())
+ if (IM_get_IC (buf))
{
found = true;
break;
}
/* try with XMODIFIERS env. var. */
- if ((p = XSetLocaleModifiers ("")) && *p
- && GET_R->IM_get_IC ())
+ if (IM_get_IC (""))
goto done;
/* try with no modifiers base IF the user didn't specify an IM */
- if ((p = XSetLocaleModifiers ("@im=none")) && *p
- && GET_R->IM_get_IC () == True)
+ if (IM_get_IC ("@im=none"))
goto done;
done:
#if defined(HAVE_XSETLOCALE) || defined(HAVE_SETLOCALE)
- if (GET_R->rs[Rs_imLocale])
- setlocale (LC_CTYPE, GET_R->locale);
+ if (rs[Rs_imLocale])
+ setlocale (LC_CTYPE, locale);
#endif
}
XGetICValues(Input_Context, XNStatusAttributes, status_attr, NULL);
XFree(status_attr);
- set_preedit_area(&preedit_rect, &status_rect, needed_rect);
+ im_set_preedit_area (&preedit_rect, &status_rect, needed_rect);
preedit_attr = XVaCreateNestedList(0, XNArea, &preedit_rect, NULL);
status_attr = XVaCreateNestedList(0, XNArea, &status_rect, NULL);
NUM_RESOURCES
};
-// see init.C:xa_named, which must be kept in sync
+// see init.C:xa_names, which must be kept in sync
enum {
XA_TEXT = 0,
XA_COMPOUND_TEXT,
KeySym ks_greekmodeswith;
#endif
#ifdef USE_XIM
+ rxvt_xim *input_method;
XIC Input_Context;
XIMStyle input_style;
int event_type;
void create_windows (int argc, const char *const *argv);
void resize_all_windows (unsigned int width, unsigned int height, int ignoreparent);
void window_calc (unsigned int width, unsigned int height);
- void set_preedit_area (XRectangle * preedit_rect, XRectangle * status_rect, XRectangle * needed_rect);
#if USE_XIM
- void set_size (XRectangle *size);
- void set_position (XPoint *pos);
- void set_color (unsigned long *fg, unsigned long *bg);
+ void im_destroy ();
+ void im_cb (); im_watcher im_ev;
+ void im_set_size (XRectangle *size);
+ void im_set_position (XPoint *pos);
+ void im_set_color (unsigned long *fg, unsigned long *bg);
+ void im_set_preedit_area (XRectangle * preedit_rect, XRectangle * status_rect, XRectangle * needed_rect);
+
+ bool IMisRunning ();
+ void IMSendSpot ();
+ bool IM_get_IC (const char *modifiers);
+ void IMSetStatusPosition ();
#endif
void resize_scrollbar ();
void set_colorfgbg ();
int rXParseAllocColor (rxvt_color * screen_in_out, const char *colour);
void set_widthheight (unsigned int width, unsigned int height);
- bool IMisRunning ();
- void IMSendSpot ();
- bool IM_get_IC ();
- void IMSetStatusPosition ();
#ifdef MENUBAR
// menubar.C
#include <unistd.h>
#include <fcntl.h>
+refcounted::refcounted (const char *id)
+{
+ this->id = STRDUP (id);
+}
+
+refcounted::~refcounted ()
+{
+ free (id);
+}
+
+template<class T>
+T *refcache<T>::get (const char *id)
+{
+ for (T **i = begin (); i < end (); ++i)
+ {
+ if (!strcmp (id, (*i)->id))
+ {
+ (*i)->referenced++;
+ return *i;
+ }
+ }
+
+ T *obj = new T (id);
+
+ obj->referenced = 1;
+
+ if (obj && obj->init ())
+ {
+ push_back (obj);
+ return obj;
+ }
+ else
+ {
+ delete obj;
+ return 0;
+ }
+}
+
+template<class T>
+void refcache<T>::put (T *obj)
+{
+ if (!obj)
+ return;
+
+ if (!--obj->referenced)
+ {
+ erase (find (begin (), end (), obj));
+ delete obj;
+ }
+}
+
+template<class T>
+refcache<T>::~refcache ()
+{
+ while (size ())
+ put (*begin ());
+}
+
/////////////////////////////////////////////////////////////////////////////
-rxvt_display::rxvt_display (const char *name)
-: x_watcher (this, &rxvt_display::x_event)
-, selection_owner (0)
+static void
+im_destroy_cb (XIM unused1, XPointer client_data, XPointer unused3)
{
- this->name = STRDUP (name);
+ rxvt_xim *xim = (rxvt_xim *)client_data;
+ rxvt_display *display = xim->display;
+
+ display->xims.erase (find (display->xims.begin (), display->xims.end (), xim));
+
+ display->im_change_cb ();
}
-rxvt_display::~rxvt_display ()
+bool rxvt_xim::init ()
+{
+ display = GET_R->display; //HACK: TODO
+
+ xim = XOpenIM (display->display, NULL, NULL, NULL);
+
+ if (!xim)
+ return false;
+
+ XIMCallback ximcallback;
+ ximcallback.client_data = (XPointer)this;
+ ximcallback.callback = im_destroy_cb;
+
+ XSetIMValues (xim, XNDestroyCallback, &ximcallback, NULL);
+
+ return true;
+}
+
+rxvt_xim::~rxvt_xim ()
+{
+ if (xim)
+ XCloseIM (xim);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+rxvt_display::rxvt_display (const char *id)
+: refcounted (id)
+, x_watcher (this, &rxvt_display::x_event)
+, selection_owner (0)
{
- free (name);
}
-bool rxvt_display::open ()
+bool rxvt_display::init ()
{
- display = XOpenDisplay (name);
+ display = XOpenDisplay (id);
screen = DefaultScreen (display);
root = DefaultRootWindow (display);
x_watcher.start (fd, EVENT_READ);
fcntl (fd, F_SETFL, FD_CLOEXEC);
+ XSelectInput (display, root, PropertyChangeMask);
+ xa_xim_servers = XInternAtom (display, "XIM_SERVERS", 0);
+
return true;
}
-void rxvt_display::close ()
+rxvt_display::~rxvt_display ()
{
x_watcher.stop ();
XCloseDisplay (display);
}
+void rxvt_display::im_change_cb ()
+{
+ for (im_watcher **i = imw.begin (); i != imw.end (); ++i)
+ (*i)->call ();
+}
+
void rxvt_display::x_event (io_watcher &w, short revents)
{
do
XEvent xev;
XNextEvent (display, &xev);
+ //printf ("T %d w %lx\n", xev.type, xev.xany.window);//D
+
+ if (xev.type == PropertyNotify
+ && xev.xany.window == root
+ && xev.xproperty.atom == xa_xim_servers)
+ im_change_cb ();
+
for (int i = xw.size (); i--; )
{
if (!xw[i])
xw[w->active - 1] = 0;
}
+void rxvt_display::reg (im_watcher *w)
+{
+ imw.push_back (w);
+}
+
+void rxvt_display::unreg (im_watcher *w)
+{
+ imw.erase (find (imw.begin (), imw.end (), w));
+}
+
void rxvt_display::set_selection_owner (rxvt_term *owner)
{
if (selection_owner && selection_owner != owner)
selection_owner = owner;
}
-/////////////////////////////////////////////////////////////////////////////
-
-rxvt_displays displays;
-
-rxvt_display *rxvt_displays::get (const char *name)
+rxvt_xim *rxvt_display::get_xim (const char *locale, const char *modifiers)
{
- for (rxvt_display **i = list.begin (); i < list.end (); ++i)
- {
- if (!strcmp (name, (*i)->name))
- {
- (*i)->referenced++;
- return *i;
- }
- }
+ // asprintf is a GNU and *BSD extension.. sorry...
+ char *id;
- rxvt_display *display = new rxvt_display (name);
+ if (asprintf (&id, "%s\n%s", locale, modifiers) < 0)
+ return 0;
- display->referenced = 1;
+ rxvt_xim *xim = xims.get (id);
- if (display && display->open ())
- list.push_back (display);
- else
- {
- delete display;
- display = 0;
- }
+ free (id);
- return display;
+ return xim;
}
-void rxvt_displays::release (rxvt_display *display)
+void rxvt_display::put_xim (rxvt_xim *xim)
{
- if (!--display->referenced)
- {
- display->close ();
- delete display;
- list.erase (find (list.begin (), list.end (), display));
- }
+ xims.put (xim);
}
/////////////////////////////////////////////////////////////////////////////
+
+template refcache<rxvt_display>;
+refcache<rxvt_display> displays;
+
+/////////////////////////////////////////////////////////////////////////////
bool
rxvt_color::set (rxvt_display *display, Pixel p)
struct rxvt_term;
+struct im_watcher;
struct xevent_watcher;
-struct rxvt_display {
+struct refcounted {
int referenced;
- char *name;
+ char *id;
+
+ refcounted (const char *id);
+ bool init () { }
+ ~refcounted ();
+};
+
+template<class T>
+struct refcache : vector<T *> {
+ T *get (const char *id);
+ void put (T *obj);
+ ~refcache ();
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+struct rxvt_xim : refcounted {
+ void destroy ();
+ rxvt_display *display;
+
+//public
+ XIM xim;
+
+ rxvt_xim (const char *id) : refcounted (id) { }
+ bool init ();
+ ~rxvt_xim ();
+};
+
+struct rxvt_display : refcounted {
+ Atom xa_xim_servers;
rxvt_term *selection_owner;
io_manager_vec<xevent_watcher> xw;
+
io_watcher x_watcher; void x_event (io_watcher &w, short revents);
+ refcache<rxvt_xim> xims;
+ vector<im_watcher *> imw;
+
+ void im_change_cb ();
+
//public
Display *display;
int depth;
Colormap cmap;
Window root;
- bool open ();
- void close ();
+ rxvt_display (const char *id);
+ bool init ();
+ ~rxvt_display ();
void reg (xevent_watcher *w);
void unreg (xevent_watcher *w);
-
- rxvt_display (const char *name);
- ~rxvt_display ();
+ void reg (im_watcher *w);
+ void unreg (im_watcher *w);
void set_selection_owner (rxvt_term *owner);
+
+ rxvt_xim *get_xim (const char *locale, const char *modifiers);
+ void put_xim (rxvt_xim *xim);
+};
+
+struct im_watcher : watcher, callback0<void> {
+ template<class O1, class O2>
+ im_watcher (O1 *object, void (O2::*method)())
+ : callback0<void>(object,method)
+ { }
+
+ void start (rxvt_display *display)
+ {
+ display->reg (this);
+ }
+ void stop (rxvt_display *display)
+ {
+ display->unreg (this);
+ }
};
struct xevent_watcher : watcher, callback1<void, XEvent &> {
}
};
-struct rxvt_displays {
- vector<rxvt_display *> list;
-
- rxvt_display *get (const char *name);
- void release (rxvt_display *display);
-};
+extern refcache<rxvt_display> displays;
-extern rxvt_displays displays;
+/////////////////////////////////////////////////////////////////////////////
typedef unsigned long Pixel;
/* ------------------------------------------------------------------------- */
#ifdef USE_XIM
void
-rxvt_term::set_position (XPoint *pos)
+rxvt_term::im_set_position (XPoint *pos)
{
XWindowAttributes xwa;