]> code.delx.au - gnu-emacs/blobdiff - src/nsterm.m
Prevent bar cursor overwriting next glyph (bug#16856)
[gnu-emacs] / src / nsterm.m
index ba205f53f4b75e5abe4da4d2b80cfc40d6bec5a4..8da2ffe5b7fd2c02c1c46b6ca28afde16112c07c 100644 (file)
@@ -1,14 +1,14 @@
 /* NeXT/Open/GNUstep / MacOSX communication module.      -*- coding: utf-8 -*-
 
 /* NeXT/Open/GNUstep / MacOSX communication module.      -*- coding: utf-8 -*-
 
-Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2015 Free Software
+Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2016 Free Software
 Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -72,9 +72,26 @@ GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
 extern NSString *NSMenuDidBeginTrackingNotification;
 
 
 extern NSString *NSMenuDidBeginTrackingNotification;
 
 
+/* ==========================================================================
+
+   NSTRACE, Trace support.
+
+   ========================================================================== */
+
 #if NSTRACE_ENABLED
 #if NSTRACE_ENABLED
-int nstrace_num = 0;
-int nstrace_depth = 0;
+
+/* The following use "volatile" since they can be accessed from
+   parallel threads. */
+volatile int nstrace_num = 0;
+volatile int nstrace_depth = 0;
+
+/* When 0, no trace is emitted.  This is used by NSTRACE_WHEN and
+   NSTRACE_UNLESS to silence functions called.
+
+   TODO: This should really be a thread-local variable, to avoid that
+   a function with disabled trace thread silence trace output in
+   another.  However, in practice this seldom is a problem. */
+volatile int nstrace_enabled_global = 1;
 
 /* Called when nstrace_enabled goes out of scope. */
 void nstrace_leave(int * pointer_to_nstrace_enabled)
 
 /* Called when nstrace_enabled goes out of scope. */
 void nstrace_leave(int * pointer_to_nstrace_enabled)
@@ -86,38 +103,24 @@ void nstrace_leave(int * pointer_to_nstrace_enabled)
 }
 
 
 }
 
 
-void ns_print_fullscreen_type_name (char const * s, int fs_type)
+/* Called when nstrace_saved_enabled_global goes out of scope. */
+void nstrace_restore_global_trace_state(int * pointer_to_saved_enabled_global)
 {
 {
-  // This is a support function for the NSTRACE system, don't add a
-  // NSTRACE () here.  However, a local `nstrace_enabled' variable is
-  // needed by the NSTRACE_MSG macros.
-  int nstrace_enabled = 1;
+  nstrace_enabled_global = *pointer_to_saved_enabled_global;
+}
+
 
 
+char const * nstrace_fullscreen_type_name (int fs_type)
+{
   switch (fs_type)
     {
   switch (fs_type)
     {
-    case FULLSCREEN_NONE:
-      NSTRACE_MSG ("%s: FULLSCREEN_NONE", s);
-      break;
-
-    case FULLSCREEN_WIDTH:
-      NSTRACE_MSG ("%s: FULLSCREEN_WIDTH", s);
-      break;
-
-    case FULLSCREEN_HEIGHT:
-      NSTRACE_MSG ("%s: FULLSCREEN_HEIGHT", s);
-      break;
-
-    case FULLSCREEN_BOTH:
-      NSTRACE_MSG ("%s: FULLSCREEN_BOTH", s);
-      break;
-
-    case FULLSCREEN_MAXIMIZED:
-      NSTRACE_MSG ("%s: FULLSCREEN_MAXIMIZED", s);
-      break;
-
-    default:
-      NSTRACE_MSG ("%s: %d", s, fs_type);
-      break;
+    case -1:                   return "-1";
+    case FULLSCREEN_NONE:      return "FULLSCREEN_NONE";
+    case FULLSCREEN_WIDTH:     return "FULLSCREEN_WIDTH";
+    case FULLSCREEN_HEIGHT:    return "FULLSCREEN_HEIGHT";
+    case FULLSCREEN_BOTH:      return "FULLSCREEN_BOTH";
+    case FULLSCREEN_MAXIMIZED: return "FULLSCREEN_MAXIMIZED";
+    default:                   return "FULLSCREEN_?????";
     }
 }
 #endif
     }
 }
 #endif
@@ -581,25 +584,31 @@ ns_load_path (void)
   return NULL;
 }
 
   return NULL;
 }
 
-static void
-ns_timeout (int usecs)
-/* --------------------------------------------------------------------------
-     Blocking timer utility used by ns_ring_bell
-   -------------------------------------------------------------------------- */
+
+void
+ns_init_locale (void)
+/* OS X doesn't set any environment variables for the locale when run
+   from the GUI. Get the locale from the OS and set LANG. */
 {
 {
-  struct timespec wakeup = timespec_add (current_timespec (),
-                                        make_timespec (0, usecs * 1000));
+  NSLocale *locale = [NSLocale currentLocale];
+
+  NSTRACE ("ns_init_locale");
 
 
-  /* Keep waiting until past the time wakeup.  */
-  while (1)
+  @try
     {
     {
-      struct timespec timeout, now = current_timespec ();
-      if (timespec_cmp (wakeup, now) <= 0)
-       break;
-      timeout = timespec_sub (wakeup, now);
+      /* It seems OS X should probably use UTF-8 everywhere.
+         'localeIdentifier' does not specify the encoding, and I can't
+         find any way to get the OS to tell us which encoding to use,
+         so hard-code '.UTF-8'. */
+      NSString *localeID = [NSString stringWithFormat:@"%@.UTF-8",
+                                     [locale localeIdentifier]];
 
 
-      /* Try to wait that long--but we might wake up sooner.  */
-      pselect (0, NULL, NULL, NULL, &timeout, NULL);
+      /* Set LANG to locale, but not if LANG is already set. */
+      setenv("LANG", [localeID UTF8String], 0);
+    }
+  @catch (NSException *e)
+    {
+      NSLog (@"Locale detection failed: %@: %@", [e name], [e reason]);
     }
 }
 
     }
 }
 
@@ -644,42 +653,130 @@ ns_release_autorelease_pool (void *pool)
 }
 
 
 }
 
 
-/* True, if the menu bar should be hidden.  */
-
 static BOOL
 ns_menu_bar_should_be_hidden (void)
 static BOOL
 ns_menu_bar_should_be_hidden (void)
+/* True, if the menu bar should be hidden.  */
 {
   return !NILP (ns_auto_hide_menu_bar)
     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
 }
 
 
 {
   return !NILP (ns_auto_hide_menu_bar)
     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
 }
 
 
-static CGFloat
-ns_menu_bar_height (NSScreen *screen)
-/* The height of the menu bar, if visible. */
+struct EmacsMargins
+{
+  CGFloat top;
+  CGFloat bottom;
+  CGFloat left;
+  CGFloat right;
+};
+
+
+static struct EmacsMargins
+ns_screen_margins (NSScreen *screen)
+/* The parts of SCREEN used by the operating system.  */
 {
 {
-  //  NSTRACE ("ns_menu_bar_height");
+  NSTRACE ("ns_screen_margins");
+
+  struct EmacsMargins margins;
 
 
-  CGFloat res;
+  NSRect screenFrame = [screen frame];
+  NSRect screenVisibleFrame = [screen visibleFrame];
 
 
+  /* Sometimes, visibleFrame isn't up-to-date with respect to a hidden
+     menu bar, check this explicitly.  */
   if (ns_menu_bar_should_be_hidden())
     {
   if (ns_menu_bar_should_be_hidden())
     {
-      res = 0;
+      margins.top = 0;
     }
   else
     {
     }
   else
     {
-      NSRect screenFrame = [screen frame];
-      NSRect screenVisibleFrame = [screen visibleFrame];
-
       CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
       CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
                                  + screenVisibleFrame.size.height);
 
       CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
       CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
                                  + screenVisibleFrame.size.height);
 
-      res = frameTop - visibleFrameTop;
+      margins.top = frameTop - visibleFrameTop;
+    }
+
+  {
+    CGFloat frameRight = screenFrame.origin.x + screenFrame.size.width;
+    CGFloat visibleFrameRight = (screenVisibleFrame.origin.x
+                                 + screenVisibleFrame.size.width);
+    margins.right = frameRight - visibleFrameRight;
+  }
+
+  margins.bottom = screenVisibleFrame.origin.y - screenFrame.origin.y;
+  margins.left   = screenVisibleFrame.origin.x - screenFrame.origin.x;
+
+  NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
+               margins.left,
+               margins.right,
+               margins.top,
+               margins.bottom);
+
+  return margins;
+}
+
+
+/* A screen margin between 1 and DOCK_IGNORE_LIMIT (inclusive) is
+   assumed to contain a hidden dock.  OS X currently use 4 pixels for
+   this, however, to be future compatible, a larger value is used.  */
+#define DOCK_IGNORE_LIMIT 6
 
 
+static struct EmacsMargins
+ns_screen_margins_ignoring_hidden_dock (NSScreen *screen)
+/* The parts of SCREEN used by the operating system, excluding the parts
+reserved for an hidden dock.  */
+{
+  NSTRACE ("ns_screen_margins_ignoring_hidden_dock");
+
+  struct EmacsMargins margins = ns_screen_margins(screen);
+
+  /* OS X (currently) reserved 4 pixels along the edge where a hidden
+     dock is located.  Unfortunately, it's not possible to find the
+     location and information about if the dock is hidden.  Instead,
+     it is assumed that if the margin of an edge is less than
+     DOCK_IGNORE_LIMIT, it contains a hidden dock.  */
+  if (margins.left <= DOCK_IGNORE_LIMIT)
+    {
+      margins.left = 0;
+    }
+  if (margins.right <= DOCK_IGNORE_LIMIT)
+    {
+      margins.right = 0;
     }
     }
+  if (margins.top <= DOCK_IGNORE_LIMIT)
+    {
+      margins.top = 0;
+    }
+  /* Note: This doesn't occur in current versions of OS X, but
+     included for completeness and future compatibility.  */
+  if (margins.bottom <= DOCK_IGNORE_LIMIT)
+    {
+      margins.bottom = 0;
+    }
+
+  NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
+               margins.left,
+               margins.right,
+               margins.top,
+               margins.bottom);
+
+  return margins;
+}
+
+
+static CGFloat
+ns_menu_bar_height (NSScreen *screen)
+/* The height of the menu bar, if visible.
 
 
-  // NSTRACE_MSG (NSTRACE_FMT_RETURN "%.0f", res);
+   Note: Don't use this when fullscreen is enabled -- the screen
+   sometimes includes, sometimes excludes the menu bar area.  */
+{
+  struct EmacsMargins margins = ns_screen_margins(screen);
+
+  CGFloat res = margins.top;
+
+  NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res);
 
   return res;
 }
 
   return res;
 }
@@ -733,7 +830,7 @@ ns_menu_bar_height (NSScreen *screen)
 //    Result: Menu bar visible, frame placed immediately below the menu.
 //
 
 //    Result: Menu bar visible, frame placed immediately below the menu.
 //
 
-static NSRect constrain_frame_rect(NSRect frameRect)
+static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
 {
   NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
              NSTRACE_ARG_RECT (frameRect));
 {
   NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
              NSTRACE_ARG_RECT (frameRect));
@@ -765,7 +862,11 @@ static NSRect constrain_frame_rect(NSRect frameRect)
         {
           multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
 
         {
           multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
 
-          menu_bar_height = max(menu_bar_height, ns_menu_bar_height (s));
+          if (!isFullscreen)
+            {
+              CGFloat screen_menu_bar_height = ns_menu_bar_height (s);
+              menu_bar_height = max(menu_bar_height, screen_menu_bar_height);
+            }
         }
     }
 
         }
     }
 
@@ -839,29 +940,41 @@ static NSRect constrain_frame_rect(NSRect frameRect)
 
 static void
 ns_constrain_all_frames (void)
 
 static void
 ns_constrain_all_frames (void)
+/* --------------------------------------------------------------------------
+     Ensure that the menu bar doesn't cover any frames.
+   -------------------------------------------------------------------------- */
 {
   Lisp_Object tail, frame;
 
   NSTRACE ("ns_constrain_all_frames");
 
 {
   Lisp_Object tail, frame;
 
   NSTRACE ("ns_constrain_all_frames");
 
+  block_input ();
+
   FOR_EACH_FRAME (tail, frame)
     {
       struct frame *f = XFRAME (frame);
       if (FRAME_NS_P (f))
         {
   FOR_EACH_FRAME (tail, frame)
     {
       struct frame *f = XFRAME (frame);
       if (FRAME_NS_P (f))
         {
-          NSView *view = FRAME_NS_VIEW (f);
+          EmacsView *view = FRAME_NS_VIEW (f);
 
 
-          [[view window] setFrame:constrain_frame_rect([[view window] frame])
-                          display:NO];
+          if (![view isFullscreen])
+            {
+              [[view window]
+                setFrame:constrain_frame_rect([[view window] frame], false)
+                 display:NO];
+            }
         }
     }
         }
     }
-}
 
 
+  unblock_input ();
+}
 
 
-/* Show or hide the menu bar, based on user setting.  */
 
 static void
 ns_update_auto_hide_menu_bar (void)
 
 static void
 ns_update_auto_hide_menu_bar (void)
