*** empty log message ***
[dana/urxvt.git] / src / main.C
index b5df58d..e08736b 100644 (file)
@@ -13,7 +13,7 @@
  * Copyright (c) 1997,1998 Oezguer Kesim <kesim@math.fu-berlin.de>
  * Copyright (c) 1998-2001 Geoff Wing <gcw@pobox.com>
  *                              - extensive modifications
- * Copyright (c) 2003-2004 Marc Lehmann <pcg@goof.com>
+ * Copyright (c) 2003-2006 Marc Lehmann <pcg@goof.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 
 #include "../config.h"          /* NECESSARY */
 #include "rxvt.h"               /* NECESSARY */
-#include "main.intpro"          /* PROTOS for internal routines */
+#include "keyboard.h"
+#include "rxvtperl.h"
 
-#include <signal.h>
+#include <limits>
+
+#include <csignal>
+#include <cstring>
 
 #ifdef TTY_GID_SUPPORT
 # include <grp.h>
 # include <termios.h>
 #endif
 
-#include <cstring>
-
 vector<rxvt_term *> rxvt_term::termlist;
 
-static char curlocale[128];
+static char curlocale[128], savelocale[128];
 
 bool
 rxvt_set_locale (const char *locale)
 {
-  if (!locale || !STRNCMP (locale, curlocale, 128))
+  if (!locale || !strncmp (locale, curlocale, 128))
     return false;
 
-  STRNCPY (curlocale, locale, 128);
+  strncpy (curlocale, locale, 128);
   setlocale (LC_CTYPE, curlocale);
   return true;
 }
 
+void
+rxvt_push_locale (const char *locale)
+{
+  strcpy (savelocale, curlocale);
+  rxvt_set_locale (locale);
+}
+
+void
+rxvt_pop_locale ()
+{
+  rxvt_set_locale (savelocale);
+}
+
 #if ENABLE_COMBINING
 class rxvt_composite_vec rxvt_composite;
 
@@ -125,32 +140,14 @@ int rxvt_composite_vec::expand (unicode_t c, wchar_t *r)
 }
 #endif
 
-void *
-rxvt_term::operator new (size_t s)
-{
-  void *p = malloc (s);
-
-  MEMSET (p, 0, s);
-  return p;
-}
-
-void
-rxvt_term::operator delete (void *p, size_t s)
-{
-  free (p);
-}
-
 rxvt_term::rxvt_term ()
     :
+#if TRANSPARENT
     rootwin_ev (this, &rxvt_term::rootwin_cb),
-    termwin_ev (this, &rxvt_term::x_cb),
-    vt_ev (this, &rxvt_term::x_cb),
+#endif
 #ifdef HAVE_SCROLLBARS
     scrollbar_ev (this, &rxvt_term::x_cb),
 #endif
-#ifdef MENUBAR
-    menubar_ev (this, &rxvt_term::x_cb),
-#endif
 #ifdef CURSOR_BLINK
     cursor_blink_ev (this, &rxvt_term::cursor_blink_cb),
 #endif
@@ -172,7 +169,10 @@ rxvt_term::rxvt_term ()
 #ifdef USE_XIM
     im_ev (this, &rxvt_term::im_cb),
 #endif
+    termwin_ev (this, &rxvt_term::x_cb),
+    vt_ev (this, &rxvt_term::x_cb),
     check_ev (this, &rxvt_term::check_cb),
+    flush_ev (this, &rxvt_term::flush_cb),
     destroy_ev (this, &rxvt_term::destroy_cb),
     pty_ev (this, &rxvt_term::pty_cb),
     incr_ev (this, &rxvt_term::incr_cb)
@@ -180,73 +180,85 @@ rxvt_term::rxvt_term ()
   cmdbuf_ptr = cmdbuf_endp = cmdbuf_base;
 
   termlist.push_back (this);
