Merge from emacs-23
[bpt/emacs.git] / src / nsterm.m
index 38376e4..87dc119 100644 (file)
@@ -27,7 +27,7 @@ GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
 
 /* This should be the first include, as it may set up #defines affecting
    interpretation of even the system includes. */
-#include "config.h"
+#include <config.h>
 
 #include <math.h>
 #include <sys/types.h>
@@ -157,10 +157,20 @@ Lisp_Object ns_right_alternate_modifier;
    the Command modifier.  May be any of the modifier lisp symbols. */
 Lisp_Object ns_command_modifier;
 
+/* Specifies which emacs modifier should be generated when NS receives
+   the right Command modifier.  Has same values as ns_command_modifier plus
+   the value Qleft which means whatever value ns_command_modifier has.  */
+Lisp_Object ns_right_command_modifier;
+
 /* Specifies which emacs modifier should be generated when NS receives
    the Control modifier.  May be any of the modifier lisp symbols. */
 Lisp_Object ns_control_modifier;
 
+/* Specifies which emacs modifier should be generated when NS receives
+   the right Control modifier.  Has same values as ns_control_modifier plus
+   the value Qleft which means whatever value ns_control_modifier has.  */
+Lisp_Object ns_right_control_modifier;
+
 /* Specifies which emacs modifier should be generated when NS receives
    the Function modifier (laptops).  May be any of the modifier lisp symbols. */
 Lisp_Object ns_function_modifier;
@@ -223,6 +233,11 @@ static BOOL inNsSelect = 0;
 
 /* Convert modifiers in a NeXTSTEP event to emacs style modifiers.  */
 #define NS_FUNCTION_KEY_MASK 0x800000
+#define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
+#define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
+#define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
+#define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
+#define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
 #define EV_MODIFIERS(e)                               \
     ((([e modifierFlags] & NSHelpKeyMask) ?           \
@@ -235,10 +250,18 @@ static BOOL inNsSelect = 0;
            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
      | (([e modifierFlags] & NSShiftKeyMask) ?     \
            shift_modifier : 0)                        \
+     | (!EQ (ns_right_control_modifier, Qleft) && \
+        (([e modifierFlags] & NSRightControlKeyMask) \
+         == NSRightControlKeyMask) ? \
+           parse_solitary_modifier (ns_right_control_modifier) : 0) \
      | (([e modifierFlags] & NSControlKeyMask) ?      \
            parse_solitary_modifier (ns_control_modifier) : 0)     \
      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
            parse_solitary_modifier (ns_function_modifier) : 0)    \
+     | (!EQ (ns_right_command_modifier, Qleft) && \
+        (([e modifierFlags] & NSRightCommandKeyMask) \
+         == NSRightCommandKeyMask) ? \
+           parse_solitary_modifier (ns_right_command_modifier) : 0) \
      | (([e modifierFlags] & NSCommandKeyMask) ?      \
            parse_solitary_modifier (ns_command_modifier):0))
 
@@ -306,7 +329,7 @@ append2 (Lisp_Object list, Lisp_Object item)
 
 
 void
-ns_init_paths ()
+ns_init_paths (void)
 /* --------------------------------------------------------------------------
    Used to allow emacs to find its resources under Emacs.app
    Called from emacs.c at startup.
@@ -489,7 +512,7 @@ ns_retain_object (void *obj)
 
 
 void *
-ns_alloc_autorelease_pool ()
+ns_alloc_autorelease_pool (void)
 /* --------------------------------------------------------------------------
      Allocate a pool for temporary objects (callable from C)
    -------------------------------------------------------------------------- */
