emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] feature/tabs 5bf45ec 2/2: Try to add more tab-bar support


From: Juri Linkov
Subject: [Emacs-diffs] feature/tabs 5bf45ec 2/2: Try to add more tab-bar support on macos
Date: Sun, 1 Sep 2019 17:32:42 -0400 (EDT)

branch: feature/tabs
commit 5bf45ec48b781a1165e882e7216892bf201d15f4
Author: Juri Linkov <address@hidden>
Commit: Juri Linkov <address@hidden>

    Try to add more tab-bar support on macos
---
 src/nsfns.m  |  86 +++++++++++++++-
 src/nsmenu.m | 316 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/nsterm.h |  65 ++++++++++++
 src/nsterm.m | 147 ++++++++++++++++++++++++---
 4 files changed, 601 insertions(+), 13 deletions(-)

diff --git a/src/nsfns.m b/src/nsfns.m
index 2470c05..890da99 100644
--- a/src/nsfns.m
+++ b/src/nsfns.m
@@ -610,6 +610,75 @@ ns_set_menu_bar_lines (struct frame *f, Lisp_Object value, 
Lisp_Object oldval)
 }
 
 
+/* tabbar support */
+static void
+ns_set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
+{
+  /* Currently, when the tab bar changes state, the frame is resized.
+
+     TODO: It would be better if this didn't occur when 1) the frame
+     is full height or maximized or 2) when specified by
+     `frame-inhibit-implied-resize'.  */
+  int nlines;
+
+  NSTRACE ("ns_set_tab_bar_lines");
+
+  if (FRAME_MINIBUF_ONLY_P (f))
+    return;
+
+  if (RANGED_FIXNUMP (0, value, INT_MAX))
+    nlines = XFIXNAT (value);
+  else
+    nlines = 0;
+
+  if (nlines)
+    {
+      FRAME_EXTERNAL_TAB_BAR (f) = 1;
+      update_frame_tab_bar (f);
+    }
+  else
+    {
+      if (FRAME_EXTERNAL_TAB_BAR (f))
+        {
+          free_frame_tab_bar (f);
+          FRAME_EXTERNAL_TAB_BAR (f) = 0;
+
+          {
+            EmacsView *view = FRAME_NS_VIEW (f);
+            int fs_state = [view fullscreenState];
+
+            if (fs_state == FULLSCREEN_MAXIMIZED)
+              {
+                [view setFSValue:FULLSCREEN_WIDTH];
+              }
+            else if (fs_state == FULLSCREEN_HEIGHT)
+              {
+                [view setFSValue:FULLSCREEN_NONE];
+              }
+          }
+       }
+    }
+
+  {
+    int inhibit
+      = ((f->after_make_frame
+         && !f->tab_bar_resized
+         && (EQ (frame_inhibit_implied_resize, Qt)
+             || (CONSP (frame_inhibit_implied_resize)
+                 && !NILP (Fmemq (Qtab_bar_lines,
+                                  frame_inhibit_implied_resize))))
+         && NILP (get_frame_param (f, Qfullscreen)))
+        ? 0
+        : 2);
+
+    NSTRACE_MSG ("inhibit:%d", inhibit);
+
+    frame_size_history_add (f, Qupdate_frame_tab_bar, 0, 0, Qnil);
+    adjust_frame_size (f, -1, -1, inhibit, 0, Qtab_bar_lines);
+  }
+}
+
+
 /* toolbar support */
 static void
 ns_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
@@ -923,6 +992,7 @@ frame_parm_handler ns_frame_parm_handlers[] =
   gui_set_vertical_scroll_bars, /* generic OK */
   gui_set_horizontal_scroll_bars, /* generic OK */
   gui_set_visibility, /* generic OK */
+  ns_set_tab_bar_lines,
   ns_set_tool_bar_lines,
   0, /* x_set_scroll_bar_foreground, will ignore (not possible on NS) */
   0, /* x_set_scroll_bar_background,  will ignore (not possible on NS) */
@@ -1286,6 +1356,10 @@ DEFUN ("x-create-frame", Fx_create_frame, 
Sx_create_frame,
                          NILP (Vmenu_bar_mode)
                          ? make_fixnum (0) : make_fixnum (1),
                          NULL, NULL, RES_TYPE_NUMBER);