+
+#ifdef KEYSYM_RESOURCE
+  keyboard = new keyboard_manager;
+
+  if (!keyboard)
+    rxvt_fatal ("out of memory, aborting.\n");
+#endif
+}
+
+// clean up the most important stuff, do *not* call x or free mem etc.
+// for use before an emergency exit
+void rxvt_term::emergency_cleanup ()
+{
+  if (cmd_pid)
+    kill (-cmd_pid, SIGHUP);
+
+  delete pty; pty = 0;
 }
 
 rxvt_term::~rxvt_term ()
 {
+  HOOK_INVOKE ((this, HOOK_DESTROY, DT_END));
+
   termlist.erase (find (termlist.begin (), termlist.end(), this));
 
-  if (cmd_fd >= 0)
-    close (cmd_fd);
+  emergency_cleanup ();
 
-#ifndef NO_SETOWNER_TTYDEV
-  privileged_ttydev (RESTORE);
-#endif
-#ifdef UTMP_SUPPORT
-  privileged_utmp (RESTORE);
+#if ENABLE_STYLES
+  for (int i = RS_styleCount; --i; )
+    if (fontset[i] != fontset[0])
+      delete fontset[i];
 #endif
-
-  delete TermWin.fontset;
+  delete fontset[0];
 
   if (display)
     {
+      dDisp;
+
       selection_clear ();
 
-#ifdef MENUBAR
-      if (menubarGC) XFreeGC (display->display, menubarGC);
+#ifdef USE_XIM
+      im_destroy ();
 #endif
 #ifdef XTERM_SCROLLBAR
-      if (xscrollbarGC) XFreeGC (display->display, xscrollbarGC);
-      if (ShadowGC)     XFreeGC (display->display, ShadowGC);
+      if (xscrollbarGC) XFreeGC (disp, xscrollbarGC);
+      if (ShadowGC)     XFreeGC (disp, ShadowGC);
 #endif
 #ifdef PLAIN_SCROLLBAR
-      if (pscrollbarGC) XFreeGC (display->display, pscrollbarGC);
+      if (pscrollbarGC) XFreeGC (disp, pscrollbarGC);
 #endif
 #ifdef NEXT_SCROLLBAR
-      if (blackGC)      XFreeGC (display->display, blackGC);
-      if (whiteGC)      XFreeGC (display->display, whiteGC);
-      if (grayGC)       XFreeGC (display->display, grayGC);
-      if (darkGC)       XFreeGC (display->display, darkGC);
-      if (stippleGC)    XFreeGC (display->display, stippleGC);
-      if (dimple)       XFreePixmap (display->display, dimple);
-      if (upArrow)      XFreePixmap (display->display, upArrow);
-      if (downArrow)    XFreePixmap (display->display, downArrow);
-      if (upArrowHi)    XFreePixmap (display->display, upArrowHi);
-      if (downArrowHi)  XFreePixmap (display->display, downArrowHi);
+      if (blackGC)      XFreeGC (disp, blackGC);
+      if (whiteGC)      XFreeGC (disp, whiteGC);
+      if (grayGC)       XFreeGC (disp, grayGC);
+      if (darkGC)       XFreeGC (disp, darkGC);
+      if (stippleGC)    XFreeGC (disp, stippleGC);
+      if (dimple)       XFreePixmap (disp, dimple);
+      if (upArrow)      XFreePixmap (disp, upArrow);
+      if (downArrow)    XFreePixmap (disp, downArrow);
+      if (upArrowHi)    XFreePixmap (disp, upArrowHi);
+      if (downArrowHi)  XFreePixmap (disp, downArrowHi);
 #endif
-#if defined(MENUBAR) || defined(RXVT_SCROLLBAR)
-      if (topShadowGC)  XFreeGC (display->display, topShadowGC);
-      if (botShadowGC)  XFreeGC (display->display, botShadowGC);
-      if (scrollbarGC)  XFreeGC (display->display, scrollbarGC);
+#ifdef RXVT_SCROLLBAR
+      if (topShadowGC)  XFreeGC (disp, topShadowGC);
+      if (botShadowGC)  XFreeGC (disp, botShadowGC);
+      if (scrollbarGC)  XFreeGC (disp, scrollbarGC);
 #endif
-      if (TermWin.gc)   XFreeGC (display->display, TermWin.gc);
+      if (gc)   XFreeGC (disp, gc);
 
-#if defined(MENUBAR) && (MENUBAR_MAX > 1)
-      delete menuBar.drawable;
-      //if (menuBar.win)
-      //  XDestroyWindow (display->display, menuBar.win);
-#endif
-      delete TermWin.drawable;
+      delete drawable;
       // destroy all windows
-      if (TermWin.parent[0])
-        XDestroyWindow (display->display, TermWin.parent[0]);
+      if (parent[0])
+        XDestroyWindow (dispparent[0]);
     }
 
   // TODO: free pixcolours, colours should become part of rxvt_display
-
-  delete PixColorsFocused;
-#ifdef OFF_FOCUS_FADING
-  delete PixColorsUnFocused;
+  delete pix_colors_focused;
+#if OFF_FOCUS_FADING
+  delete pix_colors_unfocused;
 #endif
 
   displays.put (display);
@@ -255,7 +267,7 @@ rxvt_term::~rxvt_term ()
 
   /* clear all resources */
   for (int i = 0; i < allocated.size (); i++)
-    free (allocated[i]);
+    free (allocated [i]);
 
   free (selection.text);
   // TODO: manage env vars in child only(!)
@@ -264,32 +276,50 @@ rxvt_term::~rxvt_term ()
   free (env_term);
   free (env_colorfgbg);
   free (locale);
-#if 0
-  free (codeset);
-#endif
+  free (v_buffer);
+  free (incr_buf);
 
   delete envv;
   delete argv;
+
+#ifdef KEYSYM_RESOURCE
+  delete keyboard;
+#endif
+}
+
+void
+rxvt_term::child_exit ()
+{
+  cmd_pid = 0;
+
+  if (!OPTION (Opt_hold))
+    destroy ();
 }
 
 void
 rxvt_term::destroy ()
 {
+  if (destroy_ev.active)
+    return;
+
+#if ENABLE_OVERLAY
+  scr_overlay_off ();
+#endif
+
   if (display)
     {
-      rootwin_ev.stop (display);
-      termwin_ev.stop (display);
-      vt_ev.stop (display);
-#ifdef USE_XIM
-      im_destroy ();
+#if USE_XIM
       im_ev.stop (display);
 #endif
-#ifdef HAVE_SCROLLBARS
+#if HAVE_SCROLLBARS
       scrollbar_ev.stop (display);
 #endif
-#ifdef MENUBAR
-      menubar_ev.stop (display);
+#if TRANSPARENT
+      rootwin_ev.stop (display);
 #endif
+      incr_ev.stop ();
+      termwin_ev.stop (display);
+      vt_ev.stop (display);
     }
 
   check_ev.stop ();
@@ -316,378 +346,315 @@ rxvt_term::destroy ()
 void
 rxvt_term::destroy_cb (time_watcher &w)
 {
-  SET_R (this);
+  make_current ();
 
   delete this;
 }
 
 /*----------------------------------------------------------------------*/
-/* rxvt_init () */
+/*
+ * Exit gracefully, clearing the utmp entry and restoring tty attributes
+ * TODO: if debugging, this should free up any known resources if we can
+ */
+static XErrorHandler old_xerror_handler;
+
+static void
+rxvt_emergency_cleanup ()
+{
+  for (rxvt_term **t = rxvt_term::termlist.begin (); t < rxvt_term::termlist.end (); t++)
+    (*t)->emergency_cleanup ();
+}
+
+#if ENABLE_FRILLS
+static void
+print_x_error (Display *dpy, XErrorEvent *event)
+{
+    char buffer[BUFSIZ];
+    char mesg[BUFSIZ];
+    char number[32];
+    char *mtype = "XlibMessage";
+    XGetErrorText(dpy, event->error_code, buffer, BUFSIZ);
+    XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", mesg, BUFSIZ);
+    rxvt_warn ("An X Error occured, trying to continue after report.\n");
+    rxvt_warn ("%s:  %s\n", mesg, buffer);
+    XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d", mesg, BUFSIZ);
+    rxvt_warn (strncat (mesg, "\n", BUFSIZ), event->request_code);
+    sprintf(number, "%d", event->request_code);
+    XGetErrorDatabaseText(dpy, "XRequest", number, "", buffer, BUFSIZ);
+    rxvt_warn ("(which is %s)\n", buffer);
+    if (event->request_code >= 128) {
+       XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d",
+                             mesg, BUFSIZ);
+        rxvt_warn (strncat (mesg, "\n", BUFSIZ), event->minor_code);
+    }
+    if ((event->error_code == BadWindow) ||
+              (event->error_code == BadPixmap) ||
+              (event->error_code == BadCursor) ||
+              (event->error_code == BadFont) ||
+              (event->error_code == BadDrawable) ||
+              (event->error_code == BadColor) ||
+              (event->error_code == BadGC) ||
+              (event->error_code == BadIDChoice) ||
+              (event->error_code == BadValue) ||
+              (event->error_code == BadAtom)) {
+       if (event->error_code == BadValue)
+           XGetErrorDatabaseText(dpy, mtype, "Value", "Value 0x%x",
+                                 mesg, BUFSIZ);
+       else if (event->error_code == BadAtom)
+           XGetErrorDatabaseText(dpy, mtype, "AtomID", "AtomID 0x%x",
+                                 mesg, BUFSIZ);
+       else
+           XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x",
+                                 mesg, BUFSIZ);
+       rxvt_warn (strncat (mesg, "\n", BUFSIZ), event->resourceid);
+    }
+    XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d", 
+                         mesg, BUFSIZ);
+    rxvt_warn (strncat (mesg, "\n", BUFSIZ), event->serial);
+}
+#endif
+
+int
+rxvt_xerror_handler (Display *display, XErrorEvent *event)
+{
+  if (GET_R->allowedxerror == -1)
+    GET_R->allowedxerror = event->error_code;
+  else
+    {
+      // GET_R is most likely not the terminal which caused the error,
+      // so just output the error and continue
+#if ENABLE_FRILLS
+      print_x_error (display, event);
+#else
+      old_xerror_handler (display, event);
+#endif
+    }
+
+  return 0;
+}
+
+int
+rxvt_xioerror_handler (Display *display)
+{
+  rxvt_warn ("X connection to '%s' broken, unable to recover, exiting.\n",
+             DisplayString (display));
+  rxvt_emergency_cleanup ();
+  _exit (EXIT_FAILURE);
+}
+
+/*----------------------------------------------------------------------*/
 bool
 rxvt_term::init (int argc, const char *const *argv)
 {
   SET_R (this);
+  set_locale ("");
+  set_environ (envv); // few things in X do not call setlocale :(
 
   if (!init_vars ())
     return false;
 
-  /*
-   * Save and then give up any super-user privileges
-   * If we need privileges in any area then we must specifically request it.
-   * We should only need to be root in these cases:
-   *  1.  write utmp entries on some systems
-   *  2.  chown tty on some systems
-   */
-  privileges (SAVE);
-  privileges (IGNORE);
-
   init_secondary ();
 
   const char **cmd_argv = init_resources (argc, argv);
 
-  set_locale ("");
-
-#if MENUBAR_MAX
-  menubar_read (rs[Rs_menu]);
+#ifdef KEYSYM_RESOURCE
+  keyboard->register_done ();
 #endif
+
 #ifdef HAVE_SCROLLBARS
-  if (Options & Opt_scrollBar)
+  if (OPTION (Opt_scrollBar))
     scrollBar.setIdle ();    /* set existence for size calculations */
 #endif
 
+#if ENABLE_PERL
+  if (!rs[Rs_perl_ext_1])
+    rs[Rs_perl_ext_1] = "default";
+
+  if ((rs[Rs_perl_ext_1] && *rs[Rs_perl_ext_1])
+      || (rs[Rs_perl_ext_2] && *rs[Rs_perl_ext_2])
+      || (rs[Rs_perl_eval] && *rs[Rs_perl_eval]))
+    {
+      rxvt_perl.init (this);
+      HOOK_INVOKE ((this, HOOK_INIT, DT_END));
+    }
+#endif
+
+  pty = rxvt_new_ptytty ();
+
   create_windows (argc, argv);
 
+  dDisp;
+
   init_xlocale ();
 
-  scr_reset ();         /* initialize screen */
+  scr_reset (); // initialize screen
 
 #if 0
-  XSynchronize (display->display, True);
+  XSynchronize (disp, True);
 #endif
 
 #ifdef HAVE_SCROLLBARS
-  if (Options & Opt_scrollBar)
+  if (OPTION (Opt_scrollBar))
     resize_scrollbar ();      /* create and map scrollbar */
 #endif
-#if (MENUBAR_MAX)
-  if (menubar_visible ())
-    XMapWindow (display->display, menuBar.win);
-#endif
 #ifdef TRANSPARENT
-  if (Options & Opt_transparent)
+  if (OPTION (Opt_transparent))
     {
-      XSelectInput (display->display, display->root, PropertyChangeMask);
+      XSelectInput (disp, display->root, PropertyChangeMask);
       check_our_parents ();
+      rootwin_ev.start (display, display->root);
     }
 #endif
 
-  rootwin_ev.start (display, display->root);
+  XMapWindow (disp, vt);
+  XMapWindow (disp, parent[0]);
 
-  XMapWindow (display->display, TermWin.vt);
-  XMapWindow (display->display, TermWin.parent[0]);
+  set_colorfgbg ();
 
   init_command (cmd_argv);
 
-  pty_ev.start (cmd_fd, EVENT_READ);
+  free (cmd_argv);
+
+  if (pty->pty >= 0)
+    pty_ev.start (pty->pty, EVENT_READ);
 
   check_ev.start ();
 
+  HOOK_INVOKE ((this, HOOK_START, DT_END));
+
   return true;
 }
 