@@ -553,7 +576,7 @@ ns_update_window_begin (struct window *w)
    -------------------------------------------------------------------------- */
 {
   struct frame *f = XFRAME (WINDOW_FRAME (w));
 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
   NSTRACE (ns_update_window_begin);
 
   updated_window = w;
@@ -561,15 +584,15 @@ ns_update_window_begin (struct window *w)
 
   BLOCK_INPUT;
 
-  if (f == dpyinfo->mouse_face_mouse_frame)
+  if (f == hlinfo->mouse_face_mouse_frame)
     {
       /* Don't do highlighting for mouse motion during the update.  */
-      dpyinfo->mouse_face_defer = 1;
+      hlinfo->mouse_face_defer = 1;
 
         /* If the frame needs to be redrawn,
            simply forget about any prior mouse highlighting.  */
       if (FRAME_GARBAGED_P (f))
-        dpyinfo->mouse_face_window = Qnil;
+        hlinfo->mouse_face_window = Qnil;
 
       /* (further code for mouse faces ifdef'd out in other terms elided) */
     }
@@ -586,7 +609,7 @@ ns_update_window_end (struct window *w, int cursor_on_p,
    external (RIF) call; for one window called before update_end
    -------------------------------------------------------------------------- */
 {
-  struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (XFRAME (w->frame));
+  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
 
   /* note: this fn is nearly identical in all terms */
   if (!w->pseudo_window_p)
@@ -608,9 +631,9 @@ ns_update_window_end (struct window *w, int cursor_on_p,
      frame_up_to_date to redisplay the mouse highlight.  */
   if (mouse_face_overwritten_p)
     {
-      dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
-      dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
-      dpyinfo->mouse_face_window = Qnil;
+      hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
+      hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
+      hlinfo->mouse_face_window = Qnil;
     }
 
   updated_window = NULL;
@@ -627,8 +650,8 @@ ns_update_end (struct frame *f)
 {
   NSView *view = FRAME_NS_VIEW (f);
 
-/*   if (f == FRAME_NS_DISPLAY_INFO (f)->mouse_face_mouse_frame) */
-    FRAME_NS_DISPLAY_INFO (f)->mouse_face_defer = 0;
+/*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
+    MOUSE_HL_INFO (f)->mouse_face_defer = 0;
 
   BLOCK_INPUT;
 
@@ -800,7 +823,7 @@ ns_clip_to_row (struct window *w, struct glyph_row *row, int area, BOOL gc)
 
 
 static void
-ns_ring_bell ()
+ns_ring_bell (struct frame *f)
 /* --------------------------------------------------------------------------
      "Beep" routine
    -------------------------------------------------------------------------- */
@@ -1032,6 +1055,7 @@ x_destroy_window (struct frame *f)
 {
   NSView *view = FRAME_NS_VIEW (f);
   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
+  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
   NSTRACE (x_destroy_window);
   check_ns ();
 
@@ -1048,13 +1072,13 @@ x_destroy_window (struct frame *f)
     dpyinfo->x_focus_frame = 0;
   if (f == dpyinfo->x_highlight_frame)
     dpyinfo->x_highlight_frame = 0;
-  if (f == dpyinfo->mouse_face_mouse_frame)
+  if (f == hlinfo->mouse_face_mouse_frame)
     {
-      dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
-      dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
-      dpyinfo->mouse_face_window = Qnil;
-      dpyinfo->mouse_face_deferred_gc = 0;
-      dpyinfo->mouse_face_mouse_frame = 0;
+      hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
+      hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
+      hlinfo->mouse_face_window = Qnil;
+      hlinfo->mouse_face_deferred_gc = 0;
+      hlinfo->mouse_face_mouse_frame = 0;
     }
 
   xfree (f->output_data.ns);
@@ -1211,12 +1235,14 @@ x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
      difference between the real width and Emacs' imagined one.  For
      right-hand bars, don't worry about it since the extra is never used.
      (Obviously doesn't work for vertically split windows tho..) */
-  NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
-    ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
-                  - NS_SCROLL_BAR_WIDTH (f), 0)
-    : NSMakePoint (0, 0);
-  [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
-  [view setBoundsOrigin: origin];
+  {
+    NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
+      ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
+                     - NS_SCROLL_BAR_WIDTH (f), 0)
+      : NSMakePoint (0, 0);
+    [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
+    [view setBoundsOrigin: origin];
+  }
 
   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
   FRAME_PIXEL_WIDTH (f) = pixelwidth;
@@ -1532,7 +1558,10 @@ ns_query_color(void *col, XColor *color_def, int setPixel)
 
 
 int
-ns_defined_color (struct frame *f, char *name, XColor *color_def, int alloc,
+ns_defined_color (struct frame *f,
+                  const char *name,
+                  XColor *color_def,
+                  int alloc,
                   char makeIndex)
 /* --------------------------------------------------------------------------
          Return 1 if named color found, and set color_def rgb accordingly.
@@ -1782,18 +1811,18 @@ ns_frame_up_to_date (struct frame *f)
 
   if (FRAME_NS_P (f))
     {
-      struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
-      if ((dpyinfo->mouse_face_deferred_gc||f ==dpyinfo->mouse_face_mouse_frame)
-      /*&& dpyinfo->mouse_face_mouse_frame*/)
+      Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
+      if ((hlinfo->mouse_face_deferred_gc || f ==hlinfo->mouse_face_mouse_frame)
+      /*&& hlinfo->mouse_face_mouse_frame*/)
         {
           BLOCK_INPUT;
-         ns_update_begin(f);
-          if (dpyinfo->mouse_face_mouse_frame)
-            note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
-                                  dpyinfo->mouse_face_mouse_x,
-                                  dpyinfo->mouse_face_mouse_y);
-          dpyinfo->mouse_face_deferred_gc = 0;
-         ns_update_end(f);
+         ns_update_begin(f);
+          if (hlinfo->mouse_face_mouse_frame)
+            note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
+                                  hlinfo->mouse_face_mouse_x,
+                                  hlinfo->mouse_face_mouse_y);
+          hlinfo->mouse_face_deferred_gc = 0;
+         ns_update_end(f);
           UNBLOCK_INPUT;
         }
     }
@@ -1812,6 +1841,9 @@ ns_define_frame_cursor (struct frame *f, Cursor cursor)
       EmacsView *view = FRAME_NS_VIEW (f);
       FRAME_POINTER_TYPE (f) = cursor;
       [[view window] invalidateCursorRectsForView: view];
+      /* Redisplay assumes this function also draws the changed frame
+         cursor, but this function doesn't, so do it explicitly.  */
+      x_update_cursor (f, 1);
     }
 }
 
@@ -2188,11 +2220,11 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
     {
       EmacsImage **newBimgs
        = xmalloc (max_used_fringe_bitmap * sizeof (EmacsImage *));
-      bzero (newBimgs, max_used_fringe_bitmap * sizeof (EmacsImage *));
+      memset (newBimgs, 0, max_used_fringe_bitmap * sizeof (EmacsImage *));
 
       if (nBimgs)
         {
-          bcopy (bimgs, newBimgs, nBimgs * sizeof (EmacsImage *));
+          memcpy (newBimgs, bimgs, nBimgs * sizeof (EmacsImage *));
           xfree (bimgs);
         }
 
@@ -2209,9 +2241,8 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
       int yAdjust = rowY - FRAME_INTERNAL_BORDER_WIDTH (f) < 5 ?
         -FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
       int yIncr = FRAME_PIXEL_HEIGHT (f) - (p->by+yAdjust + p->ny) < 5 ?
-        FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
-      if (yAdjust)
-        yIncr += FRAME_INTERNAL_BORDER_WIDTH (f);
+        FRAME_INTERNAL_BORDER_WIDTH (f) : 0
+        + (yAdjust ? FRAME_INTERNAL_BORDER_WIDTH (f) : 0);
       NSRect r = NSMakeRect (p->bx+xAdjust, p->by+yAdjust, p->nx, p->ny+yIncr);
       NSRectClip (r);
       [ns_lookup_indexed_color(face->background, f) set];
@@ -2269,6 +2300,11 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
   struct frame *f = WINDOW_XFRAME (w);
   struct glyph *phys_cursor_glyph;
   int overspill;
+  struct glyph *cursor_glyph;
+
+  /* If cursor is out of bounds, don't draw garbage.  This can happen
+     in mini-buffer windows when switching between echo area glyphs
+     and mini-buffer.  */
 
   NSTRACE (dumpcursor);
 //fprintf(stderr, "drawcursor (%d,%d) activep = %d\tonp = %d\tc_type = %d\twidth = %d\n",x,y, active_p,on_p,cursor_type,cursor_width);
@@ -2346,6 +2382,13 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
     case BAR_CURSOR:
       s = r;
       s.size.width = min (cursor_width, 2); //FIXME(see above)
+
+      /* If the character under cursor is R2L, draw the bar cursor
+         on the right of its glyph, rather than on the left.  */
+      cursor_glyph = get_phys_cursor_glyph (w);
+      if ((cursor_glyph->resolved_level & 1) != 0)
+        s.origin.x += cursor_glyph->pixel_width - s.size.width;
+
       NSRectFill (s);
       break;
     }
@@ -2400,7 +2443,7 @@ show_hourglass (struct atimer *timer)
 
 
 void
-hide_hourglass ()
+hide_hourglass (void)
 {
   if (!hourglass_shown_p)
     return;
@@ -2591,8 +2634,7 @@ ns_dumpglyphs_box_or_relief (struct glyph_string *s)
 
   if (s->hl == DRAW_MOUSE_FACE)
     {
-      face = FACE_FROM_ID
-        (s->f, FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
+      face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
       if (!face)
         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
     }
@@ -2659,8 +2701,8 @@ ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
           struct face *face;
           if (s->hl == DRAW_MOUSE_FACE)
             {
-              face = FACE_FROM_ID
-                (s->f, FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
+              face = FACE_FROM_ID (s->f,
+                                  MOUSE_HL_INFO (s->f)->mouse_face_face_id);
               if (!face)
                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
             }
@@ -2745,8 +2787,7 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
      with its background color), we must clear just the image area. */
   if (s->hl == DRAW_MOUSE_FACE)
     {
-      face = FACE_FROM_ID
-       (s->f, FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
+      face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
       if (!face)
        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
     }
@@ -2882,8 +2923,7 @@ ns_dumpglyphs_stretch (struct glyph_string *s)
 
       if (s->hl == DRAW_MOUSE_FACE)
        {
-         face = FACE_FROM_ID
-           (s->f, FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
+         face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
          if (!face)
            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
        }
@@ -2984,11 +3024,41 @@ ns_draw_glyph_string (struct glyph_string *s)
       if (ns_tmp_font == NULL)
           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
 
+      if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
+        {
+          unsigned long tmp = NS_FACE_BACKGROUND (s->face);
+          NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
+          NS_FACE_FOREGROUND (s->face) = tmp;
+        }
+                    
       ns_tmp_font->font.driver->draw
         (s, 0, s->nchars, s->x, s->y,
          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
 
+      if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
+        {
+          unsigned long tmp = NS_FACE_BACKGROUND (s->face);
+          NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
+          NS_FACE_FOREGROUND (s->face) = tmp;
+        }
+
+      ns_unfocus (s->f);
+      break;
+
+    case GLYPHLESS_GLYPH:
+      n = ns_get_glyph_string_clip_rect (s, r);
+      ns_focus (s->f, r, n);
+
+      if (s->for_overlaps || (s->cmp_from > 0
+                             && ! s->first_glyph->u.cmp.automatic))
+        s->background_filled_p = 1;
+      else
+        ns_maybe_dumpglyphs_background
+          (s, s->first_glyph->type == COMPOSITE_GLYPH);
+      /* ... */ 
+      /* Not yet implemented.  */
+      /* ... */ 
       ns_unfocus (s->f);
       break;
 
@@ -3444,16 +3514,14 @@ x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
    ========================================================================== */
 
 int
-x_display_pixel_height (dpyinfo)
-     struct ns_display_info *dpyinfo;
+x_display_pixel_height (struct ns_display_info *dpyinfo)
 {
   NSScreen *screen = [NSScreen mainScreen];
   return [screen frame].size.height;
 }
 
 int
-x_display_pixel_width (dpyinfo)
-     struct ns_display_info *dpyinfo;
+x_display_pixel_width (struct ns_display_info *dpyinfo)
 {
   NSScreen *screen = [NSScreen mainScreen];
   return [screen frame].size.width;
@@ -3540,6 +3608,7 @@ ns_initialize_display_info (struct ns_display_info *dpyinfo)
 {
     NSScreen *screen = [NSScreen mainScreen];
     NSWindowDepth depth = [screen depth];
+    Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
 
     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
     dpyinfo->resy = 72.27;
@@ -3554,16 +3623,16 @@ ns_initialize_display_info (struct ns_display_info *dpyinfo)
     dpyinfo->color_table->colors = NULL;
     dpyinfo->root_window = 42; /* a placeholder.. */
 
-    dpyinfo->mouse_face_mouse_frame = NULL;
-    dpyinfo->mouse_face_deferred_gc = 0;
-    dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
-    dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
-    dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
-    dpyinfo->mouse_face_window = dpyinfo->mouse_face_overlay = Qnil;
-    dpyinfo->mouse_face_hidden = 0;
+    hlinfo->mouse_face_mouse_frame = NULL;
+    hlinfo->mouse_face_deferred_gc = 0;
+    hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
+    hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
+    hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
+    hlinfo->mouse_face_window = hlinfo->mouse_face_overlay = Qnil;
+    hlinfo->mouse_face_hidden = 0;
 
-    dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
-    dpyinfo->mouse_face_defer = 0;
+    hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
+    hlinfo->mouse_face_defer = 0;
 
     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
 
@@ -3732,7 +3801,7 @@ ns_term_init (Lisp_Object display_name)
                                              name: nil object: nil]; */
 
   dpyinfo = (struct ns_display_info *)xmalloc (sizeof (struct ns_display_info));
-  bzero (dpyinfo, sizeof (struct ns_display_info));
+  memset (dpyinfo, 0, sizeof (struct ns_display_info));
 
   ns_initialize_display_info (dpyinfo);
   terminal = ns_create_terminal (dpyinfo);
@@ -4346,7 +4415,7 @@ ns_term_shutdown (int sig)
 
 - (void)keyDown: (NSEvent *)theEvent
 {
-  struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
+  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
   int code;
   unsigned fnKeysym = 0;
   int flags;
@@ -4384,10 +4453,10 @@ ns_term_shutdown (int sig)
 
   [NSCursor setHiddenUntilMouseMoves: YES];
 
-  if (dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
+  if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
     {
-      clear_mouse_face (dpyinfo);
-      dpyinfo->mouse_face_hidden = 1;
+      clear_mouse_face (hlinfo);
+      hlinfo->mouse_face_hidden = 1;
     }
 
   if (!processingCompose)
@@ -4395,7 +4464,7 @@ ns_term_shutdown (int sig)
       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
       /* (Carbon way: [theEvent keyCode]) */
-
+      
       /* is it a "function key"? */
       fnKeysym = ns_convert_key (code);
       if (fnKeysym)
@@ -4418,9 +4487,17 @@ ns_term_shutdown (int sig)
       if (flags & NSShiftKeyMask)
         emacs_event->modifiers |= shift_modifier;
 
-      if (flags & NSCommandKeyMask)
+      if ((flags & NSRightCommandKeyMask) == NSRightCommandKeyMask)
+        emacs_event->modifiers |= parse_solitary_modifier
+          (EQ (ns_right_command_modifier, Qleft)
+           ? ns_command_modifier
+           : ns_right_command_modifier);
+
+      if ((flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask)
         {
-          emacs_event->modifiers |= parse_solitary_modifier (ns_command_modifier);
+          emacs_event->modifiers |= parse_solitary_modifier
+            (ns_command_modifier);
+
           /* if super (default), take input manager's word so things like
              dvorak / qwerty layout work */
           if (EQ (ns_command_modifier, Qsuper)
@@ -4453,23 +4530,43 @@ ns_term_shutdown (int sig)
             }
         }
 
-      if (flags & NSControlKeyMask)
-          emacs_event->modifiers |=
-            parse_solitary_modifier (ns_control_modifier);
+      if ((flags & NSRightControlKeyMask) == NSRightControlKeyMask)
+          emacs_event->modifiers |= parse_solitary_modifier
+              (EQ (ns_right_control_modifier, Qleft)
+               ? ns_control_modifier
+               : ns_right_control_modifier);
+
+      if ((flags & NSLeftControlKeyMask) == NSLeftControlKeyMask)
+        emacs_event->modifiers |= parse_solitary_modifier
+          (ns_control_modifier);
 
       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
           emacs_event->modifiers |=
             parse_solitary_modifier (ns_function_modifier);
 
-      if (!EQ (ns_right_alternate_modifier, Qleft)
-          && ((flags & NSRightAlternateKeyMask) == NSRightAlternateKeyMask)) 
-       {
-         emacs_event->modifiers |= parse_solitary_modifier
-            (ns_right_alternate_modifier);
-       }
-      else if (flags & NSAlternateKeyMask) /* default = meta */
+      if ((flags & NSRightAlternateKeyMask) == NSRightAlternateKeyMask)
+        {
+          if ((NILP (ns_right_alternate_modifier)
+               || EQ (ns_right_alternate_modifier, Qnone))
+              && !fnKeysym)
+            {   /* accept pre-interp alt comb */
+              if ([[theEvent characters] length] > 0)
+                code = [[theEvent characters] characterAtIndex: 0];
+              /*HACK: clear lone shift modifier to stop next if from firing */
+              if (emacs_event->modifiers == shift_modifier)
+                emacs_event->modifiers = 0;
+            }
+          else
+            emacs_event->modifiers |= parse_solitary_modifier
+              (EQ (ns_right_alternate_modifier, Qleft)
+               ? ns_alternate_modifier
+               : ns_right_alternate_modifier);
+        }
+
+      if ((flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask) /* default = meta */
         {
-          if ((NILP (ns_alternate_modifier) || EQ (ns_alternate_modifier, Qnone))
+          if ((NILP (ns_alternate_modifier)
+               || EQ (ns_alternate_modifier, Qnone))
               && !fnKeysym)
             {   /* accept pre-interp alt comb */
               if ([[theEvent characters] length] > 0)
@@ -4824,7 +4921,7 @@ ns_term_shutdown (int sig)
 /* Tell emacs the mouse has moved. */
 - (void)mouseMoved: (NSEvent *)e
 {
-  struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
+  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
   Lisp_Object frame;
 
 //  NSTRACE (mouseMoved);
@@ -4834,10 +4931,10 @@ ns_term_shutdown (int sig)
     = [self convertPoint: [e locationInWindow] fromView: nil];
 
   /* update any mouse face */
-  if (dpyinfo->mouse_face_hidden)
+  if (hlinfo->mouse_face_hidden)
     {
-      dpyinfo->mouse_face_hidden = 0;
-      clear_mouse_face (dpyinfo);
+      hlinfo->mouse_face_hidden = 0;
+      clear_mouse_face (hlinfo);
     }
 
   /* tooltip handling */
@@ -5303,20 +5400,19 @@ ns_term_shutdown (int sig)
 {
   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
   NSRect r;
-  struct ns_display_info *dpyinfo
-    = emacsframe ? FRAME_NS_DISPLAY_INFO (emacsframe) : NULL;
+  Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
 
   NSTRACE (mouseExited);
 
-  if (dpyinfo || !emacsframe)
+  if (!hlinfo)
     return;
 
   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
 
-  if (emacsframe == dpyinfo->mouse_face_mouse_frame)
+  if (emacsframe == hlinfo->mouse_face_mouse_frame)
     {
-      clear_mouse_face (dpyinfo);
-      dpyinfo->mouse_face_mouse_frame = 0;
+      clear_mouse_face (hlinfo);
+      hlinfo->mouse_face_mouse_frame = 0;
     }
 }
 
@@ -5431,7 +5527,7 @@ ns_term_shutdown (int sig)
   NSTRACE (performDragOperation);
 
   if (!emacs_event)
-    return;
+    return NO;
 
   position = [self convertPoint: [sender draggingLocation] fromView: nil];
   x = lrint (position.x);  y = lrint (position.y);
@@ -5787,9 +5883,10 @@ ns_term_shutdown (int sig)
   NSTRACE (judge);
   if (condemned)
     {
+      EmacsView *view;
       BLOCK_INPUT;
       /* ensure other scrollbar updates after deletion */
-      EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
+      view = (EmacsView *)FRAME_NS_VIEW (frame);
       if (view != nil)
         view->scrollbarsNeedingUpdate++;
       [self removeFromSuperview];
@@ -6166,7 +6263,7 @@ ns_xlfd_to_fontname (const char *xlfd)
 
 
 void
-syms_of_nsterm ()
+syms_of_nsterm (void)
 {
   NSTRACE (syms_of_nsterm);
 
@@ -6242,11 +6339,27 @@ at all, allowing it to be used at a lower level for accented character entry.");
 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
   ns_command_modifier = Qsuper;
 
+  DEFVAR_LISP ("ns-right-command-modifier", &ns_right_command_modifier,
+               "This variable describes the behavior of the right command key.\n\
+Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
+Set to left means be the same key as `ns-command-modifier'.\n\
+Set to none means that the command / option key is not interpreted by Emacs\n\
+at all, allowing it to be used at a lower level for accented character entry.");
+  ns_right_command_modifier = Qleft;
+
   DEFVAR_LISP ("ns-control-modifier", &ns_control_modifier,
                "This variable describes the behavior of the control key.\n\
 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
   ns_control_modifier = Qcontrol;
 
+  DEFVAR_LISP ("ns-right-control-modifier", &ns_right_control_modifier,
+               "This variable describes the behavior of the right control key.\n\
+Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
+Set to left means be the same key as `ns-control-modifier'.\n\
+Set to none means that the control / option key is not interpreted by Emacs\n\
+at all, allowing it to be used at a lower level for accented character entry.");
+  ns_right_control_modifier = Qleft;
+
   DEFVAR_LISP ("ns-function-modifier", &ns_function_modifier,
                "This variable describes the behavior of the function key (on laptops).\n\
 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\