Add bug reference.
[bpt/emacs.git] / src / nsterm.m
index f8000b9..f785425 100644 (file)
@@ -25,12 +25,15 @@ MacOSX/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
 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 <math.h>
 #include <sys/types.h>
 #include <time.h>
 #include <unistd.h>
 
-#include "config.h"
 #include "lisp.h"
 #include "blockinput.h"
 #include "sysselect.h"
@@ -78,6 +81,7 @@ int term_trace_num = 0;
 #define KEY_NS_INSERT_WORKING_TEXT     ((1<<28)|(0<<16)|9)
 #define KEY_NS_DELETE_WORKING_TEXT     ((1<<28)|(0<<16)|10)
 #define KEY_NS_SPI_SERVICE_CALL        ((1<<28)|(0<<16)|11)
+#define KEY_NS_NEW_FRAME               ((1<<28)|(0<<16)|12)
 
 /* Convert a symbol indexed with an NSxxx value to a value as defined
    in keyboard.c (lispy_function_key). I hope this is a correct way
@@ -167,13 +171,6 @@ Lisp_Object ns_control_modifier;
    the Function modifer (laptops).  May be any of the modifier lisp symbols. */
 Lisp_Object ns_function_modifier;
 
-/* A floating point value specifying the rate at which to blink the cursor.
-   YES indicates 0.5, NO indicates no blinking. */
-Lisp_Object ns_cursor_blink_rate;
-
-/* Used for liason with core emacs cursor-blink-mode. */
-Lisp_Object ns_cursor_blink_mode;
-
 /* A floating point value specifying vertical stretch (positive) or shrink
   (negative) of text line spacing.  Zero means default spacing.
   YES indicates 0.5, NO indicates 0.0. */
@@ -234,7 +231,6 @@ static BOOL send_appdefined = YES;
 static NSEvent *last_appdefined_event = 0;
 static NSTimer *timed_entry = 0;
 static NSTimer *fd_entry = nil;
-static NSTimer *cursor_blink_entry = nil;
 static NSTimer *scroll_repeat_entry = nil;
 static fd_set select_readfds, t_readfds;
 static struct timeval select_timeout;
@@ -267,14 +263,18 @@ static BOOL inNsSelect = 0;
 #define EV_UDMODIFIERS(e)                                      \
     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
+     | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
+     | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
-     | (([e type] == NSRightMouseUp)   ? up_modifier   : 0))
+     | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
+     | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
 
 #define EV_BUTTON(e)                                                         \
     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
-      (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : 1)
+      (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
+     [e buttonNumber] - 1)
 
 /* Convert the time field to a timestamp in milliseconds. */
 #ifdef NS_IMPL_GNUSTEP