-static int (*old_xerror_handler) (Display *dpy, XErrorEvent *event);
+static struct sig_handlers
+{
+  sig_watcher sw_chld, sw_term, sw_int;
+  
+  void sig_chld (sig_watcher &w)
+  {
+    // we are being called for every SIGCHLD, find the corresponding term
+    int pid;
+
+    while ((pid = waitpid (-1, NULL, WNOHANG)) > 0)
+      for (rxvt_term **t = rxvt_term::termlist.begin (); t < rxvt_term::termlist.end (); t++)
+        if (pid == (*t)->cmd_pid)
+          {
+            (*t)->child_exit ();
+            break;
+          }
+  }
+
+  /*
+   * Catch a fatal signal and tidy up before quitting
+   */
+  void
+  sig_term (sig_watcher &w)
+  {
+#ifdef DEBUG_CMD
+    rxvt_warn ("caught signal %d, exiting.\n", w.signum);
+#endif
+    rxvt_emergency_cleanup ();
+    signal (w.signum, SIG_DFL);
+    kill (getpid (), w.signum);
+  }
+
+  sig_handlers ()
+  : sw_chld (this, &sig_handlers::sig_chld),
+    sw_term (this, &sig_handlers::sig_term),
+    sw_int  (this, &sig_handlers::sig_term)
+  {
+  }
+} sig_handlers;
+
+char **rxvt_environ; // startup environment
 
 void
-rxvt_init_signals ()
+rxvt_init ()
 {
-  /* install exit handler for cleanup */
-#if 0
-#ifdef HAVE_ATEXIT
-  atexit (rxvt_clean_exit);
+  uid_t uid = getuid ();
+  gid_t gid = getgid ();
+      
+  // before doing anything else, check for setuid/setgid operation,
+  // start the helper process and drop privileges
+  if (uid != geteuid ()
+      || gid != getegid ())
+    {
+#if PTYTTY_HELPER
+      rxvt_ptytty_server ();
 #else
+      rxvt_warn ("running setuid/setgid without pty helper compiled in, continuing unprivileged.\n");
 #endif
+
+      // drop privileges
+#if HAVE_SETRESUID
+      setresgid (gid, gid, gid);
+      setresuid (uid, uid, uid);
+#elif HAVE_SETREUID
+      setregid (gid, gid);
+      setreuid (uid, uid);
+#elif HAVE_SETUID
+      setgid (gid);
+      setuid (uid);
 #endif
 
-  struct sigaction sa;
+      if (uid != geteuid ()
+          || gid != getegid ())
+        rxvt_fatal ("unable to drop privileges, aborting.\n");
+    }
+
+  rxvt_environ = environ;
+
+  signal (SIGHUP,  SIG_IGN);
+  signal (SIGPIPE, SIG_IGN);
 
-  sigfillset (&sa.sa_mask);
-  sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
-  sa.sa_handler = SIG_IGN;           sigaction (SIGHUP , &sa, 0);
-  sa.sa_handler = SIG_IGN;           sigaction (SIGPIPE, &sa, 0);
-  sa.sa_handler = rxvt_Exit_signal;  sigaction (SIGINT , &sa, 0);
-  sa.sa_handler = rxvt_Exit_signal;  sigaction (SIGQUIT, &sa, 0);
-  sa.sa_handler = rxvt_Exit_signal;  sigaction (SIGTERM, &sa, 0);
-  sa.sa_handler = rxvt_Child_signal; sigaction (SIGCHLD, &sa, 0);
+  sig_handlers.sw_chld.start (SIGCHLD);
+  sig_handlers.sw_term.start (SIGTERM);
+  sig_handlers.sw_int.start  (SIGINT);
 
   /* need to trap SIGURG for SVR4 (Unixware) rlogin */
   /* signal (SIGURG, SIG_DFL); */
 
   old_xerror_handler = XSetErrorHandler ((XErrorHandler) rxvt_xerror_handler);
-  //XSetIOErrorHandler ((XErrorHandler) rxvt_xioerror_handler);
-}
-
-/* ------------------------------------------------------------------------- *
- *                       SIGNAL HANDLING & EXIT HANDLER                      *
- * ------------------------------------------------------------------------- */
-/*
- * Catch a SIGCHLD signal and exit if the direct child has died
- */
-
-void rxvt_term::child_exited (int pid)
-{
-  for (rxvt_term **t = termlist.begin (); t < termlist.end (); t++)
-    if (pid == (*t)->cmd_pid)
-      {
-        (*t)->destroy ();
-        break;
-      }
-}
-
-/* ARGSUSED */
-/* EXTPROTO */
-RETSIGTYPE
-rxvt_Child_signal (int sig __attribute__ ((unused)))
-{
-  int pid, save_errno = errno;
-
-  while ((pid = waitpid (-1, NULL, WNOHANG)) > 0)
-    rxvt_term::child_exited (pid);
-
-  errno = save_errno;
-}
-
-/*
- * Catch a fatal signal and tidy up before quitting
- */
-/* EXTPROTO */
-RETSIGTYPE
-rxvt_Exit_signal (int sig)
-{
-  signal (sig, SIG_DFL);
-#ifdef DEBUG_CMD
-  rxvt_warn ("caught signal %d, exiting.\n", sig);
-#endif
-  rxvt_clean_exit ();
-  kill (getpid (), sig);
-}
-
-/* INTPROTO */
-int
-rxvt_xerror_handler (Display *display, XErrorEvent *event)
-{
-  if (GET_R->allowedxerror == -1)
-    GET_R->allowedxerror = event->error_code;
-  else
-    {
-      old_xerror_handler (display, event);
-      GET_R->destroy ();
-    }
-
-  return 0;
-}
+  // TODO: handle this with exceptions and tolerate the memory loss
+  XSetIOErrorHandler (rxvt_xioerror_handler);
 
-/*----------------------------------------------------------------------*/
-/*
- * Exit gracefully, clearing the utmp entry and restoring tty attributes
- * TODO: if debugging, this should free up any known resources if we can
- */
-/* EXTPROTO */
-void
-rxvt_clean_exit ()
-{
-  // TODO: rxvtd should clean up all ressources
-  if (GET_R)
-    GET_R->destroy ();
+  XrmInitialize ();
 }
 
 /* ------------------------------------------------------------------------- *
  *                         MEMORY ALLOCATION WRAPPERS                        *
  * ------------------------------------------------------------------------- */
-/* EXTPROTO */
-void           *
+void *
 rxvt_malloc (size_t size)
 {
-  void           *p;
+  void *p = malloc (size);
 
-  p = malloc (size);
-  if (p)
-    return p;
+  if (!p)
+    rxvt_fatal ("memory allocation failure. aborting.\n");
 
-  fprintf (stderr, RESNAME ": memory allocation failure.  Aborting");
-  rxvt_clean_exit ();
-  exit (EXIT_FAILURE);
-  /* NOTREACHED */
+  return p;
 }
 
-/* EXTPROTO */
-void           *
+void *
 rxvt_calloc (size_t number, size_t size)
 {
-  void           *p;
+  void *p = calloc (number, size);
 
-  p = calloc (number, size);
-  if (p)
-    return p;
+  if (!p)
+    rxvt_fatal ("memory allocation failure. aborting.\n");
 
-  fprintf (stderr, RESNAME ": memory allocation failure.  Aborting");
-  rxvt_clean_exit ();
-  exit (EXIT_FAILURE);
-  /* NOTREACHED */
+  return p;
 }
 
-/* EXTPROTO */
 void           *
 rxvt_realloc (void *ptr, size_t size)
 {
-  void           *p;
+  void *p = realloc (ptr, size);
 
-  if (ptr)
-    p = realloc (ptr, size);
-  else
-    p = malloc (size);
-  if (p)
-    return p;
-
-  fprintf (stderr, RESNAME ": memory allocation failure.  Aborting");
-  rxvt_clean_exit ();
-  exit (EXIT_FAILURE);
-  /* NOTREACHED */
-}
+  if (!p)
+    rxvt_fatal ("memory allocation failure. aborting.\n");
 
