(defface tab-bar
'((default
:box (:line-width 1 :style released-button)
- :foreground "black")
+ :foreground "black"
+ :background "white")
(((type x w32 ns) (class color))
:background "grey75")
(((type x) (class mono))
(global-set-key [(control shift iso-lefttab)] 'tab-bar-switch-to-prev-tab)
(global-set-key [(control tab)] 'tab-bar-switch-to-next-tab)))
-;;;###autoload
+(defun tab-bar-mouse (event)
+ "Text-mode emulation of switching tabs on the tab-bar.
+This command is used when you click the mouse in the tab-bar
+on a console which has no window system but does have a mouse."
+ (interactive "e")
+ (let* ((x-position (car (posn-x-y (event-start event))))
+ (keymap (lookup-key (cons 'keymap (nreverse (current-active-maps))) [tab-bar]))
+ (column 0))
+ (when x-position
+ (unless (catch 'done
+ (map-keymap
+ (lambda (_key binding)
+ (when (eq (car-safe binding) 'menu-item)
+ (when (> (+ column (length (nth 1 binding))) x-position)
+ (call-interactively (nth 2 binding))
+ (throw 'done t))
+ (setq column (+ column (length (nth 1 binding)) 1))))
+ keymap))
+ ;; Clicking anywhere outside existing tabs will add a new tab
+ (tab-bar-add-tab)))))
+
;; Used in the Show/Hide menu, to have the toggle reflect the current frame.
(defun toggle-tab-bar-mode-from-frame (&optional arg)
"Toggle tab bar on or off, based on the status of the current frame.
"Generate an actual keymap from `tab-bar-map', without caching."
(let ((i 0))
(append
- '(keymap)
+ '(keymap (mouse-1 . tab-bar-mouse))
(mapcan
(lambda (tab)
(setq i (1+ i))
0, 1, 0, 0);
}
}
+
+static void
+set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
+{
+ int nlines;
+ int olines = FRAME_TAB_BAR_LINES (f);
+
+ /* Right now, tab bars don't work properly in minibuf-only frames;
+ most of the commands try to apply themselves to the minibuffer
+ frame itself, and get an error because you can't switch buffers
+ in or split the minibuffer window. */
+ if (FRAME_MINIBUF_ONLY_P (f))
+ return;
+
+ if (TYPE_RANGED_FIXNUMP (int, value))
+ nlines = XFIXNUM (value);
+ else
+ nlines = 0;
+
+ if (nlines != olines)
+ {
+ windows_or_buffers_changed = 14;
+ FRAME_TAB_BAR_LINES (f) = nlines;
+ FRAME_TAB_BAR_HEIGHT (f) = nlines * FRAME_LINE_HEIGHT (f);
+ change_frame_size (f, FRAME_COLS (f),
+ FRAME_LINES (f) + olines - nlines,
+ 0, 1, 0, 0);
+ }
+}
\f
Lisp_Object Vframe_list;
if ((FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f)) && NILP (horizontal))
{
int min_height = (FRAME_MENU_BAR_LINES (f)
+ + FRAME_TAB_BAR_LINES (f)
+ FRAME_WANTS_MODELINE_P (f)
+ 2); /* one text line and one echo-area line */
if (retval < min_height)
/* The default value of menu-bar-mode is t. */
set_menu_bar_lines (f, make_fixnum (1), Qnil);
+ /* The default value of tab-bar-mode is nil. */
+ set_tab_bar_lines (f, make_fixnum (0), Qnil);
+
/* Allocate glyph matrices. */
adjust_frame_glyphs (f);
{
if (EQ (prop, Qmenu_bar_lines))
set_menu_bar_lines (f, val, make_fixnum (FRAME_MENU_BAR_LINES (f)));
+ else if (EQ (prop, Qtab_bar_lines))
+ set_tab_bar_lines (f, val, make_fixnum (FRAME_TAB_BAR_LINES (f)));
else if (EQ (prop, Qname))
set_term_frame_name (f, val);
}
Lisp_Object lines;
XSETFASTINT (lines, FRAME_MENU_BAR_LINES (f));
store_in_alist (&alist, Qmenu_bar_lines, lines);
+ XSETFASTINT (lines, FRAME_TAB_BAR_LINES (f));
+ store_in_alist (&alist, Qtab_bar_lines, lines);
}
return alist;
#ifdef HAVE_WINDOW_SYSTEM
+static void display_tab_bar (struct window *);
static void update_tab_bar (struct frame *, bool);
static void update_tool_bar (struct frame *, bool);
static void gui_draw_bottom_divider (struct window *w);
static void
update_tab_bar (struct frame *f, bool save_match_data)
{
- bool do_update = (WINDOWP (f->tab_bar_window)
- && WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window)) > 0);
+ bool do_update = ((FRAME_WINDOW_P (f) && WINDOWP (f->tab_bar_window))
+ ? (WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window)) > 0)
+ : (FRAME_TAB_BAR_LINES (f) > 0));
if (do_update)
{
return false;
}
+/* Redisplay the tab bar in the frame for window W.
+
+ The tab bar of X frames that don't have X toolkit support is
+ displayed in a special window W->frame->tab_bar_window.
+
+ The tab bar of terminal frames is treated specially as far as
+ glyph matrices are concerned. Tab bar lines are not part of
+ windows, so the update is done directly on the frame matrix rows
+ for the tab bar. */
+
+static void
+display_tab_bar (struct window *w)
+{
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+ struct it it;
+ Lisp_Object items;
+ int i;
+ bool has_menu_p = FRAME_MENU_BAR_LINES (f) > 0;
+
+ /* Don't do all this for graphical frames. */
+#ifdef HAVE_NTGUI
+ if (FRAME_W32_P (f))
+ return;
+#endif
+#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
+ if (FRAME_X_P (f))
+ return;
+#endif
+
+#ifdef HAVE_NS
+ if (FRAME_NS_P (f))
+ return;
+#endif /* HAVE_NS */
+
+#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
+ eassert (!FRAME_WINDOW_P (f));
+ init_iterator (&it, w, -1, -1, f->desired_matrix->rows + (has_menu_p ? 1 : 0), TAB_BAR_FACE_ID);
+ it.first_visible_x = 0;
+ it.last_visible_x = FRAME_PIXEL_WIDTH (f);
+#elif defined (HAVE_X_WINDOWS) /* X without toolkit. */
+ if (FRAME_WINDOW_P (f))
+ {
+ /* Tab bar lines are displayed in the desired matrix of the
+ dummy window tab_bar_window. */
+ struct window *tab_w;
+ tab_w = XWINDOW (f->tab_bar_window);
+ init_iterator (&it, tab_w, -1, -1, tab_w->desired_matrix->rows + (has_menu_p ? 1 : 0),
+ TAB_BAR_FACE_ID);
+ it.first_visible_x = 0;
+ it.last_visible_x = FRAME_PIXEL_WIDTH (f);
+ }
+ else
+#endif /* not USE_X_TOOLKIT and not USE_GTK */
+ {
+ /* This is a TTY frame, i.e. character hpos/vpos are used as
+ pixel x/y. */
+ init_iterator (&it, w, -1, -1, f->desired_matrix->rows + (has_menu_p ? 1 : 0),
+ TAB_BAR_FACE_ID);
+ it.first_visible_x = 0;
+ it.last_visible_x = FRAME_COLS (f);
+ }
+
+ /* FIXME: This should be controlled by a user option. See the
+ comments in redisplay_tool_bar and display_mode_line about
+ this. */
+ it.paragraph_embedding = L2R;
+
+ /* Clear all rows of the tab bar. */
+ for (i = 0; i < FRAME_TAB_BAR_LINES (f); ++i)
+ {
+ struct glyph_row *row = it.glyph_row + i;
+ clear_glyph_row (row);
+ row->enabled_p = true;
+ row->full_width_p = true;
+ row->reversed_p = false;
+ }
+
+ /* Display all items of the tab bar. */
+ items = it.f->tab_bar_items;
+ for (i = 0; i < ASIZE (items); i += 11)
+ {
+ Lisp_Object string;
+
+ /* Stop at nil string. */
+ string = AREF (items, i + 3);
+ if (NILP (string))
+ break;
+
+ /* string = build_string ("Test 4"); */
+
+ /* Display the item, pad with one space. */
+ if (it.current_x < it.last_visible_x)
+ display_string (NULL, string, Qnil, 0, 0, &it,
+ SCHARS (string) + 1, 0, 0, -1);
+ }
+
+ /* Fill out the line with spaces. */
+ if (it.current_x < it.last_visible_x)
+ display_string ("", Qnil, Qnil, 0, 0, &it, -1, 0, 0, -1);
+
+ /* Compute the total height of the lines. */
+ compute_line_metrics (&it);
+}
+
/* Get information about the tab-bar item which is displayed in GLYPH
on frame F. Return in *PROP_IDX the index where tab-bar item
properties start in F->tab_bar_items. Value is false if
ignore_mouse_drag_p = true;
#endif
}
+ else
+ {
+ if ((FRAME_TAB_BAR_LINES (f) > 0))
+ display_tab_bar (w);
+ }
+
gui_consider_frame_title (w->frame);
#endif
}