+/* --------------------------------------------------------------------------
+     Show or hide the menu bar, based on user setting.
+   -------------------------------------------------------------------------- */
 {
 #ifdef NS_IMPL_COCOA
   NSTRACE ("ns_update_auto_hide_menu_bar");
 {
 #ifdef NS_IMPL_COCOA
   NSTRACE ("ns_update_auto_hide_menu_bar");
@@ -907,7 +1020,7 @@ ns_update_begin (struct frame *f)
    -------------------------------------------------------------------------- */
 {
   EmacsView *view = FRAME_NS_VIEW (f);
    -------------------------------------------------------------------------- */
 {
   EmacsView *view = FRAME_NS_VIEW (f);
-  NSTRACE ("ns_update_begin");
+  NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
 
   ns_update_auto_hide_menu_bar ();
 
 
   ns_update_auto_hide_menu_bar ();
 
@@ -964,7 +1077,7 @@ ns_update_window_begin (struct window *w)
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
 
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
 
-  NSTRACE ("ns_update_window_begin");
+  NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_begin");
   w->output_cursor = w->cursor;
 
   block_input ();
   w->output_cursor = w->cursor;
 
   block_input ();
@@ -994,7 +1107,7 @@ ns_update_window_end (struct window *w, bool cursor_on_p,
    external (RIF) call; for one window called before update_end
    -------------------------------------------------------------------------- */
 {
    external (RIF) call; for one window called before update_end
    -------------------------------------------------------------------------- */
 {
-  NSTRACE ("update_window_end");
+  NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_end");
 
   /* note: this fn is nearly identical in all terms */
   if (!w->pseudo_window_p)
 
   /* note: this fn is nearly identical in all terms */
   if (!w->pseudo_window_p)
@@ -1033,7 +1146,7 @@ ns_update_end (struct frame *f)
 {
   EmacsView *view = FRAME_NS_VIEW (f);
 
 {
   EmacsView *view = FRAME_NS_VIEW (f);
 
-  NSTRACE ("ns_update_end");
+  NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
 
 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
 
 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
@@ -1058,11 +1171,11 @@ ns_focus (struct frame *f, NSRect *r, int n)
      the entire window.
    -------------------------------------------------------------------------- */
 {
      the entire window.
    -------------------------------------------------------------------------- */
 {
-//  NSTRACE ("ns_focus");
-/* static int c =0;
-   fprintf (stderr, "focus: %d", c++);
-   if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
-   fprintf (stderr, "\n"); */
+  NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
+  if (r != NULL)
+    {
+      NSTRACE_RECT ("r", *r);
+    }
 
   if (f != ns_updating_frame)
     {
 
   if (f != ns_updating_frame)
     {
@@ -1102,7 +1215,7 @@ ns_unfocus (struct frame *f)
      Internal: Remove focus on given frame
    -------------------------------------------------------------------------- */
 {
      Internal: Remove focus on given frame
    -------------------------------------------------------------------------- */
 {
-//  NSTRACE ("ns_unfocus");
+  NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
 
   if (gsaved)
     {
 
   if (gsaved)
     {
@@ -1146,6 +1259,135 @@ ns_clip_to_row (struct window *w, struct glyph_row *row,
 }
 
 
 }
 
 
+/* ==========================================================================
+
+    Visible bell and beep.
+
+   ========================================================================== */
+
+
+// This bell implementation shows the visual bell image asynchronously
+// from the rest of Emacs. This is done by adding a NSView to the
+// superview of the Emacs window and removing it using a timer.
+//
+// Unfortunately, some Emacs operations, like scrolling, is done using
+// low-level primitives that copy the content of the window, including
+// the bell image. To some extent, this is handled by removing the
+// image prior to scrolling and marking that the window is in need for
+// redisplay.
+//
+// To test this code, make sure that there is no artifacts of the bell
+// image in the following situations. Use a non-empty buffer (like the
+// tutorial) to ensure that a scroll is performed:
+//
+// * Single-window: C-g C-v
+//
+// * Side-by-windows: C-x 3 C-g C-v
+//
+// * Windows above each other: C-x 2 C-g C-v
+
+@interface EmacsBell : NSImageView
+{
+  // Number of currently active bell:s.
+  unsigned int nestCount;
+  NSView * mView;
+  bool isAttached;
+}
+- (void)show:(NSView *)view;
+- (void)hide;
+- (void)remove;
+@end
+
+@implementation EmacsBell
+
+- (id)init;
+{
+  NSTRACE ("[EmacsBell init]");
+  if ((self = [super init]))
+    {
+      nestCount = 0;
+      isAttached = false;
+#ifdef NS_IMPL_GNUSTEP
+      // GNUstep doesn't provide named images.  This was reported in
+      // 2011, see https://savannah.gnu.org/bugs/?33396
+      //
+      // As a drop in replacement, a semitransparent gray square is used.
+      self.image = [[NSImage alloc] initWithSize:NSMakeSize(32 * 5, 32 * 5)];
+      [self.image lockFocus];
+      [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set];
+      NSRectFill(NSMakeRect(0, 0, 32, 32));
+      [self.image unlockFocus];
+#else
+      self.image = [NSImage imageNamed:NSImageNameCaution];
+      [self.image setSize:NSMakeSize(self.image.size.width * 5,
+                                     self.image.size.height * 5)];
+#endif
+    }
+  return self;
+}
+
+- (void)show:(NSView *)view
+{
+  NSTRACE ("[EmacsBell show:]");
+  NSTRACE_MSG ("nestCount: %u", nestCount);
+
+  // Show the image, unless it's already shown.
+  if (nestCount == 0)
+    {
+      NSRect rect = [view bounds];
+      NSPoint pos;
+      pos.x = rect.origin.x + (rect.size.width  - self.image.size.width )/2;
+      pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
+
+      [self setFrameOrigin:pos];
+      [self setFrameSize:self.image.size];
+
+      isAttached = true;
+      mView = view;
+      [[[view window] contentView] addSubview:self
+                                   positioned:NSWindowAbove
+                                   relativeTo:nil];
+    }
+
+  ++nestCount;
+
+  [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
+}
+
+
+- (void)hide
+{
+  // Note: Trace output from this method isn't shown, reason unknown.
+  // NSTRACE ("[EmacsBell hide]");
+
+  if (nestCount > 0)
+    --nestCount;
+
+  // Remove the image once the last bell became inactive.
+  if (nestCount == 0)
+    {
+      [self remove];
+    }
+}
+
+
+-(void)remove
+{
+  NSTRACE ("[EmacsBell remove]");
+  if (isAttached)
+    {
+      NSTRACE_MSG ("removeFromSuperview");
+      [self removeFromSuperview];
+      mView.needsDisplay = YES;
+      isAttached = false;
+    }
+}
+
+@end
+
+
+static EmacsBell * bell_view = nil;
+
 static void
 ns_ring_bell (struct frame *f)
 /* --------------------------------------------------------------------------
 static void
 ns_ring_bell (struct frame *f)
 /* --------------------------------------------------------------------------
@@ -1155,37 +1397,23 @@ ns_ring_bell (struct frame *f)
   NSTRACE ("ns_ring_bell");
   if (visible_bell)
     {
   NSTRACE ("ns_ring_bell");
   if (visible_bell)
     {
-      NSAutoreleasePool *pool;
       struct frame *frame = SELECTED_FRAME ();
       NSView *view;
 
       struct frame *frame = SELECTED_FRAME ();
       NSView *view;
 
+      if (bell_view == nil)
+        {
+          bell_view = [[EmacsBell alloc] init];
+          [bell_view retain];
+        }
+
       block_input ();
       block_input ();
-      pool = [[NSAutoreleasePool alloc] init];
 
       view = FRAME_NS_VIEW (frame);
       if (view != nil)
         {
 
       view = FRAME_NS_VIEW (frame);
       if (view != nil)
         {
-          NSRect r, surr;
-          NSPoint dim = NSMakePoint (128, 128);
-
-          r = [view bounds];
-          r.origin.x += (r.size.width - dim.x) / 2;
-          r.origin.y += (r.size.height - dim.y) / 2;
-          r.size.width = dim.x;
-          r.size.height = dim.y;
-          surr = NSInsetRect (r, -2, -2);
-          ns_focus (frame, &surr, 1);
-          [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
-          [ns_lookup_indexed_color (NS_FACE_FOREGROUND
-                                      (FRAME_DEFAULT_FACE (frame)), frame) set];
-          NSRectFill (r);
-          [[view window] flushWindow];
-          ns_timeout (150000);
-          [[view window] restoreCachedImage];
-          [[view window] flushWindow];
-          ns_unfocus (frame);
+          [bell_view show:view];
         }
         }
-      [pool release];
+
       unblock_input ();
     }
   else
       unblock_input ();
     }
   else
@@ -1194,6 +1422,21 @@ ns_ring_bell (struct frame *f)
     }
 }
 
     }
 }
 
+
+static void hide_bell ()
+/* --------------------------------------------------------------------------
+     Ensure the bell is hidden.
+   -------------------------------------------------------------------------- */
+{
+  NSTRACE ("hide_bell");
+
+  if (bell_view != nil)
+    {
+      [bell_view remove];
+    }
+}
+
+
 /* ==========================================================================
 
     Frame / window manager related functions
 /* ==========================================================================
 
     Frame / window manager related functions
@@ -1208,6 +1451,7 @@ ns_raise_frame (struct frame *f)
    -------------------------------------------------------------------------- */
 {
   NSView *view;
    -------------------------------------------------------------------------- */
 {
   NSView *view;
+
   check_window_system (f);
   view = FRAME_NS_VIEW (f);
   block_input ();
   check_window_system (f);
   view = FRAME_NS_VIEW (f);
   block_input ();
@@ -1224,6 +1468,7 @@ ns_lower_frame (struct frame *f)
    -------------------------------------------------------------------------- */
 {
   NSView *view;
    -------------------------------------------------------------------------- */
 {
   NSView *view;
+
   check_window_system (f);
   view = FRAME_NS_VIEW (f);
   block_input ();
   check_window_system (f);
   view = FRAME_NS_VIEW (f);
   block_input ();
@@ -1367,7 +1612,12 @@ x_iconify_frame (struct frame *f)
       [[view window] orderOut: NSApp];
       [[view window] setFrame: t display: NO];
     }
       [[view window] orderOut: NSApp];
       [[view window] setFrame: t display: NO];
     }
+
+  /* Processing input while Emacs is being minimized can cause a
+     crash, so block it for the duration. */
+  block_input();
   [[view window] miniaturize: NSApp];
   [[view window] miniaturize: NSApp];
+  unblock_input();
 }
 
 /* Free X resources of frame F.  */
 }
 
 /* Free X resources of frame F.  */
@@ -1489,7 +1739,6 @@ x_set_window_size (struct frame *f,
   NSRect wr = [window frame];
   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
   int pixelwidth, pixelheight;
   NSRect wr = [window frame];
   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
   int pixelwidth, pixelheight;
-  int rows, cols;
   int orig_height = wr.size.height;
 
   NSTRACE ("x_set_window_size");
   int orig_height = wr.size.height;
 
   NSTRACE ("x_set_window_size");
@@ -1498,8 +1747,8 @@ x_set_window_size (struct frame *f,
     return;
 
   NSTRACE_RECT ("current", wr);
     return;
 
   NSTRACE_RECT ("current", wr);
-
-/*fprintf (stderr, "\tsetWindowSize: %d x %d, pixelwise %d, font size %d x %d\n", width, height, pixelwise, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));*/
+  NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
+  NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
 
   block_input ();
 
 
   block_input ();
 
@@ -1507,15 +1756,11 @@ x_set_window_size (struct frame *f,
     {
       pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
       pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
     {
       pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
       pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
-      cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
-      rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
     }
   else
     {
       pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, width);
       pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
     }
   else
     {
       pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, width);
       pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
-      cols = width;
-      rows = height;
     }
 
   /* If we have a toolbar, take its height into account. */
     }
 
   /* If we have a toolbar, take its height into account. */
@@ -1559,26 +1804,8 @@ x_set_window_size (struct frame *f,
           make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
           make_number (FRAME_TOOLBAR_HEIGHT (f))));
 
           make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
           make_number (FRAME_TOOLBAR_HEIGHT (f))));
 
-  NSTRACE_RECT ("setFrame", wr);
   [window setFrame: wr display: YES];
 
   [window setFrame: wr display: YES];
 
-  /* This is a trick to compensate for Emacs' managing the scrollbar area
-     as a fixed number of standard character columns.  Instead of leaving
-     blank space for the extra, we chopped it off above.  Now for
-     left-hand scrollbars, we shift all rendering to the left by the
-     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);
-    NSTRACE_RECT ("setFrame", wr);
-    [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
-    [view setBoundsOrigin: origin];
-  }
-
   [view updateFrameSize: NO];
   unblock_input ();
 }
   [view updateFrameSize: NO];
   unblock_input ();
 }
@@ -1716,7 +1943,8 @@ ns_get_color (const char *name, NSColor **col)
   float r = -1.0, g, b;
   NSString *nsname = [NSString stringWithUTF8String: name];
 
   float r = -1.0, g, b;
   NSString *nsname = [NSString stringWithUTF8String: name];
 
-/*fprintf (stderr, "ns_get_color: '%s'\n", name); */
+  NSTRACE ("ns_get_color(%s, **)", name);
+
   block_input ();
 
   if ([nsname isEqualToString: @"ns_selection_bg_color"])
   block_input ();
 
   if ([nsname isEqualToString: @"ns_selection_bg_color"])
@@ -1923,7 +2151,7 @@ ns_defined_color (struct frame *f,
    -------------------------------------------------------------------------- */
 {
   NSColor *col;
    -------------------------------------------------------------------------- */
 {
   NSColor *col;
-  NSTRACE ("ns_defined_color");
+  NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
 
   block_input ();
   if (ns_get_color (name, &col) != 0) /* Color not found  */
 
   block_input ();
   if (ns_get_color (name, &col) != 0) /* Color not found  */
@@ -1949,6 +2177,8 @@ x_set_frame_alpha (struct frame *f)
   double alpha = 1.0;
   double alpha_min = 1.0;
 
   double alpha = 1.0;
   double alpha_min = 1.0;
 
+  NSTRACE ("x_set_frame_alpha");
+
   if (dpyinfo->x_highlight_frame == f)
     alpha = f->alpha[0];
   else
   if (dpyinfo->x_highlight_frame == f)
     alpha = f->alpha[0];
   else
@@ -2085,7 +2315,7 @@ ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
       position = [view convertPoint: position fromView: nil];
       remember_mouse_glyph (f, position.x, position.y,
                             &dpyinfo->last_mouse_glyph);
       position = [view convertPoint: position fromView: nil];
       remember_mouse_glyph (f, position.x, position.y,
                             &dpyinfo->last_mouse_glyph);
-/*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
+      NSTRACE_POINT ("position", position);
 
       if (bar_window) *bar_window = Qnil;
       if (part) *part = scroll_bar_above_handle;
 
       if (bar_window) *bar_window = Qnil;
       if (part) *part = scroll_bar_above_handle;
@@ -2108,7 +2338,7 @@ ns_frame_up_to_date (struct frame *f)
     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
    -------------------------------------------------------------------------- */
 {
     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
    -------------------------------------------------------------------------- */
 {
-  NSTRACE ("ns_frame_up_to_date");
+  NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
 
   if (FRAME_NS_P (f))
     {
 
   if (FRAME_NS_P (f))
     {
@@ -2219,7 +2449,7 @@ ns_clear_frame (struct frame *f)
   NSView *view = FRAME_NS_VIEW (f);
   NSRect r;
 
   NSView *view = FRAME_NS_VIEW (f);
   NSRect r;
 
-  NSTRACE ("ns_clear_frame");
+  NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
 
  /* comes on initial frame because we have
     after-make-frame-functions = select-frame */
 
  /* comes on initial frame because we have
     after-make-frame-functions = select-frame */
@@ -2255,7 +2485,7 @@ ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
   if (!view || !face)
     return;
 
   if (!view || !face)
     return;
 
-  NSTRACE ("ns_clear_frame_area");
+  NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
 
   r = NSIntersectionRect (r, [view frame]);
   ns_focus (f, &r, 1);
 
   r = NSIntersectionRect (r, [view frame]);
   ns_focus (f, &r, 1);
@@ -2270,8 +2500,12 @@ ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
 static void
 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
 {
 static void
 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
 {
+  NSTRACE ("ns_copy_bits");
+
   if (FRAME_NS_VIEW (f))
     {
   if (FRAME_NS_VIEW (f))
     {
+      hide_bell();              // Ensure the bell image isn't scrolled.
+
       ns_focus (f, &dest, 1);
       [FRAME_NS_VIEW (f) scrollRect: src
                                  by: NSMakeSize (dest.origin.x - src.origin.x,
       ns_focus (f, &dest, 1);
       [FRAME_NS_VIEW (f) scrollRect: src
                                  by: NSMakeSize (dest.origin.x - src.origin.x,
@@ -2348,7 +2582,7 @@ ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
   struct frame *f;
   int width, height;
 
   struct frame *f;
   int width, height;
 
-  NSTRACE ("ns_after_update_window_line");
+  NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
 
   /* begin copy from other terms */
   eassert (w);
 
   /* begin copy from other terms */
   eassert (w);
@@ -2452,11 +2686,31 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
     External (RIF); fringe-related
    -------------------------------------------------------------------------- */
 {
     External (RIF); fringe-related
    -------------------------------------------------------------------------- */
 {
+  /* Fringe bitmaps comes in two variants, normal and periodic.  A
+     periodic bitmap is used to create a continuous pattern.  Since a
+     bitmap is rendered one text line at a time, the start offset (dh)
+     of the bitmap varies.  Concretely, this is used for the empty
+     line indicator.
+
+     For a bitmap, "h + dh" is the full height and is always
+     invariant.  For a normal bitmap "dh" is zero.
+
+     For example, when the period is three and the full height is 72
+     the following combinations exists:
+
+       h=72 dh=0
+       h=71 dh=1
+       h=70 dh=2 */
+
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   struct face *face = p->face;
   static EmacsImage **bimgs = NULL;
   static int nBimgs = 0;
 
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   struct face *face = p->face;
   static EmacsImage **bimgs = NULL;
   static int nBimgs = 0;
 
+  NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
+  NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
+               p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
+
   /* grow bimgs if needed */
   if (nBimgs < max_used_fringe_bitmap)
     {
   /* grow bimgs if needed */
   if (nBimgs < max_used_fringe_bitmap)
     {
@@ -2489,19 +2743,24 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
 
       if (!img)
         {
 
       if (!img)
         {
-          unsigned short *bits = p->bits + p->dh;
-          int len = p->h;
+          // Note: For "periodic" images, allocate one EmacsImage for
+          // the base image, and use it for all dh:s.
+          unsigned short *bits = p->bits;
+          int full_height = p->h + p->dh;
           int i;
           int i;
-          unsigned char *cbits = xmalloc (len);
+          unsigned char *cbits = xmalloc (full_height);
 
 
-          for (i = 0; i < len; i++)
-            cbits[i] = ~(bits[i] & 0xff);
-          img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
+          for (i = 0; i < full_height; i++)
+            cbits[i] = bits[i];
+          img = [[EmacsImage alloc] initFromXBM: cbits width: 8
+                                         height: full_height
                                              fg: 0 bg: 0];
           bimgs[p->which - 1] = img;
           xfree (cbits);
         }
 
                                              fg: 0 bg: 0];
           bimgs[p->which - 1] = img;
           xfree (cbits);
         }
 
+      NSTRACE_RECT ("r", r);
+
       NSRectClip (r);
       /* Since we composite the bitmap instead of just blitting it, we need
          to erase the whole background. */
       NSRectClip (r);
       /* Since we composite the bitmap instead of just blitting it, we need
          to erase the whole background. */
@@ -2520,8 +2779,14 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
       }
 
 #ifdef NS_IMPL_COCOA
       }
 
 #ifdef NS_IMPL_COCOA
+      // Note: For periodic images, the full image height is "h + hd".
+      // By using the height h, a suitable part of the image is used.
+      NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
+
+      NSTRACE_RECT ("fromRect", fromRect);
+
       [img drawInRect: r
       [img drawInRect: r
-              fromRect: NSZeroRect
+              fromRect: fromRect
              operation: NSCompositeSourceOver
               fraction: 1.0
            respectFlipped: YES
              operation: NSCompositeSourceOver
               fraction: 1.0
            respectFlipped: YES
@@ -2559,7 +2824,7 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
      in mini-buffer windows when switching between echo area glyphs
      and mini-buffer.  */
 
      in mini-buffer windows when switching between echo area glyphs
      and mini-buffer.  */
 
-  NSTRACE ("dumpcursor");
+  NSTRACE ("ns_draw_window_cursor");
 
   if (!on_p)
     return;
 
   if (!on_p)
     return;
@@ -2596,7 +2861,10 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
     {
       if (cursor_width < 1)
        cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
     {
       if (cursor_width < 1)
        cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
-      w->phys_cursor_width = cursor_width;
+
+      /* The bar cursor should never be wider than the glyph. */
+      if (cursor_width < w->phys_cursor_width)
+        w->phys_cursor_width = cursor_width;
     }
   /* If we have an HBAR, "cursor_width" MAY specify height. */
   else if (cursor_type == HBAR_CURSOR)
     }
   /* If we have an HBAR, "cursor_width" MAY specify height. */
   else if (cursor_type == HBAR_CURSOR)
@@ -2613,12 +2881,11 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
   r.size.height = h;
   r.size.width = w->phys_cursor_width;
 
   r.size.height = h;
   r.size.width = w->phys_cursor_width;
 
-  /* 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, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
+  /* Prevent the cursor from being drawn outside the text area. */
+  ns_clip_to_row (w, glyph_row, TEXT_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
 
 
 
 
-  face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
+  face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id);
   if (face && NS_FACE_BACKGROUND (face)
       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
     {
   if (face && NS_FACE_BACKGROUND (face)
       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
     {
@@ -2690,11 +2957,12 @@ ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
 
   NSTRACE ("ns_draw_vertical_window_border");
 
 
   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];
+  face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
 
   ns_focus (f, &r, 1);
 
   ns_focus (f, &r, 1);
+  if (face)
+    [ns_lookup_indexed_color(face->foreground, f) set];
+
   NSRectFill(r);
   ns_unfocus (f);
 }
   NSRectFill(r);
   ns_unfocus (f);
 }
@@ -2712,11 +2980,12 @@ ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
 
   NSTRACE ("ns_draw_window_divider");
 
 
   NSTRACE ("ns_draw_window_divider");
 
-  face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID);
-  if (face)
-      [ns_lookup_indexed_color(face->foreground, f) set];
+  face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
 
   ns_focus (f, &r, 1);
 
   ns_focus (f, &r, 1);
+  if (face)
+    [ns_lookup_indexed_color(face->foreground, f) set];
+
   NSRectFill(r);
   ns_unfocus (f);
 }
   NSRectFill(r);
   ns_unfocus (f);
 }
@@ -3045,9 +3314,10 @@ ns_dumpglyphs_box_or_relief (struct glyph_string *s)
 
   if (s->hl == DRAW_MOUSE_FACE)
     {
 
   if (s->hl == DRAW_MOUSE_FACE)
     {
-      face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
+      face = FACE_FROM_ID_OR_NULL (s->f,
+                                  MOUSE_HL_INFO (s->f)->mouse_face_face_id);
       if (!face)
       if (!face)
-        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
+        face = FACE_FROM_ID_OR_NULL (s->f, MOUSE_FACE_ID);
     }
   else
     face = s->face;
     }
   else
     face = s->face;
@@ -3112,8 +3382,9 @@ ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
           struct face *face;
           if (s->hl == DRAW_MOUSE_FACE)
             {
           struct face *face;
           if (s->hl == DRAW_MOUSE_FACE)
             {
-              face = FACE_FROM_ID (s->f,
-                                  MOUSE_HL_INFO (s->f)->mouse_face_face_id);
+              face
+               = FACE_FROM_ID_OR_NULL (s->f,
+                                       MOUSE_HL_INFO (s->f)->mouse_face_face_id);
               if (!face)
                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
             }
               if (!face)
                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
             }
@@ -3179,7 +3450,8 @@ 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)
     {
      with its background color), we must clear just the image area. */
   if (s->hl == DRAW_MOUSE_FACE)
     {
-      face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
+      face = FACE_FROM_ID_OR_NULL (s->f,
+                                  MOUSE_HL_INFO (s->f)->mouse_face_face_id);
       if (!face)
        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
     }
       if (!face)
        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
     }
@@ -3296,7 +3568,8 @@ ns_dumpglyphs_stretch (struct glyph_string *s)
 
       if (s->hl == DRAW_MOUSE_FACE)
        {
 
       if (s->hl == DRAW_MOUSE_FACE)
        {
-         face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
+         face = FACE_FROM_ID_OR_NULL (s->f,
+                                     MOUSE_HL_INFO (s->f)->mouse_face_face_id);
          if (!face)
            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
        }
          if (!face)
            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
        }
@@ -3373,6 +3646,32 @@ ns_dumpglyphs_stretch (struct glyph_string *s)
 }
 
 
 }
 
 
+static void
+ns_draw_glyph_string_foreground (struct glyph_string *s)
+{
+  int x, flags;
+  struct font *font = s->font;
+
+  /* If first glyph of S has a left box line, start drawing the text
+     of S to the right of that box line.  */
+  if (s->face && s->face->box != FACE_NO_BOX
+      && s->first_glyph->left_box_line_p)
+    x = s->x + eabs (s->face->box_line_width);
+  else
+    x = s->x;
+
+  flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
+    (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
+     (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
+      NS_DUMPGLYPH_NORMAL));
+
+  font->driver->draw
+    (s, s->cmp_from, s->nchars, x, s->ybase,
+     (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
+     || flags == NS_DUMPGLYPH_MOUSEFACE);
+}
+
+
 static void
 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
 {
 static void
 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
 {
@@ -3471,12 +3770,12 @@ ns_draw_glyph_string (struct glyph_string *s)
 {
   /* TODO (optimize): focus for box and contents draw */
   NSRect r[2];
 {
   /* TODO (optimize): focus for box and contents draw */
   NSRect r[2];
-  int n, flags;
+  int n;
   char box_drawn_p = 0;
   struct font *font = s->face->font;
   if (! font) font = FRAME_FONT (s->f);
 
   char box_drawn_p = 0;
   struct font *font = s->face->font;
   if (! font) font = FRAME_FONT (s->f);
 
-  NSTRACE ("ns_draw_glyph_string");
+  NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "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*/)
     {
@@ -3541,11 +3840,6 @@ ns_draw_glyph_string (struct glyph_string *s)
         ns_maybe_dumpglyphs_background
           (s, s->first_glyph->type == COMPOSITE_GLYPH);
 
         ns_maybe_dumpglyphs_background
           (s, s->first_glyph->type == COMPOSITE_GLYPH);
 
-      flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
-        (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
-         (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
-          NS_DUMPGLYPH_NORMAL));
-
       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
         {
           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
         {
           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
@@ -3559,10 +3853,7 @@ ns_draw_glyph_string (struct glyph_string *s)
         if (isComposite)
           ns_draw_composite_glyph_string_foreground (s);
         else
         if (isComposite)
           ns_draw_composite_glyph_string_foreground (s);
         else
-          font->driver->draw
-            (s, s->cmp_from, s->nchars, s->x, s->ybase,
-             (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
-             || flags == NS_DUMPGLYPH_MOUSEFACE);
+          ns_draw_glyph_string_foreground (s);
       }
 
       {
       }
 
       {
@@ -3634,7 +3925,7 @@ ns_send_appdefined (int value)
               recognize and take as a command to halt the event loop.
    -------------------------------------------------------------------------- */
 {
               recognize and take as a command to halt the event loop.
    -------------------------------------------------------------------------- */
 {
-  /*NSTRACE ("ns_send_appdefined"); */
+  NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
 
 #ifdef NS_IMPL_GNUSTEP
   // GNUstep needs postEvent to happen on the main thread.
 
 #ifdef NS_IMPL_GNUSTEP
   // GNUstep needs postEvent to happen on the main thread.
@@ -3808,7 +4099,10 @@ ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
   struct input_event ev;
   int nevents;
 
   struct input_event ev;
   int nevents;
 
-/* NSTRACE ("ns_read_socket"); */
+  NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
+
+  if (apploopnr > 0)
+    return -1; /* Already within event loop. */
 
 #ifdef HAVE_NATIVE_FS
   check_native_fs ();
 
 #ifdef HAVE_NATIVE_FS
   check_native_fs ();
@@ -3892,7 +4186,10 @@ ns_select (int nfds, fd_set *readfds, fd_set *writefds,
   struct input_event event;
   char c;
 
   struct input_event event;
   char c;
 
-/*  NSTRACE ("ns_select"); */
+  NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
+
+  if (apploopnr > 0)
+    return -1; /* Already within event loop. */
 
 #ifdef HAVE_NATIVE_FS
   check_native_fs ();
 
 #ifdef HAVE_NATIVE_FS
   check_native_fs ();
@@ -4074,7 +4371,7 @@ ns_set_vertical_scroll_bar (struct window *window,
   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
   top = window_y;
   height = window_height;
   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
   top = window_y;
   height = window_height;
-  width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
+  width = NS_SCROLL_BAR_WIDTH (f);
   left = WINDOW_SCROLL_BAR_AREA_X (window);
 
   r = NSMakeRect (left, top, width, height);
   left = WINDOW_SCROLL_BAR_AREA_X (window);
 
   r = NSMakeRect (left, top, width, height);
@@ -4165,34 +4462,20 @@ ns_set_horizontal_scroll_bar (struct window *window,
   NSTRACE ("ns_set_horizontal_scroll_bar");
 
   /* Get dimensions.  */
   NSTRACE ("ns_set_horizontal_scroll_bar");
 
   /* Get dimensions.  */
-  window_box (window, ANY_AREA, 0, &window_x, &window_width, 0);
+  window_box (window, ANY_AREA, &window_x, 0, &window_width, 0);
   left = window_x;
   width = window_width;
   left = window_x;
   width = window_width;
-  height = WINDOW_CONFIG_SCROLL_BAR_LINES (window) * FRAME_LINE_HEIGHT (f);
+  height = NS_SCROLL_BAR_HEIGHT (f);
   top = WINDOW_SCROLL_BAR_AREA_Y (window);
 
   r = NSMakeRect (left, top, width, height);
   /* the parent view is flipped, so we need to flip y value */
   v = [view frame];
   top = WINDOW_SCROLL_BAR_AREA_Y (window);
 
   r = NSMakeRect (left, top, width, height);
   /* the parent view is flipped, so we need to flip y value */
   v = [view frame];
-  /* ??????? PXW/scrollbars !!!!!!!!!!!!!!!!!!!! */
   r.origin.y = (v.size.height - r.size.height - r.origin.y);
 
   XSETWINDOW (win, window);
   block_input ();
 
   r.origin.y = (v.size.height - r.size.height - r.origin.y);
 
   XSETWINDOW (win, window);
   block_input ();
 
-  if (WINDOW_TOTAL_COLS (window) < 5)
-    {
-      if (!NILP (window->horizontal_scroll_bar))
-        {
-          bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
-          [bar removeFromSuperview];
-          wset_horizontal_scroll_bar (window, Qnil);
-        }
-      ns_clear_frame_area (f, left, top, width, height);
-      unblock_input ();
-      return;
-    }
-
   if (NILP (window->horizontal_scroll_bar))
     {
       if (width > 0 && height > 0)
   if (NILP (window->horizontal_scroll_bar))
     {
       if (width > 0 && height > 0)
@@ -4207,16 +4490,22 @@ ns_set_horizontal_scroll_bar (struct window *window,
       NSRect oldRect;
       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
       oldRect = [bar frame];
       NSRect oldRect;
       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
       oldRect = [bar frame];
-      r.size.width = oldRect.size.width;
       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
         {
       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
         {
-          if (oldRect.origin.x != r.origin.x)
-              ns_clear_frame_area (f, left, top, width, height);
+          if (oldRect.origin.y != r.origin.y)
+            ns_clear_frame_area (f, left, top, width, height);
           [bar setFrame: r];
           update_p = YES;
         }
     }
 
           [bar setFrame: r];
           update_p = YES;
         }
     }
 
+  /* If there are both horizontal and vertical scroll-bars they leave
+     a square that belongs to neither. We need to clear it otherwise
+     it fills with junk. */
+  if (!NILP (window->vertical_scroll_bar))
+    ns_clear_frame_area (f, WINDOW_SCROLL_BAR_AREA_X (window), top,
+                         NS_SCROLL_BAR_HEIGHT (f), height);
+
   if (update_p)
     [bar setPosition: position portion: portion whole: whole];
   unblock_input ();
   if (update_p)
     [bar setPosition: position portion: portion whole: whole];
   unblock_input ();
@@ -4254,13 +4543,15 @@ ns_redeem_scroll_bar (struct window *window)
 {
   id bar;
   NSTRACE ("ns_redeem_scroll_bar");
 {
   id bar;
   NSTRACE ("ns_redeem_scroll_bar");
-  if (!NILP (window->vertical_scroll_bar))
+  if (!NILP (window->vertical_scroll_bar)
+      && WINDOW_HAS_VERTICAL_SCROLL_BAR (window))
     {
       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
       [bar reprieve];
     }
 
     {
       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
       [bar reprieve];
     }
 
-  if (!NILP (window->horizontal_scroll_bar))
+  if (!NILP (window->horizontal_scroll_bar)
+      && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (window))
     {
       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
       [bar reprieve];
     {
       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
       [bar reprieve];
@@ -4528,6 +4819,8 @@ ns_term_init (Lisp_Object display_name)
   if (ns_initialized) return x_display_list;
   ns_initialized = 1;
 
   if (ns_initialized) return x_display_list;
   ns_initialized = 1;
 
+  block_input ();
+
   NSTRACE ("ns_term_init");
 
   [outerpool release];
   NSTRACE ("ns_term_init");
 
   [outerpool release];
@@ -4767,6 +5060,8 @@ ns_term_init (Lisp_Object display_name)
 
   NSTRACE_MSG ("ns_term_init done");
 
 
   NSTRACE_MSG ("ns_term_init done");
 
+  unblock_input ();
+
   return dpyinfo;
 }
 
   return dpyinfo;
 }
 
@@ -4802,6 +5097,8 @@ ns_term_shutdown (int sig)
 
 - (id)init
 {
 
 - (id)init
 {
+  NSTRACE ("[EmacsApp init]");
+
   if ((self = [super init]))
     {
 #ifdef NS_IMPL_COCOA
   if ((self = [super init]))
     {
 #ifdef NS_IMPL_COCOA
@@ -4818,6 +5115,8 @@ ns_term_shutdown (int sig)
 #ifdef NS_IMPL_COCOA
 - (void)run
 {
 #ifdef NS_IMPL_COCOA
 - (void)run
 {
+  NSTRACE ("[EmacsApp run]");
+
 #ifndef NSAppKitVersionNumber10_9
 #define NSAppKitVersionNumber10_9 1265
 #endif
 #ifndef NSAppKitVersionNumber10_9
 #define NSAppKitVersionNumber10_9 1265
 #endif
@@ -4854,6 +5153,8 @@ ns_term_shutdown (int sig)
 
 - (void)stop: (id)sender
 {
 
 - (void)stop: (id)sender
 {
+  NSTRACE ("[EmacsApp stop:]");
+
     shouldKeepRunning = NO;
     // Stop possible dialog also.  Noop if no dialog present.
     // The file dialog still leaks 7k - 10k on 10.9 though.
     shouldKeepRunning = NO;
     // Stop possible dialog also.  Noop if no dialog present.
     // The file dialog still leaks 7k - 10k on 10.9 though.
@@ -4863,6 +5164,8 @@ ns_term_shutdown (int sig)
 
 - (void)logNotification: (NSNotification *)notification
 {
 
 - (void)logNotification: (NSNotification *)notification
 {
+  NSTRACE ("[EmacsApp logNotification:]");
+
   const char *name = [[notification name] UTF8String];
   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
       && !strstr (name, "WindowNumber"))
   const char *name = [[notification name] UTF8String];
   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
       && !strstr (name, "WindowNumber"))
@@ -4879,8 +5182,8 @@ ns_term_shutdown (int sig)
   int type = [theEvent type];
   NSWindow *window = [theEvent window];
 
   int type = [theEvent type];
   NSWindow *window = [theEvent window];
 
-/*  NSTRACE ("sendEvent"); */
-/*fprintf (stderr, "received event of type %d\t%d\n", type);*/
+  NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
+  NSTRACE_MSG ("Type: %d", type);
 
 #ifdef NS_IMPL_GNUSTEP
   // Keyboard events aren't propagated to file dialogs for some reason.
 
 #ifdef NS_IMPL_GNUSTEP
   // Keyboard events aren't propagated to file dialogs for some reason.
@@ -4966,6 +5269,8 @@ ns_term_shutdown (int sig)
     }
 #endif
 
     }
 #endif
 
+  NSTRACE_UNSILENCE();
+
   [super sendEvent: theEvent];
 }
 
   [super sendEvent: theEvent];
 }
 
@@ -4986,6 +5291,8 @@ ns_term_shutdown (int sig)
 
 - (void)newFrame: (id)sender
 {
 
 - (void)newFrame: (id)sender
 {
+  NSTRACE ("[EmacsApp newFrame:]");
+
   struct frame *emacsframe = SELECTED_FRAME ();
   NSEvent *theEvent = [NSApp currentEvent];
 
   struct frame *emacsframe = SELECTED_FRAME ();
   NSEvent *theEvent = [NSApp currentEvent];
 
@@ -5001,6 +5308,8 @@ ns_term_shutdown (int sig)
 /* Open a file (used by below, after going into queue read by ns_read_socket) */
 - (BOOL) openFile: (NSString *)fileName
 {
 /* Open a file (used by below, after going into queue read by ns_read_socket) */
 - (BOOL) openFile: (NSString *)fileName
 {
+  NSTRACE ("[EmacsApp openFile:]");
+
   struct frame *emacsframe = SELECTED_FRAME ();
   NSEvent *theEvent = [NSApp currentEvent];
 
   struct frame *emacsframe = SELECTED_FRAME ();
   NSEvent *theEvent = [NSApp currentEvent];
 
@@ -5029,7 +5338,8 @@ ns_term_shutdown (int sig)
      When application is loaded, terminate event loop in ns_term_init
    -------------------------------------------------------------------------- */
 {
      When application is loaded, terminate event loop in ns_term_init
    -------------------------------------------------------------------------- */
 {
-  NSTRACE ("applicationDidFinishLaunching");
+  NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
+
 #ifdef NS_IMPL_GNUSTEP
   ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
 #endif
 #ifdef NS_IMPL_GNUSTEP
   ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
 #endif
@@ -5078,6 +5388,8 @@ ns_term_shutdown (int sig)
 
 - (void) terminate: (id)sender
 {
 
 - (void) terminate: (id)sender
 {
+  NSTRACE ("[EmacsApp terminate:]");
+
   struct frame *emacsframe = SELECTED_FRAME ();
 
   if (!emacs_event)
   struct frame *emacsframe = SELECTED_FRAME ();
 
   if (!emacs_event)
@@ -5114,6 +5426,8 @@ runAlertPanel(NSString *title,
 
 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
 {
 
 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
 {
+  NSTRACE ("[EmacsApp applicationShouldTerminate:]");
+
   bool ret;
 
   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
   bool ret;
 
   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
@@ -5193,11 +5507,13 @@ not_in_argv (NSString *arg)
 /* TODO: these may help w/IO switching btwn terminal and NSApp */
 - (void)applicationWillBecomeActive: (NSNotification *)notification
 {
 /* TODO: these may help w/IO switching btwn terminal and NSApp */
 - (void)applicationWillBecomeActive: (NSNotification *)notification
 {
+  NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
   //ns_app_active=YES;
 }
   //ns_app_active=YES;
 }
+
 - (void)applicationDidBecomeActive: (NSNotification *)notification
 {
 - (void)applicationDidBecomeActive: (NSNotification *)notification
 {
-  NSTRACE ("applicationDidBecomeActive");
+  NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
 
 #ifdef NS_IMPL_GNUSTEP
   if (! applicationDidFinishLaunchingCalled)
 
 #ifdef NS_IMPL_GNUSTEP
   if (! applicationDidFinishLaunchingCalled)
@@ -5211,6 +5527,8 @@ not_in_argv (NSString *arg)
 }
 - (void)applicationDidResignActive: (NSNotification *)notification
 {
 }
 - (void)applicationDidResignActive: (NSNotification *)notification
 {
+  NSTRACE ("[EmacsApp applicationDidResignActive:]");
+
   //ns_app_active=NO;
   ns_send_appdefined (-1);
 }
   //ns_app_active=NO;
   ns_send_appdefined (-1);
 }
@@ -5354,6 +5672,8 @@ not_in_argv (NSString *arg)
   struct frame *emacsframe = SELECTED_FRAME ();
   NSEvent *theEvent = [NSApp currentEvent];
 
   struct frame *emacsframe = SELECTED_FRAME ();
   NSEvent *theEvent = [NSApp currentEvent];
 
+  NSTRACE ("[EmacsApp fulfillService:withArg:]");
+
   if (!emacs_event)
     return NO;
 
   if (!emacs_event)
     return NO;
 
@@ -5384,13 +5704,15 @@ not_in_argv (NSString *arg)
 /* needed to inform when window closed from LISP */
 - (void) setWindowClosing: (BOOL)closing
 {
 /* needed to inform when window closed from LISP */
 - (void) setWindowClosing: (BOOL)closing
 {
+  NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
+
   windowClosing = closing;
 }
 
 
 - (void)dealloc
 {
   windowClosing = closing;
 }
 
 
 - (void)dealloc
 {
-  NSTRACE ("EmacsView_dealloc");
+  NSTRACE ("[EmacsView dealloc]");
   [toolbar release];
   if (fs_state == FULLSCREEN_BOTH)
     [nonfs_window release];
   [toolbar release];
   if (fs_state == FULLSCREEN_BOTH)
     [nonfs_window release];
@@ -5408,7 +5730,7 @@ not_in_argv (NSString *arg)
   CGFloat size;
   NSFont *nsfont;
 
   CGFloat size;
   NSFont *nsfont;
 
-  NSTRACE ("changeFont");
+  NSTRACE ("[EmacsView changeFont:]");
 
   if (!emacs_event)
     return;
 
   if (!emacs_event)
     return;
@@ -5438,7 +5760,7 @@ not_in_argv (NSString *arg)
 
 - (BOOL)acceptsFirstResponder
 {
 
 - (BOOL)acceptsFirstResponder
 {
-  NSTRACE ("acceptsFirstResponder");
+  NSTRACE ("[EmacsView acceptsFirstResponder]");
   return YES;
 }
 
   return YES;
 }
 
@@ -5447,7 +5769,7 @@ not_in_argv (NSString *arg)
 {
   NSRect visible = [self visibleRect];
   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
 {
   NSRect visible = [self visibleRect];
   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
-  NSTRACE ("resetCursorRects");
+  NSTRACE ("[EmacsView resetCursorRects]");
 
   if (currentCursor == nil)
     currentCursor = [NSCursor arrowCursor];
 
   if (currentCursor == nil)
     currentCursor = [NSCursor arrowCursor];
@@ -5472,7 +5794,7 @@ not_in_argv (NSString *arg)
   int left_is_none;
   unsigned int flags = [theEvent modifierFlags];
 
   int left_is_none;
   unsigned int flags = [theEvent modifierFlags];
 
-  NSTRACE ("keyDown");
+  NSTRACE ("[EmacsView keyDown:]");
 
   /* Rhapsody and OS X give up and down events for the arrow keys */
   if (ns_fake_keydown == YES)
 
   /* Rhapsody and OS X give up and down events for the arrow keys */
   if (ns_fake_keydown == YES)
@@ -5717,6 +6039,9 @@ not_in_argv (NSString *arg)
 {
   int flags = [theEvent modifierFlags];
   int code = [theEvent keyCode];
 {
   int flags = [theEvent modifierFlags];
   int code = [theEvent keyCode];
+
+  NSTRACE ("[EmacsView keyUp:]");
+
   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
     {
   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
     {
@@ -5741,6 +6066,8 @@ not_in_argv (NSString *arg)
   int len = [(NSString *)aString length];
   int i;
 
   int len = [(NSString *)aString length];
   int i;
 
+  NSTRACE ("[EmacsView insertText:]");
+
   if (NS_KEYLOG)
     NSLog (@"insertText '%@'\tlen = %d", aString, len);
   processingCompose = NO;
   if (NS_KEYLOG)
     NSLog (@"insertText '%@'\tlen = %d", aString, len);
   processingCompose = NO;
@@ -5774,6 +6101,9 @@ not_in_argv (NSString *arg)
 {
   NSString *str = [aString respondsToSelector: @selector (string)] ?
     [aString string] : aString;
 {
   NSString *str = [aString respondsToSelector: @selector (string)] ?
     [aString string] : aString;
+
+  NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
+
   if (NS_KEYLOG)
     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
            str, (unsigned long)[str length],
   if (NS_KEYLOG)
     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
            str, (unsigned long)[str length],
@@ -5801,6 +6131,8 @@ not_in_argv (NSString *arg)
 /* delete display of composing characters [not in <NSTextInput>] */
 - (void)deleteWorkingText
 {
 /* delete display of composing characters [not in <NSTextInput>] */
 - (void)deleteWorkingText
 {
+  NSTRACE ("[EmacsView deleteWorkingText]");
+
   if (workingText == nil)
     return;
   if (NS_KEYLOG)
   if (workingText == nil)
     return;
   if (NS_KEYLOG)
@@ -5820,12 +6152,16 @@ not_in_argv (NSString *arg)
 
 - (BOOL)hasMarkedText
 {
 
 - (BOOL)hasMarkedText
 {
+  NSTRACE ("[EmacsView hasMarkedText]");
+
   return workingText != nil;
 }
 
 
 - (NSRange)markedRange
 {
   return workingText != nil;
 }
 
 
 - (NSRange)markedRange
 {
+  NSTRACE ("[EmacsView markedRange]");
+
   NSRange rng = workingText != nil
     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
   if (NS_KEYLOG)
   NSRange rng = workingText != nil
     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
   if (NS_KEYLOG)
@@ -5836,6 +6172,8 @@ not_in_argv (NSString *arg)
 
 - (void)unmarkText
 {
 
 - (void)unmarkText
 {
+  NSTRACE ("[EmacsView unmarkText]");
+
   if (NS_KEYLOG)
     NSLog (@"unmark (accept) text");
   [self deleteWorkingText];
   if (NS_KEYLOG)
     NSLog (@"unmark (accept) text");
   [self deleteWorkingText];
@@ -5849,6 +6187,9 @@ not_in_argv (NSString *arg)
   NSRect rect;
   NSPoint pt;
   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
   NSRect rect;
   NSPoint pt;
   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
+
+  NSTRACE ("[EmacsView firstRectForCharacterRange:]");
+
   if (NS_KEYLOG)
     NSLog (@"firstRectForCharRange request");
 
   if (NS_KEYLOG)
     NSLog (@"firstRectForCharRange request");
 
@@ -5859,8 +6200,14 @@ not_in_argv (NSString *arg)
                                        +FRAME_LINE_HEIGHT (emacsframe));
 
   pt = [self convertPoint: pt toView: nil];
                                        +FRAME_LINE_HEIGHT (emacsframe));
 
   pt = [self convertPoint: pt toView: nil];
+#if !defined (NS_IMPL_COCOA) || \
+  MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
   pt = [[self window] convertBaseToScreen: pt];
   rect.origin = pt;
   pt = [[self window] convertBaseToScreen: pt];
   rect.origin = pt;
+#else
+  rect.origin = pt;
+  rect = [[self window] convertRectToScreen: rect];
+#endif
   return rect;
 }
 
   return rect;
 }
 
@@ -5873,6 +6220,8 @@ not_in_argv (NSString *arg)
 
 - (void)doCommandBySelector: (SEL)aSelector
 {
 
 - (void)doCommandBySelector: (SEL)aSelector
 {
+  NSTRACE ("[EmacsView doCommandBySelector:]");
+
   if (NS_KEYLOG)
     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
 
   if (NS_KEYLOG)
     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
 
@@ -5935,7 +6284,7 @@ not_in_argv (NSString *arg)
   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
 
   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
 
-  NSTRACE ("mouseDown");
+  NSTRACE ("[EmacsView mouseDown:]");
 
   [self deleteWorkingText];
 
 
   [self deleteWorkingText];
 
@@ -5956,7 +6305,7 @@ not_in_argv (NSString *arg)
           delta = [theEvent deltaX];
           if (delta == 0)
             {
           delta = [theEvent deltaX];
           if (delta == 0)
             {
-              NSTRACE ("deltaIsZero");
+              NSTRACE_MSG ("deltaIsZero");
               return;
             }
           emacs_event->kind = HORIZ_WHEEL_EVENT;
               return;
             }
           emacs_event->kind = HORIZ_WHEEL_EVENT;
@@ -5983,42 +6332,42 @@ not_in_argv (NSString *arg)
 
 - (void)rightMouseDown: (NSEvent *)theEvent
 {
 
 - (void)rightMouseDown: (NSEvent *)theEvent
 {
-  NSTRACE ("rightMouseDown");
+  NSTRACE ("[EmacsView rightMouseDown:]");
   [self mouseDown: theEvent];
 }
 
 
 - (void)otherMouseDown: (NSEvent *)theEvent
 {
   [self mouseDown: theEvent];
 }
 
 
 - (void)otherMouseDown: (NSEvent *)theEvent
 {
-  NSTRACE ("otherMouseDown");
+  NSTRACE ("[EmacsView otherMouseDown:]");
   [self mouseDown: theEvent];
 }
 
 
 - (void)mouseUp: (NSEvent *)theEvent
 {
   [self mouseDown: theEvent];
 }
 
 
 - (void)mouseUp: (NSEvent *)theEvent
 {
-  NSTRACE ("mouseUp");
+  NSTRACE ("[EmacsView mouseUp:]");
   [self mouseDown: theEvent];
 }
 
 
 - (void)rightMouseUp: (NSEvent *)theEvent
 {
   [self mouseDown: theEvent];
 }
 
 
 - (void)rightMouseUp: (NSEvent *)theEvent
 {
-  NSTRACE ("rightMouseUp");
+  NSTRACE ("[EmacsView rightMouseUp:]");
   [self mouseDown: theEvent];
 }
 
 
 - (void)otherMouseUp: (NSEvent *)theEvent
 {
   [self mouseDown: theEvent];
 }
 
 
 - (void)otherMouseUp: (NSEvent *)theEvent
 {
-  NSTRACE ("otherMouseUp");
+  NSTRACE ("[EmacsView otherMouseUp:]");
   [self mouseDown: theEvent];
 }
 
 
 - (void) scrollWheel: (NSEvent *)theEvent
 {
   [self mouseDown: theEvent];
 }
 
 
 - (void) scrollWheel: (NSEvent *)theEvent
 {
-  NSTRACE ("scrollWheel");
+  NSTRACE ("[EmacsView scrollWheel:]");
   [self mouseDown: theEvent];
 }
 
   [self mouseDown: theEvent];
 }
 
@@ -6031,7 +6380,7 @@ not_in_argv (NSString *arg)
   Lisp_Object frame;
   NSPoint pt;
 
   Lisp_Object frame;
   NSPoint pt;
 
-//  NSTRACE ("mouseMoved");
+  NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
 
   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
   pt = [self convertPoint: [e locationInWindow] fromView: nil];
 
   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
   pt = [self convertPoint: [e locationInWindow] fromView: nil];
@@ -6051,7 +6400,7 @@ not_in_argv (NSString *arg)
 
   if (!NILP (Vmouse_autoselect_window))
     {
 
   if (!NILP (Vmouse_autoselect_window))
     {
-      NSTRACE ("mouse_autoselect_window");
+      NSTRACE_MSG ("mouse_autoselect_window");
       static Lisp_Object last_mouse_window;
       Lisp_Object window
        = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
       static Lisp_Object last_mouse_window;
       Lisp_Object window
        = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
@@ -6063,7 +6412,7 @@ not_in_argv (NSString *arg)
               || (EQ (XWINDOW (window)->frame,
                       XWINDOW (selected_window)->frame))))
         {
               || (EQ (XWINDOW (window)->frame,
                       XWINDOW (selected_window)->frame))))
         {
-          NSTRACE ("in_window");
+          NSTRACE_MSG ("in_window");
           emacs_event->kind = SELECT_WINDOW_EVENT;
           emacs_event->frame_or_window = window;
           EV_TRAILER2 (e);
           emacs_event->kind = SELECT_WINDOW_EVENT;
           emacs_event->frame_or_window = window;
           EV_TRAILER2 (e);
@@ -6093,21 +6442,21 @@ not_in_argv (NSString *arg)
 
 - (void)mouseDragged: (NSEvent *)e
 {
 
 - (void)mouseDragged: (NSEvent *)e
 {
-  NSTRACE ("mouseDragged");
+  NSTRACE ("[EmacsView mouseDragged:]");
   [self mouseMoved: e];
 }
 
 
 - (void)rightMouseDragged: (NSEvent *)e
 {
   [self mouseMoved: e];
 }
 
 
 - (void)rightMouseDragged: (NSEvent *)e
 {
-  NSTRACE ("rightMouseDragged");
+  NSTRACE ("[EmacsView rightMouseDragged:]");
   [self mouseMoved: e];
 }
 
 
 - (void)otherMouseDragged: (NSEvent *)e
 {
   [self mouseMoved: e];
 }
 
 
 - (void)otherMouseDragged: (NSEvent *)e
 {
-  NSTRACE ("otherMouseDragged");
+  NSTRACE ("[EmacsView otherMouseDragged:]");
   [self mouseMoved: e];
 }
 
   [self mouseMoved: e];
 }
 
@@ -6116,7 +6465,7 @@ not_in_argv (NSString *arg)
 {
   NSEvent *e =[[self window] currentEvent];
 
 {
   NSEvent *e =[[self window] currentEvent];
 
-  NSTRACE ("windowShouldClose");
+  NSTRACE ("[EmacsView windowShouldClose:]");
   windowClosing = YES;
   if (!emacs_event)
     return NO;
   windowClosing = YES;
   if (!emacs_event)
     return NO;
@@ -6138,7 +6487,7 @@ not_in_argv (NSString *arg)
   int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
   int neww, newh;
 
   int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
   int neww, newh;
 
-  NSTRACE ("updateFrameSize");
+  NSTRACE ("[EmacsView updateFrameSize:]");
   NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
   NSTRACE_RECT ("Original frame", wr);
   NSTRACE_MSG  ("Original columns: %d", cols);
   NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
   NSTRACE_RECT ("Original frame", wr);
   NSTRACE_MSG  ("Original columns: %d", cols);
@@ -6181,13 +6530,12 @@ not_in_argv (NSString *arg)
   if (rows < MINHEIGHT)
     rows = MINHEIGHT;
 
   if (rows < MINHEIGHT)
     rows = MINHEIGHT;
 
-  NSTRACE_MSG  ("New columns: %d", cols);
-  NSTRACE_MSG  ("New rows: %d", rows);
+  NSTRACE_MSG ("New columns: %d", cols);
+  NSTRACE_MSG ("New rows: %d", rows);
 
   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
     {
       NSView *view = FRAME_NS_VIEW (emacsframe);
 
   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
     {
       NSView *view = FRAME_NS_VIEW (emacsframe);
-      NSWindow *win = [view window];
 
       change_frame_size (emacsframe,
                          FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
 
       change_frame_size (emacsframe,
                          FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
@@ -6197,9 +6545,13 @@ not_in_argv (NSString *arg)
       cancel_mouse_face (emacsframe);
 
       wr = NSMakeRect (0, 0, neww, newh);
       cancel_mouse_face (emacsframe);
 
       wr = NSMakeRect (0, 0, neww, newh);
-      NSTRACE_RECT ("setFrame", wr);
+
       [view setFrame: wr];
       [view setFrame: wr];
-      [self windowDidMove:nil];   // Update top/left.
+
+      // to do: consider using [NSNotificationCenter postNotificationName:].
+      [self windowDidMove: // Update top/left.
+             [NSNotification notificationWithName:NSWindowDidMoveNotification
+                                           object:[view window]]];
     }
   else
     {
     }
   else
     {
@@ -6212,7 +6564,7 @@ not_in_argv (NSString *arg)
 {
   int extra = 0;
 
 {
   int extra = 0;
 
-  NSTRACE ("windowWillResize: toSize: " NSTRACE_FMT_SIZE,
+  NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
            NSTRACE_ARG_SIZE (frameSize));
   NSTRACE_RECT   ("[sender frame]", [sender frame]);
   NSTRACE_FSTYPE ("fs_state", fs_state);
            NSTRACE_ARG_SIZE (frameSize));
   NSTRACE_RECT   ("[sender frame]", [sender frame]);
   NSTRACE_FSTYPE ("fs_state", fs_state);
@@ -6282,7 +6634,7 @@ not_in_argv (NSString *arg)
 
   /* Restrict the new size to the text gird.
 
 
   /* Restrict the new size to the text gird.
 
-     Don't restict the width if the user only adjusted the height, and
+     Don't restrict the width if the user only adjusted the height, and
      vice versa.  (Without this, the frame would shrink, and move
      slightly, if the window was resized by dragging one of its
      borders.) */
      vice versa.  (Without this, the frame would shrink, and move
      slightly, if the window was resized by dragging one of its
      borders.) */
@@ -6311,8 +6663,12 @@ not_in_argv (NSString *arg)
 
 - (void)windowDidResize: (NSNotification *)notification
 {
 
 - (void)windowDidResize: (NSNotification *)notification
 {
-  NSTRACE ("windowDidResize");
-
+  NSTRACE ("[EmacsView windowDidResize:]");
+  if (!FRAME_LIVE_P (emacsframe))
+    {
+      NSTRACE_MSG ("Ignored (frame dead)");
+      return;
+    }
   if (emacsframe->output_data.ns->in_animation)
     {
       NSTRACE_MSG ("Ignored (in animation)");
   if (emacsframe->output_data.ns->in_animation)
     {
       NSTRACE_MSG ("Ignored (in animation)");
@@ -6350,6 +6706,8 @@ not_in_argv (NSString *arg)
 #ifdef NS_IMPL_COCOA
 - (void)viewDidEndLiveResize
 {
 #ifdef NS_IMPL_COCOA
 - (void)viewDidEndLiveResize
 {
+  NSTRACE ("[EmacsView viewDidEndLiveResize]");
+
   [super viewDidEndLiveResize];
   if (old_title != 0)
     {
   [super viewDidEndLiveResize];
   if (old_title != 0)
     {
@@ -6364,11 +6722,17 @@ not_in_argv (NSString *arg)
 
 - (void)windowDidBecomeKey: (NSNotification *)notification
 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
 
 - (void)windowDidBecomeKey: (NSNotification *)notification
 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
+{
+  [self windowDidBecomeKey];
+}
+
+
+- (void)windowDidBecomeKey      /* for direct calls */
 {
   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
   struct frame *old_focus = dpyinfo->x_focus_frame;
 
 {
   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
   struct frame *old_focus = dpyinfo->x_focus_frame;
 
-  NSTRACE ("windowDidBecomeKey");
+  NSTRACE ("[EmacsView windowDidBecomeKey]");
 
   if (emacsframe != old_focus)
     dpyinfo->x_focus_frame = emacsframe;
 
   if (emacsframe != old_focus)
     dpyinfo->x_focus_frame = emacsframe;
@@ -6388,7 +6752,7 @@ not_in_argv (NSString *arg)
 {
   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
 {
   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
-  NSTRACE ("windowDidResignKey");
+  NSTRACE ("[EmacsView windowDidResignKey:]");
 
   if (is_focus_frame)
     dpyinfo->x_focus_frame = 0;
 
   if (is_focus_frame)
     dpyinfo->x_focus_frame = 0;
@@ -6423,7 +6787,16 @@ not_in_argv (NSString *arg)
 
 - (void)windowWillMiniaturize: sender
 {
 
 - (void)windowWillMiniaturize: sender
 {
-  NSTRACE ("windowWillMiniaturize");
+  NSTRACE ("[EmacsView windowWillMiniaturize:]");
+}
+
+
+- (void)setFrame:(NSRect)frameRect;
+{
+  NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
+           NSTRACE_ARG_RECT (frameRect));
+
+  [super setFrame:(NSRect)frameRect];
 }
 
 
 }
 
 
@@ -6447,7 +6820,8 @@ not_in_argv (NSString *arg)
   NSColor *col;
   NSString *name;
 
   NSColor *col;
   NSString *name;
 
-  NSTRACE ("initFrameFromEmacs");
+  NSTRACE ("[EmacsView initFrameFromEmacs:]");
+  NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
 
   windowClosing = NO;
   processingCompose = NO;
 
   windowClosing = NO;
   processingCompose = NO;
@@ -6462,8 +6836,6 @@ not_in_argv (NSString *arg)
   maximized_width = maximized_height = -1;
   nonfs_window = nil;
 
   maximized_width = maximized_height = -1;
   nonfs_window = nil;
 
-/*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
-
   ns_userRect = NSMakeRect (0, 0, 0, 0);
   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
   ns_userRect = NSMakeRect (0, 0, 0, 0);
   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
@@ -6551,8 +6923,6 @@ not_in_argv (NSString *arg)
            IN_BOUND (-SCREENMAX,
                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX));
 
            IN_BOUND (-SCREENMAX,
                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX));
 
-        NSTRACE_POINT ("setFrameTopLeftPoint", pt);
-
         [win setFrameTopLeftPoint: pt];
 
         NSTRACE_RECT ("new frame", [win frame]);
         [win setFrameTopLeftPoint: pt];
 
         NSTRACE_RECT ("new frame", [win frame]);
@@ -6586,7 +6956,7 @@ not_in_argv (NSString *arg)
   NSArray *screens = [NSScreen screens];
   NSScreen *screen = [screens objectAtIndex: 0];
 
   NSArray *screens = [NSScreen screens];
   NSScreen *screen = [screens objectAtIndex: 0];
 
-  NSTRACE ("windowDidMove");
+  NSTRACE ("[EmacsView windowDidMove:]");
 
   if (!emacsframe->output_data.ns)
     return;
 
   if (!emacsframe->output_data.ns)
     return;
@@ -6604,7 +6974,7 @@ not_in_argv (NSString *arg)
    location so set_window_size moves the frame. */
 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
 {
    location so set_window_size moves the frame. */
 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
 {
-  NSTRACE (("[windowShouldZoom:win toFrame:" NSTRACE_FMT_RECT "]"
+  NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
             NSTRACE_FMT_RETURN "YES"),
            NSTRACE_ARG_RECT (newFrame));
 
             NSTRACE_FMT_RETURN "YES"),
            NSTRACE_ARG_RECT (newFrame));
 
@@ -6623,7 +6993,7 @@ not_in_argv (NSString *arg)
   // all paths.
   NSRect result = [sender frame];
 
   // all paths.
   NSRect result = [sender frame];
 
-  NSTRACE (("[windowWillUseStandardFrame: defaultFrame:"
+  NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
             NSTRACE_FMT_RECT "]"),
            NSTRACE_ARG_RECT (defaultFrame));
   NSTRACE_FSTYPE ("fs_state", fs_state);
             NSTRACE_FMT_RECT "]"),
            NSTRACE_ARG_RECT (defaultFrame));
   NSTRACE_FSTYPE ("fs_state", fs_state);
@@ -6736,7 +7106,7 @@ not_in_argv (NSString *arg)
 
 - (void)windowDidDeminiaturize: sender
 {
 
 - (void)windowDidDeminiaturize: sender
 {
-  NSTRACE ("windowDidDeminiaturize");
+  NSTRACE ("[EmacsView windowDidDeminiaturize:]");
   if (!emacsframe->output_data.ns)
     return;
 
   if (!emacsframe->output_data.ns)
     return;
 
@@ -6754,7 +7124,7 @@ not_in_argv (NSString *arg)
 
 - (void)windowDidExpose: sender
 {
 
 - (void)windowDidExpose: sender
 {
-  NSTRACE ("windowDidExpose");
+  NSTRACE ("[EmacsView windowDidExpose:]");
   if (!emacsframe->output_data.ns)
     return;
 
   if (!emacsframe->output_data.ns)
     return;
 
@@ -6768,7 +7138,7 @@ not_in_argv (NSString *arg)
 
 - (void)windowDidMiniaturize: sender
 {
 
 - (void)windowDidMiniaturize: sender
 {
-  NSTRACE ("windowDidMiniaturize");
+  NSTRACE ("[EmacsView windowDidMiniaturize:]");
   if (!emacsframe->output_data.ns)
     return;
 
   if (!emacsframe->output_data.ns)
     return;
 
@@ -6793,17 +7163,28 @@ not_in_argv (NSString *arg)
 
 - (void)windowWillEnterFullScreen:(NSNotification *)notification
 {
 
 - (void)windowWillEnterFullScreen:(NSNotification *)notification
 {
-  NSTRACE ("windowWillEnterFullScreen");
+  NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
+  [self windowWillEnterFullScreen];
+}
+- (void)windowWillEnterFullScreen /* provided for direct calls */
+{
+  NSTRACE ("[EmacsView windowWillEnterFullScreen]");
   fs_before_fs = fs_state;
 }
 
 - (void)windowDidEnterFullScreen:(NSNotification *)notification
 {
   fs_before_fs = fs_state;
 }
 
 - (void)windowDidEnterFullScreen:(NSNotification *)notification
 {
-  NSTRACE ("windowDidEnterFullScreen");
+  NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
+  [self windowDidEnterFullScreen];
+}
+
+- (void)windowDidEnterFullScreen /* provided for direct calls */
+{
+  NSTRACE ("[EmacsView windowDidEnterFullScreen]");
   [self setFSValue: FULLSCREEN_BOTH];
   if (! [self fsIsNative])
     {
   [self setFSValue: FULLSCREEN_BOTH];
   if (! [self fsIsNative])
     {
-      [self windowDidBecomeKey:notification];
+      [self windowDidBecomeKey];
       [nonfs_window orderOut:self];
     }
   else
       [nonfs_window orderOut:self];
     }
   else
@@ -6833,16 +7214,36 @@ not_in_argv (NSString *arg)
 
 - (void)windowWillExitFullScreen:(NSNotification *)notification
 {
 
 - (void)windowWillExitFullScreen:(NSNotification *)notification
 {
-  NSTRACE ("windowWillExitFullScreen");
+  NSTRACE ("[EmacsView windowWillExitFullScreen:]");
+  [self windowWillExitFullScreen];
+}
 
 
+- (void)windowWillExitFullScreen /* provided for direct calls */
+{
+  NSTRACE ("[EmacsView windowWillExitFullScreen]");
+  if (!FRAME_LIVE_P (emacsframe))
+    {
+      NSTRACE_MSG ("Ignored (frame dead)");
+      return;
+    }
   if (next_maximized != -1)
     fs_before_fs = next_maximized;
 }
 
 - (void)windowDidExitFullScreen:(NSNotification *)notification
 {
   if (next_maximized != -1)
     fs_before_fs = next_maximized;
 }
 
 - (void)windowDidExitFullScreen:(NSNotification *)notification
 {
-  NSTRACE ("windowDidExitFullScreen");
+  NSTRACE ("[EmacsView windowDidExitFullScreen:]");
+  [self windowDidExitFullScreen];
+}
 
 
+- (void)windowDidExitFullScreen /* provided for direct calls */
+{
+  NSTRACE ("[EmacsView windowDidExitFullScreen]");
+  if (!FRAME_LIVE_P (emacsframe))
+    {
+      NSTRACE_MSG ("Ignored (frame dead)");
+      return;
+    }
   [self setFSValue: fs_before_fs];
   fs_before_fs = -1;
 #ifdef HAVE_NATIVE_FS
   [self setFSValue: fs_before_fs];
   fs_before_fs = -1;
 #ifdef HAVE_NATIVE_FS
@@ -6869,17 +7270,32 @@ not_in_argv (NSString *arg)
 
 - (BOOL)isFullscreen
 {
 
 - (BOOL)isFullscreen
 {
-  if (! fs_is_native) return nonfs_window != nil;
+  BOOL res;
+
+  if (! fs_is_native)
+    {
+      res = (nonfs_window != nil);
+    }
+  else
+    {
 #ifdef HAVE_NATIVE_FS
 #ifdef HAVE_NATIVE_FS
-  return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
+      res = (([[self window] styleMask] & NSFullScreenWindowMask) != 0);
 #else
 #else
-  return NO;
+      res = NO;
 #endif
 #endif
+    }
+
+  NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
+           (int) res);
+
+  return res;
 }
 
 #ifdef HAVE_NATIVE_FS
 - (void)updateCollectionBehavior
 {
 }
 
 #ifdef HAVE_NATIVE_FS
 - (void)updateCollectionBehavior
 {
+  NSTRACE ("[EmacsView updateCollectionBehavior]");
+
   if (! [self isFullscreen])
     {
       NSWindow *win = [self window];
   if (! [self isFullscreen])
     {
       NSWindow *win = [self window];
@@ -6903,7 +7319,7 @@ not_in_argv (NSString *arg)
   NSRect r, wr;
   NSColor *col;
 
   NSRect r, wr;
   NSColor *col;
 
-  NSTRACE ("toggleFullScreen");
+  NSTRACE ("[EmacsView toggleFullScreen:]");
 
   if (fs_is_native)
     {
 
   if (fs_is_native)
     {
@@ -6971,13 +7387,13 @@ not_in_argv (NSString *arg)
 
       nonfs_window = w;
 
 
       nonfs_window = w;
 
-      [self windowWillEnterFullScreen:nil];
+      [self windowWillEnterFullScreen];
       [fw makeKeyAndOrderFront:NSApp];
       [fw makeFirstResponder:self];
       [w orderOut:self];
       r = [fw frameRectForContentRect:[screen frame]];
       [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
       [fw makeKeyAndOrderFront:NSApp];
       [fw makeFirstResponder:self];
       [w orderOut:self];
       r = [fw frameRectForContentRect:[screen frame]];
       [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
-      [self windowDidEnterFullScreen:nil];
+      [self windowDidEnterFullScreen];
       [fw display];
     }
   else
       [fw display];
     }
   else
@@ -7005,18 +7421,20 @@ not_in_argv (NSString *arg)
       if (FRAME_EXTERNAL_TOOL_BAR (f))
         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
 
       if (FRAME_EXTERNAL_TOOL_BAR (f))
         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
 
-      [self windowWillExitFullScreen:nil];
+      // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
+
+      [self windowWillExitFullScreen];
       [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
       [fw close];
       [w makeKeyAndOrderFront:NSApp];
       [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
       [fw close];
       [w makeKeyAndOrderFront:NSApp];
-      [self windowDidExitFullScreen:nil];
+      [self windowDidExitFullScreen];
       [self updateFrameSize:YES];
     }
 }
 
 - (void)handleFS
 {
       [self updateFrameSize:YES];
     }
 }
 
 - (void)handleFS
 {
-  NSTRACE ("handleFS");
+  NSTRACE ("[EmacsView handleFS]");
 
   if (fs_state != emacsframe->want_fullscreen)
     {
 
   if (fs_state != emacsframe->want_fullscreen)
     {
@@ -7067,8 +7485,8 @@ not_in_argv (NSString *arg)
 
 - (void) setFSValue: (int)value
 {
 
 - (void) setFSValue: (int)value
 {
-  NSTRACE ("setFSValue");
-  NSTRACE_FSTYPE ("value", value);
+  NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
+           NSTRACE_ARG_FSTYPE(value));
 
   Lisp_Object lval = Qnil;
   switch (value)
 
   Lisp_Object lval = Qnil;
   switch (value)
@@ -7092,7 +7510,7 @@ not_in_argv (NSString *arg)
 
 - (void)mouseEntered: (NSEvent *)theEvent
 {
 
 - (void)mouseEntered: (NSEvent *)theEvent
 {
-  NSTRACE ("mouseEntered");
+  NSTRACE ("[EmacsView mouseEntered:]");
   if (emacsframe)
     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
       = EV_TIMESTAMP (theEvent);
   if (emacsframe)
     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
       = EV_TIMESTAMP (theEvent);
@@ -7103,7 +7521,7 @@ not_in_argv (NSString *arg)
 {
   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
 
 {
   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
 
-  NSTRACE ("mouseExited");
+  NSTRACE ("[EmacsView mouseExited:]");
 
   if (!hlinfo)
     return;
 
   if (!hlinfo)
     return;
@@ -7121,7 +7539,7 @@ not_in_argv (NSString *arg)
 
 - menuDown: sender
 {
 
 - menuDown: sender
 {
-  NSTRACE ("menuDown");
+  NSTRACE ("[EmacsView menuDown:]");
   if (context_menu_value == -1)
     context_menu_value = [sender tag];
   else
   if (context_menu_value == -1)
     context_menu_value = [sender tag];
   else
@@ -7149,7 +7567,7 @@ not_in_argv (NSString *arg)
   NSEvent *theEvent;
   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
 
   NSEvent *theEvent;
   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
 
-  NSTRACE ("toolbarClicked");
+  NSTRACE ("[EmacsView toolbarClicked:]");
 
   if (!emacs_event)
     return self;
 
   if (!emacs_event)
     return self;
@@ -7172,6 +7590,8 @@ not_in_argv (NSString *arg)
 
 - toggleToolbar: (id)sender
 {
 
 - toggleToolbar: (id)sender
 {
+  NSTRACE ("[EmacsView toggleToolbar:]");
+
   if (!emacs_event)
     return self;
 
   if (!emacs_event)
     return self;
 
@@ -7187,8 +7607,8 @@ not_in_argv (NSString *arg)
   int x = NSMinX (rect), y = NSMinY (rect);
   int width = NSWidth (rect), height = NSHeight (rect);
 
   int x = NSMinX (rect), y = NSMinY (rect);
   int width = NSWidth (rect), height = NSHeight (rect);
 
-  NSTRACE ("drawRect");
-  NSTRACE_RECT ("input", rect);
+  NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
+           NSTRACE_ARG_RECT(rect));
 
   if (!emacsframe || !emacsframe->output_data.ns)
     return;
 
   if (!emacsframe || !emacsframe->output_data.ns)
     return;
@@ -7214,7 +7634,7 @@ not_in_argv (NSString *arg)
 
 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
 {
 
 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
 {
-  NSTRACE ("draggingEntered");
+  NSTRACE ("[EmacsView draggingEntered:]");
   return NSDragOperationGeneric;
 }
 
   return NSDragOperationGeneric;
 }
 
@@ -7235,7 +7655,7 @@ not_in_argv (NSString *arg)
   NSDragOperation op = [sender draggingSourceOperationMask];
   int modifiers = 0;
 
   NSDragOperation op = [sender draggingSourceOperationMask];
   int modifiers = 0;
 
-  NSTRACE ("performDragOperation");
+  NSTRACE ("[EmacsView performDragOperation:]");
 
   if (!emacs_event)
     return NO;
 
   if (!emacs_event)
     return NO;
@@ -7335,7 +7755,7 @@ not_in_argv (NSString *arg)
 - (id) validRequestorForSendType: (NSString *)typeSent
                       returnType: (NSString *)typeReturned
 {
 - (id) validRequestorForSendType: (NSString *)typeSent
                       returnType: (NSString *)typeReturned
 {
-  NSTRACE ("validRequestorForSendType");
+  NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
       && typeReturned == nil)
     {
   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
       && typeReturned == nil)
     {
@@ -7368,6 +7788,8 @@ not_in_argv (NSString *arg)
   NSArray *typesDeclared;
   Lisp_Object val;
 
   NSArray *typesDeclared;
   Lisp_Object val;
 
+  NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
+
   /* We only support NSStringPboardType */
   if ([types containsObject:NSStringPboardType] == NO) {
     return NO;
   /* We only support NSStringPboardType */
   if ([types containsObject:NSStringPboardType] == NO) {
     return NO;
@@ -7397,7 +7819,7 @@ not_in_argv (NSString *arg)
 - setMiniwindowImage: (BOOL) setMini
 {
   id image = [[self window] miniwindowImage];
 - setMiniwindowImage: (BOOL) setMini
 {
   id image = [[self window] miniwindowImage];
-  NSTRACE ("setMiniwindowImage");
+  NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
 
   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
      about "AppleDockIconEnabled" notwithstanding, however the set message
 
   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
      about "AppleDockIconEnabled" notwithstanding, however the set message
@@ -7445,6 +7867,8 @@ not_in_argv (NSString *arg)
   struct frame *f = SELECTED_FRAME ();
   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
 
   struct frame *f = SELECTED_FRAME ();
   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
 
+  NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
+
   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
     return NSAccessibilityTextFieldRole;
 
   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
     return NSAccessibilityTextFieldRole;
 
@@ -7498,7 +7922,7 @@ not_in_argv (NSString *arg)
 /* Constrain size and placement of a frame.
 
    By returning the original "frameRect", the frame is not
 /* Constrain size and placement of a frame.
 
    By returning the original "frameRect", the frame is not
-   contrained. This can lead to unwanted situations where, for
+   constrained. This can lead to unwanted situations where, for
    example, the menu bar covers the frame.
 
    The default implementation (accessed using "super") constrains the
    example, the menu bar covers the frame.
 
    The default implementation (accessed using "super") constrains the
@@ -7513,7 +7937,7 @@ not_in_argv (NSString *arg)
    large screen). */
 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
 {
    large screen). */
 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
 {
-  NSTRACE ("constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:",
+  NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
              NSTRACE_ARG_RECT (frameRect));
 
 #ifdef NS_IMPL_COCOA
              NSTRACE_ARG_RECT (frameRect));
 
 #ifdef NS_IMPL_COCOA
@@ -7530,22 +7954,21 @@ not_in_argv (NSString *arg)
 #endif
 #endif
 
 #endif
 #endif
 
-  return constrain_frame_rect(frameRect);
+  return constrain_frame_rect(frameRect,
+                              [(EmacsView *)[self delegate] isFullscreen]);
 }
 
 
 - (void)performZoom:(id)sender
 {
 }
 
 
 - (void)performZoom:(id)sender
 {
-  NSTRACE ("performZoom");
+  NSTRACE ("[EmacsWindow performZoom:]");
 
   return [super performZoom:sender];
 }
 
 - (void)zoom:(id)sender
 {
 
   return [super performZoom:sender];
 }
 
 - (void)zoom:(id)sender
 {
-  struct frame * f = SELECTED_FRAME ();
-
-  NSTRACE ("zoom");
+  NSTRACE ("[EmacsWindow zoom:]");
 
   ns_update_auto_hide_menu_bar();
 
 
   ns_update_auto_hide_menu_bar();
 
@@ -7554,13 +7977,14 @@ not_in_argv (NSString *arg)
 
 #if 0
   // Native zoom done using the standard zoom animation.  Size of the
 
 #if 0
   // Native zoom done using the standard zoom animation.  Size of the
-  // resulting frame reduced to accomodate the Dock and, if present,
+  // resulting frame reduced to accommodate the Dock and, if present,
   // the menu-bar.
   [super zoom:sender];
 
   // the menu-bar.
   [super zoom:sender];
 
-#elsif 0
+#elif 0
   // Native zoom done using the standard zoom animation, plus an
   // Native zoom done using the standard zoom animation, plus an
-  // explicit resize to cover the full screen.
+  // explicit resize to cover the full screen, except the menu-bar and
+  // dock, if present.
   [super zoom:sender];
 
   // After the native zoom, resize the resulting frame to fill the
   [super zoom:sender];
 
   // After the native zoom, resize the resulting frame to fill the
@@ -7568,8 +7992,8 @@ not_in_argv (NSString *arg)
   //
   // This works for all practical purposes.  (The only minor oddity is
   // when transiting from full-height frame to a maximized, the
   //
   // This works for all practical purposes.  (The only minor oddity is
   // when transiting from full-height frame to a maximized, the
-  // animation reduces the height of the frame slighty (to the 4
-  // pixels needed to accomodate the Doc) before it snaps back into
+  // animation reduces the height of the frame slightly (to the 4
+  // pixels needed to accommodate the Doc) before it snaps back into
   // full height.  The user would need a very trained eye to spot
   // this.)
   NSScreen * screen = [self screen];
   // full height.  The user would need a very trained eye to spot
   // this.)
   NSScreen * screen = [self screen];
@@ -7580,6 +8004,9 @@ not_in_argv (NSString *arg)
       NSTRACE_FSTYPE ("fullscreenState", fs_state);
 
       NSRect sr = [screen frame];
       NSTRACE_FSTYPE ("fullscreenState", fs_state);
 
       NSRect sr = [screen frame];
+      struct EmacsMargins margins
+        = ns_screen_margins_ignoring_hidden_dock(screen);
+
       NSRect wr = [self frame];
       NSTRACE_RECT ("Rect after zoom", wr);
 
       NSRect wr = [self frame];
       NSTRACE_RECT ("Rect after zoom", wr);
 
@@ -7588,15 +8015,15 @@ not_in_argv (NSString *arg)
       if (fs_state == FULLSCREEN_MAXIMIZED
           || fs_state == FULLSCREEN_HEIGHT)
         {
       if (fs_state == FULLSCREEN_MAXIMIZED
           || fs_state == FULLSCREEN_HEIGHT)
         {
-          newWr.origin.x = 0;
-          newWr.size.height = sr.size.height - ns_menu_bar_height(screen);
+          newWr.origin.y = sr.origin.y + margins.bottom;
+          newWr.size.height = sr.size.height - margins.top - margins.bottom;
         }
 
       if (fs_state == FULLSCREEN_MAXIMIZED
           || fs_state == FULLSCREEN_WIDTH)
         {
         }
 
       if (fs_state == FULLSCREEN_MAXIMIZED
           || fs_state == FULLSCREEN_WIDTH)
         {
-          newWr.origin.y = 0;
-          newWr.size.width = sr.size.width;
+          newWr.origin.x = sr.origin.x + margins.left;
+          newWr.size.width = sr.size.width - margins.right - margins.left;
         }
 
       if (newWr.size.width     != wr.size.width
         }
 
       if (newWr.size.width     != wr.size.width
@@ -7604,18 +8031,25 @@ not_in_argv (NSString *arg)
           || newWr.origin.x    != wr.origin.x
           || newWr.origin.y    != wr.origin.y)
         {
           || newWr.origin.x    != wr.origin.x
           || newWr.origin.y    != wr.origin.y)
         {
-          NSTRACE_RECT ("Corrected rect", newWr);
+          NSTRACE_MSG ("New frame different");
           [self setFrame: newWr display: NO];
         }
     }
 #else
           [self setFrame: newWr display: NO];
         }
     }
 #else
-  // Non-native zoom which is done instantaneous.  The resulting frame
-  // covert the entire scrren, except the menu-bar, if present.
+  // Non-native zoom which is done instantaneously.  The resulting
+  // frame covers the entire screen, except the menu-bar and dock, if
+  // present.
   NSScreen * screen = [self screen];
   if (screen != nil)
     {
       NSRect sr = [screen frame];
   NSScreen * screen = [self screen];
   if (screen != nil)
     {
       NSRect sr = [screen frame];
-      sr.size.height -= ns_menu_bar_height (screen);
+      struct EmacsMargins margins
+        = ns_screen_margins_ignoring_hidden_dock(screen);
+
+      sr.size.height -= (margins.top + margins.bottom);
+      sr.size.width  -= (margins.left + margins.right);
+      sr.origin.x += margins.left;
+      sr.origin.y += margins.bottom;
 
       sr = [[self delegate] windowWillUseStandardFrame:self
                                           defaultFrame:sr];
 
       sr = [[self delegate] windowWillUseStandardFrame:self
                                           defaultFrame:sr];
@@ -7624,6 +8058,33 @@ not_in_argv (NSString *arg)
 #endif
 }
 
 #endif
 }
 
+- (void)setFrame:(NSRect)windowFrame
+         display:(BOOL)displayViews
+{
+  NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
+           NSTRACE_ARG_RECT (windowFrame), displayViews);
+
+  [super setFrame:windowFrame display:displayViews];
+}
+
+- (void)setFrame:(NSRect)windowFrame
+         display:(BOOL)displayViews
+         animate:(BOOL)performAnimation
+{
+  NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
+           " display:%d performAnimation:%d]",
+           NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
+
+  [super setFrame:windowFrame display:displayViews animate:performAnimation];
+}
+
+- (void)setFrameTopLeftPoint:(NSPoint)point
+{
+  NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
+           NSTRACE_ARG_POINT (point));
+
+  [super setFrameTopLeftPoint:point];
+}
 @end /* EmacsWindow */
 
 
 @end /* EmacsWindow */
 
 
@@ -7669,12 +8130,15 @@ not_in_argv (NSString *arg)
   return r;
 }
 
   return r;
 }
 
-
 - initFrame: (NSRect )r window: (Lisp_Object)nwin
 {
 - initFrame: (NSRect )r window: (Lisp_Object)nwin
 {
-  NSTRACE ("EmacsScroller_initFrame");
+  NSTRACE ("[EmacsScroller initFrame: window:]");
+
+  if (r.size.width > r.size.height)
+      horizontal = YES;
+  else
+      horizontal = NO;
 
 
-  r.size.width = [EmacsScroller scrollerWidth];
   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
   [self setContinuous: YES];
   [self setEnabled: YES];
   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
   [self setContinuous: YES];
   [self setEnabled: YES];
@@ -7690,9 +8154,12 @@ not_in_argv (NSString *arg)
 
   window = XWINDOW (nwin);
   condemned = NO;
 
   window = XWINDOW (nwin);
   condemned = NO;
-  pixel_height = NSHeight (r);
-  if (pixel_height == 0) pixel_height = 1;
-  min_portion = 20 / pixel_height;
+  if (horizontal)
+    pixel_length = NSWidth (r);
+  else
+    pixel_length = NSHeight (r);
+  if (pixel_length == 0) pixel_length = 1;
+  min_portion = 20 / pixel_length;
 
   frame = XFRAME (window->frame);
   if (FRAME_LIVE_P (frame))
 
   frame = XFRAME (window->frame);
   if (FRAME_LIVE_P (frame))
@@ -7718,11 +8185,15 @@ not_in_argv (NSString *arg)
 
 - (void)setFrame: (NSRect)newRect
 {
 
 - (void)setFrame: (NSRect)newRect
 {
-  NSTRACE ("EmacsScroller_setFrame");
+  NSTRACE ("[EmacsScroller setFrame:]");
+
 /*  block_input (); */
 /*  block_input (); */
-  pixel_height = NSHeight (newRect);
-  if (pixel_height == 0) pixel_height = 1;
-  min_portion = 20 / pixel_height;
+  if (horizontal)
+    pixel_length = NSWidth (newRect);
+  else
+    pixel_length = NSHeight (newRect);
+  if (pixel_length == 0) pixel_length = 1;
+  min_portion = 20 / pixel_length;
   [super setFrame: newRect];
 /*  unblock_input (); */
 }
   [super setFrame: newRect];
 /*  unblock_input (); */
 }
@@ -7730,9 +8201,14 @@ not_in_argv (NSString *arg)
 
 - (void)dealloc
 {
 
 - (void)dealloc
 {
-  NSTRACE ("EmacsScroller_dealloc");
+  NSTRACE ("[EmacsScroller dealloc]");
   if (window)
   if (window)
-    wset_vertical_scroll_bar (window, Qnil);
+    {
+      if (horizontal)
+        wset_horizontal_scroll_bar (window, Qnil);
+      else
+        wset_vertical_scroll_bar (window, Qnil);
+    }
   window = 0;
   [super dealloc];
 }
   window = 0;
   [super dealloc];
 }
@@ -7740,7 +8216,7 @@ not_in_argv (NSString *arg)
 
 - condemn
 {
 
 - condemn
 {
-  NSTRACE ("condemn");
+  NSTRACE ("[EmacsScroller condemn]");
   condemned =YES;
   return self;
 }
   condemned =YES;
   return self;
 }
@@ -7748,7 +8224,7 @@ not_in_argv (NSString *arg)
 
 - reprieve
 {
 
 - reprieve
 {
-  NSTRACE ("reprieve");
+  NSTRACE ("[EmacsScroller reprieve]");
   condemned =NO;
   return self;
 }
   condemned =NO;
   return self;
 }
@@ -7756,7 +8232,7 @@ not_in_argv (NSString *arg)
 
 -(bool)judge
 {
 
 -(bool)judge
 {
-  NSTRACE ("judge");
+  NSTRACE ("[EmacsScroller judge]");
   bool ret = condemned;
   if (condemned)
     {
   bool ret = condemned;
   if (condemned)
     {
@@ -7767,7 +8243,12 @@ not_in_argv (NSString *arg)
       if (view != nil)
         view->scrollbarsNeedingUpdate++;
       if (window)
       if (view != nil)
         view->scrollbarsNeedingUpdate++;
       if (window)
-        wset_vertical_scroll_bar (window, Qnil);
+        {
+          if (horizontal)
+            wset_horizontal_scroll_bar (window, Qnil);
+          else
+            wset_vertical_scroll_bar (window, Qnil);
+        }
       window = 0;
       [self removeFromSuperview];
       [self release];
       window = 0;
       [self removeFromSuperview];
       [self release];
@@ -7780,7 +8261,7 @@ not_in_argv (NSString *arg)
 - (void)resetCursorRects
 {
   NSRect visible = [self visibleRect];
 - (void)resetCursorRects
 {
   NSRect visible = [self visibleRect];
-  NSTRACE ("resetCursorRects");
+  NSTRACE ("[EmacsScroller resetCursorRects]");
 
   if (!NSIsEmptyRect (visible))
     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
 
   if (!NSIsEmptyRect (visible))
     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
@@ -7798,7 +8279,7 @@ not_in_argv (NSString *arg)
 
 - setPosition: (int)position portion: (int)portion whole: (int)whole
 {
 
 - setPosition: (int)position portion: (int)portion whole: (int)whole
 {
-  NSTRACE ("setPosition");
+  NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
 
   em_position = position;
   em_portion = portion;
 
   em_position = position;
   em_portion = portion;
@@ -7817,7 +8298,7 @@ not_in_argv (NSString *arg)
     {
       float pos;
       CGFloat por;
     {
       float pos;
       CGFloat por;
-      portion = max ((float)whole*min_portion/pixel_height, portion);
+      portion = max ((float)whole*min_portion/pixel_length, portion);
       pos = (float)position / (whole - portion);
       por = (CGFloat)portion/whole;
 #ifdef NS_IMPL_COCOA
       pos = (float)position / (whole - portion);
       por = (CGFloat)portion/whole;
 #ifdef NS_IMPL_COCOA
@@ -7835,6 +8316,9 @@ not_in_argv (NSString *arg)
 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
 {
   Lisp_Object win;
 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
 {
   Lisp_Object win;
+
+  NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
+
   if (!emacs_event)
     return;
 
   if (!emacs_event)
     return;
 
@@ -7844,10 +8328,20 @@ not_in_argv (NSString *arg)
   XSETWINDOW (win, window);
   emacs_event->frame_or_window = win;
   emacs_event->timestamp = EV_TIMESTAMP (e);
   XSETWINDOW (win, window);
   emacs_event->frame_or_window = win;
   emacs_event->timestamp = EV_TIMESTAMP (e);
-  emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
   emacs_event->arg = Qnil;
   emacs_event->arg = Qnil;
-  XSETINT (emacs_event->x, loc * pixel_height);
-  XSETINT (emacs_event->y, pixel_height-20);
+
+  if (horizontal)
+    {
+      emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
+      XSETINT (emacs_event->x, em_whole * loc / pixel_length);
+      XSETINT (emacs_event->y, em_whole);
+    }
+  else
+    {
+      emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
+      XSETINT (emacs_event->x, loc);
+      XSETINT (emacs_event->y, pixel_length-20);
+    }
 
   if (q_event_ptr)
     {
 
   if (q_event_ptr)
     {
@@ -7868,6 +8362,8 @@ not_in_argv (NSString *arg)
   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
 
   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
 
+  NSTRACE ("[EmacsScroller repeatScroll:]");
+
   /* clear timer if need be */
   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
     {
   /* clear timer if need be */
   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
     {
@@ -7903,20 +8399,20 @@ not_in_argv (NSString *arg)
   CGFloat inc = 0.0, loc, kloc, pos;
   int edge = 0;
 
   CGFloat inc = 0.0, loc, kloc, pos;
   int edge = 0;
 
-  NSTRACE ("EmacsScroller_mouseDown");
+  NSTRACE ("[EmacsScroller mouseDown:]");
 
   switch (part)
     {
     case NSScrollerDecrementPage:
 
   switch (part)
     {
     case NSScrollerDecrementPage:
-        last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
+      last_hit_part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle; break;
     case NSScrollerIncrementPage:
     case NSScrollerIncrementPage:
-        last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
+      last_hit_part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle; break;
     case NSScrollerDecrementLine:
     case NSScrollerDecrementLine:
-      last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
+      last_hit_part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow; break;
     case NSScrollerIncrementLine:
     case NSScrollerIncrementLine:
-      last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
+      last_hit_part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow; break;
     case NSScrollerKnob:
     case NSScrollerKnob:
-      last_hit_part = scroll_bar_handle; break;
+      last_hit_part = horizontal ? scroll_bar_horizontal_handle : scroll_bar_handle; break;
     case NSScrollerKnobSlot:  /* GNUstep-only */
       last_hit_part = scroll_bar_move_ratio; break;
     default:  /* NSScrollerNoPart? */
     case NSScrollerKnobSlot:  /* GNUstep-only */
       last_hit_part = scroll_bar_move_ratio; break;
     default:  /* NSScrollerNoPart? */
@@ -7925,36 +8421,34 @@ not_in_argv (NSString *arg)
       return;
     }
 
       return;
     }
 
-  if (inc != 0.0)
-    {
-      pos = 0;      /* ignored */
-
-      /* set a timer to repeat, as we can't let superclass do this modally */
-      scroll_repeat_entry
-       = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
-                                            target: self
-                                          selector: @selector (repeatScroll:)
-                                          userInfo: 0
-                                           repeats: YES]
-           retain];
-    }
-  else
+  if (part == NSScrollerKnob || part == NSScrollerKnobSlot)
     {
       /* handle, or on GNUstep possibly slot */
       NSEvent *fake_event;
     {
       /* handle, or on GNUstep possibly slot */
       NSEvent *fake_event;
+      int length;
 
       /* compute float loc in slot and mouse offset on knob */
       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
                       toView: nil];
 
       /* compute float loc in slot and mouse offset on knob */
       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
                       toView: nil];
-      loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
+      if (horizontal)
+        {
+          length = NSWidth (sr);
+          loc = ([e locationInWindow].x - NSMinX (sr));
+        }
+      else
+        {
+          length = NSHeight (sr);
+          loc = length - ([e locationInWindow].y - NSMinY (sr));
+        }
+
       if (loc <= 0.0)
         {
           loc = 0.0;
           edge = -1;
         }
       if (loc <= 0.0)
         {
           loc = 0.0;
           edge = -1;
         }
-      else if (loc >= NSHeight (sr))
+      else if (loc >= length)
         {
         {
-          loc = NSHeight (sr);
+          loc = length;
           edge = 1;
         }
 
           edge = 1;
         }
 
@@ -7964,17 +8458,16 @@ not_in_argv (NSString *arg)
         {
           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
                           toView: nil];
         {
           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
                           toView: nil];
-          kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
+          if (horizontal)
+            kloc = ([e locationInWindow].x - NSMinX (kr));
+          else
+            kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
         }
       last_mouse_offset = kloc;
 
         }
       last_mouse_offset = kloc;
 
-      /* if knob, tell emacs a location offset by knob pos
-         (to indicate top of handle) */
-      if (part == NSScrollerKnob)
-          pos = (loc - last_mouse_offset) / NSHeight (sr);
-      else
-        /* else this is a slot click on GNUstep: go straight there */
-        pos = loc / NSHeight (sr);
+      if (part != NSScrollerKnob)
+        /* this is a slot click on GNUstep: go straight there */
+        pos = loc;
 
       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
 
       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
@@ -7988,6 +8481,19 @@ not_in_argv (NSString *arg)
                                       pressure: [e pressure]];
       [super mouseUp: fake_event];
     }
                                       pressure: [e pressure]];
       [super mouseUp: fake_event];
     }
+  else
+    {
+      pos = 0;      /* ignored */
+
+      /* set a timer to repeat, as we can't let superclass do this modally */
+      scroll_repeat_entry
+       = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
+                                            target: self
+                                          selector: @selector (repeatScroll:)
+                                          userInfo: 0
+                                           repeats: YES]
+           retain];
+    }
 
   if (part != NSScrollerKnob)
     [self sendScrollEventAtLoc: pos fromEvent: e];
 
   if (part != NSScrollerKnob)
     [self sendScrollEventAtLoc: pos fromEvent: e];
@@ -7999,29 +8505,42 @@ not_in_argv (NSString *arg)
 {
     NSRect sr;
     double loc, pos;
 {
     NSRect sr;
     double loc, pos;
+    int length;
 
 
-    NSTRACE ("EmacsScroller_mouseDragged");
+    NSTRACE ("[EmacsScroller mouseDragged:]");
 
       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
                       toView: nil];
 
       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
                       toView: nil];
-      loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
+
+      if (horizontal)
+        {
+          length = NSWidth (sr);
+          loc = ([e locationInWindow].x - NSMinX (sr));
+        }
+      else
+        {
+          length = NSHeight (sr);
+          loc = length - ([e locationInWindow].y - NSMinY (sr));
+        }
 
       if (loc <= 0.0)
         {
           loc = 0.0;
         }
 
       if (loc <= 0.0)
         {
           loc = 0.0;
         }
-      else if (loc >= NSHeight (sr) + last_mouse_offset)
+      else if (loc >= length + last_mouse_offset)
         {
         {
-          loc = NSHeight (sr) + last_mouse_offset;
+          loc = length + last_mouse_offset;
         }
 
         }
 
-      pos = (loc - last_mouse_offset) / NSHeight (sr);
+      pos = (loc - last_mouse_offset);
       [self sendScrollEventAtLoc: pos fromEvent: e];
 }
 
 
 - (void)mouseUp: (NSEvent *)e
 {
       [self sendScrollEventAtLoc: pos fromEvent: e];
 }
 
 
 - (void)mouseUp: (NSEvent *)e
 {
+  NSTRACE ("[EmacsScroller mouseUp:]");
+
   if (scroll_repeat_entry)
     {
       [scroll_repeat_entry invalidate];
   if (scroll_repeat_entry)
     {
       [scroll_repeat_entry invalidate];
@@ -8035,6 +8554,8 @@ not_in_argv (NSString *arg)
 /* treat scrollwheel events in the bar as though they were in the main window */
 - (void) scrollWheel: (NSEvent *)theEvent
 {
 /* treat scrollwheel events in the bar as though they were in the main window */
 - (void) scrollWheel: (NSEvent *)theEvent
 {
+  NSTRACE ("[EmacsScroller scrollWheel:]");
+
   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
   [view mouseDown: theEvent];
 }
   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
   [view mouseDown: theEvent];
 }