-/* ------------------------------------------------------------------------- *
- *                            PRIVILEGED OPERATIONS                          *
- * ------------------------------------------------------------------------- */
-/* take care of suid/sgid super-user (root) privileges */
-void
-rxvt_term::privileges (int mode)
-{
-#if ! defined(__CYGWIN32__)
-# if !defined(HAVE_SETEUID) && defined(HAVE_SETREUID)
-  /* setreuid () is the poor man's setuid (), seteuid () */
-#  define seteuid(a)    setreuid(-1, (a))
-#  define setegid(a)    setregid(-1, (a))
-#  define HAVE_SETEUID
-# endif
-# ifdef HAVE_SETEUID
-  switch (mode)
-    {
-      case IGNORE:
-        /*
-         * change effective uid/gid - not real uid/gid - so we can switch
-         * back to root later, as required
-         */
-        seteuid (getuid ());
-        setegid (getgid ());
-        break;
-      case SAVE:
-        euid = geteuid ();
-        egid = getegid ();
-        break;
-      case RESTORE:
-        seteuid (euid);
-        setegid (egid);
-        break;
-    }
-# else
-  switch (mode)
-    {
-      case IGNORE:
-        setuid (getuid ());
-        setgid (getgid ());
-        /* FALLTHROUGH */
-      case SAVE:
-        /* FALLTHROUGH */
-      case RESTORE:
-        break;
-    }
-# endif
-#endif
-}
-
-#ifdef UTMP_SUPPORT
-void
-rxvt_term::privileged_utmp (char action)
-{
-  D_MAIN ((stderr, "rxvt_privileged_utmp (%c); waiting for: %c (pid: %d)",
-          action, next_utmp_action, getpid ()));
-  if (next_utmp_action != action || (action != SAVE && action != RESTORE)
-      || (Options & Opt_utmpInhibit)
-      || ttydev == NULL || *ttydev == '\0')
-    return;
-
-  privileges (RESTORE);
-  if (action == SAVE)
-    {
-      next_utmp_action = RESTORE;
-      makeutent (ttydev, rs[Rs_display_name]);
-    }
-  else
-    {                    /* action == RESTORE */
-      next_utmp_action = IGNORE;
-      cleanutent ();
-    }
-  privileges (IGNORE);
-}
-#endif
-
-#ifndef NO_SETOWNER_TTYDEV
-void
-rxvt_term::privileged_ttydev (char action)
-{
-  D_MAIN ((stderr,
-          "privileged_ttydev (%c); waiting for: %c (pid: %d)",
-          action, next_tty_action, getpid ()));
-  if (next_tty_action != action || (action != SAVE && action != RESTORE)
-      || ttydev == NULL || *ttydev == '\0')
-    return;
-
-  privileges (RESTORE);
-
-  if (action == SAVE)
-    {
-      next_tty_action = RESTORE;
-# ifndef RESET_TTY_TO_COMMON_DEFAULTS
-      /* store original tty status for restoration rxvt_clean_exit () -- rgg 04/12/95 */
-      if (lstat (ttydev, &ttyfd_stat) < 0)       /* you lose out */
-        next_tty_action = IGNORE;
-      else
-# endif
-
-        {
-          chown (ttydev, getuid (), ttygid);      /* fail silently */
-          chmod (ttydev, ttymode);
-# ifdef HAVE_REVOKE
-          revoke (ttydev);
-# endif
-
-        }
-    }
-  else
-    {                    /* action == RESTORE */
-      next_tty_action = IGNORE;
-# ifndef RESET_TTY_TO_COMMON_DEFAULTS
-      chmod (ttydev, ttyfd_stat.st_mode);
-      chown (ttydev, ttyfd_stat.st_uid, ttyfd_stat.st_gid);
-# else
-      chmod (ttydev,
-            (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH));
-      chown (ttydev, 0, 0);
-# endif
-
-    }
-
-  privileges (IGNORE);
-
-# ifndef RESET_TTY_TO_COMMON_DEFAULTS
-  D_MAIN ((stderr, "%s \"%s\": mode %03o, uid %d, gid %d",
-          action == RESTORE ? "Restoring" : (action ==
-                                             SAVE ? "Saving" :
-                                             "UNKNOWN ERROR for"), ttydev,
-          ttyfd_stat.st_mode, ttyfd_stat.st_uid,
-          ttyfd_stat.st_gid));
-# endif
+  return p;
 }
-#endif
 
 /*----------------------------------------------------------------------*/
 /*
@@ -695,54 +662,64 @@ rxvt_term::privileged_ttydev (char action)
  * if width/height are non-zero then override calculated width/height
  */
 void
-rxvt_term::window_calc (unsigned int width, unsigned int height)
+rxvt_term::window_calc (unsigned int newwidth, unsigned int newheight)
 {
-  short           recalc_x, recalc_y;
-  int             x, y, sb_w, mb_h, flags;
-  unsigned int    w, h;
-  unsigned int    max_width, max_height;
+  short recalc_x, recalc_y;
+  int x, y, sb_w, flags;
+  unsigned int w, h;
+  unsigned int max_width, max_height;
+  dDisp;
 
   D_SIZE ((stderr, "< Cols/Rows: %3d x %3d ; Width/Height: %4d x %4d",
-          TermWin.ncol, TermWin.nrow, szHint.width,
-          szHint.height));
+          ncol, nrow, szHint.width, szHint.height));
+
   szHint.flags = PMinSize | PResizeInc | PBaseSize | PWinGravity;
   szHint.win_gravity = NorthWestGravity;
   /* szHint.min_aspect.x = szHint.min_aspect.y = 1; */
 
   recalc_x = recalc_y = 0;
   flags = 0;
+
   if (!parsed_geometry)
     {
       parsed_geometry = 1;
+
       if (rs[Rs_geometry])
         flags = XParseGeometry (rs[Rs_geometry], &x, &y, &w, &h);
+
       if (flags & WidthValue)
         {
-          TermWin.ncol = BOUND_POSITIVE_INT16 (w);
+          ncol = clamp (w, 0, std::numeric_limits<int16_t>::max ());
           szHint.flags |= USSize;
         }
+
       if (flags & HeightValue)
         {
-          TermWin.nrow = BOUND_POSITIVE_INT16 (h);
+          nrow = clamp (h, 0, std::numeric_limits<int16_t>::max ());
           szHint.flags |= USSize;
         }
+
       if (flags & XValue)
         {
           szHint.x = x;
           szHint.flags |= USPosition;
+
           if (flags & XNegative)
             {
               recalc_x = 1;
               szHint.win_gravity = NorthEastGravity;
             }
         }
+
       if (flags & YValue)
         {
           szHint.y = y;
           szHint.flags |= USPosition;
+
           if (flags & YNegative)
             {
               recalc_y = 1;
+
               if (szHint.win_gravity == NorthEastGravity)
                 szHint.win_gravity = SouthEastGravity;
               else
@@ -752,72 +729,63 @@ rxvt_term::window_calc (unsigned int width, unsigned int height)
     }
 
   /* TODO: BOUNDS */
-  TermWin.width = TermWin.ncol * TermWin.fwidth;
-  TermWin.height = TermWin.nrow * TermWin.fheight;
-  max_width = MAX_COLS * TermWin.fwidth;
-  max_height = MAX_ROWS * TermWin.fheight;
+  width = ncol * fwidth;
+  height = nrow * fheight;
+  max_width = MAX_COLS * fwidth;
+  max_height = MAX_ROWS * fheight;
 
-  szHint.base_width = szHint.base_height = 2 * TermWin.int_bwidth;
+  szHint.base_width = szHint.base_height = 2 * int_bwidth;
 
-  sb_w = mb_h = 0;
-  window_vt_x = window_vt_y = TermWin.int_bwidth;
+  sb_w = 0;
+  window_vt_x = window_vt_y = int_bwidth;
 
-  if (scrollbar_visible ())
+  if (scrollBar.state)
     {
       sb_w = scrollbar_TotalWidth ();
       szHint.base_width += sb_w;
-      if (!(Options & Opt_scrollBar_right))
+      if (!OPTION (Opt_scrollBar_right))
         window_vt_x += sb_w;
     }
 
-  if (menubar_visible ())
-    {
-      mb_h = menuBar_TotalHeight ();
-      szHint.base_height += mb_h;
-      window_vt_y += mb_h;
-    }
-
-  szHint.width_inc = TermWin.fwidth;
-  szHint.height_inc = TermWin.fheight;
+  szHint.width_inc = fwidth;
+  szHint.height_inc = fheight;
   szHint.min_width = szHint.base_width + szHint.width_inc;
   szHint.min_height = szHint.base_height + szHint.height_inc;
 
-  if (width && width - szHint.base_width < max_width)
+  if (newwidth && newwidth - szHint.base_width < max_width)
     {
-      szHint.width = width;
-      TermWin.width = width - szHint.base_width;
+      szHint.width = newwidth;
+      width = newwidth - szHint.base_width;
     }
   else
     {
-      MIN_IT (TermWin.width, max_width);
-      szHint.width = szHint.base_width + TermWin.width;
+      min_it (width, max_width);
+      szHint.width = szHint.base_width + width;
     }
 
-  if (height && height - szHint.base_height < max_height)
+  if (newheight && newheight - szHint.base_height < max_height)
     {
-      szHint.height = height;
-      TermWin.height = height - szHint.base_height;
+      szHint.height = newheight;
+      height = newheight - szHint.base_height;
     }
   else
     {
-      MIN_IT (TermWin.height, max_height);
-      szHint.height = szHint.base_height + TermWin.height;
+      min_it (height, max_height);
+      szHint.height = szHint.base_height + height;
     }
 
-  if (scrollbar_visible () && (Options & Opt_scrollBar_right))
+  if (scrollBar.state && OPTION (Opt_scrollBar_right))
     window_sb_x = szHint.width - sb_w;
 
   if (recalc_x)
-    szHint.x += (DisplayWidth (display->display, DefaultScreen (display->display))
-                 - szHint.width - 2 * TermWin.ext_bwidth);
+    szHint.x += DisplayWidth  (disp, display->screen) - szHint.width  - 2 * ext_bwidth;
   if (recalc_y)
-    szHint.y += (DisplayHeight (display->display, DefaultScreen (display->display))
-                 - szHint.height - 2 * TermWin.ext_bwidth);
+    szHint.y += DisplayHeight (disp, display->screen) - szHint.height - 2 * ext_bwidth;
 
-  TermWin.ncol = TermWin.width / TermWin.fwidth;
-  TermWin.nrow = TermWin.height / TermWin.fheight;
+  ncol = width / fwidth;
+  nrow = height / fheight;
   D_SIZE ((stderr, "> Cols/Rows: %3d x %3d ; Width/Height: %4d x %4d",
-          TermWin.ncol, TermWin.nrow, szHint.width,
+          ncol, nrow, szHint.width,
           szHint.height));
   return;
 }
@@ -830,75 +798,121 @@ rxvt_term::window_calc (unsigned int width, unsigned int height)
 void
 rxvt_term::tt_winch ()
 {
+  if (pty->pty < 0)
+    return;
+
   struct winsize ws;
 
-  if (cmd_fd < 0)
-    return;
+  ws.ws_col = ncol;
+  ws.ws_row = nrow;
+  ws.ws_xpixel = width;
+  ws.ws_ypixel = height;
+  (void)ioctl (pty->pty, TIOCSWINSZ, &ws);
 
-  ws.ws_col = TermWin.ncol;
-  ws.ws_row = TermWin.nrow;
-  ws.ws_xpixel = ws.ws_ypixel = 0;
-#ifndef DEBUG_SIZE
-  (void)ioctl (cmd_fd, TIOCSWINSZ, &ws);
-#else
-  if (ioctl (cmd_fd, TIOCSWINSZ, &ws) < 0)
-    D_SIZE ((stderr, "Failed to send TIOCSWINSZ to fd %d", fd));
-# ifdef SIGWINCH
-  else if (cmd_pid)               /* force through to the command */
-    kill (cmd_pid, SIGWINCH);
-# endif
+#if 0
+  // TIOCSWINSZ⎈ is supposed to do this automatically and correctly
+  if (cmd_pid)               /* force through to the command */
+    kill (-cmd_pid, SIGWINCH);
 #endif
 }
 
 /*----------------------------------------------------------------------*/
-/* rxvt_change_font () - Switch to a new font */
-/*
+/* set_fonts () - load and set the various fonts
+ *
  * init = 1   - initialize
  *
  * fontname == FONT_UP  - switch to bigger font
  * fontname == FONT_DN  - switch to smaller font
  */
 bool
-rxvt_term::change_font (const char *fontname)
+rxvt_term::set_fonts ()
 {
-  if (fontname == FONT_UP)
-    {
-      // TODO
-    }
-  else if (fontname == FONT_DN)
+  rxvt_fontset *fs = new rxvt_fontset (this);
+  rxvt_fontprop prop;
+
+  if (!fs
+      || !fs->populate (rs[Rs_font] ? rs[Rs_font] : "fixed")
+      || !fs->realize_font (1))
     {
-      // TODO
+      delete fs;
+      return false;
     }
-  else
+
+#if ENABLE_STYLES
+  for (int i = RS_styleCount; --i; )
+    if (fontset[i] != fontset[0])
+      delete fontset[i];
+#endif
+
+  delete fontset[0];
+  fontset[0] = fs;
+
+  prop = (*fs)[1]->properties ();
+  prop.height += lineSpace;
+  fs->set_prop (prop);
+
+  fwidth  = prop.width;
+  fheight = prop.height;
+  fbase   = prop.ascent;
+
+  for (int style = 1; style < 4; style++)
     {
-      rxvt_fontset *fs = new rxvt_fontset (this);
+#if ENABLE_STYLES
+      const char *res = rs[Rs_font + style];
 
-      if (fs && fs->populate (fontname ? fontname : "fixed"))
+      if (res && !*res)
+        fontset[style] = fontset[0];
+      else
         {
-          delete TermWin.fontset;
-          TermWin.fontset = fs;
-          TermWin.fwidth  = fs->base_font ()->width;
-          TermWin.fheight = fs->base_font ()->height;
-          TermWin.fbase   = fs->base_font ()->ascent;
+          fontset[style] = fs = new rxvt_fontset (this);
+          rxvt_fontprop prop2 = prop;
 
-          if (TermWin.parent[0])
+          if (res)
+            prop2.weight = prop2.slant = rxvt_fontprop::unset;
+          else
             {
-              resize_all_windows (0, 0, 0);
-              scr_remap_chars ();
-              scr_touch (true);
-            }   
+              res = fontset[0]->fontdesc;
+
+              if (SET_STYLE (0, style) & RS_Bold)   prop2.weight = rxvt_fontprop::bold;
+              if (SET_STYLE (0, style) & RS_Italic) prop2.slant  = rxvt_fontprop::italic;
+            }
 
-          return true;
+          fs->populate (res);
+          fs->set_prop (prop2);
         }
+#else
+      fontset[style] = fontset[0];
+#endif
     }
 
-  return false;
+  if (parent[0])
+    {
+      resize_all_windows (0, 0, 0);
+      scr_remap_chars ();
+      scr_touch (true);
+    }   
+
+  return true;
 }
 