@@ -554,7 +554,6 @@ ns_update_begin (struct frame *f)
 {
   NSView *view = FRAME_NS_VIEW (f);
   NSTRACE (ns_update_begin);
-/*fprintf (stderr, "\\%p\n", f); */
 
   ns_updating_frame = f;
   [view lockFocus];
@@ -690,7 +689,7 @@ ns_focus (struct frame *f, NSRect *r, int n)
      the entire window.
    -------------------------------------------------------------------------- */
 {
-  NSTRACE (ns_focus);
+//  NSTRACE (ns_focus);
 #ifdef NS_IMPL_GNUSTEP
   NSRect u;
     if (n == 2)
@@ -763,7 +762,7 @@ ns_unfocus (struct frame *f)
      Internal: Remove focus on given frame
    -------------------------------------------------------------------------- */
 {
-  NSTRACE (ns_unfocus);
+//  NSTRACE (ns_unfocus);
 
   if (gsaved)
     {
@@ -846,7 +845,7 @@ ns_ring_bell ()
           r.origin.y += (r.size.height - dim.y) / 2;
           r.size.width = dim.x;
           r.size.height = dim.y;
-          /* XXX: cacheImageInRect under GNUSTEP does not account for
+          /* XXX: cacheImageInRect under GNUstep does not account for
              offset in x_set_window_size, so overestimate (4 fine on Cocoa) */
           surr = NSInsetRect (r, -10, -10);
           ns_focus (frame, &surr, 1);
@@ -964,17 +963,16 @@ ns_frame_rehighlight (struct frame *frame)
   if (dpyinfo->x_highlight_frame &&
          dpyinfo->x_highlight_frame != old_highlight)
     {
-      /* as of 20080602 the lower and raise are superfluous */
       if (old_highlight)
-        {
-          /*ns_lower_frame (old_highlight); */
+       {
           x_update_cursor (old_highlight, 1);
-        }
+         x_set_frame_alpha (old_highlight);
+       }
       if (dpyinfo->x_highlight_frame)
-        {
-          /*ns_raise_frame (dpyinfo->x_highlight_frame); */
+       {
           x_update_cursor (dpyinfo->x_highlight_frame, 1);
-        }
+          x_set_frame_alpha (dpyinfo->x_highlight_frame);
+       }
     }
 }
 
@@ -1154,7 +1152,7 @@ x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
 
   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
-  
+
   /* If we have a change in toolbar display, calculate height */
   if (tb)
     /* XXX: GNUstep has not yet implemented the first method below, added
@@ -1234,12 +1232,14 @@ x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
 }
 
 
+
 /* ==========================================================================
 
     Color management
 
    ========================================================================== */
 
+
 NSColor *
 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
 {
@@ -1293,7 +1293,6 @@ ns_index_color (NSColor *color, struct frame *f)
                                    color_table->size * sizeof (NSColor *));
         }
       idx = color_table->avail++;
-      index = [NSNumber numberWithUnsignedInt: idx];
     }
 
   color_table->colors[idx] = color;
@@ -1306,10 +1305,26 @@ ns_index_color (NSColor *color, struct frame *f)
 void
 ns_free_indexed_color (unsigned long idx, struct frame *f)
 {
-  struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
+  struct ns_color_table *color_table;
   NSColor *color;
-  if (!idx)
+  NSNumber *index;
+
+  if (!f)
+    return;
+
+  color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
+
+  if (idx <= 0 || idx >= color_table->size) {
+    message1("ns_free_indexed_color: Color index out of range.\n");
+    return;
+  }
+
+  index = [NSNumber numberWithUnsignedInt: idx];
+  if ([color_table->empty_indices containsObject: index]) {
+    message1("ns_free_indexed_color: attempt to free already freed color.\n");
     return;
+  }
+
   color = color_table->colors[idx];
   [color release];
   color_table->colors[idx] = nil;
@@ -1402,13 +1417,22 @@ ns_get_color (const char *name, NSColor **col)
   /* Direct colors (hex values) */
   if (hex)
     {
-      unsigned int color = 0;
+      unsigned long color = 0;
       if (sscanf (hex, "%x", &color))
         {
-          float f1 = ((color >> 24) & 0xff) / 255.0;
-          float f2 = ((color >> 16) & 0xff) / 255.0;
-          float f3 = ((color >>  8) & 0xff) / 255.0;
-          float f4 = ((color      ) & 0xff) / 255.0;
+          float f1, f2, f3, f4;
+          /* Assume it's either 1 byte or 2 per channel... */
+          if (strlen(hex) > 8) {
+            f1 = ((color >> 48) & 0xffff) / 65535.0;
+            f2 = ((color >> 32) & 0xffff) / 65535.0;
+            f3 = ((color >> 16) & 0xffff) / 65535.0;
+            f4 = ((color      ) & 0xffff) / 65535.0;
+          } else {
+            f1 = ((color >> 24) & 0xff) / 255.0;
+            f2 = ((color >> 16) & 0xff) / 255.0;
+            f3 = ((color >>  8) & 0xff) / 255.0;
+            f4 = ((color      ) & 0xff) / 255.0;
+          }
 
           switch (color_space)
             {
@@ -1458,17 +1482,13 @@ ns_get_color (const char *name, NSColor **col)
     NSEnumerator *lenum, *cenum;
     NSString *name;
     NSColorList *clist;
+
 #ifdef NS_IMPL_GNUSTEP
     /* XXX: who is wrong, the requestor or the implementation? */
     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
         == NSOrderedSame)
       nsname = @"highlightColor";
 #endif
-    if ([nsname compare: @"dark blue" options: NSCaseInsensitiveSearch]
-        == NSOrderedSame
-      || [nsname compare: @"darkblue" options: NSCaseInsensitiveSearch]
-        == NSOrderedSame)
-      nsname = @"navy blue";
 
     lenum = [[NSColorList availableColorLists] objectEnumerator];
     while ( (clist = [lenum nextObject]) && new == nil)
@@ -1620,6 +1640,39 @@ ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
 }
 
 
+void
+x_set_frame_alpha (struct frame *f)
+/* --------------------------------------------------------------------------
+     change the entire-frame transparency
+   -------------------------------------------------------------------------- */
+{
+  struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
+  EmacsView *view = FRAME_NS_VIEW (f);
+  double alpha = 1.0;
+  double alpha_min = 1.0;
+
+  if (dpyinfo->x_highlight_frame == f)
+    alpha = f->alpha[0];
+  else
+    alpha = f->alpha[1];
+
+  if (FLOATP (Vframe_alpha_lower_limit))
+    alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
+  else if (INTEGERP (Vframe_alpha_lower_limit))
+    alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
+
+  if (alpha < 0.0)
+    return;
+  else if (1.0 < alpha)
+    alpha = 1.0;
+  else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
+    alpha = alpha_min;
+
+#ifdef NS_IMPL_COCOA
+  [[view window] setAlphaValue: alpha];
+#endif
+}
+
 
 /* ==========================================================================
 
@@ -1676,10 +1729,10 @@ note_mouse_movement (struct frame *frame, float x, float y)
      known as last_mouse_glyph.
      ------------------------------------------------------------------------ */
 {
-  NSTRACE (note_mouse_movement);
+//  NSTRACE (note_mouse_movement);
 
   XSETFRAME (last_mouse_motion_frame, frame);
-  
+
   /* Note, this doesn't get called for enter/leave, since we don't have a
      position.  Those are taken care of in the corresponding NSView methods. */
 
@@ -1939,6 +1992,8 @@ ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
   if (!view || !face)
     return;
 
+  NSTRACE (ns_clear_frame_area);
+
   r = NSIntersectionRect (r, [view frame]);
   ns_focus (f, &r, 1);
   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
@@ -2273,22 +2328,26 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
                        int on_p, int active_p)
 /* --------------------------------------------------------------------------
      External call (RIF): draw cursor
+     (modeled after x_draw_window_cursor
+     FIXME: cursor_width is effectively bogus -- it sometimes gets set
+     in xdisp.c set_frame_cursor_types, sometimes left uninitialized;
+     DON'T USE IT (no other terms do)
    -------------------------------------------------------------------------- */
 {
   NSRect r, s;
   int fx, fy, h;
   struct frame *f = WINDOW_XFRAME (w);
   struct glyph *phys_cursor_glyph;
-  int overspill;
-  unsigned char drawGlyph = 0, cursorType, oldCursorType;
+  int overspill, cursorToDraw;
 
   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);
 
   if (!on_p)
-      return;
+       return;
 
   w->phys_cursor_type = cursor_type;
-  w->phys_cursor_on_p = 1;
+  w->phys_cursor_on_p = on_p;
 
   if (cursor_type == NO_CURSOR)
     {
@@ -2321,75 +2380,57 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
   if (overspill > 0)
     r.size.width -= overspill;
 
-  /* TODO: 23: use emacs stored f->cursor_type instead of ns-specific */
-  oldCursorType = FRAME_CURSOR (f);
-  cursorType = FRAME_CURSOR (f) = FRAME_NEW_CURSOR (f);
-  f->output_data.ns->current_cursor_color
-    = f->output_data.ns->desired_cursor_color;
-
   /* TODO: only needed in rare cases with last-resort font in HELLO..
      should we do this more efficiently? */
-  ns_clip_to_row (w, glyph_row, -1, NO);
-/*  ns_focus (f, &r, 1); */
-
-  if (FRAME_LAST_INACTIVE (f))
-    {
-      /* previously hollow box; clear entire area */
-      [FRAME_BACKGROUND_COLOR (f) set];
-      NSRectFill (r);
-      drawGlyph = 1;
-      FRAME_LAST_INACTIVE (f) = NO;
-    }
-
-  /* prepare to draw */
-  if (cursorType == no_highlight || cursor_type == NO_CURSOR)
-    {
-      /* clearing for blink: erase the cursor itself */
-      [FRAME_BACKGROUND_COLOR (f) set];
-      cursorType = oldCursorType; /* just clear what we had before */
-    }
-  else
-      [FRAME_CURSOR_COLOR (f) set];
+  ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
+  [FRAME_CURSOR_COLOR (f) set];
 
-  if (!active_p)
-    {
-      /* inactive window: ignore what we just set and use a hollow box */
-      cursorType = hollow_box;
-      [FRAME_CURSOR_COLOR (f) set];
-    }
+#ifdef NS_IMPL_COCOA
+  /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
+           atomic.  Cleaner ways of doing this should be investigated.
+           One way would be to set a global variable DRAWING_CURSOR
+          when making the call to draw_phys..(), don't focus in that
+          case, then move the ns_unfocus() here after that call. */
+  NSDisableScreenUpdates ();
+#endif
 
-  switch (cursorType)
+  cursorToDraw = active_p ? cursor_type : HOLLOW_BOX_CURSOR;
+  switch (cursorToDraw)
     {
-    case no_highlight:
+    case NO_CURSOR:
       break;
-    case filled_box:
+    case FILLED_BOX_CURSOR:
       NSRectFill (r);
-      drawGlyph = 1;
       break;
-    case hollow_box:
+    case HOLLOW_BOX_CURSOR:
       NSRectFill (r);
       [FRAME_BACKGROUND_COLOR (f) set];
       NSRectFill (NSInsetRect (r, 1, 1));
       [FRAME_CURSOR_COLOR (f) set];
-      drawGlyph = 1;
       break;
-    case underscore:
+    case HBAR_CURSOR:
       s = r;
       s.origin.y += lrint (0.75 * s.size.height);
+      s.size.width = min (FRAME_COLUMN_WIDTH (f), s.size.width);
       s.size.height = lrint (s.size.height * 0.25);
       NSRectFill (s);
       break;
-    case bar:
+    case BAR_CURSOR:
       s = r;
-      s.size.width = 1;
+      s.size.width = min (cursor_width, 2); //FIXME(see above)
       NSRectFill (s);
       break;
     }
   ns_unfocus (f);
 
-  /* if needed, draw the character under the cursor */
-  if (drawGlyph)
+  /* draw the character under the cursor */
+  if (cursorToDraw != NO_CURSOR)
     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
+
+#ifdef NS_IMPL_COCOA
+  NSEnableScreenUpdates ();
+#endif
+
 }
 
 
@@ -2403,6 +2444,8 @@ ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
   struct face *face;
   NSRect r = NSMakeRect (x, y0, 2, y1-y0);
 
+  NSTRACE (ns_draw_vertical_window_border);
+
   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
   if (face)
       [ns_lookup_indexed_color(face->foreground, f) set];
@@ -2452,11 +2495,11 @@ hide_hourglass ()
 
 
 static inline NSRect
+ns_fix_rect_ibw (NSRect r, int fibw, int frame_pixel_width)
 /* --------------------------------------------------------------------------
     Under NS we draw internal borders inside fringes, and want full-width
     rendering to go all the way to edge.  This function makes that correction.
    -------------------------------------------------------------------------- */
-ns_fix_rect_ibw (NSRect r, int fibw, int frame_pixel_width)
 {
   if (r.origin.y <= fibw+1)
     {
@@ -2851,13 +2894,22 @@ ns_draw_glyph_string (struct glyph_string *s)
 
   NSTRACE (ns_draw_glyph_string);
 
-  if (s->next && s->right_overhang && !s->for_overlaps && s->hl != DRAW_CURSOR)
+  if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
     {
-      xassert (s->next->img == NULL);
-      n = ns_get_glyph_string_clip_rect (s->next, r);
-      ns_focus (s->f, r, n);
-      ns_maybe_dumpglyphs_background (s->next, 1);
-      ns_unfocus (s->f);
+      int width;
+      struct glyph_string *next;
+
+      for (width = 0, next = s->next;
+          next && width < s->right_overhang;
+          width += next->width, next = next->next)
+       if (next->first_glyph->type != IMAGE_GLYPH)
+          {
+            n = ns_get_glyph_string_clip_rect (s->next, r);
+            ns_focus (s->f, r, n);
+            ns_maybe_dumpglyphs_background (s->next, 1);
+            ns_unfocus (s->f);
+            next->num_clips = 0;
+          }
     }
 
   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
@@ -2932,7 +2984,8 @@ ns_draw_glyph_string (struct glyph_string *s)
       n = ns_get_glyph_string_clip_rect (s, r);
       ns_focus (s->f, r, n);
 
-      if (s->for_overlaps || s->gidx > 0)
+      if (s->for_overlaps || (s->cmp_from > 0
+                             && ! s->first_glyph->u.cmp.automatic))
         s->background_filled_p = 1;
       else      /* 1 */
         ns_maybe_dumpglyphs_background
@@ -2967,6 +3020,7 @@ ns_draw_glyph_string (struct glyph_string *s)
       ns_unfocus (s->f);
     }
 
+  s->num_clips = 0;
 }
 
 
@@ -3072,7 +3126,7 @@ ns_read_socket (struct terminal *terminal, int expected,
 
   /* If have pending open-file requests, attend to the next one of those. */
   if (ns_pending_files && [ns_pending_files count] != 0
-      && [NSApp openFile: [ns_pending_files objectAtIndex: 0]])
+      && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
     {
       [ns_pending_files removeObjectAtIndex: 0];
     }
@@ -3176,35 +3230,6 @@ ns_select (int nfds, fd_set *readfds, fd_set *writefds,
                                               repeats: YES]
                retain];
 
-  if (!NILP (ns_cursor_blink_mode) && !cursor_blink_entry)
-    {
-      if (!NUMBERP (ns_cursor_blink_rate))
-        ns_cursor_blink_rate = make_float (0.5);
-      cursor_blink_entry = [[NSTimer
-        scheduledTimerWithTimeInterval: XFLOATINT (ns_cursor_blink_rate)
-                                target: NSApp
-                              selector: @selector (cursor_blink_handler:)
-                              userInfo: 0
-                               repeats: YES]
-                             retain];
-    }
-  else if (NILP (ns_cursor_blink_mode) && cursor_blink_entry)
-    {
-      if (NUMBERP (ns_cursor_blink_rate))
-          ns_cursor_blink_rate = Qnil;
-      struct ns_display_info *dpyinfo = x_display_list; /* HACK */
-      [cursor_blink_entry invalidate];
-      [cursor_blink_entry release];
-      cursor_blink_entry = 0;
-      if (dpyinfo->x_highlight_frame)
-        {
-          Lisp_Object tem
-           = get_frame_param (dpyinfo->x_highlight_frame, Qcursor_type);
-          dpyinfo->x_highlight_frame->output_data.ns->desired_cursor
-           = ns_lisp_to_cursor_type (tem);
-        }
-    }
-
   /* Let Application dispatch events until it receives an event of the type
        NX_APPDEFINED, which should only be sent by timeout_handler.  */
   inNsSelect = 1;
@@ -3438,6 +3463,23 @@ 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;
+{
+  NSScreen *screen = [NSScreen mainScreen];
+  return [screen frame].size.height;
+}
+
+int
+x_display_pixel_width (dpyinfo)
+     struct ns_display_info *dpyinfo;
+{
+  NSScreen *screen = [NSScreen mainScreen];
+  return [screen frame].size.width;
+}
+
+
 static Lisp_Object ns_string_to_lispmod (const char *s)
 /* --------------------------------------------------------------------------
      Convert modifier name to lisp symbol
@@ -3490,8 +3532,6 @@ ns_set_default_prefs ()
   ns_command_modifier = Qsuper;
   ns_control_modifier = Qcontrol;
   ns_function_modifier = Qnone;
-  ns_cursor_blink_rate = Qnil;
-  ns_cursor_blink_mode = Qnil;
   ns_expand_space = make_float (0.0);
   ns_antialias_text = Qt;
   ns_antialias_threshold = 10.0; /* not exposed to lisp side */
@@ -3539,8 +3579,6 @@ ns_initialize_display_info (struct ns_display_info *dpyinfo)
     NSScreen *screen = [NSScreen mainScreen];
     NSWindowDepth depth = [screen depth];
 
-    dpyinfo->width = [screen frame].size.width;
-    dpyinfo->height = [screen frame].size.height;
     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
     dpyinfo->resy = 72.27;
     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
@@ -3624,7 +3662,7 @@ ns_delete_terminal (struct terminal *terminal)
   struct ns_display_info *dpyinfo = terminal->display_info.ns;
   int i;
 
-  /* Protect against recursive calls.  Fdelete_frame in
+  /* Protect against recursive calls.  delete_frame in
      delete_terminal calls us back when it deletes our last frame.  */
   if (!terminal->name)
     return;
@@ -3798,10 +3836,6 @@ ns_term_init (Lisp_Object display_name)
              Qnil, Qnil, NO, YES);
   if (NILP (ns_function_modifier))
     ns_function_modifier = Qnone;
-  ns_default ("CursorBlinkRate", &ns_cursor_blink_rate,
-             make_float (0.5), Qnil, YES, NO);
-  if (NUMBERP (ns_cursor_blink_rate))
-    ns_cursor_blink_mode = Qt;
   ns_default ("ExpandSpace", &ns_expand_space,
              make_float (0.5), make_float (0.0), YES, NO);
   ns_default ("GSFontAntiAlias", &ns_antialias_text,
@@ -3884,6 +3918,7 @@ ns_term_init (Lisp_Object display_name)
     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
     [appMenu setAutoenablesItems: NO];
     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
+    dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
 
     [appMenu insertItemWithTitle: @"About Emacs"
                           action: @selector (orderFrontStandardAboutPanel:)
@@ -3922,6 +3957,10 @@ ns_term_init (Lisp_Object display_name)
                            keyEquivalent: @""
                                  atIndex: 0];
     [mainMenu setSubmenu: appMenu forItem: item];
+    [dockMenu insertItemWithTitle: @"New Frame"
+                          action: @selector (newFrame:)
+                   keyEquivalent: @""
+                         atIndex: 0];
 
     [NSApp setMainMenu: mainMenu];
     [NSApp setAppleMenu: appMenu];
@@ -4030,6 +4069,20 @@ ns_term_shutdown (int sig)
 }
 
 
+- (void)newFrame: (id)sender
+{
+  struct frame *emacsframe = SELECTED_FRAME ();
+  NSEvent *theEvent = [NSApp currentEvent];
+
+  if (!emacs_event)
+    return;
+  emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
+  emacs_event->code = KEY_NS_NEW_FRAME;
+  emacs_event->modifiers = 0;
+  EV_TRAILER (theEvent);
+}
+
+
 /* Open a file (used by below, after going into queue read by ns_read_socket) */
 - (BOOL) openFile: (NSString *)fileName
 {
@@ -4065,7 +4118,7 @@ ns_term_shutdown (int sig)
   [NSApp setServicesProvider: NSApp];
   ns_send_appdefined (-2);
 }
+
 
 - (void) terminate: (id)sender
 {
@@ -4133,14 +4186,22 @@ fprintf (stderr, "res = %d\n", EQ (res, Qt)); /* FIXME */
   while ((file = [files nextObject]) != nil)
     [ns_pending_files addObject: file];
 
-#ifdef NS_IMPL_GNUSTEP
-  [self replyToOpenOrPrint: 0];
-#else
+/* TODO: when GNUstep implements this (and we require that version of
+         GNUstep), remove. */
+#ifndef NS_IMPL_GNUSTEP
   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
-#endif /* NS_IMPL_GNUSTEP */
+#endif /* !NS_IMPL_GNUSTEP */
+
+}
+
 
+/* Handle dock menu requests.  */
+- (NSMenu *)applicationDockMenu: (NSApplication *) sender
+{
+  return dockMenu;
 }
 
+
 /* TODO: these may help w/IO switching btwn terminal and NSApp */
 - (void)applicationDidBecomeActive: (NSNotification *)notification
 {
@@ -4170,31 +4231,6 @@ fprintf (stderr, "res = %d\n", EQ (res, Qt)); /* FIXME */
 
 extern void update_window_cursor (struct window *w, int on);
 
-- (void)cursor_blink_handler: (NSTimer *)cursorEntry
-/* --------------------------------------------------------------------------
-     Flash the cursor
-   -------------------------------------------------------------------------- */
-{
-  struct ns_display_info *dpyinfo = x_display_list; /*HACK, but OK for now */
-  struct frame *f = dpyinfo->x_highlight_frame;
-  NSTRACE (cursor_blink_handler);
-
-  if (!f)
-    return;
-  if (f->output_data.ns->current_cursor == no_highlight)
-    {
-      Lisp_Object tem = get_frame_param (f, Qcursor_type);
-      f->output_data.ns->desired_cursor = ns_lisp_to_cursor_type (tem);
-    }
-  else
-    {
-      f->output_data.ns->desired_cursor = no_highlight;
-    }
-  update_window_cursor (XWINDOW (FRAME_SELECTED_WINDOW (f)), 1);
-  /*x_update_cursor (f, 1); */
-}
-
-
 - (void)fd_handler: (NSTimer *) fdEntry
 /* --------------------------------------------------------------------------
      Check data waiting on file descriptors and terminate if so
@@ -4300,6 +4336,8 @@ extern void update_window_cursor (struct window *w, int on);
   if (newFont = [sender convertFont:
                            ((struct nsfont_info *)face->font)->nsfont])
     {
+      SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
+
       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
       emacs_event->modifiers = 0;
       emacs_event->code = KEY_NS_CHANGE_FONT;
@@ -4645,17 +4683,10 @@ if (NS_KEYLOG) NSLog (@"firstRectForCharRange request");
   return rect;
 }
 
-#ifdef NS_IMPL_GNUSTEP
-- (long)conversationIdentifier
-{
-  return (long)self;
-}
-#else
 - (NSInteger)conversationIdentifier
 {
   return (NSInteger)self;
 }
-#endif
 
 /* TODO: below here not yet implemented correctly, but may not be needed */
 
@@ -4750,16 +4781,23 @@ if (NS_KEYLOG) NSLog (@"attributedSubstringFromRange request");
 }
 
 
-- (void)mouseUp: (NSEvent *)theEvent
+- (void)rightMouseDown: (NSEvent *)theEvent
 {
-  NSTRACE (mouseUp);
+  NSTRACE (rightMouseDown);
   [self mouseDown: theEvent];
 }
 
 
-- (void)rightMouseDown: (NSEvent *)theEvent
+- (void)otherMouseDown: (NSEvent *)theEvent
 {
-  NSTRACE (rightMouseDown);
+  NSTRACE (otherMouseDown);
+  [self mouseDown: theEvent];
+}
+
+
+- (void)mouseUp: (NSEvent *)theEvent
+{
+  NSTRACE (mouseUp);
   [self mouseDown: theEvent];
 }
 
@@ -4771,6 +4809,13 @@ if (NS_KEYLOG) NSLog (@"attributedSubstringFromRange request");
 }
 
 
+- (void)otherMouseUp: (NSEvent *)theEvent
+{
+  NSTRACE (otherMouseUp);
+  [self mouseDown: theEvent];
+}
+
+
 - (void) scrollWheel: (NSEvent *)theEvent
 {
   NSTRACE (scrollWheel);
@@ -4784,7 +4829,7 @@ if (NS_KEYLOG) NSLog (@"attributedSubstringFromRange request");
   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
   Lisp_Object frame;
 
-  NSTRACE (mouseMoved);
+//  NSTRACE (mouseMoved);
 
   last_mouse_movement_time = EV_TIMESTAMP (e);
   last_mouse_motion_position
@@ -4839,14 +4884,19 @@ if (NS_KEYLOG) NSLog (@"attributedSubstringFromRange request");
 }
 
 
+- (void)otherMouseDragged: (NSEvent *)e
+{
+  NSTRACE (otherMouseDragged);
+  [self mouseMoved: e];
+}
+
+
 - (BOOL)windowShouldClose: (id)sender
 {
   NSEvent *e =[[self window] currentEvent];
 
   NSTRACE (windowShouldClose);
   windowClosing = YES;
-  if (ns_window_num <= 1)
-    return NO;
   if (!emacs_event)
     return NO;
   emacs_event->kind = DELETE_WINDOW_EVENT;
@@ -4954,7 +5004,7 @@ if (NS_KEYLOG) NSLog (@"attributedSubstringFromRange request");
 
   ns_send_appdefined (-1);
 
-  /* The following line causes a crash on GNUstep.  Adrian Roberts
+  /* The following line causes a crash on GNUstep.  Adrian Robert
      says he doesn't remember why he added this line, but removing it
      doesn't seem to cause problems on OSX, either.  */
 #if 0
@@ -4964,8 +5014,8 @@ if (NS_KEYLOG) NSLog (@"attributedSubstringFromRange request");
 
 
 - (void)windowDidBecomeKey: (NSNotification *)notification
+/* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
 {
-  int val = ns_lisp_to_cursor_type (get_frame_param (emacsframe, Qcursor_type));
   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
   struct frame *old_focus = dpyinfo->x_focus_frame;
 
@@ -4973,13 +5023,6 @@ if (NS_KEYLOG) NSLog (@"attributedSubstringFromRange request");
 
   if (emacsframe != old_focus)
     dpyinfo->x_focus_frame = emacsframe;
-  /*/last_mouse_frame = emacsframe;? */
-
-  if (val >= 0)
-    {
-      FRAME_NEW_CURSOR (emacsframe) = val;
-/*    x_update_cursor (emacsframe, 1); // will happen in ns_frame_rehighlight */
-    }
 
   ns_frame_rehighlight (emacsframe);
 
@@ -4992,26 +5035,22 @@ if (NS_KEYLOG) NSLog (@"attributedSubstringFromRange request");
 
 
 - (void)windowDidResignKey: (NSNotification *)notification
+/* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
 {
   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
   NSTRACE (windowDidResignKey);
 
-  if (!windowClosing && [[self window] isVisible] == YES)
-    {
-      FRAME_NEW_CURSOR (emacsframe) = hollow_box;
-      x_update_cursor (emacsframe, 1);
-      FRAME_LAST_INACTIVE (emacsframe) = YES;
-    }
-
-  if (dpyinfo->x_highlight_frame == emacsframe)
-    dpyinfo->x_highlight_frame = 0;
   if (dpyinfo->x_focus_frame == emacsframe)
     dpyinfo->x_focus_frame = 0;
 
-  if (dpyinfo->mouse_face_mouse_frame == emacsframe)
+  ns_frame_rehighlight (emacsframe);
+
+  /* FIXME: for some reason needed on second and subsequent clicks away
+            from sole-frame Emacs to get hollow box to show */
+  if (!windowClosing && [[self window] isVisible] == YES)
     {
-      clear_mouse_face (dpyinfo);
-      dpyinfo->mouse_face_mouse_frame = 0;
+      x_update_cursor (emacsframe, 1);
+      x_set_frame_alpha (emacsframe);
     }
 
   if (emacs_event)
@@ -6010,18 +6049,15 @@ static void selectItemWithTag (NSPopUpButton *popup, int tag)
   int cursorType
     = ns_lisp_to_cursor_type (get_frame_param (frame, Qcursor_type));
   prevExpandSpace = XFLOATINT (ns_expand_space);
-  prevBlinkRate = NILP (ns_cursor_blink_rate)
-    ? 0 : XFLOATINT (ns_cursor_blink_rate);
 
 #ifdef NS_IMPL_COCOA
   prevUseHighlightColor = ns_use_system_highlight_color;
 #endif
 
   [expandSpaceSlider setFloatValue: prevExpandSpace];
-  [cursorBlinkSlider setFloatValue: prevBlinkRate];
-  [cursorTypeMatrix selectCellWithTag: (cursorType == filled_box ? 1 :
-                                        (cursorType == bar ? 2 :
-                                         (cursorType == underscore ? 3 : 4)))];
+  [cursorTypeMatrix selectCellWithTag: (cursorType == FILLED_BOX_CURSOR ? 1 :
+                                        (cursorType == BAR_CURSOR ? 2 :
+                                         (cursorType == HBAR_CURSOR ? 3 : 4)))];
   selectItemWithTag (alternateModMenu,
                     parse_solitary_modifier (ns_alternate_modifier));
   selectItemWithTag (commandModMenu,
@@ -6040,16 +6076,18 @@ static void selectItemWithTag (NSPopUpButton *popup, int tag)
 
 - (void) setValuesFromPanel
 {
-  int cursorTag = [[cursorTypeMatrix selectedCell] tag];
   int altTag = [[alternateModMenu selectedItem] tag];
   int cmdTag = [[commandModMenu selectedItem] tag];
 #ifdef NS_IMPL_COCOA
   int ctrlTag = [[controlModMenu selectedItem] tag];
   int fnTag = [[functionModMenu selectedItem] tag];
 #endif
-  float blinkRate = [cursorBlinkSlider floatValue];
   float expandSpace = [expandSpaceSlider floatValue];
-  Lisp_Object old_cursor_blink_mode;
+  int cursorTag = [[cursorTypeMatrix selectedCell] tag];
+  Lisp_Object cursor_type = ns_cursor_type_to_lisp
+       ( cursorTag == 1 ? FILLED_BOX_CURSOR
+       : cursorTag == 2 ? BAR_CURSOR
+       : cursorTag == 3 ? HBAR_CURSOR : HOLLOW_BOX_CURSOR);
 
   if (expandSpace != prevExpandSpace)
     {
@@ -6060,44 +6098,10 @@ static void selectItemWithTag (NSPopUpButton *popup, int tag)
            x_set_window_size (frame, 0, frame->text_cols, frame->text_lines); */
       prevExpandSpace = expandSpace;
     }
-  if (blinkRate != prevBlinkRate)
-    {
-      old_cursor_blink_mode = ns_cursor_blink_mode;
-      if (blinkRate == 0.0)
-        {
-          ns_cursor_blink_rate = Qnil;
-          ns_cursor_blink_mode = Qnil;
-        }
-      else
-        {
-          ns_cursor_blink_rate = make_float (blinkRate);
-          ns_cursor_blink_mode = Qt;
-        }
-      if (!EQ (ns_cursor_blink_mode, old_cursor_blink_mode))
-          Feval (Fcons (intern ("blink-cursor-mode"), Qnil));
-
-      if (blinkRate != 0.0 && prevBlinkRate != 0.0)
-        {  /* if changed rates, remove blink handler so change picked up */
-          struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
-          [cursor_blink_entry invalidate];
-          [cursor_blink_entry release];
-          cursor_blink_entry = 0;
-          if (dpyinfo->x_highlight_frame)
-            {
-              Lisp_Object tem
-               = get_frame_param (dpyinfo->x_highlight_frame, Qcursor_type);
-              dpyinfo->x_highlight_frame->output_data.ns->desired_cursor
-               = ns_lisp_to_cursor_type (tem);
-            }
-        }
-      prevBlinkRate = blinkRate;
-    }
-  FRAME_NEW_CURSOR (frame)
-    = (cursorTag == 1 ? filled_box
-       : cursorTag == 2 ? bar
-       : cursorTag == 3 ? underscore : hollow_box);
-  store_frame_param (frame, Qcursor_type,
-                    ns_cursor_type_to_lisp (FRAME_NEW_CURSOR (frame)));
+
+  store_frame_param (frame, Qcursor_type, cursor_type);
+  ns_set_cursor_type(frame, cursor_type, Qnil);  /* FIXME: do only if changed */
+
   ns_alternate_modifier = ns_mod_to_lisp (altTag);
   ns_command_modifier = ns_mod_to_lisp (cmdTag);
 #ifdef NS_IMPL_COCOA
@@ -6309,7 +6313,7 @@ ns_xlfd_to_fontname (const char *xlfd)
   char *name = xmalloc (180);
   int i, len;
   const char *ret;
-  
+
   if (!strncmp (xlfd, "--", 2))
     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
   else
@@ -6404,14 +6408,6 @@ Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
 Set to none means that the function key is not interpreted by Emacs at all,\n\
 allowing it to be used at a lower level for accented character entry.");
 
-  DEFVAR_LISP ("ns-cursor-blink-rate", &ns_cursor_blink_rate,
-               "Rate at which the Emacs cursor blinks (in seconds).\n\
-Set to nil to disable blinking.");
-
-  DEFVAR_LISP ("ns-cursor-blink-mode", &ns_cursor_blink_mode,
-               "Internal variable -- use M-x blink-cursor-mode or preferences\n\
-panel to control this setting.");
-
   DEFVAR_LISP ("ns-expand-space", &ns_expand_space,
                "Amount by which spacing between lines is expanded (positive)\n\
 or shrunk (negative).  Zero (the default) means standard line height.\n\
@@ -6479,13 +6475,6 @@ baseline level.  The default value is nil.  */);
 
   /* Tell emacs about this window system. */
   Fprovide (intern ("ns"), Qnil);
-  /* TODO: try to move this back into lisp,  ns-win.el loaded too late
-           right now */
-  {
-    Lisp_Object args[3] = { intern ("ns-version-string"), build_string ("9.0"),
-                    build_string ("NS Window system port version number.") };
-    Fdefconst (Flist (3, args));
-  }
 }