+  gui_default_parameter (f, parms, Qtab_bar_lines,
+                         NILP (Vtab_bar_mode)
+                         ? make_fixnum (0) : make_fixnum (1),
+                         NULL, NULL, RES_TYPE_NUMBER);
   gui_default_parameter (f, parms, Qtool_bar_lines,
                          NILP (Vtool_bar_mode)
                          ? make_fixnum (0) : make_fixnum (1),
@@ -2790,6 +2864,10 @@ frame_geometry (Lisp_Object frame, Lisp_Object attribute)
   int native_right = f->left_pos + outer_width - border;
   int native_bottom = f->top_pos + outer_height - border;
   int internal_border_width = FRAME_INTERNAL_BORDER_WIDTH (f);
+  int tab_bar_height = FRAME_TABBAR_HEIGHT (f);
+  int tab_bar_width = (tab_bar_height
+                      ? outer_width - 2 * internal_border_width
+                      : 0);
   int tool_bar_height = FRAME_TOOLBAR_HEIGHT (f);
   int tool_bar_width = (tool_bar_height
                        ? outer_width - 2 * internal_border_width
@@ -2805,7 +2883,7 @@ frame_geometry (Lisp_Object frame, Lisp_Object attribute)
                   native_right, native_bottom);
   else if (EQ (attribute, Qinner_edges))
     return list4i (native_left + internal_border_width,
-                  native_top + tool_bar_height + internal_border_width,
+                  native_top + tab_bar_height + tool_bar_height + 
internal_border_width,
                   native_right - internal_border_width,
                   native_bottom - internal_border_width);
   else
@@ -2824,6 +2902,9 @@ frame_geometry (Lisp_Object frame, Lisp_Object attribute)
                    Fcons (make_fixnum (0), make_fixnum (title_height))),
             Fcons (Qmenu_bar_external, Qnil),
             Fcons (Qmenu_bar_size, Fcons (make_fixnum (0), make_fixnum (0))),
+            Fcons (Qtab_bar_size,
+                   Fcons (make_fixnum (tab_bar_width),
+                          make_fixnum (tab_bar_height))),
             Fcons (Qtool_bar_external,
                    FRAME_EXTERNAL_TOOL_BAR (f) ? Qt : Qnil),
             Fcons (Qtool_bar_position, FRAME_TOOL_BAR_POSITION (f)),