-bool
-rxvt_term::font_up_down (int n, int direction)
+void rxvt_term::set_string_property (Atom prop, const char *str, int len)
+{
+  XChangeProperty (display->display, parent[0],
+                   prop, XA_STRING, 8, PropModeReplace,
+                   (const unsigned char *)str, len >= 0 ? len : strlen (str));
+}
+
+void rxvt_term::set_utf8_property (Atom prop, const char *str, int len)
 {
-  return false;
+  wchar_t *ws = rxvt_mbstowcs (str, len);
+  char *s = rxvt_wcstoutf8 (ws);
+
+  XChangeProperty (display->display, parent[0],
+                   prop, xa[XA_UTF8_STRING], 8, PropModeReplace,
+                   (const unsigned char *)s, strlen (s));
+
+  free (s);
+  free (ws);
 }
 
 /*----------------------------------------------------------------------*/
@@ -907,38 +921,18 @@ rxvt_term::font_up_down (int n, int direction)
 void
 rxvt_term::set_title (const char *str)
 {
-#ifdef SMART_WINDOW_TITLE
-  char *name;
-
-  if (!XFetchName (display->display, TermWin.parent[0], &name))
-    name = NULL;
-
-  if (name == NULL || STRCMP (name, str))
-#endif
-    XStoreName (display->display, TermWin.parent[0], str);
-
-#ifdef SMART_WINDOW_TITLE
-  if (name)
-    XFree (name);
+  set_string_property (XA_WM_NAME, str);
+#if ENABLE_EWMH
+  set_utf8_property (xa[XA_NET_WM_NAME], str);
 #endif
 }
 
 void
 rxvt_term::set_icon_name (const char *str)
 {
-#ifdef SMART_WINDOW_TITLE
-  char *name;
-
-  if (!XGetIconName (display->display, TermWin.parent[0], &name))
-    name = NULL;
-
-  if (name == NULL || STRCMP (name, str))
-#endif
-    XSetIconName (display->display, TermWin.parent[0], str);
-
-#ifdef SMART_WINDOW_TITLE
-  if (name)
-    XFree (name);
+  set_string_property (XA_WM_ICON_NAME, str);
+#if ENABLE_EWMH
+  set_utf8_property (xa[XA_NET_WM_ICON_NAME], str);
 #endif
 }
 
@@ -956,28 +950,27 @@ rxvt_term::set_window_color (int idx, const char *color)
   if (isdigit (*color))
     {
       i = atoi (color);
+
       if (i >= 8 && i <= 15)
         {        /* bright colors */
           i -= 8;
-# ifndef NO_BRIGHTCOLOR
-          PixColorsFocused[idx] = PixColorsFocused[minBrightCOLOR + i];
+          pix_colors_focused[idx] = pix_colors_focused[minBrightCOLOR + i];
           SET_PIXCOLOR (idx);
-          goto Done;
-# endif
-
+          goto done;
         }
+
       if (i >= 0 && i <= 7)
         { /* normal colors */
-          PixColorsFocused[idx] = PixColorsFocused[minCOLOR + i];
+          pix_colors_focused[idx] = pix_colors_focused[minCOLOR + i];
           SET_PIXCOLOR (idx);
-          goto Done;
+          goto done;
         }
     }
 
-  if (!rXParseAllocColor (& xcol, color))
+  if (!rXParseAllocColor (&xcol, color))
     return;
 
-  /* XStoreColor (display->display, XCMAP, XColor*); */
+  /* XStoreColor (display->display, display->cmap, XColor*); */
 
   /*
    * FIXME: should free colors here, but no idea how to do it so instead,
@@ -985,33 +978,32 @@ rxvt_term::set_window_color (int idx, const char *color)
    */
 # if 0
   for (i = Color_Black; i <= Color_White; i++)
