Merge branch 'feature/tabs'
This commit is contained in:
commit
2698d3dba2
53 changed files with 3871 additions and 187 deletions
|
@ -2150,6 +2150,10 @@ The mouse was in a vertical scroll bar. (This is the only kind of
|
|||
scroll bar Emacs currently supports.)
|
||||
@item menu-bar
|
||||
The mouse was in the menu bar.
|
||||
@item tab-bar
|
||||
The mouse was in a tab bar.
|
||||
@item tab-line
|
||||
The mouse was in a tab line.
|
||||
@item header-line
|
||||
The mouse was in a header line.
|
||||
@ignore
|
||||
|
|
|
@ -722,6 +722,10 @@ Similar to @code{highlight} and @code{mode-line-highlight}, but used
|
|||
for mouse-sensitive portions of text on header lines. This is a
|
||||
separate face because the @code{header-line} face might be customized
|
||||
in a way that does not interact well with @code{highlight}.
|
||||
@item tab-line
|
||||
@cindex @code{tab-line} face
|
||||
Similar to @code{mode-line} for a window's tab line, which appears
|
||||
at the top of a window with tabs representing window buffers.
|
||||
@item vertical-border
|
||||
@cindex @code{vertical-border} face
|
||||
This face is used for the vertical divider between windows on text
|
||||
|
@ -763,6 +767,8 @@ This face determines the visual appearance of the scroll bar.
|
|||
@xref{Scroll Bars}.
|
||||
@item tool-bar
|
||||
This face determines the color of tool bar icons. @xref{Tool Bars}.
|
||||
@item tab-bar
|
||||
This face determines the color of tab bar icons. @xref{Tab Bars}.
|
||||
@item menu
|
||||
@cindex menu bar appearance
|
||||
@cindex @code{menu} face, no effect if customized
|
||||
|
|
|
@ -540,6 +540,7 @@ Frames and Graphical Displays
|
|||
* Drag and Drop:: Using drag and drop to open files and insert text.
|
||||
* Menu Bars:: Enabling and disabling the menu bar.
|
||||
* Tool Bars:: Enabling and disabling the tool bar.
|
||||
* Tab Bars:: Enabling and disabling the tab bar.
|
||||
* Dialog Boxes:: Controlling use of dialog boxes.
|
||||
* Tooltips:: Displaying information at the current mouse position.
|
||||
* Mouse Avoidance:: Preventing the mouse pointer from obscuring text.
|
||||
|
|
|
@ -58,6 +58,7 @@ for doing so on MS-DOS). Menus are supported on all text terminals.
|
|||
* Drag and Drop:: Using drag and drop to open files and insert text.
|
||||
* Menu Bars:: Enabling and disabling the menu bar.
|
||||
* Tool Bars:: Enabling and disabling the tool bar.
|
||||
* Tab Bars:: Enabling and disabling the tab bar.
|
||||
* Dialog Boxes:: Controlling use of dialog boxes.
|
||||
* Tooltips:: Displaying information at the current mouse position.
|
||||
* Mouse Avoidance:: Preventing the mouse pointer from obscuring text.
|
||||
|
@ -1214,6 +1215,41 @@ Parameters,,, elisp, The Emacs Lisp Reference Manual}. On macOS the
|
|||
tool bar is hidden when the frame is put into fullscreen, but can be
|
||||
displayed by moving the mouse pointer to the top of the screen.
|
||||
|
||||
@node Tab Bars
|
||||
@section Tab Bars
|
||||
@cindex Tab Bar mode
|
||||
@cindex mode, Tab Bar
|
||||
@cindex tabs, tabbar
|
||||
|
||||
On graphical displays and on text terminals, Emacs puts a @dfn{tab bar}
|
||||
at the top of each frame, just below the menu bar. This is a row of
|
||||
tabs which you can click on with the mouse to switch window configurations.
|
||||
|
||||
Each tab on the tab bar represents a named persistent window
|
||||
configuration. Its name is composed from the names of buffers
|
||||
visible in windows of the window configuration. Clicking on the
|
||||
tab name switches the current window configuration to the previously
|
||||
used configuration of windows and buffers.
|
||||
|
||||
If you are using the desktop library to save and restore your
|
||||
sessions, the tabs from the tab bar are recorded in the desktop file,
|
||||
together with their associated window configurations.
|
||||
|
||||
@findex tab-bar-mode
|
||||
@vindex tab-bar-mode
|
||||
To toggle the use of tab bars, type @kbd{M-x tab-bar-mode}. This
|
||||
command applies to all frames, including frames yet to be created. To
|
||||
control the use of tab bars at startup, customize the variable
|
||||
@code{tab-bar-mode}.
|
||||
|
||||
@vindex tab-bar-new-tab-choice
|
||||
@cindex Tab Bar new tab
|
||||
By default, Emacs follows the same behavior as when creating frames,
|
||||
to start a new tab with the current buffer, i.e. the buffer
|
||||
that was current before calling the command that adds a new tab.
|
||||
To start a new tab with other buffers, customize the variable
|
||||
@code{tab-bar-new-tab-choice}.
|
||||
|
||||
@node Dialog Boxes
|
||||
@section Using Dialog Boxes
|
||||
@cindex dialog boxes
|
||||
|
|
|
@ -1360,6 +1360,15 @@ your buffers, unsaved edits, undo history, etc. @xref{Exiting}.
|
|||
@key{TAB} is the tab character. In Emacs it is typically used for
|
||||
indentation or completion.
|
||||
|
||||
@item Tab Bar
|
||||
The tab bar is a row of tabs at the top of an Emacs frame.
|
||||
Clicking on one of these tabs switches named persistent window
|
||||
configurations. @xref{Tab Bars}.
|
||||
|
||||
@item Tab Line
|
||||
The tab line is a line of tabs at the top of an Emacs window.
|
||||
Clicking on one of these tabs switches window buffers.
|
||||
|
||||
@anchor{Glossary---Tags Table}
|
||||
@item Tags Table
|
||||
A tags table is a file that serves as an index to the function
|
||||
|
|
|
@ -295,6 +295,12 @@ Tool Bar mode gives each frame a tool bar. It is enabled by default,
|
|||
but the tool bar is only displayed on graphical terminals. @xref{Tool
|
||||
Bars}.
|
||||
|
||||
@item
|
||||
Tab Bar mode gives each frame a tab bar. @xref{Tab Bars}.
|
||||
|
||||
@item
|
||||
Tab Line mode gives each window a tab line.
|
||||
|
||||
@item
|
||||
Transient Mark mode highlights the region, and makes many Emacs
|
||||
commands operate on the region when the mark is active. It is enabled
|
||||
|
|
|
@ -1348,8 +1348,8 @@ button. @xref{Repeat Events}.
|
|||
@var{position} slot of a click event, you should typically use the
|
||||
functions documented in @ref{Accessing Mouse}. The explicit format of
|
||||
the list depends on where the click occurred. For clicks in the text
|
||||
area, mode line, header line, or in the fringe or marginal areas, the
|
||||
mouse position list has the form
|
||||
area, mode line, header line, tab line, or in the fringe or marginal
|
||||
areas, the mouse position list has the form
|
||||
|
||||
@example
|
||||
(@var{window} @var{pos-or-area} (@var{x} . @var{y}) @var{timestamp}
|
||||
|
@ -1368,8 +1368,9 @@ The window in which the click occurred.
|
|||
The buffer position of the character clicked on in the text area; or,
|
||||
if the click was outside the text area, the window area where it
|
||||
occurred. It is one of the symbols @code{mode-line},
|
||||
@code{header-line}, @code{vertical-line}, @code{left-margin},
|
||||
@code{right-margin}, @code{left-fringe}, or @code{right-fringe}.
|
||||
@code{header-line}, @code{tab-line}, @code{vertical-line},
|
||||
@code{left-margin}, @code{right-margin}, @code{left-fringe}, or
|
||||
@code{right-fringe}.
|
||||
|
||||
In one special case, @var{pos-or-area} is a list containing a symbol
|
||||
(one of the symbols listed above) instead of just the symbol. This
|
||||
|
@ -1380,12 +1381,12 @@ by Emacs. @xref{Key Sequence Input}.
|
|||
The relative pixel coordinates of the click. For clicks in the text
|
||||
area of a window, the coordinate origin @code{(0 . 0)} is taken to be
|
||||
the top left corner of the text area. @xref{Window Sizes}. For
|
||||
clicks in a mode line or header line, the coordinate origin is the top
|
||||
left corner of the window itself. For fringes, margins, and the
|
||||
vertical border, @var{x} does not have meaningful data. For fringes
|
||||
and margins, @var{y} is relative to the bottom edge of the header
|
||||
line. In all cases, the @var{x} and @var{y} coordinates increase
|
||||
rightward and downward respectively.
|
||||
clicks in a mode line, header line or tab line, the coordinate origin
|
||||
is the top left corner of the window itself. For fringes, margins,
|
||||
and the vertical border, @var{x} does not have meaningful data.
|
||||
For fringes and margins, @var{y} is relative to the bottom edge of the
|
||||
header line. In all cases, the @var{x} and @var{y} coordinates
|
||||
increase rightward and downward respectively.
|
||||
|
||||
@item @var{timestamp}
|
||||
The time at which the event occurred, as an integer number of
|
||||
|
@ -1407,17 +1408,18 @@ The position in the string where the click occurred.
|
|||
@item @var{text-pos}
|
||||
For clicks on a marginal area or on a fringe, this is the buffer
|
||||
position of the first visible character in the corresponding line in
|
||||
the window. For clicks on the mode line or the header line, this is
|
||||
@code{nil}. For other events, it is the buffer position closest to
|
||||
the click.
|
||||
the window. For clicks on the mode line, the header line or the tab
|
||||
line, this is @code{nil}. For other events, it is the buffer position
|
||||
closest to the click.
|
||||
|
||||
@item @var{col}, @var{row}
|
||||
These are the actual column and row coordinate numbers of the glyph
|
||||
under the @var{x}, @var{y} position. If @var{x} lies beyond the last
|
||||
column of actual text on its line, @var{col} is reported by adding
|
||||
fictional extra columns that have the default character width. Row 0
|
||||
is taken to be the header line if the window has one, or the topmost
|
||||
row of the text area otherwise. Column 0 is taken to be the leftmost
|
||||
fictional extra columns that have the default character width.
|
||||
Row 0 is taken to be the header line if the window has one, or Row 1
|
||||
if the window also has the tab line, or the topmost row of
|
||||
the text area otherwise. Column 0 is taken to be the leftmost
|
||||
column of the text area for clicks on a window text area, or the
|
||||
leftmost mode line or header line column for clicks there. For clicks
|
||||
on fringes or vertical borders, these have no meaningful data. For
|
||||
|
@ -2094,7 +2096,8 @@ computed values.)
|
|||
|
||||
Note that @var{row} is counted from the top of the text area. If the
|
||||
window given by @var{position} possesses a header line (@pxref{Header
|
||||
Lines}), it is @emph{not} included in the @var{row} count.
|
||||
Lines}) or a tab line, they are @emph{not} included in the @var{row}
|
||||
count.
|
||||
@end defun
|
||||
|
||||
@defun posn-actual-col-row position
|
||||
|
@ -2452,12 +2455,14 @@ button-down events entirely. It also reshuffles focus events and
|
|||
miscellaneous window events so that they never appear in a key sequence
|
||||
with any other events.
|
||||
|
||||
@cindex @code{tab-line} prefix key
|
||||
@cindex @code{header-line} prefix key
|
||||
@cindex @code{mode-line} prefix key
|
||||
@cindex @code{vertical-line} prefix key
|
||||
@cindex @code{horizontal-scroll-bar} prefix key
|
||||
@cindex @code{vertical-scroll-bar} prefix key
|
||||
@cindex @code{menu-bar} prefix key
|
||||
@cindex @code{tab-bar} prefix key
|
||||
@cindex mouse events, in special parts of frame
|
||||
When mouse events occur in special parts of a window, such as a mode
|
||||
line or a scroll bar, the event type shows nothing special---it is the
|
||||
|
@ -2465,8 +2470,8 @@ same symbol that would normally represent that combination of mouse
|
|||
button and modifier keys. The information about the window part is kept
|
||||
elsewhere in the event---in the coordinates. But
|
||||
@code{read-key-sequence} translates this information into imaginary
|
||||
prefix keys, all of which are symbols: @code{header-line},
|
||||
@code{horizontal-scroll-bar}, @code{menu-bar}, @code{mode-line},
|
||||
prefix keys, all of which are symbols: @code{tab-line}, @code{header-line},
|
||||
@code{horizontal-scroll-bar}, @code{menu-bar}, @code{tab-bar}, @code{mode-line},
|
||||
@code{vertical-line}, and @code{vertical-scroll-bar}. You can define
|
||||
meanings for mouse clicks in special window parts by defining key
|
||||
sequences using these imaginary prefix keys.
|
||||
|
|
|
@ -2944,6 +2944,7 @@ If the text lies within the mode line of the selected window, Emacs
|
|||
applies the @code{mode-line} face. For the mode line of a
|
||||
non-selected window, Emacs applies the @code{mode-line-inactive} face.
|
||||
For a header line, Emacs applies the @code{header-line} face.
|
||||
For a tab line, Emacs applies the @code{tab-line} face.
|
||||
|
||||
@item
|
||||
If the text comes from an overlay string via @code{before-string} or
|
||||
|
|
|
@ -5558,6 +5558,9 @@ The coordinates are in the mode line of @var{window}.
|
|||
@item header-line
|
||||
The coordinates are in the header line of @var{window}.
|
||||
|
||||
@item tab-line
|
||||
The coordinates are in the tab line of @var{window}.
|
||||
|
||||
@item right-divider
|
||||
The coordinates are in the divider separating @var{window} from a
|
||||
window on the right.
|
||||
|
@ -6115,6 +6118,15 @@ to suppress display of a header line for this window. Display and
|
|||
contents of the header line on other windows showing this buffer are not
|
||||
affected.
|
||||
|
||||
@item tab-line-format
|
||||
@vindex tab-line-format@r{, a window parameter}
|
||||
This parameter replaces the value of the buffer-local variable
|
||||
@code{tab-line-format} (@pxref{Mode Line Basics}) of this window's
|
||||
buffer whenever this window is displayed. The symbol @code{none} means
|
||||
to suppress display of a tab line for this window. Display and
|
||||
contents of the tab line on other windows showing this buffer are not
|
||||
affected.
|
||||
|
||||
@item min-margins
|
||||
@vindex min-margins@r{, a window parameter}
|
||||
The value of this parameter is a cons cell whose @sc{car} and
|
||||
|
|
28
etc/NEWS
28
etc/NEWS
|
@ -2030,6 +2030,34 @@ file-local variable, you may need to update the value.
|
|||
|
||||
* New Modes and Packages in Emacs 27.1
|
||||
|
||||
** 'tab-bar-mode' enables the tab-bar at the top of each frame,
|
||||
to switch named persistent window configurations in it using tabs.
|
||||
New tab-based keybindings (similar to frame-based commands):
|
||||
'C-x 6 2' creates a new tab;
|
||||
'C-x 6 0' deletes the current tab;
|
||||
'C-x 6 b' switches to buffer in another tab;
|
||||
'C-x 6 f' and 'C-x 6 C-f' edit file in another tab;
|
||||
'C-TAB' switches to the next tab;
|
||||
'S-C-TAB' switches to the previous tab.
|
||||
|
||||
Also it's possible to switch named persistent window configurations
|
||||
without having graphical access to the tab-bar, even on a tty
|
||||
or when 'tab-bar-mode' is disabled, with these commands:
|
||||
'tab-new' creates a new window configuration;
|
||||
'tab-close' deletes the current window configuration;
|
||||
'tab-select' switches to the window configuration by its name;
|
||||
'tab-previous' switches to the previous window configuration;
|
||||
'tab-next' switches to the next window configuration;
|
||||
'tab-list' displays a list of named window configurations for switching.
|
||||
|
||||
** 'global-tab-line-mode' enables the tab-line above each window to
|
||||
switch buffers in it to previous/next buffers. Selecting a previous
|
||||
window-local tab is the same as running 'C-x <left>' (previous-buffer),
|
||||
selecting a next tab switches to the tab available by 'C-x <right>'
|
||||
(next-buffer). Clicking on the plus icon adds a new buffer to the
|
||||
window-local tab-line of window buffers. Using the mouse wheel on the
|
||||
tab-line scrolls the window buffers whose names are displayed in tabs.
|
||||
|
||||
** fileloop.el lets one setup multifile operations like search&replace.
|
||||
|
||||
+++
|
||||
|
|
14
etc/TODO
14
etc/TODO
|
@ -324,20 +324,6 @@ consistency checks that make sure the new code computes the same results
|
|||
as the old code. And once that works well, we can remove the old code
|
||||
and old fields.
|
||||
|
||||
** Having tabs above a window to switch buffers in it.
|
||||
|
||||
** "Perspectives" are named persistent window configurations. We have
|
||||
had the window configuration mechanism in GNU Emacs since the
|
||||
beginning but we have never developed a good user interface to take
|
||||
advantage of them. Eclipse's user interface seems to be good.
|
||||
|
||||
Perspectives work well even if you do the equivalent of C-x 4 C-f
|
||||
because of the distinction between view windows vs file windows. In
|
||||
Emacs this is more or less the "dedicated window" feature, but we have
|
||||
never really made it work for this.
|
||||
|
||||
Perspectives also need to interact with the tabs.
|
||||
|
||||
** FFI (foreign function interface)
|
||||
See eg https://lists.gnu.org/r/emacs-devel/2013-10/msg00246.html
|
||||
|
||||
|
|
8
etc/images/tabs/README
Normal file
8
etc/images/tabs/README
Normal file
|
@ -0,0 +1,8 @@
|
|||
This directory contains icons for the Tabs user interface.
|
||||
|
||||
COPYRIGHT AND LICENSE INFORMATION FOR IMAGE FILES
|
||||
|
||||
Files: close.xpm new.xpm
|
||||
Author: Juri Linkov <juri@linkov.net>
|
||||
Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
License: GNU General Public License version 3 or later (see COPYING)
|
16
etc/images/tabs/close.xpm
Normal file
16
etc/images/tabs/close.xpm
Normal file
|
@ -0,0 +1,16 @@
|
|||
/* XPM */
|
||||
static char * close_xpm[] = {
|
||||
"9 9 4 1",
|
||||
" c None",
|
||||
". c #BFBFBF",
|
||||
"+ c #000000",
|
||||
"@ c #808080",
|
||||
" ..... ",
|
||||
" ....... ",
|
||||
"..+@.@+..",
|
||||
"..@+@+@..",
|
||||
"...@+@...",
|
||||
"..@+@+@..",
|
||||
"..+@.@+..",
|
||||
" ....... ",
|
||||
" ..... "};
|
16
etc/images/tabs/new.xpm
Normal file
16
etc/images/tabs/new.xpm
Normal file
|
@ -0,0 +1,16 @@
|
|||
/* XPM */
|
||||
static char * new_xpm[] = {
|
||||
"9 9 4 1",
|
||||
" c None",
|
||||
". c #BFBFBF",
|
||||
"+ c #808080",
|
||||
"@ c #000000",
|
||||
".........",
|
||||
"....+....",
|
||||
"....@....",
|
||||
"....@....",
|
||||
".+@@@@@+.",
|
||||
"....@....",
|
||||
"....@....",
|
||||
"....+....",
|
||||
"........."};
|
|
@ -324,6 +324,9 @@ Leaving \"Default\" unchecked is equivalent with specifying a default of
|
|||
;; FIXME?
|
||||
;; :initialize custom-initialize-default
|
||||
:set custom-set-minor-mode)
|
||||
(tab-bar-mode (frames mouse) boolean nil
|
||||
;; :initialize custom-initialize-default
|
||||
:set custom-set-minor-mode)
|
||||
(tool-bar-mode (frames mouse) boolean nil
|
||||
;; :initialize custom-initialize-default
|
||||
:set custom-set-minor-mode)
|
||||
|
@ -726,6 +729,8 @@ since it could result in memory overflow and make Emacs crash."
|
|||
;; the condition for loadup.el to preload tool-bar.el.
|
||||
((string-match "tool-bar-" (symbol-name symbol))
|
||||
(fboundp 'x-create-frame))
|
||||
((string-match "tab-bar-" (symbol-name symbol))
|
||||
(fboundp 'x-create-frame))
|
||||
((equal "vertical-centering-font-regexp"
|
||||
(symbol-name symbol))
|
||||
;; Any function from fontset.c will do.
|
||||
|
|
|
@ -363,6 +363,47 @@ there (in decreasing order of priority)."
|
|||
;; If the initial frame is still around, apply initial-frame-alist
|
||||
;; and default-frame-alist to it.
|
||||
(when (frame-live-p frame-initial-frame)
|
||||
;; When tab-bar has been switched off, correct the frame size
|
||||
;; by the lines added in x-create-frame for the tab-bar and
|
||||
;; switch `tab-bar-mode' off.
|
||||
(when (display-graphic-p)
|
||||
(let* ((init-lines
|
||||
(assq 'tab-bar-lines initial-frame-alist))
|
||||
(other-lines
|
||||
(or (assq 'tab-bar-lines window-system-frame-alist)
|
||||
(assq 'tab-bar-lines default-frame-alist)))
|
||||
(lines (or init-lines other-lines))
|
||||
(height (tab-bar-height frame-initial-frame t)))
|
||||
;; Adjust frame top if either zero (nil) tab bar lines have
|
||||
;; been requested in the most relevant of the frame's alists
|
||||
;; or tab bar mode has been explicitly turned off in the
|
||||
;; user's init file.
|
||||
(when (and (> height 0)
|
||||
(or (and lines
|
||||
(or (null (cdr lines))
|
||||
(eq 0 (cdr lines))))
|
||||
(not tab-bar-mode)))
|
||||
(let* ((initial-top
|
||||
(cdr (assq 'top frame-initial-geometry-arguments)))
|
||||
(top (frame-parameter frame-initial-frame 'top)))
|
||||
(when (and (consp initial-top) (eq '- (car initial-top)))
|
||||
(let ((adjusted-top
|
||||
(cond
|
||||
((and (consp top) (eq '+ (car top)))
|
||||
(list '+ (+ (cadr top) height)))
|
||||
((and (consp top) (eq '- (car top)))
|
||||
(list '- (- (cadr top) height)))
|
||||
(t (+ top height)))))
|
||||
(modify-frame-parameters
|
||||
frame-initial-frame `((top . ,adjusted-top))))))
|
||||
;; Reset `tab-bar-mode' when zero tab bar lines have been
|
||||
;; requested for the window-system or default frame alists.
|
||||
(when (and tab-bar-mode
|
||||
(and other-lines
|
||||
(or (null (cdr other-lines))
|
||||
(eq 0 (cdr other-lines)))))
|
||||
(tab-bar-mode -1)))))
|
||||
|
||||
;; When tool-bar has been switched off, correct the frame size
|
||||
;; by the lines added in x-create-frame for the tool-bar and
|
||||
;; switch `tool-bar-mode' off.
|
||||
|
@ -1593,6 +1634,7 @@ and width values are in pixels.
|
|||
'(tool-bar-external . nil)
|
||||
'(tool-bar-position . nil)
|
||||
'(tool-bar-size 0 . 0)
|
||||
'(tab-bar-size 0 . 0)
|
||||
(cons 'internal-border-width
|
||||
(frame-parameter frame 'internal-border-width)))))))
|
||||
|
||||
|
|
|
@ -267,6 +267,7 @@
|
|||
(load "rfn-eshadow")
|
||||
|
||||
(load "menu-bar")
|
||||
(load "tab-bar")
|
||||
(load "emacs-lisp/lisp")
|
||||
(load "textmodes/page")
|
||||
(load "register")
|
||||
|
|
|
@ -687,7 +687,7 @@ The selected font will be the default on both the existing and future frames."
|
|||
;; side-effect that turning them off via X
|
||||
;; resources acts like having customized them, but
|
||||
;; that seems harmless.
|
||||
menu-bar-mode tool-bar-mode))
|
||||
menu-bar-mode tab-bar-mode tool-bar-mode))
|
||||
;; FIXME ? It's a little annoying that running this command
|
||||
;; always loads cua-base, paren, time, and battery, even if they
|
||||
;; have not been customized in any way. (Due to custom-load-symbol.)
|
||||
|
@ -1242,6 +1242,14 @@ mail status in mode line"))
|
|||
(frame-parameter (menu-bar-frame-for-menubar)
|
||||
'menu-bar-lines)))))
|
||||
|
||||
(bindings--define-key menu [showhide-tab-bar]
|
||||
'(menu-item "Tab Bar" toggle-tab-bar-mode-from-frame
|
||||
:help "Turn tab bar on/off"
|
||||
:button
|
||||
(:toggle . (menu-bar-positive-p
|
||||
(frame-parameter (menu-bar-frame-for-menubar)
|
||||
'tab-bar-lines)))))
|
||||
|
||||
(if (and (boundp 'menu-bar-showhide-tool-bar-menu)
|
||||
(keymapp menu-bar-showhide-tool-bar-menu))
|
||||
(bindings--define-key menu [showhide-tool-bar]
|
||||
|
|
|
@ -2734,6 +2734,7 @@ is copied instead of being cut."
|
|||
;; versions.
|
||||
(global-set-key [header-line down-mouse-1] 'mouse-drag-header-line)
|
||||
(global-set-key [header-line mouse-1] 'mouse-select-window)
|
||||
(global-set-key [tab-line mouse-1] 'mouse-select-window)
|
||||
;; (global-set-key [mode-line drag-mouse-1] 'mouse-select-window)
|
||||
(global-set-key [mode-line down-mouse-1] 'mouse-drag-mode-line)
|
||||
(global-set-key [mode-line mouse-1] 'mouse-select-window)
|
||||
|
|
|
@ -769,6 +769,7 @@ It is the default value of the variable `top-level'."
|
|||
("--background-color" . "-bg")
|
||||
("--color" . "-color")))
|
||||
|
||||
;; FIXME: this var unused?
|
||||
(defconst tool-bar-images-pixel-height 24
|
||||
"Height in pixels of images in the tool-bar.")
|
||||
|
||||
|
@ -1300,6 +1301,7 @@ please check its value")
|
|||
(unless (daemonp)
|
||||
(if (or noninteractive emacs-basic-display)
|
||||
(setq menu-bar-mode nil
|
||||
tab-bar-mode nil
|
||||
tool-bar-mode nil
|
||||
no-blinking-cursor t))
|
||||
(frame-initialize))
|
||||
|
@ -1515,6 +1517,7 @@ This can set the values of `menu-bar-mode', `tool-bar-mode', and
|
|||
settings will be marked as \"CHANGED outside of Customize\"."
|
||||
(let ((no-vals '("no" "off" "false" "0"))
|
||||
(settings '(("menuBar" "MenuBar" menu-bar-mode nil)
|
||||
("tabBar" "TabBar" tab-bar-mode nil)
|
||||
("toolBar" "ToolBar" tool-bar-mode nil)
|
||||
("scrollBar" "ScrollBar" scroll-bar-mode nil)
|
||||
("cursorBlink" "CursorBlink" no-blinking-cursor t))))
|
||||
|
|
|
@ -2395,8 +2395,12 @@ some sort of escape sequence, the ambiguity is resolved via `read-key-delay'."
|
|||
(progn
|
||||
(use-global-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
;; Don't hide the menu-bar and tool-bar entries.
|
||||
;; Don't hide the menu-bar, tab-bar and tool-bar entries.
|
||||
(define-key map [menu-bar] (lookup-key global-map [menu-bar]))
|
||||
(define-key map [tab-bar]
|
||||
;; This hack avoids evaluating the :filter (Bug#9922).
|
||||
(or (cdr (assq 'tab-bar global-map))
|
||||
(lookup-key global-map [tab-bar])))
|
||||
(define-key map [tool-bar]
|
||||
;; This hack avoids evaluating the :filter (Bug#9922).
|
||||
(or (cdr (assq 'tool-bar global-map))
|
||||
|
|
764
lisp/tab-bar.el
Normal file
764
lisp/tab-bar.el
Normal file
|
@ -0,0 +1,764 @@
|
|||
;;; tab-bar.el --- frame-local tabs with named persistent window configurations -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Juri Linkov <juri@linkov.net>
|
||||
;; Keywords: frames tabs
|
||||
;; Maintainer: emacs-devel@gnu.org
|
||||
|
||||
;; 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.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Provides `tab-bar-mode' to control display of the tab bar and
|
||||
;; bindings for the global tab bar.
|
||||
|
||||
;; The normal global binding for [tab-bar] (below) uses the value of
|
||||
;; `tab-bar-map' as the actual keymap to define the tab bar. Modes
|
||||
;; may either bind items under the [tab-bar] prefix key of the local
|
||||
;; map to add to the global bar or may set `tab-bar-map'
|
||||
;; buffer-locally to override it.
|
||||
|
||||
;;; Code:
|
||||
|
||||
|
||||
(defgroup tab-bar nil
|
||||
"Frame-local tabs."
|
||||
:group 'convenience
|
||||
:version "27.1")
|
||||
|
||||
(defgroup tab-bar-faces nil
|
||||
"Faces used in the tab bar."
|
||||
:group 'tab-bar
|
||||
:group 'faces
|
||||
:version "27.1")
|
||||
|
||||
(defface tab-bar
|
||||
'((((type x w32 ns) (class color))
|
||||
:height 1.1
|
||||
:background "grey85"
|
||||
:foreground "black")
|
||||
(((type x) (class mono))
|
||||
:background "grey")
|
||||
(t
|
||||
:inverse-video t))
|
||||
"Tab bar face."
|
||||
:version "27.1"
|
||||
:group 'tab-bar-faces)
|
||||
|
||||
(defface tab-bar-tab
|
||||
'((((class color) (min-colors 88))
|
||||
:box (:line-width 1 :style released-button))
|
||||
(t
|
||||
:inverse-video nil))
|
||||
"Tab bar face for selected tab."
|
||||
:version "27.1"
|
||||
:group 'tab-bar-faces)
|
||||
|
||||
(defface tab-bar-tab-inactive
|
||||
'((default
|
||||
:inherit tab-bar-tab)
|
||||
(((class color) (min-colors 88))
|
||||
:background "grey75")
|
||||
(t
|
||||
:inverse-video t))
|
||||
"Tab bar face for non-selected tab."
|
||||
:version "27.1"
|
||||
:group 'tab-bar-faces)
|
||||
|
||||
|
||||
(define-minor-mode tab-bar-mode
|
||||
"Toggle the tab bar in all graphical frames (Tab Bar mode)."
|
||||
:global t
|
||||
;; It's defined in C/cus-start, this stops the d-m-m macro defining it again.
|
||||
:variable tab-bar-mode
|
||||
(let ((val (if tab-bar-mode 1 0)))
|
||||
(dolist (frame (frame-list))
|
||||
(set-frame-parameter frame 'tab-bar-lines val))
|
||||
;; If the user has given `default-frame-alist' a `tab-bar-lines'
|
||||
;; parameter, replace it.
|
||||
(if (assq 'tab-bar-lines default-frame-alist)
|
||||
(setq default-frame-alist
|
||||
(cons (cons 'tab-bar-lines val)
|
||||
(assq-delete-all 'tab-bar-lines
|
||||
default-frame-alist)))))
|
||||
(when tab-bar-mode
|
||||
(global-set-key [(control shift iso-lefttab)] 'tab-bar-switch-to-prev-tab)
|
||||
(global-set-key [(control shift tab)] 'tab-bar-switch-to-prev-tab)
|
||||
(global-set-key [(control tab)] 'tab-bar-switch-to-next-tab)))
|
||||
|
||||
(defun tab-bar-handle-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)
|
||||
;; TODO: handle close
|
||||
(unless (get-text-property (- x-position column) 'close-tab (nth 1 binding))
|
||||
(call-interactively (nth 2 binding)))
|
||||
(throw 'done t))
|
||||
(setq column (+ column (length (nth 1 binding))))))
|
||||
keymap))
|
||||
;; Clicking anywhere outside existing tabs will add a new tab
|
||||
(tab-bar-new-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.
|
||||
See `tab-bar-mode' for more information."
|
||||
(interactive (list (or current-prefix-arg 'toggle)))
|
||||
(if (eq arg 'toggle)
|
||||
(tab-bar-mode (if (> (frame-parameter nil 'tab-bar-lines) 0) 0 1))
|
||||
(tab-bar-mode arg)))
|
||||
|
||||
(defvar tab-bar-map (make-sparse-keymap)
|
||||
"Keymap for the tab bar.
|
||||
Define this locally to override the global tab bar.")
|
||||
|
||||
(global-set-key [tab-bar]
|
||||
`(menu-item ,(purecopy "tab bar") ignore
|
||||
:filter tab-bar-make-keymap))
|
||||
|
||||
(defconst tab-bar-keymap-cache (make-hash-table :weakness t :test 'equal))
|
||||
|
||||
(defun tab-bar-make-keymap (&optional _ignore)
|
||||
"Generate an actual keymap from `tab-bar-map'.
|
||||
Its main job is to show tabs in the tab bar."
|
||||
(if (= 1 (length tab-bar-map))
|
||||
(tab-bar-make-keymap-1)
|
||||
(let ((key (cons (frame-terminal) tab-bar-map)))
|
||||
(or (gethash key tab-bar-keymap-cache)
|
||||
(puthash key tab-bar-map tab-bar-keymap-cache)))))
|
||||
|
||||
|
||||
(defcustom tab-bar-new-tab-choice t
|
||||
"Defines what to show in a new tab.
|
||||
If t, start a new tab with the current buffer, i.e. the buffer
|
||||
that was current before calling the command that adds a new tab
|
||||
(this is the same what `make-frame' does by default).
|
||||
If the value is a string, switch to a buffer if it exists, or switch
|
||||
to a buffer visiting the file or directory that the string specifies.
|
||||
If the value is a function, call it with no arguments and switch to
|
||||
the buffer that it returns.
|
||||
If nil, duplicate the contents of the tab that was active
|
||||
before calling the command that adds a new tab."
|
||||
:type '(choice (const :tag "Current buffer" t)
|
||||
(directory :tag "Directory" :value "~/")
|
||||
(file :tag "File" :value "~/.emacs")
|
||||
(string :tag "Buffer" "*scratch*")
|
||||
(function :tag "Function")
|
||||
(const :tag "Duplicate tab" nil))
|
||||
:group 'tab-bar
|
||||
:version "27.1")
|
||||
|
||||
(defvar tab-bar-new-button
|
||||
(propertize " + "
|
||||
'display `(image :type xpm
|
||||
:file ,(expand-file-name
|
||||
"images/tabs/new.xpm"
|
||||
data-directory)
|
||||
:margin (2 . 0)
|
||||
:ascent center))
|
||||
"Button for creating a new tab.")
|
||||
|
||||
(defcustom tab-bar-close-button-show t
|
||||
"Defines where to show the close tab button.
|
||||
If t, show the close tab button on all tabs.
|
||||
If `selected', show it only on the selected tab.
|
||||
If `non-selected', show it only on non-selected tab.
|
||||
If nil, don't show it at all."
|
||||
:type '(choice (const :tag "On all tabs" t)
|
||||
(const :tag "On selected tab" selected)
|
||||
(const :tag "On non-selected tabs" non-selected)
|
||||
(const :tag "None" nil))
|
||||
:set (lambda (sym val)
|
||||
(set sym val)
|
||||
(force-mode-line-update))
|
||||
:group 'tab-bar
|
||||
:version "27.1")
|
||||
|
||||
(defvar tab-bar-close-button
|
||||
(propertize " x"
|
||||
'display `(image :type xpm
|
||||
:file ,(expand-file-name
|
||||
"images/tabs/close.xpm"
|
||||
data-directory)
|
||||
:margin (2 . 0)
|
||||
:ascent center)
|
||||
'close-tab t
|
||||
:help "Click to close tab")
|
||||
"Button for closing the clicked tab.")
|
||||
|
||||
(defvar tab-bar-separator nil)
|
||||
|
||||
|
||||
(defvar tab-bar-tab-name-function #'tab-bar-tab-name
|
||||
"Function to get a tab name.
|
||||
Function gets no arguments.
|
||||
By default, use function `tab-bar-tab-name'.")
|
||||
|
||||
(defun tab-bar-tab-name ()
|
||||
"Generate tab name in the context of the selected frame."
|
||||
(mapconcat #'buffer-name
|
||||
(delete-dups (mapcar #'window-buffer
|
||||
(window-list-1 (frame-first-window)
|
||||
'nomini)))
|
||||
", "))
|
||||
|
||||
(defvar tab-bar-tabs-function #'tab-bar-tabs
|
||||
"Function to get a list of tabs to display in the tab bar.
|
||||
This function should return a list of alists with parameters
|
||||
that include at least the element (name . TAB-NAME).
|
||||
For example, '((tab (name . \"Tab 1\")) (current-tab (name . \"Tab 2\")))
|
||||
By default, use function `tab-bar-tabs'.")
|
||||
|
||||
(defun tab-bar-tabs ()
|
||||
"Return a list of tabs belonging to the selected frame.
|
||||
Ensure the frame parameter `tabs' is pre-populated.
|
||||
Return its existing value or a new value."
|
||||
(let ((tabs (frame-parameter nil 'tabs)))
|
||||
(if tabs
|
||||
;; Update current tab name
|
||||
(let ((name (assq 'name (assq 'current-tab tabs))))
|
||||
(when name (setcdr name (funcall tab-bar-tab-name-function))))
|
||||
;; Create default tabs
|
||||
(setq tabs `((current-tab (name . ,(funcall tab-bar-tab-name-function)))))
|
||||
(set-frame-parameter nil 'tabs tabs))
|
||||
tabs))
|
||||
|
||||
(defun tab-bar-make-keymap-1 ()
|
||||
"Generate an actual keymap from `tab-bar-map', without caching."
|
||||
(let ((separator (or tab-bar-separator (if window-system " " "|")))
|
||||
(i 0))
|
||||
(append
|
||||
'(keymap (mouse-1 . tab-bar-handle-mouse))
|
||||
(mapcan
|
||||
(lambda (tab)
|
||||
(setq i (1+ i))
|
||||
(append
|
||||
`((,(intern (format "sep-%i" i)) menu-item ,separator ignore))
|
||||
(cond
|
||||
((eq (car tab) 'current-tab)
|
||||
`((current-tab
|
||||
menu-item
|
||||
,(propertize (concat (cdr (assq 'name tab))
|
||||
(or (and tab-bar-close-button-show
|
||||
(not (eq tab-bar-close-button-show
|
||||
'non-selected))
|
||||
tab-bar-close-button) ""))
|
||||
'face 'tab-bar-tab)
|
||||
ignore
|
||||
:help "Current tab")))
|
||||
(t
|
||||
`((,(intern (format "tab-%i" i))
|
||||
menu-item
|
||||
,(propertize (concat (cdr (assq 'name tab))
|
||||
(or (and tab-bar-close-button-show
|
||||
(not (eq tab-bar-close-button-show
|
||||
'selected))
|
||||
tab-bar-close-button) ""))
|
||||
'face 'tab-bar-tab-inactive)
|
||||
,(or
|
||||
(cdr (assq 'binding tab))
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(tab-bar-select-tab tab)))
|
||||
:help "Click to visit tab"))))
|
||||
`((,(if (eq (car tab) 'current-tab) 'C-current-tab (intern (format "C-tab-%i" i)))
|
||||
menu-item ""
|
||||
,(or
|
||||
(cdr (assq 'close-binding tab))
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(tab-bar-close-tab tab)))))))
|
||||
(funcall tab-bar-tabs-function))
|
||||
(when tab-bar-new-button
|
||||
`((sep-add-tab menu-item ,separator ignore)
|
||||
(add-tab menu-item ,tab-bar-new-button tab-bar-new-tab
|
||||
:help "New tab"))))))
|
||||
|
||||
|
||||
(defun tab-bar-read-tab-name (prompt)
|
||||
(let* ((tabs (tab-bar-tabs))
|
||||
(tab-name
|
||||
(completing-read prompt
|
||||
(or (delq nil (mapcar (lambda (tab)
|
||||
(cdr (assq 'name tab)))
|
||||
tabs))
|
||||
'("")))))
|
||||
(catch 'done
|
||||
(dolist (tab tabs)
|
||||
(when (equal (cdr (assq 'name tab)) tab-name)
|
||||
(throw 'done tab))))))
|
||||
|
||||
(defun tab-bar-tab-default ()
|
||||
(let ((tab `(tab
|
||||
(name . ,(funcall tab-bar-tab-name-function))
|
||||
(time . ,(time-convert nil 'integer))
|
||||
(wc . ,(current-window-configuration))
|
||||
(ws . ,(window-state-get
|
||||
(frame-root-window (selected-frame)) 'writable)))))
|
||||
tab))
|
||||
|
||||
(defun tab-bar-find-prev-tab (&optional tabs)
|
||||
(unless tabs
|
||||
(setq tabs (tab-bar-tabs)))
|
||||
(unless (eq (car (car tabs)) 'current-tab)
|
||||
(while (and tabs (not (eq (car (car (cdr tabs))) 'current-tab)))
|
||||
(setq tabs (cdr tabs)))
|
||||
tabs))
|
||||
|
||||
|
||||
(defun tab-bar-select-tab (tab)
|
||||
"Switch to the specified TAB."
|
||||
(interactive (list (tab-bar-read-tab-name "Select tab by name: ")))
|
||||
(when (and tab (not (eq (car tab) 'current-tab)))
|
||||
(let* ((tabs (tab-bar-tabs))
|
||||
(new-tab (tab-bar-tab-default))
|
||||
(wc (cdr (assq 'wc tab))))
|
||||
;; During the same session, use window-configuration to switch
|
||||
;; tabs, because window-configurations are more reliable
|
||||
;; (they keep references to live buffers) than window-states.
|
||||
;; But after restoring tabs from a previously saved session,
|
||||
;; its value of window-configuration is unreadable,
|
||||
;; so restore its saved window-state.
|
||||
(if (window-configuration-p wc)
|
||||
(set-window-configuration wc)
|
||||
(window-state-put (cdr (assq 'ws tab))
|
||||
(frame-root-window (selected-frame)) 'safe))
|
||||
(while tabs
|
||||
(cond
|
||||
((eq (car tabs) tab)
|
||||
(setcar tabs `(current-tab (name . ,(funcall tab-bar-tab-name-function)))))
|
||||
((eq (car (car tabs)) 'current-tab)
|
||||
(setcar tabs new-tab)))
|
||||
(setq tabs (cdr tabs)))
|
||||
(force-mode-line-update))))
|
||||
|
||||
(defun tab-bar-switch-to-prev-tab (&optional _arg)
|
||||
"Switch to ARGth previous tab."
|
||||
(interactive "p")
|
||||
(let ((prev-tab (tab-bar-find-prev-tab)))
|
||||
(when prev-tab
|
||||
(tab-bar-select-tab (car prev-tab)))))
|
||||
|
||||
(defun tab-bar-switch-to-next-tab (&optional _arg)
|
||||
"Switch to ARGth next tab."
|
||||
(interactive "p")
|
||||
(let* ((tabs (tab-bar-tabs))
|
||||
(prev-tab (tab-bar-find-prev-tab tabs)))
|
||||
(if prev-tab
|
||||
(tab-bar-select-tab (car (cdr (cdr prev-tab))))
|
||||
(tab-bar-select-tab (car (cdr tabs))))))
|
||||
|
||||
|
||||
(defcustom tab-bar-new-tab-to 'right
|
||||
"Defines where to create a new tab.
|
||||
If `leftmost', create as the first tab.
|
||||
If `left', create to the left from the current tab.
|
||||
If `right', create to the right from the current tab.
|
||||
If `rightmost', create as the last tab."
|
||||
:type '(choice (const :tag "First tab" leftmost)
|
||||
(const :tag "To the left" left)
|
||||
(const :tag "To the right" right)
|
||||
(const :tag "Last tab" rightmost))
|
||||
:group 'tab-bar
|
||||
:version "27.1")
|
||||
|
||||
(defun tab-bar-new-tab ()
|
||||
"Clone the current tab to the position specified by `tab-bar-new-tab-to'."
|
||||
(interactive)
|
||||
(unless tab-bar-mode
|
||||
(tab-bar-mode 1))
|
||||
(let* ((tabs (tab-bar-tabs))
|
||||
;; (i-tab (- (length tabs) (length (memq tab tabs))))
|
||||
(new-tab (tab-bar-tab-default)))
|
||||
(cond
|
||||
((eq tab-bar-new-tab-to 'leftmost)
|
||||
(setq tabs (cons new-tab tabs)))
|
||||
((eq tab-bar-new-tab-to 'rightmost)
|
||||
(setq tabs (append tabs (list new-tab))))
|
||||
(t
|
||||
(let ((prev-tab (tab-bar-find-prev-tab tabs)))
|
||||
(cond
|
||||
((eq tab-bar-new-tab-to 'left)
|
||||
(if prev-tab
|
||||
(setcdr prev-tab (cons new-tab (cdr prev-tab)))
|
||||
(setq tabs (cons new-tab tabs))))
|
||||
((eq tab-bar-new-tab-to 'right)
|
||||
(if prev-tab
|
||||
(setq prev-tab (cdr prev-tab))
|
||||
(setq prev-tab tabs))
|
||||
(setcdr prev-tab (cons new-tab (cdr prev-tab))))))))
|
||||
(set-frame-parameter nil 'tabs tabs)
|
||||
(tab-bar-select-tab new-tab)
|
||||
(when tab-bar-new-tab-choice
|
||||
(delete-other-windows)
|
||||
(let ((buffer
|
||||
(if (functionp tab-bar-new-tab-choice)
|
||||
(funcall tab-bar-new-tab-choice)
|
||||
(if (stringp tab-bar-new-tab-choice)
|
||||
(or (get-buffer tab-bar-new-tab-choice)
|
||||
(find-file-noselect tab-bar-new-tab-choice))))))
|
||||
(when (buffer-live-p buffer)
|
||||
(switch-to-buffer buffer))))
|
||||
(unless tab-bar-mode
|
||||
(message "Added new tab with the current window configuration"))))
|
||||
|
||||
|
||||
(defcustom tab-bar-close-tab-select 'right
|
||||
"Defines what tab to select after closing the specified tab.
|
||||
If `left', select the adjacent left tab.
|
||||
If `right', select the adjacent right tab."
|
||||
:type '(choice (const :tag "Select left tab" left)
|
||||
(const :tag "Select right tab" right))
|
||||
:group 'tab-bar
|
||||
:version "27.1")
|
||||
|
||||
(defun tab-bar-close-current-tab (&optional tab select-tab)
|
||||
"Close the current TAB.
|
||||
After closing the current tab switch to the tab
|
||||
specified by `tab-bar-close-tab-select', or to `select-tab'
|
||||
if its value is provided."
|
||||
(interactive)
|
||||
(let ((tabs (tab-bar-tabs)))
|
||||
(unless tab
|
||||
(let ((prev-tab (tab-bar-find-prev-tab tabs)))
|
||||
(setq tab (if prev-tab
|
||||
(car (cdr prev-tab))
|
||||
(car tabs)))))
|
||||
(if select-tab
|
||||
(setq tabs (delq tab tabs))
|
||||
(let* ((i-tab (- (length tabs) (length (memq tab tabs))))
|
||||
(i-select
|
||||
(cond
|
||||
((eq tab-bar-close-tab-select 'left)
|
||||
(1- i-tab))
|
||||
((eq tab-bar-close-tab-select 'right)
|
||||
;; Do nothing: the next tab will take
|
||||
;; the index of the closed tab
|
||||
i-tab)
|
||||
(t 0))))
|
||||
(setq tabs (delq tab tabs)
|
||||
i-select (max 0 (min (1- (length tabs)) i-select))
|
||||
select-tab (nth i-select tabs))))
|
||||
(set-frame-parameter nil 'tabs tabs)
|
||||
(tab-bar-select-tab select-tab)))
|
||||
|
||||
(defun tab-bar-close-tab (tab)
|
||||
"Close the specified TAB.
|
||||
After closing the current tab switch to the tab
|
||||
specified by `tab-bar-close-tab-select'."
|
||||
(interactive (list (tab-bar-read-tab-name "Close tab by name: ")))
|
||||
(when tab
|
||||
(if (eq (car tab) 'current-tab)
|
||||
(tab-bar-close-current-tab tab)
|
||||
;; Close non-current tab, no need to switch to another tab
|
||||
(set-frame-parameter nil 'tabs (delq tab (tab-bar-tabs)))
|
||||
(force-mode-line-update))))
|
||||
|
||||
|
||||
;;; Non-graphical access to frame-local tabs (named window configurations)
|
||||
|
||||
(defun tab-new ()
|
||||
"Create a new named window configuration without having to click a tab."
|
||||
(interactive)
|
||||
(tab-bar-new-tab)
|
||||
(unless tab-bar-mode
|
||||
(message "Added new tab with the current window configuration")))
|
||||
|
||||
(defun tab-close ()
|
||||
"Delete the current window configuration without clicking a close button."
|
||||
(interactive)
|
||||
(tab-bar-close-current-tab)
|
||||
(unless tab-bar-mode
|
||||
(message "Deleted the current tab")))
|
||||
|
||||
;; Short aliases
|
||||
;; (defalias 'tab-switch 'tab-bar-switch-to-next-tab)
|
||||
(defalias 'tab-select 'tab-bar-select-tab)
|
||||
(defalias 'tab-previous 'tab-bar-switch-to-prev-tab)
|
||||
(defalias 'tab-next 'tab-bar-switch-to-next-tab)
|
||||
(defalias 'tab-list 'tab-bar-list)
|
||||
|
||||
(defun tab-bar-list ()
|
||||
"Display a list of named window configurations.
|
||||
The list is displayed in the buffer `*Tabs*'.
|
||||
|
||||
In this list of window configurations you can delete or select them.
|
||||
Type ? after invocation to get help on commands available.
|
||||
Type q to remove the list of window configurations from the display.
|
||||
|
||||
The first column shows `D' for for a window configuration you have
|
||||
marked for deletion."
|
||||
(interactive)
|
||||
(let ((dir default-directory)
|
||||
(minibuf (minibuffer-selected-window)))
|
||||
(let ((tab-bar-mode t)) ; don't enable tab-bar-mode if it's disabled
|
||||
(tab-bar-new-tab))
|
||||
;; Handle the case when it's called in the active minibuffer.
|
||||
(when minibuf (select-window (minibuffer-selected-window)))
|
||||
(delete-other-windows)
|
||||
;; Create a new window to replace the existing one, to not break the
|
||||
;; window parameters (e.g. prev/next buffers) of the window just saved
|
||||
;; to the window configuration. So when a saved window is restored,
|
||||
;; its parameters left intact.
|
||||
(split-window) (delete-window)
|
||||
(let ((switch-to-buffer-preserve-window-point nil))
|
||||
(switch-to-buffer (tab-bar-list-noselect)))
|
||||
(setq default-directory dir))
|
||||
(message "Commands: d, x; RET; q to quit; ? for help."))
|
||||
|
||||
(defun tab-bar-list-noselect ()
|
||||
"Create and return a buffer with a list of window configurations.
|
||||
The list is displayed in a buffer named `*Tabs*'.
|
||||
|
||||
For more information, see the function `tab-bar-list'."
|
||||
(let* ((tabs (delq nil (mapcar (lambda (tab) ; remove current tab
|
||||
(unless (eq (car tab) 'current-tab)
|
||||
tab))
|
||||
(tab-bar-tabs))))
|
||||
;; Sort by recency
|
||||
(tabs (sort tabs (lambda (a b) (< (cdr (assq 'time b))
|
||||
(cdr (assq 'time a)))))))
|
||||
(with-current-buffer (get-buffer-create
|
||||
(format " *Tabs*<%s>" (or (frame-parameter nil 'window-id)
|
||||
(frame-parameter nil 'name))))
|
||||
(erase-buffer)
|
||||
(tab-bar-list-mode)
|
||||
(setq buffer-read-only nil)
|
||||
;; Vertical alignment to the center of the frame
|
||||
(insert-char ?\n (/ (- (frame-height) (length tabs) 1) 2))
|
||||
;; Horizontal alignment to the center of the frame
|
||||
(setq tab-bar-list-column (- (/ (frame-width) 2) 15))
|
||||
(dolist (tab tabs)
|
||||
(insert (propertize
|
||||
(format "%s %s\n"
|
||||
(make-string tab-bar-list-column ?\040)
|
||||
(propertize
|
||||
(cdr (assq 'name tab))
|
||||
'mouse-face 'highlight
|
||||
'help-echo "mouse-2: select this window configuration"))
|
||||
'tab tab)))
|
||||
(goto-char (point-min))
|
||||
(goto-char (or (next-single-property-change (point) 'tab) (point-min)))
|
||||
(when (> (length tabs) 1)
|
||||
(tab-bar-list-next-line))
|
||||
(move-to-column tab-bar-list-column)
|
||||
(set-buffer-modified-p nil)
|
||||
(current-buffer))))
|
||||
|
||||
(defvar tab-bar-list-column 3)
|
||||
(make-variable-buffer-local 'tab-bar-list-column)
|
||||
|
||||
(defvar tab-bar-list-mode-map
|
||||
(let ((map (make-keymap)))
|
||||
(suppress-keymap map t)
|
||||
(define-key map "q" 'quit-window)
|
||||
(define-key map "\C-m" 'tab-bar-list-select)
|
||||
(define-key map "d" 'tab-bar-list-delete)
|
||||
(define-key map "k" 'tab-bar-list-delete)
|
||||
(define-key map "\C-d" 'tab-bar-list-delete-backwards)
|
||||
(define-key map "\C-k" 'tab-bar-list-delete)
|
||||
(define-key map "x" 'tab-bar-list-execute)
|
||||
(define-key map " " 'tab-bar-list-next-line)
|
||||
(define-key map "n" 'tab-bar-list-next-line)
|
||||
(define-key map "p" 'tab-bar-list-prev-line)
|
||||
(define-key map "\177" 'tab-bar-list-backup-unmark)
|
||||
(define-key map "?" 'describe-mode)
|
||||
(define-key map "u" 'tab-bar-list-unmark)
|
||||
(define-key map [mouse-2] 'tab-bar-list-mouse-select)
|
||||
(define-key map [follow-link] 'mouse-face)
|
||||
map)
|
||||
"Local keymap for `tab-bar-list-mode' buffers.")
|
||||
|
||||
(define-derived-mode tab-bar-list-mode nil "Window Configurations"
|
||||
"Major mode for selecting a window configuration.
|
||||
Each line describes one window configuration in Emacs.
|
||||
Letters do not insert themselves; instead, they are commands.
|
||||
\\<tab-bar-list-mode-map>
|
||||
\\[tab-bar-list-mouse-select] -- select window configuration you click on.
|
||||
\\[tab-bar-list-select] -- select current line's window configuration.
|
||||
\\[tab-bar-list-delete] -- mark that window configuration to be deleted, and move down.
|
||||
\\[tab-bar-list-delete-backwards] -- mark that window configuration to be deleted, and move up.
|
||||
\\[tab-bar-list-execute] -- delete marked window configurations.
|
||||
\\[tab-bar-list-unmark] -- remove all kinds of marks from current line.
|
||||
With prefix argument, also move up one line.
|
||||
\\[tab-bar-list-backup-unmark] -- back up a line and remove marks."
|
||||
(setq truncate-lines t)
|
||||
(setq buffer-read-only t))
|
||||
|
||||
(defun tab-bar-list-current-tab (error-if-non-existent-p)
|
||||
"Return window configuration described by this line of the list."
|
||||
(let* ((where (save-excursion
|
||||
(beginning-of-line)
|
||||
(+ 2 (point) tab-bar-list-column)))
|
||||
(tab (and (not (eobp)) (get-text-property where 'tab))))
|
||||
(or tab
|
||||
(if error-if-non-existent-p
|
||||
(user-error "No window configuration on this line")
|
||||
nil))))
|
||||
|
||||
|
||||
(defun tab-bar-list-next-line (&optional arg)
|
||||
(interactive)
|
||||
(forward-line arg)
|
||||
(beginning-of-line)
|
||||
(move-to-column tab-bar-list-column))
|
||||
|
||||
(defun tab-bar-list-prev-line (&optional arg)
|
||||
(interactive)
|
||||
(forward-line (- arg))
|
||||
(beginning-of-line)
|
||||
(move-to-column tab-bar-list-column))
|
||||
|
||||
(defun tab-bar-list-unmark (&optional backup)
|
||||
"Cancel all requested operations on window configuration on this line and move down.
|
||||
Optional prefix arg means move up."
|
||||
(interactive "P")
|
||||
(beginning-of-line)
|
||||
(move-to-column tab-bar-list-column)
|
||||
(let* ((buffer-read-only nil))
|
||||
(delete-char 1)
|
||||
(insert " "))
|
||||
(forward-line (if backup -1 1))
|
||||
(move-to-column tab-bar-list-column))
|
||||
|
||||
(defun tab-bar-list-backup-unmark ()
|
||||
"Move up and cancel all requested operations on window configuration on line above."
|
||||
(interactive)
|
||||
(forward-line -1)
|
||||
(tab-bar-list-unmark)
|
||||
(forward-line -1)
|
||||
(move-to-column tab-bar-list-column))
|
||||
|
||||
(defun tab-bar-list-delete (&optional arg)
|
||||
"Mark window configuration on this line to be deleted by \\<tab-bar-list-mode-map>\\[tab-bar-list-execute] command.
|
||||
Prefix arg is how many window configurations to delete.
|
||||
Negative arg means delete backwards."
|
||||
(interactive "p")
|
||||
(let ((buffer-read-only nil))
|
||||
(if (or (null arg) (= arg 0))
|
||||
(setq arg 1))
|
||||
(while (> arg 0)
|
||||
(delete-char 1)
|
||||
(insert ?D)
|
||||
(forward-line 1)
|
||||
(setq arg (1- arg)))
|
||||
(while (< arg 0)
|
||||
(delete-char 1)
|
||||
(insert ?D)
|
||||
(forward-line -1)
|
||||
(setq arg (1+ arg)))
|
||||
(move-to-column tab-bar-list-column)))
|
||||
|
||||
(defun tab-bar-list-delete-backwards (&optional arg)
|
||||
"Mark window configuration on this line to be deleted by \\<tab-bar-list-mode-map>\\[tab-bar-list-execute] command.
|
||||
Then move up one line. Prefix arg means move that many lines."
|
||||
(interactive "p")
|
||||
(tab-bar-list-delete (- (or arg 1))))
|
||||
|
||||
(defun tab-bar-list-delete-from-list (tab)
|
||||
"Delete the window configuration from both lists."
|
||||
(set-frame-parameter nil 'tabs (delq tab (tab-bar-tabs))))
|
||||
|
||||
(defun tab-bar-list-execute ()
|
||||
"Delete window configurations marked with \\<tab-bar-list-mode-map>\\[tab-bar-list-delete] commands."
|
||||
(interactive)
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(let ((buffer-read-only nil))
|
||||
(while (re-search-forward
|
||||
(format "^%sD" (make-string tab-bar-list-column ?\040))
|
||||
nil t)
|
||||
(forward-char -1)
|
||||
(let ((tab (tab-bar-list-current-tab nil)))
|
||||
(when tab
|
||||
(tab-bar-list-delete-from-list tab)
|
||||
(beginning-of-line)
|
||||
(delete-region (point) (progn (forward-line 1) (point))))))))
|
||||
(beginning-of-line)
|
||||
(move-to-column tab-bar-list-column)
|
||||
(when tab-bar-mode
|
||||
(force-mode-line-update)))
|
||||
|
||||
(defun tab-bar-list-select ()
|
||||
"Select this line's window configuration.
|
||||
This command deletes and replaces all the previously existing windows
|
||||
in the selected frame."
|
||||
(interactive)
|
||||
(let* ((select-tab (tab-bar-list-current-tab t)))
|
||||
(kill-buffer (current-buffer))
|
||||
;; Delete the current window configuration
|
||||
(tab-bar-close-current-tab nil select-tab)
|
||||
;; (tab-bar-select-tab select-tab)
|
||||
))
|
||||
|
||||
(defun tab-bar-list-mouse-select (event)
|
||||
"Select the window configuration whose line you click on."
|
||||
(interactive "e")
|
||||
(set-buffer (window-buffer (posn-window (event-end event))))
|
||||
(goto-char (posn-point (event-end event)))
|
||||
(tab-bar-list-select))
|
||||
|
||||
|
||||
(defvar ctl-x-6-map (make-sparse-keymap)
|
||||
"Keymap for tab commands.")
|
||||
(defalias 'ctl-x-6-prefix ctl-x-6-map)
|
||||
(define-key ctl-x-map "6" 'ctl-x-6-prefix)
|
||||
|
||||
(defun switch-to-buffer-other-tab (buffer-or-name &optional norecord)
|
||||
"Switch to buffer BUFFER-OR-NAME in another tab.
|
||||
Like \\[switch-to-buffer-other-frame] (which see), but creates a new tab."
|
||||
(interactive
|
||||
(list (read-buffer-to-switch "Switch to buffer in other tab: ")))
|
||||
(tab-bar-new-tab)
|
||||
(delete-other-windows)
|
||||
(switch-to-buffer buffer-or-name norecord))
|
||||
|
||||
(defun find-file-other-tab (filename &optional wildcards)
|
||||
"Edit file FILENAME, in another tab.
|
||||
Like \\[find-file-other-frame] (which see), but creates a new tab."
|
||||
(interactive
|
||||
(find-file-read-args "Find file in other tab: "
|
||||
(confirm-nonexistent-file-or-buffer)))
|
||||
(let ((value (find-file-noselect filename nil nil wildcards)))
|
||||
(if (listp value)
|
||||
(progn
|
||||
(setq value (nreverse value))
|
||||
(switch-to-buffer-other-tab (car value))
|
||||
(mapc 'switch-to-buffer (cdr value))
|
||||
value)
|
||||
(switch-to-buffer-other-tab value))))
|
||||
|
||||
(define-key ctl-x-6-map "2" 'tab-bar-new-tab)
|
||||
(define-key ctl-x-6-map "0" 'tab-bar-close-current-tab)
|
||||
(define-key ctl-x-6-map "b" 'switch-to-buffer-other-tab)
|
||||
(define-key ctl-x-6-map "f" 'find-file-other-tab)
|
||||
(define-key ctl-x-6-map "\C-f" 'find-file-other-tab)
|
||||
|
||||
|
||||
(provide 'tab-bar)
|
||||
|
||||
;;; tab-bar.el ends here
|
362
lisp/tab-line.el
Normal file
362
lisp/tab-line.el
Normal file
|
@ -0,0 +1,362 @@
|
|||
;;; tab-line.el --- window-local tabs with window buffers -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Juri Linkov <juri@linkov.net>
|
||||
;; Keywords: windows tabs
|
||||
;; Maintainer: emacs-devel@gnu.org
|
||||
|
||||
;; 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.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; To enable this mode, run `M-x global-tab-line-mode'.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'seq) ; tab-line.el is not pre-loaded so it's safe to use it here
|
||||
|
||||
|
||||
(defgroup tab-line nil
|
||||
"Window-local tabs."
|
||||
:group 'convenience
|
||||
:version "27.1")
|
||||
|
||||
(defgroup tab-line-faces nil
|
||||
"Faces used in the tab line."
|
||||
:group 'tab-line
|
||||
:group 'faces
|
||||
:version "27.1")
|
||||
|
||||
(defface tab-line
|
||||
'((((type x w32 ns) (class color))
|
||||
:background "grey85"
|
||||
:foreground "black")
|
||||
(((type x) (class mono))
|
||||
:background "grey")
|
||||
(t
|
||||
:inverse-video t))
|
||||
"Tab line face."
|
||||
:version "27.1"
|
||||
:group 'tab-line-faces)
|
||||
|
||||
(defface tab-line-tab
|
||||
'((((class color) (min-colors 88))
|
||||
:box (:line-width 1 :style released-button)
|
||||
:background "grey85")
|
||||
(t
|
||||
:inverse-video nil))
|
||||
"Tab line face for selected tab."
|
||||
:version "27.1"
|
||||
:group 'tab-line-faces)
|
||||
|
||||
(defface tab-line-tab-inactive
|
||||
'((default
|
||||
:inherit tab-line-tab)
|
||||
(((class color) (min-colors 88))
|
||||
:background "grey75")
|
||||
(t
|
||||
:inverse-video t))
|
||||
"Tab line face for non-selected tab."
|
||||
:version "27.1"
|
||||
:group 'tab-line-faces)
|
||||
|
||||
(defface tab-line-highlight
|
||||
'((default :inherit tab-line-tab))
|
||||
"Tab line face for highlighting."
|
||||
:version "27.1"
|
||||
:group 'tab-line-faces)
|
||||
|
||||
(defface tab-line-close-highlight
|
||||
'((t :foreground "red"))
|
||||
"Tab line face for highlighting of the close button."
|
||||
:version "27.1"
|
||||
:group 'tab-line-faces)
|
||||
|
||||
|
||||
(defvar tab-line-tab-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map [tab-line mouse-1] 'tab-line-select-tab)
|
||||
(define-key map [tab-line mouse-2] 'tab-line-close-tab)
|
||||
(define-key map [tab-line mouse-4] 'tab-line-switch-to-prev-tab)
|
||||
(define-key map [tab-line mouse-5] 'tab-line-switch-to-next-tab)
|
||||
(define-key map "\C-m" 'tab-line-select-tab)
|
||||
map)
|
||||
"Local keymap for `tab-line-mode' window tabs.")
|
||||
|
||||
(defvar tab-line-add-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map [tab-line mouse-1] 'tab-line-new-tab)
|
||||
(define-key map [tab-line mouse-2] 'tab-line-new-tab)
|
||||
(define-key map "\C-m" 'tab-line-new-tab)
|
||||
map)
|
||||
"Local keymap to add `tab-line-mode' window tabs.")
|
||||
|
||||
(defvar tab-line-tab-close-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map [tab-line mouse-1] 'tab-line-close-tab)
|
||||
(define-key map [tab-line mouse-2] 'tab-line-close-tab)
|
||||
map)
|
||||
"Local keymap to close `tab-line-mode' window tabs.")
|
||||
|
||||
|
||||
(defcustom tab-line-new-tab-choice t
|
||||
"Defines what to show in a new tab.
|
||||
If t, display a selection menu with all available buffers.
|
||||
If the value is a function, call it with no arguments.
|
||||
If nil, don't show the new tab button."
|
||||
:type '(choice (const :tag "Buffer menu" t)
|
||||
(function :tag "Function")
|
||||
(const :tag "No button" nil))
|
||||
:group 'tab-line
|
||||
:version "27.1")
|
||||
|
||||
(defvar tab-line-new-button
|
||||
(propertize " + "
|
||||
'display `(image :type xpm
|
||||
:file ,(expand-file-name
|
||||
"images/tabs/new.xpm"
|
||||
data-directory)
|
||||
:margin (2 . 0)
|
||||
:ascent center)
|
||||
'keymap tab-line-add-map
|
||||
'mouse-face 'tab-line-highlight
|
||||
'help-echo "Click to add tab")
|
||||
"Button for creating a new tab.")
|
||||
|
||||
(defcustom tab-line-close-button-show t
|
||||
"Defines where to show the close tab button.
|
||||
If t, show the close tab button on all tabs.
|
||||
If `selected', show it only on the selected tab.
|
||||
If `non-selected', show it only on non-selected tab.
|
||||
If nil, don't show it at all."
|
||||
:type '(choice (const :tag "On all tabs" t)
|
||||
(const :tag "On selected tab" selected)
|
||||
(const :tag "On non-selected tabs" non-selected)
|
||||
(const :tag "None" nil))
|
||||
:set (lambda (sym val)
|
||||
(set sym val)
|
||||
(force-mode-line-update))
|
||||
:group 'tab-line
|
||||
:version "27.1")
|
||||
|
||||
(defvar tab-line-close-button
|
||||
(propertize " x"
|
||||
'display `(image :type xpm
|
||||
:file ,(expand-file-name
|
||||
"images/tabs/close.xpm"
|
||||
data-directory)
|
||||
:margin (2 . 0)
|
||||
:ascent center)
|
||||
'keymap tab-line-tab-close-map
|
||||
'mouse-face 'tab-line-close-highlight
|
||||
'help-echo "Click to close tab")
|
||||
"Button for closing the clicked tab.")
|
||||
|
||||
(defvar tab-line-separator nil)
|
||||
|
||||
(defvar tab-line-tab-name-ellipsis
|
||||
(if (char-displayable-p ?…) "…" "..."))
|
||||
|
||||
|
||||
(defvar tab-line-tab-name-function #'tab-line-tab-name
|
||||
"Function to get a tab name.
|
||||
Function gets two arguments: tab to get name for and a list of tabs
|
||||
to display. By default, use function `tab-line-tab-name'.")
|
||||
|
||||
(defun tab-line-tab-name (buffer &optional buffers)
|
||||
"Generate tab name from BUFFER.
|
||||
Reduce tab width proportionally to space taken by other tabs.
|
||||
This function can be overridden by changing the default value of the
|
||||
variable `tab-line-tab-name-function'."
|
||||
(let ((tab-name (buffer-name buffer))
|
||||
(limit (when buffers
|
||||
(max 1 (- (/ (window-width) (length buffers)) 3)))))
|
||||
(if (or (not limit) (< (length tab-name) limit))
|
||||
tab-name
|
||||
(propertize (truncate-string-to-width tab-name limit nil nil
|
||||
tab-line-tab-name-ellipsis)
|
||||
'help-echo tab-name))))
|
||||
|
||||
(defvar tab-line-tabs-limit 15
|
||||
"Maximum number of buffer tabs displayed in the tab line.")
|
||||
|
||||
(defvar tab-line-tabs-function #'tab-line-tabs
|
||||
"Function to get a list of tabs to display in the tab line.
|
||||
This function should return either a list of buffers whose names will
|
||||
be displayed, or just a list of strings to display in the tab line.
|
||||
By default, use function `tab-line-tabs'.")
|
||||
|
||||
(defun tab-line-tabs ()
|
||||
"Return a list of tabs that should be displayed in the tab line.
|
||||
By default returns a list of window buffers, i.e. buffers previously
|
||||
shown in the same window where the tab line is displayed.
|
||||
This list can be overridden by changing the default value of the
|
||||
variable `tab-line-tabs-function'."
|
||||
(let* ((window (selected-window))
|
||||
(buffer (window-buffer window))
|
||||
(next-buffers (seq-remove (lambda (b) (eq b buffer))
|
||||
(window-next-buffers window)))
|
||||
(next-buffers (seq-filter #'buffer-live-p next-buffers))
|
||||
(prev-buffers (seq-remove (lambda (b) (eq b buffer))
|
||||
(mapcar #'car (window-prev-buffers window))))
|
||||
(prev-buffers (seq-filter #'buffer-live-p prev-buffers))
|
||||
;; Remove next-buffers from prev-buffers
|
||||
(prev-buffers (seq-difference prev-buffers next-buffers))
|
||||
(half-limit (/ tab-line-tabs-limit 2))
|
||||
(prev-buffers-limit
|
||||
(if (> (length prev-buffers) half-limit)
|
||||
(if (> (length next-buffers) half-limit)
|
||||
half-limit
|
||||
(+ half-limit (- half-limit (length next-buffers))))
|
||||
(length prev-buffers)))
|
||||
(next-buffers-limit
|
||||
(- tab-line-tabs-limit prev-buffers-limit))
|
||||
(buffer-tabs
|
||||
(append (reverse (seq-take prev-buffers prev-buffers-limit))
|
||||
(list buffer)
|
||||
(seq-take next-buffers next-buffers-limit))))
|
||||
buffer-tabs))
|
||||
|
||||
(defun tab-line-format ()
|
||||
"Template for displaying tab line for selected window."
|
||||
(let* ((window (selected-window))
|
||||
(selected-buffer (window-buffer window))
|
||||
(tabs (funcall tab-line-tabs-function))
|
||||
(separator (or tab-line-separator (if window-system " " "|"))))
|
||||
(append
|
||||
(mapcar
|
||||
(lambda (tab)
|
||||
(concat
|
||||
separator
|
||||
(apply 'propertize (concat (propertize
|
||||
(funcall tab-line-tab-name-function tab tabs)
|
||||
'keymap tab-line-tab-map)
|
||||
(or (and tab-line-close-button-show
|
||||
(not (eq tab-line-close-button-show
|
||||
(if (eq tab selected-buffer)
|
||||
'non-selected
|
||||
'selected)))
|
||||
tab-line-close-button) ""))
|
||||
`(
|
||||
tab ,tab
|
||||
face ,(if (eq tab selected-buffer)
|
||||
'tab-line-tab
|
||||
'tab-line-tab-inactive)
|
||||
mouse-face tab-line-highlight))))
|
||||
tabs)
|
||||
(list (concat separator (when tab-line-new-tab-choice
|
||||
tab-line-new-button))))))
|
||||
|
||||
|
||||
(defun tab-line-new-tab (&optional e)
|
||||
"Add a new tab to the tab line.
|
||||
Usually is invoked by clicking on the plus-shaped button.
|
||||
But any switching to other buffer also adds a new tab
|
||||
corresponding to the switched buffer."
|
||||
(interactive "e")
|
||||
(if (functionp tab-line-new-tab-choice)
|
||||
(funcall tab-line-new-tab-choice)
|
||||
(if window-system ; (display-popup-menus-p)
|
||||
(mouse-buffer-menu e) ; like (buffer-menu-open)
|
||||
;; tty menu doesn't support mouse clicks, so use tmm
|
||||
(tmm-prompt (mouse-buffer-menu-keymap)))))
|
||||
|
||||
(defun tab-line-select-tab (&optional e)
|
||||
"Switch to the selected tab.
|
||||
This command maintains the original order of prev/next buffers.
|
||||
So for example, switching to a previous tab is equivalent to
|
||||
using the `previous-buffer' command."
|
||||
(interactive "e")
|
||||
(let* ((posnp (event-start e))
|
||||
(window (posn-window posnp))
|
||||
(buffer (get-pos-property 1 'tab (car (posn-string posnp))))
|
||||
(window-buffer (window-buffer window))
|
||||
(next-buffers (seq-remove (lambda (b) (eq b window-buffer))
|
||||
(window-next-buffers window)))
|
||||
(prev-buffers (seq-remove (lambda (b) (eq b window-buffer))
|
||||
(mapcar #'car (window-prev-buffers window))))
|
||||
;; Remove next-buffers from prev-buffers
|
||||
(prev-buffers (seq-difference prev-buffers next-buffers)))
|
||||
(cond
|
||||
((memq buffer next-buffers)
|
||||
(dotimes (_ (1+ (seq-position next-buffers buffer)))
|
||||
(switch-to-next-buffer window)))
|
||||
((memq buffer prev-buffers)
|
||||
(dotimes (_ (1+ (seq-position prev-buffers buffer)))
|
||||
(switch-to-prev-buffer window)))
|
||||
(t
|
||||
(with-selected-window window
|
||||
(switch-to-buffer buffer))))))
|
||||
|
||||
(defun tab-line-switch-to-prev-tab (&optional e)
|
||||
"Switch to the previous tab.
|
||||
Its effect is the same as using the `previous-buffer' command
|
||||
(\\[previous-buffer])."
|
||||
(interactive "e")
|
||||
(switch-to-prev-buffer (posn-window (event-start e))))
|
||||
|
||||
(defun tab-line-switch-to-next-tab (&optional e)
|
||||
"Switch to the next tab.
|
||||
Its effect is the same as using the `next-buffer' command
|
||||
(\\[next-buffer])."
|
||||
(interactive "e")
|
||||
(switch-to-next-buffer (posn-window (event-start e))))
|
||||
|
||||
(defcustom tab-line-close-tab-action 'bury-buffer
|
||||
"Defines what to do on closing the tab.
|
||||
If `bury-buffer', put the tab's buffer at the end of the list of all
|
||||
buffers that effectively hides the buffer's tab from the tab line.
|
||||
If `kill-buffer', kills the tab's buffer."
|
||||
:type '(choice (const :tag "Bury buffer" bury-buffer)
|
||||
(const :tag "Kill buffer" kill-buffer))
|
||||
:group 'tab-line
|
||||
:version "27.1")
|
||||
|
||||
(defun tab-line-close-tab (&optional e)
|
||||
"Close the selected tab.
|
||||
Usually is invoked by clicking on the close button on the right side
|
||||
of the tab. This command buries the buffer, so it goes out of sight
|
||||
from the tab line."
|
||||
(interactive "e")
|
||||
(let* ((posnp (event-start e))
|
||||
(window (posn-window posnp))
|
||||
(buffer (get-pos-property 1 'tab (car (posn-string posnp)))))
|
||||
(with-selected-window window
|
||||
(cond
|
||||
((eq tab-line-close-tab-action 'kill-buffer)
|
||||
(kill-buffer buffer))
|
||||
((eq tab-line-close-tab-action 'bury-buffer)
|
||||
(if (eq buffer (current-buffer))
|
||||
(bury-buffer)
|
||||
(set-window-prev-buffers nil (assq-delete-all buffer (window-prev-buffers)))
|
||||
(set-window-next-buffers nil (delq buffer (window-next-buffers))))))
|
||||
(force-mode-line-update))))
|
||||
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode global-tab-line-mode
|
||||
"Display window-local tab line."
|
||||
:group 'tab-line
|
||||
:type 'boolean
|
||||
:global t
|
||||
:init-value nil
|
||||
(setq-default tab-line-format (when global-tab-line-mode
|
||||
'(:eval (tab-line-format)))))
|
||||
|
||||
|
||||
(provide 'tab-line)
|
||||
;;; tab-line.el ends here
|
|
@ -1419,7 +1419,10 @@ dumping to it."
|
|||
(format "frame text pixel: %s x %s cols/lines: %s x %s\n"
|
||||
(frame-text-width frame) (frame-text-height frame)
|
||||
(frame-text-cols frame) (frame-text-lines frame))
|
||||
(format "tool: %s scroll: %s/%s fringe: %s border: %s right: %s bottom: %s\n\n"
|
||||
(format "tab: %s tool: %s scroll: %s/%s fringe: %s border: %s right: %s bottom: %s\n\n"
|
||||
(if (fboundp 'tab-bar-height)
|
||||
(tab-bar-height frame t)
|
||||
"0")
|
||||
(if (fboundp 'tool-bar-height)
|
||||
(tool-bar-height frame t)
|
||||
"0")
|
||||
|
|
|
@ -253,7 +253,13 @@ which is the \"1006\" extension implemented in Xterm >= 277."
|
|||
(top (nth 1 ltrb))
|
||||
(posn (if w
|
||||
(posn-at-x-y (- x left) (- y top) w t)
|
||||
(append (list nil 'menu-bar)
|
||||
(append (list nil (if (and tab-bar-mode
|
||||
(or (not menu-bar-mode)
|
||||
;; The tab-bar is on the
|
||||
;; second row below menu-bar
|
||||
(eq y 1)))
|
||||
'tab-bar
|
||||
'menu-bar))
|
||||
(nthcdr 2 (posn-at-x-y x y)))))
|
||||
(event (list type posn)))
|
||||
(setcar (nthcdr 3 posn) timestamp)
|
||||
|
|
16
src/buffer.c
16
src/buffer.c
|
@ -249,6 +249,11 @@ bset_header_line_format (struct buffer *b, Lisp_Object val)
|
|||
b->header_line_format_ = val;
|
||||
}
|
||||
static void
|
||||
bset_tab_line_format (struct buffer *b, Lisp_Object val)
|
||||
{
|
||||
b->tab_line_format_ = val;
|
||||
}
|
||||
static void
|
||||
bset_indicate_buffer_boundaries (struct buffer *b, Lisp_Object val)
|
||||
{
|
||||
b->indicate_buffer_boundaries_ = val;
|
||||
|
@ -1329,7 +1334,7 @@ No argument or nil as argument means use current buffer as BUFFER. */)
|
|||
DEFUN ("force-mode-line-update", Fforce_mode_line_update,
|
||||
Sforce_mode_line_update, 0, 1, 0,
|
||||
doc: /* Force redisplay of the current buffer's mode line and header line.
|
||||
With optional non-nil ALL, force redisplay of all mode lines and
|
||||
With optional non-nil ALL, force redisplay of all mode lines, tab lines and
|
||||
header lines. This function also forces recomputation of the
|
||||
menu bar menus and the frame title. */)
|
||||
(Lisp_Object all)
|
||||
|
@ -5194,6 +5199,7 @@ init_buffer_once (void)
|
|||
XSETFASTINT (BVAR (&buffer_local_flags, scroll_up_aggressively), idx); ++idx;
|
||||
XSETFASTINT (BVAR (&buffer_local_flags, scroll_down_aggressively), idx); ++idx;
|
||||
XSETFASTINT (BVAR (&buffer_local_flags, header_line_format), idx); ++idx;
|
||||
XSETFASTINT (BVAR (&buffer_local_flags, tab_line_format), idx); ++idx;
|
||||
XSETFASTINT (BVAR (&buffer_local_flags, cursor_type), idx); ++idx;
|
||||
XSETFASTINT (BVAR (&buffer_local_flags, extra_line_spacing), idx); ++idx;
|
||||
XSETFASTINT (BVAR (&buffer_local_flags, cursor_in_non_selected_windows), idx); ++idx;
|
||||
|
@ -5239,6 +5245,7 @@ init_buffer_once (void)
|
|||
/* real setup is done in bindings.el */
|
||||
bset_mode_line_format (&buffer_defaults, build_pure_c_string ("%-"));
|
||||
bset_header_line_format (&buffer_defaults, Qnil);
|
||||
bset_tab_line_format (&buffer_defaults, Qnil);
|
||||
bset_abbrev_mode (&buffer_defaults, Qnil);
|
||||
bset_overwrite_mode (&buffer_defaults, Qnil);
|
||||
bset_case_fold_search (&buffer_defaults, Qt);
|
||||
|
@ -5510,6 +5517,13 @@ syms_of_buffer (void)
|
|||
Fput (Qprotected_field, Qerror_message,
|
||||
build_pure_c_string ("Attempt to modify a protected field"));
|
||||
|
||||
DEFVAR_PER_BUFFER ("tab-line-format",
|
||||
&BVAR (current_buffer, tab_line_format),
|
||||
Qnil,
|
||||
doc: /* Analogous to `mode-line-format', but controls the tab line.
|
||||
The tab line appears, optionally, at the top of a window;
|
||||
the mode line appears at the bottom. */);
|
||||
|
||||
DEFVAR_PER_BUFFER ("header-line-format",
|
||||
&BVAR (current_buffer, header_line_format),
|
||||
Qnil,
|
||||
|
|
|
@ -348,6 +348,10 @@ struct buffer
|
|||
of windows. Nil means don't display that line. */
|
||||
Lisp_Object header_line_format_;
|
||||
|
||||
/* Analogous to mode_line_format for the line displayed at the top
|
||||
of windows. Nil means don't display that line. */
|
||||
Lisp_Object tab_line_format_;
|
||||
|
||||
/* Keys that are bound local to this buffer. */
|
||||
Lisp_Object keymap_;
|
||||
|
||||
|
|
105
src/dispextern.h
105
src/dispextern.h
|
@ -166,6 +166,7 @@ enum window_part
|
|||
ON_MODE_LINE,
|
||||
ON_VERTICAL_BORDER,
|
||||
ON_HEADER_LINE,
|
||||
ON_TAB_LINE,
|
||||
ON_LEFT_FRINGE,
|
||||
ON_RIGHT_FRINGE,
|
||||
ON_LEFT_MARGIN,
|
||||
|
@ -762,6 +763,9 @@ struct glyph_matrix
|
|||
which do their own scrolling. */
|
||||
bool_bf no_scrolling_p : 1;
|
||||
|
||||
/* True means window displayed in this matrix has a tab line. */
|
||||
bool_bf tab_line_p : 1;
|
||||
|
||||
/* True means window displayed in this matrix has a header
|
||||
line. */
|
||||
bool_bf header_line_p : 1;
|
||||
|
@ -1001,9 +1005,12 @@ struct glyph_row
|
|||
implies that the row doesn't have marginal areas. */
|
||||
bool_bf full_width_p : 1;
|
||||
|
||||
/* True means row is a mode or header-line. */
|
||||
/* True means row is a mode or header/tab-line. */
|
||||
bool_bf mode_line_p : 1;
|
||||
|
||||
/* True means row is a tab-line. */
|
||||
bool_bf tab_line_p : 1;
|
||||
|
||||
/* True in a current row means this row is overlapped by another row. */
|
||||
bool_bf overlapped_p : 1;
|
||||
|
||||
|
@ -1084,16 +1091,25 @@ struct glyph_row *matrix_row (struct glyph_matrix *, int);
|
|||
#define MATRIX_MODE_LINE_ROW(MATRIX) \
|
||||
((MATRIX)->rows + (MATRIX)->nrows - 1)
|
||||
|
||||
/* Return a pointer to the row reserved for the header line in MATRIX.
|
||||
/* Return a pointer to the row reserved for the tab line in MATRIX.
|
||||
This is always the first row in MATRIX because that's the only
|
||||
way that works in frame-based redisplay. */
|
||||
|
||||
#define MATRIX_HEADER_LINE_ROW(MATRIX) (MATRIX)->rows
|
||||
#define MATRIX_TAB_LINE_ROW(MATRIX) (MATRIX)->rows
|
||||
|
||||
/* Return a pointer to the row reserved for the header line in MATRIX.
|
||||
This is always the second row in MATRIX because that's the only
|
||||
way that works in frame-based redisplay. */
|
||||
|
||||
#define MATRIX_HEADER_LINE_ROW(MATRIX) \
|
||||
((MATRIX)->tab_line_p ? ((MATRIX)->rows + 1) : (MATRIX)->rows)
|
||||
|
||||
/* Return a pointer to first row in MATRIX used for text display. */
|
||||
|
||||
#define MATRIX_FIRST_TEXT_ROW(MATRIX) \
|
||||
((MATRIX)->rows->mode_line_p ? (MATRIX)->rows + 1 : (MATRIX)->rows)
|
||||
((MATRIX)->rows->mode_line_p ? \
|
||||
(((MATRIX)->rows + 1)->mode_line_p ? \
|
||||
(MATRIX)->rows + 2 : (MATRIX)->rows + 1) : (MATRIX)->rows)
|
||||
|
||||
/* Return a pointer to the first glyph in the text area of a row.
|
||||
MATRIX is the glyph matrix accessed, and ROW is the row index in
|
||||
|
@ -1162,7 +1178,7 @@ struct glyph_row *matrix_row (struct glyph_matrix *, int);
|
|||
((ROW)->height != (ROW)->visible_height)
|
||||
|
||||
#define MR_PARTIALLY_VISIBLE_AT_TOP(W, ROW) \
|
||||
((ROW)->y < WINDOW_HEADER_LINE_HEIGHT ((W)))
|
||||
((ROW)->y < (WINDOW_TAB_LINE_HEIGHT ((W)) + WINDOW_HEADER_LINE_HEIGHT ((W))))
|
||||
|
||||
#define MR_PARTIALLY_VISIBLE_AT_BOTTOM(W, ROW) \
|
||||
(((ROW)->y + (ROW)->height - (ROW)->extra_line_spacing) \
|
||||
|
@ -1433,6 +1449,15 @@ struct glyph_string
|
|||
? MATRIX_HEADER_LINE_ROW (MATRIX)->height \
|
||||
: 0)
|
||||
|
||||
/* Return the height of the tab line in glyph matrix MATRIX, or zero
|
||||
if not known. This macro is called under circumstances where
|
||||
MATRIX might not have been allocated yet. */
|
||||
|
||||
#define MATRIX_TAB_LINE_HEIGHT(MATRIX) \
|
||||
((MATRIX) && (MATRIX)->rows \
|
||||
? MATRIX_TAB_LINE_ROW (MATRIX)->height \
|
||||
: 0)
|
||||
|
||||
/* Return the desired face id for the mode line of a window, depending
|
||||
on whether the window is selected or not, or if the window is the
|
||||
scrolling window for the currently active minibuffer window.
|
||||
|
@ -1485,6 +1510,19 @@ struct glyph_string
|
|||
: estimate_mode_line_height \
|
||||
(XFRAME (W->frame), HEADER_LINE_FACE_ID))))
|
||||
|
||||
/* Return the current height of the tab line of window W. If not known
|
||||
from W->tab_line_height, look at W's current glyph matrix, or return
|
||||
an estimation based on the height of the font of the face `tab-line'. */
|
||||
|
||||
#define CURRENT_TAB_LINE_HEIGHT(W) \
|
||||
(W->tab_line_height >= 0 \
|
||||
? W->tab_line_height \
|
||||
: (W->tab_line_height \
|
||||
= (MATRIX_TAB_LINE_HEIGHT (W->current_matrix) \
|
||||
? MATRIX_TAB_LINE_HEIGHT (W->current_matrix) \
|
||||
: estimate_mode_line_height \
|
||||
(XFRAME (W->frame), TAB_LINE_FACE_ID))))
|
||||
|
||||
/* Return the height of the desired mode line of window W. */
|
||||
|
||||
#define DESIRED_MODE_LINE_HEIGHT(W) \
|
||||
|
@ -1495,6 +1533,11 @@ struct glyph_string
|
|||
#define DESIRED_HEADER_LINE_HEIGHT(W) \
|
||||
MATRIX_HEADER_LINE_HEIGHT ((W)->desired_matrix)
|
||||
|
||||
/* Return the height of the desired tab line of window W. */
|
||||
|
||||
#define DESIRED_TAB_LINE_HEIGHT(W) \
|
||||
MATRIX_TAB_LINE_HEIGHT ((W)->desired_matrix)
|
||||
|
||||
/* Return proper value to be used as baseline offset of font that has
|
||||
ASCENT and DESCENT to draw characters by the font at the vertical
|
||||
center of the line of frame F.
|
||||
|
@ -1780,6 +1823,8 @@ enum face_id
|
|||
WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID,
|
||||
WINDOW_DIVIDER_LAST_PIXEL_FACE_ID,
|
||||
INTERNAL_BORDER_FACE_ID,
|
||||
TAB_BAR_FACE_ID,
|
||||
TAB_LINE_FACE_ID,
|
||||
BASIC_FACE_ID_SENTINEL
|
||||
};
|
||||
|
||||
|
@ -2283,6 +2328,9 @@ struct it
|
|||
/* True means multibyte characters are enabled. */
|
||||
bool_bf multibyte_p : 1;
|
||||
|
||||
/* True means window has a tab line at its top. */
|
||||
bool_bf tab_line_p : 1;
|
||||
|
||||
/* True means window has a mode line at its top. */
|
||||
bool_bf header_line_p : 1;
|
||||
|
||||
|
@ -3128,6 +3176,50 @@ struct image_cache
|
|||
#endif /* HAVE_WINDOW_SYSTEM */
|
||||
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
Tab-bars
|
||||
***********************************************************************/
|
||||
|
||||
/* Enumeration defining where to find tab-bar item information in
|
||||
tab-bar items vectors stored with frames. Each tab-bar item
|
||||
occupies TAB_BAR_ITEM_NSLOTS elements in such a vector. */
|
||||
|
||||
enum tab_bar_item_idx
|
||||
{
|
||||
/* The key of the tab-bar item. Used to remove items when a binding
|
||||
for `undefined' is found. */
|
||||
TAB_BAR_ITEM_KEY,
|
||||
|
||||
/* Non-nil if item is enabled. */
|
||||
TAB_BAR_ITEM_ENABLED_P,
|
||||
|
||||
/* Non-nil if item is selected (pressed). */
|
||||
TAB_BAR_ITEM_SELECTED_P,
|
||||
|
||||
/* Caption. */
|
||||
TAB_BAR_ITEM_CAPTION,
|
||||
|
||||
/* The binding. */
|
||||
TAB_BAR_ITEM_BINDING,
|
||||
|
||||
/* Help string. */
|
||||
TAB_BAR_ITEM_HELP,
|
||||
|
||||
/* Sentinel = number of slots in tab_bar_items occupied by one
|
||||
tab-bar item. */
|
||||
TAB_BAR_ITEM_NSLOTS
|
||||
};
|
||||
|
||||
/* Default values of the above variables. */
|
||||
|
||||
#define DEFAULT_TAB_BAR_BUTTON_MARGIN 4
|
||||
#define DEFAULT_TAB_BAR_BUTTON_RELIEF 1
|
||||
|
||||
/* The height in pixels of the default tab-bar images. */
|
||||
|
||||
#define DEFAULT_TAB_BAR_IMAGE_HEIGHT 18
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
Tool-bars
|
||||
|
@ -3285,6 +3377,7 @@ extern bool help_echo_showing_p;
|
|||
extern Lisp_Object help_echo_string, help_echo_window;
|
||||
extern Lisp_Object help_echo_object, previous_help_echo_string;
|
||||
extern ptrdiff_t help_echo_pos;
|
||||
extern int last_tab_bar_item;
|
||||
extern int last_tool_bar_item;
|
||||
extern void reseat_at_previous_visible_line_start (struct it *);
|
||||
extern Lisp_Object lookup_glyphless_char_display (int, struct it *);
|
||||
|
@ -3332,6 +3425,8 @@ extern void get_glyph_string_clip_rect (struct glyph_string *,
|
|||
NativeRectangle *nr);
|
||||
extern Lisp_Object find_hot_spot (Lisp_Object, int, int);
|
||||
|
||||
extern void handle_tab_bar_click (struct frame *,
|
||||
int, int, bool, int);
|
||||
extern void handle_tool_bar_click (struct frame *,
|
||||
int, int, bool, int);
|
||||
|
||||
|
|
164
src/dispnew.c
164
src/dispnew.c
|
@ -80,7 +80,7 @@ static void adjust_decode_mode_spec_buffer (struct frame *);
|
|||
static void fill_up_glyph_row_with_spaces (struct glyph_row *);
|
||||
static void clear_window_matrices (struct window *, bool);
|
||||
static void fill_up_glyph_row_area_with_spaces (struct glyph_row *, int);
|
||||
static int scrolling_window (struct window *, bool);
|
||||
static int scrolling_window (struct window *, int);
|
||||
static bool update_window_line (struct window *, int, bool *);
|
||||
static void mirror_make_current (struct window *, int);
|
||||
#ifdef GLYPH_DEBUG
|
||||
|
@ -366,6 +366,8 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y
|
|||
int i;
|
||||
int new_rows;
|
||||
bool marginal_areas_changed_p = 0;
|
||||
bool tab_line_changed_p = 0;
|
||||
bool tab_line_p = 0;
|
||||
bool header_line_changed_p = 0;
|
||||
bool header_line_p = 0;
|
||||
int left = -1, right = -1;
|
||||
|
@ -377,9 +379,13 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y
|
|||
{
|
||||
window_box (w, ANY_AREA, 0, 0, &window_width, &window_height);
|
||||
|
||||
tab_line_p = window_wants_tab_line (w);
|
||||
tab_line_changed_p = tab_line_p != matrix->tab_line_p;
|
||||
|
||||
header_line_p = window_wants_header_line (w);
|
||||
header_line_changed_p = header_line_p != matrix->header_line_p;
|
||||
}
|
||||
matrix->tab_line_p = tab_line_p;
|
||||
matrix->header_line_p = header_line_p;
|
||||
|
||||
/* If POOL is null, MATRIX is a window matrix for window-based redisplay.
|
||||
|
@ -397,6 +403,7 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y
|
|||
|
||||
if (!marginal_areas_changed_p
|
||||
&& !XFRAME (w->frame)->fonts_changed
|
||||
&& !tab_line_changed_p
|
||||
&& !header_line_changed_p
|
||||
&& matrix->window_pixel_left == WINDOW_LEFT_PIXEL_EDGE (w)
|
||||
&& matrix->window_pixel_top == WINDOW_TOP_PIXEL_EDGE (w)
|
||||
|
@ -448,7 +455,11 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y
|
|||
if (w == NULL
|
||||
|| (row == matrix->rows + dim.height - 1
|
||||
&& window_wants_mode_line (w))
|
||||
|| (row == matrix->rows && matrix->header_line_p))
|
||||
|| (row == matrix->rows && matrix->tab_line_p)
|
||||
|| (row == matrix->rows
|
||||
&& !matrix->tab_line_p && matrix->header_line_p)
|
||||
|| (row == (matrix->rows + 1)
|
||||
&& matrix->tab_line_p && matrix->header_line_p))
|
||||
{
|
||||
row->glyphs[TEXT_AREA]
|
||||
= row->glyphs[LEFT_MARGIN_AREA];
|
||||
|
@ -478,6 +489,7 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y
|
|||
Allocate glyph memory from the heap. */
|
||||
if (dim.width > matrix->matrix_w
|
||||
|| new_rows
|
||||
|| tab_line_changed_p
|
||||
|| header_line_changed_p
|
||||
|| marginal_areas_changed_p)
|
||||
{
|
||||
|
@ -493,7 +505,11 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y
|
|||
/* The mode line, if displayed, never has marginal areas. */
|
||||
if ((row == matrix->rows + dim.height - 1
|
||||
&& !(w && window_wants_mode_line (w)))
|
||||
|| (row == matrix->rows && matrix->header_line_p))
|
||||
|| (row == matrix->rows && matrix->tab_line_p)
|
||||
|| (row == matrix->rows
|
||||
&& !matrix->tab_line_p && matrix->header_line_p)
|
||||
|| (row == (matrix->rows + 1)
|
||||
&& matrix->tab_line_p && matrix->header_line_p))
|
||||
{
|
||||
row->glyphs[TEXT_AREA]
|
||||
= row->glyphs[LEFT_MARGIN_AREA];
|
||||
|
@ -539,6 +555,7 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y
|
|||
upper window). Invalidate all rows that are no longer part
|
||||
of the window. */
|
||||
if (!marginal_areas_changed_p
|
||||
&& !tab_line_changed_p
|
||||
&& !header_line_changed_p
|
||||
&& new_rows == 0
|
||||
&& dim.width == matrix->matrix_w
|
||||
|
@ -728,7 +745,7 @@ shift_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int start, in
|
|||
eassert (start >= 0 && start < matrix->nrows);
|
||||
eassert (end >= 0 && end <= matrix->nrows);
|
||||
|
||||
min_y = WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
min_y = WINDOW_TAB_LINE_HEIGHT (w) + WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
max_y = WINDOW_BOX_HEIGHT_NO_MODE_LINE (w);
|
||||
|
||||
for (; start < end; ++start)
|
||||
|
@ -767,6 +784,12 @@ clear_current_matrices (register struct frame *f)
|
|||
clear_glyph_matrix (XWINDOW (f->menu_bar_window)->current_matrix);
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_WINDOW_SYSTEM)
|
||||
/* Clear the matrix of the tab-bar window, if any. */
|
||||
if (WINDOWP (f->tab_bar_window))
|
||||
clear_glyph_matrix (XWINDOW (f->tab_bar_window)->current_matrix);
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR)
|
||||
/* Clear the matrix of the tool-bar window, if any. */
|
||||
if (WINDOWP (f->tool_bar_window))
|
||||
|
@ -792,6 +815,11 @@ clear_desired_matrices (register struct frame *f)
|
|||
clear_glyph_matrix (XWINDOW (f->menu_bar_window)->desired_matrix);
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_WINDOW_SYSTEM)
|
||||
if (WINDOWP (f->tab_bar_window))
|
||||
clear_glyph_matrix (XWINDOW (f->tab_bar_window)->desired_matrix);
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR)
|
||||
if (WINDOWP (f->tool_bar_window))
|
||||
clear_glyph_matrix (XWINDOW (f->tool_bar_window)->desired_matrix);
|
||||
|
@ -857,7 +885,7 @@ blank_row (struct window *w, struct glyph_row *row, int y)
|
|||
{
|
||||
int min_y, max_y;
|
||||
|
||||
min_y = WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
min_y = WINDOW_TAB_LINE_HEIGHT (w) + WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
max_y = WINDOW_BOX_HEIGHT_NO_MODE_LINE (w);
|
||||
|
||||
clear_glyph_row (row);
|
||||
|
@ -1062,7 +1090,7 @@ find_glyph_row_slice (struct glyph_matrix *window_matrix,
|
|||
call to this function really clears it. In addition, this function
|
||||
makes sure the marginal areas of ROW are in sync with the window's
|
||||
display margins. MODE_LINE_P non-zero means we are preparing a
|
||||
glyph row for header line or mode line. */
|
||||
glyph row for tab/header line or mode line. */
|
||||
|
||||
void
|
||||
prepare_desired_row (struct window *w, struct glyph_row *row, bool mode_line_p)
|
||||
|
@ -1077,11 +1105,11 @@ prepare_desired_row (struct window *w, struct glyph_row *row, bool mode_line_p)
|
|||
}
|
||||
if (mode_line_p)
|
||||
{
|
||||
/* Mode and header lines, if displayed, never have marginal
|
||||
/* Mode and header/tab lines, if displayed, never have marginal
|
||||
areas. If we are called with MODE_LINE_P non-zero, we are
|
||||
displaying the mode/header line in this window, and so the
|
||||
displaying the mode/header/tab line in this window, and so the
|
||||
marginal areas of this glyph row should be eliminated. This
|
||||
is needed when the mode/header line is switched on in a
|
||||
is needed when the mode/header/tab line is switched on in a
|
||||
window that has display margins. */
|
||||
if (w->left_margin_cols > 0)
|
||||
row->glyphs[TEXT_AREA] = row->glyphs[LEFT_MARGIN_AREA];
|
||||
|
@ -1099,7 +1127,7 @@ prepare_desired_row (struct window *w, struct glyph_row *row, bool mode_line_p)
|
|||
|
||||
/* Make sure the marginal areas of this row are in sync with
|
||||
what the window wants, when the row actually displays text
|
||||
and not header/mode line. */
|
||||
and not tab/header/mode line. */
|
||||
if (w->left_margin_cols > 0
|
||||
&& (left != row->glyphs[TEXT_AREA] - row->glyphs[LEFT_MARGIN_AREA]))
|
||||
row->glyphs[TEXT_AREA] = row->glyphs[LEFT_MARGIN_AREA] + left;
|
||||
|
@ -1708,8 +1736,8 @@ required_matrix_height (struct window *w)
|
|||
/* One partially visible line at the top and
|
||||
bottom of the window. */
|
||||
+ 2
|
||||
/* 2 for header and mode line. */
|
||||
+ 2);
|
||||
/* 3 for tab, header and mode line. */
|
||||
+ 3);
|
||||
}
|
||||
#endif /* HAVE_WINDOW_SYSTEM */
|
||||
|
||||
|
@ -1862,6 +1890,7 @@ fake_current_matrices (Lisp_Object window)
|
|||
- r->used[LEFT_MARGIN_AREA]
|
||||
- r->used[RIGHT_MARGIN_AREA]);
|
||||
r->mode_line_p = 0;
|
||||
r->tab_line_p = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2106,6 +2135,36 @@ adjust_frame_glyphs_for_window_redisplay (struct frame *f)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_WINDOW_SYSTEM)
|
||||
{
|
||||
/* Allocate/ reallocate matrices of the tab bar window. If we
|
||||
don't have a tab bar window yet, make one. */
|
||||
struct window *w;
|
||||
if (NILP (f->tab_bar_window))
|
||||
{
|
||||
Lisp_Object frame;
|
||||
fset_tab_bar_window (f, make_window ());
|
||||
w = XWINDOW (f->tab_bar_window);
|
||||
XSETFRAME (frame, f);
|
||||
wset_frame (w, frame);
|
||||
w->pseudo_window_p = 1;
|
||||
}
|
||||
else
|
||||
w = XWINDOW (f->tab_bar_window);
|
||||
|
||||
w->pixel_left = 0;
|
||||
w->left_col = 0;
|
||||
w->pixel_top = FRAME_MENU_BAR_HEIGHT (f);
|
||||
w->top_line = FRAME_MENU_BAR_LINES (f);
|
||||
w->total_cols = FRAME_TOTAL_COLS (f);
|
||||
w->pixel_width = (FRAME_PIXEL_WIDTH (f)
|
||||
- 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
|
||||
w->total_lines = FRAME_TAB_BAR_LINES (f);
|
||||
w->pixel_height = FRAME_TAB_BAR_HEIGHT (f);
|
||||
allocate_matrices_for_window_redisplay (w);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR)
|
||||
{
|
||||
/* Allocate/ reallocate matrices of the tool bar window. If we
|
||||
|
@ -2125,8 +2184,8 @@ adjust_frame_glyphs_for_window_redisplay (struct frame *f)
|
|||
|
||||
w->pixel_left = 0;
|
||||
w->left_col = 0;
|
||||
w->pixel_top = FRAME_MENU_BAR_HEIGHT (f);
|
||||
w->top_line = FRAME_MENU_BAR_LINES (f);
|
||||
w->pixel_top = FRAME_MENU_BAR_HEIGHT (f) + FRAME_TAB_BAR_HEIGHT (f);
|
||||
w->top_line = FRAME_MENU_BAR_LINES (f) + FRAME_TAB_BAR_LINES (f);
|
||||
w->total_cols = FRAME_TOTAL_COLS (f);
|
||||
w->pixel_width = (FRAME_PIXEL_WIDTH (f)
|
||||
- 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
|
||||
|
@ -2188,6 +2247,18 @@ free_glyphs (struct frame *f)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_WINDOW_SYSTEM)
|
||||
/* Free the tab bar window and its glyph matrices. */
|
||||
if (!NILP (f->tab_bar_window))
|
||||
{
|
||||
struct window *w = XWINDOW (f->tab_bar_window);
|
||||
free_glyph_matrix (w->desired_matrix);
|
||||
free_glyph_matrix (w->current_matrix);
|
||||
w->desired_matrix = w->current_matrix = NULL;
|
||||
fset_tab_bar_window (f, Qnil);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR)
|
||||
/* Free the tool bar window and its glyph matrices. */
|
||||
if (!NILP (f->tool_bar_window))
|
||||
|
@ -3082,6 +3153,29 @@ update_frame (struct frame *f, bool force_p, bool inhibit_hairy_id_p)
|
|||
update_window (XWINDOW (f->menu_bar_window), true);
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_WINDOW_SYSTEM)
|
||||
/* Update the tab-bar window, if present. */
|
||||
if (WINDOWP (f->tab_bar_window))
|
||||
{
|
||||
struct window *w = XWINDOW (f->tab_bar_window);
|
||||
|
||||
/* Update tab-bar window. */
|
||||
if (w->must_be_updated_p)
|
||||
{
|
||||
Lisp_Object tem;
|
||||
|
||||
update_window (w, true);
|
||||
w->must_be_updated_p = false;
|
||||
|
||||
/* Swap tab-bar strings. We swap because we want to
|
||||
reuse strings. */
|
||||
tem = f->current_tab_bar_string;
|
||||
fset_current_tab_bar_string (f, f->desired_tab_bar_string);
|
||||
fset_desired_tab_bar_string (f, tem);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR)
|
||||
/* Update the tool-bar window, if present. */
|
||||
if (WINDOWP (f->tool_bar_window))
|
||||
|
@ -3408,6 +3502,7 @@ update_window (struct window *w, bool force_p)
|
|||
{
|
||||
struct glyph_row *row, *end;
|
||||
struct glyph_row *mode_line_row;
|
||||
struct glyph_row *tab_line_row;
|
||||
struct glyph_row *header_line_row;
|
||||
int yb;
|
||||
bool changed_p = 0, mouse_face_overwritten_p = 0;
|
||||
|
@ -3420,6 +3515,16 @@ update_window (struct window *w, bool force_p)
|
|||
row = MATRIX_ROW (desired_matrix, 0);
|
||||
end = MATRIX_MODE_LINE_ROW (desired_matrix);
|
||||
|
||||
/* Take note of the tab line, if there is one. We will
|
||||
update it below, after updating all of the window's lines. */
|
||||
if (row->mode_line_p && row->tab_line_p)
|
||||
{
|
||||
tab_line_row = row;
|
||||
++row;
|
||||
}
|
||||
else
|
||||
tab_line_row = NULL;
|
||||
|
||||
/* Take note of the header line, if there is one. We will
|
||||
update it below, after updating all of the window's lines. */
|
||||
if (row->mode_line_p)
|
||||
|
@ -3449,7 +3554,8 @@ update_window (struct window *w, bool force_p)
|
|||
/* Try reusing part of the display by copying. */
|
||||
if (row < end && !desired_matrix->no_scrolling_p)
|
||||
{
|
||||
int rc = scrolling_window (w, header_line_row != NULL);
|
||||
int rc = scrolling_window (w, (tab_line_row != NULL ? 1 : 0)
|
||||
+ (header_line_row != NULL ? 1 : 0));
|
||||
if (rc < 0)
|
||||
{
|
||||
/* All rows were found to be equal. */
|
||||
|
@ -3501,13 +3607,22 @@ update_window (struct window *w, bool force_p)
|
|||
|
||||
set_cursor:
|
||||
|
||||
/* Update the tab line after scrolling because a new tab
|
||||
line would otherwise overwrite lines at the top of the window
|
||||
that can be scrolled. */
|
||||
if (tab_line_row && tab_line_row->enabled_p)
|
||||
{
|
||||
tab_line_row->y = 0;
|
||||
update_window_line (w, 0, &mouse_face_overwritten_p);
|
||||
}
|
||||
|
||||
/* Update the header line after scrolling because a new header
|
||||
line would otherwise overwrite lines at the top of the window
|
||||
that can be scrolled. */
|
||||
if (header_line_row && header_line_row->enabled_p)
|
||||
{
|
||||
header_line_row->y = 0;
|
||||
update_window_line (w, 0, &mouse_face_overwritten_p);
|
||||
header_line_row->y = tab_line_row ? CURRENT_TAB_LINE_HEIGHT (w) : 0;
|
||||
update_window_line (w, tab_line_row ? 1 : 0, &mouse_face_overwritten_p);
|
||||
}
|
||||
|
||||
/* Fix the appearance of overlapping/overlapped rows. */
|
||||
|
@ -4178,7 +4293,7 @@ add_row_entry (struct glyph_row *row)
|
|||
1 if we did scroll. */
|
||||
|
||||
static int
|
||||
scrolling_window (struct window *w, bool header_line_p)
|
||||
scrolling_window (struct window *w, int tab_line_p)
|
||||
{
|
||||
struct glyph_matrix *desired_matrix = w->desired_matrix;
|
||||
struct glyph_matrix *current_matrix = w->current_matrix;
|
||||
|
@ -4191,7 +4306,7 @@ scrolling_window (struct window *w, bool header_line_p)
|
|||
struct redisplay_interface *rif = FRAME_RIF (XFRAME (WINDOW_FRAME (w)));
|
||||
|
||||
/* Skip over rows equal at the start. */
|
||||
for (i = header_line_p; i < current_matrix->nrows - 1; ++i)
|
||||
for (i = tab_line_p; i < current_matrix->nrows - 1; ++i)
|
||||
{
|
||||
struct glyph_row *d = MATRIX_ROW (desired_matrix, i);
|
||||
struct glyph_row *c = MATRIX_ROW (current_matrix, i);
|
||||
|
@ -5318,7 +5433,8 @@ buffer_posn_from_coords (struct window *w, int *x, int *y, struct display_pos *p
|
|||
start position, i.e. it excludes the header-line row, but
|
||||
MATRIX_ROW includes the header-line row. Adjust for a possible
|
||||
header-line row. */
|
||||
it_vpos = it.vpos + window_wants_header_line (w);
|
||||
it_vpos = it.vpos + window_wants_header_line (w)
|
||||
+ window_wants_tab_line (w);
|
||||
if (it_vpos < w->current_matrix->nrows
|
||||
&& (row = MATRIX_ROW (w->current_matrix, it_vpos),
|
||||
row->enabled_p))
|
||||
|
@ -5382,6 +5498,8 @@ mode_line_string (struct window *w, enum window_part part,
|
|||
|
||||
if (part == ON_MODE_LINE)
|
||||
row = MATRIX_MODE_LINE_ROW (w->current_matrix);
|
||||
else if (part == ON_TAB_LINE)
|
||||
row = MATRIX_TAB_LINE_ROW (w->current_matrix);
|
||||
else
|
||||
row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
|
||||
y0 = *y - row->y;
|
||||
|
@ -5563,7 +5681,8 @@ handle_window_change_signal (int sig)
|
|||
structures now. Let that be done later outside of the
|
||||
signal handler. */
|
||||
change_frame_size (XFRAME (frame), width,
|
||||
height - FRAME_MENU_BAR_LINES (XFRAME (frame)),
|
||||
height - FRAME_MENU_BAR_LINES (XFRAME (frame))
|
||||
- FRAME_TAB_BAR_LINES (XFRAME (frame)),
|
||||
0, 1, 0, 0);
|
||||
}
|
||||
}
|
||||
|
@ -6243,7 +6362,8 @@ init_display_interactive (void)
|
|||
change_frame_size (XFRAME (selected_frame),
|
||||
FrameCols (t->display_info.tty),
|
||||
FrameRows (t->display_info.tty)
|
||||
- FRAME_MENU_BAR_LINES (f), 0, 0, 1, 0);
|
||||
- FRAME_MENU_BAR_LINES (f)
|
||||
- FRAME_TAB_BAR_LINES (f), 0, 0, 1, 0);
|
||||
|
||||
/* Delete the initial terminal. */
|
||||
if (--initial_terminal->reference_count == 0
|
||||
|
|
114
src/frame.c
114
src/frame.c
|
@ -69,6 +69,9 @@ static struct frame *last_nonminibuf_frame;
|
|||
/* False means there are no visible garbaged frames. */
|
||||
bool frame_garbaged;
|
||||
|
||||
/* The default tab bar height for future frames. */
|
||||
int frame_default_tab_bar_height;
|
||||
|
||||
/* The default tool bar height for future frames. */
|
||||
#ifdef HAVE_EXT_TOOL_BAR
|
||||
enum { frame_default_tool_bar_height = 0 };
|
||||
|
@ -230,6 +233,35 @@ set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Lisp_Object Vframe_list;
|
||||
|
||||
|
@ -379,6 +411,7 @@ frame_windows_min_size (Lisp_Object frame, Lisp_Object horizontal,
|
|||
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)
|
||||
|
@ -719,6 +752,15 @@ adjust_frame_size (struct frame *f, int new_width, int new_height, int inhibit,
|
|||
if ((FRAME_TERMCAP_P (f) && !pretend) || FRAME_MSDOS_P (f))
|
||||
FrameCols (FRAME_TTY (f)) = new_cols;
|
||||
|
||||
#if defined (HAVE_WINDOW_SYSTEM)
|
||||
if (WINDOWP (f->tab_bar_window))
|
||||
{
|
||||
XWINDOW (f->tab_bar_window)->pixel_width = new_windows_width;
|
||||
XWINDOW (f->tab_bar_window)->total_cols
|
||||
= new_windows_width / unit_width;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR)
|
||||
if (WINDOWP (f->tool_bar_window))
|
||||
{
|
||||
|
@ -838,6 +880,8 @@ make_frame (bool mini_p)
|
|||
f->after_make_frame = false;
|
||||
f->inhibit_horizontal_resize = false;
|
||||
f->inhibit_vertical_resize = false;
|
||||
f->tab_bar_redisplayed = false;
|
||||
f->tab_bar_resized = false;
|
||||
f->tool_bar_redisplayed = false;
|
||||
f->tool_bar_resized = false;
|
||||
f->column_width = 1; /* !FRAME_WINDOW_P value. */
|
||||
|
@ -856,6 +900,7 @@ make_frame (bool mini_p)
|
|||
f->no_accept_focus = false;
|
||||
f->z_group = z_group_none;
|
||||
f->tooltip = false;
|
||||
f->last_tab_bar_item = -1;
|
||||
#ifndef HAVE_EXT_TOOL_BAR
|
||||
f->last_tool_bar_item = -1;
|
||||
#endif
|
||||
|
@ -1084,6 +1129,9 @@ make_initial_frame (void)
|
|||
/* 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);
|
||||
|
||||
|
@ -1142,9 +1190,13 @@ make_terminal_frame (struct terminal *terminal)
|
|||
#endif
|
||||
|
||||
FRAME_MENU_BAR_LINES (f) = NILP (Vmenu_bar_mode) ? 0 : 1;
|
||||
FRAME_LINES (f) = FRAME_LINES (f) - FRAME_MENU_BAR_LINES (f);
|
||||
FRAME_TAB_BAR_LINES (f) = NILP (Vtab_bar_mode) ? 0 : 1;
|
||||
FRAME_LINES (f) = FRAME_LINES (f) - FRAME_MENU_BAR_LINES (f)
|
||||
- FRAME_TAB_BAR_LINES (f);
|
||||
FRAME_MENU_BAR_HEIGHT (f) = FRAME_MENU_BAR_LINES (f) * FRAME_LINE_HEIGHT (f);
|
||||
FRAME_TEXT_HEIGHT (f) = FRAME_TEXT_HEIGHT (f) - FRAME_MENU_BAR_HEIGHT (f);
|
||||
FRAME_TAB_BAR_HEIGHT (f) = FRAME_TAB_BAR_LINES (f) * FRAME_LINE_HEIGHT (f);
|
||||
FRAME_TEXT_HEIGHT (f) = FRAME_TEXT_HEIGHT (f) - FRAME_MENU_BAR_HEIGHT (f)
|
||||
- FRAME_TAB_BAR_HEIGHT (f);
|
||||
|
||||
/* Set the top frame to the newly created frame. */
|
||||
if (FRAMEP (FRAME_TTY (f)->top_frame)
|
||||
|
@ -1266,7 +1318,8 @@ affects all frames on the same terminal device. */)
|
|||
{
|
||||
int width, height;
|
||||
get_tty_size (fileno (FRAME_TTY (f)->input), &width, &height);
|
||||
adjust_frame_size (f, width, height - FRAME_MENU_BAR_LINES (f),
|
||||
adjust_frame_size (f, width, height - FRAME_MENU_BAR_LINES (f)
|
||||
- FRAME_TAB_BAR_LINES (f),
|
||||
5, 0, Qterminal_frame);
|
||||
}
|
||||
|
||||
|
@ -3071,6 +3124,8 @@ store_frame_param (struct frame *f, Lisp_Object prop, Lisp_Object val)
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
@ -3166,6 +3221,8 @@ If FRAME is omitted or nil, return information on the currently selected frame.
|
|||
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;
|
||||
|
@ -3695,6 +3752,7 @@ static const struct frame_parm_table frame_parms[] =
|
|||
{"vertical-scroll-bars", SYMBOL_INDEX (Qvertical_scroll_bars)},
|
||||
{"horizontal-scroll-bars", SYMBOL_INDEX (Qhorizontal_scroll_bars)},
|
||||
{"visibility", SYMBOL_INDEX (Qvisibility)},
|
||||
{"tab-bar-lines", SYMBOL_INDEX (Qtab_bar_lines)},
|
||||
{"tool-bar-lines", SYMBOL_INDEX (Qtool_bar_lines)},
|
||||
{"scroll-bar-foreground", SYMBOL_INDEX (Qscroll_bar_foreground)},
|
||||
{"scroll-bar-background", SYMBOL_INDEX (Qscroll_bar_background)},
|
||||
|
@ -4450,6 +4508,8 @@ gui_set_font (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
|
|||
#ifdef HAVE_X_WINDOWS
|
||||
store_frame_param (f, Qfont_parameter, font_param);
|
||||
#endif
|
||||
/* Recalculate tabbar height. */
|
||||
f->n_tab_bar_rows = 0;
|
||||
/* Recalculate toolbar height. */
|
||||
f->n_tool_bar_rows = 0;
|
||||
|
||||
|
@ -5390,8 +5450,8 @@ On Nextstep, this just calls `ns-parse-geometry'. */)
|
|||
#define DEFAULT_COLS 80
|
||||
|
||||
long
|
||||
gui_figure_window_size (struct frame *f, Lisp_Object parms, bool toolbar_p,
|
||||
int *x_width, int *x_height)
|
||||
gui_figure_window_size (struct frame *f, Lisp_Object parms, bool tabbar_p,
|
||||
bool toolbar_p, int *x_width, int *x_height)
|
||||
{
|
||||
Lisp_Object height, width, user_size, top, left, user_position;
|
||||
long window_prompting = 0;
|
||||
|
@ -5411,6 +5471,36 @@ gui_figure_window_size (struct frame *f, Lisp_Object parms, bool toolbar_p,
|
|||
f->top_pos = 0;
|
||||
f->left_pos = 0;
|
||||
|
||||
/* Calculate a tab bar height so that the user gets a text display
|
||||
area of the size he specified with -g or via .Xdefaults. Later
|
||||
changes of the tab bar height don't change the frame size. This
|
||||
is done so that users can create tall Emacs frames without having
|
||||
to guess how tall the tab bar will get. */
|
||||
if (tabbar_p && FRAME_TAB_BAR_LINES (f))
|
||||
{
|
||||
if (frame_default_tab_bar_height)
|
||||
FRAME_TAB_BAR_HEIGHT (f) = frame_default_tab_bar_height;
|
||||
else
|
||||
{
|
||||
int margin, relief;
|
||||
|
||||
relief = (tab_bar_button_relief < 0
|
||||
? DEFAULT_TAB_BAR_BUTTON_RELIEF
|
||||
: min (tab_bar_button_relief, 1000000));
|
||||
|
||||
if (RANGED_FIXNUMP (1, Vtab_bar_button_margin, INT_MAX))
|
||||
margin = XFIXNAT (Vtab_bar_button_margin);
|
||||
else if (CONSP (Vtab_bar_button_margin)
|
||||
&& RANGED_FIXNUMP (1, XCDR (Vtab_bar_button_margin), INT_MAX))
|
||||
margin = XFIXNAT (XCDR (Vtab_bar_button_margin));
|
||||
else
|
||||
margin = 0;
|
||||
|
||||
FRAME_TAB_BAR_HEIGHT (f)
|
||||
= DEFAULT_TAB_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate a tool bar height so that the user gets a text display
|
||||
area of the size he specified with -g or via .Xdefaults. Later
|
||||
changes of the tool bar height don't change the frame size. This
|
||||
|
@ -5837,6 +5927,7 @@ syms_of_frame (void)
|
|||
DEFSYM (Qtitle_bar_size, "title-bar-size");
|
||||
DEFSYM (Qmenu_bar_external, "menu-bar-external");
|
||||
DEFSYM (Qmenu_bar_size, "menu-bar-size");
|
||||
DEFSYM (Qtab_bar_size, "tab-bar-size");
|
||||
DEFSYM (Qtool_bar_external, "tool-bar-external");
|
||||
DEFSYM (Qtool_bar_size, "tool-bar-size");
|
||||
/* The following are used for frame_size_history. */
|
||||
|
@ -5860,7 +5951,9 @@ syms_of_frame (void)
|
|||
DEFSYM (Qx_net_wm_state, "x-net-wm-state");
|
||||
DEFSYM (Qx_handle_net_wm_state, "x-handle-net-wm-state");
|
||||
DEFSYM (Qtb_size_cb, "tb-size-cb");
|
||||
DEFSYM (Qupdate_frame_tab_bar, "update-frame-tab-bar");
|
||||
DEFSYM (Qupdate_frame_tool_bar, "update-frame-tool-bar");
|
||||
DEFSYM (Qfree_frame_tab_bar, "free-frame-tab-bar");
|
||||
DEFSYM (Qfree_frame_tool_bar, "free-frame-tool-bar");
|
||||
DEFSYM (Qx_set_menu_bar_lines, "x-set-menu-bar-lines");
|
||||
DEFSYM (Qchange_frame_size, "change-frame-size");
|
||||
|
@ -5910,6 +6003,7 @@ syms_of_frame (void)
|
|||
DEFSYM (Qscroll_bar_width, "scroll-bar-width");
|
||||
DEFSYM (Qsticky, "sticky");
|
||||
DEFSYM (Qtitle, "title");
|
||||
DEFSYM (Qtab_bar_lines, "tab-bar-lines");
|
||||
DEFSYM (Qtool_bar_lines, "tool-bar-lines");
|
||||
DEFSYM (Qtool_bar_position, "tool-bar-position");
|
||||
DEFSYM (Qunsplittable, "unsplittable");
|
||||
|
@ -6071,6 +6165,14 @@ either customize it (see the info node `Easy Customization')
|
|||
or call the function `menu-bar-mode'. */);
|
||||
Vmenu_bar_mode = Qt;
|
||||
|
||||
DEFVAR_LISP ("tab-bar-mode", Vtab_bar_mode,
|
||||
doc: /* Non-nil if Tab-Bar mode is enabled.
|
||||
See the command `tab-bar-mode' for a description of this minor mode.
|
||||
Setting this variable directly does not take effect;
|
||||
either customize it (see the info node `Easy Customization')
|
||||
or call the function `tab-bar-mode'. */);
|
||||
Vtab_bar_mode = Qnil;
|
||||
|
||||
DEFVAR_LISP ("tool-bar-mode", Vtool_bar_mode,
|
||||
doc: /* Non-nil if Tool-Bar mode is enabled.
|
||||
See the command `tool-bar-mode' for a description of this minor mode.
|
||||
|
@ -6200,7 +6302,7 @@ any of the parameters listed above, Emacs may try to enlarge the frame
|
|||
even if this option is non-nil. */);
|
||||
#if defined (HAVE_WINDOW_SYSTEM)
|
||||
#if defined (USE_LUCID) || defined (USE_MOTIF) || defined (HAVE_NTGUI)
|
||||
frame_inhibit_implied_resize = list1 (Qtool_bar_lines);
|
||||
frame_inhibit_implied_resize = list2 (Qtab_bar_lines, Qtool_bar_lines);
|
||||
#else
|
||||
frame_inhibit_implied_resize = Qnil;
|
||||
#endif
|
||||
|
|
72
src/frame.h
72
src/frame.h
|
@ -181,6 +181,15 @@ struct frame
|
|||
Lisp_Object menu_bar_window;
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_WINDOW_SYSTEM)
|
||||
/* A window used to display the tab-bar of a frame. */
|
||||
Lisp_Object tab_bar_window;
|
||||
|
||||
/* Desired and current contents displayed in that window. */
|
||||
Lisp_Object desired_tab_bar_string;
|
||||
Lisp_Object current_tab_bar_string;
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR)
|
||||
/* A window used to display the tool-bar of a frame. */
|
||||
Lisp_Object tool_bar_window;
|
||||
|
@ -201,6 +210,9 @@ struct frame
|
|||
Lisp_Object font_data;
|
||||
#endif
|
||||
|
||||
/* Desired and current tab-bar items. */
|
||||
Lisp_Object tab_bar_items;
|
||||
|
||||
/* Desired and current tool-bar items. */
|
||||
Lisp_Object tool_bar_items;
|
||||
/* tool_bar_items should be the last Lisp_Object member. */
|
||||
|
@ -208,6 +220,11 @@ struct frame
|
|||
/* Cache of realized faces. */
|
||||
struct face_cache *face_cache;
|
||||
|
||||
#if defined (HAVE_WINDOW_SYSTEM)
|
||||
/* Tab-bar item index of the item on which a mouse button was pressed. */
|
||||
int last_tab_bar_item;
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR)
|
||||
/* Tool-bar item index of the item on which a mouse button was pressed. */
|
||||
int last_tool_bar_item;
|
||||
|
@ -256,6 +273,12 @@ struct frame
|
|||
/* Set to true when current redisplay has updated frame. */
|
||||
bool_bf updated_p : 1;
|
||||
|
||||
#if defined (HAVE_WINDOW_SYSTEM)
|
||||
/* Set to true to minimize tab-bar height even when
|
||||
auto-resize-tab-bar is set to grow-only. */
|
||||
bool_bf minimize_tab_bar_window_p : 1;
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR)
|
||||
/* Set to true to minimize tool-bar height even when
|
||||
auto-resize-tool-bar is set to grow-only. */
|
||||
|
@ -404,6 +427,10 @@ struct frame
|
|||
/* Set to true after this frame was made by `make-frame'. */
|
||||
bool_bf after_make_frame : 1;
|
||||
|
||||
/* Whether the tab bar height change should be taken into account. */
|
||||
bool_bf tab_bar_redisplayed : 1;
|
||||
bool_bf tab_bar_resized : 1;
|
||||
|
||||
/* Whether the tool bar height change should be taken into account. */
|
||||
bool_bf tool_bar_redisplayed : 1;
|
||||
bool_bf tool_bar_resized : 1;
|
||||
|
@ -435,6 +462,15 @@ struct frame
|
|||
last time run_window_change_functions was called on it. */
|
||||
ptrdiff_t number_of_windows;
|
||||
|
||||
/* Number of lines (rounded up) of tab bar. REMOVE THIS */
|
||||
int tab_bar_lines;
|
||||
|
||||
/* Height of frame internal tab bar in pixels. */
|
||||
int tab_bar_height;
|
||||
|
||||
int n_tab_bar_rows;
|
||||
int n_tab_bar_items;
|
||||
|
||||
/* Number of lines (rounded up) of tool bar. REMOVE THIS */
|
||||
int tool_bar_lines;
|
||||
|
||||
|
@ -701,6 +737,28 @@ fset_title (struct frame *f, Lisp_Object val)
|
|||
f->title = val;
|
||||
}
|
||||
INLINE void
|
||||
fset_tab_bar_items (struct frame *f, Lisp_Object val)
|
||||
{
|
||||
f->tab_bar_items = val;
|
||||
}
|
||||
#if defined (HAVE_WINDOW_SYSTEM)
|
||||
INLINE void
|
||||
fset_tab_bar_window (struct frame *f, Lisp_Object val)
|
||||
{
|
||||
f->tab_bar_window = val;
|
||||
}
|
||||
INLINE void
|
||||
fset_current_tab_bar_string (struct frame *f, Lisp_Object val)
|
||||
{
|
||||
f->current_tab_bar_string = val;
|
||||
}
|
||||
INLINE void
|
||||
fset_desired_tab_bar_string (struct frame *f, Lisp_Object val)
|
||||
{
|
||||
f->desired_tab_bar_string = val;
|
||||
}
|
||||
#endif /* HAVE_WINDOW_SYSTEM */
|
||||
INLINE void
|
||||
fset_tool_bar_items (struct frame *f, Lisp_Object val)
|
||||
{
|
||||
f->tool_bar_items = val;
|
||||
|
@ -878,6 +936,12 @@ default_pixels_per_inch_y (void)
|
|||
/* Pixel height of frame F's menu bar. */
|
||||
#define FRAME_MENU_BAR_HEIGHT(f) (f)->menu_bar_height
|
||||
|
||||
/* Number of lines of frame F used for the tab-bar. */
|
||||
#define FRAME_TAB_BAR_LINES(f) (f)->tab_bar_lines
|
||||
|
||||
/* Pixel height of frame F's tab-bar. */
|
||||
#define FRAME_TAB_BAR_HEIGHT(f) (f)->tab_bar_height
|
||||
|
||||
/* True if this frame should display a tool bar
|
||||
in a way that does not use any text lines. */
|
||||
#ifdef HAVE_EXT_TOOL_BAR
|
||||
|
@ -901,11 +965,11 @@ default_pixels_per_inch_y (void)
|
|||
|
||||
/* Lines above the top-most window in frame F. */
|
||||
#define FRAME_TOP_MARGIN(F) \
|
||||
(FRAME_MENU_BAR_LINES (F) + FRAME_TOOL_BAR_LINES (F))
|
||||
(FRAME_MENU_BAR_LINES (F) + FRAME_TAB_BAR_LINES (F) + FRAME_TOOL_BAR_LINES (F))
|
||||
|
||||
/* Pixel height of frame F's top margin. */
|
||||
#define FRAME_TOP_MARGIN_HEIGHT(F) \
|
||||
(FRAME_MENU_BAR_HEIGHT (F) + FRAME_TOOL_BAR_HEIGHT (F))
|
||||
(FRAME_MENU_BAR_HEIGHT (F) + FRAME_TAB_BAR_HEIGHT (F) + FRAME_TOOL_BAR_HEIGHT (F))
|
||||
|
||||
/* True if this frame should display a menu bar
|
||||
in a way that does not use any text lines. */
|
||||
|
@ -1255,6 +1319,8 @@ SET_FRAME_VISIBLE (struct frame *f, int v)
|
|||
extern Lisp_Object selected_frame;
|
||||
extern Lisp_Object old_selected_frame;
|
||||
|
||||
extern int frame_default_tab_bar_height;
|
||||
|
||||
#ifndef HAVE_EXT_TOOL_BAR
|
||||
extern int frame_default_tool_bar_height;
|
||||
#endif
|
||||
|
@ -1566,7 +1632,7 @@ extern void gui_set_horizontal_scroll_bars (struct frame *, Lisp_Object, Lisp_Ob
|
|||
extern void gui_set_scroll_bar_width (struct frame *, Lisp_Object, Lisp_Object);
|
||||
extern void gui_set_scroll_bar_height (struct frame *, Lisp_Object, Lisp_Object);
|
||||
|
||||
extern long gui_figure_window_size (struct frame *, Lisp_Object, bool, int *, int *);
|
||||
extern long gui_figure_window_size (struct frame *, Lisp_Object, bool, bool, int *, int *);
|
||||
|
||||
extern void gui_set_alpha (struct frame *, Lisp_Object, Lisp_Object);
|
||||
extern void gui_set_no_special_glyphs (struct frame *, Lisp_Object, Lisp_Object);
|
||||
|
|
12
src/fringe.c
12
src/fringe.c
|
@ -634,7 +634,8 @@ draw_fringe_bitmap_1 (struct window *w, struct glyph_row *row, int left_p, int o
|
|||
/* Clear left fringe if no bitmap to draw or if bitmap doesn't fill
|
||||
the fringe. */
|
||||
p.bx = -1;
|
||||
header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
header_line_height = WINDOW_TAB_LINE_HEIGHT (w)
|
||||
+ WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
p.by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, row->y));
|
||||
p.ny = row->visible_height;
|
||||
if (left_p)
|
||||
|
@ -1091,7 +1092,8 @@ update_window_fringes (struct window *w, bool keep_current_p)
|
|||
struct glyph_row *row1;
|
||||
int top_ind_max_y;
|
||||
|
||||
top_ind_min_y = WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
top_ind_min_y = WINDOW_TAB_LINE_HEIGHT (w)
|
||||
+ WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
top_ind_max_y = top_ind_min_y + fb->height;
|
||||
if (top_ind_max_y > yb)
|
||||
top_ind_max_y = yb;
|
||||
|
@ -1148,8 +1150,10 @@ update_window_fringes (struct window *w, bool keep_current_p)
|
|||
|
||||
bot_ind_max_y = row->y + row->visible_height;
|
||||
bot_ind_min_y = bot_ind_max_y - fb->height;
|
||||
if (bot_ind_min_y < WINDOW_HEADER_LINE_HEIGHT (w))
|
||||
bot_ind_min_y = WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
if (bot_ind_min_y < WINDOW_TAB_LINE_HEIGHT (w)
|
||||
+ WINDOW_HEADER_LINE_HEIGHT (w))
|
||||
bot_ind_min_y = WINDOW_TAB_LINE_HEIGHT (w)
|
||||
+ WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
|
||||
for (y = row->y, rn = bot_ind_rn - 1;
|
||||
y >= bot_ind_min_y && rn >= 0;
|
||||
|
|
436
src/keyboard.c
436
src/keyboard.c
|
@ -2385,7 +2385,8 @@ read_char (int commandflag, Lisp_Object map,
|
|||
if (used_mouse_menu
|
||||
/* Also check was_disabled so last-nonmenu-event won't return
|
||||
a bad value when submenus are involved. (Bug#447) */
|
||||
&& (EQ (c, Qtool_bar) || EQ (c, Qmenu_bar) || was_disabled))
|
||||
&& (EQ (c, Qtool_bar) || EQ (c, Qtab_bar) || EQ (c, Qmenu_bar)
|
||||
|| was_disabled))
|
||||
*used_mouse_menu = true;
|
||||
|
||||
goto reread_for_input_method;
|
||||
|
@ -2666,6 +2667,7 @@ read_char (int commandflag, Lisp_Object map,
|
|||
&& !NILP (prev_event)
|
||||
&& EVENT_HAS_PARAMETERS (prev_event)
|
||||
&& !EQ (XCAR (prev_event), Qmenu_bar)
|
||||
&& !EQ (XCAR (prev_event), Qtab_bar)
|
||||
&& !EQ (XCAR (prev_event), Qtool_bar)
|
||||
/* Don't bring up a menu if we already have another event. */
|
||||
&& !CONSP (Vunread_command_events))
|
||||
|
@ -2930,7 +2932,7 @@ read_char (int commandflag, Lisp_Object map,
|
|||
posn = POSN_POSN (xevent_start (c));
|
||||
/* Handle menu-bar events:
|
||||
insert the dummy prefix event `menu-bar'. */
|
||||
if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar))
|
||||
if (EQ (posn, Qmenu_bar) || EQ (posn, Qtab_bar) || EQ (posn, Qtool_bar))
|
||||
{
|
||||
/* Change menu-bar to (menu-bar) as the event "position". */
|
||||
POSN_SET_POSN (xevent_start (c), list1 (posn));
|
||||
|
@ -3974,6 +3976,7 @@ kbd_buffer_get_event (KBOARD **kbp,
|
|||
if (used_mouse_menu
|
||||
&& !EQ (event->ie.frame_or_window, event->ie.arg)
|
||||
&& (event->kind == MENU_BAR_EVENT
|
||||
|| event->kind == TAB_BAR_EVENT
|
||||
|| event->kind == TOOL_BAR_EVENT))
|
||||
*used_mouse_menu = true;
|
||||
#endif
|
||||
|
@ -5012,7 +5015,7 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
|
|||
int xret = 0, yret = 0;
|
||||
/* The window or frame under frame pixel coordinates (x,y) */
|
||||
Lisp_Object window_or_frame = f
|
||||
? window_from_coordinates (f, XFIXNUM (x), XFIXNUM (y), &part, 0)
|
||||
? window_from_coordinates (f, XFIXNUM (x), XFIXNUM (y), &part, 0, 0)
|
||||
: Qnil;
|
||||
|
||||
if (WINDOWP (window_or_frame))
|
||||
|
@ -5036,17 +5039,21 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
|
|||
if (part == ON_TEXT)
|
||||
{
|
||||
xret = XFIXNUM (x) - window_box_left (w, TEXT_AREA);
|
||||
yret = wy - WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
yret = wy - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
}
|
||||
/* For mode line and header line clicks, return X, Y relative to
|
||||
the left window edge. Use mode_line_string to look for a
|
||||
string on the click position. */
|
||||
else if (part == ON_MODE_LINE || part == ON_HEADER_LINE)
|
||||
else if (part == ON_MODE_LINE || part == ON_TAB_LINE
|
||||
|| part == ON_HEADER_LINE)
|
||||
{
|
||||
Lisp_Object string;
|
||||
ptrdiff_t charpos;
|
||||
|
||||
posn = (part == ON_MODE_LINE) ? Qmode_line : Qheader_line;
|
||||
posn = (part == ON_MODE_LINE ? Qmode_line
|
||||
: (part == ON_TAB_LINE ? Qtab_line
|
||||
: Qheader_line));
|
||||
|
||||
/* Note that mode_line_string takes COL, ROW as pixels and
|
||||
converts them to characters. */
|
||||
col = wx;
|
||||
|
@ -5075,7 +5082,7 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
|
|||
if (STRINGP (string))
|
||||
string_info = Fcons (string, make_fixnum (charpos));
|
||||
xret = wx;
|
||||
yret = wy - WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
yret = wy - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
}
|
||||
else if (part == ON_LEFT_FRINGE)
|
||||
{
|
||||
|
@ -5085,7 +5092,7 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
|
|||
dx = wx
|
||||
- (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
|
||||
? 0 : window_box_width (w, LEFT_MARGIN_AREA));
|
||||
dy = yret = wy - WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
dy = yret = wy - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
}
|
||||
else if (part == ON_RIGHT_FRINGE)
|
||||
{
|
||||
|
@ -5098,7 +5105,7 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
|
|||
- (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
|
||||
? window_box_width (w, RIGHT_MARGIN_AREA)
|
||||
: 0);
|
||||
dy = yret = wy - WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
dy = yret = wy - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
}
|
||||
else if (part == ON_VERTICAL_BORDER)
|
||||
{
|
||||
|
@ -5953,6 +5960,16 @@ make_lispy_event (struct input_event *event)
|
|||
/* Make an event (select-window (WINDOW)). */
|
||||
return list2 (Qselect_window, list1 (event->frame_or_window));
|
||||
|
||||
case TAB_BAR_EVENT:
|
||||
if (EQ (event->arg, event->frame_or_window))
|
||||
/* This is the prefix key. We translate this to
|
||||
`(tab_bar)' because the code in keyboard.c for tab bar
|
||||
events, which we use, relies on this. */
|
||||
return list1 (Qtab_bar);
|
||||
else if (SYMBOLP (event->arg))
|
||||
return apply_modifiers (event->modifiers, event->arg);
|
||||
return event->arg;
|
||||
|
||||
case TOOL_BAR_EVENT:
|
||||
if (EQ (event->arg, event->frame_or_window))
|
||||
/* This is the prefix key. We translate this to
|
||||
|
@ -6730,6 +6747,7 @@ lucid_event_type_list_p (Lisp_Object object)
|
|||
if (EQ (XCAR (object), Qhelp_echo)
|
||||
|| EQ (XCAR (object), Qvertical_line)
|
||||
|| EQ (XCAR (object), Qmode_line)
|
||||
|| EQ (XCAR (object), Qtab_line)
|
||||
|| EQ (XCAR (object), Qheader_line))
|
||||
return 0;
|
||||
|
||||
|
@ -7889,6 +7907,389 @@ parse_menu_item (Lisp_Object item, int inmenubar)
|
|||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
Tab-bars
|
||||
***********************************************************************/
|
||||
|
||||
/* A vector holding tab bar items while they are parsed in function
|
||||
tab_bar_items. Each item occupies TAB_BAR_ITEM_NSCLOTS elements
|
||||
in the vector. */
|
||||
|
||||
static Lisp_Object tab_bar_items_vector;
|
||||
|
||||
/* A vector holding the result of parse_tab_bar_item. Layout is like
|
||||
the one for a single item in tab_bar_items_vector. */
|
||||
|
||||
static Lisp_Object tab_bar_item_properties;
|
||||
|
||||
/* Next free index in tab_bar_items_vector. */
|
||||
|
||||
static int ntab_bar_items;
|
||||
|
||||
/* Function prototypes. */
|
||||
|
||||
static void init_tab_bar_items (Lisp_Object);
|
||||
static void process_tab_bar_item (Lisp_Object, Lisp_Object, Lisp_Object,
|
||||
void *);
|
||||
static bool parse_tab_bar_item (Lisp_Object, Lisp_Object);
|
||||
static void append_tab_bar_item (void);
|
||||
|
||||
|
||||
/* Return a vector of tab bar items for keymaps currently in effect.
|
||||
Reuse vector REUSE if non-nil. Return in *NITEMS the number of
|
||||
tab bar items found. */
|
||||
|
||||
Lisp_Object
|
||||
tab_bar_items (Lisp_Object reuse, int *nitems)
|
||||
{
|
||||
Lisp_Object *maps;
|
||||
Lisp_Object mapsbuf[3];
|
||||
ptrdiff_t nmaps, i;
|
||||
Lisp_Object oquit;
|
||||
Lisp_Object *tmaps;
|
||||
USE_SAFE_ALLOCA;
|
||||
|
||||
*nitems = 0;
|
||||
|
||||
/* In order to build the menus, we need to call the keymap
|
||||
accessors. They all call maybe_quit. But this function is called
|
||||
during redisplay, during which a quit is fatal. So inhibit
|
||||
quitting while building the menus. We do this instead of
|
||||
specbind because (1) errors will clear it anyway and (2) this
|
||||
avoids risk of specpdl overflow. */
|
||||
oquit = Vinhibit_quit;
|
||||
Vinhibit_quit = Qt;
|
||||
|
||||
/* Initialize tab_bar_items_vector and protect it from GC. */
|
||||
init_tab_bar_items (reuse);
|
||||
|
||||
/* Build list of keymaps in maps. Set nmaps to the number of maps
|
||||
to process. */
|
||||
|
||||
/* Should overriding-terminal-local-map and overriding-local-map apply? */
|
||||
if (!NILP (Voverriding_local_map_menu_flag)
|
||||
&& !NILP (Voverriding_local_map))
|
||||
{
|
||||
/* Yes, use them (if non-nil) as well as the global map. */
|
||||
maps = mapsbuf;
|
||||
nmaps = 0;
|
||||
if (!NILP (KVAR (current_kboard, Voverriding_terminal_local_map)))
|
||||
maps[nmaps++] = KVAR (current_kboard, Voverriding_terminal_local_map);
|
||||
if (!NILP (Voverriding_local_map))
|
||||
maps[nmaps++] = Voverriding_local_map;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No, so use major and minor mode keymaps and keymap property.
|
||||
Note that tab-bar bindings in the local-map and keymap
|
||||
properties may not work reliably, as they are only
|
||||
recognized when the tab-bar (or mode-line) is updated,
|
||||
which does not normally happen after every command. */
|
||||
ptrdiff_t nminor = current_minor_maps (NULL, &tmaps);
|
||||
SAFE_NALLOCA (maps, 1, nminor + 4);
|
||||
nmaps = 0;
|
||||
Lisp_Object tem = KVAR (current_kboard, Voverriding_terminal_local_map);
|
||||
if (!NILP (tem) && !NILP (Voverriding_local_map_menu_flag))
|
||||
maps[nmaps++] = tem;
|
||||
if (tem = get_local_map (PT, current_buffer, Qkeymap), !NILP (tem))
|
||||
maps[nmaps++] = tem;
|
||||
if (nminor != 0)
|
||||
{
|
||||
memcpy (maps + nmaps, tmaps, nminor * sizeof (maps[0]));
|
||||
nmaps += nminor;
|
||||
}
|
||||
maps[nmaps++] = get_local_map (PT, current_buffer, Qlocal_map);
|
||||
}
|
||||
|
||||
/* Add global keymap at the end. */
|
||||
maps[nmaps++] = current_global_map;
|
||||
|
||||
/* Process maps in reverse order and look up in each map the prefix
|
||||
key `tab-bar'. */
|
||||
for (i = nmaps - 1; i >= 0; --i)
|
||||
if (!NILP (maps[i]))
|
||||
{
|
||||
Lisp_Object keymap;
|
||||
|
||||
keymap = get_keymap (access_keymap (maps[i], Qtab_bar, 1, 0, 1), 0, 1);
|
||||
if (CONSP (keymap))
|
||||
map_keymap (keymap, process_tab_bar_item, Qnil, NULL, 1);
|
||||
}
|
||||
|
||||
Vinhibit_quit = oquit;
|
||||
*nitems = ntab_bar_items / TAB_BAR_ITEM_NSLOTS;
|
||||
SAFE_FREE ();
|
||||
return tab_bar_items_vector;
|
||||
}
|
||||
|
||||
|
||||
/* Process the definition of KEY which is DEF. */
|
||||
|
||||
static void
|
||||
process_tab_bar_item (Lisp_Object key, Lisp_Object def, Lisp_Object data, void *args)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (EQ (def, Qundefined))
|
||||
{
|
||||
/* If a map has an explicit `undefined' as definition,
|
||||
discard any previously made item. */
|
||||
for (i = 0; i < ntab_bar_items; i += TAB_BAR_ITEM_NSLOTS)
|
||||
{
|
||||
Lisp_Object *v = XVECTOR (tab_bar_items_vector)->contents + i;
|
||||
|
||||
if (EQ (key, v[TAB_BAR_ITEM_KEY]))
|
||||
{
|
||||
if (ntab_bar_items > i + TAB_BAR_ITEM_NSLOTS)
|
||||
memmove (v, v + TAB_BAR_ITEM_NSLOTS,
|
||||
((ntab_bar_items - i - TAB_BAR_ITEM_NSLOTS)
|
||||
* word_size));
|
||||
ntab_bar_items -= TAB_BAR_ITEM_NSLOTS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (parse_tab_bar_item (key, def))
|
||||
/* Append a new tab bar item to tab_bar_items_vector. Accept
|
||||
more than one definition for the same key. */
|
||||
append_tab_bar_item ();
|
||||
}
|
||||
|
||||
/* Access slot with index IDX of vector tab_bar_item_properties. */
|
||||
#define PROP(IDX) AREF (tab_bar_item_properties, (IDX))
|
||||
static void
|
||||
set_prop_tab_bar (ptrdiff_t idx, Lisp_Object val)
|
||||
{
|
||||
ASET (tab_bar_item_properties, idx, val);
|
||||
}
|
||||
|
||||
|
||||
/* Parse a tab bar item specification ITEM for key KEY and return the
|
||||
result in tab_bar_item_properties. Value is false if ITEM is
|
||||
invalid.
|
||||
|
||||
ITEM is a list `(menu-item CAPTION BINDING PROPS...)'.
|
||||
|
||||
CAPTION is the caption of the item, If it's not a string, it is
|
||||
evaluated to get a string.
|
||||
|
||||
BINDING is the tab bar item's binding. Tab-bar items with keymaps
|
||||
as binding are currently ignored.
|
||||
|
||||
The following properties are recognized:
|
||||
|
||||
- `:enable FORM'.
|
||||
|
||||
FORM is evaluated and specifies whether the tab bar item is
|
||||
enabled or disabled.
|
||||
|
||||
- `:visible FORM'
|
||||
|
||||
FORM is evaluated and specifies whether the tab bar item is visible.
|
||||
|
||||
- `:filter FUNCTION'
|
||||
|
||||
FUNCTION is invoked with one parameter `(quote BINDING)'. Its
|
||||
result is stored as the new binding.
|
||||
|
||||
- `:button (TYPE SELECTED)'
|
||||
|
||||
TYPE must be one of `:radio' or `:toggle'. SELECTED is evaluated
|
||||
and specifies whether the button is selected (pressed) or not.
|
||||
|
||||
- `:image IMAGES'
|
||||
|
||||
IMAGES is either a single image specification or a vector of four
|
||||
image specifications. See enum tab_bar_item_images.
|
||||
|
||||
- `:help HELP-STRING'.
|
||||
|
||||
Gives a help string to display for the tab bar item.
|
||||
|
||||
- `:label LABEL-STRING'.
|
||||
|
||||
A text label to show with the tab bar button if labels are enabled. */
|
||||
|
||||
static bool
|
||||
parse_tab_bar_item (Lisp_Object key, Lisp_Object item)
|
||||
{
|
||||
Lisp_Object filter = Qnil;
|
||||
Lisp_Object caption;
|
||||
int i;
|
||||
|
||||
/* Definition looks like `(menu-item CAPTION BINDING PROPS...)'.
|
||||
Rule out items that aren't lists, don't start with
|
||||
`menu-item' or whose rest following `tab-bar-item' is not a
|
||||
list. */
|
||||
if (!CONSP (item))
|
||||
return 0;
|
||||
|
||||
/* As an exception, allow old-style menu separators. */
|
||||
if (STRINGP (XCAR (item)))
|
||||
item = list1 (XCAR (item));
|
||||
else if (!EQ (XCAR (item), Qmenu_item)
|
||||
|| (item = XCDR (item), !CONSP (item)))
|
||||
return 0;
|
||||
|
||||
/* Create tab_bar_item_properties vector if necessary. Reset it to
|
||||
defaults. */
|
||||
if (VECTORP (tab_bar_item_properties))
|
||||
{
|
||||
for (i = 0; i < TAB_BAR_ITEM_NSLOTS; ++i)
|
||||
set_prop_tab_bar (i, Qnil);
|
||||
}
|
||||
else
|
||||
tab_bar_item_properties = make_nil_vector (TAB_BAR_ITEM_NSLOTS);
|
||||
|
||||
/* Set defaults. */
|
||||
set_prop_tab_bar (TAB_BAR_ITEM_KEY, key);
|
||||
set_prop_tab_bar (TAB_BAR_ITEM_ENABLED_P, Qt);
|
||||
|
||||
/* Get the caption of the item. If the caption is not a string,
|
||||
evaluate it to get a string. If we don't get a string, skip this
|
||||
item. */
|
||||
caption = XCAR (item);
|
||||
if (!STRINGP (caption))
|
||||
{
|
||||
caption = menu_item_eval_property (caption);
|
||||
if (!STRINGP (caption))
|
||||
return 0;
|
||||
}
|
||||
set_prop_tab_bar (TAB_BAR_ITEM_CAPTION, caption);
|
||||
|
||||
/* If the rest following the caption is not a list, the menu item is
|
||||
either a separator, or invalid. */
|
||||
item = XCDR (item);
|
||||
if (!CONSP (item))
|
||||
{
|
||||
if (menu_separator_name_p (SSDATA (caption)))
|
||||
{
|
||||
set_prop_tab_bar (TAB_BAR_ITEM_ENABLED_P, Qnil);
|
||||
set_prop_tab_bar (TAB_BAR_ITEM_SELECTED_P, Qnil);
|
||||
set_prop_tab_bar (TAB_BAR_ITEM_CAPTION, Qnil);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Store the binding. */
|
||||
set_prop_tab_bar (TAB_BAR_ITEM_BINDING, XCAR (item));
|
||||
item = XCDR (item);
|
||||
|
||||
/* Ignore cached key binding, if any. */
|
||||
if (CONSP (item) && CONSP (XCAR (item)))
|
||||
item = XCDR (item);
|
||||
|
||||
/* Process the rest of the properties. */
|
||||
for (; CONSP (item) && CONSP (XCDR (item)); item = XCDR (XCDR (item)))
|
||||
{
|
||||
Lisp_Object ikey, value;
|
||||
|
||||
ikey = XCAR (item);
|
||||
value = XCAR (XCDR (item));
|
||||
|
||||
if (EQ (ikey, QCenable))
|
||||
{
|
||||
/* `:enable FORM'. */
|
||||
if (!NILP (Venable_disabled_menus_and_buttons))
|
||||
set_prop_tab_bar (TAB_BAR_ITEM_ENABLED_P, Qt);
|
||||
else
|
||||
set_prop_tab_bar (TAB_BAR_ITEM_ENABLED_P, value);
|
||||
}
|
||||
else if (EQ (ikey, QCvisible))
|
||||
{
|
||||
/* `:visible FORM'. If got a visible property and that
|
||||
evaluates to nil then ignore this item. */
|
||||
if (NILP (menu_item_eval_property (value)))
|
||||
return 0;
|
||||
}
|
||||
else if (EQ (ikey, QChelp))
|
||||
/* `:help HELP-STRING'. */
|
||||
set_prop_tab_bar (TAB_BAR_ITEM_HELP, value);
|
||||
else if (EQ (ikey, QCfilter))
|
||||
/* ':filter FORM'. */
|
||||
filter = value;
|
||||
else if (EQ (ikey, QCbutton) && CONSP (value))
|
||||
{
|
||||
/* `:button (TYPE . SELECTED)'. */
|
||||
Lisp_Object type, selected;
|
||||
|
||||
type = XCAR (value);
|
||||
selected = XCDR (value);
|
||||
if (EQ (type, QCtoggle) || EQ (type, QCradio))
|
||||
{
|
||||
set_prop_tab_bar (TAB_BAR_ITEM_SELECTED_P, selected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If got a filter apply it on binding. */
|
||||
if (!NILP (filter))
|
||||
set_prop_tab_bar (TAB_BAR_ITEM_BINDING,
|
||||
(menu_item_eval_property
|
||||
(list2 (filter,
|
||||
list2 (Qquote,
|
||||
PROP (TAB_BAR_ITEM_BINDING))))));
|
||||
|
||||
/* See if the binding is a keymap. Give up if it is. */
|
||||
if (CONSP (get_keymap (PROP (TAB_BAR_ITEM_BINDING), 0, 1)))
|
||||
return 0;
|
||||
|
||||
/* Enable or disable selection of item. */
|
||||
if (!EQ (PROP (TAB_BAR_ITEM_ENABLED_P), Qt))
|
||||
set_prop_tab_bar (TAB_BAR_ITEM_ENABLED_P,
|
||||
menu_item_eval_property (PROP (TAB_BAR_ITEM_ENABLED_P)));
|
||||
|
||||
/* Handle radio buttons or toggle boxes. */
|
||||
if (!NILP (PROP (TAB_BAR_ITEM_SELECTED_P)))
|
||||
set_prop_tab_bar (TAB_BAR_ITEM_SELECTED_P,
|
||||
menu_item_eval_property (PROP (TAB_BAR_ITEM_SELECTED_P)));
|
||||
|
||||
return 1;
|
||||
|
||||
#undef PROP
|
||||
}
|
||||
|
||||
|
||||
/* Initialize tab_bar_items_vector. REUSE, if non-nil, is a vector
|
||||
that can be reused. */
|
||||
|
||||
static void
|
||||
init_tab_bar_items (Lisp_Object reuse)
|
||||
{
|
||||
if (VECTORP (reuse))
|
||||
tab_bar_items_vector = reuse;
|
||||
else
|
||||
tab_bar_items_vector = make_nil_vector (64);
|
||||
ntab_bar_items = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Append parsed tab bar item properties from
|
||||
tab_bar_item_properties */
|
||||
|
||||
static void
|
||||
append_tab_bar_item (void)
|
||||
{
|
||||
ptrdiff_t incr
|
||||
= (ntab_bar_items
|
||||
- (ASIZE (tab_bar_items_vector) - TAB_BAR_ITEM_NSLOTS));
|
||||
|
||||
/* Enlarge tab_bar_items_vector if necessary. */
|
||||
if (incr > 0)
|
||||
tab_bar_items_vector = larger_vector (tab_bar_items_vector, incr, -1);
|
||||
|
||||
/* Append entries from tab_bar_item_properties to the end of
|
||||
tab_bar_items_vector. */
|
||||
vcopy (tab_bar_items_vector, ntab_bar_items,
|
||||
XVECTOR (tab_bar_item_properties)->contents, TAB_BAR_ITEM_NSLOTS);
|
||||
ntab_bar_items += TAB_BAR_ITEM_NSLOTS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
Tool-bars
|
||||
|
@ -8402,6 +8803,7 @@ read_char_x_menu_prompt (Lisp_Object map,
|
|||
use a real menu for mouse selection. */
|
||||
if (EVENT_HAS_PARAMETERS (prev_event)
|
||||
&& !EQ (XCAR (prev_event), Qmenu_bar)
|
||||
&& !EQ (XCAR (prev_event), Qtab_bar)
|
||||
&& !EQ (XCAR (prev_event), Qtool_bar))
|
||||
{
|
||||
/* Display the menu and get the selection. */
|
||||
|
@ -9377,7 +9779,7 @@ read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt,
|
|||
posn = POSN_POSN (xevent_start (key));
|
||||
/* Handle menu-bar events:
|
||||
insert the dummy prefix event `menu-bar'. */
|
||||
if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar))
|
||||
if (EQ (posn, Qmenu_bar) || EQ (posn, Qtab_bar) || EQ (posn, Qtool_bar))
|
||||
{
|
||||
if (READ_KEY_ELTS - t <= 1)
|
||||
error ("Key sequence too long");
|
||||
|
@ -10237,7 +10639,8 @@ On such systems, Emacs starts a subshell instead of suspending. */)
|
|||
get_tty_size (fileno (CURTTY ()->input), &width, &height);
|
||||
if (width != old_width || height != old_height)
|
||||
change_frame_size (SELECTED_FRAME (), width,
|
||||
height - FRAME_MENU_BAR_LINES (SELECTED_FRAME ()),
|
||||
height - FRAME_MENU_BAR_LINES (SELECTED_FRAME ())
|
||||
- FRAME_TAB_BAR_LINES (SELECTED_FRAME ()),
|
||||
0, 0, 0, 0);
|
||||
|
||||
run_hook (intern ("suspend-resume-hook"));
|
||||
|
@ -11057,6 +11460,11 @@ syms_of_keyboard (void)
|
|||
staticpro (&item_properties);
|
||||
item_properties = Qnil;
|
||||
|
||||
staticpro (&tab_bar_item_properties);
|
||||
tab_bar_item_properties = Qnil;
|
||||
staticpro (&tab_bar_items_vector);
|
||||
tab_bar_items_vector = Qnil;
|
||||
|
||||
staticpro (&tool_bar_item_properties);
|
||||
tool_bar_item_properties = Qnil;
|
||||
staticpro (&tool_bar_items_vector);
|
||||
|
@ -11610,6 +12018,12 @@ See also `pre-command-hook'. */);
|
|||
The elements of the list are event types that may have menu bar bindings. */);
|
||||
Vmenu_bar_final_items = Qnil;
|
||||
|
||||
DEFVAR_LISP ("tab-bar-separator-image-expression", Vtab_bar_separator_image_expression,
|
||||
doc: /* Expression evaluating to the image spec for a tab-bar separator.
|
||||
This is used internally by graphical displays that do not render
|
||||
tab-bar separators natively. Otherwise it is unused (e.g. on GTK). */);
|
||||
Vtab_bar_separator_image_expression = Qnil;
|
||||
|
||||
DEFVAR_LISP ("tool-bar-separator-image-expression", Vtool_bar_separator_image_expression,
|
||||
doc: /* Expression evaluating to the image spec for a tool-bar separator.
|
||||
This is used internally by graphical displays that do not render
|
||||
|
|
|
@ -3663,7 +3663,8 @@ be preferred. */);
|
|||
DEFSYM (Qmode_line, "mode-line");
|
||||
|
||||
staticpro (&Vmouse_events);
|
||||
Vmouse_events = pure_list (Qmenu_bar, Qtool_bar, Qheader_line, Qmode_line,
|
||||
Vmouse_events = pure_list (Qmenu_bar, Qtab_bar, Qtool_bar,
|
||||
Qtab_line, Qheader_line, Qmode_line,
|
||||
intern_c_string ("mouse-1"),
|
||||
intern_c_string ("mouse-2"),
|
||||
intern_c_string ("mouse-3"),
|
||||
|
|
|
@ -4391,6 +4391,7 @@ extern bool input_pending;
|
|||
extern sigjmp_buf return_to_command_loop;
|
||||
#endif
|
||||
extern Lisp_Object menu_bar_items (Lisp_Object);
|
||||
extern Lisp_Object tab_bar_items (Lisp_Object, int *);
|
||||
extern Lisp_Object tool_bar_items (Lisp_Object, int *);
|
||||
extern void discard_mouse_events (void);
|
||||
#ifdef USABLE_SIGIO
|
||||
|
|
|
@ -1130,6 +1130,7 @@ x_popup_menu_1 (Lisp_Object position, Lisp_Object menu)
|
|||
/* Decode the first argument: find the window and the coordinates. */
|
||||
if (EQ (position, Qt)
|
||||
|| (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
|
||||
|| EQ (XCAR (position), Qtab_bar)
|
||||
|| EQ (XCAR (position), Qtool_bar))))
|
||||
{
|
||||
get_current_pos_p = 1;
|
||||
|
@ -1506,6 +1507,7 @@ for instance using the window manager, then this produces a quit and
|
|||
/* Decode the first argument: find the window or frame to use. */
|
||||
if (EQ (position, Qt)
|
||||
|| (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
|
||||
|| EQ (XCAR (position), Qtab_bar)
|
||||
|| EQ (XCAR (position), Qtool_bar))))
|
||||
window = selected_window;
|
||||
else if (CONSP (position))
|
||||
|
|
|
@ -2655,7 +2655,7 @@ dos_rawgetc (void)
|
|||
static Lisp_Object last_mouse_window;
|
||||
|
||||
mouse_window = window_from_coordinates
|
||||
(SELECTED_FRAME (), mouse_last_x, mouse_last_y, 0, 0);
|
||||
(SELECTED_FRAME (), mouse_last_x, mouse_last_y, 0, 0, 0);
|
||||
/* A window will be selected only when it is not
|
||||
selected now, and the last mouse movement event was
|
||||
not in it. A minibuffer window will be selected iff
|
||||
|
|
12
src/nsfns.m
12
src/nsfns.m
|
@ -610,6 +610,15 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side.
|
|||
}
|
||||
|
||||
|
||||
/* tabbar support */
|
||||
static void
|
||||
ns_set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
|
||||
{
|
||||
/* Currently unimplemented. */
|
||||
NSTRACE ("ns_set_tab_bar_lines");
|
||||
}
|
||||
|
||||
|
||||
/* toolbar support */
|
||||
static void
|
||||
ns_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
|
||||
|
@ -923,6 +932,7 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side.
|
|||
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) */
|
||||
|
@ -1297,7 +1307,7 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side.
|
|||
RES_TYPE_STRING);
|
||||
|
||||
parms = get_geometry_from_preferences (dpyinfo, parms);
|
||||
window_prompting = gui_figure_window_size (f, parms, true,
|
||||
window_prompting = gui_figure_window_size (f, parms, false, true,
|
||||
&x_width, &x_height);
|
||||
|
||||
tem = gui_display_get_arg (dpyinfo, parms, Qunsplittable, 0, 0,
|
||||
|
|
|
@ -6859,7 +6859,7 @@ - (void)mouseMoved: (NSEvent *)e
|
|||
NSTRACE_MSG ("mouse_autoselect_window");
|
||||
static Lisp_Object last_mouse_window;
|
||||
Lisp_Object window
|
||||
= window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
|
||||
= window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0, 0);
|
||||
|
||||
if (WINDOWP (window)
|
||||
&& !EQ (window, last_mouse_window)
|
||||
|
|
|
@ -2341,7 +2341,8 @@ frame's terminal). */)
|
|||
was suspended. */
|
||||
get_tty_size (fileno (t->display_info.tty->input), &width, &height);
|
||||
if (width != old_width || height != old_height)
|
||||
change_frame_size (f, width, height - FRAME_MENU_BAR_LINES (f),
|
||||
change_frame_size (f, width, height - FRAME_MENU_BAR_LINES (f)
|
||||
- FRAME_TAB_BAR_LINES (f),
|
||||
0, 0, 0, 0);
|
||||
SET_FRAME_VISIBLE (XFRAME (t->display_info.tty->top_frame), 1);
|
||||
}
|
||||
|
|
|
@ -194,6 +194,11 @@ enum event_kind
|
|||
the help to show. */
|
||||
HELP_EVENT,
|
||||
|
||||
/* An event from a tab-bar. Member `arg' of the input event
|
||||
contains the tab-bar item selected. If `frame_or_window'
|
||||
and `arg' are equal, this is a prefix event. */
|
||||
TAB_BAR_EVENT,
|
||||
|
||||
/* An event from a tool-bar. Member `arg' of the input event
|
||||
contains the tool-bar item selected. If `frame_or_window'
|
||||
and `arg' are equal, this is a prefix event. */
|
||||
|
@ -624,6 +629,9 @@ struct terminal
|
|||
Lisp_Object (*popup_dialog_hook) (struct frame *f, Lisp_Object header,
|
||||
Lisp_Object contents);
|
||||
|
||||
/* This hook is called to change the frame's (internal) tab-bar. */
|
||||
void (*change_tab_bar_height_hook) (struct frame *f, int height);
|
||||
|
||||
/* This hook is called to change the frame's (internal) tool-bar. */
|
||||
void (*change_tool_bar_height_hook) (struct frame *f, int height);
|
||||
|
||||
|
|
110
src/w32fns.c
110
src/w32fns.c
|
@ -1773,6 +1773,94 @@ w32_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
|
|||
}
|
||||
|
||||
|
||||
/* Set the number of lines used for the tab bar of frame F to VALUE.
|
||||
VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
|
||||
is the old number of tab bar lines. This function changes the
|
||||
height of all windows on frame F to match the new tab bar height.
|
||||
The frame's height doesn't change. */
|
||||
|
||||
static void
|
||||
w32_set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
|
||||
{
|
||||
int nlines;
|
||||
|
||||
/* Treat tab bars like menu bars. */
|
||||
if (FRAME_MINIBUF_ONLY_P (f))
|
||||
return;
|
||||
|
||||
/* Use VALUE only if an int >= 0. */
|
||||
if (RANGED_FIXNUMP (0, value, INT_MAX))
|
||||
nlines = XFIXNAT (value);
|
||||
else
|
||||
nlines = 0;
|
||||
|
||||
w32_change_tab_bar_height (f, nlines * FRAME_LINE_HEIGHT (f));
|
||||
}
|
||||
|
||||
|
||||
/* Set the pixel height of the tab bar of frame F to HEIGHT. */
|
||||
void
|
||||
w32_change_tab_bar_height (struct frame *f, int height)
|
||||
{
|
||||
int unit = FRAME_LINE_HEIGHT (f);
|
||||
int old_height = FRAME_TAB_BAR_HEIGHT (f);
|
||||
int lines = (height + unit - 1) / unit;
|
||||
Lisp_Object fullscreen;
|
||||
|
||||
/* Make sure we redisplay all windows in this frame. */
|
||||
fset_redisplay (f);
|
||||
|
||||
/* Recalculate tab bar and frame text sizes. */
|
||||
FRAME_TAB_BAR_HEIGHT (f) = height;
|
||||
FRAME_TAB_BAR_LINES (f) = lines;
|
||||
/* Store the `tab-bar-lines' and `height' frame parameters. */
|
||||
store_frame_param (f, Qtab_bar_lines, make_fixnum (lines));
|
||||
store_frame_param (f, Qheight, make_fixnum (FRAME_LINES (f)));
|
||||
|
||||
/* We also have to make sure that the internal border at the top of
|
||||
the frame, below the menu bar or tab bar, is redrawn when the
|
||||
tab bar disappears. This is so because the internal border is
|
||||
below the tab bar if one is displayed, but is below the menu bar
|
||||
if there isn't a tab bar. The tab bar draws into the area
|
||||
below the menu bar. */
|
||||
if (FRAME_W32_WINDOW (f) && FRAME_TAB_BAR_HEIGHT (f) == 0)
|
||||
{
|
||||
clear_frame (f);
|
||||
clear_current_matrices (f);
|
||||
}
|
||||
|
||||
if ((height < old_height) && WINDOWP (f->tab_bar_window))
|
||||
clear_glyph_matrix (XWINDOW (f->tab_bar_window)->current_matrix);
|
||||
|
||||
/* Recalculate tabbar height. */
|
||||
f->n_tab_bar_rows = 0;
|
||||
if (old_height == 0
|
||||
&& (!f->after_make_frame
|
||||
|| NILP (frame_inhibit_implied_resize)
|
||||
|| (CONSP (frame_inhibit_implied_resize)
|
||||
&& NILP (Fmemq (Qtab_bar_lines, frame_inhibit_implied_resize)))))
|
||||
f->tab_bar_redisplayed = f->tab_bar_resized = false;
|
||||
|
||||
adjust_frame_size (f, -1, -1,
|
||||
((!f->tab_bar_resized
|
||||
&& (NILP (fullscreen =
|
||||
get_frame_param (f, Qfullscreen))
|
||||
|| EQ (fullscreen, Qfullwidth))) ? 1
|
||||
: (old_height == 0 || height == 0) ? 2
|
||||
: 4),
|
||||
false, Qtab_bar_lines);
|
||||
|
||||
f->tab_bar_resized = f->tab_bar_redisplayed;
|
||||
|
||||
/* adjust_frame_size might not have done anything, garbage frame
|
||||
here. */
|
||||
adjust_frame_glyphs (f);
|
||||
SET_FRAME_GARBAGED (f);
|
||||
if (FRAME_W32_WINDOW (f))
|
||||
w32_clear_under_internal_border (f);
|
||||
}
|
||||
|
||||
|
||||
/* Set the number of lines used for the tool bar of frame F to VALUE.
|
||||
VALUE not an integer, or < 0 means set the lines to zero. OLDVAL is
|
||||
the old number of tool bar lines (and is unused). This function may
|
||||
|
@ -5989,6 +6077,11 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
|
|||
/* No menu bar for child frames. */
|
||||
store_frame_param (f, Qmenu_bar_lines, make_fixnum (0));
|
||||
|
||||
gui_default_parameter (f, parameters, Qtab_bar_lines,
|
||||
NILP (Vtab_bar_mode)
|
||||
? make_fixnum (0) : make_fixnum (1),
|
||||
NULL, NULL, RES_TYPE_NUMBER);
|
||||
|
||||
gui_default_parameter (f, parameters, Qtool_bar_lines,
|
||||
NILP (Vtool_bar_mode)
|
||||
? make_fixnum (0) : make_fixnum (1),
|
||||
|
@ -6018,7 +6111,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
|
|||
|
||||
f->output_data.w32->current_cursor = f->output_data.w32->nontext_cursor;
|
||||
|
||||
window_prompting = gui_figure_window_size (f, parameters, true,
|
||||
window_prompting = gui_figure_window_size (f, parameters, true, true,
|
||||
&x_width, &x_height);
|
||||
|
||||
tem = gui_display_get_arg (dpyinfo, parameters, Qunsplittable, 0, 0,
|
||||
|
@ -6986,7 +7079,7 @@ w32_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms)
|
|||
f->output_data.w32->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
|
||||
f->output_data.w32->explicit_parent = false;
|
||||
|
||||
gui_figure_window_size (f, parms, true, &x_width, &x_height);
|
||||
gui_figure_window_size (f, parms, true, true, &x_width, &x_height);
|
||||
|
||||
/* No fringes on tip frame. */
|
||||
f->fringe_cols = 0;
|
||||
|
@ -8739,6 +8832,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).
|
||||
|
||||
|
@ -8761,6 +8857,7 @@ and width values are in pixels.
|
|||
unsigned int external_border_width, external_border_height;
|
||||
int title_bar_width = 0, title_bar_height = 0;
|
||||
int single_menu_bar_height, wrapped_menu_bar_height, menu_bar_height;
|
||||
int tab_bar_height = FRAME_TAB_BAR_HEIGHT (f);
|
||||
int tool_bar_height = FRAME_TOOL_BAR_HEIGHT (f);
|
||||
int internal_border_width = FRAME_INTERNAL_BORDER_WIDTH (f);
|
||||
|
||||
|
@ -8834,6 +8931,13 @@ and width values are in pixels.
|
|||
Fcons (make_fixnum
|
||||
(menu_bar.rcBar.right - menu_bar.rcBar.left),
|
||||
make_fixnum (menu_bar_height))),
|
||||
Fcons (Qtab_bar_size,
|
||||
Fcons (make_fixnum
|
||||
(tab_bar_height
|
||||
? (right - left - 2 * external_border_width
|
||||
- 2 * internal_border_width)
|
||||
: 0),
|
||||
make_fixnum (tab_bar_height))),
|
||||
Fcons (Qtool_bar_external, Qnil),
|
||||
Fcons (Qtool_bar_position, tool_bar_height ? Qtop : Qnil),
|
||||
Fcons (Qtool_bar_size,
|
||||
|
@ -8925,6 +9029,7 @@ menu bar or tool bar of FRAME. */)
|
|||
|
||||
return list4 (make_fixnum (left + internal_border_width),
|
||||
make_fixnum (top
|
||||
+ FRAME_TAB_BAR_HEIGHT (f)
|
||||
+ FRAME_TOOL_BAR_HEIGHT (f)
|
||||
+ internal_border_width),
|
||||
make_fixnum (right - internal_border_width),
|
||||
|
@ -10212,6 +10317,7 @@ frame_parm_handler w32_frame_parm_handlers[] =
|
|||
gui_set_vertical_scroll_bars,
|
||||
gui_set_horizontal_scroll_bars,
|
||||
gui_set_visibility,
|
||||
w32_set_tab_bar_lines,
|
||||
w32_set_tool_bar_lines,
|
||||
0, /* x_set_scroll_bar_foreground, */
|
||||
0, /* x_set_scroll_bar_background, */
|
||||
|
|
|
@ -492,7 +492,7 @@ do_mouse_event (MOUSE_EVENT_RECORD *event,
|
|||
if (!NILP (Vmouse_autoselect_window))
|
||||
{
|
||||
Lisp_Object mouse_window = window_from_coordinates (f, mx, my,
|
||||
0, 0);
|
||||
0, 0, 0);
|
||||
/* A window will be selected only when it is not
|
||||
selected now, and the last mouse movement event was
|
||||
not in it. A minibuffer window will be selected iff
|
||||
|
|
|
@ -36,6 +36,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
"emacs.tooltip.attributeBackground:SystemInfoWindow\0" \
|
||||
"emacs.tool-bar.attributeForeground:SystemButtonText\0" \
|
||||
"emacs.tool-bar.attributeBackground:SystemButtonFace\0" \
|
||||
"emacs.tab-bar.attributeForeground:SystemButtonText\0" \
|
||||
"emacs.tab-bar.attributeBackground:SystemButtonFace\0" \
|
||||
"emacs.menu.attributeForeground:SystemMenuText\0" \
|
||||
"emacs.menu.attributeBackground:SystemMenu\0" \
|
||||
"emacs.scroll-bar.attributeForeground:SystemScrollbar\0"
|
||||
|
|
|
@ -168,6 +168,8 @@ int w32_keyboard_codepage;
|
|||
int w32_message_fd = -1;
|
||||
#endif /* CYGWIN */
|
||||
|
||||
static void w32_handle_tab_bar_click (struct frame *,
|
||||
struct input_event *);
|
||||
static void w32_handle_tool_bar_click (struct frame *,
|
||||
struct input_event *);
|
||||
static void w32_define_cursor (Window, Emacs_Cursor);
|
||||
|
@ -3602,6 +3604,29 @@ w32_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
|
|||
unblock_input ();
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
Tab-bars
|
||||
***********************************************************************/
|
||||
|
||||
/* Handle mouse button event on the tab-bar of frame F, at
|
||||
frame-relative coordinates X/Y. EVENT_TYPE is either ButtonPress
|
||||
or ButtonRelease. */
|
||||
|
||||
static void
|
||||
w32_handle_tab_bar_click (struct frame *f, struct input_event *button_event)
|
||||
{
|
||||
int x = XFIXNAT (button_event->x);
|
||||
int y = XFIXNAT (button_event->y);
|
||||
|
||||
if (button_event->modifiers & down_modifier)
|
||||
handle_tab_bar_click (f, x, y, 1, 0);
|
||||
else
|
||||
handle_tab_bar_click (f, x, y, 0,
|
||||
button_event->modifiers & ~up_modifier);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
Tool-bars
|
||||
|
@ -4843,6 +4868,7 @@ w32_read_socket (struct terminal *terminal,
|
|||
if (f && !FRAME_ICONIFIED_P (f))
|
||||
{
|
||||
if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight)
|
||||
&& !EQ (f->tab_bar_window, hlinfo->mouse_face_window)
|
||||
&& !EQ (f->tool_bar_window, hlinfo->mouse_face_window))
|
||||
{
|
||||
clear_mouse_face (hlinfo);
|
||||
|
@ -4868,6 +4894,7 @@ w32_read_socket (struct terminal *terminal,
|
|||
if (f && !FRAME_ICONIFIED_P (f))
|
||||
{
|
||||
if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight)
|
||||
&& !EQ (f->tab_bar_window, hlinfo->mouse_face_window)
|
||||
&& !EQ (f->tool_bar_window, hlinfo->mouse_face_window))
|
||||
{
|
||||
clear_mouse_face (hlinfo);
|
||||
|
@ -4946,6 +4973,7 @@ w32_read_socket (struct terminal *terminal,
|
|||
if (f && !FRAME_ICONIFIED_P (f))
|
||||
{
|
||||
if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight)
|
||||
&& !EQ (f->tab_bar_window, hlinfo->mouse_face_window)
|
||||
&& !EQ (f->tool_bar_window, hlinfo->mouse_face_window))
|
||||
{
|
||||
clear_mouse_face (hlinfo);
|
||||
|
@ -4998,7 +5026,7 @@ w32_read_socket (struct terminal *terminal,
|
|||
{
|
||||
static Lisp_Object last_mouse_window;
|
||||
Lisp_Object window = window_from_coordinates
|
||||
(f, LOWORD (msg.msg.lParam), HIWORD (msg.msg.lParam), 0, 0);
|
||||
(f, LOWORD (msg.msg.lParam), HIWORD (msg.msg.lParam), 0, 0, 0);
|
||||
|
||||
/* Window will be selected only when it is not
|
||||
selected now and last mouse movement event was
|
||||
|
@ -5051,6 +5079,7 @@ w32_read_socket (struct terminal *terminal,
|
|||
{
|
||||
/* If we decide we want to generate an event to be seen
|
||||
by the rest of Emacs, we put it here. */
|
||||
bool tab_bar_p = 0;
|
||||
bool tool_bar_p = 0;
|
||||
int button = 0;
|
||||
int up = 0;
|
||||
|
@ -5060,6 +5089,31 @@ w32_read_socket (struct terminal *terminal,
|
|||
{
|
||||
w32_construct_mouse_click (&inev, &msg, f);
|
||||
|
||||
/* Is this in the tab-bar? */
|
||||
if (WINDOWP (f->tab_bar_window)
|
||||
&& WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window)))
|
||||
{
|
||||
Lisp_Object window;
|
||||
int x = XFIXNAT (inev.x);
|
||||
int y = XFIXNAT (inev.y);
|
||||
|
||||
window = window_from_coordinates (f, x, y, 0, 1, 1);
|
||||
|
||||
if (EQ (window, f->tab_bar_window))
|
||||
{
|
||||
w32_handle_tab_bar_click (f, &inev);
|
||||
tab_bar_p = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (tab_bar_p
|
||||
|| (dpyinfo->w32_focus_frame
|
||||
&& f != dpyinfo->w32_focus_frame
|
||||
/* This does not help when the click happens in
|
||||
a grand-parent frame. */
|
||||
&& !frame_ancestor_p (f, dpyinfo->w32_focus_frame)))
|
||||
inev.kind = NO_EVENT;
|
||||
|
||||
/* Is this in the tool-bar? */
|
||||
if (WINDOWP (f->tool_bar_window)
|
||||
&& WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)))
|
||||
|
@ -5068,7 +5122,7 @@ w32_read_socket (struct terminal *terminal,
|
|||
int x = XFIXNAT (inev.x);
|
||||
int y = XFIXNAT (inev.y);
|
||||
|
||||
window = window_from_coordinates (f, x, y, 0, 1);
|
||||
window = window_from_coordinates (f, x, y, 0, 1, 1);
|
||||
|
||||
if (EQ (window, f->tool_bar_window))
|
||||
{
|
||||
|
@ -5104,6 +5158,8 @@ w32_read_socket (struct terminal *terminal,
|
|||
if (f != 0)
|
||||
{
|
||||
f->mouse_moved = false;
|
||||
if (!tab_bar_p)
|
||||
f->last_tab_bar_item = -1;
|
||||
if (!tool_bar_p)
|
||||
f->last_tool_bar_item = -1;
|
||||
}
|
||||
|
@ -5127,6 +5183,7 @@ w32_read_socket (struct terminal *terminal,
|
|||
event; any subsequent mouse-movement Emacs events
|
||||
should reflect only motion after the ButtonPress. */
|
||||
f->mouse_moved = false;
|
||||
f->last_tab_bar_item = -1;
|
||||
f->last_tool_bar_item = -1;
|
||||
dpyinfo->last_mouse_frame = f;
|
||||
}
|
||||
|
@ -5140,6 +5197,7 @@ w32_read_socket (struct terminal *terminal,
|
|||
{
|
||||
w32_construct_mouse_wheel (&inev, &msg, f1);
|
||||
f1->mouse_moved = false;
|
||||
f1->last_tab_bar_item = -1;
|
||||
f1->last_tool_bar_item = -1;
|
||||
dpyinfo->last_mouse_frame = f1;
|
||||
}
|
||||
|
@ -5936,7 +5994,8 @@ w32_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
|
|||
= (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
|
||||
+ glyph_row->ascent - w->phys_cursor_ascent);
|
||||
w32_system_caret_window = w;
|
||||
w32_system_caret_hdr_height = WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
w32_system_caret_hdr_height = WINDOW_TAB_LINE_HEIGHT (w)
|
||||
+ WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
w32_system_caret_mode_height = WINDOW_MODE_LINE_HEIGHT (w);
|
||||
|
||||
PostMessage (hwnd, WM_IME_STARTCOMPOSITION, 0, 0);
|
||||
|
@ -7192,6 +7251,7 @@ w32_create_terminal (struct w32_display_info *dpyinfo)
|
|||
terminal->menu_show_hook = w32_menu_show;
|
||||
terminal->activate_menubar_hook = w32_activate_menubar;
|
||||
terminal->popup_dialog_hook = w32_popup_dialog;
|
||||
terminal->change_tab_bar_height_hook = w32_change_tab_bar_height;
|
||||
terminal->change_tool_bar_height_hook = w32_change_tool_bar_height;
|
||||
terminal->set_vertical_scroll_bar_hook = w32_set_vertical_scroll_bar;
|
||||
terminal->set_horizontal_scroll_bar_hook = w32_set_horizontal_scroll_bar;
|
||||
|
|
|
@ -233,6 +233,7 @@ extern void w32_real_positions (struct frame *f, int *xptr, int *yptr);
|
|||
|
||||
extern void w32_clear_under_internal_border (struct frame *);
|
||||
|
||||
extern void w32_change_tab_bar_height (struct frame *, int);
|
||||
extern void w32_change_tool_bar_height (struct frame *, int);
|
||||
extern void w32_implicitly_set_name (struct frame *, Lisp_Object, Lisp_Object);
|
||||
extern void w32_set_scroll_bar_default_width (struct frame *);
|
||||
|
|
134
src/window.c
134
src/window.c
|
@ -1002,6 +1002,7 @@ static int
|
|||
window_body_height (struct window *w, bool pixelwise)
|
||||
{
|
||||
int height = (w->pixel_height
|
||||
- WINDOW_TAB_LINE_HEIGHT (w)
|
||||
- WINDOW_HEADER_LINE_HEIGHT (w)
|
||||
- (WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w)
|
||||
? WINDOW_SCROLL_BAR_AREA_HEIGHT (w)
|
||||
|
@ -1131,6 +1132,15 @@ WINDOW must be a live window and defaults to the selected one. */)
|
|||
return (make_fixnum (WINDOW_HEADER_LINE_HEIGHT (decode_live_window (window))));
|
||||
}
|
||||
|
||||
DEFUN ("window-tab-line-height", Fwindow_tab_line_height,
|
||||
Swindow_tab_line_height, 0, 1, 0,
|
||||
doc: /* Return the height in pixels of WINDOW's tab-line.
|
||||
WINDOW must be a live window and defaults to the selected one. */)
|
||||
(Lisp_Object window)
|
||||
{
|
||||
return (make_fixnum (WINDOW_TAB_LINE_HEIGHT (decode_live_window (window))));
|
||||
}
|
||||
|
||||
DEFUN ("window-right-divider-width", Fwindow_right_divider_width,
|
||||
Swindow_right_divider_width, 0, 1, 0,
|
||||
doc: /* Return the width in pixels of WINDOW's right divider.
|
||||
|
@ -1249,7 +1259,8 @@ end-trigger value is reset to nil. */)
|
|||
if it is on the border between the window and its right sibling,
|
||||
return ON_VERTICAL_BORDER;
|
||||
if it is on a scroll bar, return ON_SCROLL_BAR;
|
||||
if it is on the window's top line, return ON_HEADER_LINE;
|
||||
if it is on the window's top line, return ON_TAB_LINE;
|
||||
if it is on the window's header line, return ON_HEADER_LINE;
|
||||
if it is in left or right fringe of the window,
|
||||
return ON_LEFT_FRINGE or ON_RIGHT_FRINGE;
|
||||
if it is in the marginal area to the left/right of the window,
|
||||
|
@ -1299,15 +1310,19 @@ coordinates_in_window (register struct window *w, int x, int y)
|
|||
- CURRENT_MODE_LINE_HEIGHT (w)
|
||||
- WINDOW_BOTTOM_DIVIDER_WIDTH (w))))
|
||||
return ON_HORIZONTAL_SCROLL_BAR;
|
||||
/* On the mode or header line? */
|
||||
/* On the mode or header/tab line? */
|
||||
else if ((window_wants_mode_line (w)
|
||||
&& y >= (bottom_y
|
||||
- CURRENT_MODE_LINE_HEIGHT (w)
|
||||
- WINDOW_BOTTOM_DIVIDER_WIDTH (w))
|
||||
&& y <= bottom_y - WINDOW_BOTTOM_DIVIDER_WIDTH (w)
|
||||
&& (part = ON_MODE_LINE))
|
||||
|| (window_wants_tab_line (w)
|
||||
&& y < top_y + CURRENT_TAB_LINE_HEIGHT (w)
|
||||
&& (part = ON_TAB_LINE))
|
||||
|| (window_wants_header_line (w)
|
||||
&& y < top_y + CURRENT_HEADER_LINE_HEIGHT (w)
|
||||
&& y < top_y + CURRENT_TAB_LINE_HEIGHT (w)
|
||||
+ CURRENT_HEADER_LINE_HEIGHT (w)
|
||||
&& (part = ON_HEADER_LINE)))
|
||||
{
|
||||
/* If it's under/over the scroll bar portion of the mode/header
|
||||
|
@ -1407,6 +1422,7 @@ window_relative_x_coord (struct window *w, enum window_part part, int x)
|
|||
case ON_TEXT:
|
||||
return x - window_box_left (w, TEXT_AREA);
|
||||
|
||||
case ON_TAB_LINE:
|
||||
case ON_HEADER_LINE:
|
||||
case ON_MODE_LINE:
|
||||
case ON_LEFT_FRINGE:
|
||||
|
@ -1457,6 +1473,7 @@ If they are in the bottom divider of WINDOW, `bottom-divider' is returned.
|
|||
If they are in the right divider of WINDOW, `right-divider' is returned.
|
||||
If they are in the mode line of WINDOW, `mode-line' is returned.
|
||||
If they are in the header line of WINDOW, `header-line' is returned.
|
||||
If they are in the tab line of WINDOW, `tab-line' is returned.
|
||||
If they are in the left fringe of WINDOW, `left-fringe' is returned.
|
||||
If they are in the right fringe of WINDOW, `right-fringe' is returned.
|
||||
If they are on the border between WINDOW and its right sibling,
|
||||
|
@ -1502,6 +1519,9 @@ If they are in the windows's left or right marginal areas, `left-margin'\n\
|
|||
case ON_HEADER_LINE:
|
||||
return Qheader_line;
|
||||
|
||||
case ON_TAB_LINE:
|
||||
return Qtab_line;
|
||||
|
||||
case ON_LEFT_FRINGE:
|
||||
return Qleft_fringe;
|
||||
|
||||
|
@ -1585,7 +1605,7 @@ check_window_containing (struct window *w, void *user_data)
|
|||
|
||||
Lisp_Object
|
||||
window_from_coordinates (struct frame *f, int x, int y,
|
||||
enum window_part *part, bool tool_bar_p)
|
||||
enum window_part *part, bool tab_bar_p, bool tool_bar_p)
|
||||
{
|
||||
Lisp_Object window;
|
||||
struct check_window_data cw;
|
||||
|
@ -1598,6 +1618,21 @@ window_from_coordinates (struct frame *f, int x, int y,
|
|||
cw.window = &window, cw.x = x, cw.y = y; cw.part = part;
|
||||
foreach_window (f, check_window_containing, &cw);
|
||||
|
||||
#if defined (HAVE_WINDOW_SYSTEM)
|
||||
/* If not found above, see if it's in the tab bar window, if a tab
|
||||
bar exists. */
|
||||
if (NILP (window)
|
||||
&& tab_bar_p
|
||||
&& WINDOWP (f->tab_bar_window)
|
||||
&& WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window)) > 0
|
||||
&& (coordinates_in_window (XWINDOW (f->tab_bar_window), x, y)
|
||||
!= ON_NOTHING))
|
||||
{
|
||||
*part = ON_TEXT;
|
||||
window = f->tab_bar_window;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR)
|
||||
/* If not found above, see if it's in the tool bar window, if a tool
|
||||
bar exists. */
|
||||
|
@ -1633,7 +1668,7 @@ column 0. */)
|
|||
+ FRAME_INTERNAL_BORDER_WIDTH (f)),
|
||||
(FRAME_PIXEL_Y_FROM_CANON_Y (f, y)
|
||||
+ FRAME_INTERNAL_BORDER_WIDTH (f)),
|
||||
0, false);
|
||||
0, false, false);
|
||||
}
|
||||
|
||||
DEFUN ("window-point", Fwindow_point, Swindow_point, 0, 1, 0,
|
||||
|
@ -1945,6 +1980,14 @@ Return nil if window display is not up-to-date. In that case, use
|
|||
goto found_row;
|
||||
}
|
||||
|
||||
if (EQ (line, Qtab_line))
|
||||
{
|
||||
if (!window_wants_tab_line (w))
|
||||
return Qnil;
|
||||
row = MATRIX_TAB_LINE_ROW (w->current_matrix);
|
||||
return row->enabled_p ? list4i (row->height, 0, 0, 0) : Qnil;
|
||||
}
|
||||
|
||||
if (EQ (line, Qheader_line))
|
||||
{
|
||||
if (!window_wants_header_line (w))
|
||||
|
@ -1959,7 +2002,8 @@ Return nil if window display is not up-to-date. In that case, use
|
|||
return (row->enabled_p ?
|
||||
list4i (row->height,
|
||||
0, /* not accurate */
|
||||
(WINDOW_HEADER_LINE_HEIGHT (w)
|
||||
(WINDOW_TAB_LINE_HEIGHT (w)
|
||||
+ WINDOW_HEADER_LINE_HEIGHT (w)
|
||||
+ window_text_bottom_y (w)),
|
||||
0)
|
||||
: Qnil);
|
||||
|
@ -2045,8 +2089,9 @@ though when run from an idle timer with a delay of zero seconds. */)
|
|||
int max_y = NILP (body) ? WINDOW_PIXEL_HEIGHT (w) : window_text_bottom_y (w);
|
||||
Lisp_Object rows = Qnil;
|
||||
int window_width = NILP (body) ? w->pixel_width : window_body_width (w, true);
|
||||
int tab_line_height = WINDOW_TAB_LINE_HEIGHT (w);
|
||||
int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
int subtract = NILP (body) ? 0 : header_line_height;
|
||||
int subtract = NILP (body) ? 0 : (tab_line_height + header_line_height);
|
||||
bool invert = !NILP (inverse);
|
||||
bool left_flag = !NILP (left);
|
||||
|
||||
|
@ -4246,7 +4291,7 @@ make_window (void)
|
|||
non-Lisp data, so do it only for slots which should not be zero. */
|
||||
w->nrows_scale_factor = w->ncols_scale_factor = 1;
|
||||
w->left_fringe_width = w->right_fringe_width = -1;
|
||||
w->mode_line_height = w->header_line_height = -1;
|
||||
w->mode_line_height = w->tab_line_height = w->header_line_height = -1;
|
||||
#ifdef HAVE_WINDOW_SYSTEM
|
||||
w->phys_cursor_type = NO_CURSOR;
|
||||
w->phys_cursor_width = -1;
|
||||
|
@ -4772,7 +4817,7 @@ Third argument SIDE nil (or `below') specifies that the new window shall
|
|||
be located below WINDOW. SIDE `above' means the new window shall be
|
||||
located above WINDOW. In both cases PIXEL-SIZE specifies the pixel
|
||||
height of the new window including space reserved for the mode and/or
|
||||
header line.
|
||||
header/tab line.
|
||||
|
||||
SIDE t (or `right') specifies that the new window shall be located on
|
||||
the right side of WINDOW. SIDE `left' means the new window shall be
|
||||
|
@ -5350,6 +5395,41 @@ window_wants_header_line (struct window *w)
|
|||
: 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* window_wants_tab_line:
|
||||
*
|
||||
* Return 1 if window W wants a tab line and is high enough to
|
||||
* accommodate it, 0 otherwise.
|
||||
*
|
||||
* W wants a tab line if it's a leaf window and neither a minibuffer
|
||||
* nor a pseudo window. Moreover, its 'window-mode-line-format'
|
||||
* parameter must not be 'none' and either that parameter or W's
|
||||
* buffer's 'mode-line-format' value must be non-nil. Finally, W must
|
||||
* be higher than its frame's canonical character height and be able
|
||||
* to accommodate a mode line and a header line too if necessary (the
|
||||
* mode line and a header line prevail).
|
||||
*/
|
||||
bool
|
||||
window_wants_tab_line (struct window *w)
|
||||
{
|
||||
Lisp_Object window_tab_line_format =
|
||||
window_parameter (w, Qtab_line_format);
|
||||
|
||||
return ((WINDOW_LEAF_P (w)
|
||||
&& !MINI_WINDOW_P (w)
|
||||
&& !WINDOW_PSEUDO_P (w)
|
||||
&& !EQ (window_tab_line_format, Qnone)
|
||||
&& (!NILP (window_tab_line_format)
|
||||
|| !NILP (BVAR (XBUFFER (WINDOW_BUFFER (w)), tab_line_format)))
|
||||
&& (WINDOW_PIXEL_HEIGHT (w)
|
||||
> (((window_wants_mode_line (w) ? 1 : 0)
|
||||
+ (window_wants_header_line (w) ? 1 : 0)
|
||||
+ 1) * WINDOW_FRAME_LINE_HEIGHT (w))))
|
||||
? 1
|
||||
: 0);
|
||||
}
|
||||
|
||||
/* Return number of lines of text in window W, not counting the mode
|
||||
line and header line, if any. Do NOT use this for windows on GUI
|
||||
frames; use window_body_height instead. This function is only for
|
||||
|
@ -5366,6 +5446,9 @@ window_internal_height (struct window *w)
|
|||
if (window_wants_header_line (w))
|
||||
--ht;
|
||||
|
||||
if (window_wants_tab_line (w))
|
||||
--ht;
|
||||
|
||||
return ht;
|
||||
}
|
||||
|
||||
|
@ -5726,8 +5809,9 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
|
|||
move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
|
||||
if (IT_CHARPOS (it) == PT
|
||||
&& it.current_y >= this_scroll_margin
|
||||
&& it.current_y <= last_y - WINDOW_HEADER_LINE_HEIGHT (w)
|
||||
&& (NILP (Vscroll_preserve_screen_position)
|
||||
&& it.current_y <= last_y - WINDOW_TAB_LINE_HEIGHT (w)
|
||||
- WINDOW_HEADER_LINE_HEIGHT (w)
|
||||
&& (NILP (Vscroll_preserve_screen_position)
|
||||
|| EQ (Vscroll_preserve_screen_position, Qt)))
|
||||
/* We found PT at a legitimate height. Leave it alone. */
|
||||
;
|
||||
|
@ -5742,7 +5826,8 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
|
|||
is necessary because we set it.current_y to 0, above. */
|
||||
move_it_to (&it, -1,
|
||||
window_scroll_pixel_based_preserve_x,
|
||||
goal_y - WINDOW_HEADER_LINE_HEIGHT (w),
|
||||
goal_y - WINDOW_TAB_LINE_HEIGHT (w)
|
||||
- WINDOW_HEADER_LINE_HEIGHT (w),
|
||||
-1, MOVE_TO_Y | MOVE_TO_X);
|
||||
}
|
||||
|
||||
|
@ -5778,8 +5863,9 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
|
|||
/* We subtract WINDOW_HEADER_LINE_HEIGHT because
|
||||
it.y is relative to the bottom of the header
|
||||
line, see above. */
|
||||
(it.last_visible_y - WINDOW_HEADER_LINE_HEIGHT (w)
|
||||
- partial_line_height (&it) - this_scroll_margin - 1),
|
||||
(it.last_visible_y - WINDOW_TAB_LINE_HEIGHT (w)
|
||||
- WINDOW_HEADER_LINE_HEIGHT (w)
|
||||
- partial_line_height (&it) - this_scroll_margin - 1),
|
||||
-1,
|
||||
MOVE_TO_POS | MOVE_TO_Y);
|
||||
|
||||
|
@ -5817,13 +5903,15 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
|
|||
if (it.what == IT_EOB)
|
||||
partial_p =
|
||||
it.current_y + it.ascent + it.descent
|
||||
> it.last_visible_y - this_scroll_margin - WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
> it.last_visible_y - this_scroll_margin
|
||||
- WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
else
|
||||
{
|
||||
move_it_by_lines (&it, 1);
|
||||
partial_p =
|
||||
it.current_y
|
||||
> it.last_visible_y - this_scroll_margin - WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
> it.last_visible_y - this_scroll_margin
|
||||
- WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w);
|
||||
}
|
||||
|
||||
if (charpos == PT && !partial_p
|
||||
|
@ -6370,6 +6458,9 @@ and redisplay normally--don't erase and redraw the frame. */)
|
|||
/* Invalidate pixel data calculated for all compositions. */
|
||||
for (i = 0; i < n_compositions; i++)
|
||||
composition_table[i]->font = NULL;
|
||||
#if defined (HAVE_WINDOW_SYSTEM)
|
||||
WINDOW_XFRAME (w)->minimize_tab_bar_window_p = 1;
|
||||
#endif
|
||||
#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR)
|
||||
WINDOW_XFRAME (w)->minimize_tool_bar_window_p = 1;
|
||||
#endif
|
||||
|
@ -6686,13 +6777,13 @@ struct save_window_data
|
|||
|
||||
/* We should be able to do without the following two. */
|
||||
int frame_cols, frame_lines;
|
||||
/* These two should get eventually replaced by their pixel
|
||||
/* These three should get eventually replaced by their pixel
|
||||
counterparts. */
|
||||
int frame_menu_bar_lines, frame_tool_bar_lines;
|
||||
int frame_menu_bar_lines, frame_tab_bar_lines, frame_tool_bar_lines;
|
||||
int frame_text_width, frame_text_height;
|
||||
/* These are currently unused. We need them as soon as we convert
|
||||
to pixels. */
|
||||
int frame_menu_bar_height, frame_tool_bar_height;
|
||||
int frame_menu_bar_height, frame_tab_bar_height, frame_tool_bar_height;
|
||||
} GCALIGNED_STRUCT;
|
||||
|
||||
/* This is saved as a Lisp_Vector. */
|
||||
|
@ -7370,10 +7461,12 @@ saved by this function. */)
|
|||
data->frame_cols = FRAME_COLS (f);
|
||||
data->frame_lines = FRAME_LINES (f);
|
||||
data->frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
|
||||
data->frame_tab_bar_lines = FRAME_TAB_BAR_LINES (f);
|
||||
data->frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
|
||||
data->frame_text_width = FRAME_TEXT_WIDTH (f);
|
||||
data->frame_text_height = FRAME_TEXT_HEIGHT (f);
|
||||
data->frame_menu_bar_height = FRAME_MENU_BAR_HEIGHT (f);
|
||||
data->frame_tab_bar_height = FRAME_TAB_BAR_HEIGHT (f);
|
||||
data->frame_tool_bar_height = FRAME_TOOL_BAR_HEIGHT (f);
|
||||
data->selected_frame = selected_frame;
|
||||
data->current_window = FRAME_SELECTED_WINDOW (f);
|
||||
|
@ -7663,6 +7756,7 @@ set_window_scroll_bars (struct window *w, Lisp_Object width,
|
|||
|
||||
/* Don't change anything if new scroll bar won't fit. */
|
||||
if ((WINDOW_PIXEL_HEIGHT (w)
|
||||
- WINDOW_TAB_LINE_HEIGHT (w)
|
||||
- WINDOW_HEADER_LINE_HEIGHT (w)
|
||||
- WINDOW_MODE_LINE_HEIGHT (w)
|
||||
- (new_height == -1 ? FRAME_SCROLL_BAR_AREA_HEIGHT (f) : new_height))
|
||||
|
@ -8086,6 +8180,7 @@ syms_of_window (void)
|
|||
DEFSYM (Qmark_for_redisplay, "mark-for-redisplay");
|
||||
DEFSYM (Qmode_line_format, "mode-line-format");
|
||||
DEFSYM (Qheader_line_format, "header-line-format");
|
||||
DEFSYM (Qtab_line_format, "tab-line-format");
|
||||
|
||||
DEFVAR_LISP ("temp-buffer-show-function", Vtemp_buffer_show_function,
|
||||
doc: /* Non-nil means call as function to display a help buffer.
|
||||
|
@ -8389,6 +8484,7 @@ displayed after a scrolling operation to be somewhat inaccurate. */);
|
|||
defsubr (&Sset_window_redisplay_end_trigger);
|
||||
defsubr (&Swindow_mode_line_height);
|
||||
defsubr (&Swindow_header_line_height);
|
||||
defsubr (&Swindow_tab_line_height);
|
||||
defsubr (&Swindow_right_divider_width);
|
||||
defsubr (&Swindow_bottom_divider_width);
|
||||
defsubr (&Swindow_scroll_bar_width);
|
||||
|
|
38
src/window.h
38
src/window.h
|
@ -361,6 +361,9 @@ struct window
|
|||
/* Effective height of the header line, or -1 if not known. */
|
||||
int header_line_height;
|
||||
|
||||
/* Effective height of the tab line, or -1 if not known. */
|
||||
int tab_line_height;
|
||||
|
||||
/* Z - the buffer position of the last glyph in the current
|
||||
matrix of W. Only valid if window_end_valid is true. */
|
||||
ptrdiff_t window_end_pos;
|
||||
|
@ -697,7 +700,7 @@ wset_next_buffers (struct window *w, Lisp_Object val)
|
|||
(WINDOW_LEFT_EDGE_COL (W) + WINDOW_TOTAL_COLS (W))
|
||||
|
||||
/* Return the canonical frame line at which window W starts.
|
||||
This includes a header line, if any. */
|
||||
This includes a header/tab line, if any. */
|
||||
#define WINDOW_TOP_EDGE_LINE(W) (W)->top_line
|
||||
|
||||
/* Return the canonical frame line before which window W ends.
|
||||
|
@ -715,7 +718,7 @@ wset_next_buffers (struct window *w, Lisp_Object val)
|
|||
(WINDOW_LEFT_PIXEL_EDGE (W) + WINDOW_PIXEL_WIDTH (W))
|
||||
|
||||
/* Return the top pixel edge at which window W starts.
|
||||
This includes a header line, if any. */
|
||||
This includes a header/tab line, if any. */
|
||||
#define WINDOW_TOP_PIXEL_EDGE(W) (W)->pixel_top
|
||||
|
||||
/* Return the bottom pixel edge before which window W ends.
|
||||
|
@ -745,6 +748,15 @@ wset_next_buffers (struct window *w, Lisp_Object val)
|
|||
#define WINDOW_MENU_BAR_P(W) false
|
||||
#endif
|
||||
|
||||
/* True if W is a tab bar window. */
|
||||
#if defined (HAVE_WINDOW_SYSTEM)
|
||||
#define WINDOW_TAB_BAR_P(W) \
|
||||
(WINDOWP (WINDOW_XFRAME (W)->tab_bar_window) \
|
||||
&& (W) == XWINDOW (WINDOW_XFRAME (W)->tab_bar_window))
|
||||
#else
|
||||
#define WINDOW_TAB_BAR_P(W) false
|
||||
#endif
|
||||
|
||||
/* True if W is a tool bar window. */
|
||||
#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR)
|
||||
#define WINDOW_TOOL_BAR_P(W) \
|
||||
|
@ -756,13 +768,13 @@ wset_next_buffers (struct window *w, Lisp_Object val)
|
|||
|
||||
/* Return the frame y-position at which window W starts. */
|
||||
#define WINDOW_TOP_EDGE_Y(W) \
|
||||
(((WINDOW_MENU_BAR_P (W) || WINDOW_TOOL_BAR_P (W)) \
|
||||
(((WINDOW_MENU_BAR_P (W) || WINDOW_TAB_BAR_P (W) || WINDOW_TOOL_BAR_P (W)) \
|
||||
? 0 : FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W))) \
|
||||
+ WINDOW_TOP_PIXEL_EDGE (W))
|
||||
|
||||
/* Return the frame y-position before which window W ends. */
|
||||
#define WINDOW_BOTTOM_EDGE_Y(W) \
|
||||
(((WINDOW_MENU_BAR_P (W) || WINDOW_TOOL_BAR_P (W)) \
|
||||
(((WINDOW_MENU_BAR_P (W) || WINDOW_TAB_BAR_P (W) || WINDOW_TOOL_BAR_P (W)) \
|
||||
? 0 : FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W))) \
|
||||
+ WINDOW_BOTTOM_PIXEL_EDGE (W))
|
||||
|
||||
|
@ -996,6 +1008,16 @@ wset_next_buffers (struct window *w, Lisp_Object val)
|
|||
#define WINDOW_HEADER_LINE_LINES(W) \
|
||||
window_wants_header_line (W)
|
||||
|
||||
/* Height in pixels of the tab line.
|
||||
Zero if W doesn't have a tab line. */
|
||||
#define WINDOW_TAB_LINE_HEIGHT(W) \
|
||||
(window_wants_tab_line (W) \
|
||||
? CURRENT_TAB_LINE_HEIGHT (W) \
|
||||
: 0)
|
||||
|
||||
#define WINDOW_TAB_LINE_LINES(W) \
|
||||
window_wants_tab_line (W)
|
||||
|
||||
/* Pixel height of window W without mode line, bottom scroll bar and
|
||||
bottom divider. */
|
||||
#define WINDOW_BOX_HEIGHT_NO_MODE_LINE(W) \
|
||||
|
@ -1004,14 +1026,15 @@ wset_next_buffers (struct window *w, Lisp_Object val)
|
|||
- WINDOW_SCROLL_BAR_AREA_HEIGHT (W) \
|
||||
- WINDOW_MODE_LINE_HEIGHT (W))
|
||||
|
||||
/* Pixel height of window W without mode and header line and bottom
|
||||
/* Pixel height of window W without mode and header/tab line and bottom
|
||||
divider. */
|
||||
#define WINDOW_BOX_TEXT_HEIGHT(W) \
|
||||
(WINDOW_PIXEL_HEIGHT ((W)) \
|
||||
- WINDOW_BOTTOM_DIVIDER_WIDTH (W) \
|
||||
- WINDOW_SCROLL_BAR_AREA_HEIGHT (W) \
|
||||
- WINDOW_MODE_LINE_HEIGHT (W) \
|
||||
- WINDOW_HEADER_LINE_HEIGHT (W))
|
||||
- WINDOW_HEADER_LINE_HEIGHT (W) \
|
||||
- WINDOW_TAB_LINE_HEIGHT (W))
|
||||
|
||||
/* Return the frame position where the horizontal scroll bar of window W
|
||||
starts. */
|
||||
|
@ -1068,7 +1091,7 @@ extern Lisp_Object minibuf_selected_window;
|
|||
|
||||
extern Lisp_Object make_window (void);
|
||||
extern Lisp_Object window_from_coordinates (struct frame *, int, int,
|
||||
enum window_part *, bool);
|
||||
enum window_part *, bool, bool);
|
||||
extern void resize_frame_windows (struct frame *, int, bool);
|
||||
extern void restore_window_configuration (Lisp_Object);
|
||||
extern void delete_all_child_windows (Lisp_Object);
|
||||
|
@ -1158,6 +1181,7 @@ extern bool compare_window_configurations (Lisp_Object, Lisp_Object, bool);
|
|||
extern void mark_window_cursors_off (struct window *);
|
||||
extern bool window_wants_mode_line (struct window *);
|
||||
extern bool window_wants_header_line (struct window *);
|
||||
extern bool window_wants_tab_line (struct window *);
|
||||
extern int window_internal_height (struct window *);
|
||||
extern int window_body_width (struct window *w, bool);
|
||||
enum margin_unit { MARGIN_IN_LINES, MARGIN_IN_PIXELS };
|
||||
|
|
1165
src/xdisp.c
1165
src/xdisp.c
File diff suppressed because it is too large
Load diff
|
@ -4586,6 +4586,8 @@ lookup_basic_face (struct window *w, struct frame *f, int face_id)
|
|||
case MODE_LINE_FACE_ID: name = Qmode_line; break;
|
||||
case MODE_LINE_INACTIVE_FACE_ID: name = Qmode_line_inactive; break;
|
||||
case HEADER_LINE_FACE_ID: name = Qheader_line; break;
|
||||
case TAB_LINE_FACE_ID: name = Qtab_line; break;
|
||||
case TAB_BAR_FACE_ID: name = Qtab_bar; break;
|
||||
case TOOL_BAR_FACE_ID: name = Qtool_bar; break;
|
||||
case FRINGE_FACE_ID: name = Qfringe; break;
|
||||
case SCROLL_BAR_FACE_ID: name = Qscroll_bar; break;
|
||||
|
@ -5293,6 +5295,8 @@ realize_basic_faces (struct frame *f)
|
|||
realize_named_face (f, Qwindow_divider_last_pixel,
|
||||
WINDOW_DIVIDER_LAST_PIXEL_FACE_ID);
|
||||
realize_named_face (f, Qinternal_border, INTERNAL_BORDER_FACE_ID);
|
||||
realize_named_face (f, Qtab_bar, TAB_BAR_FACE_ID);
|
||||
realize_named_face (f, Qtab_line, TAB_LINE_FACE_ID);
|
||||
|
||||
/* Reflect changes in the `menu' face in menu bars. */
|
||||
if (FRAME_FACE_CACHE (f)->menu_face_changed_p)
|
||||
|
@ -6579,7 +6583,9 @@ syms_of_xfaces (void)
|
|||
/* Names of basic faces. */
|
||||
DEFSYM (Qdefault, "default");
|
||||
DEFSYM (Qtool_bar, "tool-bar");
|
||||
DEFSYM (Qtab_bar, "tab-bar");
|
||||
DEFSYM (Qfringe, "fringe");
|
||||
DEFSYM (Qtab_line, "tab-line");
|
||||
DEFSYM (Qheader_line, "header-line");
|
||||
DEFSYM (Qscroll_bar, "scroll-bar");
|
||||
DEFSYM (Qmenu, "menu");
|
||||
|
|
107
src/xfns.c
107
src/xfns.c
|
@ -1602,6 +1602,94 @@ x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
|
|||
}
|
||||
|
||||
|
||||
/* Set the number of lines used for the tab bar of frame F to VALUE.
|
||||
VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
|
||||
is the old number of tab bar lines. This function changes the
|
||||
height of all windows on frame F to match the new tab bar height.
|
||||
The frame's height doesn't change. */
|
||||
|
||||
static void
|
||||
x_set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
|
||||
{
|
||||
int nlines;
|
||||
|
||||
/* Treat tab bars like menu bars. */
|
||||
if (FRAME_MINIBUF_ONLY_P (f))
|
||||
return;
|
||||
|
||||
/* Use VALUE only if an int >= 0. */
|
||||
if (RANGED_FIXNUMP (0, value, INT_MAX))
|
||||
nlines = XFIXNAT (value);
|
||||
else
|
||||
nlines = 0;
|
||||
|
||||
x_change_tab_bar_height (f, nlines * FRAME_LINE_HEIGHT (f));
|
||||
}
|
||||
|
||||
|
||||
/* Set the pixel height of the tab bar of frame F to HEIGHT. */
|
||||
void
|
||||
x_change_tab_bar_height (struct frame *f, int height)
|
||||
{
|
||||
int unit = FRAME_LINE_HEIGHT (f);
|
||||
int old_height = FRAME_TAB_BAR_HEIGHT (f);
|
||||
int lines = (height + unit - 1) / unit;
|
||||
Lisp_Object fullscreen;
|
||||
|
||||
/* Make sure we redisplay all windows in this frame. */
|
||||
fset_redisplay (f);
|
||||
|
||||
/* Recalculate tab bar and frame text sizes. */
|
||||
FRAME_TAB_BAR_HEIGHT (f) = height;
|
||||
FRAME_TAB_BAR_LINES (f) = lines;
|
||||
/* Store the `tab-bar-lines' and `height' frame parameters. */
|
||||
store_frame_param (f, Qtab_bar_lines, make_fixnum (lines));
|
||||
store_frame_param (f, Qheight, make_fixnum (FRAME_LINES (f)));
|
||||
|
||||
/* We also have to make sure that the internal border at the top of
|
||||
the frame, below the menu bar or tab bar, is redrawn when the
|
||||
tab bar disappears. This is so because the internal border is
|
||||
below the tab bar if one is displayed, but is below the menu bar
|
||||
if there isn't a tab bar. The tab bar draws into the area
|
||||
below the menu bar. */
|
||||
if (FRAME_X_WINDOW (f) && FRAME_TAB_BAR_HEIGHT (f) == 0)
|
||||
{
|
||||
clear_frame (f);
|
||||
clear_current_matrices (f);
|
||||
}
|
||||
|
||||
if ((height < old_height) && WINDOWP (f->tab_bar_window))
|
||||
clear_glyph_matrix (XWINDOW (f->tab_bar_window)->current_matrix);
|
||||
|
||||
/* Recalculate tabbar height. */
|
||||
f->n_tab_bar_rows = 0;
|
||||
if (old_height == 0
|
||||
&& (!f->after_make_frame
|
||||
|| NILP (frame_inhibit_implied_resize)
|
||||
|| (CONSP (frame_inhibit_implied_resize)
|
||||
&& NILP (Fmemq (Qtab_bar_lines, frame_inhibit_implied_resize)))))
|
||||
f->tab_bar_redisplayed = f->tab_bar_resized = false;
|
||||
|
||||
adjust_frame_size (f, -1, -1,
|
||||
((!f->tab_bar_resized
|
||||
&& (NILP (fullscreen =
|
||||
get_frame_param (f, Qfullscreen))
|
||||
|| EQ (fullscreen, Qfullwidth))) ? 1
|
||||
: (old_height == 0 || height == 0) ? 2
|
||||
: 4),
|
||||
false, Qtab_bar_lines);
|
||||
|
||||
f->tab_bar_resized = f->tab_bar_redisplayed;
|
||||
|
||||
/* adjust_frame_size might not have done anything, garbage frame
|
||||
here. */
|
||||
adjust_frame_glyphs (f);
|
||||
SET_FRAME_GARBAGED (f);
|
||||
if (FRAME_X_WINDOW (f))
|
||||
x_clear_under_internal_border (f);
|
||||
}
|
||||
|
||||
|
||||
/* Set the number of lines used for the tool bar of frame F to VALUE.
|
||||
VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
|
||||
is the old number of tool bar lines. This function changes the
|
||||
|
@ -3922,6 +4010,10 @@ This function is an internal primitive--use `make-frame' instead. */)
|
|||
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),
|
||||
|
@ -3941,7 +4033,7 @@ This function is an internal primitive--use `make-frame' instead. */)
|
|||
RES_TYPE_BOOLEAN);
|
||||
|
||||
/* Compute the size of the X window. */
|
||||
window_prompting = gui_figure_window_size (f, parms, true,
|
||||
window_prompting = gui_figure_window_size (f, parms, true, true,
|
||||
&x_width, &x_height);
|
||||
|
||||
tem = gui_display_get_arg (dpyinfo, parms, Qunsplittable, 0, 0,
|
||||
|
@ -5060,6 +5152,7 @@ frame_geometry (Lisp_Object frame, Lisp_Object attribute)
|
|||
int internal_border_width;
|
||||
bool menu_bar_external = false, tool_bar_external = false;
|
||||
int menu_bar_height = 0, menu_bar_width = 0;
|
||||
int tab_bar_height = 0, tab_bar_width = 0;
|
||||
int tool_bar_height = 0, tool_bar_width = 0;
|
||||
|
||||
if (FRAME_INITIAL_P (f) || !FRAME_X_P (f) || !FRAME_OUTER_WINDOW (f))
|
||||
|
@ -5130,6 +5223,12 @@ frame_geometry (Lisp_Object frame, Lisp_Object attribute)
|
|||
#endif
|
||||
menu_bar_width = menu_bar_height ? native_width : 0;
|
||||
|
||||
tab_bar_height = FRAME_TAB_BAR_HEIGHT (f);
|
||||
tab_bar_width = (tab_bar_height
|
||||
? native_width - 2 * internal_border_width
|
||||
: 0);
|
||||
inner_top += tab_bar_height;
|
||||
|
||||
#ifdef HAVE_EXT_TOOL_BAR
|
||||
tool_bar_external = true;
|
||||
if (EQ (FRAME_TOOL_BAR_POSITION (f), Qleft))
|
||||
|
@ -5198,6 +5297,9 @@ frame_geometry (Lisp_Object frame, Lisp_Object attribute)
|
|||
Fcons (Qmenu_bar_size,
|
||||
Fcons (make_fixnum (menu_bar_width),
|
||||
make_fixnum (menu_bar_height))),
|
||||
Fcons (Qtab_bar_size,
|
||||
Fcons (make_fixnum (tab_bar_width),
|
||||
make_fixnum (tab_bar_height))),
|
||||
Fcons (Qtool_bar_external, tool_bar_external ? Qt : Qnil),
|
||||
Fcons (Qtool_bar_position, FRAME_TOOL_BAR_POSITION (f)),
|
||||
Fcons (Qtool_bar_size,
|
||||
|
@ -6331,7 +6433,7 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms)
|
|||
"inhibitDoubleBuffering", "InhibitDoubleBuffering",
|
||||
RES_TYPE_BOOLEAN);
|
||||
|
||||
gui_figure_window_size (f, parms, false, &x_width, &x_height);
|
||||
gui_figure_window_size (f, parms, false, false, &x_width, &x_height);
|
||||
|
||||
{
|
||||
XSetWindowAttributes attrs;
|
||||
|
@ -7672,6 +7774,7 @@ frame_parm_handler x_frame_parm_handlers[] =
|
|||
gui_set_vertical_scroll_bars,
|
||||
gui_set_horizontal_scroll_bars,
|
||||
gui_set_visibility,
|
||||
x_set_tab_bar_lines,
|
||||
x_set_tool_bar_lines,
|
||||
x_set_scroll_bar_foreground,
|
||||
x_set_scroll_bar_background,
|
||||
|
|
63
src/xterm.c
63
src/xterm.c
|
@ -3220,9 +3220,11 @@ x_draw_image_relief (struct glyph_string *s)
|
|||
if (s->hl == DRAW_IMAGE_SUNKEN
|
||||
|| s->hl == DRAW_IMAGE_RAISED)
|
||||
{
|
||||
thick = (tool_bar_button_relief < 0
|
||||
? DEFAULT_TOOL_BAR_BUTTON_RELIEF
|
||||
: min (tool_bar_button_relief, 1000000));
|
||||
thick = (tab_bar_button_relief < 0
|
||||
? DEFAULT_TAB_BAR_BUTTON_RELIEF
|
||||
: (tool_bar_button_relief < 0
|
||||
? DEFAULT_TOOL_BAR_BUTTON_RELIEF
|
||||
: min (tool_bar_button_relief, 1000000)));
|
||||
raised_p = s->hl == DRAW_IMAGE_RAISED;
|
||||
}
|
||||
else
|
||||
|
@ -3235,6 +3237,19 @@ x_draw_image_relief (struct glyph_string *s)
|
|||
y1 = y + s->slice.height - 1;
|
||||
|
||||
extra_x = extra_y = 0;
|
||||
if (s->face->id == TAB_BAR_FACE_ID)
|
||||
{
|
||||
if (CONSP (Vtab_bar_button_margin)
|
||||
&& FIXNUMP (XCAR (Vtab_bar_button_margin))
|
||||
&& FIXNUMP (XCDR (Vtab_bar_button_margin)))
|
||||
{
|
||||
extra_x = XFIXNUM (XCAR (Vtab_bar_button_margin));
|
||||
extra_y = XFIXNUM (XCDR (Vtab_bar_button_margin));
|
||||
}
|
||||
else if (FIXNUMP (Vtab_bar_button_margin))
|
||||
extra_x = extra_y = XFIXNUM (Vtab_bar_button_margin);
|
||||
}
|
||||
|
||||
if (s->face->id == TOOL_BAR_FACE_ID)
|
||||
{
|
||||
if (CONSP (Vtool_bar_button_margin)
|
||||
|
@ -8396,10 +8411,11 @@ handle_one_xevent (struct x_display_info *dpyinfo,
|
|||
/* If mouse-highlight is an integer, input clears out
|
||||
mouse highlighting. */
|
||||
if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight)
|
||||
#if ! defined (USE_GTK)
|
||||
&& (f == 0
|
||||
|| !EQ (f->tool_bar_window, hlinfo->mouse_face_window))
|
||||
#if ! defined (USE_GTK)
|
||||
|| !EQ (f->tool_bar_window, hlinfo->mouse_face_window)
|
||||
#endif
|
||||
|| !EQ (f->tab_bar_window, hlinfo->mouse_face_window))
|
||||
)
|
||||
{
|
||||
clear_mouse_face (hlinfo);
|
||||
|
@ -8823,7 +8839,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
|
|||
{
|
||||
static Lisp_Object last_mouse_window;
|
||||
Lisp_Object window = window_from_coordinates
|
||||
(f, event->xmotion.x, event->xmotion.y, 0, false);
|
||||
(f, event->xmotion.x, event->xmotion.y, 0, false, false);
|
||||
|
||||
/* A window will be autoselected only when it is not
|
||||
selected now and the last mouse movement event was
|
||||
|
@ -9034,6 +9050,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
|
|||
{
|
||||
/* If we decide we want to generate an event to be seen
|
||||
by the rest of Emacs, we put it here. */
|
||||
bool tab_bar_p = false;
|
||||
bool tool_bar_p = false;
|
||||
|
||||
memset (&compose_status, 0, sizeof (compose_status));
|
||||
|
@ -9070,6 +9087,23 @@ handle_one_xevent (struct x_display_info *dpyinfo,
|
|||
#endif
|
||||
if (f)
|
||||
{
|
||||
/* Is this in the tab-bar? */
|
||||
if (WINDOWP (f->tab_bar_window)
|
||||
&& WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window)))
|
||||
{
|
||||
Lisp_Object window;
|
||||
int x = event->xbutton.x;
|
||||
int y = event->xbutton.y;
|
||||
|
||||
window = window_from_coordinates (f, x, y, 0, true, true);
|
||||
tab_bar_p = EQ (window, f->tab_bar_window);
|
||||
|
||||
if (tab_bar_p && event->xbutton.button < 4)
|
||||
handle_tab_bar_click
|
||||
(f, x, y, event->xbutton.type == ButtonPress,
|
||||
x_x_to_emacs_modifiers (dpyinfo, event->xbutton.state));
|
||||
}
|
||||
|
||||
#if ! defined (USE_GTK)
|
||||
/* Is this in the tool-bar? */
|
||||
if (WINDOWP (f->tool_bar_window)
|
||||
|
@ -9079,7 +9113,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
|
|||
int x = event->xbutton.x;
|
||||
int y = event->xbutton.y;
|
||||
|
||||
window = window_from_coordinates (f, x, y, 0, true);
|
||||
window = window_from_coordinates (f, x, y, 0, true, true);
|
||||
tool_bar_p = EQ (window, f->tool_bar_window);
|
||||
|
||||
if (tool_bar_p && event->xbutton.button < 4)
|
||||
|
@ -9089,7 +9123,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
|
|||
}
|
||||
#endif /* !USE_GTK */
|
||||
|
||||
if (!tool_bar_p)
|
||||
if (!tab_bar_p && !tool_bar_p)
|
||||
#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
|
||||
if (! popup_activated ())
|
||||
#endif
|
||||
|
@ -9136,6 +9170,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
|
|||
{
|
||||
dpyinfo->grabbed |= (1 << event->xbutton.button);
|
||||
dpyinfo->last_mouse_frame = f;
|
||||
if (f && !tab_bar_p)
|
||||
f->last_tab_bar_item = -1;
|
||||
#if ! defined (USE_GTK)
|
||||
if (f && !tool_bar_p)
|
||||
f->last_tool_bar_item = -1;
|
||||
|
@ -10142,6 +10178,7 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
|
|||
int unit, font_ascent, font_descent;
|
||||
#ifndef USE_X_TOOLKIT
|
||||
int old_menu_bar_height = FRAME_MENU_BAR_HEIGHT (f);
|
||||
int old_tab_bar_height = FRAME_TAB_BAR_HEIGHT (f);
|
||||
Lisp_Object fullscreen;
|
||||
#endif
|
||||
|
||||
|
@ -10161,6 +10198,7 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
|
|||
|
||||
#ifndef USE_X_TOOLKIT
|
||||
FRAME_MENU_BAR_HEIGHT (f) = FRAME_MENU_BAR_LINES (f) * FRAME_LINE_HEIGHT (f);
|
||||
FRAME_TAB_BAR_HEIGHT (f) = FRAME_TAB_BAR_LINES (f) * FRAME_LINE_HEIGHT (f);
|
||||
#endif
|
||||
|
||||
/* Compute character columns occupied by scrollbar.
|
||||
|
@ -10185,18 +10223,20 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
|
|||
FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
|
||||
false, Qfont);
|
||||
#ifndef USE_X_TOOLKIT
|
||||
if (FRAME_MENU_BAR_HEIGHT (f) != old_menu_bar_height
|
||||
if ((FRAME_MENU_BAR_HEIGHT (f) != old_menu_bar_height
|
||||
|| FRAME_TAB_BAR_HEIGHT (f) != old_tab_bar_height)
|
||||
&& !f->after_make_frame
|
||||
&& (EQ (frame_inhibit_implied_resize, Qt)
|
||||
|| (CONSP (frame_inhibit_implied_resize)
|
||||
&& NILP (Fmemq (Qfont, frame_inhibit_implied_resize))))
|
||||
&& (NILP (fullscreen = get_frame_param (f, Qfullscreen))
|
||||
|| EQ (fullscreen, Qfullwidth)))
|
||||
/* If the menu bar height changes, try to keep text height
|
||||
/* If the menu/tab bar height changes, try to keep text height
|
||||
constant. */
|
||||
adjust_frame_size
|
||||
(f, -1, FRAME_TEXT_HEIGHT (f) + FRAME_MENU_BAR_HEIGHT (f)
|
||||
- old_menu_bar_height, 1, false, Qfont);
|
||||
+ FRAME_TAB_BAR_HEIGHT (f)
|
||||
- old_menu_bar_height - old_tab_bar_height, 1, false, Qfont);
|
||||
#endif /* USE_X_TOOLKIT */
|
||||
}
|
||||
}
|
||||
|
@ -13466,6 +13506,7 @@ x_create_terminal (struct x_display_info *dpyinfo)
|
|||
#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
|
||||
terminal->popup_dialog_hook = xw_popup_dialog;
|
||||
#endif
|
||||
terminal->change_tab_bar_height_hook = x_change_tab_bar_height;
|
||||
#ifndef HAVE_EXT_TOOL_BAR
|
||||
terminal->change_tool_bar_height_hook = x_change_tool_bar_height;
|
||||
#endif
|
||||
|
|
|
@ -1178,6 +1178,7 @@ extern void initial_set_up_x_back_buffer (struct frame *f);
|
|||
|
||||
/* Defined in xfns.c. */
|
||||
extern void x_real_positions (struct frame *, int *, int *);
|
||||
extern void x_change_tab_bar_height (struct frame *, int);
|
||||
extern void x_change_tool_bar_height (struct frame *, int);
|
||||
extern void x_implicitly_set_name (struct frame *, Lisp_Object, Lisp_Object);
|
||||
extern void x_set_scroll_bar_default_width (struct frame *);
|
||||
|
|
Loading…
Add table
Reference in a new issue