@@ -2861,6 +2942,9 @@ and width values are in pixels.
 `menu-bar-size' is a cons of the width and height of the menu bar of
   FRAME.
 
+`tab-bar-size' is a cons of the width and height of the tab bar of
+  FRAME.
+
 `tool-bar-external', if non-nil, means the tool bar is external (never
   included in the inner edges of FRAME).
 
diff --git a/src/nsmenu.m b/src/nsmenu.m
index 817f8cf..223561b 100644
--- a/src/nsmenu.m
+++ b/src/nsmenu.m
@@ -993,6 +993,322 @@ ns_menu_show (struct frame *f, int x, int y, int 
menuflags,
 
 /* ==========================================================================
 
+    Tabbar: externally-called functions
+
+   ========================================================================== 
*/
+
+void
+free_frame_tab_bar (struct frame *f)
+/* --------------------------------------------------------------------------
+    Under NS we just hide the tabbar until it might be needed again.
+   -------------------------------------------------------------------------- 
*/
+{
+  EmacsView *view = FRAME_NS_VIEW (f);
+
+  NSTRACE ("free_frame_tab_bar");
+
+  block_input ();
+  view->wait_for_tab_bar = NO;
+
+  /* Note: This triggers an animation, which calls windowDidResize
+     repeatedly.  */
+  f->output_data.ns->in_animation = 1;
+  [[view tabbar] setVisible: NO];
+  f->output_data.ns->in_animation = 0;
+
+  unblock_input ();
+}
+
+void
+update_frame_tab_bar (struct frame *f)
+/* --------------------------------------------------------------------------
+    Update tabbar contents.
+   -------------------------------------------------------------------------- 
*/
+{
+  int i, k = 0;
+  EmacsView *view = FRAME_NS_VIEW (f);
+  EmacsTabbar *tabbar = [view tabbar];
+  int oldh;
+
+  NSTRACE ("update_frame_tab_bar");
+
+  if (view == nil || tabbar == nil) return;
+  block_input ();
+
+  oldh = FRAME_TABBAR_HEIGHT (f);
+
+#ifdef NS_IMPL_COCOA
+  [tabbar clearActive];
+#else
+  [tabbar clearAll];
+#endif
+
+  /* Update EmacsTabbar as in GtkUtils, build items list.  */
+  for (i = 0; i < f->n_tab_bar_items; ++i)
+    {
+#define TABPROP(IDX) AREF (f->tab_bar_items, \
+                           i * TAB_BAR_ITEM_NSLOTS + (IDX))
+
+      BOOL enabled_p = !NILP (TABPROP (TAB_BAR_ITEM_ENABLED_P));
+      int idx;
+      ptrdiff_t img_id;
+      struct image *img;
+      Lisp_Object image;
+      Lisp_Object helpObj;
+      const char *helpText;
+
+      /* Check if this is a separator.  */
+      if (EQ (TABPROP (TAB_BAR_ITEM_TYPE), Qt))
+        {
+          /* Skip separators.  Newer macOS don't show them, and on
+             GNUstep they are wide as a button, thus overflowing the
+             tabbar most of the time.  */
+          continue;
+        }
+
+      /* If image is a vector, choose the image according to the
+        button state.  */
+      image = TABPROP (TAB_BAR_ITEM_IMAGES);
+      if (VECTORP (image))
+       {
+          /* NS tabbar auto-computes disabled and selected images.  */
+          idx = TAB_BAR_IMAGE_ENABLED_SELECTED;
+         eassert (ASIZE (image) >= idx);
+         image = AREF (image, idx);
+       }
+      else
+        {
+          idx = -1;
+        }
+      helpObj = TABPROP (TAB_BAR_ITEM_HELP);
+      if (NILP (helpObj))
+        helpObj = TABPROP (TAB_BAR_ITEM_CAPTION);
+      helpText = NILP (helpObj) ? "" : SSDATA (helpObj);
+
+      /* Ignore invalid image specifications.  */
+      if (!valid_image_p (image))
+        {
+          /* Don't log anything, GNUS makes invalid images all the time.  */
+          continue;
+        }
+
+      img_id = lookup_image (f, image);
+      img = IMAGE_FROM_ID (f, img_id);
+      prepare_image_for_display (f, img);
+
+      if (img->load_failed_p || img->pixmap == nil)
+        {
+          NSLog (@"Could not prepare tabbar image for display.");
+          continue;
+        }
+
+      [tabbar addDisplayItemWithImage: img->pixmap
+                                   idx: k++
+                                   tag: i
+                              helpText: helpText
+                               enabled: enabled_p];
+#undef TABPROP
+    }
+
+  if (![tabbar isVisible])
+    {
+      f->output_data.ns->in_animation = 1;
+      [tabbar setVisible: YES];
+      f->output_data.ns->in_animation = 0;
+    }
+
+#ifdef NS_IMPL_COCOA
+  if ([tabbar changed])
+    {
+      /* Inform app that tabbar has changed.  */
+      NSDictionary *dict = [tabbar configurationDictionary];
+      NSMutableDictionary *newDict = [dict mutableCopy];
+      NSEnumerator *keys = [[dict allKeys] objectEnumerator];
+      id key;
+      while ((key = [keys nextObject]) != nil)
+        {
+          NSObject *val = [dict objectForKey: key];
+          if ([val isKindOfClass: [NSArray class]])
+            {
+              [newDict setObject:
+                         [tabbar tabbarDefaultItemIdentifiers: tabbar]
+                          forKey: key];
+              break;
+            }
+        }
+      [tabbar setConfigurationFromDictionary: newDict];
+      [newDict release];
+    }
+#endif
+
+  if (oldh != FRAME_TABBAR_HEIGHT (f))
+    [view updateFrameSize:YES];
+  if (view->wait_for_tab_bar && FRAME_TABBAR_HEIGHT (f) > 0)
+    {
+      view->wait_for_tab_bar = NO;
+      [view setNeedsDisplay: YES];
+    }
+
+  unblock_input ();
+}
+
+
+/* ==========================================================================
+
+    Tabbar: class implementation
+
+   ========================================================================== 
*/
+
+@implementation EmacsTabbar
+
+- (instancetype)initForView: (EmacsView *)view withIdentifier: (NSString 
*)identifier
+{
+  NSTRACE ("[EmacsTabbar initForView: withIdentifier:]");
+
+  self = [super initWithIdentifier: identifier];
+  emacsView = view;
+  [self setDisplayMode: NSTabbarDisplayModeIconOnly];
+  [self setSizeMode: NSTabbarSizeModeSmall];
+  [self setDelegate: self];
+  identifierToItem = [[NSMutableDictionary alloc] initWithCapacity: 10];
+  activeIdentifiers = [[NSMutableArray alloc] initWithCapacity: 8];
+  prevIdentifiers = nil;
+  prevEnablement = enablement = 0L;
+  return self;
+}
+
+- (void)dealloc
+{
+  NSTRACE ("[EmacsTabbar dealloc]");
+
+  [prevIdentifiers release];
+  [activeIdentifiers release];
+  [identifierToItem release];
+  [super dealloc];
+}
+
+- (void) clearActive
+{
+  NSTRACE ("[EmacsTabbar clearActive]");
+
+  [prevIdentifiers release];
+  prevIdentifiers = [activeIdentifiers copy];
+  [activeIdentifiers removeAllObjects];
+  prevEnablement = enablement;
+  enablement = 0L;
+}
+
+- (void) clearAll
+{
+  NSTRACE ("[EmacsTabbar clearAll]");
+
+  [self clearActive];
+  while ([[self items] count] > 0)
+    [self removeItemAtIndex: 0];
+}
+
+- (BOOL) changed
+{
+  NSTRACE ("[EmacsTabbar changed]");
+
+  return [activeIdentifiers isEqualToArray: prevIdentifiers] &&
+    enablement == prevEnablement ? NO : YES;
+}
+
+- (void) addDisplayItemWithImage: (EmacsImage *)img
+                             idx: (int)idx
+                             tag: (int)tag
+                        helpText: (const char *)help
+                         enabled: (BOOL)enabled
+{
+  NSTRACE ("[EmacsTabbar addDisplayItemWithImage: ...]");
+
+  /* 1) come up w/identifier */
+  NSString *identifier
+    = [NSString stringWithFormat: @"%lu", (unsigned long)[img hash]];
+  [activeIdentifiers addObject: identifier];
+
+  /* 2) create / reuse item */
+  NSTabbarItem *item = [identifierToItem objectForKey: identifier];
+  if (item == nil)
+    {
+      item = [[[NSTabbarItem alloc] initWithItemIdentifier: identifier]
+               autorelease];
+      [item setImage: img];
+      [item setTabTip: [NSString stringWithUTF8String: help]];
+      [item setTarget: emacsView];
+      [item setAction: @selector (tabbarClicked:)];
+      [identifierToItem setObject: item forKey: identifier];
+    }
+
+#ifdef NS_IMPL_GNUSTEP
+  [self insertItemWithItemIdentifier: identifier atIndex: idx];
+#endif
+
+  [item setTag: tag];
+  [item setEnabled: enabled];
+
+  /* 3) update state */
+  enablement = (enablement << 1) | (enabled == YES);
+}
+
+/* This overrides super's implementation, which automatically sets
+   all items to enabled state (for some reason).  */
+- (void)validateVisibleItems
+{
+  NSTRACE ("[EmacsTabbar validateVisibleItems]");
+}
+
+
+/* delegate methods */
+
+- (NSTabbarItem *)tabbar: (NSTabbar *)tabbar
+      itemForItemIdentifier: (NSString *)itemIdentifier
+  willBeInsertedIntoTabbar: (BOOL)flag
+{
+  NSTRACE ("[EmacsTabbar tabbar: ...]");
+
+  /* Look up NSTabbarItem by identifier and return...  */
+  return [identifierToItem objectForKey: itemIdentifier];
+}
+
+- (NSArray *)tabbarDefaultItemIdentifiers: (NSTabbar *)tabbar
+{
+  NSTRACE ("[EmacsTabbar tabbarDefaultItemIdentifiers:]");
+
+  /* Return entire set.  */
+  return activeIdentifiers;
+}
+
+/* for configuration palette (not yet supported) */
+- (NSArray *)tabbarAllowedItemIdentifiers: (NSTabbar *)tabbar
+{
+  NSTRACE ("[EmacsTabbar tabbarAllowedItemIdentifiers:]");
+
+  /* return entire set...  */
+  return activeIdentifiers;
+  //return [identifierToItem allKeys];
+}
+
+- (void)setVisible:(BOOL)shown
+{
+  NSTRACE ("[EmacsTabbar setVisible:%d]", shown);
+
+  [super setVisible:shown];
+}
+
+
+/* optional and unneeded */
+/* - tabbarWillAddItem: (NSNotification *)notification { } */
+/* - tabbarDidRemoveItem: (NSNotification *)notification { } */
+/* - (NSArray *)tabbarSelectableItemIdentifiers: (NSTabbar *)tabbar */
+
+@end  /* EmacsTabbar */
+
+
+
+/* ==========================================================================
+
     Toolbar: externally-called functions
 
    ========================================================================== 
*/
diff --git a/src/nsterm.h b/src/nsterm.h
index 9773eb3..ea0e5a4 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -397,6 +397,7 @@ typedef id instancetype;
 
    ========================================================================== 
*/
 
+@class EmacsTabbar;
 @class EmacsToolbar;
 
 #ifdef NS_IMPL_COCOA
@@ -421,14 +422,18 @@ typedef id instancetype;
    struct frame *emacsframe;
    int rows, cols;
    int scrollbarsNeedingUpdate;
+   EmacsTabbar *tabbar;
    EmacsToolbar *toolbar;
    NSRect ns_userRect;
+   BOOL wait_for_tab_bar;
    BOOL wait_for_tool_bar;
    }
 
 /* AppKit-side interface */
 - (instancetype)menuDown: (id)sender;
+- (instancetype)tabbarClicked: (id)item;
 - (instancetype)toolbarClicked: (id)item;
+- (instancetype)toggleTabbar: (id)sender;
 - (instancetype)toggleToolbar: (id)sender;
 - (void)keyDown: (NSEvent *)theEvent;
 - (void)mouseDown: (NSEvent *)theEvent;
@@ -437,9 +442,11 @@ typedef id instancetype;
 
 /* Emacs-side interface */
 - (instancetype) initFrameFromEmacs: (struct frame *) f;
+- (void) createTabbar: (struct frame *)f;
 - (void) createToolbar: (struct frame *)f;
 - (void) setRows: (int) r andColumns: (int) c;
 - (void) setWindowClosing: (BOOL)closing;
+- (EmacsTabbar *) tabbar;
 - (EmacsToolbar *) toolbar;
 - (void) deleteWorkingText;
 - (void) updateFrameSize: (BOOL) delay;
@@ -512,6 +519,45 @@ typedef id instancetype;
 
 /* ==========================================================================
 
+   Tabbar
+
+   ========================================================================== 
*/
+
+@class EmacsImage;
+
+#ifdef NS_IMPL_COCOA
+@interface EmacsTabbar : NSTabbar <NSTabbarDelegate>
+#else
+@interface EmacsTabbar : NSTabbar
+#endif
+   {
+     EmacsView *emacsView;
+     NSMutableDictionary *identifierToItem;
+     NSMutableArray *activeIdentifiers;
+     NSArray *prevIdentifiers;
+     unsigned long enablement, prevEnablement;
+   }
+- (instancetype) initForView: (EmacsView *)view withIdentifier: (NSString 
*)identifier;
+- (void) clearActive;
+- (void) clearAll;
+- (BOOL) changed;
+- (void) addDisplayItemWithImage: (EmacsImage *)img
+                             idx: (int)idx
+                             tag: (int)tag
+                        helpText: (const char *)help
+                         enabled: (BOOL)enabled;
+
+/* delegate methods */
+- (NSTabbarItem *)tabbar: (NSTabbar *)tabbar
+     itemForItemIdentifier: (NSString *)itemIdentifier
+ willBeInsertedIntoTabbar: (BOOL)flag;
+- (NSArray *)tabbarDefaultItemIdentifiers: (NSTabbar *)tabbar;
+- (NSArray *)tabbarAllowedItemIdentifiers: (NSTabbar *)tabbar;
+@end
+
+
+/* ==========================================================================
+
    Toolbar
 
    ========================================================================== 
*/
@@ -753,6 +799,7 @@ extern EmacsMenu *svcsMenu;
 #define KEY_NS_NEW_FRAME               ((1<<28)|(0<<16)|12)
 #define KEY_NS_TOGGLE_TOOLBAR          ((1<<28)|(0<<16)|13)
 #define KEY_NS_SHOW_PREFS              ((1<<28)|(0<<16)|14)
+#define KEY_NS_TOGGLE_TABBAR           ((1<<28)|(0<<16)|15)
 
 /* Could use list to store these, but rest of emacs has a big infrastructure
    for managing a table of bitmap "records".  */
@@ -923,6 +970,7 @@ struct ns_output
   NSColor *cursor_color;
   NSColor *foreground_color;
   NSColor *background_color;
+  EmacsTabbar *tabbar;
   EmacsToolbar *toolbar;
 #else
   void *view;
@@ -930,6 +978,7 @@ struct ns_output
   void *cursor_color;
   void *foreground_color;
   void *background_color;
+  void *tabbar;
   void *toolbar;
 #endif
 
@@ -974,6 +1023,9 @@ struct ns_output
   /* The height of the titlebar decoration (included in NSWindow's frame).  */
   int titlebar_height;
 
+  /* The height of the tabbar if displayed, else 0.  */
+  int tabbar_height;
+
   /* The height of the toolbar if displayed, else 0.  */
   int toolbar_height;
 
@@ -1029,6 +1081,16 @@ struct x_output
                        [[FRAME_NS_VIEW (f) window] frame]               \
                        styleMask:[[FRAME_NS_VIEW (f) window] styleMask]])))
 
+/* Compute pixel height of the tabbar.  */
+#define FRAME_TABBAR_HEIGHT(f)                                          \
+  (([[FRAME_NS_VIEW (f) window] tabbar] == nil                         \
+    || ! [[FRAME_NS_VIEW (f) window] tabbar].isVisible) ?              \
+   0                                                                    \
+   : (int)(NSHeight([NSWindow contentRectForFrameRect:                  \
+                     [[FRAME_NS_VIEW (f) window] frame]                 \
+                     styleMask:[[FRAME_NS_VIEW (f) window] styleMask]]) \
+           - NSHeight([[[FRAME_NS_VIEW (f) window] contentView] frame])))
+
 /* Compute pixel height of the toolbar.  */
 #define FRAME_TOOLBAR_HEIGHT(f)                                         \
   (([[FRAME_NS_VIEW (f) window] toolbar] == nil                         \
@@ -1169,6 +1231,8 @@ extern const char *ns_get_defaults_value (const char 
*key);
 extern void ns_init_locale (void);
 
 /* in nsmenu */
+extern void update_frame_tab_bar (struct frame *f);
+extern void free_frame_tab_bar (struct frame *f);
 extern void update_frame_tool_bar (struct frame *f);
 extern void free_frame_tool_bar (struct frame *f);
 extern Lisp_Object find_and_return_menu_selection (struct frame *f,
@@ -1276,6 +1340,7 @@ extern char gnustep_base_version[];  /* version tracking 
*/
 #define NSWindowCollectionBehaviorFullScreenPrimary (1 << 7)
 #define NSApplicationPresentationFullScreen         (1 << 10)
 #define NSApplicationPresentationAutoHideToolbar    (1 << 11)
+#define NSApplicationPresentationAutoHideTabbar     (1 << 12)
 #define NSAppKitVersionNumber10_7                   1138
 #endif /* !defined (MAC_OS_X_VERSION_10_7) */
 
diff --git a/src/nsterm.m b/src/nsterm.m
index c8094d0..321cdc4 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -1088,11 +1088,15 @@ ns_update_begin (struct frame *f)
 
   if ([view isFullscreen] && [view fsIsNative])
   {
-    // Fix reappearing tool bar in fullscreen for Mac OS X 10.7
-    BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
+    // Fix reappearing tool bar or tab bar in fullscreen for Mac OS X 10.7
+    BOOL tarbar_visible = FRAME_EXTERNAL_TAB_BAR (f) ? YES : NO;
+    NSTabbar *tabbar = [FRAME_NS_VIEW (f) tabbar];
+    if (! tarbar_visible != ! [tabbar isVisible])
+      [tabbar setVisible: tarbar_visible];
+    BOOL toolbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
     NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
-    if (! tbar_visible != ! [toolbar isVisible])
-      [toolbar setVisible: tbar_visible];
+    if (! toolbar_visible != ! [toolbar isVisible])
+      [toolbar setVisible: toolbar_visible];
   }
 #endif
 }
@@ -1683,7 +1687,7 @@ ns_set_offset (struct frame *f, int xoff, int yoff, int 
change_grav)
           f->top_pos = f->size_hint_flags & YNegative
             ? ([screen visibleFrame].size.height + f->top_pos
                - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
-               - FRAME_TOOLBAR_HEIGHT (f))
+               - FRAME_TABBAR_HEIGHT (f) - FRAME_TOOLBAR_HEIGHT (f))
             : f->top_pos;
 #ifdef NS_IMPL_GNUSTEP
          if (f->left_pos < 100)
@@ -1701,7 +1705,7 @@ ns_set_offset (struct frame *f, int xoff, int yoff, int 
change_grav)
             f->left_pos = FRAME_PIXEL_WIDTH (parent) - FRAME_PIXEL_WIDTH (f) + 
f->left_pos;
 
           if (f->top_pos < 0)
-            f->top_pos = FRAME_PIXEL_HEIGHT (parent) + FRAME_TOOLBAR_HEIGHT 
(parent)
+            f->top_pos = FRAME_PIXEL_HEIGHT (parent) + FRAME_TABBAR_HEIGHT 
(parent) + FRAME_TOOLBAR_HEIGHT (parent)
               - FRAME_PIXEL_HEIGHT (f) + f->top_pos;
         }
 
@@ -1764,6 +1768,7 @@ ns_set_window_size (struct frame *f,
   wr.size.height = pixelheight;
   if (! [view isFullscreen])
     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
+      + FRAME_TABBAR_HEIGHT (f)
       + FRAME_TOOLBAR_HEIGHT (f);
 
   /* Do not try to constrain to this screen.  We may have multiple
@@ -1780,7 +1785,7 @@ ns_set_window_size (struct frame *f,
           Fcons (make_fixnum (wr.size.width), make_fixnum (wr.size.height)),
           make_fixnum (f->border_width),
           make_fixnum (FRAME_NS_TITLEBAR_HEIGHT (f)),
-          make_fixnum (FRAME_TOOLBAR_HEIGHT (f))));
+          make_fixnum (FRAME_TABBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f))));
 
   [window setFrame: wr display: YES];
 
@@ -1817,10 +1822,12 @@ ns_set_undecorated (struct frame *f, Lisp_Object 
new_value, Lisp_Object old_valu
           [window setStyleMask: ((window.styleMask | FRAME_DECORATED_FLAGS)
                                   ^ FRAME_UNDECORATED_FLAGS)];
 
+          [view createTabbar: f];
           [view createToolbar: f];
         }
       else
         {
+          [window setTabbar: nil];
           [window setToolbar: nil];
           /* Do I need to release the toolbar here?  */
 
@@ -2405,7 +2412,7 @@ frame_set_mouse_pixel_position (struct frame *f, int 
pix_x, int pix_y)
   CGPoint mouse_pos =
     CGPointMake(f->left_pos + pix_x,
                 f->top_pos + pix_y +
-                FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f));
+                FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TABBAR_HEIGHT(f) + 
FRAME_TOOLBAR_HEIGHT(f));
   CGWarpMouseCursorPosition (mouse_pos);
 #endif
 }
@@ -6100,6 +6107,7 @@ not_in_argv (NSString *arg)
 - (void)dealloc
 {
   NSTRACE ("[EmacsView dealloc]");
+  [tabbar release];
   [toolbar release];
   if (fs_state == FULLSCREEN_BOTH)
     [nonfs_window release];
@@ -6951,19 +6959,40 @@ not_in_argv (NSString *arg)
 
   if (! [self isFullscreen])
     {
+      int tabbar_height;
       int toolbar_height;
 #ifdef NS_IMPL_GNUSTEP
       // GNUstep does not always update the tool bar height.  Force it.
       if (toolbar && [toolbar isVisible])
           update_frame_tool_bar (emacsframe);
+      if (tabbar && [tabbar isVisible])
+          update_frame_tab_bar (emacsframe);
 #endif
 
+      tabbar_height = FRAME_TABBAR_HEIGHT (emacsframe);
+      if (tabbar_height < 0)
+        tabbar_height = 35;
+
       toolbar_height = FRAME_TOOLBAR_HEIGHT (emacsframe);
       if (toolbar_height < 0)
         toolbar_height = 35;
 
       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
-        + toolbar_height;
+        + tabbar_height + toolbar_height;
+    }
+
+  if (wait_for_tab_bar)
+    {
+      /* The tabbar height is always 0 in fullscreen and undecorated
+         frames, so don't wait for it to become available.  */
+      if (FRAME_TABBAR_HEIGHT (emacsframe) == 0
+          && FRAME_UNDECORATED (emacsframe) == false
+          && ! [self isFullscreen])
+        {
+          NSTRACE_MSG ("Waiting for tabbar");
+          return;
+        }
+      wait_for_tab_bar = NO;
     }
 
   if (wait_for_tool_bar)
@@ -6984,6 +7013,7 @@ not_in_argv (NSString *arg)
   newh = (int)wr.size.height - extra;
 
   NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
+  NSTRACE_MSG ("FRAME_TABBAR_HEIGHT: %d", FRAME_TABBAR_HEIGHT (emacsframe));
   NSTRACE_MSG ("FRAME_TOOLBAR_HEIGHT: %d", FRAME_TOOLBAR_HEIGHT (emacsframe));
   NSTRACE_MSG ("FRAME_NS_TITLEBAR_HEIGHT: %d", FRAME_NS_TITLEBAR_HEIGHT 
(emacsframe));
 
@@ -7058,6 +7088,7 @@ not_in_argv (NSString *arg)
   if (! [self isFullscreen])
     {
       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
+        + FRAME_TABBAR_HEIGHT (emacsframe)
         + FRAME_TOOLBAR_HEIGHT (emacsframe);
     }
 
@@ -7284,6 +7315,34 @@ not_in_argv (NSString *arg)
 }
 
 
+- (void)createTabbar: (struct frame *)f
+{
+  EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
+  NSWindow *window = [view window];
+
+  tabbar = [[EmacsTabbar alloc] initForView: self withIdentifier:
+                   [NSString stringWithFormat: @"Emacs Frame %d",
+                             ns_window_num]];
+  [tabbar setVisible: NO];
+  [window setTabbar: tabbar];
+
+  /* Don't set frame garbaged until tab bar is up to date?
+     This avoids an extra clear and redraw (flicker) at frame creation.  */
+  if (FRAME_EXTERNAL_TAB_BAR (f)) wait_for_tab_bar = YES;
+  else wait_for_tab_bar = NO;
+
+
+#ifdef NS_IMPL_COCOA
+  {
+    NSButton *toggleButton;
+    toggleButton = [window standardWindowButton: NSWindowTabbarButton];
+    [toggleButton setTarget: self];
+    [toggleButton setAction: @selector (toggleTabbar: )];
+  }
+#endif
+}
+
+
 - (void)createToolbar: (struct frame *)f
 {
   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
@@ -7390,6 +7449,10 @@ not_in_argv (NSString *arg)
                    NILP (tem) ? "Emacs" : SSDATA (tem)];
   [win setTitle: name];
 
+  /* tabbar support */
+  if (! FRAME_UNDECORATED (f))
+    [self createTabbar: f];
+
   /* toolbar support */
   if (! FRAME_UNDECORATED (f))
     [self createToolbar: f];
@@ -7693,7 +7756,7 @@ not_in_argv (NSString *arg)
       willUseFullScreenPresentationOptions:
   (NSApplicationPresentationOptions)proposedOptions
 {
-  return proposedOptions|NSApplicationPresentationAutoHideToolbar;
+  return 
proposedOptions|NSApplicationPresentationAutoHideTabbar|NSApplicationPresentationAutoHideToolbar;
 }
 #endif
 
@@ -7725,7 +7788,8 @@ not_in_argv (NSString *arg)
     }
   else
     {
-      BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
+      BOOL tarbar_visible = FRAME_EXTERNAL_TAB_BAR (emacsframe) ? YES : NO;
+      BOOL toolbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 \
   && MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
       unsigned val = (unsigned)[NSApp presentationOptions];
@@ -7738,12 +7802,14 @@ not_in_argv (NSString *arg)
             = NSApplicationPresentationAutoHideDock
             | NSApplicationPresentationAutoHideMenuBar
             | NSApplicationPresentationFullScreen
+            | NSApplicationPresentationAutoHideTabbar
             | NSApplicationPresentationAutoHideToolbar;
 
           [NSApp setPresentationOptions: options];
         }
 #endif
-      [toolbar setVisible:tbar_visible];
+      [tabbar setVisible:tarbar_visible];
+      [toolbar setVisible:toolbar_visible];
     }
 }
 
@@ -7784,6 +7850,16 @@ not_in_argv (NSString *arg)
 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
   [self updateCollectionBehavior];
 #endif
+  if (FRAME_EXTERNAL_TAB_BAR (emacsframe))
+    {
+      [tabbar setVisible:YES];
+      update_frame_tab_bar (emacsframe);
+      [self updateFrameSize:YES];
+      [[self window] display];
+    }
+  else
+    [tabbar setVisible:NO];
+
   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
     {
       [toolbar setVisible:YES];
@@ -8097,6 +8173,53 @@ not_in_argv (NSString *arg)
 }
 
 
+- (EmacsTabbar *)tabbar
+{
+  return tabbar;
+}
+
+
+/* This gets called on tabbar button click.  */
+- (instancetype)tabbarClicked: (id)item
+{
+  NSEvent *theEvent;
+  int idx = [item tag] * TAB_BAR_ITEM_NSLOTS;
+
+  NSTRACE ("[EmacsView tabbarClicked:]");
+
+  if (!emacs_event)
+    return self;
+
+  /* Send first event (for some reason two needed).  */
+  theEvent = [[self window] currentEvent];
+  emacs_event->kind = TAB_BAR_EVENT;
+  XSETFRAME (emacs_event->arg, emacsframe);
+  EV_TRAILER (theEvent);
+
+  emacs_event->kind = TAB_BAR_EVENT;
+  /* XSETINT (emacs_event->code, 0); */
+  emacs_event->arg = AREF (emacsframe->tab_bar_items,
+                          idx + TAB_BAR_ITEM_KEY);
+  emacs_event->modifiers = EV_MODIFIERS (theEvent);
+  EV_TRAILER (theEvent);
+  return self;
+}
+
+
+- (instancetype)toggleTabbar: (id)sender
+{
+  NSTRACE ("[EmacsView toggleTabbar:]");
+
+  if (!emacs_event)
+    return self;
+
+  emacs_event->kind = NS_NONKEY_EVENT;
+  emacs_event->code = KEY_NS_TOGGLE_TABBAR;
+  EV_TRAILER ((id)nil);
+  return self;
+}
+
+
 - (EmacsToolbar *)toolbar
 {
   return toolbar;



reply via email to

[Prev in Thread] Current Thread [Next in Thread]