-    if (PixColors[idx] == PixColors[i])
+    if (pix_colors[idx] == pix_colors[i])
       break;
   if (i > Color_White)
     {
-      /* fprintf (stderr, "XFreeColors: PixColors [%d] = %lu\n", idx, PixColors [idx]); */
-      XFreeColors (display->display, XCMAP, (PixColors + idx), 1,
+      /* fprintf (stderr, "XFreeColors: pix_colors [%d] = %lu\n", idx, pix_colors [idx]); */
+      XFreeColors (display->display, display->cmap, (pix_colors + idx), 1,
                   DisplayPlanes (display->display, display->screen));
     }
 # endif
 
-  PixColorsFocused[idx] = xcol;
+  pix_colors_focused[idx] = xcol;
   SET_PIXCOLOR (idx);
 
   /* XSetWindowAttributes attr; */
   /* Cursor cursor; */
-Done:
-#ifdef OFF_FOCUS_FADING
-  PixColorsUnFocused[idx] = PixColorsFocused[idx].fade (display, atoi (rs[Rs_fade]));
+done:
+
+#if OFF_FOCUS_FADING
+  if (rs[Rs_fade])
+    pix_colors_unfocused[idx] = pix_colors_focused[idx].fade (display, atoi (rs[Rs_fade]), pix_colors[Color_fade]);
 #endif
-  if (idx == Color_bg && ! (Options & Opt_transparent))
-    XSetWindowBackground (display->display, TermWin.vt, PixColors[Color_bg]);
 
-  /* handle Color_BD, scrollbar background, etc. */
+  /*TODO: handle Color_BD, scrollbar background, etc. */
 
-  set_colorfgbg ();
   recolour_cursor ();
-  scr_touch (true);
+  scr_recolour ();
 }
 
 #else
@@ -1023,9 +1015,14 @@ rxvt_term::recolour_cursor ()
 {
   XColor xcol[2];
 
-  xcol[0].pixel = ISSET_PIXCOLOR (Color_pointer_fg) ? PixColorsFocused[Color_pointer_fg] : PixColorsFocused[Color_fg];
-  xcol[1].pixel = ISSET_PIXCOLOR (Color_pointer_bg) ? PixColorsFocused[Color_pointer_bg] : PixColorsFocused[Color_bg];
-  XQueryColors (display->display, XCMAP, xcol, 2);
+  xcol[0].pixel = ISSET_PIXCOLOR (Color_pointer_fg)
+                     ? pix_colors_focused[Color_pointer_fg]
+                     : pix_colors_focused[Color_fg];
+  xcol[1].pixel = ISSET_PIXCOLOR (Color_pointer_bg)
+                     ? pix_colors_focused[Color_pointer_bg]
+                     : pix_colors_focused[Color_bg];
+
+  XQueryColors (display->display, display->cmap, xcol, 2);
   XRecolorCursor (display->display, TermWin_cursor, xcol + 0, xcol + 1);
 }
 
@@ -1036,22 +1033,22 @@ rxvt_term::recolour_cursor ()
 void
 rxvt_term::set_colorfgbg ()
 {
-  unsigned int    i;
-  const char     *xpmb = "\0";
-  char            fstr[sizeof ("default") + 1], bstr[sizeof ("default") + 1];
-
-  env_colorfgbg =
-    (char *)rxvt_malloc (sizeof ("COLORFGBG=default;default;bg") + 1);
-  STRCPY (fstr, "default");
-  STRCPY (bstr, "default");
+  unsigned int i;
+  const char *xpmb = "\0";
+  char fstr[sizeof ("default") + 1], bstr[sizeof ("default") + 1];
+
+  env_colorfgbg = (char *)rxvt_malloc (sizeof ("COLORFGBG=default;default;bg") + 1);
+  strcpy (fstr, "default");
+  strcpy (bstr, "default");
   for (i = Color_Black; i <= Color_White; i++)
-    if (PixColors[Color_fg] == PixColors[i])
+    if (pix_colors[Color_fg] == pix_colors[i])
       {
         sprintf (fstr, "%d", (i - Color_Black));
         break;
       }
+
   for (i = Color_Black; i <= Color_White; i++)
-    if (PixColors[Color_bg] == PixColors[i])
+    if (pix_colors[Color_bg] == pix_colors[i])
       {
         sprintf (bstr, "%d", (i - Color_Black));
 #ifdef XPM_BACKGROUND
@@ -1061,24 +1058,9 @@ rxvt_term::set_colorfgbg ()
       }
 
   sprintf (env_colorfgbg, "COLORFGBG=%s;%s%s", fstr, xpmb, bstr);
-
-#ifndef NO_BRIGHTCOLOR
-  colorfgbg = DEFAULT_RSTYLE;
-  for (i = minCOLOR; i <= maxCOLOR; i++)
-    {
-      if (PixColors[Color_fg] == PixColors[i])
-        colorfgbg = SET_FGCOLOR (colorfgbg, i);
-      if (PixColors[Color_bg] == PixColors[i])
-        colorfgbg = SET_BGCOLOR (colorfgbg, i);
-    }
-#endif
 }
 
 /*----------------------------------------------------------------------*/
-/*
- * Colour determination for low colour displays, routine from
- *     Hans de Goede <hans@highrise.nl>
- */
 
 int
 rxvt_term::rXParseAllocColor (rxvt_color *screen_in_out, const char *colour)
@@ -1096,16 +1078,14 @@ rxvt_term::rXParseAllocColor (rxvt_color *screen_in_out, const char *colour)
  * -                         WINDOW RESIZING                          - *
  * -------------------------------------------------------------------- */
 void
-rxvt_term::resize_all_windows (unsigned int width, unsigned int height, int ignoreparent)
+rxvt_term::resize_all_windows (unsigned int newwidth, unsigned int newheight, int ignoreparent)
 {
   int fix_screen;
-
-#ifdef SMART_RESIZE
   int old_width = szHint.width, old_height = szHint.height;
-#endif
+  dDisp;
 
-  window_calc (width, height);
-  XSetWMNormalHints (display->display, TermWin.parent[0], &szHint);
+  window_calc (newwidth, newheight);
+  XSetWMNormalHints (dispparent[0], &szHint);
 
   if (!ignoreparent)
     {
@@ -1119,9 +1099,9 @@ rxvt_term::resize_all_windows (unsigned int width, unsigned int height, int igno
       unsigned int unused_w1, unused_h1, unused_b1, unused_d1;
       Window unused_cr;
 
-      XTranslateCoordinates (display->display, TermWin.parent[0], display->root,
+      XTranslateCoordinates (dispparent[0], display->root,
                              0, 0, &x, &y, &unused_cr);
-      XGetGeometry (display->display, TermWin.parent[0], &unused_cr, &x1, &y1,
+      XGetGeometry (dispparent[0], &unused_cr, &x1, &y1,
                     &unused_w1, &unused_h1, &unused_b1, &unused_d1);
       /*
        * if display->root isn't the parent window, a WM will probably have offset
@@ -1133,8 +1113,8 @@ rxvt_term::resize_all_windows (unsigned int width, unsigned int height, int igno
           y -= y1;
         }
 
-      x1 = (DisplayWidth (display->display, display->screen) - old_width) / 2;
-      y1 = (DisplayHeight (display->display, display->screen) - old_height) / 2;
+      x1 = (DisplayWidth (disp, display->screen) - old_width) / 2;
+      y1 = (DisplayHeight (disp, display->screen) - old_height) / 2;
       dx = old_width - szHint.width;
       dy = old_height - szHint.height;
 
@@ -1148,33 +1128,29 @@ rxvt_term::resize_all_windows (unsigned int width, unsigned int height, int igno
       else if (y == y1)       /* exact center */
         dy /= 2;
 
-      XMoveResizeWindow (display->display, TermWin.parent[0], x + dx, y + dy,
+      XMoveResizeWindow (dispparent[0], x + dx, y + dy,
                          szHint.width, szHint.height);
 #else
-      XResizeWindow (display->display, TermWin.parent[0], szHint.width, szHint.height);
+      XResizeWindow (dispparent[0], szHint.width, szHint.height);
 #endif
     }
 
-  fix_screen = TermWin.ncol != prev_ncol || TermWin.nrow != prev_nrow;
+  fix_screen = ncol != prev_ncol || nrow != prev_nrow;
 
-  if (fix_screen || width != old_width || height != old_height)
+  if (fix_screen || newwidth != old_width || newheight != old_height)
     {
-      if (scrollbar_visible ())
+      if (scrollBar.state)
         {
-          XMoveResizeWindow (display->display, scrollBar.win,
+          XMoveResizeWindow (disp, scrollBar.win,
                              window_sb_x, 0,
                              scrollbar_TotalWidth (), szHint.height);
           resize_scrollbar ();
         }
 
-      if (menubar_visible ())
-        XMoveResizeWindow (display->display, menuBar.win,
-                           window_vt_x, 0,
-                           TermWin_TotalWidth (), menuBar_TotalHeight ());
-
-      XMoveResizeWindow (display->display, TermWin.vt,
+      XMoveResizeWindow (disp, vt,
                          window_vt_x, window_vt_y,
-                         TermWin_TotalWidth (), TermWin_TotalHeight ());
+                         width, height);
+
       scr_clear ();
 #ifdef XPM_BACKGROUND
       resize_pixmap ();
@@ -1189,10 +1165,10 @@ rxvt_term::resize_all_windows (unsigned int width, unsigned int height, int igno
       /* scr_reset only works on the primary screen */
       if (old_height)      /* this is not the first time through */
         {
-          unsigned int ncol = TermWin.ncol;
-          TermWin.ncol = prev_ncol; // save b/c scr_blank_screen_mem uses this
+          unsigned int ocol = ncol;
+          ncol = prev_ncol; // save b/c scr_blank_screen_mem uses this
           curr_screen = scr_change_screen (PRIMARY);
-          TermWin.ncol = ncol;
+          ncol = ocol;
         }
 
       scr_reset ();
@@ -1200,13 +1176,18 @@ rxvt_term::resize_all_windows (unsigned int width, unsigned int height, int igno
       if (curr_screen >= 0) /* this is not the first time through */
         {
           scr_change_screen (curr_screen);
-          selection_check (old_ncol != TermWin.ncol ? 4 : 0);
+          selection_check (old_ncol != ncol ? 4 : 0);
         }
     }
 
   old_width = szHint.width;
   old_height = szHint.height;
 
+#ifdef XPM_BACKGROUND
+  if (pixmap)
+    scr_touch (false);
+#endif
+
 #ifdef USE_XIM
   IMSetStatusPosition ();
 #endif
@@ -1217,23 +1198,25 @@ rxvt_term::resize_all_windows (unsigned int width, unsigned int height, int igno
  * good for toggling 80/132 columns
  */
 void
-rxvt_term::set_widthheight (unsigned int width, unsigned int height)
+rxvt_term::set_widthheight (unsigned int newwidth, unsigned int newheight)
 {
   XWindowAttributes wattr;
 
-  if (width == 0 || height == 0)
+  if (newwidth == 0 || newheight == 0)
     {
       XGetWindowAttributes (display->display, display->root, &wattr);
-      if (width == 0)
-        width = wattr.width - szHint.base_width;
-      if (height == 0)
-        height = wattr.height - szHint.base_height;
+
+      if (newwidth == 0)
+        newwidth = wattr.width - szHint.base_width;
+      if (newheight == 0)
+        newheight = wattr.height - szHint.base_height;
     }
-  if (width != TermWin.width || height != TermWin.height)
+
+  if (newwidth != width || newheight != height)
     {
-      width += szHint.base_width;
-      height += szHint.base_height;
-      resize_all_windows (width, height, 0);
+      newwidth += szHint.base_width;
+      newheight += szHint.base_height;
+      resize_all_windows (newwidth, newheight, 0);
     }
 }
 
@@ -1243,63 +1226,83 @@ rxvt_term::set_widthheight (unsigned int width, unsigned int height)
 #ifdef USE_XIM
 
 void
-rxvt_term::im_set_size (XRectangle *size)
+rxvt_term::im_set_color (unsigned long &fg, unsigned long &bg)
+{
+  fg = pix_colors[Color_fg];
+  bg = pix_colors[Color_bg];
+}
+
+void
+rxvt_term::im_set_size (XRectangle &size)
 {
-  size->x = TermWin.int_bwidth;
-  size->y = TermWin.int_bwidth;
-  size->width = Width2Pixel (TermWin.ncol);
-  size->height = Height2Pixel (TermWin.nrow);
+  // the int_bwidth terms make no sense to me
+  size.x      = int_bwidth;
+  size.y      = int_bwidth;
+  size.width  = Width2Pixel (ncol) + int_bwidth;
+  size.height = Height2Pixel (nrow) + int_bwidth;
 }
 
 void
-rxvt_term::im_set_color (unsigned long *fg, unsigned long *bg)
+rxvt_term::im_set_preedit_area (XRectangle &preedit_rect,
+                                XRectangle &status_rect,
+                                const XRectangle &needed_rect)
 {
-  *fg = PixColors[Color_fg];
-  *bg = PixColors[Color_bg];
+  preedit_rect.x      = needed_rect.width;
+  preedit_rect.y      = 0;
+  preedit_rect.width  = Width2Pixel (ncol) - needed_rect.width + 1;
+  preedit_rect.height = fheight;
+
+  status_rect.x       = 0;
+  status_rect.y       = 0;
+  status_rect.width   = needed_rect.width ? needed_rect.width : Width2Pixel (ncol) + 1;
+  status_rect.height  = fheight;
 }
 
 /* Checking whether input method is running. */
 bool
 rxvt_term::IMisRunning ()
 {
-  char           *p;
-  Atom            atom;
-  Window          win;
-  char            server[IMBUFSIZ];
+  char *p;
+  Atom atom;
+  Window win;
+  char server[IMBUFSIZ];
 
   /* get current locale modifier */
   if ((p = XSetLocaleModifiers (NULL)) != NULL)
     {
-      STRCPY (server, "@server=");
-      STRNCAT (server, & (p[4]), IMBUFSIZ - 9); /* skip "@im=" */
-      if ((p = STRCHR (server + 1, '@')) != NULL)      /* first one only */
+      strcpy (server, "@server=");
+      strncat (server, & (p[4]), IMBUFSIZ - 9); /* skip "@im=" */
+
+      if ((p = strchr (server + 1, '@')) != NULL)      /* first one only */
         *p = '\0';
 
       atom = XInternAtom (display->display, server, False);
       win = XGetSelectionOwner (display->display, atom);
+
       if (win != None)
         return True;
     }
+
   return False;
 }
 
 void
 rxvt_term::IMSendSpot ()
 {
-  XPoint          spot;
-  XVaNestedList   preedit_attr;
-
-  if (Input_Context == NULL
-      || !TermWin.focus || ! (input_style & XIMPreeditPosition)
-      || ! (event_type == KeyPress
-           || event_type == Expose
-           || event_type == NoExpose
-           || event_type == SelectionNotify
-           || event_type == ButtonRelease || event_type == FocusIn)
-      || !IMisRunning ())
+  XPoint nspot;
+  XVaNestedList preedit_attr;
+
+  if (!Input_Context
+      || !focus
+      || !(input_style & XIMPreeditPosition))
+    return;
+
+  im_set_position (nspot);
+
+  if (nspot.x == spot.x && nspot.y == spot.y)
     return;
 
-  im_set_position (&spot);
+  spot = nspot;
 
   preedit_attr = XVaCreateNestedList (0, XNSpotLocation, &spot, NULL);
   XSetICValues (Input_Context, XNPreeditAttributes, preedit_attr, NULL);
@@ -1307,44 +1310,18 @@ rxvt_term::IMSendSpot ()
 }
 
 void
-rxvt_term::im_set_preedit_area (XRectangle * preedit_rect, XRectangle * status_rect,
-                                XRectangle * needed_rect)
-{
-  int mbh, vtx = 0;
-
-  if (scrollbar_visible () && ! (Options & Opt_scrollBar_right))
-    vtx = scrollbar_TotalWidth ();
-
-  mbh = menubar_visible () ? menuBar_TotalHeight () : 0;
-  mbh -= TermWin.lineSpace;
-
-  preedit_rect->x = needed_rect->width + vtx;
-  preedit_rect->y = Height2Pixel (TermWin.nrow - 1) + mbh;
-
-  preedit_rect->width = Width2Pixel (TermWin.ncol + 1) - needed_rect->width + vtx;
-  preedit_rect->height = Height2Pixel (1);
-
-  status_rect->x = vtx;
-  status_rect->y = Height2Pixel (TermWin.nrow - 1) + mbh;
-
-  status_rect->width = needed_rect->width ? needed_rect->width : Width2Pixel (TermWin.ncol + 1);
-  status_rect->height = Height2Pixel (1);
-}
-
-void
 rxvt_term::im_destroy ()
 {
-  if (Input_Context)
-    {
-      XDestroyIC (Input_Context);
-      Input_Context = NULL;
-    }
-
   if (input_method)
     {
+      if (Input_Context && input_method->xim)
+        XDestroyIC (Input_Context);
+
       display->put_xim (input_method);
       input_method = 0;
     }
+
+  Input_Context = 0;
 }
 
 /*
@@ -1354,15 +1331,16 @@ rxvt_term::im_destroy ()
 bool
 rxvt_term::IM_get_IC (const char *modifiers)
 {
-  int             i, j, found;
-  XIM             xim;
-  XPoint          spot;
-  XRectangle      rect, status_rect, needed_rect;
-  unsigned long   fg, bg;
-  const char     *p;
-  char          **s;
-  XIMStyles      *xim_styles;
-  XVaNestedList   preedit_attr, status_attr;
+  int i, j, found;
+  XIM xim;
+  XPoint spot;
+  XRectangle rect, status_rect, needed_rect;
+  unsigned long fg, bg;
+  const char *p;
+  char **s;
+  XIMStyles *xim_styles;
+
+  set_environ (envv);
 
   if (! ((p = XSetLocaleModifiers (modifiers)) && *p))
     return false;
@@ -1373,96 +1351,153 @@ rxvt_term::IM_get_IC (const char *modifiers)
     return false;
 
   xim = input_method->xim;
+  spot.x = spot.y = -1;
 
   xim_styles = NULL;
   if (XGetIMValues (xim, XNQueryInputStyle, &xim_styles, NULL)
       || !xim_styles || !xim_styles->count_styles)
     {
-      display->put_xim (input_method);
+      im_destroy ();
       return false;
     }
 
-  p = rs[Rs_preeditType] ? rs[Rs_preeditType] : "OverTheSpot,OffTheSpot,Root";
-  s = rxvt_splitcommastring (p);
-  for (i = found = 0; !found && s[i]; i++)
+  const char *pet[] = { rs[Rs_preeditType], "OverTheSpot,OffTheSpot,Root,None" };
+
+  for (int pi = 0; pi < 2; pi++)
     {
-      if (!STRCMP (s[i], "OverTheSpot"))
-        input_style = (XIMPreeditPosition | XIMStatusNothing);
-      else if (!STRCMP (s[i], "OffTheSpot"))
-        input_style = (XIMPreeditArea | XIMStatusArea);
-      else if (!STRCMP (s[i], "Root"))
-        input_style = (XIMPreeditNothing | XIMStatusNothing);
-
-      for (j = 0; j < xim_styles->count_styles; j++)
-        if (input_style == xim_styles->supported_styles[j])
-          {
-            found = 1;
-            break;
-          }
+      p = pet[pi];
+
+      if (!p)
+        continue;
+
+      s = rxvt_splitcommastring (p);
+
+      for (i = found = 0; !found && s[i]; i++)
+        {
+          if (!strcmp (s[i], "OverTheSpot"))
+            input_style = (XIMPreeditPosition | XIMStatusNothing);
+          else if (!strcmp (s[i], "OffTheSpot"))
+            input_style = (XIMPreeditArea | XIMStatusArea);
+          else if (!strcmp (s[i], "Root"))
+            input_style = (XIMPreeditNothing | XIMStatusNothing);
+          else if (!strcmp (s[i], "None"))
+            input_style = (XIMPreeditNone | XIMStatusNone);
+
+          for (j = 0; j < xim_styles->count_styles; j++)
+            if (input_style == xim_styles->supported_styles[j])
+              {
+                rxvt_freecommastring (s);
+
+                found = 1;
+                goto foundpet;
+              }
+
+        }
+
+      rxvt_freecommastring (s);
     }
 
-  for (i = 0; s[i]; i++)
-    free (s[i]);
+foundpet:
 
-  free (s);
   XFree (xim_styles);
 
   if (!found)
     {
-      display->put_xim (input_method);
+      im_destroy ();
       return false;
     }
 
-  preedit_attr = status_attr = NULL;
+  XFontSet fs = 0;
+  XVaNestedList preedit_attr = 0, status_attr = 0;
+
+  if (input_style & (XIMPreeditPosition | XIMPreeditArea))
+    {
+      // fake us a font-set, please
+      char **missing_charset_list;
+      int missing_charset_count;
+      char *def_string;
+      char pat[512];
+
+      sprintf (pat,
+               "-*-*-*-R-*-*-%d-*-*-*-*-*-*,"
+               "-*-*-*-R-*-*-%d-*-*-*-*-*-*,"
+               "-*-*-*-R-*-*-%d-*-*-*-*-*-*,"
+               "-*-*-*-R-*-*-%d-*-*-*-*-*-*,"
+               "-*-*-*-R-*-*-%d-*-*-*-*-*-*,"
+               "*",
+               fheight,
+               fheight + 1, fheight - 1,
+               fheight - 2, fheight + 2);
+
+      fs = XCreateFontSet (display->display, rs[Rs_imFont] ? rs[Rs_imFont] : pat,
+                           &missing_charset_list, &missing_charset_count, &def_string);
+
+      if (missing_charset_list)
+        XFreeStringList (missing_charset_list);
+
+      if (!fs)
+        {
+          input_style &= ~(XIMPreeditPosition | XIMPreeditArea);
+          rxvt_warn ("unable to create fontset for input method, try \"-pt Root\". Continuing.\n");
+        }
+    }
 
   if (input_style & XIMPreeditPosition)
     {
-      im_set_size (&rect);
-      im_set_position (&spot);
-      im_set_color (&fg, &bg);
-
-      preedit_attr = XVaCreateNestedList (0, XNArea, &rect,
-                                         XNSpotLocation, &spot,
-                                         XNForeground, fg, XNBackground, bg,
-                                         //XNFontSet, TermWin.fontset,
-                                         NULL);
+      im_set_size (rect);
+      im_set_position (spot);
+      im_set_color (fg, bg);
+
+      preedit_attr = XVaCreateNestedList (0,
+                                          XNForeground, fg,
+                                          XNBackground, bg,
+                                          XNArea, &rect,
+                                          XNSpotLocation, &spot,
+                                          XNFontSet, fs,
+                                          NULL);
     }
   else if (input_style & XIMPreeditArea)
     {
-      im_set_color (&fg, &bg);
+      im_set_color (fg, bg);
 
       /*
        * The necessary width of preedit area is unknown
        * until create input context.
        */
       needed_rect.width = 0;
-
-      im_set_preedit_area (&rect, &status_rect, &needed_rect);
-
-      preedit_attr = XVaCreateNestedList (0, XNArea, &rect,
-                                         XNForeground, fg, XNBackground, bg,
-                                         //XNFontSet, TermWin.fontset,
+      im_set_preedit_area (rect, status_rect, needed_rect);
+
+      preedit_attr = XVaCreateNestedList (0,
+                                          XNForeground, fg,
+                                          XNBackground, bg,
+                                          XNArea, &rect,
+                                          XNFontSet, fs,
+                                          NULL);
+      status_attr = XVaCreateNestedList (0,
+                                         XNForeground, fg,
+                                         XNBackground, bg,
+                                         XNArea, &status_rect,
+                                         XNFontSet, fs,
                                          NULL);
-      status_attr = XVaCreateNestedList (0, XNArea, &status_rect,
-                                        XNForeground, fg, XNBackground, bg,
-                                        //XNFontSet, TermWin.fontset,
-                                        NULL);
     }
 
-  Input_Context = XCreateIC (xim, XNInputStyle, input_style,
-                            XNClientWindow, TermWin.parent[0],
-                            XNFocusWindow, TermWin.parent[0],
-                            preedit_attr ? XNPreeditAttributes : NULL,
-                            preedit_attr,
-                            status_attr ? XNStatusAttributes : NULL,
-                            status_attr, NULL);
+  Input_Context = XCreateIC (xim,
+                             XNInputStyle, input_style,
+                             XNClientWindow, vt,
+                             XNFocusWindow, parent[0],
+                             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 (fs) XFreeFontSet (display->display, fs);
 
   if (Input_Context == NULL)
     {
       rxvt_warn ("failed to create input context, continuing without XIM.\n");
-      display->put_xim (input_method);
+      im_destroy ();
       return false;
     }
 
@@ -1476,11 +1511,13 @@ rxvt_term::IM_get_IC (const char *modifiers)
 void
 rxvt_term::im_cb ()
 {
-  int i, found, had_im;
+  int i;
   const char *p;
   char **s;
   char buf[IMBUFSIZ];
 
+  make_current ();
+
   im_destroy ();
 
   D_MAIN ((stderr, "rxvt_IMInstantiateCallback ()"));
@@ -1498,12 +1535,13 @@ rxvt_term::im_cb ()
       bool found = false;
 
       s = rxvt_splitcommastring (p);
+
       for (i = 0; s[i]; i++)
         {
           if (*s[i])
             {
-              STRCPY (buf, "@im=");
-              STRNCAT (buf, s[i], IMBUFSIZ - 5);
+              strcpy (buf, "@im=");
+              strncat (buf, s[i], IMBUFSIZ - 5);
               if (IM_get_IC (buf))
                 {
                   found = true;
@@ -1511,9 +1549,8 @@ rxvt_term::im_cb ()
                 }
             }
         }
-      for (i = 0; s[i]; i++)
-        free (s[i]);
-      free (s);
+
+      rxvt_freecommastring (s);
 
       if (found)
         goto done;
@@ -1537,11 +1574,12 @@ done:
 void
 rxvt_term::IMSetStatusPosition ()
 {
-  XRectangle      preedit_rect, status_rect, *needed_rect;
-  XVaNestedList   preedit_attr, status_attr;
+  XRectangle preedit_rect, status_rect, *needed_rect;
+  XVaNestedList preedit_attr, status_attr;
 
-  if (Input_Context == NULL
-      || !TermWin.focus || ! (input_style & XIMPreeditArea)
+  if (!Input_Context
+      || !focus
+      || !(input_style & XIMPreeditArea)
       || !IMisRunning ())
     return;
 
@@ -1550,14 +1588,15 @@ rxvt_term::IMSetStatusPosition ()
   XGetICValues (Input_Context, XNStatusAttributes, status_attr, NULL);
   XFree (status_attr);
 
-  im_set_preedit_area (&preedit_rect, &status_rect, needed_rect);
+  im_set_preedit_area (preedit_rect, status_rect, *needed_rect);
+  XFree (needed_rect);
 
   preedit_attr = XVaCreateNestedList (0, XNArea, &preedit_rect, NULL);
   status_attr = XVaCreateNestedList (0, XNArea, &status_rect, NULL);
 
   XSetICValues (Input_Context,
-               XNPreeditAttributes, preedit_attr,
-               XNStatusAttributes, status_attr, NULL);
+                XNPreeditAttributes, preedit_attr,
+                XNStatusAttributes, status_attr, NULL);
 
   XFree (preedit_attr);
   XFree (status_attr);