diff options
| author | Juri Linkov | 2019-10-01 23:15:03 +0300 |
|---|---|---|
| committer | Juri Linkov | 2019-10-01 23:15:03 +0300 |
| commit | 2698d3dba2e9858b026ed127d4de3f86810a5ef3 (patch) | |
| tree | 8e9b8f194cfcad8af83a4174a0105bbc691f06d6 | |
| parent | 25f45d710e91a7c1049f056ff27bc3e6968f5624 (diff) | |
| parent | 3f981a0a89bca47a207fb362485f07e7322bb145 (diff) | |
| download | emacs-2698d3dba2e9858b026ed127d4de3f86810a5ef3.tar.gz emacs-2698d3dba2e9858b026ed127d4de3f86810a5ef3.zip | |
Merge branch 'feature/tabs'
53 files changed, 3871 insertions, 187 deletions
diff --git a/doc/emacs/custom.texi b/doc/emacs/custom.texi index 0c2509e1cd6..7bb6142395f 100644 --- a/doc/emacs/custom.texi +++ b/doc/emacs/custom.texi | |||
| @@ -2150,6 +2150,10 @@ The mouse was in a vertical scroll bar. (This is the only kind of | |||
| 2150 | scroll bar Emacs currently supports.) | 2150 | scroll bar Emacs currently supports.) |
| 2151 | @item menu-bar | 2151 | @item menu-bar |
| 2152 | The mouse was in the menu bar. | 2152 | The mouse was in the menu bar. |
| 2153 | @item tab-bar | ||
| 2154 | The mouse was in a tab bar. | ||
| 2155 | @item tab-line | ||
| 2156 | The mouse was in a tab line. | ||
| 2153 | @item header-line | 2157 | @item header-line |
| 2154 | The mouse was in a header line. | 2158 | The mouse was in a header line. |
| 2155 | @ignore | 2159 | @ignore |
diff --git a/doc/emacs/display.texi b/doc/emacs/display.texi index 6fc99bd2716..84363d0f0d2 100644 --- a/doc/emacs/display.texi +++ b/doc/emacs/display.texi | |||
| @@ -722,6 +722,10 @@ Similar to @code{highlight} and @code{mode-line-highlight}, but used | |||
| 722 | for mouse-sensitive portions of text on header lines. This is a | 722 | for mouse-sensitive portions of text on header lines. This is a |
| 723 | separate face because the @code{header-line} face might be customized | 723 | separate face because the @code{header-line} face might be customized |
| 724 | in a way that does not interact well with @code{highlight}. | 724 | in a way that does not interact well with @code{highlight}. |
| 725 | @item tab-line | ||
| 726 | @cindex @code{tab-line} face | ||
| 727 | Similar to @code{mode-line} for a window's tab line, which appears | ||
| 728 | at the top of a window with tabs representing window buffers. | ||
| 725 | @item vertical-border | 729 | @item vertical-border |
| 726 | @cindex @code{vertical-border} face | 730 | @cindex @code{vertical-border} face |
| 727 | This face is used for the vertical divider between windows on text | 731 | 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. | |||
| 763 | @xref{Scroll Bars}. | 767 | @xref{Scroll Bars}. |
| 764 | @item tool-bar | 768 | @item tool-bar |
| 765 | This face determines the color of tool bar icons. @xref{Tool Bars}. | 769 | This face determines the color of tool bar icons. @xref{Tool Bars}. |
| 770 | @item tab-bar | ||
| 771 | This face determines the color of tab bar icons. @xref{Tab Bars}. | ||
| 766 | @item menu | 772 | @item menu |
| 767 | @cindex menu bar appearance | 773 | @cindex menu bar appearance |
| 768 | @cindex @code{menu} face, no effect if customized | 774 | @cindex @code{menu} face, no effect if customized |
diff --git a/doc/emacs/emacs.texi b/doc/emacs/emacs.texi index 17aaaea7364..28a0f562f89 100644 --- a/doc/emacs/emacs.texi +++ b/doc/emacs/emacs.texi | |||
| @@ -540,6 +540,7 @@ Frames and Graphical Displays | |||
| 540 | * Drag and Drop:: Using drag and drop to open files and insert text. | 540 | * Drag and Drop:: Using drag and drop to open files and insert text. |
| 541 | * Menu Bars:: Enabling and disabling the menu bar. | 541 | * Menu Bars:: Enabling and disabling the menu bar. |
| 542 | * Tool Bars:: Enabling and disabling the tool bar. | 542 | * Tool Bars:: Enabling and disabling the tool bar. |
| 543 | * Tab Bars:: Enabling and disabling the tab bar. | ||
| 543 | * Dialog Boxes:: Controlling use of dialog boxes. | 544 | * Dialog Boxes:: Controlling use of dialog boxes. |
| 544 | * Tooltips:: Displaying information at the current mouse position. | 545 | * Tooltips:: Displaying information at the current mouse position. |
| 545 | * Mouse Avoidance:: Preventing the mouse pointer from obscuring text. | 546 | * Mouse Avoidance:: Preventing the mouse pointer from obscuring text. |
diff --git a/doc/emacs/frames.texi b/doc/emacs/frames.texi index 367ac43a0a4..0003881fad1 100644 --- a/doc/emacs/frames.texi +++ b/doc/emacs/frames.texi | |||
| @@ -58,6 +58,7 @@ for doing so on MS-DOS). Menus are supported on all text terminals. | |||
| 58 | * Drag and Drop:: Using drag and drop to open files and insert text. | 58 | * Drag and Drop:: Using drag and drop to open files and insert text. |
| 59 | * Menu Bars:: Enabling and disabling the menu bar. | 59 | * Menu Bars:: Enabling and disabling the menu bar. |
| 60 | * Tool Bars:: Enabling and disabling the tool bar. | 60 | * Tool Bars:: Enabling and disabling the tool bar. |
| 61 | * Tab Bars:: Enabling and disabling the tab bar. | ||
| 61 | * Dialog Boxes:: Controlling use of dialog boxes. | 62 | * Dialog Boxes:: Controlling use of dialog boxes. |
| 62 | * Tooltips:: Displaying information at the current mouse position. | 63 | * Tooltips:: Displaying information at the current mouse position. |
| 63 | * Mouse Avoidance:: Preventing the mouse pointer from obscuring text. | 64 | * Mouse Avoidance:: Preventing the mouse pointer from obscuring text. |
| @@ -1214,6 +1215,41 @@ Parameters,,, elisp, The Emacs Lisp Reference Manual}. On macOS the | |||
| 1214 | tool bar is hidden when the frame is put into fullscreen, but can be | 1215 | tool bar is hidden when the frame is put into fullscreen, but can be |
| 1215 | displayed by moving the mouse pointer to the top of the screen. | 1216 | displayed by moving the mouse pointer to the top of the screen. |
| 1216 | 1217 | ||
| 1218 | @node Tab Bars | ||
| 1219 | @section Tab Bars | ||
| 1220 | @cindex Tab Bar mode | ||
| 1221 | @cindex mode, Tab Bar | ||
| 1222 | @cindex tabs, tabbar | ||
| 1223 | |||
| 1224 | On graphical displays and on text terminals, Emacs puts a @dfn{tab bar} | ||
| 1225 | at the top of each frame, just below the menu bar. This is a row of | ||
| 1226 | tabs which you can click on with the mouse to switch window configurations. | ||
| 1227 | |||
| 1228 | Each tab on the tab bar represents a named persistent window | ||
| 1229 | configuration. Its name is composed from the names of buffers | ||
| 1230 | visible in windows of the window configuration. Clicking on the | ||
| 1231 | tab name switches the current window configuration to the previously | ||
| 1232 | used configuration of windows and buffers. | ||
| 1233 | |||
| 1234 | If you are using the desktop library to save and restore your | ||
| 1235 | sessions, the tabs from the tab bar are recorded in the desktop file, | ||
| 1236 | together with their associated window configurations. | ||
| 1237 | |||
| 1238 | @findex tab-bar-mode | ||
| 1239 | @vindex tab-bar-mode | ||
| 1240 | To toggle the use of tab bars, type @kbd{M-x tab-bar-mode}. This | ||
| 1241 | command applies to all frames, including frames yet to be created. To | ||
| 1242 | control the use of tab bars at startup, customize the variable | ||
| 1243 | @code{tab-bar-mode}. | ||
| 1244 | |||
| 1245 | @vindex tab-bar-new-tab-choice | ||
| 1246 | @cindex Tab Bar new tab | ||
| 1247 | By default, Emacs follows the same behavior as when creating frames, | ||
| 1248 | to start a new tab with the current buffer, i.e. the buffer | ||
| 1249 | that was current before calling the command that adds a new tab. | ||
| 1250 | To start a new tab with other buffers, customize the variable | ||
| 1251 | @code{tab-bar-new-tab-choice}. | ||
| 1252 | |||
| 1217 | @node Dialog Boxes | 1253 | @node Dialog Boxes |
| 1218 | @section Using Dialog Boxes | 1254 | @section Using Dialog Boxes |
| 1219 | @cindex dialog boxes | 1255 | @cindex dialog boxes |
diff --git a/doc/emacs/glossary.texi b/doc/emacs/glossary.texi index ad16d72ddbf..30ddffab696 100644 --- a/doc/emacs/glossary.texi +++ b/doc/emacs/glossary.texi | |||
| @@ -1360,6 +1360,15 @@ your buffers, unsaved edits, undo history, etc. @xref{Exiting}. | |||
| 1360 | @key{TAB} is the tab character. In Emacs it is typically used for | 1360 | @key{TAB} is the tab character. In Emacs it is typically used for |
| 1361 | indentation or completion. | 1361 | indentation or completion. |
| 1362 | 1362 | ||
| 1363 | @item Tab Bar | ||
| 1364 | The tab bar is a row of tabs at the top of an Emacs frame. | ||
| 1365 | Clicking on one of these tabs switches named persistent window | ||
| 1366 | configurations. @xref{Tab Bars}. | ||
| 1367 | |||
| 1368 | @item Tab Line | ||
| 1369 | The tab line is a line of tabs at the top of an Emacs window. | ||
| 1370 | Clicking on one of these tabs switches window buffers. | ||
| 1371 | |||
| 1363 | @anchor{Glossary---Tags Table} | 1372 | @anchor{Glossary---Tags Table} |
| 1364 | @item Tags Table | 1373 | @item Tags Table |
| 1365 | A tags table is a file that serves as an index to the function | 1374 | A tags table is a file that serves as an index to the function |
diff --git a/doc/emacs/modes.texi b/doc/emacs/modes.texi index e01dfa2677b..64034d71860 100644 --- a/doc/emacs/modes.texi +++ b/doc/emacs/modes.texi | |||
| @@ -296,6 +296,12 @@ but the tool bar is only displayed on graphical terminals. @xref{Tool | |||
| 296 | Bars}. | 296 | Bars}. |
| 297 | 297 | ||
| 298 | @item | 298 | @item |
| 299 | Tab Bar mode gives each frame a tab bar. @xref{Tab Bars}. | ||
| 300 | |||
| 301 | @item | ||
| 302 | Tab Line mode gives each window a tab line. | ||
| 303 | |||
| 304 | @item | ||
| 299 | Transient Mark mode highlights the region, and makes many Emacs | 305 | Transient Mark mode highlights the region, and makes many Emacs |
| 300 | commands operate on the region when the mark is active. It is enabled | 306 | commands operate on the region when the mark is active. It is enabled |
| 301 | by default. @xref{Mark}. | 307 | by default. @xref{Mark}. |
diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi index 1fd56d02841..a351917b852 100644 --- a/doc/lispref/commands.texi +++ b/doc/lispref/commands.texi | |||
| @@ -1348,8 +1348,8 @@ button. @xref{Repeat Events}. | |||
| 1348 | @var{position} slot of a click event, you should typically use the | 1348 | @var{position} slot of a click event, you should typically use the |
| 1349 | functions documented in @ref{Accessing Mouse}. The explicit format of | 1349 | functions documented in @ref{Accessing Mouse}. The explicit format of |
| 1350 | the list depends on where the click occurred. For clicks in the text | 1350 | the list depends on where the click occurred. For clicks in the text |
| 1351 | area, mode line, header line, or in the fringe or marginal areas, the | 1351 | area, mode line, header line, tab line, or in the fringe or marginal |
| 1352 | mouse position list has the form | 1352 | areas, the mouse position list has the form |
| 1353 | 1353 | ||
| 1354 | @example | 1354 | @example |
| 1355 | (@var{window} @var{pos-or-area} (@var{x} . @var{y}) @var{timestamp} | 1355 | (@var{window} @var{pos-or-area} (@var{x} . @var{y}) @var{timestamp} |
| @@ -1368,8 +1368,9 @@ The window in which the click occurred. | |||
| 1368 | The buffer position of the character clicked on in the text area; or, | 1368 | The buffer position of the character clicked on in the text area; or, |
| 1369 | if the click was outside the text area, the window area where it | 1369 | if the click was outside the text area, the window area where it |
| 1370 | occurred. It is one of the symbols @code{mode-line}, | 1370 | occurred. It is one of the symbols @code{mode-line}, |
| 1371 | @code{header-line}, @code{vertical-line}, @code{left-margin}, | 1371 | @code{header-line}, @code{tab-line}, @code{vertical-line}, |
| 1372 | @code{right-margin}, @code{left-fringe}, or @code{right-fringe}. | 1372 | @code{left-margin}, @code{right-margin}, @code{left-fringe}, or |
| 1373 | @code{right-fringe}. | ||
| 1373 | 1374 | ||
| 1374 | In one special case, @var{pos-or-area} is a list containing a symbol | 1375 | In one special case, @var{pos-or-area} is a list containing a symbol |
| 1375 | (one of the symbols listed above) instead of just the symbol. This | 1376 | (one of the symbols listed above) instead of just the symbol. This |
| @@ -1380,12 +1381,12 @@ by Emacs. @xref{Key Sequence Input}. | |||
| 1380 | The relative pixel coordinates of the click. For clicks in the text | 1381 | The relative pixel coordinates of the click. For clicks in the text |
| 1381 | area of a window, the coordinate origin @code{(0 . 0)} is taken to be | 1382 | area of a window, the coordinate origin @code{(0 . 0)} is taken to be |
| 1382 | the top left corner of the text area. @xref{Window Sizes}. For | 1383 | the top left corner of the text area. @xref{Window Sizes}. For |
| 1383 | clicks in a mode line or header line, the coordinate origin is the top | 1384 | clicks in a mode line, header line or tab line, the coordinate origin |
| 1384 | left corner of the window itself. For fringes, margins, and the | 1385 | is the top left corner of the window itself. For fringes, margins, |
| 1385 | vertical border, @var{x} does not have meaningful data. For fringes | 1386 | and the vertical border, @var{x} does not have meaningful data. |
| 1386 | and margins, @var{y} is relative to the bottom edge of the header | 1387 | For fringes and margins, @var{y} is relative to the bottom edge of the |
| 1387 | line. In all cases, the @var{x} and @var{y} coordinates increase | 1388 | header line. In all cases, the @var{x} and @var{y} coordinates |
| 1388 | rightward and downward respectively. | 1389 | increase rightward and downward respectively. |
| 1389 | 1390 | ||
| 1390 | @item @var{timestamp} | 1391 | @item @var{timestamp} |
| 1391 | The time at which the event occurred, as an integer number of | 1392 | 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. | |||
| 1407 | @item @var{text-pos} | 1408 | @item @var{text-pos} |
| 1408 | For clicks on a marginal area or on a fringe, this is the buffer | 1409 | For clicks on a marginal area or on a fringe, this is the buffer |
| 1409 | position of the first visible character in the corresponding line in | 1410 | position of the first visible character in the corresponding line in |
| 1410 | the window. For clicks on the mode line or the header line, this is | 1411 | the window. For clicks on the mode line, the header line or the tab |
| 1411 | @code{nil}. For other events, it is the buffer position closest to | 1412 | line, this is @code{nil}. For other events, it is the buffer position |
| 1412 | the click. | 1413 | closest to the click. |
| 1413 | 1414 | ||
| 1414 | @item @var{col}, @var{row} | 1415 | @item @var{col}, @var{row} |
| 1415 | These are the actual column and row coordinate numbers of the glyph | 1416 | These are the actual column and row coordinate numbers of the glyph |
| 1416 | under the @var{x}, @var{y} position. If @var{x} lies beyond the last | 1417 | under the @var{x}, @var{y} position. If @var{x} lies beyond the last |
| 1417 | column of actual text on its line, @var{col} is reported by adding | 1418 | column of actual text on its line, @var{col} is reported by adding |
| 1418 | fictional extra columns that have the default character width. Row 0 | 1419 | fictional extra columns that have the default character width. |
| 1419 | is taken to be the header line if the window has one, or the topmost | 1420 | Row 0 is taken to be the header line if the window has one, or Row 1 |
| 1420 | row of the text area otherwise. Column 0 is taken to be the leftmost | 1421 | if the window also has the tab line, or the topmost row of |
| 1422 | the text area otherwise. Column 0 is taken to be the leftmost | ||
| 1421 | column of the text area for clicks on a window text area, or the | 1423 | column of the text area for clicks on a window text area, or the |
| 1422 | leftmost mode line or header line column for clicks there. For clicks | 1424 | leftmost mode line or header line column for clicks there. For clicks |
| 1423 | on fringes or vertical borders, these have no meaningful data. For | 1425 | on fringes or vertical borders, these have no meaningful data. For |
| @@ -2094,7 +2096,8 @@ computed values.) | |||
| 2094 | 2096 | ||
| 2095 | Note that @var{row} is counted from the top of the text area. If the | 2097 | Note that @var{row} is counted from the top of the text area. If the |
| 2096 | window given by @var{position} possesses a header line (@pxref{Header | 2098 | window given by @var{position} possesses a header line (@pxref{Header |
| 2097 | Lines}), it is @emph{not} included in the @var{row} count. | 2099 | Lines}) or a tab line, they are @emph{not} included in the @var{row} |
| 2100 | count. | ||
| 2098 | @end defun | 2101 | @end defun |
| 2099 | 2102 | ||
| 2100 | @defun posn-actual-col-row position | 2103 | @defun posn-actual-col-row position |
| @@ -2452,12 +2455,14 @@ button-down events entirely. It also reshuffles focus events and | |||
| 2452 | miscellaneous window events so that they never appear in a key sequence | 2455 | miscellaneous window events so that they never appear in a key sequence |
| 2453 | with any other events. | 2456 | with any other events. |
| 2454 | 2457 | ||
| 2458 | @cindex @code{tab-line} prefix key | ||
| 2455 | @cindex @code{header-line} prefix key | 2459 | @cindex @code{header-line} prefix key |
| 2456 | @cindex @code{mode-line} prefix key | 2460 | @cindex @code{mode-line} prefix key |
| 2457 | @cindex @code{vertical-line} prefix key | 2461 | @cindex @code{vertical-line} prefix key |
| 2458 | @cindex @code{horizontal-scroll-bar} prefix key | 2462 | @cindex @code{horizontal-scroll-bar} prefix key |
| 2459 | @cindex @code{vertical-scroll-bar} prefix key | 2463 | @cindex @code{vertical-scroll-bar} prefix key |
| 2460 | @cindex @code{menu-bar} prefix key | 2464 | @cindex @code{menu-bar} prefix key |
| 2465 | @cindex @code{tab-bar} prefix key | ||
| 2461 | @cindex mouse events, in special parts of frame | 2466 | @cindex mouse events, in special parts of frame |
| 2462 | When mouse events occur in special parts of a window, such as a mode | 2467 | When mouse events occur in special parts of a window, such as a mode |
| 2463 | line or a scroll bar, the event type shows nothing special---it is the | 2468 | 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 | |||
| 2465 | button and modifier keys. The information about the window part is kept | 2470 | button and modifier keys. The information about the window part is kept |
| 2466 | elsewhere in the event---in the coordinates. But | 2471 | elsewhere in the event---in the coordinates. But |
| 2467 | @code{read-key-sequence} translates this information into imaginary | 2472 | @code{read-key-sequence} translates this information into imaginary |
| 2468 | prefix keys, all of which are symbols: @code{header-line}, | 2473 | prefix keys, all of which are symbols: @code{tab-line}, @code{header-line}, |
| 2469 | @code{horizontal-scroll-bar}, @code{menu-bar}, @code{mode-line}, | 2474 | @code{horizontal-scroll-bar}, @code{menu-bar}, @code{tab-bar}, @code{mode-line}, |
| 2470 | @code{vertical-line}, and @code{vertical-scroll-bar}. You can define | 2475 | @code{vertical-line}, and @code{vertical-scroll-bar}. You can define |
| 2471 | meanings for mouse clicks in special window parts by defining key | 2476 | meanings for mouse clicks in special window parts by defining key |
| 2472 | sequences using these imaginary prefix keys. | 2477 | sequences using these imaginary prefix keys. |
diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 64b24f712ae..494bf0d3f7e 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi | |||
| @@ -2944,6 +2944,7 @@ If the text lies within the mode line of the selected window, Emacs | |||
| 2944 | applies the @code{mode-line} face. For the mode line of a | 2944 | applies the @code{mode-line} face. For the mode line of a |
| 2945 | non-selected window, Emacs applies the @code{mode-line-inactive} face. | 2945 | non-selected window, Emacs applies the @code{mode-line-inactive} face. |
| 2946 | For a header line, Emacs applies the @code{header-line} face. | 2946 | For a header line, Emacs applies the @code{header-line} face. |
| 2947 | For a tab line, Emacs applies the @code{tab-line} face. | ||
| 2947 | 2948 | ||
| 2948 | @item | 2949 | @item |
| 2949 | If the text comes from an overlay string via @code{before-string} or | 2950 | If the text comes from an overlay string via @code{before-string} or |
diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi index 39d3960c9a2..f05a6db1761 100644 --- a/doc/lispref/windows.texi +++ b/doc/lispref/windows.texi | |||
| @@ -5558,6 +5558,9 @@ The coordinates are in the mode line of @var{window}. | |||
| 5558 | @item header-line | 5558 | @item header-line |
| 5559 | The coordinates are in the header line of @var{window}. | 5559 | The coordinates are in the header line of @var{window}. |
| 5560 | 5560 | ||
| 5561 | @item tab-line | ||
| 5562 | The coordinates are in the tab line of @var{window}. | ||
| 5563 | |||
| 5561 | @item right-divider | 5564 | @item right-divider |
| 5562 | The coordinates are in the divider separating @var{window} from a | 5565 | The coordinates are in the divider separating @var{window} from a |
| 5563 | window on the right. | 5566 | window on the right. |
| @@ -6115,6 +6118,15 @@ to suppress display of a header line for this window. Display and | |||
| 6115 | contents of the header line on other windows showing this buffer are not | 6118 | contents of the header line on other windows showing this buffer are not |
| 6116 | affected. | 6119 | affected. |
| 6117 | 6120 | ||
| 6121 | @item tab-line-format | ||
| 6122 | @vindex tab-line-format@r{, a window parameter} | ||
| 6123 | This parameter replaces the value of the buffer-local variable | ||
| 6124 | @code{tab-line-format} (@pxref{Mode Line Basics}) of this window's | ||
| 6125 | buffer whenever this window is displayed. The symbol @code{none} means | ||
| 6126 | to suppress display of a tab line for this window. Display and | ||
| 6127 | contents of the tab line on other windows showing this buffer are not | ||
| 6128 | affected. | ||
| 6129 | |||
| 6118 | @item min-margins | 6130 | @item min-margins |
| 6119 | @vindex min-margins@r{, a window parameter} | 6131 | @vindex min-margins@r{, a window parameter} |
| 6120 | The value of this parameter is a cons cell whose @sc{car} and | 6132 | The value of this parameter is a cons cell whose @sc{car} and |
| @@ -2030,6 +2030,34 @@ file-local variable, you may need to update the value. | |||
| 2030 | 2030 | ||
| 2031 | * New Modes and Packages in Emacs 27.1 | 2031 | * New Modes and Packages in Emacs 27.1 |
| 2032 | 2032 | ||
| 2033 | ** 'tab-bar-mode' enables the tab-bar at the top of each frame, | ||
| 2034 | to switch named persistent window configurations in it using tabs. | ||
| 2035 | New tab-based keybindings (similar to frame-based commands): | ||
| 2036 | 'C-x 6 2' creates a new tab; | ||
| 2037 | 'C-x 6 0' deletes the current tab; | ||
| 2038 | 'C-x 6 b' switches to buffer in another tab; | ||
| 2039 | 'C-x 6 f' and 'C-x 6 C-f' edit file in another tab; | ||
| 2040 | 'C-TAB' switches to the next tab; | ||
| 2041 | 'S-C-TAB' switches to the previous tab. | ||
| 2042 | |||
| 2043 | Also it's possible to switch named persistent window configurations | ||
| 2044 | without having graphical access to the tab-bar, even on a tty | ||
| 2045 | or when 'tab-bar-mode' is disabled, with these commands: | ||
| 2046 | 'tab-new' creates a new window configuration; | ||
| 2047 | 'tab-close' deletes the current window configuration; | ||
| 2048 | 'tab-select' switches to the window configuration by its name; | ||
| 2049 | 'tab-previous' switches to the previous window configuration; | ||
| 2050 | 'tab-next' switches to the next window configuration; | ||
| 2051 | 'tab-list' displays a list of named window configurations for switching. | ||
| 2052 | |||
| 2053 | ** 'global-tab-line-mode' enables the tab-line above each window to | ||
| 2054 | switch buffers in it to previous/next buffers. Selecting a previous | ||
| 2055 | window-local tab is the same as running 'C-x <left>' (previous-buffer), | ||
| 2056 | selecting a next tab switches to the tab available by 'C-x <right>' | ||
| 2057 | (next-buffer). Clicking on the plus icon adds a new buffer to the | ||
| 2058 | window-local tab-line of window buffers. Using the mouse wheel on the | ||
| 2059 | tab-line scrolls the window buffers whose names are displayed in tabs. | ||
| 2060 | |||
| 2033 | ** fileloop.el lets one setup multifile operations like search&replace. | 2061 | ** fileloop.el lets one setup multifile operations like search&replace. |
| 2034 | 2062 | ||
| 2035 | +++ | 2063 | +++ |
| @@ -324,20 +324,6 @@ consistency checks that make sure the new code computes the same results | |||
| 324 | as the old code. And once that works well, we can remove the old code | 324 | as the old code. And once that works well, we can remove the old code |
| 325 | and old fields. | 325 | and old fields. |
| 326 | 326 | ||
| 327 | ** Having tabs above a window to switch buffers in it. | ||
| 328 | |||
| 329 | ** "Perspectives" are named persistent window configurations. We have | ||
| 330 | had the window configuration mechanism in GNU Emacs since the | ||
| 331 | beginning but we have never developed a good user interface to take | ||
| 332 | advantage of them. Eclipse's user interface seems to be good. | ||
| 333 | |||
| 334 | Perspectives work well even if you do the equivalent of C-x 4 C-f | ||
| 335 | because of the distinction between view windows vs file windows. In | ||
| 336 | Emacs this is more or less the "dedicated window" feature, but we have | ||
| 337 | never really made it work for this. | ||
| 338 | |||
| 339 | Perspectives also need to interact with the tabs. | ||
| 340 | |||
| 341 | ** FFI (foreign function interface) | 327 | ** FFI (foreign function interface) |
| 342 | See eg https://lists.gnu.org/r/emacs-devel/2013-10/msg00246.html | 328 | See eg https://lists.gnu.org/r/emacs-devel/2013-10/msg00246.html |
| 343 | 329 | ||
diff --git a/etc/images/tabs/README b/etc/images/tabs/README new file mode 100644 index 00000000000..1e9f4e5b595 --- /dev/null +++ b/etc/images/tabs/README | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | This directory contains icons for the Tabs user interface. | ||
| 2 | |||
| 3 | COPYRIGHT AND LICENSE INFORMATION FOR IMAGE FILES | ||
| 4 | |||
| 5 | Files: close.xpm new.xpm | ||
| 6 | Author: Juri Linkov <juri@linkov.net> | ||
| 7 | Copyright (C) 2019 Free Software Foundation, Inc. | ||
| 8 | License: GNU General Public License version 3 or later (see COPYING) | ||
diff --git a/etc/images/tabs/close.xpm b/etc/images/tabs/close.xpm new file mode 100644 index 00000000000..1c3f4d8fd7d --- /dev/null +++ b/etc/images/tabs/close.xpm | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | /* XPM */ | ||
| 2 | static char * close_xpm[] = { | ||
| 3 | "9 9 4 1", | ||
| 4 | " c None", | ||
| 5 | ". c #BFBFBF", | ||
| 6 | "+ c #000000", | ||
| 7 | "@ c #808080", | ||
| 8 | " ..... ", | ||
| 9 | " ....... ", | ||
| 10 | "..+@.@+..", | ||
| 11 | "..@+@+@..", | ||
| 12 | "...@+@...", | ||
| 13 | "..@+@+@..", | ||
| 14 | "..+@.@+..", | ||
| 15 | " ....... ", | ||
| 16 | " ..... "}; | ||
diff --git a/etc/images/tabs/new.xpm b/etc/images/tabs/new.xpm new file mode 100644 index 00000000000..e10a8ef238b --- /dev/null +++ b/etc/images/tabs/new.xpm | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | /* XPM */ | ||
| 2 | static char * new_xpm[] = { | ||
| 3 | "9 9 4 1", | ||
| 4 | " c None", | ||
| 5 | ". c #BFBFBF", | ||
| 6 | "+ c #808080", | ||
| 7 | "@ c #000000", | ||
| 8 | ".........", | ||
| 9 | "....+....", | ||
| 10 | "....@....", | ||
| 11 | "....@....", | ||
| 12 | ".+@@@@@+.", | ||
| 13 | "....@....", | ||
| 14 | "....@....", | ||
| 15 | "....+....", | ||
| 16 | "........."}; | ||
diff --git a/lisp/cus-start.el b/lisp/cus-start.el index 15d33b43c01..e61c1954a1f 100644 --- a/lisp/cus-start.el +++ b/lisp/cus-start.el | |||
| @@ -324,6 +324,9 @@ Leaving \"Default\" unchecked is equivalent with specifying a default of | |||
| 324 | ;; FIXME? | 324 | ;; FIXME? |
| 325 | ;; :initialize custom-initialize-default | 325 | ;; :initialize custom-initialize-default |
| 326 | :set custom-set-minor-mode) | 326 | :set custom-set-minor-mode) |
| 327 | (tab-bar-mode (frames mouse) boolean nil | ||
| 328 | ;; :initialize custom-initialize-default | ||
| 329 | :set custom-set-minor-mode) | ||
| 327 | (tool-bar-mode (frames mouse) boolean nil | 330 | (tool-bar-mode (frames mouse) boolean nil |
| 328 | ;; :initialize custom-initialize-default | 331 | ;; :initialize custom-initialize-default |
| 329 | :set custom-set-minor-mode) | 332 | :set custom-set-minor-mode) |
| @@ -726,6 +729,8 @@ since it could result in memory overflow and make Emacs crash." | |||
| 726 | ;; the condition for loadup.el to preload tool-bar.el. | 729 | ;; the condition for loadup.el to preload tool-bar.el. |
| 727 | ((string-match "tool-bar-" (symbol-name symbol)) | 730 | ((string-match "tool-bar-" (symbol-name symbol)) |
| 728 | (fboundp 'x-create-frame)) | 731 | (fboundp 'x-create-frame)) |
| 732 | ((string-match "tab-bar-" (symbol-name symbol)) | ||
| 733 | (fboundp 'x-create-frame)) | ||
| 729 | ((equal "vertical-centering-font-regexp" | 734 | ((equal "vertical-centering-font-regexp" |
| 730 | (symbol-name symbol)) | 735 | (symbol-name symbol)) |
| 731 | ;; Any function from fontset.c will do. | 736 | ;; Any function from fontset.c will do. |
diff --git a/lisp/frame.el b/lisp/frame.el index e9d4b2ebe4c..0c68fc378b9 100644 --- a/lisp/frame.el +++ b/lisp/frame.el | |||
| @@ -363,6 +363,47 @@ there (in decreasing order of priority)." | |||
| 363 | ;; If the initial frame is still around, apply initial-frame-alist | 363 | ;; If the initial frame is still around, apply initial-frame-alist |
| 364 | ;; and default-frame-alist to it. | 364 | ;; and default-frame-alist to it. |
| 365 | (when (frame-live-p frame-initial-frame) | 365 | (when (frame-live-p frame-initial-frame) |
| 366 | ;; When tab-bar has been switched off, correct the frame size | ||
| 367 | ;; by the lines added in x-create-frame for the tab-bar and | ||
| 368 | ;; switch `tab-bar-mode' off. | ||
| 369 | (when (display-graphic-p) | ||
| 370 | (let* ((init-lines | ||
| 371 | (assq 'tab-bar-lines initial-frame-alist)) | ||
| 372 | (other-lines | ||
| 373 | (or (assq 'tab-bar-lines window-system-frame-alist) | ||
| 374 | (assq 'tab-bar-lines default-frame-alist))) | ||
| 375 | (lines (or init-lines other-lines)) | ||
| 376 | (height (tab-bar-height frame-initial-frame t))) | ||
| 377 | ;; Adjust frame top if either zero (nil) tab bar lines have | ||
| 378 | ;; been requested in the most relevant of the frame's alists | ||
| 379 | ;; or tab bar mode has been explicitly turned off in the | ||
| 380 | ;; user's init file. | ||
| 381 | (when (and (> height 0) | ||
| 382 | (or (and lines | ||
| 383 | (or (null (cdr lines)) | ||
| 384 | (eq 0 (cdr lines)))) | ||
| 385 | (not tab-bar-mode))) | ||
| 386 | (let* ((initial-top | ||
| 387 | (cdr (assq 'top frame-initial-geometry-arguments))) | ||
| 388 | (top (frame-parameter frame-initial-frame 'top))) | ||
| 389 | (when (and (consp initial-top) (eq '- (car initial-top))) | ||
| 390 | (let ((adjusted-top | ||
| 391 | (cond | ||
| 392 | ((and (consp top) (eq '+ (car top))) | ||
| 393 | (list '+ (+ (cadr top) height))) | ||
| 394 | ((and (consp top) (eq '- (car top))) | ||
| 395 | (list '- (- (cadr top) height))) | ||
| 396 | (t (+ top height))))) | ||
| 397 | (modify-frame-parameters | ||
| 398 | frame-initial-frame `((top . ,adjusted-top)))))) | ||
| 399 | ;; Reset `tab-bar-mode' when zero tab bar lines have been | ||
| 400 | ;; requested for the window-system or default frame alists. | ||
| 401 | (when (and tab-bar-mode | ||
| 402 | (and other-lines | ||
| 403 | (or (null (cdr other-lines)) | ||
| 404 | (eq 0 (cdr other-lines))))) | ||
| 405 | (tab-bar-mode -1))))) | ||
| 406 | |||
| 366 | ;; When tool-bar has been switched off, correct the frame size | 407 | ;; When tool-bar has been switched off, correct the frame size |
| 367 | ;; by the lines added in x-create-frame for the tool-bar and | 408 | ;; by the lines added in x-create-frame for the tool-bar and |
| 368 | ;; switch `tool-bar-mode' off. | 409 | ;; switch `tool-bar-mode' off. |
| @@ -1593,6 +1634,7 @@ and width values are in pixels. | |||
| 1593 | '(tool-bar-external . nil) | 1634 | '(tool-bar-external . nil) |
| 1594 | '(tool-bar-position . nil) | 1635 | '(tool-bar-position . nil) |
| 1595 | '(tool-bar-size 0 . 0) | 1636 | '(tool-bar-size 0 . 0) |
| 1637 | '(tab-bar-size 0 . 0) | ||
| 1596 | (cons 'internal-border-width | 1638 | (cons 'internal-border-width |
| 1597 | (frame-parameter frame 'internal-border-width))))))) | 1639 | (frame-parameter frame 'internal-border-width))))))) |
| 1598 | 1640 | ||
diff --git a/lisp/loadup.el b/lisp/loadup.el index 67e8aa7d40a..e60922e380a 100644 --- a/lisp/loadup.el +++ b/lisp/loadup.el | |||
| @@ -267,6 +267,7 @@ | |||
| 267 | (load "rfn-eshadow") | 267 | (load "rfn-eshadow") |
| 268 | 268 | ||
| 269 | (load "menu-bar") | 269 | (load "menu-bar") |
| 270 | (load "tab-bar") | ||
| 270 | (load "emacs-lisp/lisp") | 271 | (load "emacs-lisp/lisp") |
| 271 | (load "textmodes/page") | 272 | (load "textmodes/page") |
| 272 | (load "register") | 273 | (load "register") |
diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el index 19122125c53..b7967b858ae 100644 --- a/lisp/menu-bar.el +++ b/lisp/menu-bar.el | |||
| @@ -687,7 +687,7 @@ The selected font will be the default on both the existing and future frames." | |||
| 687 | ;; side-effect that turning them off via X | 687 | ;; side-effect that turning them off via X |
| 688 | ;; resources acts like having customized them, but | 688 | ;; resources acts like having customized them, but |
| 689 | ;; that seems harmless. | 689 | ;; that seems harmless. |
| 690 | menu-bar-mode tool-bar-mode)) | 690 | menu-bar-mode tab-bar-mode tool-bar-mode)) |
| 691 | ;; FIXME ? It's a little annoying that running this command | 691 | ;; FIXME ? It's a little annoying that running this command |
| 692 | ;; always loads cua-base, paren, time, and battery, even if they | 692 | ;; always loads cua-base, paren, time, and battery, even if they |
| 693 | ;; have not been customized in any way. (Due to custom-load-symbol.) | 693 | ;; have not been customized in any way. (Due to custom-load-symbol.) |
| @@ -1242,6 +1242,14 @@ mail status in mode line")) | |||
| 1242 | (frame-parameter (menu-bar-frame-for-menubar) | 1242 | (frame-parameter (menu-bar-frame-for-menubar) |
| 1243 | 'menu-bar-lines))))) | 1243 | 'menu-bar-lines))))) |
| 1244 | 1244 | ||
| 1245 | (bindings--define-key menu [showhide-tab-bar] | ||
| 1246 | '(menu-item "Tab Bar" toggle-tab-bar-mode-from-frame | ||
| 1247 | :help "Turn tab bar on/off" | ||
| 1248 | :button | ||
| 1249 | (:toggle . (menu-bar-positive-p | ||
| 1250 | (frame-parameter (menu-bar-frame-for-menubar) | ||
| 1251 | 'tab-bar-lines))))) | ||
| 1252 | |||
| 1245 | (if (and (boundp 'menu-bar-showhide-tool-bar-menu) | 1253 | (if (and (boundp 'menu-bar-showhide-tool-bar-menu) |
| 1246 | (keymapp menu-bar-showhide-tool-bar-menu)) | 1254 | (keymapp menu-bar-showhide-tool-bar-menu)) |
| 1247 | (bindings--define-key menu [showhide-tool-bar] | 1255 | (bindings--define-key menu [showhide-tool-bar] |
diff --git a/lisp/mouse.el b/lisp/mouse.el index 123ce2ca154..76fec507e71 100644 --- a/lisp/mouse.el +++ b/lisp/mouse.el | |||
| @@ -2734,6 +2734,7 @@ is copied instead of being cut." | |||
| 2734 | ;; versions. | 2734 | ;; versions. |
| 2735 | (global-set-key [header-line down-mouse-1] 'mouse-drag-header-line) | 2735 | (global-set-key [header-line down-mouse-1] 'mouse-drag-header-line) |
| 2736 | (global-set-key [header-line mouse-1] 'mouse-select-window) | 2736 | (global-set-key [header-line mouse-1] 'mouse-select-window) |
| 2737 | (global-set-key [tab-line mouse-1] 'mouse-select-window) | ||
| 2737 | ;; (global-set-key [mode-line drag-mouse-1] 'mouse-select-window) | 2738 | ;; (global-set-key [mode-line drag-mouse-1] 'mouse-select-window) |
| 2738 | (global-set-key [mode-line down-mouse-1] 'mouse-drag-mode-line) | 2739 | (global-set-key [mode-line down-mouse-1] 'mouse-drag-mode-line) |
| 2739 | (global-set-key [mode-line mouse-1] 'mouse-select-window) | 2740 | (global-set-key [mode-line mouse-1] 'mouse-select-window) |
diff --git a/lisp/startup.el b/lisp/startup.el index 52d4dbb05c8..393d7872560 100644 --- a/lisp/startup.el +++ b/lisp/startup.el | |||
| @@ -769,6 +769,7 @@ It is the default value of the variable `top-level'." | |||
| 769 | ("--background-color" . "-bg") | 769 | ("--background-color" . "-bg") |
| 770 | ("--color" . "-color"))) | 770 | ("--color" . "-color"))) |
| 771 | 771 | ||
| 772 | ;; FIXME: this var unused? | ||
| 772 | (defconst tool-bar-images-pixel-height 24 | 773 | (defconst tool-bar-images-pixel-height 24 |
| 773 | "Height in pixels of images in the tool-bar.") | 774 | "Height in pixels of images in the tool-bar.") |
| 774 | 775 | ||
| @@ -1300,6 +1301,7 @@ please check its value") | |||
| 1300 | (unless (daemonp) | 1301 | (unless (daemonp) |
| 1301 | (if (or noninteractive emacs-basic-display) | 1302 | (if (or noninteractive emacs-basic-display) |
| 1302 | (setq menu-bar-mode nil | 1303 | (setq menu-bar-mode nil |
| 1304 | tab-bar-mode nil | ||
| 1303 | tool-bar-mode nil | 1305 | tool-bar-mode nil |
| 1304 | no-blinking-cursor t)) | 1306 | no-blinking-cursor t)) |
| 1305 | (frame-initialize)) | 1307 | (frame-initialize)) |
| @@ -1515,6 +1517,7 @@ This can set the values of `menu-bar-mode', `tool-bar-mode', and | |||
| 1515 | settings will be marked as \"CHANGED outside of Customize\"." | 1517 | settings will be marked as \"CHANGED outside of Customize\"." |
| 1516 | (let ((no-vals '("no" "off" "false" "0")) | 1518 | (let ((no-vals '("no" "off" "false" "0")) |
| 1517 | (settings '(("menuBar" "MenuBar" menu-bar-mode nil) | 1519 | (settings '(("menuBar" "MenuBar" menu-bar-mode nil) |
| 1520 | ("tabBar" "TabBar" tab-bar-mode nil) | ||
| 1518 | ("toolBar" "ToolBar" tool-bar-mode nil) | 1521 | ("toolBar" "ToolBar" tool-bar-mode nil) |
| 1519 | ("scrollBar" "ScrollBar" scroll-bar-mode nil) | 1522 | ("scrollBar" "ScrollBar" scroll-bar-mode nil) |
| 1520 | ("cursorBlink" "CursorBlink" no-blinking-cursor t)))) | 1523 | ("cursorBlink" "CursorBlink" no-blinking-cursor t)))) |
diff --git a/lisp/subr.el b/lisp/subr.el index 45b99a82d2b..da619fef147 100644 --- a/lisp/subr.el +++ b/lisp/subr.el | |||
| @@ -2395,8 +2395,12 @@ some sort of escape sequence, the ambiguity is resolved via `read-key-delay'." | |||
| 2395 | (progn | 2395 | (progn |
| 2396 | (use-global-map | 2396 | (use-global-map |
| 2397 | (let ((map (make-sparse-keymap))) | 2397 | (let ((map (make-sparse-keymap))) |
| 2398 | ;; Don't hide the menu-bar and tool-bar entries. | 2398 | ;; Don't hide the menu-bar, tab-bar and tool-bar entries. |
| 2399 | (define-key map [menu-bar] (lookup-key global-map [menu-bar])) | 2399 | (define-key map [menu-bar] (lookup-key global-map [menu-bar])) |
| 2400 | (define-key map [tab-bar] | ||
| 2401 | ;; This hack avoids evaluating the :filter (Bug#9922). | ||
| 2402 | (or (cdr (assq 'tab-bar global-map)) | ||
| 2403 | (lookup-key global-map [tab-bar]))) | ||
| 2400 | (define-key map [tool-bar] | 2404 | (define-key map [tool-bar] |
| 2401 | ;; This hack avoids evaluating the :filter (Bug#9922). | 2405 | ;; This hack avoids evaluating the :filter (Bug#9922). |
| 2402 | (or (cdr (assq 'tool-bar global-map)) | 2406 | (or (cdr (assq 'tool-bar global-map)) |
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el new file mode 100644 index 00000000000..42d40a96543 --- /dev/null +++ b/lisp/tab-bar.el | |||
| @@ -0,0 +1,764 @@ | |||
| 1 | ;;; tab-bar.el --- frame-local tabs with named persistent window configurations -*- lexical-binding: t; -*- | ||
| 2 | |||
| 3 | ;; Copyright (C) 2019 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Juri Linkov <juri@linkov.net> | ||
| 6 | ;; Keywords: frames tabs | ||
| 7 | ;; Maintainer: emacs-devel@gnu.org | ||
| 8 | |||
| 9 | ;; This file is part of GNU Emacs. | ||
| 10 | |||
| 11 | ;; GNU Emacs is free software: you can redistribute it and/or modify | ||
| 12 | ;; it under the terms of the GNU General Public License as published by | ||
| 13 | ;; the Free Software Foundation, either version 3 of the License, or | ||
| 14 | ;; (at your option) any later version. | ||
| 15 | |||
| 16 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 19 | ;; GNU General Public License for more details. | ||
| 20 | |||
| 21 | ;; You should have received a copy of the GNU General Public License | ||
| 22 | ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. | ||
| 23 | |||
| 24 | ;;; Commentary: | ||
| 25 | |||
| 26 | ;; Provides `tab-bar-mode' to control display of the tab bar and | ||
| 27 | ;; bindings for the global tab bar. | ||
| 28 | |||
| 29 | ;; The normal global binding for [tab-bar] (below) uses the value of | ||
| 30 | ;; `tab-bar-map' as the actual keymap to define the tab bar. Modes | ||
| 31 | ;; may either bind items under the [tab-bar] prefix key of the local | ||
| 32 | ;; map to add to the global bar or may set `tab-bar-map' | ||
| 33 | ;; buffer-locally to override it. | ||
| 34 | |||
| 35 | ;;; Code: | ||
| 36 | |||
| 37 | |||
| 38 | (defgroup tab-bar nil | ||
| 39 | "Frame-local tabs." | ||
| 40 | :group 'convenience | ||
| 41 | :version "27.1") | ||
| 42 | |||
| 43 | (defgroup tab-bar-faces nil | ||
| 44 | "Faces used in the tab bar." | ||
| 45 | :group 'tab-bar | ||
| 46 | :group 'faces | ||
| 47 | :version "27.1") | ||
| 48 | |||
| 49 | (defface tab-bar | ||
| 50 | '((((type x w32 ns) (class color)) | ||
| 51 | :height 1.1 | ||
| 52 | :background "grey85" | ||
| 53 | :foreground "black") | ||
| 54 | (((type x) (class mono)) | ||
| 55 | :background "grey") | ||
| 56 | (t | ||
| 57 | :inverse-video t)) | ||
| 58 | "Tab bar face." | ||
| 59 | :version "27.1" | ||
| 60 | :group 'tab-bar-faces) | ||
| 61 | |||
| 62 | (defface tab-bar-tab | ||
| 63 | '((((class color) (min-colors 88)) | ||
| 64 | :box (:line-width 1 :style released-button)) | ||
| 65 | (t | ||
| 66 | :inverse-video nil)) | ||
| 67 | "Tab bar face for selected tab." | ||
| 68 | :version "27.1" | ||
| 69 | :group 'tab-bar-faces) | ||
| 70 | |||
| 71 | (defface tab-bar-tab-inactive | ||
| 72 | '((default | ||
| 73 | :inherit tab-bar-tab) | ||
| 74 | (((class color) (min-colors 88)) | ||
| 75 | :background "grey75") | ||
| 76 | (t | ||
| 77 | :inverse-video t)) | ||
| 78 | "Tab bar face for non-selected tab." | ||
| 79 | :version "27.1" | ||
| 80 | :group 'tab-bar-faces) | ||
| 81 | |||
| 82 | |||
| 83 | (define-minor-mode tab-bar-mode | ||
| 84 | "Toggle the tab bar in all graphical frames (Tab Bar mode)." | ||
| 85 | :global t | ||
| 86 | ;; It's defined in C/cus-start, this stops the d-m-m macro defining it again. | ||
| 87 | :variable tab-bar-mode | ||
| 88 | (let ((val (if tab-bar-mode 1 0))) | ||
| 89 | (dolist (frame (frame-list)) | ||
| 90 | (set-frame-parameter frame 'tab-bar-lines val)) | ||
| 91 | ;; If the user has given `default-frame-alist' a `tab-bar-lines' | ||
| 92 | ;; parameter, replace it. | ||
| 93 | (if (assq 'tab-bar-lines default-frame-alist) | ||
| 94 | (setq default-frame-alist | ||
| 95 | (cons (cons 'tab-bar-lines val) | ||
| 96 | (assq-delete-all 'tab-bar-lines | ||
| 97 | default-frame-alist))))) | ||
| 98 | (when tab-bar-mode | ||
| 99 | (global-set-key [(control shift iso-lefttab)] 'tab-bar-switch-to-prev-tab) | ||
| 100 | (global-set-key [(control shift tab)] 'tab-bar-switch-to-prev-tab) | ||
| 101 | (global-set-key [(control tab)] 'tab-bar-switch-to-next-tab))) | ||
| 102 | |||
| 103 | (defun tab-bar-handle-mouse (event) | ||
| 104 | "Text-mode emulation of switching tabs on the tab bar. | ||
| 105 | This command is used when you click the mouse in the tab bar | ||
| 106 | on a console which has no window system but does have a mouse." | ||
| 107 | (interactive "e") | ||
| 108 | (let* ((x-position (car (posn-x-y (event-start event)))) | ||
| 109 | (keymap (lookup-key (cons 'keymap (nreverse (current-active-maps))) [tab-bar])) | ||
| 110 | (column 0)) | ||
| 111 | (when x-position | ||
| 112 | (unless (catch 'done | ||
| 113 | (map-keymap | ||
| 114 | (lambda (_key binding) | ||
| 115 | (when (eq (car-safe binding) 'menu-item) | ||
| 116 | (when (> (+ column (length (nth 1 binding))) x-position) | ||
| 117 | ;; TODO: handle close | ||
| 118 | (unless (get-text-property (- x-position column) 'close-tab (nth 1 binding)) | ||
| 119 | (call-interactively (nth 2 binding))) | ||
| 120 | (throw 'done t)) | ||
| 121 | (setq column (+ column (length (nth 1 binding)))))) | ||
| 122 | keymap)) | ||
| 123 | ;; Clicking anywhere outside existing tabs will add a new tab | ||
| 124 | (tab-bar-new-tab))))) | ||
| 125 | |||
| 126 | ;; Used in the Show/Hide menu, to have the toggle reflect the current frame. | ||
| 127 | (defun toggle-tab-bar-mode-from-frame (&optional arg) | ||
| 128 | "Toggle tab bar on or off, based on the status of the current frame. | ||
| 129 | See `tab-bar-mode' for more information." | ||
| 130 | (interactive (list (or current-prefix-arg 'toggle))) | ||
| 131 | (if (eq arg 'toggle) | ||
| 132 | (tab-bar-mode (if (> (frame-parameter nil 'tab-bar-lines) 0) 0 1)) | ||
| 133 | (tab-bar-mode arg))) | ||
| 134 | |||
| 135 | (defvar tab-bar-map (make-sparse-keymap) | ||
| 136 | "Keymap for the tab bar. | ||
| 137 | Define this locally to override the global tab bar.") | ||
| 138 | |||
| 139 | (global-set-key [tab-bar] | ||
| 140 | `(menu-item ,(purecopy "tab bar") ignore | ||
| 141 | :filter tab-bar-make-keymap)) | ||
| 142 | |||
| 143 | (defconst tab-bar-keymap-cache (make-hash-table :weakness t :test 'equal)) | ||
| 144 | |||
| 145 | (defun tab-bar-make-keymap (&optional _ignore) | ||
| 146 | "Generate an actual keymap from `tab-bar-map'. | ||
| 147 | Its main job is to show tabs in the tab bar." | ||
| 148 | (if (= 1 (length tab-bar-map)) | ||
| 149 | (tab-bar-make-keymap-1) | ||
| 150 | (let ((key (cons (frame-terminal) tab-bar-map))) | ||
| 151 | (or (gethash key tab-bar-keymap-cache) | ||
| 152 | (puthash key tab-bar-map tab-bar-keymap-cache))))) | ||
| 153 | |||
| 154 | |||
| 155 | (defcustom tab-bar-new-tab-choice t | ||
| 156 | "Defines what to show in a new tab. | ||
| 157 | If t, start a new tab with the current buffer, i.e. the buffer | ||
| 158 | that was current before calling the command that adds a new tab | ||
| 159 | (this is the same what `make-frame' does by default). | ||
| 160 | If the value is a string, switch to a buffer if it exists, or switch | ||
| 161 | to a buffer visiting the file or directory that the string specifies. | ||
| 162 | If the value is a function, call it with no arguments and switch to | ||
| 163 | the buffer that it returns. | ||
| 164 | If nil, duplicate the contents of the tab that was active | ||
| 165 | before calling the command that adds a new tab." | ||
| 166 | :type '(choice (const :tag "Current buffer" t) | ||
| 167 | (directory :tag "Directory" :value "~/") | ||
| 168 | (file :tag "File" :value "~/.emacs") | ||
| 169 | (string :tag "Buffer" "*scratch*") | ||
| 170 | (function :tag "Function") | ||
| 171 | (const :tag "Duplicate tab" nil)) | ||
| 172 | :group 'tab-bar | ||
| 173 | :version "27.1") | ||
| 174 | |||
| 175 | (defvar tab-bar-new-button | ||
| 176 | (propertize " + " | ||
| 177 | 'display `(image :type xpm | ||
| 178 | :file ,(expand-file-name | ||
| 179 | "images/tabs/new.xpm" | ||
| 180 | data-directory) | ||
| 181 | :margin (2 . 0) | ||
| 182 | :ascent center)) | ||
| 183 | "Button for creating a new tab.") | ||
| 184 | |||
| 185 | (defcustom tab-bar-close-button-show t | ||
| 186 | "Defines where to show the close tab button. | ||
| 187 | If t, show the close tab button on all tabs. | ||
| 188 | If `selected', show it only on the selected tab. | ||
| 189 | If `non-selected', show it only on non-selected tab. | ||
| 190 | If nil, don't show it at all." | ||
| 191 | :type '(choice (const :tag "On all tabs" t) | ||
| 192 | (const :tag "On selected tab" selected) | ||
| 193 | (const :tag "On non-selected tabs" non-selected) | ||
| 194 | (const :tag "None" nil)) | ||
| 195 | :set (lambda (sym val) | ||
| 196 | (set sym val) | ||
| 197 | (force-mode-line-update)) | ||
| 198 | :group 'tab-bar | ||
| 199 | :version "27.1") | ||
| 200 | |||
| 201 | (defvar tab-bar-close-button | ||
| 202 | (propertize " x" | ||
| 203 | 'display `(image :type xpm | ||
| 204 | :file ,(expand-file-name | ||
| 205 | "images/tabs/close.xpm" | ||
| 206 | data-directory) | ||
| 207 | :margin (2 . 0) | ||
| 208 | :ascent center) | ||
| 209 | 'close-tab t | ||
| 210 | :help "Click to close tab") | ||
| 211 | "Button for closing the clicked tab.") | ||
| 212 | |||
| 213 | (defvar tab-bar-separator nil) | ||
| 214 | |||
| 215 | |||
| 216 | (defvar tab-bar-tab-name-function #'tab-bar-tab-name | ||
| 217 | "Function to get a tab name. | ||
| 218 | Function gets no arguments. | ||
| 219 | By default, use function `tab-bar-tab-name'.") | ||
| 220 | |||
| 221 | (defun tab-bar-tab-name () | ||
| 222 | "Generate tab name in the context of the selected frame." | ||
| 223 | (mapconcat #'buffer-name | ||
| 224 | (delete-dups (mapcar #'window-buffer | ||
| 225 | (window-list-1 (frame-first-window) | ||
| 226 | 'nomini))) | ||
| 227 | ", ")) | ||
| 228 | |||
| 229 | (defvar tab-bar-tabs-function #'tab-bar-tabs | ||
| 230 | "Function to get a list of tabs to display in the tab bar. | ||
| 231 | This function should return a list of alists with parameters | ||
| 232 | that include at least the element (name . TAB-NAME). | ||
| 233 | For example, '((tab (name . \"Tab 1\")) (current-tab (name . \"Tab 2\"))) | ||
| 234 | By default, use function `tab-bar-tabs'.") | ||
| 235 | |||
| 236 | (defun tab-bar-tabs () | ||
| 237 | "Return a list of tabs belonging to the selected frame. | ||
| 238 | Ensure the frame parameter `tabs' is pre-populated. | ||
| 239 | Return its existing value or a new value." | ||
| 240 | (let ((tabs (frame-parameter nil 'tabs))) | ||
| 241 | (if tabs | ||
| 242 | ;; Update current tab name | ||
| 243 | (let ((name (assq 'name (assq 'current-tab tabs)))) | ||
| 244 | (when name (setcdr name (funcall tab-bar-tab-name-function)))) | ||
| 245 | ;; Create default tabs | ||
| 246 | (setq tabs `((current-tab (name . ,(funcall tab-bar-tab-name-function))))) | ||
| 247 | (set-frame-parameter nil 'tabs tabs)) | ||
| 248 | tabs)) | ||
| 249 | |||
| 250 | (defun tab-bar-make-keymap-1 () | ||
| 251 | "Generate an actual keymap from `tab-bar-map', without caching." | ||
| 252 | (let ((separator (or tab-bar-separator (if window-system " " "|"))) | ||
| 253 | (i 0)) | ||
| 254 | (append | ||
| 255 | '(keymap (mouse-1 . tab-bar-handle-mouse)) | ||
| 256 | (mapcan | ||
| 257 | (lambda (tab) | ||
| 258 | (setq i (1+ i)) | ||
| 259 | (append | ||
| 260 | `((,(intern (format "sep-%i" i)) menu-item ,separator ignore)) | ||
| 261 | (cond | ||
| 262 | ((eq (car tab) 'current-tab) | ||
| 263 | `((current-tab | ||
| 264 | menu-item | ||
| 265 | ,(propertize (concat (cdr (assq 'name tab)) | ||
| 266 | (or (and tab-bar-close-button-show | ||
| 267 | (not (eq tab-bar-close-button-show | ||
| 268 | 'non-selected)) | ||
| 269 | tab-bar-close-button) "")) | ||
| 270 | 'face 'tab-bar-tab) | ||
| 271 | ignore | ||
| 272 | :help "Current tab"))) | ||
| 273 | (t | ||
| 274 | `((,(intern (format "tab-%i" i)) | ||
| 275 | menu-item | ||
| 276 | ,(propertize (concat (cdr (assq 'name tab)) | ||
| 277 | (or (and tab-bar-close-button-show | ||
| 278 | (not (eq tab-bar-close-button-show | ||
| 279 | 'selected)) | ||
| 280 | tab-bar-close-button) "")) | ||
| 281 | 'face 'tab-bar-tab-inactive) | ||
| 282 | ,(or | ||
| 283 | (cdr (assq 'binding tab)) | ||
| 284 | (lambda () | ||
| 285 | (interactive) | ||
| 286 | (tab-bar-select-tab tab))) | ||
| 287 | :help "Click to visit tab")))) | ||
| 288 | `((,(if (eq (car tab) 'current-tab) 'C-current-tab (intern (format "C-tab-%i" i))) | ||
| 289 | menu-item "" | ||
| 290 | ,(or | ||
| 291 | (cdr (assq 'close-binding tab)) | ||
| 292 | (lambda () | ||
| 293 | (interactive) | ||
| 294 | (tab-bar-close-tab tab))))))) | ||
| 295 | (funcall tab-bar-tabs-function)) | ||
| 296 | (when tab-bar-new-button | ||
| 297 | `((sep-add-tab menu-item ,separator ignore) | ||
| 298 | (add-tab menu-item ,tab-bar-new-button tab-bar-new-tab | ||
| 299 | :help "New tab")))))) | ||
| 300 | |||
| 301 | |||
| 302 | (defun tab-bar-read-tab-name (prompt) | ||
| 303 | (let* ((tabs (tab-bar-tabs)) | ||
| 304 | (tab-name | ||
| 305 | (completing-read prompt | ||
| 306 | (or (delq nil (mapcar (lambda (tab) | ||
| 307 | (cdr (assq 'name tab))) | ||
| 308 | tabs)) | ||
| 309 | '(""))))) | ||
| 310 | (catch 'done | ||
| 311 | (dolist (tab tabs) | ||
| 312 | (when (equal (cdr (assq 'name tab)) tab-name) | ||
| 313 | (throw 'done tab)))))) | ||
| 314 | |||
| 315 | (defun tab-bar-tab-default () | ||
| 316 | (let ((tab `(tab | ||
| 317 | (name . ,(funcall tab-bar-tab-name-function)) | ||
| 318 | (time . ,(time-convert nil 'integer)) | ||
| 319 | (wc . ,(current-window-configuration)) | ||
| 320 | (ws . ,(window-state-get | ||
| 321 | (frame-root-window (selected-frame)) 'writable))))) | ||
| 322 | tab)) | ||
| 323 | |||
| 324 | (defun tab-bar-find-prev-tab (&optional tabs) | ||
| 325 | (unless tabs | ||
| 326 | (setq tabs (tab-bar-tabs))) | ||
| 327 | (unless (eq (car (car tabs)) 'current-tab) | ||
| 328 | (while (and tabs (not (eq (car (car (cdr tabs))) 'current-tab))) | ||
| 329 | (setq tabs (cdr tabs))) | ||
| 330 | tabs)) | ||
| 331 | |||
| 332 | |||
| 333 | (defun tab-bar-select-tab (tab) | ||
| 334 | "Switch to the specified TAB." | ||
| 335 | (interactive (list (tab-bar-read-tab-name "Select tab by name: "))) | ||
| 336 | (when (and tab (not (eq (car tab) 'current-tab))) | ||
| 337 | (let* ((tabs (tab-bar-tabs)) | ||
| 338 | (new-tab (tab-bar-tab-default)) | ||
| 339 | (wc (cdr (assq 'wc tab)))) | ||
| 340 | ;; During the same session, use window-configuration to switch | ||
| 341 | ;; tabs, because window-configurations are more reliable | ||
| 342 | ;; (they keep references to live buffers) than window-states. | ||
| 343 | ;; But after restoring tabs from a previously saved session, | ||
| 344 | ;; its value of window-configuration is unreadable, | ||
| 345 | ;; so restore its saved window-state. | ||
| 346 | (if (window-configuration-p wc) | ||
| 347 | (set-window-configuration wc) | ||
| 348 | (window-state-put (cdr (assq 'ws tab)) | ||
| 349 | (frame-root-window (selected-frame)) 'safe)) | ||
| 350 | (while tabs | ||
| 351 | (cond | ||
| 352 | ((eq (car tabs) tab) | ||
| 353 | (setcar tabs `(current-tab (name . ,(funcall tab-bar-tab-name-function))))) | ||
| 354 | ((eq (car (car tabs)) 'current-tab) | ||
| 355 | (setcar tabs new-tab))) | ||
| 356 | (setq tabs (cdr tabs))) | ||
| 357 | (force-mode-line-update)))) | ||
| 358 | |||
| 359 | (defun tab-bar-switch-to-prev-tab (&optional _arg) | ||
| 360 | "Switch to ARGth previous tab." | ||
| 361 | (interactive "p") | ||
| 362 | (let ((prev-tab (tab-bar-find-prev-tab))) | ||
| 363 | (when prev-tab | ||
| 364 | (tab-bar-select-tab (car prev-tab))))) | ||
| 365 | |||
| 366 | (defun tab-bar-switch-to-next-tab (&optional _arg) | ||
| 367 | "Switch to ARGth next tab." | ||
| 368 | (interactive "p") | ||
| 369 | (let* ((tabs (tab-bar-tabs)) | ||
| 370 | (prev-tab (tab-bar-find-prev-tab tabs))) | ||
| 371 | (if prev-tab | ||
| 372 | (tab-bar-select-tab (car (cdr (cdr prev-tab)))) | ||
| 373 | (tab-bar-select-tab (car (cdr tabs)))))) | ||
| 374 | |||
| 375 | |||
| 376 | (defcustom tab-bar-new-tab-to 'right | ||
| 377 | "Defines where to create a new tab. | ||
| 378 | If `leftmost', create as the first tab. | ||
| 379 | If `left', create to the left from the current tab. | ||
| 380 | If `right', create to the right from the current tab. | ||
| 381 | If `rightmost', create as the last tab." | ||
| 382 | :type '(choice (const :tag "First tab" leftmost) | ||
| 383 | (const :tag "To the left" left) | ||
| 384 | (const :tag "To the right" right) | ||
| 385 | (const :tag "Last tab" rightmost)) | ||
| 386 | :group 'tab-bar | ||
| 387 | :version "27.1") | ||
| 388 | |||
| 389 | (defun tab-bar-new-tab () | ||
| 390 | "Clone the current tab to the position specified by `tab-bar-new-tab-to'." | ||
| 391 | (interactive) | ||
| 392 | (unless tab-bar-mode | ||
| 393 | (tab-bar-mode 1)) | ||
| 394 | (let* ((tabs (tab-bar-tabs)) | ||
| 395 | ;; (i-tab (- (length tabs) (length (memq tab tabs)))) | ||
| 396 | (new-tab (tab-bar-tab-default))) | ||
| 397 | (cond | ||
| 398 | ((eq tab-bar-new-tab-to 'leftmost) | ||
| 399 | (setq tabs (cons new-tab tabs))) | ||
| 400 | ((eq tab-bar-new-tab-to 'rightmost) | ||
| 401 | (setq tabs (append tabs (list new-tab)))) | ||
| 402 | (t | ||
| 403 | (let ((prev-tab (tab-bar-find-prev-tab tabs))) | ||
| 404 | (cond | ||
| 405 | ((eq tab-bar-new-tab-to 'left) | ||
| 406 | (if prev-tab | ||
| 407 | (setcdr prev-tab (cons new-tab (cdr prev-tab))) | ||
| 408 | (setq tabs (cons new-tab tabs)))) | ||
| 409 | ((eq tab-bar-new-tab-to 'right) | ||
| 410 | (if prev-tab | ||
| 411 | (setq prev-tab (cdr prev-tab)) | ||
| 412 | (setq prev-tab tabs)) | ||
| 413 | (setcdr prev-tab (cons new-tab (cdr prev-tab)))))))) | ||
| 414 | (set-frame-parameter nil 'tabs tabs) | ||
| 415 | (tab-bar-select-tab new-tab) | ||
| 416 | (when tab-bar-new-tab-choice | ||
| 417 | (delete-other-windows) | ||
| 418 | (let ((buffer | ||
| 419 | (if (functionp tab-bar-new-tab-choice) | ||
| 420 | (funcall tab-bar-new-tab-choice) | ||
| 421 | (if (stringp tab-bar-new-tab-choice) | ||
| 422 | (or (get-buffer tab-bar-new-tab-choice) | ||
| 423 | (find-file-noselect tab-bar-new-tab-choice)))))) | ||
| 424 | (when (buffer-live-p buffer) | ||
| 425 | (switch-to-buffer buffer)))) | ||
| 426 | (unless tab-bar-mode | ||
| 427 | (message "Added new tab with the current window configuration")))) | ||
| 428 | |||
| 429 | |||
| 430 | (defcustom tab-bar-close-tab-select 'right | ||
| 431 | "Defines what tab to select after closing the specified tab. | ||
| 432 | If `left', select the adjacent left tab. | ||
| 433 | If `right', select the adjacent right tab." | ||
| 434 | :type '(choice (const :tag "Select left tab" left) | ||
| 435 | (const :tag "Select right tab" right)) | ||
| 436 | :group 'tab-bar | ||
| 437 | :version "27.1") | ||
| 438 | |||
| 439 | (defun tab-bar-close-current-tab (&optional tab select-tab) | ||
| 440 | "Close the current TAB. | ||
| 441 | After closing the current tab switch to the tab | ||
| 442 | specified by `tab-bar-close-tab-select', or to `select-tab' | ||
| 443 | if its value is provided." | ||
| 444 | (interactive) | ||
| 445 | (let ((tabs (tab-bar-tabs))) | ||
| 446 | (unless tab | ||
| 447 | (let ((prev-tab (tab-bar-find-prev-tab tabs))) | ||
| 448 | (setq tab (if prev-tab | ||
| 449 | (car (cdr prev-tab)) | ||
| 450 | (car tabs))))) | ||
| 451 | (if select-tab | ||
| 452 | (setq tabs (delq tab tabs)) | ||
| 453 | (let* ((i-tab (- (length tabs) (length (memq tab tabs)))) | ||
| 454 | (i-select | ||
| 455 | (cond | ||
| 456 | ((eq tab-bar-close-tab-select 'left) | ||
| 457 | (1- i-tab)) | ||
| 458 | ((eq tab-bar-close-tab-select 'right) | ||
| 459 | ;; Do nothing: the next tab will take | ||
| 460 | ;; the index of the closed tab | ||
| 461 | i-tab) | ||
| 462 | (t 0)))) | ||
| 463 | (setq tabs (delq tab tabs) | ||
| 464 | i-select (max 0 (min (1- (length tabs)) i-select)) | ||
| 465 | select-tab (nth i-select tabs)))) | ||
| 466 | (set-frame-parameter nil 'tabs tabs) | ||
| 467 | (tab-bar-select-tab select-tab))) | ||
| 468 | |||
| 469 | (defun tab-bar-close-tab (tab) | ||
| 470 | "Close the specified TAB. | ||
| 471 | After closing the current tab switch to the tab | ||
| 472 | specified by `tab-bar-close-tab-select'." | ||
| 473 | (interactive (list (tab-bar-read-tab-name "Close tab by name: "))) | ||
| 474 | (when tab | ||
| 475 | (if (eq (car tab) 'current-tab) | ||
| 476 | (tab-bar-close-current-tab tab) | ||
| 477 | ;; Close non-current tab, no need to switch to another tab | ||
| 478 | (set-frame-parameter nil 'tabs (delq tab (tab-bar-tabs))) | ||
| 479 | (force-mode-line-update)))) | ||
| 480 | |||
| 481 | |||
| 482 | ;;; Non-graphical access to frame-local tabs (named window configurations) | ||
| 483 | |||
| 484 | (defun tab-new () | ||
| 485 | "Create a new named window configuration without having to click a tab." | ||
| 486 | (interactive) | ||
| 487 | (tab-bar-new-tab) | ||
| 488 | (unless tab-bar-mode | ||
| 489 | (message "Added new tab with the current window configuration"))) | ||
| 490 | |||
| 491 | (defun tab-close () | ||
| 492 | "Delete the current window configuration without clicking a close button." | ||
| 493 | (interactive) | ||
| 494 | (tab-bar-close-current-tab) | ||
| 495 | (unless tab-bar-mode | ||
| 496 | (message "Deleted the current tab"))) | ||
| 497 | |||
| 498 | ;; Short aliases | ||
| 499 | ;; (defalias 'tab-switch 'tab-bar-switch-to-next-tab) | ||
| 500 | (defalias 'tab-select 'tab-bar-select-tab) | ||
| 501 | (defalias 'tab-previous 'tab-bar-switch-to-prev-tab) | ||
| 502 | (defalias 'tab-next 'tab-bar-switch-to-next-tab) | ||
| 503 | (defalias 'tab-list 'tab-bar-list) | ||
| 504 | |||
| 505 | (defun tab-bar-list () | ||
| 506 | "Display a list of named window configurations. | ||
| 507 | The list is displayed in the buffer `*Tabs*'. | ||
| 508 | |||
| 509 | In this list of window configurations you can delete or select them. | ||
| 510 | Type ? after invocation to get help on commands available. | ||
| 511 | Type q to remove the list of window configurations from the display. | ||
| 512 | |||
| 513 | The first column shows `D' for for a window configuration you have | ||
| 514 | marked for deletion." | ||
| 515 | (interactive) | ||
| 516 | (let ((dir default-directory) | ||
| 517 | (minibuf (minibuffer-selected-window))) | ||
| 518 | (let ((tab-bar-mode t)) ; don't enable tab-bar-mode if it's disabled | ||
| 519 | (tab-bar-new-tab)) | ||
| 520 | ;; Handle the case when it's called in the active minibuffer. | ||
| 521 | (when minibuf (select-window (minibuffer-selected-window))) | ||
| 522 | (delete-other-windows) | ||
| 523 | ;; Create a new window to replace the existing one, to not break the | ||
| 524 | ;; window parameters (e.g. prev/next buffers) of the window just saved | ||
| 525 | ;; to the window configuration. So when a saved window is restored, | ||
| 526 | ;; its parameters left intact. | ||
| 527 | (split-window) (delete-window) | ||
| 528 | (let ((switch-to-buffer-preserve-window-point nil)) | ||
| 529 | (switch-to-buffer (tab-bar-list-noselect))) | ||
| 530 | (setq default-directory dir)) | ||
| 531 | (message "Commands: d, x; RET; q to quit; ? for help.")) | ||
| 532 | |||
| 533 | (defun tab-bar-list-noselect () | ||
| 534 | "Create and return a buffer with a list of window configurations. | ||
| 535 | The list is displayed in a buffer named `*Tabs*'. | ||
| 536 | |||
| 537 | For more information, see the function `tab-bar-list'." | ||
| 538 | (let* ((tabs (delq nil (mapcar (lambda (tab) ; remove current tab | ||
| 539 | (unless (eq (car tab) 'current-tab) | ||
| 540 | tab)) | ||
| 541 | (tab-bar-tabs)))) | ||
| 542 | ;; Sort by recency | ||
| 543 | (tabs (sort tabs (lambda (a b) (< (cdr (assq 'time b)) | ||
| 544 | (cdr (assq 'time a))))))) | ||
| 545 | (with-current-buffer (get-buffer-create | ||
| 546 | (format " *Tabs*<%s>" (or (frame-parameter nil 'window-id) | ||
| 547 | (frame-parameter nil 'name)))) | ||
| 548 | (erase-buffer) | ||
| 549 | (tab-bar-list-mode) | ||
| 550 | (setq buffer-read-only nil) | ||
| 551 | ;; Vertical alignment to the center of the frame | ||
| 552 | (insert-char ?\n (/ (- (frame-height) (length tabs) 1) 2)) | ||
| 553 | ;; Horizontal alignment to the center of the frame | ||
| 554 | (setq tab-bar-list-column (- (/ (frame-width) 2) 15)) | ||
| 555 | (dolist (tab tabs) | ||
| 556 | (insert (propertize | ||
| 557 | (format "%s %s\n" | ||
| 558 | (make-string tab-bar-list-column ?\040) | ||
| 559 | (propertize | ||
| 560 | (cdr (assq 'name tab)) | ||
| 561 | 'mouse-face 'highlight | ||
| 562 | 'help-echo "mouse-2: select this window configuration")) | ||
| 563 | 'tab tab))) | ||
| 564 | (goto-char (point-min)) | ||
| 565 | (goto-char (or (next-single-property-change (point) 'tab) (point-min))) | ||
| 566 | (when (> (length tabs) 1) | ||
| 567 | (tab-bar-list-next-line)) | ||
| 568 | (move-to-column tab-bar-list-column) | ||
| 569 | (set-buffer-modified-p nil) | ||
| 570 | (current-buffer)))) | ||
| 571 | |||
| 572 | (defvar tab-bar-list-column 3) | ||
| 573 | (make-variable-buffer-local 'tab-bar-list-column) | ||
| 574 | |||
| 575 | (defvar tab-bar-list-mode-map | ||
| 576 | (let ((map (make-keymap))) | ||
| 577 | (suppress-keymap map t) | ||
| 578 | (define-key map "q" 'quit-window) | ||
| 579 | (define-key map "\C-m" 'tab-bar-list-select) | ||
| 580 | (define-key map "d" 'tab-bar-list-delete) | ||
| 581 | (define-key map "k" 'tab-bar-list-delete) | ||
| 582 | (define-key map "\C-d" 'tab-bar-list-delete-backwards) | ||
| 583 | (define-key map "\C-k" 'tab-bar-list-delete) | ||
| 584 | (define-key map "x" 'tab-bar-list-execute) | ||
| 585 | (define-key map " " 'tab-bar-list-next-line) | ||
| 586 | (define-key map "n" 'tab-bar-list-next-line) | ||
| 587 | (define-key map "p" 'tab-bar-list-prev-line) | ||
| 588 | (define-key map "\177" 'tab-bar-list-backup-unmark) | ||
| 589 | (define-key map "?" 'describe-mode) | ||
| 590 | (define-key map "u" 'tab-bar-list-unmark) | ||
| 591 | (define-key map [mouse-2] 'tab-bar-list-mouse-select) | ||
| 592 | (define-key map [follow-link] 'mouse-face) | ||
| 593 | map) | ||
| 594 | "Local keymap for `tab-bar-list-mode' buffers.") | ||
| 595 | |||
| 596 | (define-derived-mode tab-bar-list-mode nil "Window Configurations" | ||
| 597 | "Major mode for selecting a window configuration. | ||
| 598 | Each line describes one window configuration in Emacs. | ||
| 599 | Letters do not insert themselves; instead, they are commands. | ||
| 600 | \\<tab-bar-list-mode-map> | ||
| 601 | \\[tab-bar-list-mouse-select] -- select window configuration you click on. | ||
| 602 | \\[tab-bar-list-select] -- select current line's window configuration. | ||
| 603 | \\[tab-bar-list-delete] -- mark that window configuration to be deleted, and move down. | ||
| 604 | \\[tab-bar-list-delete-backwards] -- mark that window configuration to be deleted, and move up. | ||
| 605 | \\[tab-bar-list-execute] -- delete marked window configurations. | ||
| 606 | \\[tab-bar-list-unmark] -- remove all kinds of marks from current line. | ||
| 607 | With prefix argument, also move up one line. | ||
| 608 | \\[tab-bar-list-backup-unmark] -- back up a line and remove marks." | ||
| 609 | (setq truncate-lines t) | ||
| 610 | (setq buffer-read-only t)) | ||
| 611 | |||
| 612 | (defun tab-bar-list-current-tab (error-if-non-existent-p) | ||
| 613 | "Return window configuration described by this line of the list." | ||
| 614 | (let* ((where (save-excursion | ||
| 615 | (beginning-of-line) | ||
| 616 | (+ 2 (point) tab-bar-list-column))) | ||
| 617 | (tab (and (not (eobp)) (get-text-property where 'tab)))) | ||
| 618 | (or tab | ||
| 619 | (if error-if-non-existent-p | ||
| 620 | (user-error "No window configuration on this line") | ||
| 621 | nil)))) | ||
| 622 | |||
| 623 | |||
| 624 | (defun tab-bar-list-next-line (&optional arg) | ||
| 625 | (interactive) | ||
| 626 | (forward-line arg) | ||
| 627 | (beginning-of-line) | ||
| 628 | (move-to-column tab-bar-list-column)) | ||
| 629 | |||
| 630 | (defun tab-bar-list-prev-line (&optional arg) | ||
| 631 | (interactive) | ||
| 632 | (forward-line (- arg)) | ||
| 633 | (beginning-of-line) | ||
| 634 | (move-to-column tab-bar-list-column)) | ||
| 635 | |||
| 636 | (defun tab-bar-list-unmark (&optional backup) | ||
| 637 | "Cancel all requested operations on window configuration on this line and move down. | ||
| 638 | Optional prefix arg means move up." | ||
| 639 | (interactive "P") | ||
| 640 | (beginning-of-line) | ||
| 641 | (move-to-column tab-bar-list-column) | ||
| 642 | (let* ((buffer-read-only nil)) | ||
| 643 | (delete-char 1) | ||
| 644 | (insert " ")) | ||
| 645 | (forward-line (if backup -1 1)) | ||
| 646 | (move-to-column tab-bar-list-column)) | ||
| 647 | |||
| 648 | (defun tab-bar-list-backup-unmark () | ||
| 649 | "Move up and cancel all requested operations on window configuration on line above." | ||
| 650 | (interactive) | ||
| 651 | (forward-line -1) | ||
| 652 | (tab-bar-list-unmark) | ||
| 653 | (forward-line -1) | ||
| 654 | (move-to-column tab-bar-list-column)) | ||
| 655 | |||
| 656 | (defun tab-bar-list-delete (&optional arg) | ||
| 657 | "Mark window configuration on this line to be deleted by \\<tab-bar-list-mode-map>\\[tab-bar-list-execute] command. | ||
| 658 | Prefix arg is how many window configurations to delete. | ||
| 659 | Negative arg means delete backwards." | ||
| 660 | (interactive "p") | ||
| 661 | (let ((buffer-read-only nil)) | ||
| 662 | (if (or (null arg) (= arg 0)) | ||
| 663 | (setq arg 1)) | ||
| 664 | (while (> arg 0) | ||
| 665 | (delete-char 1) | ||
| 666 | (insert ?D) | ||
| 667 | (forward-line 1) | ||
| 668 | (setq arg (1- arg))) | ||
| 669 | (while (< arg 0) | ||
| 670 | (delete-char 1) | ||
| 671 | (insert ?D) | ||
| 672 | (forward-line -1) | ||
| 673 | (setq arg (1+ arg))) | ||
| 674 | (move-to-column tab-bar-list-column))) | ||
| 675 | |||
| 676 | (defun tab-bar-list-delete-backwards (&optional arg) | ||
| 677 | "Mark window configuration on this line to be deleted by \\<tab-bar-list-mode-map>\\[tab-bar-list-execute] command. | ||
| 678 | Then move up one line. Prefix arg means move that many lines." | ||
| 679 | (interactive "p") | ||
| 680 | (tab-bar-list-delete (- (or arg 1)))) | ||
| 681 | |||
| 682 | (defun tab-bar-list-delete-from-list (tab) | ||
| 683 | "Delete the window configuration from both lists." | ||
| 684 | (set-frame-parameter nil 'tabs (delq tab (tab-bar-tabs)))) | ||
| 685 | |||
| 686 | (defun tab-bar-list-execute () | ||
| 687 | "Delete window configurations marked with \\<tab-bar-list-mode-map>\\[tab-bar-list-delete] commands." | ||
| 688 | (interactive) | ||
| 689 | (save-excursion | ||
| 690 | (goto-char (point-min)) | ||
| 691 | (let ((buffer-read-only nil)) | ||
| 692 | (while (re-search-forward | ||
| 693 | (format "^%sD" (make-string tab-bar-list-column ?\040)) | ||
| 694 | nil t) | ||
| 695 | (forward-char -1) | ||
| 696 | (let ((tab (tab-bar-list-current-tab nil))) | ||
| 697 | (when tab | ||
| 698 | (tab-bar-list-delete-from-list tab) | ||
| 699 | (beginning-of-line) | ||
| 700 | (delete-region (point) (progn (forward-line 1) (point)))))))) | ||
| 701 | (beginning-of-line) | ||
| 702 | (move-to-column tab-bar-list-column) | ||
| 703 | (when tab-bar-mode | ||
| 704 | (force-mode-line-update))) | ||
| 705 | |||
| 706 | (defun tab-bar-list-select () | ||
| 707 | "Select this line's window configuration. | ||
| 708 | This command deletes and replaces all the previously existing windows | ||
| 709 | in the selected frame." | ||
| 710 | (interactive) | ||
| 711 | (let* ((select-tab (tab-bar-list-current-tab t))) | ||
| 712 | (kill-buffer (current-buffer)) | ||
| 713 | ;; Delete the current window configuration | ||
| 714 | (tab-bar-close-current-tab nil select-tab) | ||
| 715 | ;; (tab-bar-select-tab select-tab) | ||
| 716 | )) | ||
| 717 | |||
| 718 | (defun tab-bar-list-mouse-select (event) | ||
| 719 | "Select the window configuration whose line you click on." | ||
| 720 | (interactive "e") | ||
| 721 | (set-buffer (window-buffer (posn-window (event-end event)))) | ||
| 722 | (goto-char (posn-point (event-end event))) | ||
| 723 | (tab-bar-list-select)) | ||
| 724 | |||
| 725 | |||
| 726 | (defvar ctl-x-6-map (make-sparse-keymap) | ||
| 727 | "Keymap for tab commands.") | ||
| 728 | (defalias 'ctl-x-6-prefix ctl-x-6-map) | ||
| 729 | (define-key ctl-x-map "6" 'ctl-x-6-prefix) | ||
| 730 | |||
| 731 | (defun switch-to-buffer-other-tab (buffer-or-name &optional norecord) | ||
| 732 | "Switch to buffer BUFFER-OR-NAME in another tab. | ||
| 733 | Like \\[switch-to-buffer-other-frame] (which see), but creates a new tab." | ||
| 734 | (interactive | ||
| 735 | (list (read-buffer-to-switch "Switch to buffer in other tab: "))) | ||
| 736 | (tab-bar-new-tab) | ||
| 737 | (delete-other-windows) | ||
| 738 | (switch-to-buffer buffer-or-name norecord)) | ||
| 739 | |||
| 740 | (defun find-file-other-tab (filename &optional wildcards) | ||
| 741 | "Edit file FILENAME, in another tab. | ||
| 742 | Like \\[find-file-other-frame] (which see), but creates a new tab." | ||
| 743 | (interactive | ||
| 744 | (find-file-read-args "Find file in other tab: " | ||
| 745 | (confirm-nonexistent-file-or-buffer))) | ||
| 746 | (let ((value (find-file-noselect filename nil nil wildcards))) | ||
| 747 | (if (listp value) | ||
| 748 | (progn | ||
| 749 | (setq value (nreverse value)) | ||
| 750 | (switch-to-buffer-other-tab (car value)) | ||
| 751 | (mapc 'switch-to-buffer (cdr value)) | ||
| 752 | value) | ||
| 753 | (switch-to-buffer-other-tab value)))) | ||
| 754 | |||
| 755 | (define-key ctl-x-6-map "2" 'tab-bar-new-tab) | ||
| 756 | (define-key ctl-x-6-map "0" 'tab-bar-close-current-tab) | ||
| 757 | (define-key ctl-x-6-map "b" 'switch-to-buffer-other-tab) | ||
| 758 | (define-key ctl-x-6-map "f" 'find-file-other-tab) | ||
| 759 | (define-key ctl-x-6-map "\C-f" 'find-file-other-tab) | ||
| 760 | |||
| 761 | |||
| 762 | (provide 'tab-bar) | ||
| 763 | |||
| 764 | ;;; tab-bar.el ends here | ||
diff --git a/lisp/tab-line.el b/lisp/tab-line.el new file mode 100644 index 00000000000..62e06a797d5 --- /dev/null +++ b/lisp/tab-line.el | |||
| @@ -0,0 +1,362 @@ | |||
| 1 | ;;; tab-line.el --- window-local tabs with window buffers -*- lexical-binding: t; -*- | ||
| 2 | |||
| 3 | ;; Copyright (C) 2019 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Juri Linkov <juri@linkov.net> | ||
| 6 | ;; Keywords: windows tabs | ||
| 7 | ;; Maintainer: emacs-devel@gnu.org | ||
| 8 | |||
| 9 | ;; This file is part of GNU Emacs. | ||
| 10 | |||
| 11 | ;; GNU Emacs is free software: you can redistribute it and/or modify | ||
| 12 | ;; it under the terms of the GNU General Public License as published by | ||
| 13 | ;; the Free Software Foundation, either version 3 of the License, or | ||
| 14 | ;; (at your option) any later version. | ||
| 15 | |||
| 16 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 19 | ;; GNU General Public License for more details. | ||
| 20 | |||
| 21 | ;; You should have received a copy of the GNU General Public License | ||
| 22 | ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. | ||
| 23 | |||
| 24 | ;;; Commentary: | ||
| 25 | |||
| 26 | ;; To enable this mode, run `M-x global-tab-line-mode'. | ||
| 27 | |||
| 28 | ;;; Code: | ||
| 29 | |||
| 30 | (require 'seq) ; tab-line.el is not pre-loaded so it's safe to use it here | ||
| 31 | |||
| 32 | |||
| 33 | (defgroup tab-line nil | ||
| 34 | "Window-local tabs." | ||
| 35 | :group 'convenience | ||
| 36 | :version "27.1") | ||
| 37 | |||
| 38 | (defgroup tab-line-faces nil | ||
| 39 | "Faces used in the tab line." | ||
| 40 | :group 'tab-line | ||
| 41 | :group 'faces | ||
| 42 | :version "27.1") | ||
| 43 | |||
| 44 | (defface tab-line | ||
| 45 | '((((type x w32 ns) (class color)) | ||
| 46 | :background "grey85" | ||
| 47 | :foreground "black") | ||
| 48 | (((type x) (class mono)) | ||
| 49 | :background "grey") | ||
| 50 | (t | ||
| 51 | :inverse-video t)) | ||
| 52 | "Tab line face." | ||
| 53 | :version "27.1" | ||
| 54 | :group 'tab-line-faces) | ||
| 55 | |||
| 56 | (defface tab-line-tab | ||
| 57 | '((((class color) (min-colors 88)) | ||
| 58 | :box (:line-width 1 :style released-button) | ||
| 59 | :background "grey85") | ||
| 60 | (t | ||
| 61 | :inverse-video nil)) | ||
| 62 | "Tab line face for selected tab." | ||
| 63 | :version "27.1" | ||
| 64 | :group 'tab-line-faces) | ||
| 65 | |||
| 66 | (defface tab-line-tab-inactive | ||
| 67 | '((default | ||
| 68 | :inherit tab-line-tab) | ||
| 69 | (((class color) (min-colors 88)) | ||
| 70 | :background "grey75") | ||
| 71 | (t | ||
| 72 | :inverse-video t)) | ||
| 73 | "Tab line face for non-selected tab." | ||
| 74 | :version "27.1" | ||
| 75 | :group 'tab-line-faces) | ||
| 76 | |||
| 77 | (defface tab-line-highlight | ||
| 78 | '((default :inherit tab-line-tab)) | ||
| 79 | "Tab line face for highlighting." | ||
| 80 | :version "27.1" | ||
| 81 | :group 'tab-line-faces) | ||
| 82 | |||
| 83 | (defface tab-line-close-highlight | ||
| 84 | '((t :foreground "red")) | ||
| 85 | "Tab line face for highlighting of the close button." | ||
| 86 | :version "27.1" | ||
| 87 | :group 'tab-line-faces) | ||
| 88 | |||
| 89 | |||
| 90 | (defvar tab-line-tab-map | ||
| 91 | (let ((map (make-sparse-keymap))) | ||
| 92 | (define-key map [tab-line mouse-1] 'tab-line-select-tab) | ||
| 93 | (define-key map [tab-line mouse-2] 'tab-line-close-tab) | ||
| 94 | (define-key map [tab-line mouse-4] 'tab-line-switch-to-prev-tab) | ||
| 95 | (define-key map [tab-line mouse-5] 'tab-line-switch-to-next-tab) | ||
| 96 | (define-key map "\C-m" 'tab-line-select-tab) | ||
| 97 | map) | ||
| 98 | "Local keymap for `tab-line-mode' window tabs.") | ||
| 99 | |||
| 100 | (defvar tab-line-add-map | ||
| 101 | (let ((map (make-sparse-keymap))) | ||
| 102 | (define-key map [tab-line mouse-1] 'tab-line-new-tab) | ||
| 103 | (define-key map [tab-line mouse-2] 'tab-line-new-tab) | ||
| 104 | (define-key map "\C-m" 'tab-line-new-tab) | ||
| 105 | map) | ||
| 106 | "Local keymap to add `tab-line-mode' window tabs.") | ||
| 107 | |||
| 108 | (defvar tab-line-tab-close-map | ||
| 109 | (let ((map (make-sparse-keymap))) | ||
| 110 | (define-key map [tab-line mouse-1] 'tab-line-close-tab) | ||
| 111 | (define-key map [tab-line mouse-2] 'tab-line-close-tab) | ||
| 112 | map) | ||
| 113 | "Local keymap to close `tab-line-mode' window tabs.") | ||
| 114 | |||
| 115 | |||
| 116 | (defcustom tab-line-new-tab-choice t | ||
| 117 | "Defines what to show in a new tab. | ||
| 118 | If t, display a selection menu with all available buffers. | ||
| 119 | If the value is a function, call it with no arguments. | ||
| 120 | If nil, don't show the new tab button." | ||
| 121 | :type '(choice (const :tag "Buffer menu" t) | ||
| 122 | (function :tag "Function") | ||
| 123 | (const :tag "No button" nil)) | ||
| 124 | :group 'tab-line | ||
| 125 | :version "27.1") | ||
| 126 | |||
| 127 | (defvar tab-line-new-button | ||
| 128 | (propertize " + " | ||
| 129 | 'display `(image :type xpm | ||
| 130 | :file ,(expand-file-name | ||
| 131 | "images/tabs/new.xpm" | ||
| 132 | data-directory) | ||
| 133 | :margin (2 . 0) | ||
| 134 | :ascent center) | ||
| 135 | 'keymap tab-line-add-map | ||
| 136 | 'mouse-face 'tab-line-highlight | ||
| 137 | 'help-echo "Click to add tab") | ||
| 138 | "Button for creating a new tab.") | ||
| 139 | |||
| 140 | (defcustom tab-line-close-button-show t | ||
| 141 | "Defines where to show the close tab button. | ||
| 142 | If t, show the close tab button on all tabs. | ||
| 143 | If `selected', show it only on the selected tab. | ||
| 144 | If `non-selected', show it only on non-selected tab. | ||
| 145 | If nil, don't show it at all." | ||
| 146 | :type '(choice (const :tag "On all tabs" t) | ||
| 147 | (const :tag "On selected tab" selected) | ||
| 148 | (const :tag "On non-selected tabs" non-selected) | ||
| 149 | (const :tag "None" nil)) | ||
| 150 | :set (lambda (sym val) | ||
| 151 | (set sym val) | ||
| 152 | (force-mode-line-update)) | ||
| 153 | :group 'tab-line | ||
| 154 | :version "27.1") | ||
| 155 | |||
| 156 | (defvar tab-line-close-button | ||
| 157 | (propertize " x" | ||
| 158 | 'display `(image :type xpm | ||
| 159 | :file ,(expand-file-name | ||
| 160 | "images/tabs/close.xpm" | ||
| 161 | data-directory) | ||
| 162 | :margin (2 . 0) | ||
| 163 | :ascent center) | ||
| 164 | 'keymap tab-line-tab-close-map | ||
| 165 | 'mouse-face 'tab-line-close-highlight | ||
| 166 | 'help-echo "Click to close tab") | ||
| 167 | "Button for closing the clicked tab.") | ||
| 168 | |||
| 169 | (defvar tab-line-separator nil) | ||
| 170 | |||
| 171 | (defvar tab-line-tab-name-ellipsis | ||
| 172 | (if (char-displayable-p ?…) "…" "...")) | ||
| 173 | |||
| 174 | |||
| 175 | (defvar tab-line-tab-name-function #'tab-line-tab-name | ||
| 176 | "Function to get a tab name. | ||
| 177 | Function gets two arguments: tab to get name for and a list of tabs | ||
| 178 | to display. By default, use function `tab-line-tab-name'.") | ||
| 179 | |||
| 180 | (defun tab-line-tab-name (buffer &optional buffers) | ||
| 181 | "Generate tab name from BUFFER. | ||
| 182 | Reduce tab width proportionally to space taken by other tabs. | ||
| 183 | This function can be overridden by changing the default value of the | ||
| 184 | variable `tab-line-tab-name-function'." | ||
| 185 | (let ((tab-name (buffer-name buffer)) | ||
| 186 | (limit (when buffers | ||
| 187 | (max 1 (- (/ (window-width) (length buffers)) 3))))) | ||
| 188 | (if (or (not limit) (< (length tab-name) limit)) | ||
| 189 | tab-name | ||
| 190 | (propertize (truncate-string-to-width tab-name limit nil nil | ||
| 191 | tab-line-tab-name-ellipsis) | ||
| 192 | 'help-echo tab-name)))) | ||
| 193 | |||
| 194 | (defvar tab-line-tabs-limit 15 | ||
| 195 | "Maximum number of buffer tabs displayed in the tab line.") | ||
| 196 | |||
| 197 | (defvar tab-line-tabs-function #'tab-line-tabs | ||
| 198 | "Function to get a list of tabs to display in the tab line. | ||
| 199 | This function should return either a list of buffers whose names will | ||
| 200 | be displayed, or just a list of strings to display in the tab line. | ||
| 201 | By default, use function `tab-line-tabs'.") | ||
| 202 | |||
| 203 | (defun tab-line-tabs () | ||
| 204 | "Return a list of tabs that should be displayed in the tab line. | ||
| 205 | By default returns a list of window buffers, i.e. buffers previously | ||
| 206 | shown in the same window where the tab line is displayed. | ||
| 207 | This list can be overridden by changing the default value of the | ||
| 208 | variable `tab-line-tabs-function'." | ||
| 209 | (let* ((window (selected-window)) | ||
| 210 | (buffer (window-buffer window)) | ||
| 211 | (next-buffers (seq-remove (lambda (b) (eq b buffer)) | ||
| 212 | (window-next-buffers window))) | ||
| 213 | (next-buffers (seq-filter #'buffer-live-p next-buffers)) | ||
| 214 | (prev-buffers (seq-remove (lambda (b) (eq b buffer)) | ||
| 215 | (mapcar #'car (window-prev-buffers window)))) | ||
| 216 | (prev-buffers (seq-filter #'buffer-live-p prev-buffers)) | ||
| 217 | ;; Remove next-buffers from prev-buffers | ||
| 218 | (prev-buffers (seq-difference prev-buffers next-buffers)) | ||
| 219 | (half-limit (/ tab-line-tabs-limit 2)) | ||
| 220 | (prev-buffers-limit | ||
| 221 | (if (> (length prev-buffers) half-limit) | ||
| 222 | (if (> (length next-buffers) half-limit) | ||
| 223 | half-limit | ||
| 224 | (+ half-limit (- half-limit (length next-buffers)))) | ||
| 225 | (length prev-buffers))) | ||
| 226 | (next-buffers-limit | ||
| 227 | (- tab-line-tabs-limit prev-buffers-limit)) | ||
| 228 | (buffer-tabs | ||
| 229 | (append (reverse (seq-take prev-buffers prev-buffers-limit)) | ||
| 230 | (list buffer) | ||
| 231 | (seq-take next-buffers next-buffers-limit)))) | ||
| 232 | buffer-tabs)) | ||
| 233 | |||
| 234 | (defun tab-line-format () | ||
| 235 | "Template for displaying tab line for selected window." | ||
| 236 | (let* ((window (selected-window)) | ||
| 237 | (selected-buffer (window-buffer window)) | ||
| 238 | (tabs (funcall tab-line-tabs-function)) | ||
| 239 | (separator (or tab-line-separator (if window-system " " "|")))) | ||
| 240 | (append | ||
| 241 | (mapcar | ||
| 242 | (lambda (tab) | ||
| 243 | (concat | ||
| 244 | separator | ||
| 245 | (apply 'propertize (concat (propertize | ||
| 246 | (funcall tab-line-tab-name-function tab tabs) | ||
| 247 | 'keymap tab-line-tab-map) | ||
| 248 | (or (and tab-line-close-button-show | ||
| 249 | (not (eq tab-line-close-button-show | ||
| 250 | (if (eq tab selected-buffer) | ||
| 251 | 'non-selected | ||
| 252 | 'selected))) | ||
| 253 | tab-line-close-button) "")) | ||
| 254 | `( | ||
| 255 | tab ,tab | ||
| 256 | face ,(if (eq tab selected-buffer) | ||
| 257 | 'tab-line-tab | ||
| 258 | 'tab-line-tab-inactive) | ||
| 259 | mouse-face tab-line-highlight)))) | ||
| 260 | tabs) | ||
| 261 | (list (concat separator (when tab-line-new-tab-choice | ||
| 262 | tab-line-new-button)))))) | ||
| 263 | |||
| 264 | |||
| 265 | (defun tab-line-new-tab (&optional e) | ||
| 266 | "Add a new tab to the tab line. | ||
| 267 | Usually is invoked by clicking on the plus-shaped button. | ||
| 268 | But any switching to other buffer also adds a new tab | ||
| 269 | corresponding to the switched buffer." | ||
| 270 | (interactive "e") | ||
| 271 | (if (functionp tab-line-new-tab-choice) | ||
| 272 | (funcall tab-line-new-tab-choice) | ||
| 273 | (if window-system ; (display-popup-menus-p) | ||
| 274 | (mouse-buffer-menu e) ; like (buffer-menu-open) | ||
| 275 | ;; tty menu doesn't support mouse clicks, so use tmm | ||
| 276 | (tmm-prompt (mouse-buffer-menu-keymap))))) | ||
| 277 | |||
| 278 | (defun tab-line-select-tab (&optional e) | ||
| 279 | "Switch to the selected tab. | ||
| 280 | This command maintains the original order of prev/next buffers. | ||
| 281 | So for example, switching to a previous tab is equivalent to | ||
| 282 | using the `previous-buffer' command." | ||
| 283 | (interactive "e") | ||
| 284 | (let* ((posnp (event-start e)) | ||
| 285 | (window (posn-window posnp)) | ||
| 286 | (buffer (get-pos-property 1 'tab (car (posn-string posnp)))) | ||
| 287 | (window-buffer (window-buffer window)) | ||
| 288 | (next-buffers (seq-remove (lambda (b) (eq b window-buffer)) | ||
| 289 | (window-next-buffers window))) | ||
| 290 | (prev-buffers (seq-remove (lambda (b) (eq b window-buffer)) | ||
| 291 | (mapcar #'car (window-prev-buffers window)))) | ||
| 292 | ;; Remove next-buffers from prev-buffers | ||
| 293 | (prev-buffers (seq-difference prev-buffers next-buffers))) | ||
| 294 | (cond | ||
| 295 | ((memq buffer next-buffers) | ||
| 296 | (dotimes (_ (1+ (seq-position next-buffers buffer))) | ||
| 297 | (switch-to-next-buffer window))) | ||
| 298 | ((memq buffer prev-buffers) | ||
| 299 | (dotimes (_ (1+ (seq-position prev-buffers buffer))) | ||
| 300 | (switch-to-prev-buffer window))) | ||
| 301 | (t | ||
| 302 | (with-selected-window window | ||
| 303 | (switch-to-buffer buffer)))))) | ||
| 304 | |||
| 305 | (defun tab-line-switch-to-prev-tab (&optional e) | ||
| 306 | "Switch to the previous tab. | ||
| 307 | Its effect is the same as using the `previous-buffer' command | ||
| 308 | (\\[previous-buffer])." | ||
| 309 | (interactive "e") | ||
| 310 | (switch-to-prev-buffer (posn-window (event-start e)))) | ||
| 311 | |||
| 312 | (defun tab-line-switch-to-next-tab (&optional e) | ||
| 313 | "Switch to the next tab. | ||
| 314 | Its effect is the same as using the `next-buffer' command | ||
| 315 | (\\[next-buffer])." | ||
| 316 | (interactive "e") | ||
| 317 | (switch-to-next-buffer (posn-window (event-start e)))) | ||
| 318 | |||
| 319 | (defcustom tab-line-close-tab-action 'bury-buffer | ||
| 320 | "Defines what to do on closing the tab. | ||
| 321 | If `bury-buffer', put the tab's buffer at the end of the list of all | ||
| 322 | buffers that effectively hides the buffer's tab from the tab line. | ||
| 323 | If `kill-buffer', kills the tab's buffer." | ||
| 324 | :type '(choice (const :tag "Bury buffer" bury-buffer) | ||
| 325 | (const :tag "Kill buffer" kill-buffer)) | ||
| 326 | :group 'tab-line | ||
| 327 | :version "27.1") | ||
| 328 | |||
| 329 | (defun tab-line-close-tab (&optional e) | ||
| 330 | "Close the selected tab. | ||
| 331 | Usually is invoked by clicking on the close button on the right side | ||
| 332 | of the tab. This command buries the buffer, so it goes out of sight | ||
| 333 | from the tab line." | ||
| 334 | (interactive "e") | ||
| 335 | (let* ((posnp (event-start e)) | ||
| 336 | (window (posn-window posnp)) | ||
| 337 | (buffer (get-pos-property 1 'tab (car (posn-string posnp))))) | ||
| 338 | (with-selected-window window | ||
| 339 | (cond | ||
| 340 | ((eq tab-line-close-tab-action 'kill-buffer) | ||
| 341 | (kill-buffer buffer)) | ||
| 342 | ((eq tab-line-close-tab-action 'bury-buffer) | ||
| 343 | (if (eq buffer (current-buffer)) | ||
| 344 | (bury-buffer) | ||
| 345 | (set-window-prev-buffers nil (assq-delete-all buffer (window-prev-buffers))) | ||
| 346 | (set-window-next-buffers nil (delq buffer (window-next-buffers)))))) | ||
| 347 | (force-mode-line-update)))) | ||
| 348 | |||
| 349 | |||
| 350 | ;;;###autoload | ||
| 351 | (define-minor-mode global-tab-line-mode | ||
| 352 | "Display window-local tab line." | ||
| 353 | :group 'tab-line | ||
| 354 | :type 'boolean | ||
| 355 | :global t | ||
| 356 | :init-value nil | ||
| 357 | (setq-default tab-line-format (when global-tab-line-mode | ||
| 358 | '(:eval (tab-line-format))))) | ||
| 359 | |||
| 360 | |||
| 361 | (provide 'tab-line) | ||
| 362 | ;;; tab-line.el ends here | ||
diff --git a/lisp/window.el b/lisp/window.el index 620eacdd290..d93ec0add67 100644 --- a/lisp/window.el +++ b/lisp/window.el | |||
| @@ -1419,7 +1419,10 @@ dumping to it." | |||
| 1419 | (format "frame text pixel: %s x %s cols/lines: %s x %s\n" | 1419 | (format "frame text pixel: %s x %s cols/lines: %s x %s\n" |
| 1420 | (frame-text-width frame) (frame-text-height frame) | 1420 | (frame-text-width frame) (frame-text-height frame) |
| 1421 | (frame-text-cols frame) (frame-text-lines frame)) | 1421 | (frame-text-cols frame) (frame-text-lines frame)) |
| 1422 | (format "tool: %s scroll: %s/%s fringe: %s border: %s right: %s bottom: %s\n\n" | 1422 | (format "tab: %s tool: %s scroll: %s/%s fringe: %s border: %s right: %s bottom: %s\n\n" |
| 1423 | (if (fboundp 'tab-bar-height) | ||
| 1424 | (tab-bar-height frame t) | ||
| 1425 | "0") | ||
| 1423 | (if (fboundp 'tool-bar-height) | 1426 | (if (fboundp 'tool-bar-height) |
| 1424 | (tool-bar-height frame t) | 1427 | (tool-bar-height frame t) |
| 1425 | "0") | 1428 | "0") |
diff --git a/lisp/xt-mouse.el b/lisp/xt-mouse.el index 9e8a32a28ff..308f602b6d0 100644 --- a/lisp/xt-mouse.el +++ b/lisp/xt-mouse.el | |||
| @@ -253,7 +253,13 @@ which is the \"1006\" extension implemented in Xterm >= 277." | |||
| 253 | (top (nth 1 ltrb)) | 253 | (top (nth 1 ltrb)) |
| 254 | (posn (if w | 254 | (posn (if w |
| 255 | (posn-at-x-y (- x left) (- y top) w t) | 255 | (posn-at-x-y (- x left) (- y top) w t) |
| 256 | (append (list nil 'menu-bar) | 256 | (append (list nil (if (and tab-bar-mode |
| 257 | (or (not menu-bar-mode) | ||
| 258 | ;; The tab-bar is on the | ||
| 259 | ;; second row below menu-bar | ||
| 260 | (eq y 1))) | ||
| 261 | 'tab-bar | ||
| 262 | 'menu-bar)) | ||
| 257 | (nthcdr 2 (posn-at-x-y x y))))) | 263 | (nthcdr 2 (posn-at-x-y x y))))) |
| 258 | (event (list type posn))) | 264 | (event (list type posn))) |
| 259 | (setcar (nthcdr 3 posn) timestamp) | 265 | (setcar (nthcdr 3 posn) timestamp) |
diff --git a/src/buffer.c b/src/buffer.c index 77e8b6bb779..8cb28d8aa70 100644 --- a/src/buffer.c +++ b/src/buffer.c | |||
| @@ -249,6 +249,11 @@ bset_header_line_format (struct buffer *b, Lisp_Object val) | |||
| 249 | b->header_line_format_ = val; | 249 | b->header_line_format_ = val; |
| 250 | } | 250 | } |
| 251 | static void | 251 | static void |
| 252 | bset_tab_line_format (struct buffer *b, Lisp_Object val) | ||
| 253 | { | ||
| 254 | b->tab_line_format_ = val; | ||
| 255 | } | ||
| 256 | static void | ||
| 252 | bset_indicate_buffer_boundaries (struct buffer *b, Lisp_Object val) | 257 | bset_indicate_buffer_boundaries (struct buffer *b, Lisp_Object val) |
| 253 | { | 258 | { |
| 254 | b->indicate_buffer_boundaries_ = val; | 259 | b->indicate_buffer_boundaries_ = val; |
| @@ -1329,7 +1334,7 @@ No argument or nil as argument means use current buffer as BUFFER. */) | |||
| 1329 | DEFUN ("force-mode-line-update", Fforce_mode_line_update, | 1334 | DEFUN ("force-mode-line-update", Fforce_mode_line_update, |
| 1330 | Sforce_mode_line_update, 0, 1, 0, | 1335 | Sforce_mode_line_update, 0, 1, 0, |
| 1331 | doc: /* Force redisplay of the current buffer's mode line and header line. | 1336 | doc: /* Force redisplay of the current buffer's mode line and header line. |
| 1332 | With optional non-nil ALL, force redisplay of all mode lines and | 1337 | With optional non-nil ALL, force redisplay of all mode lines, tab lines and |
| 1333 | header lines. This function also forces recomputation of the | 1338 | header lines. This function also forces recomputation of the |
| 1334 | menu bar menus and the frame title. */) | 1339 | menu bar menus and the frame title. */) |
| 1335 | (Lisp_Object all) | 1340 | (Lisp_Object all) |
| @@ -5194,6 +5199,7 @@ init_buffer_once (void) | |||
| 5194 | XSETFASTINT (BVAR (&buffer_local_flags, scroll_up_aggressively), idx); ++idx; | 5199 | XSETFASTINT (BVAR (&buffer_local_flags, scroll_up_aggressively), idx); ++idx; |
| 5195 | XSETFASTINT (BVAR (&buffer_local_flags, scroll_down_aggressively), idx); ++idx; | 5200 | XSETFASTINT (BVAR (&buffer_local_flags, scroll_down_aggressively), idx); ++idx; |
| 5196 | XSETFASTINT (BVAR (&buffer_local_flags, header_line_format), idx); ++idx; | 5201 | XSETFASTINT (BVAR (&buffer_local_flags, header_line_format), idx); ++idx; |
| 5202 | XSETFASTINT (BVAR (&buffer_local_flags, tab_line_format), idx); ++idx; | ||
| 5197 | XSETFASTINT (BVAR (&buffer_local_flags, cursor_type), idx); ++idx; | 5203 | XSETFASTINT (BVAR (&buffer_local_flags, cursor_type), idx); ++idx; |
| 5198 | XSETFASTINT (BVAR (&buffer_local_flags, extra_line_spacing), idx); ++idx; | 5204 | XSETFASTINT (BVAR (&buffer_local_flags, extra_line_spacing), idx); ++idx; |
| 5199 | XSETFASTINT (BVAR (&buffer_local_flags, cursor_in_non_selected_windows), idx); ++idx; | 5205 | XSETFASTINT (BVAR (&buffer_local_flags, cursor_in_non_selected_windows), idx); ++idx; |
| @@ -5239,6 +5245,7 @@ init_buffer_once (void) | |||
| 5239 | /* real setup is done in bindings.el */ | 5245 | /* real setup is done in bindings.el */ |
| 5240 | bset_mode_line_format (&buffer_defaults, build_pure_c_string ("%-")); | 5246 | bset_mode_line_format (&buffer_defaults, build_pure_c_string ("%-")); |
| 5241 | bset_header_line_format (&buffer_defaults, Qnil); | 5247 | bset_header_line_format (&buffer_defaults, Qnil); |
| 5248 | bset_tab_line_format (&buffer_defaults, Qnil); | ||
| 5242 | bset_abbrev_mode (&buffer_defaults, Qnil); | 5249 | bset_abbrev_mode (&buffer_defaults, Qnil); |
| 5243 | bset_overwrite_mode (&buffer_defaults, Qnil); | 5250 | bset_overwrite_mode (&buffer_defaults, Qnil); |
| 5244 | bset_case_fold_search (&buffer_defaults, Qt); | 5251 | bset_case_fold_search (&buffer_defaults, Qt); |
| @@ -5510,6 +5517,13 @@ syms_of_buffer (void) | |||
| 5510 | Fput (Qprotected_field, Qerror_message, | 5517 | Fput (Qprotected_field, Qerror_message, |
| 5511 | build_pure_c_string ("Attempt to modify a protected field")); | 5518 | build_pure_c_string ("Attempt to modify a protected field")); |
| 5512 | 5519 | ||
| 5520 | DEFVAR_PER_BUFFER ("tab-line-format", | ||
| 5521 | &BVAR (current_buffer, tab_line_format), | ||
| 5522 | Qnil, | ||
| 5523 | doc: /* Analogous to `mode-line-format', but controls the tab line. | ||
| 5524 | The tab line appears, optionally, at the top of a window; | ||
| 5525 | the mode line appears at the bottom. */); | ||
| 5526 | |||
| 5513 | DEFVAR_PER_BUFFER ("header-line-format", | 5527 | DEFVAR_PER_BUFFER ("header-line-format", |
| 5514 | &BVAR (current_buffer, header_line_format), | 5528 | &BVAR (current_buffer, header_line_format), |
| 5515 | Qnil, | 5529 | Qnil, |
diff --git a/src/buffer.h b/src/buffer.h index 280d4e9098e..37a50d276f1 100644 --- a/src/buffer.h +++ b/src/buffer.h | |||
| @@ -348,6 +348,10 @@ struct buffer | |||
| 348 | of windows. Nil means don't display that line. */ | 348 | of windows. Nil means don't display that line. */ |
| 349 | Lisp_Object header_line_format_; | 349 | Lisp_Object header_line_format_; |
| 350 | 350 | ||
| 351 | /* Analogous to mode_line_format for the line displayed at the top | ||
| 352 | of windows. Nil means don't display that line. */ | ||
| 353 | Lisp_Object tab_line_format_; | ||
| 354 | |||
| 351 | /* Keys that are bound local to this buffer. */ | 355 | /* Keys that are bound local to this buffer. */ |
| 352 | Lisp_Object keymap_; | 356 | Lisp_Object keymap_; |
| 353 | 357 | ||
diff --git a/src/dispextern.h b/src/dispextern.h index 05f199ff353..817f8c77d97 100644 --- a/src/dispextern.h +++ b/src/dispextern.h | |||
| @@ -166,6 +166,7 @@ enum window_part | |||
| 166 | ON_MODE_LINE, | 166 | ON_MODE_LINE, |
| 167 | ON_VERTICAL_BORDER, | 167 | ON_VERTICAL_BORDER, |
| 168 | ON_HEADER_LINE, | 168 | ON_HEADER_LINE, |
| 169 | ON_TAB_LINE, | ||
| 169 | ON_LEFT_FRINGE, | 170 | ON_LEFT_FRINGE, |
| 170 | ON_RIGHT_FRINGE, | 171 | ON_RIGHT_FRINGE, |
| 171 | ON_LEFT_MARGIN, | 172 | ON_LEFT_MARGIN, |
| @@ -762,6 +763,9 @@ struct glyph_matrix | |||
| 762 | which do their own scrolling. */ | 763 | which do their own scrolling. */ |
| 763 | bool_bf no_scrolling_p : 1; | 764 | bool_bf no_scrolling_p : 1; |
| 764 | 765 | ||
| 766 | /* True means window displayed in this matrix has a tab line. */ | ||
| 767 | bool_bf tab_line_p : 1; | ||
| 768 | |||
| 765 | /* True means window displayed in this matrix has a header | 769 | /* True means window displayed in this matrix has a header |
| 766 | line. */ | 770 | line. */ |
| 767 | bool_bf header_line_p : 1; | 771 | bool_bf header_line_p : 1; |
| @@ -1001,9 +1005,12 @@ struct glyph_row | |||
| 1001 | implies that the row doesn't have marginal areas. */ | 1005 | implies that the row doesn't have marginal areas. */ |
| 1002 | bool_bf full_width_p : 1; | 1006 | bool_bf full_width_p : 1; |
| 1003 | 1007 | ||
| 1004 | /* True means row is a mode or header-line. */ | 1008 | /* True means row is a mode or header/tab-line. */ |
| 1005 | bool_bf mode_line_p : 1; | 1009 | bool_bf mode_line_p : 1; |
| 1006 | 1010 | ||
| 1011 | /* True means row is a tab-line. */ | ||
| 1012 | bool_bf tab_line_p : 1; | ||
| 1013 | |||
| 1007 | /* True in a current row means this row is overlapped by another row. */ | 1014 | /* True in a current row means this row is overlapped by another row. */ |
| 1008 | bool_bf overlapped_p : 1; | 1015 | bool_bf overlapped_p : 1; |
| 1009 | 1016 | ||
| @@ -1084,16 +1091,25 @@ struct glyph_row *matrix_row (struct glyph_matrix *, int); | |||
| 1084 | #define MATRIX_MODE_LINE_ROW(MATRIX) \ | 1091 | #define MATRIX_MODE_LINE_ROW(MATRIX) \ |
| 1085 | ((MATRIX)->rows + (MATRIX)->nrows - 1) | 1092 | ((MATRIX)->rows + (MATRIX)->nrows - 1) |
| 1086 | 1093 | ||
| 1087 | /* Return a pointer to the row reserved for the header line in MATRIX. | 1094 | /* Return a pointer to the row reserved for the tab line in MATRIX. |
| 1088 | This is always the first row in MATRIX because that's the only | 1095 | This is always the first row in MATRIX because that's the only |
| 1089 | way that works in frame-based redisplay. */ | 1096 | way that works in frame-based redisplay. */ |
| 1090 | 1097 | ||
| 1091 | #define MATRIX_HEADER_LINE_ROW(MATRIX) (MATRIX)->rows | 1098 | #define MATRIX_TAB_LINE_ROW(MATRIX) (MATRIX)->rows |
| 1099 | |||
| 1100 | /* Return a pointer to the row reserved for the header line in MATRIX. | ||
| 1101 | This is always the second row in MATRIX because that's the only | ||
| 1102 | way that works in frame-based redisplay. */ | ||
| 1103 | |||
| 1104 | #define MATRIX_HEADER_LINE_ROW(MATRIX) \ | ||
| 1105 | ((MATRIX)->tab_line_p ? ((MATRIX)->rows + 1) : (MATRIX)->rows) | ||
| 1092 | 1106 | ||
| 1093 | /* Return a pointer to first row in MATRIX used for text display. */ | 1107 | /* Return a pointer to first row in MATRIX used for text display. */ |
| 1094 | 1108 | ||
| 1095 | #define MATRIX_FIRST_TEXT_ROW(MATRIX) \ | 1109 | #define MATRIX_FIRST_TEXT_ROW(MATRIX) \ |
| 1096 | ((MATRIX)->rows->mode_line_p ? (MATRIX)->rows + 1 : (MATRIX)->rows) | 1110 | ((MATRIX)->rows->mode_line_p ? \ |
| 1111 | (((MATRIX)->rows + 1)->mode_line_p ? \ | ||
| 1112 | (MATRIX)->rows + 2 : (MATRIX)->rows + 1) : (MATRIX)->rows) | ||
| 1097 | 1113 | ||
| 1098 | /* Return a pointer to the first glyph in the text area of a row. | 1114 | /* Return a pointer to the first glyph in the text area of a row. |
| 1099 | MATRIX is the glyph matrix accessed, and ROW is the row index in | 1115 | 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); | |||
| 1162 | ((ROW)->height != (ROW)->visible_height) | 1178 | ((ROW)->height != (ROW)->visible_height) |
| 1163 | 1179 | ||
| 1164 | #define MR_PARTIALLY_VISIBLE_AT_TOP(W, ROW) \ | 1180 | #define MR_PARTIALLY_VISIBLE_AT_TOP(W, ROW) \ |
| 1165 | ((ROW)->y < WINDOW_HEADER_LINE_HEIGHT ((W))) | 1181 | ((ROW)->y < (WINDOW_TAB_LINE_HEIGHT ((W)) + WINDOW_HEADER_LINE_HEIGHT ((W)))) |
| 1166 | 1182 | ||
| 1167 | #define MR_PARTIALLY_VISIBLE_AT_BOTTOM(W, ROW) \ | 1183 | #define MR_PARTIALLY_VISIBLE_AT_BOTTOM(W, ROW) \ |
| 1168 | (((ROW)->y + (ROW)->height - (ROW)->extra_line_spacing) \ | 1184 | (((ROW)->y + (ROW)->height - (ROW)->extra_line_spacing) \ |
| @@ -1433,6 +1449,15 @@ struct glyph_string | |||
| 1433 | ? MATRIX_HEADER_LINE_ROW (MATRIX)->height \ | 1449 | ? MATRIX_HEADER_LINE_ROW (MATRIX)->height \ |
| 1434 | : 0) | 1450 | : 0) |
| 1435 | 1451 | ||
| 1452 | /* Return the height of the tab line in glyph matrix MATRIX, or zero | ||
| 1453 | if not known. This macro is called under circumstances where | ||
| 1454 | MATRIX might not have been allocated yet. */ | ||
| 1455 | |||
| 1456 | #define MATRIX_TAB_LINE_HEIGHT(MATRIX) \ | ||
| 1457 | ((MATRIX) && (MATRIX)->rows \ | ||
| 1458 | ? MATRIX_TAB_LINE_ROW (MATRIX)->height \ | ||
| 1459 | : 0) | ||
| 1460 | |||
| 1436 | /* Return the desired face id for the mode line of a window, depending | 1461 | /* Return the desired face id for the mode line of a window, depending |
| 1437 | on whether the window is selected or not, or if the window is the | 1462 | on whether the window is selected or not, or if the window is the |
| 1438 | scrolling window for the currently active minibuffer window. | 1463 | scrolling window for the currently active minibuffer window. |
| @@ -1485,6 +1510,19 @@ struct glyph_string | |||
| 1485 | : estimate_mode_line_height \ | 1510 | : estimate_mode_line_height \ |
| 1486 | (XFRAME (W->frame), HEADER_LINE_FACE_ID)))) | 1511 | (XFRAME (W->frame), HEADER_LINE_FACE_ID)))) |
| 1487 | 1512 | ||
| 1513 | /* Return the current height of the tab line of window W. If not known | ||
| 1514 | from W->tab_line_height, look at W's current glyph matrix, or return | ||
| 1515 | an estimation based on the height of the font of the face `tab-line'. */ | ||
| 1516 | |||
| 1517 | #define CURRENT_TAB_LINE_HEIGHT(W) \ | ||
| 1518 | (W->tab_line_height >= 0 \ | ||
| 1519 | ? W->tab_line_height \ | ||
| 1520 | : (W->tab_line_height \ | ||
| 1521 | = (MATRIX_TAB_LINE_HEIGHT (W->current_matrix) \ | ||
| 1522 | ? MATRIX_TAB_LINE_HEIGHT (W->current_matrix) \ | ||
| 1523 | : estimate_mode_line_height \ | ||
| 1524 | (XFRAME (W->frame), TAB_LINE_FACE_ID)))) | ||
| 1525 | |||
| 1488 | /* Return the height of the desired mode line of window W. */ | 1526 | /* Return the height of the desired mode line of window W. */ |
| 1489 | 1527 | ||
| 1490 | #define DESIRED_MODE_LINE_HEIGHT(W) \ | 1528 | #define DESIRED_MODE_LINE_HEIGHT(W) \ |
| @@ -1495,6 +1533,11 @@ struct glyph_string | |||
| 1495 | #define DESIRED_HEADER_LINE_HEIGHT(W) \ | 1533 | #define DESIRED_HEADER_LINE_HEIGHT(W) \ |
| 1496 | MATRIX_HEADER_LINE_HEIGHT ((W)->desired_matrix) | 1534 | MATRIX_HEADER_LINE_HEIGHT ((W)->desired_matrix) |
| 1497 | 1535 | ||
| 1536 | /* Return the height of the desired tab line of window W. */ | ||
| 1537 | |||
| 1538 | #define DESIRED_TAB_LINE_HEIGHT(W) \ | ||
| 1539 | MATRIX_TAB_LINE_HEIGHT ((W)->desired_matrix) | ||
| 1540 | |||
| 1498 | /* Return proper value to be used as baseline offset of font that has | 1541 | /* Return proper value to be used as baseline offset of font that has |
| 1499 | ASCENT and DESCENT to draw characters by the font at the vertical | 1542 | ASCENT and DESCENT to draw characters by the font at the vertical |
| 1500 | center of the line of frame F. | 1543 | center of the line of frame F. |
| @@ -1780,6 +1823,8 @@ enum face_id | |||
| 1780 | WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID, | 1823 | WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID, |
| 1781 | WINDOW_DIVIDER_LAST_PIXEL_FACE_ID, | 1824 | WINDOW_DIVIDER_LAST_PIXEL_FACE_ID, |
| 1782 | INTERNAL_BORDER_FACE_ID, | 1825 | INTERNAL_BORDER_FACE_ID, |
| 1826 | TAB_BAR_FACE_ID, | ||
| 1827 | TAB_LINE_FACE_ID, | ||
| 1783 | BASIC_FACE_ID_SENTINEL | 1828 | BASIC_FACE_ID_SENTINEL |
| 1784 | }; | 1829 | }; |
| 1785 | 1830 | ||
| @@ -2283,6 +2328,9 @@ struct it | |||
| 2283 | /* True means multibyte characters are enabled. */ | 2328 | /* True means multibyte characters are enabled. */ |
| 2284 | bool_bf multibyte_p : 1; | 2329 | bool_bf multibyte_p : 1; |
| 2285 | 2330 | ||
| 2331 | /* True means window has a tab line at its top. */ | ||
| 2332 | bool_bf tab_line_p : 1; | ||
| 2333 | |||
| 2286 | /* True means window has a mode line at its top. */ | 2334 | /* True means window has a mode line at its top. */ |
| 2287 | bool_bf header_line_p : 1; | 2335 | bool_bf header_line_p : 1; |
| 2288 | 2336 | ||
| @@ -3130,6 +3178,50 @@ struct image_cache | |||
| 3130 | 3178 | ||
| 3131 | 3179 | ||
| 3132 | /*********************************************************************** | 3180 | /*********************************************************************** |
| 3181 | Tab-bars | ||
| 3182 | ***********************************************************************/ | ||
| 3183 | |||
| 3184 | /* Enumeration defining where to find tab-bar item information in | ||
| 3185 | tab-bar items vectors stored with frames. Each tab-bar item | ||
| 3186 | occupies TAB_BAR_ITEM_NSLOTS elements in such a vector. */ | ||
| 3187 | |||
| 3188 | enum tab_bar_item_idx | ||
| 3189 | { | ||
| 3190 | /* The key of the tab-bar item. Used to remove items when a binding | ||
| 3191 | for `undefined' is found. */ | ||
| 3192 | TAB_BAR_ITEM_KEY, | ||
| 3193 | |||
| 3194 | /* Non-nil if item is enabled. */ | ||
| 3195 | TAB_BAR_ITEM_ENABLED_P, | ||
| 3196 | |||
| 3197 | /* Non-nil if item is selected (pressed). */ | ||
| 3198 | TAB_BAR_ITEM_SELECTED_P, | ||
| 3199 | |||
| 3200 | /* Caption. */ | ||
| 3201 | TAB_BAR_ITEM_CAPTION, | ||
| 3202 | |||
| 3203 | /* The binding. */ | ||
| 3204 | TAB_BAR_ITEM_BINDING, | ||
| 3205 | |||
| 3206 | /* Help string. */ | ||
| 3207 | TAB_BAR_ITEM_HELP, | ||
| 3208 | |||
| 3209 | /* Sentinel = number of slots in tab_bar_items occupied by one | ||
| 3210 | tab-bar item. */ | ||
| 3211 | TAB_BAR_ITEM_NSLOTS | ||
| 3212 | }; | ||
| 3213 | |||
| 3214 | /* Default values of the above variables. */ | ||
| 3215 | |||
| 3216 | #define DEFAULT_TAB_BAR_BUTTON_MARGIN 4 | ||
| 3217 | #define DEFAULT_TAB_BAR_BUTTON_RELIEF 1 | ||
| 3218 | |||
| 3219 | /* The height in pixels of the default tab-bar images. */ | ||
| 3220 | |||
| 3221 | #define DEFAULT_TAB_BAR_IMAGE_HEIGHT 18 | ||
| 3222 | |||
| 3223 | |||
| 3224 | /*********************************************************************** | ||
| 3133 | Tool-bars | 3225 | Tool-bars |
| 3134 | ***********************************************************************/ | 3226 | ***********************************************************************/ |
| 3135 | 3227 | ||
| @@ -3285,6 +3377,7 @@ extern bool help_echo_showing_p; | |||
| 3285 | extern Lisp_Object help_echo_string, help_echo_window; | 3377 | extern Lisp_Object help_echo_string, help_echo_window; |
| 3286 | extern Lisp_Object help_echo_object, previous_help_echo_string; | 3378 | extern Lisp_Object help_echo_object, previous_help_echo_string; |
| 3287 | extern ptrdiff_t help_echo_pos; | 3379 | extern ptrdiff_t help_echo_pos; |
| 3380 | extern int last_tab_bar_item; | ||
| 3288 | extern int last_tool_bar_item; | 3381 | extern int last_tool_bar_item; |
| 3289 | extern void reseat_at_previous_visible_line_start (struct it *); | 3382 | extern void reseat_at_previous_visible_line_start (struct it *); |
| 3290 | extern Lisp_Object lookup_glyphless_char_display (int, struct it *); | 3383 | extern Lisp_Object lookup_glyphless_char_display (int, struct it *); |
| @@ -3332,6 +3425,8 @@ extern void get_glyph_string_clip_rect (struct glyph_string *, | |||
| 3332 | NativeRectangle *nr); | 3425 | NativeRectangle *nr); |
| 3333 | extern Lisp_Object find_hot_spot (Lisp_Object, int, int); | 3426 | extern Lisp_Object find_hot_spot (Lisp_Object, int, int); |
| 3334 | 3427 | ||
| 3428 | extern void handle_tab_bar_click (struct frame *, | ||
| 3429 | int, int, bool, int); | ||
| 3335 | extern void handle_tool_bar_click (struct frame *, | 3430 | extern void handle_tool_bar_click (struct frame *, |
| 3336 | int, int, bool, int); | 3431 | int, int, bool, int); |
| 3337 | 3432 | ||
diff --git a/src/dispnew.c b/src/dispnew.c index 799ef2beae8..4cf131522ec 100644 --- a/src/dispnew.c +++ b/src/dispnew.c | |||
| @@ -80,7 +80,7 @@ static void adjust_decode_mode_spec_buffer (struct frame *); | |||
| 80 | static void fill_up_glyph_row_with_spaces (struct glyph_row *); | 80 | static void fill_up_glyph_row_with_spaces (struct glyph_row *); |
| 81 | static void clear_window_matrices (struct window *, bool); | 81 | static void clear_window_matrices (struct window *, bool); |
| 82 | static void fill_up_glyph_row_area_with_spaces (struct glyph_row *, int); | 82 | static void fill_up_glyph_row_area_with_spaces (struct glyph_row *, int); |
| 83 | static int scrolling_window (struct window *, bool); | 83 | static int scrolling_window (struct window *, int); |
| 84 | static bool update_window_line (struct window *, int, bool *); | 84 | static bool update_window_line (struct window *, int, bool *); |
| 85 | static void mirror_make_current (struct window *, int); | 85 | static void mirror_make_current (struct window *, int); |
| 86 | #ifdef GLYPH_DEBUG | 86 | #ifdef GLYPH_DEBUG |
| @@ -366,6 +366,8 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y | |||
| 366 | int i; | 366 | int i; |
| 367 | int new_rows; | 367 | int new_rows; |
| 368 | bool marginal_areas_changed_p = 0; | 368 | bool marginal_areas_changed_p = 0; |
| 369 | bool tab_line_changed_p = 0; | ||
| 370 | bool tab_line_p = 0; | ||
| 369 | bool header_line_changed_p = 0; | 371 | bool header_line_changed_p = 0; |
| 370 | bool header_line_p = 0; | 372 | bool header_line_p = 0; |
| 371 | int left = -1, right = -1; | 373 | int left = -1, right = -1; |
| @@ -377,9 +379,13 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y | |||
| 377 | { | 379 | { |
| 378 | window_box (w, ANY_AREA, 0, 0, &window_width, &window_height); | 380 | window_box (w, ANY_AREA, 0, 0, &window_width, &window_height); |
| 379 | 381 | ||
| 382 | tab_line_p = window_wants_tab_line (w); | ||
| 383 | tab_line_changed_p = tab_line_p != matrix->tab_line_p; | ||
| 384 | |||
| 380 | header_line_p = window_wants_header_line (w); | 385 | header_line_p = window_wants_header_line (w); |
| 381 | header_line_changed_p = header_line_p != matrix->header_line_p; | 386 | header_line_changed_p = header_line_p != matrix->header_line_p; |
| 382 | } | 387 | } |
| 388 | matrix->tab_line_p = tab_line_p; | ||
| 383 | matrix->header_line_p = header_line_p; | 389 | matrix->header_line_p = header_line_p; |
| 384 | 390 | ||
| 385 | /* If POOL is null, MATRIX is a window matrix for window-based redisplay. | 391 | /* 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 | |||
| 397 | 403 | ||
| 398 | if (!marginal_areas_changed_p | 404 | if (!marginal_areas_changed_p |
| 399 | && !XFRAME (w->frame)->fonts_changed | 405 | && !XFRAME (w->frame)->fonts_changed |
| 406 | && !tab_line_changed_p | ||
| 400 | && !header_line_changed_p | 407 | && !header_line_changed_p |
| 401 | && matrix->window_pixel_left == WINDOW_LEFT_PIXEL_EDGE (w) | 408 | && matrix->window_pixel_left == WINDOW_LEFT_PIXEL_EDGE (w) |
| 402 | && matrix->window_pixel_top == WINDOW_TOP_PIXEL_EDGE (w) | 409 | && 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 | |||
| 448 | if (w == NULL | 455 | if (w == NULL |
| 449 | || (row == matrix->rows + dim.height - 1 | 456 | || (row == matrix->rows + dim.height - 1 |
| 450 | && window_wants_mode_line (w)) | 457 | && window_wants_mode_line (w)) |
| 451 | || (row == matrix->rows && matrix->header_line_p)) | 458 | || (row == matrix->rows && matrix->tab_line_p) |
| 459 | || (row == matrix->rows | ||
| 460 | && !matrix->tab_line_p && matrix->header_line_p) | ||
| 461 | || (row == (matrix->rows + 1) | ||
| 462 | && matrix->tab_line_p && matrix->header_line_p)) | ||
| 452 | { | 463 | { |
| 453 | row->glyphs[TEXT_AREA] | 464 | row->glyphs[TEXT_AREA] |
| 454 | = row->glyphs[LEFT_MARGIN_AREA]; | 465 | = row->glyphs[LEFT_MARGIN_AREA]; |
| @@ -478,6 +489,7 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y | |||
| 478 | Allocate glyph memory from the heap. */ | 489 | Allocate glyph memory from the heap. */ |
| 479 | if (dim.width > matrix->matrix_w | 490 | if (dim.width > matrix->matrix_w |
| 480 | || new_rows | 491 | || new_rows |
| 492 | || tab_line_changed_p | ||
| 481 | || header_line_changed_p | 493 | || header_line_changed_p |
| 482 | || marginal_areas_changed_p) | 494 | || marginal_areas_changed_p) |
| 483 | { | 495 | { |
| @@ -493,7 +505,11 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y | |||
| 493 | /* The mode line, if displayed, never has marginal areas. */ | 505 | /* The mode line, if displayed, never has marginal areas. */ |
| 494 | if ((row == matrix->rows + dim.height - 1 | 506 | if ((row == matrix->rows + dim.height - 1 |
| 495 | && !(w && window_wants_mode_line (w))) | 507 | && !(w && window_wants_mode_line (w))) |
| 496 | || (row == matrix->rows && matrix->header_line_p)) | 508 | || (row == matrix->rows && matrix->tab_line_p) |
| 509 | || (row == matrix->rows | ||
| 510 | && !matrix->tab_line_p && matrix->header_line_p) | ||
| 511 | || (row == (matrix->rows + 1) | ||
| 512 | && matrix->tab_line_p && matrix->header_line_p)) | ||
| 497 | { | 513 | { |
| 498 | row->glyphs[TEXT_AREA] | 514 | row->glyphs[TEXT_AREA] |
| 499 | = row->glyphs[LEFT_MARGIN_AREA]; | 515 | = row->glyphs[LEFT_MARGIN_AREA]; |
| @@ -539,6 +555,7 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y | |||
| 539 | upper window). Invalidate all rows that are no longer part | 555 | upper window). Invalidate all rows that are no longer part |
| 540 | of the window. */ | 556 | of the window. */ |
| 541 | if (!marginal_areas_changed_p | 557 | if (!marginal_areas_changed_p |
| 558 | && !tab_line_changed_p | ||
| 542 | && !header_line_changed_p | 559 | && !header_line_changed_p |
| 543 | && new_rows == 0 | 560 | && new_rows == 0 |
| 544 | && dim.width == matrix->matrix_w | 561 | && dim.width == matrix->matrix_w |
| @@ -728,7 +745,7 @@ shift_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int start, in | |||
| 728 | eassert (start >= 0 && start < matrix->nrows); | 745 | eassert (start >= 0 && start < matrix->nrows); |
| 729 | eassert (end >= 0 && end <= matrix->nrows); | 746 | eassert (end >= 0 && end <= matrix->nrows); |
| 730 | 747 | ||
| 731 | min_y = WINDOW_HEADER_LINE_HEIGHT (w); | 748 | min_y = WINDOW_TAB_LINE_HEIGHT (w) + WINDOW_HEADER_LINE_HEIGHT (w); |
| 732 | max_y = WINDOW_BOX_HEIGHT_NO_MODE_LINE (w); | 749 | max_y = WINDOW_BOX_HEIGHT_NO_MODE_LINE (w); |
| 733 | 750 | ||
| 734 | for (; start < end; ++start) | 751 | for (; start < end; ++start) |
| @@ -767,6 +784,12 @@ clear_current_matrices (register struct frame *f) | |||
| 767 | clear_glyph_matrix (XWINDOW (f->menu_bar_window)->current_matrix); | 784 | clear_glyph_matrix (XWINDOW (f->menu_bar_window)->current_matrix); |
| 768 | #endif | 785 | #endif |
| 769 | 786 | ||
| 787 | #if defined (HAVE_WINDOW_SYSTEM) | ||
| 788 | /* Clear the matrix of the tab-bar window, if any. */ | ||
| 789 | if (WINDOWP (f->tab_bar_window)) | ||
| 790 | clear_glyph_matrix (XWINDOW (f->tab_bar_window)->current_matrix); | ||
| 791 | #endif | ||
| 792 | |||
| 770 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) | 793 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) |
| 771 | /* Clear the matrix of the tool-bar window, if any. */ | 794 | /* Clear the matrix of the tool-bar window, if any. */ |
| 772 | if (WINDOWP (f->tool_bar_window)) | 795 | if (WINDOWP (f->tool_bar_window)) |
| @@ -792,6 +815,11 @@ clear_desired_matrices (register struct frame *f) | |||
| 792 | clear_glyph_matrix (XWINDOW (f->menu_bar_window)->desired_matrix); | 815 | clear_glyph_matrix (XWINDOW (f->menu_bar_window)->desired_matrix); |
| 793 | #endif | 816 | #endif |
| 794 | 817 | ||
| 818 | #if defined (HAVE_WINDOW_SYSTEM) | ||
| 819 | if (WINDOWP (f->tab_bar_window)) | ||
| 820 | clear_glyph_matrix (XWINDOW (f->tab_bar_window)->desired_matrix); | ||
| 821 | #endif | ||
| 822 | |||
| 795 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) | 823 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) |
| 796 | if (WINDOWP (f->tool_bar_window)) | 824 | if (WINDOWP (f->tool_bar_window)) |
| 797 | clear_glyph_matrix (XWINDOW (f->tool_bar_window)->desired_matrix); | 825 | 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) | |||
| 857 | { | 885 | { |
| 858 | int min_y, max_y; | 886 | int min_y, max_y; |
| 859 | 887 | ||
| 860 | min_y = WINDOW_HEADER_LINE_HEIGHT (w); | 888 | min_y = WINDOW_TAB_LINE_HEIGHT (w) + WINDOW_HEADER_LINE_HEIGHT (w); |
| 861 | max_y = WINDOW_BOX_HEIGHT_NO_MODE_LINE (w); | 889 | max_y = WINDOW_BOX_HEIGHT_NO_MODE_LINE (w); |
| 862 | 890 | ||
| 863 | clear_glyph_row (row); | 891 | clear_glyph_row (row); |
| @@ -1062,7 +1090,7 @@ find_glyph_row_slice (struct glyph_matrix *window_matrix, | |||
| 1062 | call to this function really clears it. In addition, this function | 1090 | call to this function really clears it. In addition, this function |
| 1063 | makes sure the marginal areas of ROW are in sync with the window's | 1091 | makes sure the marginal areas of ROW are in sync with the window's |
| 1064 | display margins. MODE_LINE_P non-zero means we are preparing a | 1092 | display margins. MODE_LINE_P non-zero means we are preparing a |
| 1065 | glyph row for header line or mode line. */ | 1093 | glyph row for tab/header line or mode line. */ |
| 1066 | 1094 | ||
| 1067 | void | 1095 | void |
| 1068 | prepare_desired_row (struct window *w, struct glyph_row *row, bool mode_line_p) | 1096 | 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) | |||
| 1077 | } | 1105 | } |
| 1078 | if (mode_line_p) | 1106 | if (mode_line_p) |
| 1079 | { | 1107 | { |
| 1080 | /* Mode and header lines, if displayed, never have marginal | 1108 | /* Mode and header/tab lines, if displayed, never have marginal |
| 1081 | areas. If we are called with MODE_LINE_P non-zero, we are | 1109 | areas. If we are called with MODE_LINE_P non-zero, we are |
| 1082 | displaying the mode/header line in this window, and so the | 1110 | displaying the mode/header/tab line in this window, and so the |
| 1083 | marginal areas of this glyph row should be eliminated. This | 1111 | marginal areas of this glyph row should be eliminated. This |
| 1084 | is needed when the mode/header line is switched on in a | 1112 | is needed when the mode/header/tab line is switched on in a |
| 1085 | window that has display margins. */ | 1113 | window that has display margins. */ |
| 1086 | if (w->left_margin_cols > 0) | 1114 | if (w->left_margin_cols > 0) |
| 1087 | row->glyphs[TEXT_AREA] = row->glyphs[LEFT_MARGIN_AREA]; | 1115 | 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) | |||
| 1099 | 1127 | ||
| 1100 | /* Make sure the marginal areas of this row are in sync with | 1128 | /* Make sure the marginal areas of this row are in sync with |
| 1101 | what the window wants, when the row actually displays text | 1129 | what the window wants, when the row actually displays text |
| 1102 | and not header/mode line. */ | 1130 | and not tab/header/mode line. */ |
| 1103 | if (w->left_margin_cols > 0 | 1131 | if (w->left_margin_cols > 0 |
| 1104 | && (left != row->glyphs[TEXT_AREA] - row->glyphs[LEFT_MARGIN_AREA])) | 1132 | && (left != row->glyphs[TEXT_AREA] - row->glyphs[LEFT_MARGIN_AREA])) |
| 1105 | row->glyphs[TEXT_AREA] = row->glyphs[LEFT_MARGIN_AREA] + left; | 1133 | row->glyphs[TEXT_AREA] = row->glyphs[LEFT_MARGIN_AREA] + left; |
| @@ -1708,8 +1736,8 @@ required_matrix_height (struct window *w) | |||
| 1708 | /* One partially visible line at the top and | 1736 | /* One partially visible line at the top and |
| 1709 | bottom of the window. */ | 1737 | bottom of the window. */ |
| 1710 | + 2 | 1738 | + 2 |
| 1711 | /* 2 for header and mode line. */ | 1739 | /* 3 for tab, header and mode line. */ |
| 1712 | + 2); | 1740 | + 3); |
| 1713 | } | 1741 | } |
| 1714 | #endif /* HAVE_WINDOW_SYSTEM */ | 1742 | #endif /* HAVE_WINDOW_SYSTEM */ |
| 1715 | 1743 | ||
| @@ -1862,6 +1890,7 @@ fake_current_matrices (Lisp_Object window) | |||
| 1862 | - r->used[LEFT_MARGIN_AREA] | 1890 | - r->used[LEFT_MARGIN_AREA] |
| 1863 | - r->used[RIGHT_MARGIN_AREA]); | 1891 | - r->used[RIGHT_MARGIN_AREA]); |
| 1864 | r->mode_line_p = 0; | 1892 | r->mode_line_p = 0; |
| 1893 | r->tab_line_p = 0; | ||
| 1865 | } | 1894 | } |
| 1866 | } | 1895 | } |
| 1867 | } | 1896 | } |
| @@ -2106,6 +2135,36 @@ adjust_frame_glyphs_for_window_redisplay (struct frame *f) | |||
| 2106 | } | 2135 | } |
| 2107 | #endif | 2136 | #endif |
| 2108 | 2137 | ||
| 2138 | #if defined (HAVE_WINDOW_SYSTEM) | ||
| 2139 | { | ||
| 2140 | /* Allocate/ reallocate matrices of the tab bar window. If we | ||
| 2141 | don't have a tab bar window yet, make one. */ | ||
| 2142 | struct window *w; | ||
| 2143 | if (NILP (f->tab_bar_window)) | ||
| 2144 | { | ||
| 2145 | Lisp_Object frame; | ||
| 2146 | fset_tab_bar_window (f, make_window ()); | ||
| 2147 | w = XWINDOW (f->tab_bar_window); | ||
| 2148 | XSETFRAME (frame, f); | ||
| 2149 | wset_frame (w, frame); | ||
| 2150 | w->pseudo_window_p = 1; | ||
| 2151 | } | ||
| 2152 | else | ||
| 2153 | w = XWINDOW (f->tab_bar_window); | ||
| 2154 | |||
| 2155 | w->pixel_left = 0; | ||
| 2156 | w->left_col = 0; | ||
| 2157 | w->pixel_top = FRAME_MENU_BAR_HEIGHT (f); | ||
| 2158 | w->top_line = FRAME_MENU_BAR_LINES (f); | ||
| 2159 | w->total_cols = FRAME_TOTAL_COLS (f); | ||
| 2160 | w->pixel_width = (FRAME_PIXEL_WIDTH (f) | ||
| 2161 | - 2 * FRAME_INTERNAL_BORDER_WIDTH (f)); | ||
| 2162 | w->total_lines = FRAME_TAB_BAR_LINES (f); | ||
| 2163 | w->pixel_height = FRAME_TAB_BAR_HEIGHT (f); | ||
| 2164 | allocate_matrices_for_window_redisplay (w); | ||
| 2165 | } | ||
| 2166 | #endif | ||
| 2167 | |||
| 2109 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) | 2168 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) |
| 2110 | { | 2169 | { |
| 2111 | /* Allocate/ reallocate matrices of the tool bar window. If we | 2170 | /* Allocate/ reallocate matrices of the tool bar window. If we |
| @@ -2125,8 +2184,8 @@ adjust_frame_glyphs_for_window_redisplay (struct frame *f) | |||
| 2125 | 2184 | ||
| 2126 | w->pixel_left = 0; | 2185 | w->pixel_left = 0; |
| 2127 | w->left_col = 0; | 2186 | w->left_col = 0; |
| 2128 | w->pixel_top = FRAME_MENU_BAR_HEIGHT (f); | 2187 | w->pixel_top = FRAME_MENU_BAR_HEIGHT (f) + FRAME_TAB_BAR_HEIGHT (f); |
| 2129 | w->top_line = FRAME_MENU_BAR_LINES (f); | 2188 | w->top_line = FRAME_MENU_BAR_LINES (f) + FRAME_TAB_BAR_LINES (f); |
| 2130 | w->total_cols = FRAME_TOTAL_COLS (f); | 2189 | w->total_cols = FRAME_TOTAL_COLS (f); |
| 2131 | w->pixel_width = (FRAME_PIXEL_WIDTH (f) | 2190 | w->pixel_width = (FRAME_PIXEL_WIDTH (f) |
| 2132 | - 2 * FRAME_INTERNAL_BORDER_WIDTH (f)); | 2191 | - 2 * FRAME_INTERNAL_BORDER_WIDTH (f)); |
| @@ -2188,6 +2247,18 @@ free_glyphs (struct frame *f) | |||
| 2188 | } | 2247 | } |
| 2189 | #endif | 2248 | #endif |
| 2190 | 2249 | ||
| 2250 | #if defined (HAVE_WINDOW_SYSTEM) | ||
| 2251 | /* Free the tab bar window and its glyph matrices. */ | ||
| 2252 | if (!NILP (f->tab_bar_window)) | ||
| 2253 | { | ||
| 2254 | struct window *w = XWINDOW (f->tab_bar_window); | ||
| 2255 | free_glyph_matrix (w->desired_matrix); | ||
| 2256 | free_glyph_matrix (w->current_matrix); | ||
| 2257 | w->desired_matrix = w->current_matrix = NULL; | ||
| 2258 | fset_tab_bar_window (f, Qnil); | ||
| 2259 | } | ||
| 2260 | #endif | ||
| 2261 | |||
| 2191 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) | 2262 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) |
| 2192 | /* Free the tool bar window and its glyph matrices. */ | 2263 | /* Free the tool bar window and its glyph matrices. */ |
| 2193 | if (!NILP (f->tool_bar_window)) | 2264 | if (!NILP (f->tool_bar_window)) |
| @@ -3082,6 +3153,29 @@ update_frame (struct frame *f, bool force_p, bool inhibit_hairy_id_p) | |||
| 3082 | update_window (XWINDOW (f->menu_bar_window), true); | 3153 | update_window (XWINDOW (f->menu_bar_window), true); |
| 3083 | #endif | 3154 | #endif |
| 3084 | 3155 | ||
| 3156 | #if defined (HAVE_WINDOW_SYSTEM) | ||
| 3157 | /* Update the tab-bar window, if present. */ | ||
| 3158 | if (WINDOWP (f->tab_bar_window)) | ||
| 3159 | { | ||
| 3160 | struct window *w = XWINDOW (f->tab_bar_window); | ||
| 3161 | |||
| 3162 | /* Update tab-bar window. */ | ||
| 3163 | if (w->must_be_updated_p) | ||
| 3164 | { | ||
| 3165 | Lisp_Object tem; | ||
| 3166 | |||
| 3167 | update_window (w, true); | ||
| 3168 | w->must_be_updated_p = false; | ||
| 3169 | |||
| 3170 | /* Swap tab-bar strings. We swap because we want to | ||
| 3171 | reuse strings. */ | ||
| 3172 | tem = f->current_tab_bar_string; | ||
| 3173 | fset_current_tab_bar_string (f, f->desired_tab_bar_string); | ||
| 3174 | fset_desired_tab_bar_string (f, tem); | ||
| 3175 | } | ||
| 3176 | } | ||
| 3177 | #endif | ||
| 3178 | |||
| 3085 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) | 3179 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) |
| 3086 | /* Update the tool-bar window, if present. */ | 3180 | /* Update the tool-bar window, if present. */ |
| 3087 | if (WINDOWP (f->tool_bar_window)) | 3181 | if (WINDOWP (f->tool_bar_window)) |
| @@ -3408,6 +3502,7 @@ update_window (struct window *w, bool force_p) | |||
| 3408 | { | 3502 | { |
| 3409 | struct glyph_row *row, *end; | 3503 | struct glyph_row *row, *end; |
| 3410 | struct glyph_row *mode_line_row; | 3504 | struct glyph_row *mode_line_row; |
| 3505 | struct glyph_row *tab_line_row; | ||
| 3411 | struct glyph_row *header_line_row; | 3506 | struct glyph_row *header_line_row; |
| 3412 | int yb; | 3507 | int yb; |
| 3413 | bool changed_p = 0, mouse_face_overwritten_p = 0; | 3508 | bool changed_p = 0, mouse_face_overwritten_p = 0; |
| @@ -3420,6 +3515,16 @@ update_window (struct window *w, bool force_p) | |||
| 3420 | row = MATRIX_ROW (desired_matrix, 0); | 3515 | row = MATRIX_ROW (desired_matrix, 0); |
| 3421 | end = MATRIX_MODE_LINE_ROW (desired_matrix); | 3516 | end = MATRIX_MODE_LINE_ROW (desired_matrix); |
| 3422 | 3517 | ||
| 3518 | /* Take note of the tab line, if there is one. We will | ||
| 3519 | update it below, after updating all of the window's lines. */ | ||
| 3520 | if (row->mode_line_p && row->tab_line_p) | ||
| 3521 | { | ||
| 3522 | tab_line_row = row; | ||
| 3523 | ++row; | ||
| 3524 | } | ||
| 3525 | else | ||
| 3526 | tab_line_row = NULL; | ||
| 3527 | |||
| 3423 | /* Take note of the header line, if there is one. We will | 3528 | /* Take note of the header line, if there is one. We will |
| 3424 | update it below, after updating all of the window's lines. */ | 3529 | update it below, after updating all of the window's lines. */ |
| 3425 | if (row->mode_line_p) | 3530 | if (row->mode_line_p) |
| @@ -3449,7 +3554,8 @@ update_window (struct window *w, bool force_p) | |||
| 3449 | /* Try reusing part of the display by copying. */ | 3554 | /* Try reusing part of the display by copying. */ |
| 3450 | if (row < end && !desired_matrix->no_scrolling_p) | 3555 | if (row < end && !desired_matrix->no_scrolling_p) |
| 3451 | { | 3556 | { |
| 3452 | int rc = scrolling_window (w, header_line_row != NULL); | 3557 | int rc = scrolling_window (w, (tab_line_row != NULL ? 1 : 0) |
| 3558 | + (header_line_row != NULL ? 1 : 0)); | ||
| 3453 | if (rc < 0) | 3559 | if (rc < 0) |
| 3454 | { | 3560 | { |
| 3455 | /* All rows were found to be equal. */ | 3561 | /* All rows were found to be equal. */ |
| @@ -3501,13 +3607,22 @@ update_window (struct window *w, bool force_p) | |||
| 3501 | 3607 | ||
| 3502 | set_cursor: | 3608 | set_cursor: |
| 3503 | 3609 | ||
| 3610 | /* Update the tab line after scrolling because a new tab | ||
| 3611 | line would otherwise overwrite lines at the top of the window | ||
| 3612 | that can be scrolled. */ | ||
| 3613 | if (tab_line_row && tab_line_row->enabled_p) | ||
| 3614 | { | ||
| 3615 | tab_line_row->y = 0; | ||
| 3616 | update_window_line (w, 0, &mouse_face_overwritten_p); | ||
| 3617 | } | ||
| 3618 | |||
| 3504 | /* Update the header line after scrolling because a new header | 3619 | /* Update the header line after scrolling because a new header |
| 3505 | line would otherwise overwrite lines at the top of the window | 3620 | line would otherwise overwrite lines at the top of the window |
| 3506 | that can be scrolled. */ | 3621 | that can be scrolled. */ |
| 3507 | if (header_line_row && header_line_row->enabled_p) | 3622 | if (header_line_row && header_line_row->enabled_p) |
| 3508 | { | 3623 | { |
| 3509 | header_line_row->y = 0; | 3624 | header_line_row->y = tab_line_row ? CURRENT_TAB_LINE_HEIGHT (w) : 0; |
| 3510 | update_window_line (w, 0, &mouse_face_overwritten_p); | 3625 | update_window_line (w, tab_line_row ? 1 : 0, &mouse_face_overwritten_p); |
| 3511 | } | 3626 | } |
| 3512 | 3627 | ||
| 3513 | /* Fix the appearance of overlapping/overlapped rows. */ | 3628 | /* Fix the appearance of overlapping/overlapped rows. */ |
| @@ -4178,7 +4293,7 @@ add_row_entry (struct glyph_row *row) | |||
| 4178 | 1 if we did scroll. */ | 4293 | 1 if we did scroll. */ |
| 4179 | 4294 | ||
| 4180 | static int | 4295 | static int |
| 4181 | scrolling_window (struct window *w, bool header_line_p) | 4296 | scrolling_window (struct window *w, int tab_line_p) |
| 4182 | { | 4297 | { |
| 4183 | struct glyph_matrix *desired_matrix = w->desired_matrix; | 4298 | struct glyph_matrix *desired_matrix = w->desired_matrix; |
| 4184 | struct glyph_matrix *current_matrix = w->current_matrix; | 4299 | struct glyph_matrix *current_matrix = w->current_matrix; |
| @@ -4191,7 +4306,7 @@ scrolling_window (struct window *w, bool header_line_p) | |||
| 4191 | struct redisplay_interface *rif = FRAME_RIF (XFRAME (WINDOW_FRAME (w))); | 4306 | struct redisplay_interface *rif = FRAME_RIF (XFRAME (WINDOW_FRAME (w))); |
| 4192 | 4307 | ||
| 4193 | /* Skip over rows equal at the start. */ | 4308 | /* Skip over rows equal at the start. */ |
| 4194 | for (i = header_line_p; i < current_matrix->nrows - 1; ++i) | 4309 | for (i = tab_line_p; i < current_matrix->nrows - 1; ++i) |
| 4195 | { | 4310 | { |
| 4196 | struct glyph_row *d = MATRIX_ROW (desired_matrix, i); | 4311 | struct glyph_row *d = MATRIX_ROW (desired_matrix, i); |
| 4197 | struct glyph_row *c = MATRIX_ROW (current_matrix, i); | 4312 | 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 | |||
| 5318 | start position, i.e. it excludes the header-line row, but | 5433 | start position, i.e. it excludes the header-line row, but |
| 5319 | MATRIX_ROW includes the header-line row. Adjust for a possible | 5434 | MATRIX_ROW includes the header-line row. Adjust for a possible |
| 5320 | header-line row. */ | 5435 | header-line row. */ |
| 5321 | it_vpos = it.vpos + window_wants_header_line (w); | 5436 | it_vpos = it.vpos + window_wants_header_line (w) |
| 5437 | + window_wants_tab_line (w); | ||
| 5322 | if (it_vpos < w->current_matrix->nrows | 5438 | if (it_vpos < w->current_matrix->nrows |
| 5323 | && (row = MATRIX_ROW (w->current_matrix, it_vpos), | 5439 | && (row = MATRIX_ROW (w->current_matrix, it_vpos), |
| 5324 | row->enabled_p)) | 5440 | row->enabled_p)) |
| @@ -5382,6 +5498,8 @@ mode_line_string (struct window *w, enum window_part part, | |||
| 5382 | 5498 | ||
| 5383 | if (part == ON_MODE_LINE) | 5499 | if (part == ON_MODE_LINE) |
| 5384 | row = MATRIX_MODE_LINE_ROW (w->current_matrix); | 5500 | row = MATRIX_MODE_LINE_ROW (w->current_matrix); |
| 5501 | else if (part == ON_TAB_LINE) | ||
| 5502 | row = MATRIX_TAB_LINE_ROW (w->current_matrix); | ||
| 5385 | else | 5503 | else |
| 5386 | row = MATRIX_HEADER_LINE_ROW (w->current_matrix); | 5504 | row = MATRIX_HEADER_LINE_ROW (w->current_matrix); |
| 5387 | y0 = *y - row->y; | 5505 | y0 = *y - row->y; |
| @@ -5563,7 +5681,8 @@ handle_window_change_signal (int sig) | |||
| 5563 | structures now. Let that be done later outside of the | 5681 | structures now. Let that be done later outside of the |
| 5564 | signal handler. */ | 5682 | signal handler. */ |
| 5565 | change_frame_size (XFRAME (frame), width, | 5683 | change_frame_size (XFRAME (frame), width, |
| 5566 | height - FRAME_MENU_BAR_LINES (XFRAME (frame)), | 5684 | height - FRAME_MENU_BAR_LINES (XFRAME (frame)) |
| 5685 | - FRAME_TAB_BAR_LINES (XFRAME (frame)), | ||
| 5567 | 0, 1, 0, 0); | 5686 | 0, 1, 0, 0); |
| 5568 | } | 5687 | } |
| 5569 | } | 5688 | } |
| @@ -6243,7 +6362,8 @@ init_display_interactive (void) | |||
| 6243 | change_frame_size (XFRAME (selected_frame), | 6362 | change_frame_size (XFRAME (selected_frame), |
| 6244 | FrameCols (t->display_info.tty), | 6363 | FrameCols (t->display_info.tty), |
| 6245 | FrameRows (t->display_info.tty) | 6364 | FrameRows (t->display_info.tty) |
| 6246 | - FRAME_MENU_BAR_LINES (f), 0, 0, 1, 0); | 6365 | - FRAME_MENU_BAR_LINES (f) |
| 6366 | - FRAME_TAB_BAR_LINES (f), 0, 0, 1, 0); | ||
| 6247 | 6367 | ||
| 6248 | /* Delete the initial terminal. */ | 6368 | /* Delete the initial terminal. */ |
| 6249 | if (--initial_terminal->reference_count == 0 | 6369 | if (--initial_terminal->reference_count == 0 |
diff --git a/src/frame.c b/src/frame.c index 1d42d0cb4de..d72dfec0cf8 100644 --- a/src/frame.c +++ b/src/frame.c | |||
| @@ -69,6 +69,9 @@ static struct frame *last_nonminibuf_frame; | |||
| 69 | /* False means there are no visible garbaged frames. */ | 69 | /* False means there are no visible garbaged frames. */ |
| 70 | bool frame_garbaged; | 70 | bool frame_garbaged; |
| 71 | 71 | ||
| 72 | /* The default tab bar height for future frames. */ | ||
| 73 | int frame_default_tab_bar_height; | ||
| 74 | |||
| 72 | /* The default tool bar height for future frames. */ | 75 | /* The default tool bar height for future frames. */ |
| 73 | #ifdef HAVE_EXT_TOOL_BAR | 76 | #ifdef HAVE_EXT_TOOL_BAR |
| 74 | enum { frame_default_tool_bar_height = 0 }; | 77 | enum { frame_default_tool_bar_height = 0 }; |
| @@ -230,6 +233,35 @@ set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) | |||
| 230 | 0, 1, 0, 0); | 233 | 0, 1, 0, 0); |
| 231 | } | 234 | } |
| 232 | } | 235 | } |
| 236 | |||
| 237 | static void | ||
| 238 | set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) | ||
| 239 | { | ||
| 240 | int nlines; | ||
| 241 | int olines = FRAME_TAB_BAR_LINES (f); | ||
| 242 | |||
| 243 | /* Right now, tab bars don't work properly in minibuf-only frames; | ||
| 244 | most of the commands try to apply themselves to the minibuffer | ||
| 245 | frame itself, and get an error because you can't switch buffers | ||
| 246 | in or split the minibuffer window. */ | ||
| 247 | if (FRAME_MINIBUF_ONLY_P (f)) | ||
| 248 | return; | ||
| 249 | |||
| 250 | if (TYPE_RANGED_FIXNUMP (int, value)) | ||
| 251 | nlines = XFIXNUM (value); | ||
| 252 | else | ||
| 253 | nlines = 0; | ||
| 254 | |||
| 255 | if (nlines != olines) | ||
| 256 | { | ||
| 257 | windows_or_buffers_changed = 14; | ||
| 258 | FRAME_TAB_BAR_LINES (f) = nlines; | ||
| 259 | FRAME_TAB_BAR_HEIGHT (f) = nlines * FRAME_LINE_HEIGHT (f); | ||
| 260 | change_frame_size (f, FRAME_COLS (f), | ||
| 261 | FRAME_LINES (f) + olines - nlines, | ||
| 262 | 0, 1, 0, 0); | ||
| 263 | } | ||
| 264 | } | ||
| 233 | 265 | ||
| 234 | Lisp_Object Vframe_list; | 266 | Lisp_Object Vframe_list; |
| 235 | 267 | ||
| @@ -379,6 +411,7 @@ frame_windows_min_size (Lisp_Object frame, Lisp_Object horizontal, | |||
| 379 | if ((FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f)) && NILP (horizontal)) | 411 | if ((FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f)) && NILP (horizontal)) |
| 380 | { | 412 | { |
| 381 | int min_height = (FRAME_MENU_BAR_LINES (f) | 413 | int min_height = (FRAME_MENU_BAR_LINES (f) |
| 414 | + FRAME_TAB_BAR_LINES (f) | ||
| 382 | + FRAME_WANTS_MODELINE_P (f) | 415 | + FRAME_WANTS_MODELINE_P (f) |
| 383 | + 2); /* one text line and one echo-area line */ | 416 | + 2); /* one text line and one echo-area line */ |
| 384 | if (retval < min_height) | 417 | if (retval < min_height) |
| @@ -719,6 +752,15 @@ adjust_frame_size (struct frame *f, int new_width, int new_height, int inhibit, | |||
| 719 | if ((FRAME_TERMCAP_P (f) && !pretend) || FRAME_MSDOS_P (f)) | 752 | if ((FRAME_TERMCAP_P (f) && !pretend) || FRAME_MSDOS_P (f)) |
| 720 | FrameCols (FRAME_TTY (f)) = new_cols; | 753 | FrameCols (FRAME_TTY (f)) = new_cols; |
| 721 | 754 | ||
| 755 | #if defined (HAVE_WINDOW_SYSTEM) | ||
| 756 | if (WINDOWP (f->tab_bar_window)) | ||
| 757 | { | ||
| 758 | XWINDOW (f->tab_bar_window)->pixel_width = new_windows_width; | ||
| 759 | XWINDOW (f->tab_bar_window)->total_cols | ||
| 760 | = new_windows_width / unit_width; | ||
| 761 | } | ||
| 762 | #endif | ||
| 763 | |||
| 722 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) | 764 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) |
| 723 | if (WINDOWP (f->tool_bar_window)) | 765 | if (WINDOWP (f->tool_bar_window)) |
| 724 | { | 766 | { |
| @@ -838,6 +880,8 @@ make_frame (bool mini_p) | |||
| 838 | f->after_make_frame = false; | 880 | f->after_make_frame = false; |
| 839 | f->inhibit_horizontal_resize = false; | 881 | f->inhibit_horizontal_resize = false; |
| 840 | f->inhibit_vertical_resize = false; | 882 | f->inhibit_vertical_resize = false; |
| 883 | f->tab_bar_redisplayed = false; | ||
| 884 | f->tab_bar_resized = false; | ||
| 841 | f->tool_bar_redisplayed = false; | 885 | f->tool_bar_redisplayed = false; |
| 842 | f->tool_bar_resized = false; | 886 | f->tool_bar_resized = false; |
| 843 | f->column_width = 1; /* !FRAME_WINDOW_P value. */ | 887 | f->column_width = 1; /* !FRAME_WINDOW_P value. */ |
| @@ -856,6 +900,7 @@ make_frame (bool mini_p) | |||
| 856 | f->no_accept_focus = false; | 900 | f->no_accept_focus = false; |
| 857 | f->z_group = z_group_none; | 901 | f->z_group = z_group_none; |
| 858 | f->tooltip = false; | 902 | f->tooltip = false; |
| 903 | f->last_tab_bar_item = -1; | ||
| 859 | #ifndef HAVE_EXT_TOOL_BAR | 904 | #ifndef HAVE_EXT_TOOL_BAR |
| 860 | f->last_tool_bar_item = -1; | 905 | f->last_tool_bar_item = -1; |
| 861 | #endif | 906 | #endif |
| @@ -1084,6 +1129,9 @@ make_initial_frame (void) | |||
| 1084 | /* The default value of menu-bar-mode is t. */ | 1129 | /* The default value of menu-bar-mode is t. */ |
| 1085 | set_menu_bar_lines (f, make_fixnum (1), Qnil); | 1130 | set_menu_bar_lines (f, make_fixnum (1), Qnil); |
| 1086 | 1131 | ||
| 1132 | /* The default value of tab-bar-mode is nil. */ | ||
| 1133 | set_tab_bar_lines (f, make_fixnum (0), Qnil); | ||
| 1134 | |||
| 1087 | /* Allocate glyph matrices. */ | 1135 | /* Allocate glyph matrices. */ |
| 1088 | adjust_frame_glyphs (f); | 1136 | adjust_frame_glyphs (f); |
| 1089 | 1137 | ||
| @@ -1142,9 +1190,13 @@ make_terminal_frame (struct terminal *terminal) | |||
| 1142 | #endif | 1190 | #endif |
| 1143 | 1191 | ||
| 1144 | FRAME_MENU_BAR_LINES (f) = NILP (Vmenu_bar_mode) ? 0 : 1; | 1192 | FRAME_MENU_BAR_LINES (f) = NILP (Vmenu_bar_mode) ? 0 : 1; |
| 1145 | FRAME_LINES (f) = FRAME_LINES (f) - FRAME_MENU_BAR_LINES (f); | 1193 | FRAME_TAB_BAR_LINES (f) = NILP (Vtab_bar_mode) ? 0 : 1; |
| 1194 | FRAME_LINES (f) = FRAME_LINES (f) - FRAME_MENU_BAR_LINES (f) | ||
| 1195 | - FRAME_TAB_BAR_LINES (f); | ||
| 1146 | FRAME_MENU_BAR_HEIGHT (f) = FRAME_MENU_BAR_LINES (f) * FRAME_LINE_HEIGHT (f); | 1196 | FRAME_MENU_BAR_HEIGHT (f) = FRAME_MENU_BAR_LINES (f) * FRAME_LINE_HEIGHT (f); |
| 1147 | FRAME_TEXT_HEIGHT (f) = FRAME_TEXT_HEIGHT (f) - FRAME_MENU_BAR_HEIGHT (f); | 1197 | FRAME_TAB_BAR_HEIGHT (f) = FRAME_TAB_BAR_LINES (f) * FRAME_LINE_HEIGHT (f); |
| 1198 | FRAME_TEXT_HEIGHT (f) = FRAME_TEXT_HEIGHT (f) - FRAME_MENU_BAR_HEIGHT (f) | ||
| 1199 | - FRAME_TAB_BAR_HEIGHT (f); | ||
| 1148 | 1200 | ||
| 1149 | /* Set the top frame to the newly created frame. */ | 1201 | /* Set the top frame to the newly created frame. */ |
| 1150 | if (FRAMEP (FRAME_TTY (f)->top_frame) | 1202 | if (FRAMEP (FRAME_TTY (f)->top_frame) |
| @@ -1266,7 +1318,8 @@ affects all frames on the same terminal device. */) | |||
| 1266 | { | 1318 | { |
| 1267 | int width, height; | 1319 | int width, height; |
| 1268 | get_tty_size (fileno (FRAME_TTY (f)->input), &width, &height); | 1320 | get_tty_size (fileno (FRAME_TTY (f)->input), &width, &height); |
| 1269 | adjust_frame_size (f, width, height - FRAME_MENU_BAR_LINES (f), | 1321 | adjust_frame_size (f, width, height - FRAME_MENU_BAR_LINES (f) |
| 1322 | - FRAME_TAB_BAR_LINES (f), | ||
| 1270 | 5, 0, Qterminal_frame); | 1323 | 5, 0, Qterminal_frame); |
| 1271 | } | 1324 | } |
| 1272 | 1325 | ||
| @@ -3071,6 +3124,8 @@ store_frame_param (struct frame *f, Lisp_Object prop, Lisp_Object val) | |||
| 3071 | { | 3124 | { |
| 3072 | if (EQ (prop, Qmenu_bar_lines)) | 3125 | if (EQ (prop, Qmenu_bar_lines)) |
| 3073 | set_menu_bar_lines (f, val, make_fixnum (FRAME_MENU_BAR_LINES (f))); | 3126 | set_menu_bar_lines (f, val, make_fixnum (FRAME_MENU_BAR_LINES (f))); |
| 3127 | else if (EQ (prop, Qtab_bar_lines)) | ||
| 3128 | set_tab_bar_lines (f, val, make_fixnum (FRAME_TAB_BAR_LINES (f))); | ||
| 3074 | else if (EQ (prop, Qname)) | 3129 | else if (EQ (prop, Qname)) |
| 3075 | set_term_frame_name (f, val); | 3130 | set_term_frame_name (f, val); |
| 3076 | } | 3131 | } |
| @@ -3166,6 +3221,8 @@ If FRAME is omitted or nil, return information on the currently selected frame. | |||
| 3166 | Lisp_Object lines; | 3221 | Lisp_Object lines; |
| 3167 | XSETFASTINT (lines, FRAME_MENU_BAR_LINES (f)); | 3222 | XSETFASTINT (lines, FRAME_MENU_BAR_LINES (f)); |
| 3168 | store_in_alist (&alist, Qmenu_bar_lines, lines); | 3223 | store_in_alist (&alist, Qmenu_bar_lines, lines); |
| 3224 | XSETFASTINT (lines, FRAME_TAB_BAR_LINES (f)); | ||
| 3225 | store_in_alist (&alist, Qtab_bar_lines, lines); | ||
| 3169 | } | 3226 | } |
| 3170 | 3227 | ||
| 3171 | return alist; | 3228 | return alist; |
| @@ -3695,6 +3752,7 @@ static const struct frame_parm_table frame_parms[] = | |||
| 3695 | {"vertical-scroll-bars", SYMBOL_INDEX (Qvertical_scroll_bars)}, | 3752 | {"vertical-scroll-bars", SYMBOL_INDEX (Qvertical_scroll_bars)}, |
| 3696 | {"horizontal-scroll-bars", SYMBOL_INDEX (Qhorizontal_scroll_bars)}, | 3753 | {"horizontal-scroll-bars", SYMBOL_INDEX (Qhorizontal_scroll_bars)}, |
| 3697 | {"visibility", SYMBOL_INDEX (Qvisibility)}, | 3754 | {"visibility", SYMBOL_INDEX (Qvisibility)}, |
| 3755 | {"tab-bar-lines", SYMBOL_INDEX (Qtab_bar_lines)}, | ||
| 3698 | {"tool-bar-lines", SYMBOL_INDEX (Qtool_bar_lines)}, | 3756 | {"tool-bar-lines", SYMBOL_INDEX (Qtool_bar_lines)}, |
| 3699 | {"scroll-bar-foreground", SYMBOL_INDEX (Qscroll_bar_foreground)}, | 3757 | {"scroll-bar-foreground", SYMBOL_INDEX (Qscroll_bar_foreground)}, |
| 3700 | {"scroll-bar-background", SYMBOL_INDEX (Qscroll_bar_background)}, | 3758 | {"scroll-bar-background", SYMBOL_INDEX (Qscroll_bar_background)}, |
| @@ -4450,6 +4508,8 @@ gui_set_font (struct frame *f, Lisp_Object arg, Lisp_Object oldval) | |||
| 4450 | #ifdef HAVE_X_WINDOWS | 4508 | #ifdef HAVE_X_WINDOWS |
| 4451 | store_frame_param (f, Qfont_parameter, font_param); | 4509 | store_frame_param (f, Qfont_parameter, font_param); |
| 4452 | #endif | 4510 | #endif |
| 4511 | /* Recalculate tabbar height. */ | ||
| 4512 | f->n_tab_bar_rows = 0; | ||
| 4453 | /* Recalculate toolbar height. */ | 4513 | /* Recalculate toolbar height. */ |
| 4454 | f->n_tool_bar_rows = 0; | 4514 | f->n_tool_bar_rows = 0; |
| 4455 | 4515 | ||
| @@ -5390,8 +5450,8 @@ On Nextstep, this just calls `ns-parse-geometry'. */) | |||
| 5390 | #define DEFAULT_COLS 80 | 5450 | #define DEFAULT_COLS 80 |
| 5391 | 5451 | ||
| 5392 | long | 5452 | long |
| 5393 | gui_figure_window_size (struct frame *f, Lisp_Object parms, bool toolbar_p, | 5453 | gui_figure_window_size (struct frame *f, Lisp_Object parms, bool tabbar_p, |
| 5394 | int *x_width, int *x_height) | 5454 | bool toolbar_p, int *x_width, int *x_height) |
| 5395 | { | 5455 | { |
| 5396 | Lisp_Object height, width, user_size, top, left, user_position; | 5456 | Lisp_Object height, width, user_size, top, left, user_position; |
| 5397 | long window_prompting = 0; | 5457 | long window_prompting = 0; |
| @@ -5411,6 +5471,36 @@ gui_figure_window_size (struct frame *f, Lisp_Object parms, bool toolbar_p, | |||
| 5411 | f->top_pos = 0; | 5471 | f->top_pos = 0; |
| 5412 | f->left_pos = 0; | 5472 | f->left_pos = 0; |
| 5413 | 5473 | ||
| 5474 | /* Calculate a tab bar height so that the user gets a text display | ||
| 5475 | area of the size he specified with -g or via .Xdefaults. Later | ||
| 5476 | changes of the tab bar height don't change the frame size. This | ||
| 5477 | is done so that users can create tall Emacs frames without having | ||
| 5478 | to guess how tall the tab bar will get. */ | ||
| 5479 | if (tabbar_p && FRAME_TAB_BAR_LINES (f)) | ||
| 5480 | { | ||
| 5481 | if (frame_default_tab_bar_height) | ||
| 5482 | FRAME_TAB_BAR_HEIGHT (f) = frame_default_tab_bar_height; | ||
| 5483 | else | ||
| 5484 | { | ||
| 5485 | int margin, relief; | ||
| 5486 | |||
| 5487 | relief = (tab_bar_button_relief < 0 | ||
| 5488 | ? DEFAULT_TAB_BAR_BUTTON_RELIEF | ||
| 5489 | : min (tab_bar_button_relief, 1000000)); | ||
| 5490 | |||
| 5491 | if (RANGED_FIXNUMP (1, Vtab_bar_button_margin, INT_MAX)) | ||
| 5492 | margin = XFIXNAT (Vtab_bar_button_margin); | ||
| 5493 | else if (CONSP (Vtab_bar_button_margin) | ||
| 5494 | && RANGED_FIXNUMP (1, XCDR (Vtab_bar_button_margin), INT_MAX)) | ||
| 5495 | margin = XFIXNAT (XCDR (Vtab_bar_button_margin)); | ||
| 5496 | else | ||
| 5497 | margin = 0; | ||
| 5498 | |||
| 5499 | FRAME_TAB_BAR_HEIGHT (f) | ||
| 5500 | = DEFAULT_TAB_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief; | ||
| 5501 | } | ||
| 5502 | } | ||
| 5503 | |||
| 5414 | /* Calculate a tool bar height so that the user gets a text display | 5504 | /* Calculate a tool bar height so that the user gets a text display |
| 5415 | area of the size he specified with -g or via .Xdefaults. Later | 5505 | area of the size he specified with -g or via .Xdefaults. Later |
| 5416 | changes of the tool bar height don't change the frame size. This | 5506 | changes of the tool bar height don't change the frame size. This |
| @@ -5837,6 +5927,7 @@ syms_of_frame (void) | |||
| 5837 | DEFSYM (Qtitle_bar_size, "title-bar-size"); | 5927 | DEFSYM (Qtitle_bar_size, "title-bar-size"); |
| 5838 | DEFSYM (Qmenu_bar_external, "menu-bar-external"); | 5928 | DEFSYM (Qmenu_bar_external, "menu-bar-external"); |
| 5839 | DEFSYM (Qmenu_bar_size, "menu-bar-size"); | 5929 | DEFSYM (Qmenu_bar_size, "menu-bar-size"); |
| 5930 | DEFSYM (Qtab_bar_size, "tab-bar-size"); | ||
| 5840 | DEFSYM (Qtool_bar_external, "tool-bar-external"); | 5931 | DEFSYM (Qtool_bar_external, "tool-bar-external"); |
| 5841 | DEFSYM (Qtool_bar_size, "tool-bar-size"); | 5932 | DEFSYM (Qtool_bar_size, "tool-bar-size"); |
| 5842 | /* The following are used for frame_size_history. */ | 5933 | /* The following are used for frame_size_history. */ |
| @@ -5860,7 +5951,9 @@ syms_of_frame (void) | |||
| 5860 | DEFSYM (Qx_net_wm_state, "x-net-wm-state"); | 5951 | DEFSYM (Qx_net_wm_state, "x-net-wm-state"); |
| 5861 | DEFSYM (Qx_handle_net_wm_state, "x-handle-net-wm-state"); | 5952 | DEFSYM (Qx_handle_net_wm_state, "x-handle-net-wm-state"); |
| 5862 | DEFSYM (Qtb_size_cb, "tb-size-cb"); | 5953 | DEFSYM (Qtb_size_cb, "tb-size-cb"); |
| 5954 | DEFSYM (Qupdate_frame_tab_bar, "update-frame-tab-bar"); | ||
| 5863 | DEFSYM (Qupdate_frame_tool_bar, "update-frame-tool-bar"); | 5955 | DEFSYM (Qupdate_frame_tool_bar, "update-frame-tool-bar"); |
| 5956 | DEFSYM (Qfree_frame_tab_bar, "free-frame-tab-bar"); | ||
| 5864 | DEFSYM (Qfree_frame_tool_bar, "free-frame-tool-bar"); | 5957 | DEFSYM (Qfree_frame_tool_bar, "free-frame-tool-bar"); |
| 5865 | DEFSYM (Qx_set_menu_bar_lines, "x-set-menu-bar-lines"); | 5958 | DEFSYM (Qx_set_menu_bar_lines, "x-set-menu-bar-lines"); |
| 5866 | DEFSYM (Qchange_frame_size, "change-frame-size"); | 5959 | DEFSYM (Qchange_frame_size, "change-frame-size"); |
| @@ -5910,6 +6003,7 @@ syms_of_frame (void) | |||
| 5910 | DEFSYM (Qscroll_bar_width, "scroll-bar-width"); | 6003 | DEFSYM (Qscroll_bar_width, "scroll-bar-width"); |
| 5911 | DEFSYM (Qsticky, "sticky"); | 6004 | DEFSYM (Qsticky, "sticky"); |
| 5912 | DEFSYM (Qtitle, "title"); | 6005 | DEFSYM (Qtitle, "title"); |
| 6006 | DEFSYM (Qtab_bar_lines, "tab-bar-lines"); | ||
| 5913 | DEFSYM (Qtool_bar_lines, "tool-bar-lines"); | 6007 | DEFSYM (Qtool_bar_lines, "tool-bar-lines"); |
| 5914 | DEFSYM (Qtool_bar_position, "tool-bar-position"); | 6008 | DEFSYM (Qtool_bar_position, "tool-bar-position"); |
| 5915 | DEFSYM (Qunsplittable, "unsplittable"); | 6009 | DEFSYM (Qunsplittable, "unsplittable"); |
| @@ -6071,6 +6165,14 @@ either customize it (see the info node `Easy Customization') | |||
| 6071 | or call the function `menu-bar-mode'. */); | 6165 | or call the function `menu-bar-mode'. */); |
| 6072 | Vmenu_bar_mode = Qt; | 6166 | Vmenu_bar_mode = Qt; |
| 6073 | 6167 | ||
| 6168 | DEFVAR_LISP ("tab-bar-mode", Vtab_bar_mode, | ||
| 6169 | doc: /* Non-nil if Tab-Bar mode is enabled. | ||
| 6170 | See the command `tab-bar-mode' for a description of this minor mode. | ||
| 6171 | Setting this variable directly does not take effect; | ||
| 6172 | either customize it (see the info node `Easy Customization') | ||
| 6173 | or call the function `tab-bar-mode'. */); | ||
| 6174 | Vtab_bar_mode = Qnil; | ||
| 6175 | |||
| 6074 | DEFVAR_LISP ("tool-bar-mode", Vtool_bar_mode, | 6176 | DEFVAR_LISP ("tool-bar-mode", Vtool_bar_mode, |
| 6075 | doc: /* Non-nil if Tool-Bar mode is enabled. | 6177 | doc: /* Non-nil if Tool-Bar mode is enabled. |
| 6076 | See the command `tool-bar-mode' for a description of this minor mode. | 6178 | 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 | |||
| 6200 | even if this option is non-nil. */); | 6302 | even if this option is non-nil. */); |
| 6201 | #if defined (HAVE_WINDOW_SYSTEM) | 6303 | #if defined (HAVE_WINDOW_SYSTEM) |
| 6202 | #if defined (USE_LUCID) || defined (USE_MOTIF) || defined (HAVE_NTGUI) | 6304 | #if defined (USE_LUCID) || defined (USE_MOTIF) || defined (HAVE_NTGUI) |
| 6203 | frame_inhibit_implied_resize = list1 (Qtool_bar_lines); | 6305 | frame_inhibit_implied_resize = list2 (Qtab_bar_lines, Qtool_bar_lines); |
| 6204 | #else | 6306 | #else |
| 6205 | frame_inhibit_implied_resize = Qnil; | 6307 | frame_inhibit_implied_resize = Qnil; |
| 6206 | #endif | 6308 | #endif |
diff --git a/src/frame.h b/src/frame.h index fa45a32d6b6..1b21cc6284b 100644 --- a/src/frame.h +++ b/src/frame.h | |||
| @@ -181,6 +181,15 @@ struct frame | |||
| 181 | Lisp_Object menu_bar_window; | 181 | Lisp_Object menu_bar_window; |
| 182 | #endif | 182 | #endif |
| 183 | 183 | ||
| 184 | #if defined (HAVE_WINDOW_SYSTEM) | ||
| 185 | /* A window used to display the tab-bar of a frame. */ | ||
| 186 | Lisp_Object tab_bar_window; | ||
| 187 | |||
| 188 | /* Desired and current contents displayed in that window. */ | ||
| 189 | Lisp_Object desired_tab_bar_string; | ||
| 190 | Lisp_Object current_tab_bar_string; | ||
| 191 | #endif | ||
| 192 | |||
| 184 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) | 193 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) |
| 185 | /* A window used to display the tool-bar of a frame. */ | 194 | /* A window used to display the tool-bar of a frame. */ |
| 186 | Lisp_Object tool_bar_window; | 195 | Lisp_Object tool_bar_window; |
| @@ -201,6 +210,9 @@ struct frame | |||
| 201 | Lisp_Object font_data; | 210 | Lisp_Object font_data; |
| 202 | #endif | 211 | #endif |
| 203 | 212 | ||
| 213 | /* Desired and current tab-bar items. */ | ||
| 214 | Lisp_Object tab_bar_items; | ||
| 215 | |||
| 204 | /* Desired and current tool-bar items. */ | 216 | /* Desired and current tool-bar items. */ |
| 205 | Lisp_Object tool_bar_items; | 217 | Lisp_Object tool_bar_items; |
| 206 | /* tool_bar_items should be the last Lisp_Object member. */ | 218 | /* tool_bar_items should be the last Lisp_Object member. */ |
| @@ -208,6 +220,11 @@ struct frame | |||
| 208 | /* Cache of realized faces. */ | 220 | /* Cache of realized faces. */ |
| 209 | struct face_cache *face_cache; | 221 | struct face_cache *face_cache; |
| 210 | 222 | ||
| 223 | #if defined (HAVE_WINDOW_SYSTEM) | ||
| 224 | /* Tab-bar item index of the item on which a mouse button was pressed. */ | ||
| 225 | int last_tab_bar_item; | ||
| 226 | #endif | ||
| 227 | |||
| 211 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) | 228 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) |
| 212 | /* Tool-bar item index of the item on which a mouse button was pressed. */ | 229 | /* Tool-bar item index of the item on which a mouse button was pressed. */ |
| 213 | int last_tool_bar_item; | 230 | int last_tool_bar_item; |
| @@ -256,6 +273,12 @@ struct frame | |||
| 256 | /* Set to true when current redisplay has updated frame. */ | 273 | /* Set to true when current redisplay has updated frame. */ |
| 257 | bool_bf updated_p : 1; | 274 | bool_bf updated_p : 1; |
| 258 | 275 | ||
| 276 | #if defined (HAVE_WINDOW_SYSTEM) | ||
| 277 | /* Set to true to minimize tab-bar height even when | ||
| 278 | auto-resize-tab-bar is set to grow-only. */ | ||
| 279 | bool_bf minimize_tab_bar_window_p : 1; | ||
| 280 | #endif | ||
| 281 | |||
| 259 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) | 282 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) |
| 260 | /* Set to true to minimize tool-bar height even when | 283 | /* Set to true to minimize tool-bar height even when |
| 261 | auto-resize-tool-bar is set to grow-only. */ | 284 | auto-resize-tool-bar is set to grow-only. */ |
| @@ -404,6 +427,10 @@ struct frame | |||
| 404 | /* Set to true after this frame was made by `make-frame'. */ | 427 | /* Set to true after this frame was made by `make-frame'. */ |
| 405 | bool_bf after_make_frame : 1; | 428 | bool_bf after_make_frame : 1; |
| 406 | 429 | ||
| 430 | /* Whether the tab bar height change should be taken into account. */ | ||
| 431 | bool_bf tab_bar_redisplayed : 1; | ||
| 432 | bool_bf tab_bar_resized : 1; | ||
| 433 | |||
| 407 | /* Whether the tool bar height change should be taken into account. */ | 434 | /* Whether the tool bar height change should be taken into account. */ |
| 408 | bool_bf tool_bar_redisplayed : 1; | 435 | bool_bf tool_bar_redisplayed : 1; |
| 409 | bool_bf tool_bar_resized : 1; | 436 | bool_bf tool_bar_resized : 1; |
| @@ -435,6 +462,15 @@ struct frame | |||
| 435 | last time run_window_change_functions was called on it. */ | 462 | last time run_window_change_functions was called on it. */ |
| 436 | ptrdiff_t number_of_windows; | 463 | ptrdiff_t number_of_windows; |
| 437 | 464 | ||
| 465 | /* Number of lines (rounded up) of tab bar. REMOVE THIS */ | ||
| 466 | int tab_bar_lines; | ||
| 467 | |||
| 468 | /* Height of frame internal tab bar in pixels. */ | ||
| 469 | int tab_bar_height; | ||
| 470 | |||
| 471 | int n_tab_bar_rows; | ||
| 472 | int n_tab_bar_items; | ||
| 473 | |||
| 438 | /* Number of lines (rounded up) of tool bar. REMOVE THIS */ | 474 | /* Number of lines (rounded up) of tool bar. REMOVE THIS */ |
| 439 | int tool_bar_lines; | 475 | int tool_bar_lines; |
| 440 | 476 | ||
| @@ -701,6 +737,28 @@ fset_title (struct frame *f, Lisp_Object val) | |||
| 701 | f->title = val; | 737 | f->title = val; |
| 702 | } | 738 | } |
| 703 | INLINE void | 739 | INLINE void |
| 740 | fset_tab_bar_items (struct frame *f, Lisp_Object val) | ||
| 741 | { | ||
| 742 | f->tab_bar_items = val; | ||
| 743 | } | ||
| 744 | #if defined (HAVE_WINDOW_SYSTEM) | ||
| 745 | INLINE void | ||
| 746 | fset_tab_bar_window (struct frame *f, Lisp_Object val) | ||
| 747 | { | ||
| 748 | f->tab_bar_window = val; | ||
| 749 | } | ||
| 750 | INLINE void | ||
| 751 | fset_current_tab_bar_string (struct frame *f, Lisp_Object val) | ||
| 752 | { | ||
| 753 | f->current_tab_bar_string = val; | ||
| 754 | } | ||
| 755 | INLINE void | ||
| 756 | fset_desired_tab_bar_string (struct frame *f, Lisp_Object val) | ||
| 757 | { | ||
| 758 | f->desired_tab_bar_string = val; | ||
| 759 | } | ||
| 760 | #endif /* HAVE_WINDOW_SYSTEM */ | ||
| 761 | INLINE void | ||
| 704 | fset_tool_bar_items (struct frame *f, Lisp_Object val) | 762 | fset_tool_bar_items (struct frame *f, Lisp_Object val) |
| 705 | { | 763 | { |
| 706 | f->tool_bar_items = val; | 764 | f->tool_bar_items = val; |
| @@ -878,6 +936,12 @@ default_pixels_per_inch_y (void) | |||
| 878 | /* Pixel height of frame F's menu bar. */ | 936 | /* Pixel height of frame F's menu bar. */ |
| 879 | #define FRAME_MENU_BAR_HEIGHT(f) (f)->menu_bar_height | 937 | #define FRAME_MENU_BAR_HEIGHT(f) (f)->menu_bar_height |
| 880 | 938 | ||
| 939 | /* Number of lines of frame F used for the tab-bar. */ | ||
| 940 | #define FRAME_TAB_BAR_LINES(f) (f)->tab_bar_lines | ||
| 941 | |||
| 942 | /* Pixel height of frame F's tab-bar. */ | ||
| 943 | #define FRAME_TAB_BAR_HEIGHT(f) (f)->tab_bar_height | ||
| 944 | |||
| 881 | /* True if this frame should display a tool bar | 945 | /* True if this frame should display a tool bar |
| 882 | in a way that does not use any text lines. */ | 946 | in a way that does not use any text lines. */ |
| 883 | #ifdef HAVE_EXT_TOOL_BAR | 947 | #ifdef HAVE_EXT_TOOL_BAR |
| @@ -901,11 +965,11 @@ default_pixels_per_inch_y (void) | |||
| 901 | 965 | ||
| 902 | /* Lines above the top-most window in frame F. */ | 966 | /* Lines above the top-most window in frame F. */ |
| 903 | #define FRAME_TOP_MARGIN(F) \ | 967 | #define FRAME_TOP_MARGIN(F) \ |
| 904 | (FRAME_MENU_BAR_LINES (F) + FRAME_TOOL_BAR_LINES (F)) | 968 | (FRAME_MENU_BAR_LINES (F) + FRAME_TAB_BAR_LINES (F) + FRAME_TOOL_BAR_LINES (F)) |
| 905 | 969 | ||
| 906 | /* Pixel height of frame F's top margin. */ | 970 | /* Pixel height of frame F's top margin. */ |
| 907 | #define FRAME_TOP_MARGIN_HEIGHT(F) \ | 971 | #define FRAME_TOP_MARGIN_HEIGHT(F) \ |
| 908 | (FRAME_MENU_BAR_HEIGHT (F) + FRAME_TOOL_BAR_HEIGHT (F)) | 972 | (FRAME_MENU_BAR_HEIGHT (F) + FRAME_TAB_BAR_HEIGHT (F) + FRAME_TOOL_BAR_HEIGHT (F)) |
| 909 | 973 | ||
| 910 | /* True if this frame should display a menu bar | 974 | /* True if this frame should display a menu bar |
| 911 | in a way that does not use any text lines. */ | 975 | in a way that does not use any text lines. */ |
| @@ -1255,6 +1319,8 @@ SET_FRAME_VISIBLE (struct frame *f, int v) | |||
| 1255 | extern Lisp_Object selected_frame; | 1319 | extern Lisp_Object selected_frame; |
| 1256 | extern Lisp_Object old_selected_frame; | 1320 | extern Lisp_Object old_selected_frame; |
| 1257 | 1321 | ||
| 1322 | extern int frame_default_tab_bar_height; | ||
| 1323 | |||
| 1258 | #ifndef HAVE_EXT_TOOL_BAR | 1324 | #ifndef HAVE_EXT_TOOL_BAR |
| 1259 | extern int frame_default_tool_bar_height; | 1325 | extern int frame_default_tool_bar_height; |
| 1260 | #endif | 1326 | #endif |
| @@ -1566,7 +1632,7 @@ extern void gui_set_horizontal_scroll_bars (struct frame *, Lisp_Object, Lisp_Ob | |||
| 1566 | extern void gui_set_scroll_bar_width (struct frame *, Lisp_Object, Lisp_Object); | 1632 | extern void gui_set_scroll_bar_width (struct frame *, Lisp_Object, Lisp_Object); |
| 1567 | extern void gui_set_scroll_bar_height (struct frame *, Lisp_Object, Lisp_Object); | 1633 | extern void gui_set_scroll_bar_height (struct frame *, Lisp_Object, Lisp_Object); |
| 1568 | 1634 | ||
| 1569 | extern long gui_figure_window_size (struct frame *, Lisp_Object, bool, int *, int *); | 1635 | extern long gui_figure_window_size (struct frame *, Lisp_Object, bool, bool, int *, int *); |
| 1570 | 1636 | ||
| 1571 | extern void gui_set_alpha (struct frame *, Lisp_Object, Lisp_Object); | 1637 | extern void gui_set_alpha (struct frame *, Lisp_Object, Lisp_Object); |
| 1572 | extern void gui_set_no_special_glyphs (struct frame *, Lisp_Object, Lisp_Object); | 1638 | extern void gui_set_no_special_glyphs (struct frame *, Lisp_Object, Lisp_Object); |
diff --git a/src/fringe.c b/src/fringe.c index 4c5a4d748fb..22f3bdc2ba8 100644 --- a/src/fringe.c +++ b/src/fringe.c | |||
| @@ -634,7 +634,8 @@ draw_fringe_bitmap_1 (struct window *w, struct glyph_row *row, int left_p, int o | |||
| 634 | /* Clear left fringe if no bitmap to draw or if bitmap doesn't fill | 634 | /* Clear left fringe if no bitmap to draw or if bitmap doesn't fill |
| 635 | the fringe. */ | 635 | the fringe. */ |
| 636 | p.bx = -1; | 636 | p.bx = -1; |
| 637 | header_line_height = WINDOW_HEADER_LINE_HEIGHT (w); | 637 | header_line_height = WINDOW_TAB_LINE_HEIGHT (w) |
| 638 | + WINDOW_HEADER_LINE_HEIGHT (w); | ||
| 638 | p.by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, row->y)); | 639 | p.by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, row->y)); |
| 639 | p.ny = row->visible_height; | 640 | p.ny = row->visible_height; |
| 640 | if (left_p) | 641 | if (left_p) |
| @@ -1091,7 +1092,8 @@ update_window_fringes (struct window *w, bool keep_current_p) | |||
| 1091 | struct glyph_row *row1; | 1092 | struct glyph_row *row1; |
| 1092 | int top_ind_max_y; | 1093 | int top_ind_max_y; |
| 1093 | 1094 | ||
| 1094 | top_ind_min_y = WINDOW_HEADER_LINE_HEIGHT (w); | 1095 | top_ind_min_y = WINDOW_TAB_LINE_HEIGHT (w) |
| 1096 | + WINDOW_HEADER_LINE_HEIGHT (w); | ||
| 1095 | top_ind_max_y = top_ind_min_y + fb->height; | 1097 | top_ind_max_y = top_ind_min_y + fb->height; |
| 1096 | if (top_ind_max_y > yb) | 1098 | if (top_ind_max_y > yb) |
| 1097 | top_ind_max_y = yb; | 1099 | top_ind_max_y = yb; |
| @@ -1148,8 +1150,10 @@ update_window_fringes (struct window *w, bool keep_current_p) | |||
| 1148 | 1150 | ||
| 1149 | bot_ind_max_y = row->y + row->visible_height; | 1151 | bot_ind_max_y = row->y + row->visible_height; |
| 1150 | bot_ind_min_y = bot_ind_max_y - fb->height; | 1152 | bot_ind_min_y = bot_ind_max_y - fb->height; |
| 1151 | if (bot_ind_min_y < WINDOW_HEADER_LINE_HEIGHT (w)) | 1153 | if (bot_ind_min_y < WINDOW_TAB_LINE_HEIGHT (w) |
| 1152 | bot_ind_min_y = WINDOW_HEADER_LINE_HEIGHT (w); | 1154 | + WINDOW_HEADER_LINE_HEIGHT (w)) |
| 1155 | bot_ind_min_y = WINDOW_TAB_LINE_HEIGHT (w) | ||
| 1156 | + WINDOW_HEADER_LINE_HEIGHT (w); | ||
| 1153 | 1157 | ||
| 1154 | for (y = row->y, rn = bot_ind_rn - 1; | 1158 | for (y = row->y, rn = bot_ind_rn - 1; |
| 1155 | y >= bot_ind_min_y && rn >= 0; | 1159 | y >= bot_ind_min_y && rn >= 0; |
diff --git a/src/keyboard.c b/src/keyboard.c index a16d13cc7b8..40aaf496384 100644 --- a/src/keyboard.c +++ b/src/keyboard.c | |||
| @@ -2385,7 +2385,8 @@ read_char (int commandflag, Lisp_Object map, | |||
| 2385 | if (used_mouse_menu | 2385 | if (used_mouse_menu |
| 2386 | /* Also check was_disabled so last-nonmenu-event won't return | 2386 | /* Also check was_disabled so last-nonmenu-event won't return |
| 2387 | a bad value when submenus are involved. (Bug#447) */ | 2387 | a bad value when submenus are involved. (Bug#447) */ |
| 2388 | && (EQ (c, Qtool_bar) || EQ (c, Qmenu_bar) || was_disabled)) | 2388 | && (EQ (c, Qtool_bar) || EQ (c, Qtab_bar) || EQ (c, Qmenu_bar) |
| 2389 | || was_disabled)) | ||
| 2389 | *used_mouse_menu = true; | 2390 | *used_mouse_menu = true; |
| 2390 | 2391 | ||
| 2391 | goto reread_for_input_method; | 2392 | goto reread_for_input_method; |
| @@ -2666,6 +2667,7 @@ read_char (int commandflag, Lisp_Object map, | |||
| 2666 | && !NILP (prev_event) | 2667 | && !NILP (prev_event) |
| 2667 | && EVENT_HAS_PARAMETERS (prev_event) | 2668 | && EVENT_HAS_PARAMETERS (prev_event) |
| 2668 | && !EQ (XCAR (prev_event), Qmenu_bar) | 2669 | && !EQ (XCAR (prev_event), Qmenu_bar) |
| 2670 | && !EQ (XCAR (prev_event), Qtab_bar) | ||
| 2669 | && !EQ (XCAR (prev_event), Qtool_bar) | 2671 | && !EQ (XCAR (prev_event), Qtool_bar) |
| 2670 | /* Don't bring up a menu if we already have another event. */ | 2672 | /* Don't bring up a menu if we already have another event. */ |
| 2671 | && !CONSP (Vunread_command_events)) | 2673 | && !CONSP (Vunread_command_events)) |
| @@ -2930,7 +2932,7 @@ read_char (int commandflag, Lisp_Object map, | |||
| 2930 | posn = POSN_POSN (xevent_start (c)); | 2932 | posn = POSN_POSN (xevent_start (c)); |
| 2931 | /* Handle menu-bar events: | 2933 | /* Handle menu-bar events: |
| 2932 | insert the dummy prefix event `menu-bar'. */ | 2934 | insert the dummy prefix event `menu-bar'. */ |
| 2933 | if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar)) | 2935 | if (EQ (posn, Qmenu_bar) || EQ (posn, Qtab_bar) || EQ (posn, Qtool_bar)) |
| 2934 | { | 2936 | { |
| 2935 | /* Change menu-bar to (menu-bar) as the event "position". */ | 2937 | /* Change menu-bar to (menu-bar) as the event "position". */ |
| 2936 | POSN_SET_POSN (xevent_start (c), list1 (posn)); | 2938 | POSN_SET_POSN (xevent_start (c), list1 (posn)); |
| @@ -3974,6 +3976,7 @@ kbd_buffer_get_event (KBOARD **kbp, | |||
| 3974 | if (used_mouse_menu | 3976 | if (used_mouse_menu |
| 3975 | && !EQ (event->ie.frame_or_window, event->ie.arg) | 3977 | && !EQ (event->ie.frame_or_window, event->ie.arg) |
| 3976 | && (event->kind == MENU_BAR_EVENT | 3978 | && (event->kind == MENU_BAR_EVENT |
| 3979 | || event->kind == TAB_BAR_EVENT | ||
| 3977 | || event->kind == TOOL_BAR_EVENT)) | 3980 | || event->kind == TOOL_BAR_EVENT)) |
| 3978 | *used_mouse_menu = true; | 3981 | *used_mouse_menu = true; |
| 3979 | #endif | 3982 | #endif |
| @@ -5012,7 +5015,7 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y, | |||
| 5012 | int xret = 0, yret = 0; | 5015 | int xret = 0, yret = 0; |
| 5013 | /* The window or frame under frame pixel coordinates (x,y) */ | 5016 | /* The window or frame under frame pixel coordinates (x,y) */ |
| 5014 | Lisp_Object window_or_frame = f | 5017 | Lisp_Object window_or_frame = f |
| 5015 | ? window_from_coordinates (f, XFIXNUM (x), XFIXNUM (y), &part, 0) | 5018 | ? window_from_coordinates (f, XFIXNUM (x), XFIXNUM (y), &part, 0, 0) |
| 5016 | : Qnil; | 5019 | : Qnil; |
| 5017 | 5020 | ||
| 5018 | if (WINDOWP (window_or_frame)) | 5021 | if (WINDOWP (window_or_frame)) |
| @@ -5036,17 +5039,21 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y, | |||
| 5036 | if (part == ON_TEXT) | 5039 | if (part == ON_TEXT) |
| 5037 | { | 5040 | { |
| 5038 | xret = XFIXNUM (x) - window_box_left (w, TEXT_AREA); | 5041 | xret = XFIXNUM (x) - window_box_left (w, TEXT_AREA); |
| 5039 | yret = wy - WINDOW_HEADER_LINE_HEIGHT (w); | 5042 | yret = wy - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w); |
| 5040 | } | 5043 | } |
| 5041 | /* For mode line and header line clicks, return X, Y relative to | 5044 | /* For mode line and header line clicks, return X, Y relative to |
| 5042 | the left window edge. Use mode_line_string to look for a | 5045 | the left window edge. Use mode_line_string to look for a |
| 5043 | string on the click position. */ | 5046 | string on the click position. */ |
| 5044 | else if (part == ON_MODE_LINE || part == ON_HEADER_LINE) | 5047 | else if (part == ON_MODE_LINE || part == ON_TAB_LINE |
| 5048 | || part == ON_HEADER_LINE) | ||
| 5045 | { | 5049 | { |
| 5046 | Lisp_Object string; | 5050 | Lisp_Object string; |
| 5047 | ptrdiff_t charpos; | 5051 | ptrdiff_t charpos; |
| 5048 | 5052 | ||
| 5049 | posn = (part == ON_MODE_LINE) ? Qmode_line : Qheader_line; | 5053 | posn = (part == ON_MODE_LINE ? Qmode_line |
| 5054 | : (part == ON_TAB_LINE ? Qtab_line | ||
| 5055 | : Qheader_line)); | ||
| 5056 | |||
| 5050 | /* Note that mode_line_string takes COL, ROW as pixels and | 5057 | /* Note that mode_line_string takes COL, ROW as pixels and |
| 5051 | converts them to characters. */ | 5058 | converts them to characters. */ |
| 5052 | col = wx; | 5059 | col = wx; |
| @@ -5075,7 +5082,7 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y, | |||
| 5075 | if (STRINGP (string)) | 5082 | if (STRINGP (string)) |
| 5076 | string_info = Fcons (string, make_fixnum (charpos)); | 5083 | string_info = Fcons (string, make_fixnum (charpos)); |
| 5077 | xret = wx; | 5084 | xret = wx; |
| 5078 | yret = wy - WINDOW_HEADER_LINE_HEIGHT (w); | 5085 | yret = wy - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w); |
| 5079 | } | 5086 | } |
| 5080 | else if (part == ON_LEFT_FRINGE) | 5087 | else if (part == ON_LEFT_FRINGE) |
| 5081 | { | 5088 | { |
| @@ -5085,7 +5092,7 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y, | |||
| 5085 | dx = wx | 5092 | dx = wx |
| 5086 | - (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) | 5093 | - (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) |
| 5087 | ? 0 : window_box_width (w, LEFT_MARGIN_AREA)); | 5094 | ? 0 : window_box_width (w, LEFT_MARGIN_AREA)); |
| 5088 | dy = yret = wy - WINDOW_HEADER_LINE_HEIGHT (w); | 5095 | dy = yret = wy - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w); |
| 5089 | } | 5096 | } |
| 5090 | else if (part == ON_RIGHT_FRINGE) | 5097 | else if (part == ON_RIGHT_FRINGE) |
| 5091 | { | 5098 | { |
| @@ -5098,7 +5105,7 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y, | |||
| 5098 | - (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) | 5105 | - (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) |
| 5099 | ? window_box_width (w, RIGHT_MARGIN_AREA) | 5106 | ? window_box_width (w, RIGHT_MARGIN_AREA) |
| 5100 | : 0); | 5107 | : 0); |
| 5101 | dy = yret = wy - WINDOW_HEADER_LINE_HEIGHT (w); | 5108 | dy = yret = wy - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w); |
| 5102 | } | 5109 | } |
| 5103 | else if (part == ON_VERTICAL_BORDER) | 5110 | else if (part == ON_VERTICAL_BORDER) |
| 5104 | { | 5111 | { |
| @@ -5953,6 +5960,16 @@ make_lispy_event (struct input_event *event) | |||
| 5953 | /* Make an event (select-window (WINDOW)). */ | 5960 | /* Make an event (select-window (WINDOW)). */ |
| 5954 | return list2 (Qselect_window, list1 (event->frame_or_window)); | 5961 | return list2 (Qselect_window, list1 (event->frame_or_window)); |
| 5955 | 5962 | ||
| 5963 | case TAB_BAR_EVENT: | ||
| 5964 | if (EQ (event->arg, event->frame_or_window)) | ||
| 5965 | /* This is the prefix key. We translate this to | ||
| 5966 | `(tab_bar)' because the code in keyboard.c for tab bar | ||
| 5967 | events, which we use, relies on this. */ | ||
| 5968 | return list1 (Qtab_bar); | ||
| 5969 | else if (SYMBOLP (event->arg)) | ||
| 5970 | return apply_modifiers (event->modifiers, event->arg); | ||
| 5971 | return event->arg; | ||
| 5972 | |||
| 5956 | case TOOL_BAR_EVENT: | 5973 | case TOOL_BAR_EVENT: |
| 5957 | if (EQ (event->arg, event->frame_or_window)) | 5974 | if (EQ (event->arg, event->frame_or_window)) |
| 5958 | /* This is the prefix key. We translate this to | 5975 | /* This is the prefix key. We translate this to |
| @@ -6730,6 +6747,7 @@ lucid_event_type_list_p (Lisp_Object object) | |||
| 6730 | if (EQ (XCAR (object), Qhelp_echo) | 6747 | if (EQ (XCAR (object), Qhelp_echo) |
| 6731 | || EQ (XCAR (object), Qvertical_line) | 6748 | || EQ (XCAR (object), Qvertical_line) |
| 6732 | || EQ (XCAR (object), Qmode_line) | 6749 | || EQ (XCAR (object), Qmode_line) |
| 6750 | || EQ (XCAR (object), Qtab_line) | ||
| 6733 | || EQ (XCAR (object), Qheader_line)) | 6751 | || EQ (XCAR (object), Qheader_line)) |
| 6734 | return 0; | 6752 | return 0; |
| 6735 | 6753 | ||
| @@ -7891,6 +7909,389 @@ parse_menu_item (Lisp_Object item, int inmenubar) | |||
| 7891 | 7909 | ||
| 7892 | 7910 | ||
| 7893 | /*********************************************************************** | 7911 | /*********************************************************************** |
| 7912 | Tab-bars | ||
| 7913 | ***********************************************************************/ | ||
| 7914 | |||
| 7915 | /* A vector holding tab bar items while they are parsed in function | ||
| 7916 | tab_bar_items. Each item occupies TAB_BAR_ITEM_NSCLOTS elements | ||
| 7917 | in the vector. */ | ||
| 7918 | |||
| 7919 | static Lisp_Object tab_bar_items_vector; | ||
| 7920 | |||
| 7921 | /* A vector holding the result of parse_tab_bar_item. Layout is like | ||
| 7922 | the one for a single item in tab_bar_items_vector. */ | ||
| 7923 | |||
| 7924 | static Lisp_Object tab_bar_item_properties; | ||
| 7925 | |||
| 7926 | /* Next free index in tab_bar_items_vector. */ | ||
| 7927 | |||
| 7928 | static int ntab_bar_items; | ||
| 7929 | |||
| 7930 | /* Function prototypes. */ | ||
| 7931 | |||
| 7932 | static void init_tab_bar_items (Lisp_Object); | ||
| 7933 | static void process_tab_bar_item (Lisp_Object, Lisp_Object, Lisp_Object, | ||
| 7934 | void *); | ||
| 7935 | static bool parse_tab_bar_item (Lisp_Object, Lisp_Object); | ||
| 7936 | static void append_tab_bar_item (void); | ||
| 7937 | |||
| 7938 | |||
| 7939 | /* Return a vector of tab bar items for keymaps currently in effect. | ||
| 7940 | Reuse vector REUSE if non-nil. Return in *NITEMS the number of | ||
| 7941 | tab bar items found. */ | ||
| 7942 | |||
| 7943 | Lisp_Object | ||
| 7944 | tab_bar_items (Lisp_Object reuse, int *nitems) | ||
| 7945 | { | ||
| 7946 | Lisp_Object *maps; | ||
| 7947 | Lisp_Object mapsbuf[3]; | ||
| 7948 | ptrdiff_t nmaps, i; | ||
| 7949 | Lisp_Object oquit; | ||
| 7950 | Lisp_Object *tmaps; | ||
| 7951 | USE_SAFE_ALLOCA; | ||
| 7952 | |||
| 7953 | *nitems = 0; | ||
| 7954 | |||
| 7955 | /* In order to build the menus, we need to call the keymap | ||
| 7956 | accessors. They all call maybe_quit. But this function is called | ||
| 7957 | during redisplay, during which a quit is fatal. So inhibit | ||
| 7958 | quitting while building the menus. We do this instead of | ||
| 7959 | specbind because (1) errors will clear it anyway and (2) this | ||
| 7960 | avoids risk of specpdl overflow. */ | ||
| 7961 | oquit = Vinhibit_quit; | ||
| 7962 | Vinhibit_quit = Qt; | ||
| 7963 | |||
| 7964 | /* Initialize tab_bar_items_vector and protect it from GC. */ | ||
| 7965 | init_tab_bar_items (reuse); | ||
| 7966 | |||
| 7967 | /* Build list of keymaps in maps. Set nmaps to the number of maps | ||
| 7968 | to process. */ | ||
| 7969 | |||
| 7970 | /* Should overriding-terminal-local-map and overriding-local-map apply? */ | ||
| 7971 | if (!NILP (Voverriding_local_map_menu_flag) | ||
| 7972 | && !NILP (Voverriding_local_map)) | ||
| 7973 | { | ||
| 7974 | /* Yes, use them (if non-nil) as well as the global map. */ | ||
| 7975 | maps = mapsbuf; | ||
| 7976 | nmaps = 0; | ||
| 7977 | if (!NILP (KVAR (current_kboard, Voverriding_terminal_local_map))) | ||
| 7978 | maps[nmaps++] = KVAR (current_kboard, Voverriding_terminal_local_map); | ||
| 7979 | if (!NILP (Voverriding_local_map)) | ||
| 7980 | maps[nmaps++] = Voverriding_local_map; | ||
| 7981 | } | ||
| 7982 | else | ||
| 7983 | { | ||
| 7984 | /* No, so use major and minor mode keymaps and keymap property. | ||
| 7985 | Note that tab-bar bindings in the local-map and keymap | ||
| 7986 | properties may not work reliably, as they are only | ||
| 7987 | recognized when the tab-bar (or mode-line) is updated, | ||
| 7988 | which does not normally happen after every command. */ | ||
| 7989 | ptrdiff_t nminor = current_minor_maps (NULL, &tmaps); | ||
| 7990 | SAFE_NALLOCA (maps, 1, nminor + 4); | ||
| 7991 | nmaps = 0; | ||
| 7992 | Lisp_Object tem = KVAR (current_kboard, Voverriding_terminal_local_map); | ||
| 7993 | if (!NILP (tem) && !NILP (Voverriding_local_map_menu_flag)) | ||
| 7994 | maps[nmaps++] = tem; | ||
| 7995 | if (tem = get_local_map (PT, current_buffer, Qkeymap), !NILP (tem)) | ||
| 7996 | maps[nmaps++] = tem; | ||
| 7997 | if (nminor != 0) | ||
| 7998 | { | ||
| 7999 | memcpy (maps + nmaps, tmaps, nminor * sizeof (maps[0])); | ||
| 8000 | nmaps += nminor; | ||
| 8001 | } | ||
| 8002 | maps[nmaps++] = get_local_map (PT, current_buffer, Qlocal_map); | ||
| 8003 | } | ||
| 8004 | |||
| 8005 | /* Add global keymap at the end. */ | ||
| 8006 | maps[nmaps++] = current_global_map; | ||
| 8007 | |||
| 8008 | /* Process maps in reverse order and look up in each map the prefix | ||
| 8009 | key `tab-bar'. */ | ||
| 8010 | for (i = nmaps - 1; i >= 0; --i) | ||
| 8011 | if (!NILP (maps[i])) | ||
| 8012 | { | ||
| 8013 | Lisp_Object keymap; | ||
| 8014 | |||
| 8015 | keymap = get_keymap (access_keymap (maps[i], Qtab_bar, 1, 0, 1), 0, 1); | ||
| 8016 | if (CONSP (keymap)) | ||
| 8017 | map_keymap (keymap, process_tab_bar_item, Qnil, NULL, 1); | ||
| 8018 | } | ||
| 8019 | |||
| 8020 | Vinhibit_quit = oquit; | ||
| 8021 | *nitems = ntab_bar_items / TAB_BAR_ITEM_NSLOTS; | ||
| 8022 | SAFE_FREE (); | ||
| 8023 | return tab_bar_items_vector; | ||
| 8024 | } | ||
| 8025 | |||
| 8026 | |||
| 8027 | /* Process the definition of KEY which is DEF. */ | ||
| 8028 | |||
| 8029 | static void | ||
| 8030 | process_tab_bar_item (Lisp_Object key, Lisp_Object def, Lisp_Object data, void *args) | ||
| 8031 | { | ||
| 8032 | int i; | ||
| 8033 | |||
| 8034 | if (EQ (def, Qundefined)) | ||
| 8035 | { | ||
| 8036 | /* If a map has an explicit `undefined' as definition, | ||
| 8037 | discard any previously made item. */ | ||
| 8038 | for (i = 0; i < ntab_bar_items; i += TAB_BAR_ITEM_NSLOTS) | ||
| 8039 | { | ||
| 8040 | Lisp_Object *v = XVECTOR (tab_bar_items_vector)->contents + i; | ||
| 8041 | |||
| 8042 | if (EQ (key, v[TAB_BAR_ITEM_KEY])) | ||
| 8043 | { | ||
| 8044 | if (ntab_bar_items > i + TAB_BAR_ITEM_NSLOTS) | ||
| 8045 | memmove (v, v + TAB_BAR_ITEM_NSLOTS, | ||
| 8046 | ((ntab_bar_items - i - TAB_BAR_ITEM_NSLOTS) | ||
| 8047 | * word_size)); | ||
| 8048 | ntab_bar_items -= TAB_BAR_ITEM_NSLOTS; | ||
| 8049 | break; | ||
| 8050 | } | ||
| 8051 | } | ||
| 8052 | } | ||
| 8053 | else if (parse_tab_bar_item (key, def)) | ||
| 8054 | /* Append a new tab bar item to tab_bar_items_vector. Accept | ||
| 8055 | more than one definition for the same key. */ | ||
| 8056 | append_tab_bar_item (); | ||
| 8057 | } | ||
| 8058 | |||
| 8059 | /* Access slot with index IDX of vector tab_bar_item_properties. */ | ||
| 8060 | #define PROP(IDX) AREF (tab_bar_item_properties, (IDX)) | ||
| 8061 | static void | ||
| 8062 | set_prop_tab_bar (ptrdiff_t idx, Lisp_Object val) | ||
| 8063 | { | ||
| 8064 | ASET (tab_bar_item_properties, idx, val); | ||
| 8065 | } | ||
| 8066 | |||
| 8067 | |||
| 8068 | /* Parse a tab bar item specification ITEM for key KEY and return the | ||
| 8069 | result in tab_bar_item_properties. Value is false if ITEM is | ||
| 8070 | invalid. | ||
| 8071 | |||
| 8072 | ITEM is a list `(menu-item CAPTION BINDING PROPS...)'. | ||
| 8073 | |||
| 8074 | CAPTION is the caption of the item, If it's not a string, it is | ||
| 8075 | evaluated to get a string. | ||
| 8076 | |||
| 8077 | BINDING is the tab bar item's binding. Tab-bar items with keymaps | ||
| 8078 | as binding are currently ignored. | ||
| 8079 | |||
| 8080 | The following properties are recognized: | ||
| 8081 | |||
| 8082 | - `:enable FORM'. | ||
| 8083 | |||
| 8084 | FORM is evaluated and specifies whether the tab bar item is | ||
| 8085 | enabled or disabled. | ||
| 8086 | |||
| 8087 | - `:visible FORM' | ||
| 8088 | |||
| 8089 | FORM is evaluated and specifies whether the tab bar item is visible. | ||
| 8090 | |||
| 8091 | - `:filter FUNCTION' | ||
| 8092 | |||
| 8093 | FUNCTION is invoked with one parameter `(quote BINDING)'. Its | ||
| 8094 | result is stored as the new binding. | ||
| 8095 | |||
| 8096 | - `:button (TYPE SELECTED)' | ||
| 8097 | |||
| 8098 | TYPE must be one of `:radio' or `:toggle'. SELECTED is evaluated | ||
| 8099 | and specifies whether the button is selected (pressed) or not. | ||
| 8100 | |||
| 8101 | - `:image IMAGES' | ||
| 8102 | |||
| 8103 | IMAGES is either a single image specification or a vector of four | ||
| 8104 | image specifications. See enum tab_bar_item_images. | ||
| 8105 | |||
| 8106 | - `:help HELP-STRING'. | ||
| 8107 | |||
| 8108 | Gives a help string to display for the tab bar item. | ||
| 8109 | |||
| 8110 | - `:label LABEL-STRING'. | ||
| 8111 | |||
| 8112 | A text label to show with the tab bar button if labels are enabled. */ | ||
| 8113 | |||
| 8114 | static bool | ||
| 8115 | parse_tab_bar_item (Lisp_Object key, Lisp_Object item) | ||
| 8116 | { | ||
| 8117 | Lisp_Object filter = Qnil; | ||
| 8118 | Lisp_Object caption; | ||
| 8119 | int i; | ||
| 8120 | |||
| 8121 | /* Definition looks like `(menu-item CAPTION BINDING PROPS...)'. | ||
| 8122 | Rule out items that aren't lists, don't start with | ||
| 8123 | `menu-item' or whose rest following `tab-bar-item' is not a | ||
| 8124 | list. */ | ||
| 8125 | if (!CONSP (item)) | ||
| 8126 | return 0; | ||
| 8127 | |||
| 8128 | /* As an exception, allow old-style menu separators. */ | ||
| 8129 | if (STRINGP (XCAR (item))) | ||
| 8130 | item = list1 (XCAR (item)); | ||
| 8131 | else if (!EQ (XCAR (item), Qmenu_item) | ||
| 8132 | || (item = XCDR (item), !CONSP (item))) | ||
| 8133 | return 0; | ||
| 8134 | |||
| 8135 | /* Create tab_bar_item_properties vector if necessary. Reset it to | ||
| 8136 | defaults. */ | ||
| 8137 | if (VECTORP (tab_bar_item_properties)) | ||
| 8138 | { | ||
| 8139 | for (i = 0; i < TAB_BAR_ITEM_NSLOTS; ++i) | ||
| 8140 | set_prop_tab_bar (i, Qnil); | ||
| 8141 | } | ||
| 8142 | else | ||
| 8143 | tab_bar_item_properties = make_nil_vector (TAB_BAR_ITEM_NSLOTS); | ||
| 8144 | |||
| 8145 | /* Set defaults. */ | ||
| 8146 | set_prop_tab_bar (TAB_BAR_ITEM_KEY, key); | ||
| 8147 | set_prop_tab_bar (TAB_BAR_ITEM_ENABLED_P, Qt); | ||
| 8148 | |||
| 8149 | /* Get the caption of the item. If the caption is not a string, | ||
| 8150 | evaluate it to get a string. If we don't get a string, skip this | ||
| 8151 | item. */ | ||
| 8152 | caption = XCAR (item); | ||
| 8153 | if (!STRINGP (caption)) | ||
| 8154 | { | ||
| 8155 | caption = menu_item_eval_property (caption); | ||
| 8156 | if (!STRINGP (caption)) | ||
| 8157 | return 0; | ||
| 8158 | } | ||
| 8159 | set_prop_tab_bar (TAB_BAR_ITEM_CAPTION, caption); | ||
| 8160 | |||
| 8161 | /* If the rest following the caption is not a list, the menu item is | ||
| 8162 | either a separator, or invalid. */ | ||
| 8163 | item = XCDR (item); | ||
| 8164 | if (!CONSP (item)) | ||
| 8165 | { | ||
| 8166 | if (menu_separator_name_p (SSDATA (caption))) | ||
| 8167 | { | ||
| 8168 | set_prop_tab_bar (TAB_BAR_ITEM_ENABLED_P, Qnil); | ||
| 8169 | set_prop_tab_bar (TAB_BAR_ITEM_SELECTED_P, Qnil); | ||
| 8170 | set_prop_tab_bar (TAB_BAR_ITEM_CAPTION, Qnil); | ||
| 8171 | return 1; | ||
| 8172 | } | ||
| 8173 | return 0; | ||
| 8174 | } | ||
| 8175 | |||
| 8176 | /* Store the binding. */ | ||
| 8177 | set_prop_tab_bar (TAB_BAR_ITEM_BINDING, XCAR (item)); | ||
| 8178 | item = XCDR (item); | ||
| 8179 | |||
| 8180 | /* Ignore cached key binding, if any. */ | ||
| 8181 | if (CONSP (item) && CONSP (XCAR (item))) | ||
| 8182 | item = XCDR (item); | ||
| 8183 | |||
| 8184 | /* Process the rest of the properties. */ | ||
| 8185 | for (; CONSP (item) && CONSP (XCDR (item)); item = XCDR (XCDR (item))) | ||
| 8186 | { | ||
| 8187 | Lisp_Object ikey, value; | ||
| 8188 | |||
| 8189 | ikey = XCAR (item); | ||
| 8190 | value = XCAR (XCDR (item)); | ||
| 8191 | |||
| 8192 | if (EQ (ikey, QCenable)) | ||
| 8193 | { | ||
| 8194 | /* `:enable FORM'. */ | ||
| 8195 | if (!NILP (Venable_disabled_menus_and_buttons)) | ||
| 8196 | set_prop_tab_bar (TAB_BAR_ITEM_ENABLED_P, Qt); | ||
| 8197 | else | ||
| 8198 | set_prop_tab_bar (TAB_BAR_ITEM_ENABLED_P, value); | ||
| 8199 | } | ||
| 8200 | else if (EQ (ikey, QCvisible)) | ||
| 8201 | { | ||
| 8202 | /* `:visible FORM'. If got a visible property and that | ||
| 8203 | evaluates to nil then ignore this item. */ | ||
| 8204 | if (NILP (menu_item_eval_property (value))) | ||
| 8205 | return 0; | ||
| 8206 | } | ||
| 8207 | else if (EQ (ikey, QChelp)) | ||
| 8208 | /* `:help HELP-STRING'. */ | ||
| 8209 | set_prop_tab_bar (TAB_BAR_ITEM_HELP, value); | ||
| 8210 | else if (EQ (ikey, QCfilter)) | ||
| 8211 | /* ':filter FORM'. */ | ||
| 8212 | filter = value; | ||
| 8213 | else if (EQ (ikey, QCbutton) && CONSP (value)) | ||
| 8214 | { | ||
| 8215 | /* `:button (TYPE . SELECTED)'. */ | ||
| 8216 | Lisp_Object type, selected; | ||
| 8217 | |||
| 8218 | type = XCAR (value); | ||
| 8219 | selected = XCDR (value); | ||
| 8220 | if (EQ (type, QCtoggle) || EQ (type, QCradio)) | ||
| 8221 | { | ||
| 8222 | set_prop_tab_bar (TAB_BAR_ITEM_SELECTED_P, selected); | ||
| 8223 | } | ||
| 8224 | } | ||
| 8225 | } | ||
| 8226 | |||
| 8227 | /* If got a filter apply it on binding. */ | ||
| 8228 | if (!NILP (filter)) | ||
| 8229 | set_prop_tab_bar (TAB_BAR_ITEM_BINDING, | ||
| 8230 | (menu_item_eval_property | ||
| 8231 | (list2 (filter, | ||
| 8232 | list2 (Qquote, | ||
| 8233 | PROP (TAB_BAR_ITEM_BINDING)))))); | ||
| 8234 | |||
| 8235 | /* See if the binding is a keymap. Give up if it is. */ | ||
| 8236 | if (CONSP (get_keymap (PROP (TAB_BAR_ITEM_BINDING), 0, 1))) | ||
| 8237 | return 0; | ||
| 8238 | |||
| 8239 | /* Enable or disable selection of item. */ | ||
| 8240 | if (!EQ (PROP (TAB_BAR_ITEM_ENABLED_P), Qt)) | ||
| 8241 | set_prop_tab_bar (TAB_BAR_ITEM_ENABLED_P, | ||
| 8242 | menu_item_eval_property (PROP (TAB_BAR_ITEM_ENABLED_P))); | ||
| 8243 | |||
| 8244 | /* Handle radio buttons or toggle boxes. */ | ||
| 8245 | if (!NILP (PROP (TAB_BAR_ITEM_SELECTED_P))) | ||
| 8246 | set_prop_tab_bar (TAB_BAR_ITEM_SELECTED_P, | ||
| 8247 | menu_item_eval_property (PROP (TAB_BAR_ITEM_SELECTED_P))); | ||
| 8248 | |||
| 8249 | return 1; | ||
| 8250 | |||
| 8251 | #undef PROP | ||
| 8252 | } | ||
| 8253 | |||
| 8254 | |||
| 8255 | /* Initialize tab_bar_items_vector. REUSE, if non-nil, is a vector | ||
| 8256 | that can be reused. */ | ||
| 8257 | |||
| 8258 | static void | ||
| 8259 | init_tab_bar_items (Lisp_Object reuse) | ||
| 8260 | { | ||
| 8261 | if (VECTORP (reuse)) | ||
| 8262 | tab_bar_items_vector = reuse; | ||
| 8263 | else | ||
| 8264 | tab_bar_items_vector = make_nil_vector (64); | ||
| 8265 | ntab_bar_items = 0; | ||
| 8266 | } | ||
| 8267 | |||
| 8268 | |||
| 8269 | /* Append parsed tab bar item properties from | ||
| 8270 | tab_bar_item_properties */ | ||
| 8271 | |||
| 8272 | static void | ||
| 8273 | append_tab_bar_item (void) | ||
| 8274 | { | ||
| 8275 | ptrdiff_t incr | ||
| 8276 | = (ntab_bar_items | ||
| 8277 | - (ASIZE (tab_bar_items_vector) - TAB_BAR_ITEM_NSLOTS)); | ||
| 8278 | |||
| 8279 | /* Enlarge tab_bar_items_vector if necessary. */ | ||
| 8280 | if (incr > 0) | ||
| 8281 | tab_bar_items_vector = larger_vector (tab_bar_items_vector, incr, -1); | ||
| 8282 | |||
| 8283 | /* Append entries from tab_bar_item_properties to the end of | ||
| 8284 | tab_bar_items_vector. */ | ||
| 8285 | vcopy (tab_bar_items_vector, ntab_bar_items, | ||
| 8286 | XVECTOR (tab_bar_item_properties)->contents, TAB_BAR_ITEM_NSLOTS); | ||
| 8287 | ntab_bar_items += TAB_BAR_ITEM_NSLOTS; | ||
| 8288 | } | ||
| 8289 | |||
| 8290 | |||
| 8291 | |||
| 8292 | |||
| 8293 | |||
| 8294 | /*********************************************************************** | ||
| 7894 | Tool-bars | 8295 | Tool-bars |
| 7895 | ***********************************************************************/ | 8296 | ***********************************************************************/ |
| 7896 | 8297 | ||
| @@ -8402,6 +8803,7 @@ read_char_x_menu_prompt (Lisp_Object map, | |||
| 8402 | use a real menu for mouse selection. */ | 8803 | use a real menu for mouse selection. */ |
| 8403 | if (EVENT_HAS_PARAMETERS (prev_event) | 8804 | if (EVENT_HAS_PARAMETERS (prev_event) |
| 8404 | && !EQ (XCAR (prev_event), Qmenu_bar) | 8805 | && !EQ (XCAR (prev_event), Qmenu_bar) |
| 8806 | && !EQ (XCAR (prev_event), Qtab_bar) | ||
| 8405 | && !EQ (XCAR (prev_event), Qtool_bar)) | 8807 | && !EQ (XCAR (prev_event), Qtool_bar)) |
| 8406 | { | 8808 | { |
| 8407 | /* Display the menu and get the selection. */ | 8809 | /* Display the menu and get the selection. */ |
| @@ -9377,7 +9779,7 @@ read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt, | |||
| 9377 | posn = POSN_POSN (xevent_start (key)); | 9779 | posn = POSN_POSN (xevent_start (key)); |
| 9378 | /* Handle menu-bar events: | 9780 | /* Handle menu-bar events: |
| 9379 | insert the dummy prefix event `menu-bar'. */ | 9781 | insert the dummy prefix event `menu-bar'. */ |
| 9380 | if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar)) | 9782 | if (EQ (posn, Qmenu_bar) || EQ (posn, Qtab_bar) || EQ (posn, Qtool_bar)) |
| 9381 | { | 9783 | { |
| 9382 | if (READ_KEY_ELTS - t <= 1) | 9784 | if (READ_KEY_ELTS - t <= 1) |
| 9383 | error ("Key sequence too long"); | 9785 | error ("Key sequence too long"); |
| @@ -10237,7 +10639,8 @@ On such systems, Emacs starts a subshell instead of suspending. */) | |||
| 10237 | get_tty_size (fileno (CURTTY ()->input), &width, &height); | 10639 | get_tty_size (fileno (CURTTY ()->input), &width, &height); |
| 10238 | if (width != old_width || height != old_height) | 10640 | if (width != old_width || height != old_height) |
| 10239 | change_frame_size (SELECTED_FRAME (), width, | 10641 | change_frame_size (SELECTED_FRAME (), width, |
| 10240 | height - FRAME_MENU_BAR_LINES (SELECTED_FRAME ()), | 10642 | height - FRAME_MENU_BAR_LINES (SELECTED_FRAME ()) |
| 10643 | - FRAME_TAB_BAR_LINES (SELECTED_FRAME ()), | ||
| 10241 | 0, 0, 0, 0); | 10644 | 0, 0, 0, 0); |
| 10242 | 10645 | ||
| 10243 | run_hook (intern ("suspend-resume-hook")); | 10646 | run_hook (intern ("suspend-resume-hook")); |
| @@ -11057,6 +11460,11 @@ syms_of_keyboard (void) | |||
| 11057 | staticpro (&item_properties); | 11460 | staticpro (&item_properties); |
| 11058 | item_properties = Qnil; | 11461 | item_properties = Qnil; |
| 11059 | 11462 | ||
| 11463 | staticpro (&tab_bar_item_properties); | ||
| 11464 | tab_bar_item_properties = Qnil; | ||
| 11465 | staticpro (&tab_bar_items_vector); | ||
| 11466 | tab_bar_items_vector = Qnil; | ||
| 11467 | |||
| 11060 | staticpro (&tool_bar_item_properties); | 11468 | staticpro (&tool_bar_item_properties); |
| 11061 | tool_bar_item_properties = Qnil; | 11469 | tool_bar_item_properties = Qnil; |
| 11062 | staticpro (&tool_bar_items_vector); | 11470 | staticpro (&tool_bar_items_vector); |
| @@ -11610,6 +12018,12 @@ See also `pre-command-hook'. */); | |||
| 11610 | The elements of the list are event types that may have menu bar bindings. */); | 12018 | The elements of the list are event types that may have menu bar bindings. */); |
| 11611 | Vmenu_bar_final_items = Qnil; | 12019 | Vmenu_bar_final_items = Qnil; |
| 11612 | 12020 | ||
| 12021 | DEFVAR_LISP ("tab-bar-separator-image-expression", Vtab_bar_separator_image_expression, | ||
| 12022 | doc: /* Expression evaluating to the image spec for a tab-bar separator. | ||
| 12023 | This is used internally by graphical displays that do not render | ||
| 12024 | tab-bar separators natively. Otherwise it is unused (e.g. on GTK). */); | ||
| 12025 | Vtab_bar_separator_image_expression = Qnil; | ||
| 12026 | |||
| 11613 | DEFVAR_LISP ("tool-bar-separator-image-expression", Vtool_bar_separator_image_expression, | 12027 | DEFVAR_LISP ("tool-bar-separator-image-expression", Vtool_bar_separator_image_expression, |
| 11614 | doc: /* Expression evaluating to the image spec for a tool-bar separator. | 12028 | doc: /* Expression evaluating to the image spec for a tool-bar separator. |
| 11615 | This is used internally by graphical displays that do not render | 12029 | This is used internally by graphical displays that do not render |
diff --git a/src/keymap.c b/src/keymap.c index b1e09a92f20..da2786c8449 100644 --- a/src/keymap.c +++ b/src/keymap.c | |||
| @@ -3663,7 +3663,8 @@ be preferred. */); | |||
| 3663 | DEFSYM (Qmode_line, "mode-line"); | 3663 | DEFSYM (Qmode_line, "mode-line"); |
| 3664 | 3664 | ||
| 3665 | staticpro (&Vmouse_events); | 3665 | staticpro (&Vmouse_events); |
| 3666 | Vmouse_events = pure_list (Qmenu_bar, Qtool_bar, Qheader_line, Qmode_line, | 3666 | Vmouse_events = pure_list (Qmenu_bar, Qtab_bar, Qtool_bar, |
| 3667 | Qtab_line, Qheader_line, Qmode_line, | ||
| 3667 | intern_c_string ("mouse-1"), | 3668 | intern_c_string ("mouse-1"), |
| 3668 | intern_c_string ("mouse-2"), | 3669 | intern_c_string ("mouse-2"), |
| 3669 | intern_c_string ("mouse-3"), | 3670 | intern_c_string ("mouse-3"), |
diff --git a/src/lisp.h b/src/lisp.h index bcb91b2decc..fe20add2d70 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -4391,6 +4391,7 @@ extern bool input_pending; | |||
| 4391 | extern sigjmp_buf return_to_command_loop; | 4391 | extern sigjmp_buf return_to_command_loop; |
| 4392 | #endif | 4392 | #endif |
| 4393 | extern Lisp_Object menu_bar_items (Lisp_Object); | 4393 | extern Lisp_Object menu_bar_items (Lisp_Object); |
| 4394 | extern Lisp_Object tab_bar_items (Lisp_Object, int *); | ||
| 4394 | extern Lisp_Object tool_bar_items (Lisp_Object, int *); | 4395 | extern Lisp_Object tool_bar_items (Lisp_Object, int *); |
| 4395 | extern void discard_mouse_events (void); | 4396 | extern void discard_mouse_events (void); |
| 4396 | #ifdef USABLE_SIGIO | 4397 | #ifdef USABLE_SIGIO |
diff --git a/src/menu.c b/src/menu.c index f67bdf05667..3d9cdb02115 100644 --- a/src/menu.c +++ b/src/menu.c | |||
| @@ -1130,6 +1130,7 @@ x_popup_menu_1 (Lisp_Object position, Lisp_Object menu) | |||
| 1130 | /* Decode the first argument: find the window and the coordinates. */ | 1130 | /* Decode the first argument: find the window and the coordinates. */ |
| 1131 | if (EQ (position, Qt) | 1131 | if (EQ (position, Qt) |
| 1132 | || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar) | 1132 | || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar) |
| 1133 | || EQ (XCAR (position), Qtab_bar) | ||
| 1133 | || EQ (XCAR (position), Qtool_bar)))) | 1134 | || EQ (XCAR (position), Qtool_bar)))) |
| 1134 | { | 1135 | { |
| 1135 | get_current_pos_p = 1; | 1136 | get_current_pos_p = 1; |
| @@ -1506,6 +1507,7 @@ for instance using the window manager, then this produces a quit and | |||
| 1506 | /* Decode the first argument: find the window or frame to use. */ | 1507 | /* Decode the first argument: find the window or frame to use. */ |
| 1507 | if (EQ (position, Qt) | 1508 | if (EQ (position, Qt) |
| 1508 | || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar) | 1509 | || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar) |
| 1510 | || EQ (XCAR (position), Qtab_bar) | ||
| 1509 | || EQ (XCAR (position), Qtool_bar)))) | 1511 | || EQ (XCAR (position), Qtool_bar)))) |
| 1510 | window = selected_window; | 1512 | window = selected_window; |
| 1511 | else if (CONSP (position)) | 1513 | else if (CONSP (position)) |
diff --git a/src/msdos.c b/src/msdos.c index d13f2304852..1192b37a0d4 100644 --- a/src/msdos.c +++ b/src/msdos.c | |||
| @@ -2655,7 +2655,7 @@ dos_rawgetc (void) | |||
| 2655 | static Lisp_Object last_mouse_window; | 2655 | static Lisp_Object last_mouse_window; |
| 2656 | 2656 | ||
| 2657 | mouse_window = window_from_coordinates | 2657 | mouse_window = window_from_coordinates |
| 2658 | (SELECTED_FRAME (), mouse_last_x, mouse_last_y, 0, 0); | 2658 | (SELECTED_FRAME (), mouse_last_x, mouse_last_y, 0, 0, 0); |
| 2659 | /* A window will be selected only when it is not | 2659 | /* A window will be selected only when it is not |
| 2660 | selected now, and the last mouse movement event was | 2660 | selected now, and the last mouse movement event was |
| 2661 | not in it. A minibuffer window will be selected iff | 2661 | not in it. A minibuffer window will be selected iff |
diff --git a/src/nsfns.m b/src/nsfns.m index 2470c05c4b5..184fd71678e 100644 --- a/src/nsfns.m +++ b/src/nsfns.m | |||
| @@ -610,6 +610,15 @@ ns_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) | |||
| 610 | } | 610 | } |
| 611 | 611 | ||
| 612 | 612 | ||
| 613 | /* tabbar support */ | ||
| 614 | static void | ||
| 615 | ns_set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) | ||
| 616 | { | ||
| 617 | /* Currently unimplemented. */ | ||
| 618 | NSTRACE ("ns_set_tab_bar_lines"); | ||
| 619 | } | ||
| 620 | |||
| 621 | |||
| 613 | /* toolbar support */ | 622 | /* toolbar support */ |
| 614 | static void | 623 | static void |
| 615 | ns_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) | 624 | ns_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) |
| @@ -923,6 +932,7 @@ frame_parm_handler ns_frame_parm_handlers[] = | |||
| 923 | gui_set_vertical_scroll_bars, /* generic OK */ | 932 | gui_set_vertical_scroll_bars, /* generic OK */ |
| 924 | gui_set_horizontal_scroll_bars, /* generic OK */ | 933 | gui_set_horizontal_scroll_bars, /* generic OK */ |
| 925 | gui_set_visibility, /* generic OK */ | 934 | gui_set_visibility, /* generic OK */ |
| 935 | ns_set_tab_bar_lines, | ||
| 926 | ns_set_tool_bar_lines, | 936 | ns_set_tool_bar_lines, |
| 927 | 0, /* x_set_scroll_bar_foreground, will ignore (not possible on NS) */ | 937 | 0, /* x_set_scroll_bar_foreground, will ignore (not possible on NS) */ |
| 928 | 0, /* x_set_scroll_bar_background, will ignore (not possible on NS) */ | 938 | 0, /* x_set_scroll_bar_background, will ignore (not possible on NS) */ |
| @@ -1297,7 +1307,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame, | |||
| 1297 | RES_TYPE_STRING); | 1307 | RES_TYPE_STRING); |
| 1298 | 1308 | ||
| 1299 | parms = get_geometry_from_preferences (dpyinfo, parms); | 1309 | parms = get_geometry_from_preferences (dpyinfo, parms); |
| 1300 | window_prompting = gui_figure_window_size (f, parms, true, | 1310 | window_prompting = gui_figure_window_size (f, parms, false, true, |
| 1301 | &x_width, &x_height); | 1311 | &x_width, &x_height); |
| 1302 | 1312 | ||
| 1303 | tem = gui_display_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, | 1313 | tem = gui_display_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, |
diff --git a/src/nsterm.m b/src/nsterm.m index 42ef4dd0106..c8094d0ee37 100644 --- a/src/nsterm.m +++ b/src/nsterm.m | |||
| @@ -6859,7 +6859,7 @@ not_in_argv (NSString *arg) | |||
| 6859 | NSTRACE_MSG ("mouse_autoselect_window"); | 6859 | NSTRACE_MSG ("mouse_autoselect_window"); |
| 6860 | static Lisp_Object last_mouse_window; | 6860 | static Lisp_Object last_mouse_window; |
| 6861 | Lisp_Object window | 6861 | Lisp_Object window |
| 6862 | = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0); | 6862 | = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0, 0); |
| 6863 | 6863 | ||
| 6864 | if (WINDOWP (window) | 6864 | if (WINDOWP (window) |
| 6865 | && !EQ (window, last_mouse_window) | 6865 | && !EQ (window, last_mouse_window) |
diff --git a/src/term.c b/src/term.c index 5f70c7a3d4f..642010549bf 100644 --- a/src/term.c +++ b/src/term.c | |||
| @@ -2341,7 +2341,8 @@ frame's terminal). */) | |||
| 2341 | was suspended. */ | 2341 | was suspended. */ |
| 2342 | get_tty_size (fileno (t->display_info.tty->input), &width, &height); | 2342 | get_tty_size (fileno (t->display_info.tty->input), &width, &height); |
| 2343 | if (width != old_width || height != old_height) | 2343 | if (width != old_width || height != old_height) |
| 2344 | change_frame_size (f, width, height - FRAME_MENU_BAR_LINES (f), | 2344 | change_frame_size (f, width, height - FRAME_MENU_BAR_LINES (f) |
| 2345 | - FRAME_TAB_BAR_LINES (f), | ||
| 2345 | 0, 0, 0, 0); | 2346 | 0, 0, 0, 0); |
| 2346 | SET_FRAME_VISIBLE (XFRAME (t->display_info.tty->top_frame), 1); | 2347 | SET_FRAME_VISIBLE (XFRAME (t->display_info.tty->top_frame), 1); |
| 2347 | } | 2348 | } |
diff --git a/src/termhooks.h b/src/termhooks.h index f1827128f19..4830a85d31b 100644 --- a/src/termhooks.h +++ b/src/termhooks.h | |||
| @@ -194,6 +194,11 @@ enum event_kind | |||
| 194 | the help to show. */ | 194 | the help to show. */ |
| 195 | HELP_EVENT, | 195 | HELP_EVENT, |
| 196 | 196 | ||
| 197 | /* An event from a tab-bar. Member `arg' of the input event | ||
| 198 | contains the tab-bar item selected. If `frame_or_window' | ||
| 199 | and `arg' are equal, this is a prefix event. */ | ||
| 200 | TAB_BAR_EVENT, | ||
| 201 | |||
| 197 | /* An event from a tool-bar. Member `arg' of the input event | 202 | /* An event from a tool-bar. Member `arg' of the input event |
| 198 | contains the tool-bar item selected. If `frame_or_window' | 203 | contains the tool-bar item selected. If `frame_or_window' |
| 199 | and `arg' are equal, this is a prefix event. */ | 204 | and `arg' are equal, this is a prefix event. */ |
| @@ -624,6 +629,9 @@ struct terminal | |||
| 624 | Lisp_Object (*popup_dialog_hook) (struct frame *f, Lisp_Object header, | 629 | Lisp_Object (*popup_dialog_hook) (struct frame *f, Lisp_Object header, |
| 625 | Lisp_Object contents); | 630 | Lisp_Object contents); |
| 626 | 631 | ||
| 632 | /* This hook is called to change the frame's (internal) tab-bar. */ | ||
| 633 | void (*change_tab_bar_height_hook) (struct frame *f, int height); | ||
| 634 | |||
| 627 | /* This hook is called to change the frame's (internal) tool-bar. */ | 635 | /* This hook is called to change the frame's (internal) tool-bar. */ |
| 628 | void (*change_tool_bar_height_hook) (struct frame *f, int height); | 636 | void (*change_tool_bar_height_hook) (struct frame *f, int height); |
| 629 | 637 | ||
diff --git a/src/w32fns.c b/src/w32fns.c index 8bc5707bfa7..4ef075f715b 100644 --- a/src/w32fns.c +++ b/src/w32fns.c | |||
| @@ -1773,6 +1773,94 @@ w32_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) | |||
| 1773 | } | 1773 | } |
| 1774 | 1774 | ||
| 1775 | 1775 | ||
| 1776 | /* Set the number of lines used for the tab bar of frame F to VALUE. | ||
| 1777 | VALUE not an integer, or < 0 means set the lines to zero. OLDVAL | ||
| 1778 | is the old number of tab bar lines. This function changes the | ||
| 1779 | height of all windows on frame F to match the new tab bar height. | ||
| 1780 | The frame's height doesn't change. */ | ||
| 1781 | |||
| 1782 | static void | ||
| 1783 | w32_set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) | ||
| 1784 | { | ||
| 1785 | int nlines; | ||
| 1786 | |||
| 1787 | /* Treat tab bars like menu bars. */ | ||
| 1788 | if (FRAME_MINIBUF_ONLY_P (f)) | ||
| 1789 | return; | ||
| 1790 | |||
| 1791 | /* Use VALUE only if an int >= 0. */ | ||
| 1792 | if (RANGED_FIXNUMP (0, value, INT_MAX)) | ||
| 1793 | nlines = XFIXNAT (value); | ||
| 1794 | else | ||
| 1795 | nlines = 0; | ||
| 1796 | |||
| 1797 | w32_change_tab_bar_height (f, nlines * FRAME_LINE_HEIGHT (f)); | ||
| 1798 | } | ||
| 1799 | |||
| 1800 | |||
| 1801 | /* Set the pixel height of the tab bar of frame F to HEIGHT. */ | ||
| 1802 | void | ||
| 1803 | w32_change_tab_bar_height (struct frame *f, int height) | ||
| 1804 | { | ||
| 1805 | int unit = FRAME_LINE_HEIGHT (f); | ||
| 1806 | int old_height = FRAME_TAB_BAR_HEIGHT (f); | ||
| 1807 | int lines = (height + unit - 1) / unit; | ||
| 1808 | Lisp_Object fullscreen; | ||
| 1809 | |||
| 1810 | /* Make sure we redisplay all windows in this frame. */ | ||
| 1811 | fset_redisplay (f); | ||
| 1812 | |||
| 1813 | /* Recalculate tab bar and frame text sizes. */ | ||
| 1814 | FRAME_TAB_BAR_HEIGHT (f) = height; | ||
| 1815 | FRAME_TAB_BAR_LINES (f) = lines; | ||
| 1816 | /* Store the `tab-bar-lines' and `height' frame parameters. */ | ||
| 1817 | store_frame_param (f, Qtab_bar_lines, make_fixnum (lines)); | ||
| 1818 | store_frame_param (f, Qheight, make_fixnum (FRAME_LINES (f))); | ||
| 1819 | |||
| 1820 | /* We also have to make sure that the internal border at the top of | ||
| 1821 | the frame, below the menu bar or tab bar, is redrawn when the | ||
| 1822 | tab bar disappears. This is so because the internal border is | ||
| 1823 | below the tab bar if one is displayed, but is below the menu bar | ||
| 1824 | if there isn't a tab bar. The tab bar draws into the area | ||
| 1825 | below the menu bar. */ | ||
| 1826 | if (FRAME_W32_WINDOW (f) && FRAME_TAB_BAR_HEIGHT (f) == 0) | ||
| 1827 | { | ||
| 1828 | clear_frame (f); | ||
| 1829 | clear_current_matrices (f); | ||
| 1830 | } | ||
| 1831 | |||
| 1832 | if ((height < old_height) && WINDOWP (f->tab_bar_window)) | ||
| 1833 | clear_glyph_matrix (XWINDOW (f->tab_bar_window)->current_matrix); | ||
| 1834 | |||
| 1835 | /* Recalculate tabbar height. */ | ||
| 1836 | f->n_tab_bar_rows = 0; | ||
| 1837 | if (old_height == 0 | ||
| 1838 | && (!f->after_make_frame | ||
| 1839 | || NILP (frame_inhibit_implied_resize) | ||
| 1840 | || (CONSP (frame_inhibit_implied_resize) | ||
| 1841 | && NILP (Fmemq (Qtab_bar_lines, frame_inhibit_implied_resize))))) | ||
| 1842 | f->tab_bar_redisplayed = f->tab_bar_resized = false; | ||
| 1843 | |||
| 1844 | adjust_frame_size (f, -1, -1, | ||
| 1845 | ((!f->tab_bar_resized | ||
| 1846 | && (NILP (fullscreen = | ||
| 1847 | get_frame_param (f, Qfullscreen)) | ||
| 1848 | || EQ (fullscreen, Qfullwidth))) ? 1 | ||
| 1849 | : (old_height == 0 || height == 0) ? 2 | ||
| 1850 | : 4), | ||
| 1851 | false, Qtab_bar_lines); | ||
| 1852 | |||
| 1853 | f->tab_bar_resized = f->tab_bar_redisplayed; | ||
| 1854 | |||
| 1855 | /* adjust_frame_size might not have done anything, garbage frame | ||
| 1856 | here. */ | ||
| 1857 | adjust_frame_glyphs (f); | ||
| 1858 | SET_FRAME_GARBAGED (f); | ||
| 1859 | if (FRAME_W32_WINDOW (f)) | ||
| 1860 | w32_clear_under_internal_border (f); | ||
| 1861 | } | ||
| 1862 | |||
| 1863 | |||
| 1776 | /* Set the number of lines used for the tool bar of frame F to VALUE. | 1864 | /* Set the number of lines used for the tool bar of frame F to VALUE. |
| 1777 | VALUE not an integer, or < 0 means set the lines to zero. OLDVAL is | 1865 | VALUE not an integer, or < 0 means set the lines to zero. OLDVAL is |
| 1778 | the old number of tool bar lines (and is unused). This function may | 1866 | 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, | |||
| 5989 | /* No menu bar for child frames. */ | 6077 | /* No menu bar for child frames. */ |
| 5990 | store_frame_param (f, Qmenu_bar_lines, make_fixnum (0)); | 6078 | store_frame_param (f, Qmenu_bar_lines, make_fixnum (0)); |
| 5991 | 6079 | ||
| 6080 | gui_default_parameter (f, parameters, Qtab_bar_lines, | ||
| 6081 | NILP (Vtab_bar_mode) | ||
| 6082 | ? make_fixnum (0) : make_fixnum (1), | ||
| 6083 | NULL, NULL, RES_TYPE_NUMBER); | ||
| 6084 | |||
| 5992 | gui_default_parameter (f, parameters, Qtool_bar_lines, | 6085 | gui_default_parameter (f, parameters, Qtool_bar_lines, |
| 5993 | NILP (Vtool_bar_mode) | 6086 | NILP (Vtool_bar_mode) |
| 5994 | ? make_fixnum (0) : make_fixnum (1), | 6087 | ? make_fixnum (0) : make_fixnum (1), |
| @@ -6018,7 +6111,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame, | |||
| 6018 | 6111 | ||
| 6019 | f->output_data.w32->current_cursor = f->output_data.w32->nontext_cursor; | 6112 | f->output_data.w32->current_cursor = f->output_data.w32->nontext_cursor; |
| 6020 | 6113 | ||
| 6021 | window_prompting = gui_figure_window_size (f, parameters, true, | 6114 | window_prompting = gui_figure_window_size (f, parameters, true, true, |
| 6022 | &x_width, &x_height); | 6115 | &x_width, &x_height); |
| 6023 | 6116 | ||
| 6024 | tem = gui_display_get_arg (dpyinfo, parameters, Qunsplittable, 0, 0, | 6117 | 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) | |||
| 6986 | f->output_data.w32->parent_desc = FRAME_DISPLAY_INFO (f)->root_window; | 7079 | f->output_data.w32->parent_desc = FRAME_DISPLAY_INFO (f)->root_window; |
| 6987 | f->output_data.w32->explicit_parent = false; | 7080 | f->output_data.w32->explicit_parent = false; |
| 6988 | 7081 | ||
| 6989 | gui_figure_window_size (f, parms, true, &x_width, &x_height); | 7082 | gui_figure_window_size (f, parms, true, true, &x_width, &x_height); |
| 6990 | 7083 | ||
| 6991 | /* No fringes on tip frame. */ | 7084 | /* No fringes on tip frame. */ |
| 6992 | f->fringe_cols = 0; | 7085 | f->fringe_cols = 0; |
| @@ -8739,6 +8832,9 @@ and width values are in pixels. | |||
| 8739 | `menu-bar-size' is a cons of the width and height of the menu bar of | 8832 | `menu-bar-size' is a cons of the width and height of the menu bar of |
| 8740 | FRAME. | 8833 | FRAME. |
| 8741 | 8834 | ||
| 8835 | `tab-bar-size' is a cons of the width and height of the tab bar of | ||
| 8836 | FRAME. | ||
| 8837 | |||
| 8742 | `tool-bar-external', if non-nil, means the tool bar is external (never | 8838 | `tool-bar-external', if non-nil, means the tool bar is external (never |
| 8743 | included in the inner edges of FRAME). | 8839 | included in the inner edges of FRAME). |
| 8744 | 8840 | ||
| @@ -8761,6 +8857,7 @@ and width values are in pixels. | |||
| 8761 | unsigned int external_border_width, external_border_height; | 8857 | unsigned int external_border_width, external_border_height; |
| 8762 | int title_bar_width = 0, title_bar_height = 0; | 8858 | int title_bar_width = 0, title_bar_height = 0; |
| 8763 | int single_menu_bar_height, wrapped_menu_bar_height, menu_bar_height; | 8859 | int single_menu_bar_height, wrapped_menu_bar_height, menu_bar_height; |
| 8860 | int tab_bar_height = FRAME_TAB_BAR_HEIGHT (f); | ||
| 8764 | int tool_bar_height = FRAME_TOOL_BAR_HEIGHT (f); | 8861 | int tool_bar_height = FRAME_TOOL_BAR_HEIGHT (f); |
| 8765 | int internal_border_width = FRAME_INTERNAL_BORDER_WIDTH (f); | 8862 | int internal_border_width = FRAME_INTERNAL_BORDER_WIDTH (f); |
| 8766 | 8863 | ||
| @@ -8834,6 +8931,13 @@ and width values are in pixels. | |||
| 8834 | Fcons (make_fixnum | 8931 | Fcons (make_fixnum |
| 8835 | (menu_bar.rcBar.right - menu_bar.rcBar.left), | 8932 | (menu_bar.rcBar.right - menu_bar.rcBar.left), |
| 8836 | make_fixnum (menu_bar_height))), | 8933 | make_fixnum (menu_bar_height))), |
| 8934 | Fcons (Qtab_bar_size, | ||
| 8935 | Fcons (make_fixnum | ||
| 8936 | (tab_bar_height | ||
| 8937 | ? (right - left - 2 * external_border_width | ||
| 8938 | - 2 * internal_border_width) | ||
| 8939 | : 0), | ||
| 8940 | make_fixnum (tab_bar_height))), | ||
| 8837 | Fcons (Qtool_bar_external, Qnil), | 8941 | Fcons (Qtool_bar_external, Qnil), |
| 8838 | Fcons (Qtool_bar_position, tool_bar_height ? Qtop : Qnil), | 8942 | Fcons (Qtool_bar_position, tool_bar_height ? Qtop : Qnil), |
| 8839 | Fcons (Qtool_bar_size, | 8943 | Fcons (Qtool_bar_size, |
| @@ -8925,6 +9029,7 @@ menu bar or tool bar of FRAME. */) | |||
| 8925 | 9029 | ||
| 8926 | return list4 (make_fixnum (left + internal_border_width), | 9030 | return list4 (make_fixnum (left + internal_border_width), |
| 8927 | make_fixnum (top | 9031 | make_fixnum (top |
| 9032 | + FRAME_TAB_BAR_HEIGHT (f) | ||
| 8928 | + FRAME_TOOL_BAR_HEIGHT (f) | 9033 | + FRAME_TOOL_BAR_HEIGHT (f) |
| 8929 | + internal_border_width), | 9034 | + internal_border_width), |
| 8930 | make_fixnum (right - internal_border_width), | 9035 | make_fixnum (right - internal_border_width), |
| @@ -10212,6 +10317,7 @@ frame_parm_handler w32_frame_parm_handlers[] = | |||
| 10212 | gui_set_vertical_scroll_bars, | 10317 | gui_set_vertical_scroll_bars, |
| 10213 | gui_set_horizontal_scroll_bars, | 10318 | gui_set_horizontal_scroll_bars, |
| 10214 | gui_set_visibility, | 10319 | gui_set_visibility, |
| 10320 | w32_set_tab_bar_lines, | ||
| 10215 | w32_set_tool_bar_lines, | 10321 | w32_set_tool_bar_lines, |
| 10216 | 0, /* x_set_scroll_bar_foreground, */ | 10322 | 0, /* x_set_scroll_bar_foreground, */ |
| 10217 | 0, /* x_set_scroll_bar_background, */ | 10323 | 0, /* x_set_scroll_bar_background, */ |
diff --git a/src/w32inevt.c b/src/w32inevt.c index fc1f90cd025..2b6979bda24 100644 --- a/src/w32inevt.c +++ b/src/w32inevt.c | |||
| @@ -492,7 +492,7 @@ do_mouse_event (MOUSE_EVENT_RECORD *event, | |||
| 492 | if (!NILP (Vmouse_autoselect_window)) | 492 | if (!NILP (Vmouse_autoselect_window)) |
| 493 | { | 493 | { |
| 494 | Lisp_Object mouse_window = window_from_coordinates (f, mx, my, | 494 | Lisp_Object mouse_window = window_from_coordinates (f, mx, my, |
| 495 | 0, 0); | 495 | 0, 0, 0); |
| 496 | /* A window will be selected only when it is not | 496 | /* A window will be selected only when it is not |
| 497 | selected now, and the last mouse movement event was | 497 | selected now, and the last mouse movement event was |
| 498 | not in it. A minibuffer window will be selected iff | 498 | not in it. A minibuffer window will be selected iff |
diff --git a/src/w32reg.c b/src/w32reg.c index 99b3973d708..f156c378f93 100644 --- a/src/w32reg.c +++ b/src/w32reg.c | |||
| @@ -36,6 +36,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 36 | "emacs.tooltip.attributeBackground:SystemInfoWindow\0" \ | 36 | "emacs.tooltip.attributeBackground:SystemInfoWindow\0" \ |
| 37 | "emacs.tool-bar.attributeForeground:SystemButtonText\0" \ | 37 | "emacs.tool-bar.attributeForeground:SystemButtonText\0" \ |
| 38 | "emacs.tool-bar.attributeBackground:SystemButtonFace\0" \ | 38 | "emacs.tool-bar.attributeBackground:SystemButtonFace\0" \ |
| 39 | "emacs.tab-bar.attributeForeground:SystemButtonText\0" \ | ||
| 40 | "emacs.tab-bar.attributeBackground:SystemButtonFace\0" \ | ||
| 39 | "emacs.menu.attributeForeground:SystemMenuText\0" \ | 41 | "emacs.menu.attributeForeground:SystemMenuText\0" \ |
| 40 | "emacs.menu.attributeBackground:SystemMenu\0" \ | 42 | "emacs.menu.attributeBackground:SystemMenu\0" \ |
| 41 | "emacs.scroll-bar.attributeForeground:SystemScrollbar\0" | 43 | "emacs.scroll-bar.attributeForeground:SystemScrollbar\0" |
diff --git a/src/w32term.c b/src/w32term.c index e5874f2d365..82256db1721 100644 --- a/src/w32term.c +++ b/src/w32term.c | |||
| @@ -168,6 +168,8 @@ int w32_keyboard_codepage; | |||
| 168 | int w32_message_fd = -1; | 168 | int w32_message_fd = -1; |
| 169 | #endif /* CYGWIN */ | 169 | #endif /* CYGWIN */ |
| 170 | 170 | ||
| 171 | static void w32_handle_tab_bar_click (struct frame *, | ||
| 172 | struct input_event *); | ||
| 171 | static void w32_handle_tool_bar_click (struct frame *, | 173 | static void w32_handle_tool_bar_click (struct frame *, |
| 172 | struct input_event *); | 174 | struct input_event *); |
| 173 | static void w32_define_cursor (Window, Emacs_Cursor); | 175 | static void w32_define_cursor (Window, Emacs_Cursor); |
| @@ -3604,6 +3606,29 @@ w32_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window, | |||
| 3604 | 3606 | ||
| 3605 | 3607 | ||
| 3606 | /*********************************************************************** | 3608 | /*********************************************************************** |
| 3609 | Tab-bars | ||
| 3610 | ***********************************************************************/ | ||
| 3611 | |||
| 3612 | /* Handle mouse button event on the tab-bar of frame F, at | ||
| 3613 | frame-relative coordinates X/Y. EVENT_TYPE is either ButtonPress | ||
| 3614 | or ButtonRelease. */ | ||
| 3615 | |||
| 3616 | static void | ||
| 3617 | w32_handle_tab_bar_click (struct frame *f, struct input_event *button_event) | ||
| 3618 | { | ||
| 3619 | int x = XFIXNAT (button_event->x); | ||
| 3620 | int y = XFIXNAT (button_event->y); | ||
| 3621 | |||
| 3622 | if (button_event->modifiers & down_modifier) | ||
| 3623 | handle_tab_bar_click (f, x, y, 1, 0); | ||
| 3624 | else | ||
| 3625 | handle_tab_bar_click (f, x, y, 0, | ||
| 3626 | button_event->modifiers & ~up_modifier); | ||
| 3627 | } | ||
| 3628 | |||
| 3629 | |||
| 3630 | |||
| 3631 | /*********************************************************************** | ||
| 3607 | Tool-bars | 3632 | Tool-bars |
| 3608 | ***********************************************************************/ | 3633 | ***********************************************************************/ |
| 3609 | 3634 | ||
| @@ -4843,6 +4868,7 @@ w32_read_socket (struct terminal *terminal, | |||
| 4843 | if (f && !FRAME_ICONIFIED_P (f)) | 4868 | if (f && !FRAME_ICONIFIED_P (f)) |
| 4844 | { | 4869 | { |
| 4845 | if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight) | 4870 | if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight) |
| 4871 | && !EQ (f->tab_bar_window, hlinfo->mouse_face_window) | ||
| 4846 | && !EQ (f->tool_bar_window, hlinfo->mouse_face_window)) | 4872 | && !EQ (f->tool_bar_window, hlinfo->mouse_face_window)) |
| 4847 | { | 4873 | { |
| 4848 | clear_mouse_face (hlinfo); | 4874 | clear_mouse_face (hlinfo); |
| @@ -4868,6 +4894,7 @@ w32_read_socket (struct terminal *terminal, | |||
| 4868 | if (f && !FRAME_ICONIFIED_P (f)) | 4894 | if (f && !FRAME_ICONIFIED_P (f)) |
| 4869 | { | 4895 | { |
| 4870 | if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight) | 4896 | if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight) |
| 4897 | && !EQ (f->tab_bar_window, hlinfo->mouse_face_window) | ||
| 4871 | && !EQ (f->tool_bar_window, hlinfo->mouse_face_window)) | 4898 | && !EQ (f->tool_bar_window, hlinfo->mouse_face_window)) |
| 4872 | { | 4899 | { |
| 4873 | clear_mouse_face (hlinfo); | 4900 | clear_mouse_face (hlinfo); |
| @@ -4946,6 +4973,7 @@ w32_read_socket (struct terminal *terminal, | |||
| 4946 | if (f && !FRAME_ICONIFIED_P (f)) | 4973 | if (f && !FRAME_ICONIFIED_P (f)) |
| 4947 | { | 4974 | { |
| 4948 | if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight) | 4975 | if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight) |
| 4976 | && !EQ (f->tab_bar_window, hlinfo->mouse_face_window) | ||
| 4949 | && !EQ (f->tool_bar_window, hlinfo->mouse_face_window)) | 4977 | && !EQ (f->tool_bar_window, hlinfo->mouse_face_window)) |
| 4950 | { | 4978 | { |
| 4951 | clear_mouse_face (hlinfo); | 4979 | clear_mouse_face (hlinfo); |
| @@ -4998,7 +5026,7 @@ w32_read_socket (struct terminal *terminal, | |||
| 4998 | { | 5026 | { |
| 4999 | static Lisp_Object last_mouse_window; | 5027 | static Lisp_Object last_mouse_window; |
| 5000 | Lisp_Object window = window_from_coordinates | 5028 | Lisp_Object window = window_from_coordinates |
| 5001 | (f, LOWORD (msg.msg.lParam), HIWORD (msg.msg.lParam), 0, 0); | 5029 | (f, LOWORD (msg.msg.lParam), HIWORD (msg.msg.lParam), 0, 0, 0); |
| 5002 | 5030 | ||
| 5003 | /* Window will be selected only when it is not | 5031 | /* Window will be selected only when it is not |
| 5004 | selected now and last mouse movement event was | 5032 | selected now and last mouse movement event was |
| @@ -5051,6 +5079,7 @@ w32_read_socket (struct terminal *terminal, | |||
| 5051 | { | 5079 | { |
| 5052 | /* If we decide we want to generate an event to be seen | 5080 | /* If we decide we want to generate an event to be seen |
| 5053 | by the rest of Emacs, we put it here. */ | 5081 | by the rest of Emacs, we put it here. */ |
| 5082 | bool tab_bar_p = 0; | ||
| 5054 | bool tool_bar_p = 0; | 5083 | bool tool_bar_p = 0; |
| 5055 | int button = 0; | 5084 | int button = 0; |
| 5056 | int up = 0; | 5085 | int up = 0; |
| @@ -5060,6 +5089,31 @@ w32_read_socket (struct terminal *terminal, | |||
| 5060 | { | 5089 | { |
| 5061 | w32_construct_mouse_click (&inev, &msg, f); | 5090 | w32_construct_mouse_click (&inev, &msg, f); |
| 5062 | 5091 | ||
| 5092 | /* Is this in the tab-bar? */ | ||
| 5093 | if (WINDOWP (f->tab_bar_window) | ||
| 5094 | && WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window))) | ||
| 5095 | { | ||
| 5096 | Lisp_Object window; | ||
| 5097 | int x = XFIXNAT (inev.x); | ||
| 5098 | int y = XFIXNAT (inev.y); | ||
| 5099 | |||
| 5100 | window = window_from_coordinates (f, x, y, 0, 1, 1); | ||
| 5101 | |||
| 5102 | if (EQ (window, f->tab_bar_window)) | ||
| 5103 | { | ||
| 5104 | w32_handle_tab_bar_click (f, &inev); | ||
| 5105 | tab_bar_p = 1; | ||
| 5106 | } | ||
| 5107 | } | ||
| 5108 | |||
| 5109 | if (tab_bar_p | ||
| 5110 | || (dpyinfo->w32_focus_frame | ||
| 5111 | && f != dpyinfo->w32_focus_frame | ||
| 5112 | /* This does not help when the click happens in | ||
| 5113 | a grand-parent frame. */ | ||
| 5114 | && !frame_ancestor_p (f, dpyinfo->w32_focus_frame))) | ||
| 5115 | inev.kind = NO_EVENT; | ||
| 5116 | |||
| 5063 | /* Is this in the tool-bar? */ | 5117 | /* Is this in the tool-bar? */ |
| 5064 | if (WINDOWP (f->tool_bar_window) | 5118 | if (WINDOWP (f->tool_bar_window) |
| 5065 | && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window))) | 5119 | && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window))) |
| @@ -5068,7 +5122,7 @@ w32_read_socket (struct terminal *terminal, | |||
| 5068 | int x = XFIXNAT (inev.x); | 5122 | int x = XFIXNAT (inev.x); |
| 5069 | int y = XFIXNAT (inev.y); | 5123 | int y = XFIXNAT (inev.y); |
| 5070 | 5124 | ||
| 5071 | window = window_from_coordinates (f, x, y, 0, 1); | 5125 | window = window_from_coordinates (f, x, y, 0, 1, 1); |
| 5072 | 5126 | ||
| 5073 | if (EQ (window, f->tool_bar_window)) | 5127 | if (EQ (window, f->tool_bar_window)) |
| 5074 | { | 5128 | { |
| @@ -5104,6 +5158,8 @@ w32_read_socket (struct terminal *terminal, | |||
| 5104 | if (f != 0) | 5158 | if (f != 0) |
| 5105 | { | 5159 | { |
| 5106 | f->mouse_moved = false; | 5160 | f->mouse_moved = false; |
| 5161 | if (!tab_bar_p) | ||
| 5162 | f->last_tab_bar_item = -1; | ||
| 5107 | if (!tool_bar_p) | 5163 | if (!tool_bar_p) |
| 5108 | f->last_tool_bar_item = -1; | 5164 | f->last_tool_bar_item = -1; |
| 5109 | } | 5165 | } |
| @@ -5127,6 +5183,7 @@ w32_read_socket (struct terminal *terminal, | |||
| 5127 | event; any subsequent mouse-movement Emacs events | 5183 | event; any subsequent mouse-movement Emacs events |
| 5128 | should reflect only motion after the ButtonPress. */ | 5184 | should reflect only motion after the ButtonPress. */ |
| 5129 | f->mouse_moved = false; | 5185 | f->mouse_moved = false; |
| 5186 | f->last_tab_bar_item = -1; | ||
| 5130 | f->last_tool_bar_item = -1; | 5187 | f->last_tool_bar_item = -1; |
| 5131 | dpyinfo->last_mouse_frame = f; | 5188 | dpyinfo->last_mouse_frame = f; |
| 5132 | } | 5189 | } |
| @@ -5140,6 +5197,7 @@ w32_read_socket (struct terminal *terminal, | |||
| 5140 | { | 5197 | { |
| 5141 | w32_construct_mouse_wheel (&inev, &msg, f1); | 5198 | w32_construct_mouse_wheel (&inev, &msg, f1); |
| 5142 | f1->mouse_moved = false; | 5199 | f1->mouse_moved = false; |
| 5200 | f1->last_tab_bar_item = -1; | ||
| 5143 | f1->last_tool_bar_item = -1; | 5201 | f1->last_tool_bar_item = -1; |
| 5144 | dpyinfo->last_mouse_frame = f1; | 5202 | dpyinfo->last_mouse_frame = f1; |
| 5145 | } | 5203 | } |
| @@ -5936,7 +5994,8 @@ w32_draw_window_cursor (struct window *w, struct glyph_row *glyph_row, | |||
| 5936 | = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y) | 5994 | = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y) |
| 5937 | + glyph_row->ascent - w->phys_cursor_ascent); | 5995 | + glyph_row->ascent - w->phys_cursor_ascent); |
| 5938 | w32_system_caret_window = w; | 5996 | w32_system_caret_window = w; |
| 5939 | w32_system_caret_hdr_height = WINDOW_HEADER_LINE_HEIGHT (w); | 5997 | w32_system_caret_hdr_height = WINDOW_TAB_LINE_HEIGHT (w) |
| 5998 | + WINDOW_HEADER_LINE_HEIGHT (w); | ||
| 5940 | w32_system_caret_mode_height = WINDOW_MODE_LINE_HEIGHT (w); | 5999 | w32_system_caret_mode_height = WINDOW_MODE_LINE_HEIGHT (w); |
| 5941 | 6000 | ||
| 5942 | PostMessage (hwnd, WM_IME_STARTCOMPOSITION, 0, 0); | 6001 | PostMessage (hwnd, WM_IME_STARTCOMPOSITION, 0, 0); |
| @@ -7192,6 +7251,7 @@ w32_create_terminal (struct w32_display_info *dpyinfo) | |||
| 7192 | terminal->menu_show_hook = w32_menu_show; | 7251 | terminal->menu_show_hook = w32_menu_show; |
| 7193 | terminal->activate_menubar_hook = w32_activate_menubar; | 7252 | terminal->activate_menubar_hook = w32_activate_menubar; |
| 7194 | terminal->popup_dialog_hook = w32_popup_dialog; | 7253 | terminal->popup_dialog_hook = w32_popup_dialog; |
| 7254 | terminal->change_tab_bar_height_hook = w32_change_tab_bar_height; | ||
| 7195 | terminal->change_tool_bar_height_hook = w32_change_tool_bar_height; | 7255 | terminal->change_tool_bar_height_hook = w32_change_tool_bar_height; |
| 7196 | terminal->set_vertical_scroll_bar_hook = w32_set_vertical_scroll_bar; | 7256 | terminal->set_vertical_scroll_bar_hook = w32_set_vertical_scroll_bar; |
| 7197 | terminal->set_horizontal_scroll_bar_hook = w32_set_horizontal_scroll_bar; | 7257 | terminal->set_horizontal_scroll_bar_hook = w32_set_horizontal_scroll_bar; |
diff --git a/src/w32term.h b/src/w32term.h index 6133e100c17..378f274d7ed 100644 --- a/src/w32term.h +++ b/src/w32term.h | |||
| @@ -233,6 +233,7 @@ extern void w32_real_positions (struct frame *f, int *xptr, int *yptr); | |||
| 233 | 233 | ||
| 234 | extern void w32_clear_under_internal_border (struct frame *); | 234 | extern void w32_clear_under_internal_border (struct frame *); |
| 235 | 235 | ||
| 236 | extern void w32_change_tab_bar_height (struct frame *, int); | ||
| 236 | extern void w32_change_tool_bar_height (struct frame *, int); | 237 | extern void w32_change_tool_bar_height (struct frame *, int); |
| 237 | extern void w32_implicitly_set_name (struct frame *, Lisp_Object, Lisp_Object); | 238 | extern void w32_implicitly_set_name (struct frame *, Lisp_Object, Lisp_Object); |
| 238 | extern void w32_set_scroll_bar_default_width (struct frame *); | 239 | extern void w32_set_scroll_bar_default_width (struct frame *); |
diff --git a/src/window.c b/src/window.c index 321b3e01b79..95197985e84 100644 --- a/src/window.c +++ b/src/window.c | |||
| @@ -1002,6 +1002,7 @@ static int | |||
| 1002 | window_body_height (struct window *w, bool pixelwise) | 1002 | window_body_height (struct window *w, bool pixelwise) |
| 1003 | { | 1003 | { |
| 1004 | int height = (w->pixel_height | 1004 | int height = (w->pixel_height |
| 1005 | - WINDOW_TAB_LINE_HEIGHT (w) | ||
| 1005 | - WINDOW_HEADER_LINE_HEIGHT (w) | 1006 | - WINDOW_HEADER_LINE_HEIGHT (w) |
| 1006 | - (WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w) | 1007 | - (WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w) |
| 1007 | ? WINDOW_SCROLL_BAR_AREA_HEIGHT (w) | 1008 | ? WINDOW_SCROLL_BAR_AREA_HEIGHT (w) |
| @@ -1131,6 +1132,15 @@ WINDOW must be a live window and defaults to the selected one. */) | |||
| 1131 | return (make_fixnum (WINDOW_HEADER_LINE_HEIGHT (decode_live_window (window)))); | 1132 | return (make_fixnum (WINDOW_HEADER_LINE_HEIGHT (decode_live_window (window)))); |
| 1132 | } | 1133 | } |
| 1133 | 1134 | ||
| 1135 | DEFUN ("window-tab-line-height", Fwindow_tab_line_height, | ||
| 1136 | Swindow_tab_line_height, 0, 1, 0, | ||
| 1137 | doc: /* Return the height in pixels of WINDOW's tab-line. | ||
| 1138 | WINDOW must be a live window and defaults to the selected one. */) | ||
| 1139 | (Lisp_Object window) | ||
| 1140 | { | ||
| 1141 | return (make_fixnum (WINDOW_TAB_LINE_HEIGHT (decode_live_window (window)))); | ||
| 1142 | } | ||
| 1143 | |||
| 1134 | DEFUN ("window-right-divider-width", Fwindow_right_divider_width, | 1144 | DEFUN ("window-right-divider-width", Fwindow_right_divider_width, |
| 1135 | Swindow_right_divider_width, 0, 1, 0, | 1145 | Swindow_right_divider_width, 0, 1, 0, |
| 1136 | doc: /* Return the width in pixels of WINDOW's right divider. | 1146 | doc: /* Return the width in pixels of WINDOW's right divider. |
| @@ -1249,7 +1259,8 @@ end-trigger value is reset to nil. */) | |||
| 1249 | if it is on the border between the window and its right sibling, | 1259 | if it is on the border between the window and its right sibling, |
| 1250 | return ON_VERTICAL_BORDER; | 1260 | return ON_VERTICAL_BORDER; |
| 1251 | if it is on a scroll bar, return ON_SCROLL_BAR; | 1261 | if it is on a scroll bar, return ON_SCROLL_BAR; |
| 1252 | if it is on the window's top line, return ON_HEADER_LINE; | 1262 | if it is on the window's top line, return ON_TAB_LINE; |
| 1263 | if it is on the window's header line, return ON_HEADER_LINE; | ||
| 1253 | if it is in left or right fringe of the window, | 1264 | if it is in left or right fringe of the window, |
| 1254 | return ON_LEFT_FRINGE or ON_RIGHT_FRINGE; | 1265 | return ON_LEFT_FRINGE or ON_RIGHT_FRINGE; |
| 1255 | if it is in the marginal area to the left/right of the window, | 1266 | 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) | |||
| 1299 | - CURRENT_MODE_LINE_HEIGHT (w) | 1310 | - CURRENT_MODE_LINE_HEIGHT (w) |
| 1300 | - WINDOW_BOTTOM_DIVIDER_WIDTH (w)))) | 1311 | - WINDOW_BOTTOM_DIVIDER_WIDTH (w)))) |
| 1301 | return ON_HORIZONTAL_SCROLL_BAR; | 1312 | return ON_HORIZONTAL_SCROLL_BAR; |
| 1302 | /* On the mode or header line? */ | 1313 | /* On the mode or header/tab line? */ |
| 1303 | else if ((window_wants_mode_line (w) | 1314 | else if ((window_wants_mode_line (w) |
| 1304 | && y >= (bottom_y | 1315 | && y >= (bottom_y |
| 1305 | - CURRENT_MODE_LINE_HEIGHT (w) | 1316 | - CURRENT_MODE_LINE_HEIGHT (w) |
| 1306 | - WINDOW_BOTTOM_DIVIDER_WIDTH (w)) | 1317 | - WINDOW_BOTTOM_DIVIDER_WIDTH (w)) |
| 1307 | && y <= bottom_y - WINDOW_BOTTOM_DIVIDER_WIDTH (w) | 1318 | && y <= bottom_y - WINDOW_BOTTOM_DIVIDER_WIDTH (w) |
| 1308 | && (part = ON_MODE_LINE)) | 1319 | && (part = ON_MODE_LINE)) |
| 1320 | || (window_wants_tab_line (w) | ||
| 1321 | && y < top_y + CURRENT_TAB_LINE_HEIGHT (w) | ||
| 1322 | && (part = ON_TAB_LINE)) | ||
| 1309 | || (window_wants_header_line (w) | 1323 | || (window_wants_header_line (w) |
| 1310 | && y < top_y + CURRENT_HEADER_LINE_HEIGHT (w) | 1324 | && y < top_y + CURRENT_TAB_LINE_HEIGHT (w) |
| 1325 | + CURRENT_HEADER_LINE_HEIGHT (w) | ||
| 1311 | && (part = ON_HEADER_LINE))) | 1326 | && (part = ON_HEADER_LINE))) |
| 1312 | { | 1327 | { |
| 1313 | /* If it's under/over the scroll bar portion of the mode/header | 1328 | /* 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) | |||
| 1407 | case ON_TEXT: | 1422 | case ON_TEXT: |
| 1408 | return x - window_box_left (w, TEXT_AREA); | 1423 | return x - window_box_left (w, TEXT_AREA); |
| 1409 | 1424 | ||
| 1425 | case ON_TAB_LINE: | ||
| 1410 | case ON_HEADER_LINE: | 1426 | case ON_HEADER_LINE: |
| 1411 | case ON_MODE_LINE: | 1427 | case ON_MODE_LINE: |
| 1412 | case ON_LEFT_FRINGE: | 1428 | case ON_LEFT_FRINGE: |
| @@ -1457,6 +1473,7 @@ If they are in the bottom divider of WINDOW, `bottom-divider' is returned. | |||
| 1457 | If they are in the right divider of WINDOW, `right-divider' is returned. | 1473 | If they are in the right divider of WINDOW, `right-divider' is returned. |
| 1458 | If they are in the mode line of WINDOW, `mode-line' is returned. | 1474 | If they are in the mode line of WINDOW, `mode-line' is returned. |
| 1459 | If they are in the header line of WINDOW, `header-line' is returned. | 1475 | If they are in the header line of WINDOW, `header-line' is returned. |
| 1476 | If they are in the tab line of WINDOW, `tab-line' is returned. | ||
| 1460 | If they are in the left fringe of WINDOW, `left-fringe' is returned. | 1477 | If they are in the left fringe of WINDOW, `left-fringe' is returned. |
| 1461 | If they are in the right fringe of WINDOW, `right-fringe' is returned. | 1478 | If they are in the right fringe of WINDOW, `right-fringe' is returned. |
| 1462 | If they are on the border between WINDOW and its right sibling, | 1479 | 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\ | |||
| 1502 | case ON_HEADER_LINE: | 1519 | case ON_HEADER_LINE: |
| 1503 | return Qheader_line; | 1520 | return Qheader_line; |
| 1504 | 1521 | ||
| 1522 | case ON_TAB_LINE: | ||
| 1523 | return Qtab_line; | ||
| 1524 | |||
| 1505 | case ON_LEFT_FRINGE: | 1525 | case ON_LEFT_FRINGE: |
| 1506 | return Qleft_fringe; | 1526 | return Qleft_fringe; |
| 1507 | 1527 | ||
| @@ -1585,7 +1605,7 @@ check_window_containing (struct window *w, void *user_data) | |||
| 1585 | 1605 | ||
| 1586 | Lisp_Object | 1606 | Lisp_Object |
| 1587 | window_from_coordinates (struct frame *f, int x, int y, | 1607 | window_from_coordinates (struct frame *f, int x, int y, |
| 1588 | enum window_part *part, bool tool_bar_p) | 1608 | enum window_part *part, bool tab_bar_p, bool tool_bar_p) |
| 1589 | { | 1609 | { |
| 1590 | Lisp_Object window; | 1610 | Lisp_Object window; |
| 1591 | struct check_window_data cw; | 1611 | struct check_window_data cw; |
| @@ -1598,6 +1618,21 @@ window_from_coordinates (struct frame *f, int x, int y, | |||
| 1598 | cw.window = &window, cw.x = x, cw.y = y; cw.part = part; | 1618 | cw.window = &window, cw.x = x, cw.y = y; cw.part = part; |
| 1599 | foreach_window (f, check_window_containing, &cw); | 1619 | foreach_window (f, check_window_containing, &cw); |
| 1600 | 1620 | ||
| 1621 | #if defined (HAVE_WINDOW_SYSTEM) | ||
| 1622 | /* If not found above, see if it's in the tab bar window, if a tab | ||
| 1623 | bar exists. */ | ||
| 1624 | if (NILP (window) | ||
| 1625 | && tab_bar_p | ||
| 1626 | && WINDOWP (f->tab_bar_window) | ||
| 1627 | && WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window)) > 0 | ||
| 1628 | && (coordinates_in_window (XWINDOW (f->tab_bar_window), x, y) | ||
| 1629 | != ON_NOTHING)) | ||
| 1630 | { | ||
| 1631 | *part = ON_TEXT; | ||
| 1632 | window = f->tab_bar_window; | ||
| 1633 | } | ||
| 1634 | #endif | ||
| 1635 | |||
| 1601 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) | 1636 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) |
| 1602 | /* If not found above, see if it's in the tool bar window, if a tool | 1637 | /* If not found above, see if it's in the tool bar window, if a tool |
| 1603 | bar exists. */ | 1638 | bar exists. */ |
| @@ -1633,7 +1668,7 @@ column 0. */) | |||
| 1633 | + FRAME_INTERNAL_BORDER_WIDTH (f)), | 1668 | + FRAME_INTERNAL_BORDER_WIDTH (f)), |
| 1634 | (FRAME_PIXEL_Y_FROM_CANON_Y (f, y) | 1669 | (FRAME_PIXEL_Y_FROM_CANON_Y (f, y) |
| 1635 | + FRAME_INTERNAL_BORDER_WIDTH (f)), | 1670 | + FRAME_INTERNAL_BORDER_WIDTH (f)), |
| 1636 | 0, false); | 1671 | 0, false, false); |
| 1637 | } | 1672 | } |
| 1638 | 1673 | ||
| 1639 | DEFUN ("window-point", Fwindow_point, Swindow_point, 0, 1, 0, | 1674 | 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 | |||
| 1945 | goto found_row; | 1980 | goto found_row; |
| 1946 | } | 1981 | } |
| 1947 | 1982 | ||
| 1983 | if (EQ (line, Qtab_line)) | ||
| 1984 | { | ||
| 1985 | if (!window_wants_tab_line (w)) | ||
| 1986 | return Qnil; | ||
| 1987 | row = MATRIX_TAB_LINE_ROW (w->current_matrix); | ||
| 1988 | return row->enabled_p ? list4i (row->height, 0, 0, 0) : Qnil; | ||
| 1989 | } | ||
| 1990 | |||
| 1948 | if (EQ (line, Qheader_line)) | 1991 | if (EQ (line, Qheader_line)) |
| 1949 | { | 1992 | { |
| 1950 | if (!window_wants_header_line (w)) | 1993 | if (!window_wants_header_line (w)) |
| @@ -1959,7 +2002,8 @@ Return nil if window display is not up-to-date. In that case, use | |||
| 1959 | return (row->enabled_p ? | 2002 | return (row->enabled_p ? |
| 1960 | list4i (row->height, | 2003 | list4i (row->height, |
| 1961 | 0, /* not accurate */ | 2004 | 0, /* not accurate */ |
| 1962 | (WINDOW_HEADER_LINE_HEIGHT (w) | 2005 | (WINDOW_TAB_LINE_HEIGHT (w) |
| 2006 | + WINDOW_HEADER_LINE_HEIGHT (w) | ||
| 1963 | + window_text_bottom_y (w)), | 2007 | + window_text_bottom_y (w)), |
| 1964 | 0) | 2008 | 0) |
| 1965 | : Qnil); | 2009 | : Qnil); |
| @@ -2045,8 +2089,9 @@ though when run from an idle timer with a delay of zero seconds. */) | |||
| 2045 | int max_y = NILP (body) ? WINDOW_PIXEL_HEIGHT (w) : window_text_bottom_y (w); | 2089 | int max_y = NILP (body) ? WINDOW_PIXEL_HEIGHT (w) : window_text_bottom_y (w); |
| 2046 | Lisp_Object rows = Qnil; | 2090 | Lisp_Object rows = Qnil; |
| 2047 | int window_width = NILP (body) ? w->pixel_width : window_body_width (w, true); | 2091 | int window_width = NILP (body) ? w->pixel_width : window_body_width (w, true); |
| 2092 | int tab_line_height = WINDOW_TAB_LINE_HEIGHT (w); | ||
| 2048 | int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w); | 2093 | int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w); |
| 2049 | int subtract = NILP (body) ? 0 : header_line_height; | 2094 | int subtract = NILP (body) ? 0 : (tab_line_height + header_line_height); |
| 2050 | bool invert = !NILP (inverse); | 2095 | bool invert = !NILP (inverse); |
| 2051 | bool left_flag = !NILP (left); | 2096 | bool left_flag = !NILP (left); |
| 2052 | 2097 | ||
| @@ -4246,7 +4291,7 @@ make_window (void) | |||
| 4246 | non-Lisp data, so do it only for slots which should not be zero. */ | 4291 | non-Lisp data, so do it only for slots which should not be zero. */ |
| 4247 | w->nrows_scale_factor = w->ncols_scale_factor = 1; | 4292 | w->nrows_scale_factor = w->ncols_scale_factor = 1; |
| 4248 | w->left_fringe_width = w->right_fringe_width = -1; | 4293 | w->left_fringe_width = w->right_fringe_width = -1; |
| 4249 | w->mode_line_height = w->header_line_height = -1; | 4294 | w->mode_line_height = w->tab_line_height = w->header_line_height = -1; |
| 4250 | #ifdef HAVE_WINDOW_SYSTEM | 4295 | #ifdef HAVE_WINDOW_SYSTEM |
| 4251 | w->phys_cursor_type = NO_CURSOR; | 4296 | w->phys_cursor_type = NO_CURSOR; |
| 4252 | w->phys_cursor_width = -1; | 4297 | w->phys_cursor_width = -1; |
| @@ -4772,7 +4817,7 @@ Third argument SIDE nil (or `below') specifies that the new window shall | |||
| 4772 | be located below WINDOW. SIDE `above' means the new window shall be | 4817 | be located below WINDOW. SIDE `above' means the new window shall be |
| 4773 | located above WINDOW. In both cases PIXEL-SIZE specifies the pixel | 4818 | located above WINDOW. In both cases PIXEL-SIZE specifies the pixel |
| 4774 | height of the new window including space reserved for the mode and/or | 4819 | height of the new window including space reserved for the mode and/or |
| 4775 | header line. | 4820 | header/tab line. |
| 4776 | 4821 | ||
| 4777 | SIDE t (or `right') specifies that the new window shall be located on | 4822 | SIDE t (or `right') specifies that the new window shall be located on |
| 4778 | the right side of WINDOW. SIDE `left' means the new window shall be | 4823 | the right side of WINDOW. SIDE `left' means the new window shall be |
| @@ -5350,6 +5395,41 @@ window_wants_header_line (struct window *w) | |||
| 5350 | : 0); | 5395 | : 0); |
| 5351 | } | 5396 | } |
| 5352 | 5397 | ||
| 5398 | |||
| 5399 | /** | ||
| 5400 | * window_wants_tab_line: | ||
| 5401 | * | ||
| 5402 | * Return 1 if window W wants a tab line and is high enough to | ||
| 5403 | * accommodate it, 0 otherwise. | ||
| 5404 | * | ||
| 5405 | * W wants a tab line if it's a leaf window and neither a minibuffer | ||
| 5406 | * nor a pseudo window. Moreover, its 'window-mode-line-format' | ||
| 5407 | * parameter must not be 'none' and either that parameter or W's | ||
| 5408 | * buffer's 'mode-line-format' value must be non-nil. Finally, W must | ||
| 5409 | * be higher than its frame's canonical character height and be able | ||
| 5410 | * to accommodate a mode line and a header line too if necessary (the | ||
| 5411 | * mode line and a header line prevail). | ||
| 5412 | */ | ||
| 5413 | bool | ||
| 5414 | window_wants_tab_line (struct window *w) | ||
| 5415 | { | ||
| 5416 | Lisp_Object window_tab_line_format = | ||
| 5417 | window_parameter (w, Qtab_line_format); | ||
| 5418 | |||
| 5419 | return ((WINDOW_LEAF_P (w) | ||
| 5420 | && !MINI_WINDOW_P (w) | ||
| 5421 | && !WINDOW_PSEUDO_P (w) | ||
| 5422 | && !EQ (window_tab_line_format, Qnone) | ||
| 5423 | && (!NILP (window_tab_line_format) | ||
| 5424 | || !NILP (BVAR (XBUFFER (WINDOW_BUFFER (w)), tab_line_format))) | ||
| 5425 | && (WINDOW_PIXEL_HEIGHT (w) | ||
| 5426 | > (((window_wants_mode_line (w) ? 1 : 0) | ||
| 5427 | + (window_wants_header_line (w) ? 1 : 0) | ||
| 5428 | + 1) * WINDOW_FRAME_LINE_HEIGHT (w)))) | ||
| 5429 | ? 1 | ||
| 5430 | : 0); | ||
| 5431 | } | ||
| 5432 | |||
| 5353 | /* Return number of lines of text in window W, not counting the mode | 5433 | /* Return number of lines of text in window W, not counting the mode |
| 5354 | line and header line, if any. Do NOT use this for windows on GUI | 5434 | line and header line, if any. Do NOT use this for windows on GUI |
| 5355 | frames; use window_body_height instead. This function is only for | 5435 | frames; use window_body_height instead. This function is only for |
| @@ -5366,6 +5446,9 @@ window_internal_height (struct window *w) | |||
| 5366 | if (window_wants_header_line (w)) | 5446 | if (window_wants_header_line (w)) |
| 5367 | --ht; | 5447 | --ht; |
| 5368 | 5448 | ||
| 5449 | if (window_wants_tab_line (w)) | ||
| 5450 | --ht; | ||
| 5451 | |||
| 5369 | return ht; | 5452 | return ht; |
| 5370 | } | 5453 | } |
| 5371 | 5454 | ||
| @@ -5726,8 +5809,9 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) | |||
| 5726 | move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS); | 5809 | move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS); |
| 5727 | if (IT_CHARPOS (it) == PT | 5810 | if (IT_CHARPOS (it) == PT |
| 5728 | && it.current_y >= this_scroll_margin | 5811 | && it.current_y >= this_scroll_margin |
| 5729 | && it.current_y <= last_y - WINDOW_HEADER_LINE_HEIGHT (w) | 5812 | && it.current_y <= last_y - WINDOW_TAB_LINE_HEIGHT (w) |
| 5730 | && (NILP (Vscroll_preserve_screen_position) | 5813 | - WINDOW_HEADER_LINE_HEIGHT (w) |
| 5814 | && (NILP (Vscroll_preserve_screen_position) | ||
| 5731 | || EQ (Vscroll_preserve_screen_position, Qt))) | 5815 | || EQ (Vscroll_preserve_screen_position, Qt))) |
| 5732 | /* We found PT at a legitimate height. Leave it alone. */ | 5816 | /* We found PT at a legitimate height. Leave it alone. */ |
| 5733 | ; | 5817 | ; |
| @@ -5742,7 +5826,8 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) | |||
| 5742 | is necessary because we set it.current_y to 0, above. */ | 5826 | is necessary because we set it.current_y to 0, above. */ |
| 5743 | move_it_to (&it, -1, | 5827 | move_it_to (&it, -1, |
| 5744 | window_scroll_pixel_based_preserve_x, | 5828 | window_scroll_pixel_based_preserve_x, |
| 5745 | goal_y - WINDOW_HEADER_LINE_HEIGHT (w), | 5829 | goal_y - WINDOW_TAB_LINE_HEIGHT (w) |
| 5830 | - WINDOW_HEADER_LINE_HEIGHT (w), | ||
| 5746 | -1, MOVE_TO_Y | MOVE_TO_X); | 5831 | -1, MOVE_TO_Y | MOVE_TO_X); |
| 5747 | } | 5832 | } |
| 5748 | 5833 | ||
| @@ -5778,8 +5863,9 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) | |||
| 5778 | /* We subtract WINDOW_HEADER_LINE_HEIGHT because | 5863 | /* We subtract WINDOW_HEADER_LINE_HEIGHT because |
| 5779 | it.y is relative to the bottom of the header | 5864 | it.y is relative to the bottom of the header |
| 5780 | line, see above. */ | 5865 | line, see above. */ |
| 5781 | (it.last_visible_y - WINDOW_HEADER_LINE_HEIGHT (w) | 5866 | (it.last_visible_y - WINDOW_TAB_LINE_HEIGHT (w) |
| 5782 | - partial_line_height (&it) - this_scroll_margin - 1), | 5867 | - WINDOW_HEADER_LINE_HEIGHT (w) |
| 5868 | - partial_line_height (&it) - this_scroll_margin - 1), | ||
| 5783 | -1, | 5869 | -1, |
| 5784 | MOVE_TO_POS | MOVE_TO_Y); | 5870 | MOVE_TO_POS | MOVE_TO_Y); |
| 5785 | 5871 | ||
| @@ -5817,13 +5903,15 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) | |||
| 5817 | if (it.what == IT_EOB) | 5903 | if (it.what == IT_EOB) |
| 5818 | partial_p = | 5904 | partial_p = |
| 5819 | it.current_y + it.ascent + it.descent | 5905 | it.current_y + it.ascent + it.descent |
| 5820 | > it.last_visible_y - this_scroll_margin - WINDOW_HEADER_LINE_HEIGHT (w); | 5906 | > it.last_visible_y - this_scroll_margin |
| 5907 | - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w); | ||
| 5821 | else | 5908 | else |
| 5822 | { | 5909 | { |
| 5823 | move_it_by_lines (&it, 1); | 5910 | move_it_by_lines (&it, 1); |
| 5824 | partial_p = | 5911 | partial_p = |
| 5825 | it.current_y | 5912 | it.current_y |
| 5826 | > it.last_visible_y - this_scroll_margin - WINDOW_HEADER_LINE_HEIGHT (w); | 5913 | > it.last_visible_y - this_scroll_margin |
| 5914 | - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w); | ||
| 5827 | } | 5915 | } |
| 5828 | 5916 | ||
| 5829 | if (charpos == PT && !partial_p | 5917 | if (charpos == PT && !partial_p |
| @@ -6370,6 +6458,9 @@ and redisplay normally--don't erase and redraw the frame. */) | |||
| 6370 | /* Invalidate pixel data calculated for all compositions. */ | 6458 | /* Invalidate pixel data calculated for all compositions. */ |
| 6371 | for (i = 0; i < n_compositions; i++) | 6459 | for (i = 0; i < n_compositions; i++) |
| 6372 | composition_table[i]->font = NULL; | 6460 | composition_table[i]->font = NULL; |
| 6461 | #if defined (HAVE_WINDOW_SYSTEM) | ||
| 6462 | WINDOW_XFRAME (w)->minimize_tab_bar_window_p = 1; | ||
| 6463 | #endif | ||
| 6373 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) | 6464 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) |
| 6374 | WINDOW_XFRAME (w)->minimize_tool_bar_window_p = 1; | 6465 | WINDOW_XFRAME (w)->minimize_tool_bar_window_p = 1; |
| 6375 | #endif | 6466 | #endif |
| @@ -6686,13 +6777,13 @@ struct save_window_data | |||
| 6686 | 6777 | ||
| 6687 | /* We should be able to do without the following two. */ | 6778 | /* We should be able to do without the following two. */ |
| 6688 | int frame_cols, frame_lines; | 6779 | int frame_cols, frame_lines; |
| 6689 | /* These two should get eventually replaced by their pixel | 6780 | /* These three should get eventually replaced by their pixel |
| 6690 | counterparts. */ | 6781 | counterparts. */ |
| 6691 | int frame_menu_bar_lines, frame_tool_bar_lines; | 6782 | int frame_menu_bar_lines, frame_tab_bar_lines, frame_tool_bar_lines; |
| 6692 | int frame_text_width, frame_text_height; | 6783 | int frame_text_width, frame_text_height; |
| 6693 | /* These are currently unused. We need them as soon as we convert | 6784 | /* These are currently unused. We need them as soon as we convert |
| 6694 | to pixels. */ | 6785 | to pixels. */ |
| 6695 | int frame_menu_bar_height, frame_tool_bar_height; | 6786 | int frame_menu_bar_height, frame_tab_bar_height, frame_tool_bar_height; |
| 6696 | } GCALIGNED_STRUCT; | 6787 | } GCALIGNED_STRUCT; |
| 6697 | 6788 | ||
| 6698 | /* This is saved as a Lisp_Vector. */ | 6789 | /* This is saved as a Lisp_Vector. */ |
| @@ -7370,10 +7461,12 @@ saved by this function. */) | |||
| 7370 | data->frame_cols = FRAME_COLS (f); | 7461 | data->frame_cols = FRAME_COLS (f); |
| 7371 | data->frame_lines = FRAME_LINES (f); | 7462 | data->frame_lines = FRAME_LINES (f); |
| 7372 | data->frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f); | 7463 | data->frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f); |
| 7464 | data->frame_tab_bar_lines = FRAME_TAB_BAR_LINES (f); | ||
| 7373 | data->frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f); | 7465 | data->frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f); |
| 7374 | data->frame_text_width = FRAME_TEXT_WIDTH (f); | 7466 | data->frame_text_width = FRAME_TEXT_WIDTH (f); |
| 7375 | data->frame_text_height = FRAME_TEXT_HEIGHT (f); | 7467 | data->frame_text_height = FRAME_TEXT_HEIGHT (f); |
| 7376 | data->frame_menu_bar_height = FRAME_MENU_BAR_HEIGHT (f); | 7468 | data->frame_menu_bar_height = FRAME_MENU_BAR_HEIGHT (f); |
| 7469 | data->frame_tab_bar_height = FRAME_TAB_BAR_HEIGHT (f); | ||
| 7377 | data->frame_tool_bar_height = FRAME_TOOL_BAR_HEIGHT (f); | 7470 | data->frame_tool_bar_height = FRAME_TOOL_BAR_HEIGHT (f); |
| 7378 | data->selected_frame = selected_frame; | 7471 | data->selected_frame = selected_frame; |
| 7379 | data->current_window = FRAME_SELECTED_WINDOW (f); | 7472 | data->current_window = FRAME_SELECTED_WINDOW (f); |
| @@ -7663,6 +7756,7 @@ set_window_scroll_bars (struct window *w, Lisp_Object width, | |||
| 7663 | 7756 | ||
| 7664 | /* Don't change anything if new scroll bar won't fit. */ | 7757 | /* Don't change anything if new scroll bar won't fit. */ |
| 7665 | if ((WINDOW_PIXEL_HEIGHT (w) | 7758 | if ((WINDOW_PIXEL_HEIGHT (w) |
| 7759 | - WINDOW_TAB_LINE_HEIGHT (w) | ||
| 7666 | - WINDOW_HEADER_LINE_HEIGHT (w) | 7760 | - WINDOW_HEADER_LINE_HEIGHT (w) |
| 7667 | - WINDOW_MODE_LINE_HEIGHT (w) | 7761 | - WINDOW_MODE_LINE_HEIGHT (w) |
| 7668 | - (new_height == -1 ? FRAME_SCROLL_BAR_AREA_HEIGHT (f) : new_height)) | 7762 | - (new_height == -1 ? FRAME_SCROLL_BAR_AREA_HEIGHT (f) : new_height)) |
| @@ -8086,6 +8180,7 @@ syms_of_window (void) | |||
| 8086 | DEFSYM (Qmark_for_redisplay, "mark-for-redisplay"); | 8180 | DEFSYM (Qmark_for_redisplay, "mark-for-redisplay"); |
| 8087 | DEFSYM (Qmode_line_format, "mode-line-format"); | 8181 | DEFSYM (Qmode_line_format, "mode-line-format"); |
| 8088 | DEFSYM (Qheader_line_format, "header-line-format"); | 8182 | DEFSYM (Qheader_line_format, "header-line-format"); |
| 8183 | DEFSYM (Qtab_line_format, "tab-line-format"); | ||
| 8089 | 8184 | ||
| 8090 | DEFVAR_LISP ("temp-buffer-show-function", Vtemp_buffer_show_function, | 8185 | DEFVAR_LISP ("temp-buffer-show-function", Vtemp_buffer_show_function, |
| 8091 | doc: /* Non-nil means call as function to display a help buffer. | 8186 | 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. */); | |||
| 8389 | defsubr (&Sset_window_redisplay_end_trigger); | 8484 | defsubr (&Sset_window_redisplay_end_trigger); |
| 8390 | defsubr (&Swindow_mode_line_height); | 8485 | defsubr (&Swindow_mode_line_height); |
| 8391 | defsubr (&Swindow_header_line_height); | 8486 | defsubr (&Swindow_header_line_height); |
| 8487 | defsubr (&Swindow_tab_line_height); | ||
| 8392 | defsubr (&Swindow_right_divider_width); | 8488 | defsubr (&Swindow_right_divider_width); |
| 8393 | defsubr (&Swindow_bottom_divider_width); | 8489 | defsubr (&Swindow_bottom_divider_width); |
| 8394 | defsubr (&Swindow_scroll_bar_width); | 8490 | defsubr (&Swindow_scroll_bar_width); |
diff --git a/src/window.h b/src/window.h index dfbc6385312..21d2f3d3671 100644 --- a/src/window.h +++ b/src/window.h | |||
| @@ -361,6 +361,9 @@ struct window | |||
| 361 | /* Effective height of the header line, or -1 if not known. */ | 361 | /* Effective height of the header line, or -1 if not known. */ |
| 362 | int header_line_height; | 362 | int header_line_height; |
| 363 | 363 | ||
| 364 | /* Effective height of the tab line, or -1 if not known. */ | ||
| 365 | int tab_line_height; | ||
| 366 | |||
| 364 | /* Z - the buffer position of the last glyph in the current | 367 | /* Z - the buffer position of the last glyph in the current |
| 365 | matrix of W. Only valid if window_end_valid is true. */ | 368 | matrix of W. Only valid if window_end_valid is true. */ |
| 366 | ptrdiff_t window_end_pos; | 369 | ptrdiff_t window_end_pos; |
| @@ -697,7 +700,7 @@ wset_next_buffers (struct window *w, Lisp_Object val) | |||
| 697 | (WINDOW_LEFT_EDGE_COL (W) + WINDOW_TOTAL_COLS (W)) | 700 | (WINDOW_LEFT_EDGE_COL (W) + WINDOW_TOTAL_COLS (W)) |
| 698 | 701 | ||
| 699 | /* Return the canonical frame line at which window W starts. | 702 | /* Return the canonical frame line at which window W starts. |
| 700 | This includes a header line, if any. */ | 703 | This includes a header/tab line, if any. */ |
| 701 | #define WINDOW_TOP_EDGE_LINE(W) (W)->top_line | 704 | #define WINDOW_TOP_EDGE_LINE(W) (W)->top_line |
| 702 | 705 | ||
| 703 | /* Return the canonical frame line before which window W ends. | 706 | /* Return the canonical frame line before which window W ends. |
| @@ -715,7 +718,7 @@ wset_next_buffers (struct window *w, Lisp_Object val) | |||
| 715 | (WINDOW_LEFT_PIXEL_EDGE (W) + WINDOW_PIXEL_WIDTH (W)) | 718 | (WINDOW_LEFT_PIXEL_EDGE (W) + WINDOW_PIXEL_WIDTH (W)) |
| 716 | 719 | ||
| 717 | /* Return the top pixel edge at which window W starts. | 720 | /* Return the top pixel edge at which window W starts. |
| 718 | This includes a header line, if any. */ | 721 | This includes a header/tab line, if any. */ |
| 719 | #define WINDOW_TOP_PIXEL_EDGE(W) (W)->pixel_top | 722 | #define WINDOW_TOP_PIXEL_EDGE(W) (W)->pixel_top |
| 720 | 723 | ||
| 721 | /* Return the bottom pixel edge before which window W ends. | 724 | /* Return the bottom pixel edge before which window W ends. |
| @@ -745,6 +748,15 @@ wset_next_buffers (struct window *w, Lisp_Object val) | |||
| 745 | #define WINDOW_MENU_BAR_P(W) false | 748 | #define WINDOW_MENU_BAR_P(W) false |
| 746 | #endif | 749 | #endif |
| 747 | 750 | ||
| 751 | /* True if W is a tab bar window. */ | ||
| 752 | #if defined (HAVE_WINDOW_SYSTEM) | ||
| 753 | #define WINDOW_TAB_BAR_P(W) \ | ||
| 754 | (WINDOWP (WINDOW_XFRAME (W)->tab_bar_window) \ | ||
| 755 | && (W) == XWINDOW (WINDOW_XFRAME (W)->tab_bar_window)) | ||
| 756 | #else | ||
| 757 | #define WINDOW_TAB_BAR_P(W) false | ||
| 758 | #endif | ||
| 759 | |||
| 748 | /* True if W is a tool bar window. */ | 760 | /* True if W is a tool bar window. */ |
| 749 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) | 761 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) |
| 750 | #define WINDOW_TOOL_BAR_P(W) \ | 762 | #define WINDOW_TOOL_BAR_P(W) \ |
| @@ -756,13 +768,13 @@ wset_next_buffers (struct window *w, Lisp_Object val) | |||
| 756 | 768 | ||
| 757 | /* Return the frame y-position at which window W starts. */ | 769 | /* Return the frame y-position at which window W starts. */ |
| 758 | #define WINDOW_TOP_EDGE_Y(W) \ | 770 | #define WINDOW_TOP_EDGE_Y(W) \ |
| 759 | (((WINDOW_MENU_BAR_P (W) || WINDOW_TOOL_BAR_P (W)) \ | 771 | (((WINDOW_MENU_BAR_P (W) || WINDOW_TAB_BAR_P (W) || WINDOW_TOOL_BAR_P (W)) \ |
| 760 | ? 0 : FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W))) \ | 772 | ? 0 : FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W))) \ |
| 761 | + WINDOW_TOP_PIXEL_EDGE (W)) | 773 | + WINDOW_TOP_PIXEL_EDGE (W)) |
| 762 | 774 | ||
| 763 | /* Return the frame y-position before which window W ends. */ | 775 | /* Return the frame y-position before which window W ends. */ |
| 764 | #define WINDOW_BOTTOM_EDGE_Y(W) \ | 776 | #define WINDOW_BOTTOM_EDGE_Y(W) \ |
| 765 | (((WINDOW_MENU_BAR_P (W) || WINDOW_TOOL_BAR_P (W)) \ | 777 | (((WINDOW_MENU_BAR_P (W) || WINDOW_TAB_BAR_P (W) || WINDOW_TOOL_BAR_P (W)) \ |
| 766 | ? 0 : FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W))) \ | 778 | ? 0 : FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W))) \ |
| 767 | + WINDOW_BOTTOM_PIXEL_EDGE (W)) | 779 | + WINDOW_BOTTOM_PIXEL_EDGE (W)) |
| 768 | 780 | ||
| @@ -996,6 +1008,16 @@ wset_next_buffers (struct window *w, Lisp_Object val) | |||
| 996 | #define WINDOW_HEADER_LINE_LINES(W) \ | 1008 | #define WINDOW_HEADER_LINE_LINES(W) \ |
| 997 | window_wants_header_line (W) | 1009 | window_wants_header_line (W) |
| 998 | 1010 | ||
| 1011 | /* Height in pixels of the tab line. | ||
| 1012 | Zero if W doesn't have a tab line. */ | ||
| 1013 | #define WINDOW_TAB_LINE_HEIGHT(W) \ | ||
| 1014 | (window_wants_tab_line (W) \ | ||
| 1015 | ? CURRENT_TAB_LINE_HEIGHT (W) \ | ||
| 1016 | : 0) | ||
| 1017 | |||
| 1018 | #define WINDOW_TAB_LINE_LINES(W) \ | ||
| 1019 | window_wants_tab_line (W) | ||
| 1020 | |||
| 999 | /* Pixel height of window W without mode line, bottom scroll bar and | 1021 | /* Pixel height of window W without mode line, bottom scroll bar and |
| 1000 | bottom divider. */ | 1022 | bottom divider. */ |
| 1001 | #define WINDOW_BOX_HEIGHT_NO_MODE_LINE(W) \ | 1023 | #define WINDOW_BOX_HEIGHT_NO_MODE_LINE(W) \ |
| @@ -1004,14 +1026,15 @@ wset_next_buffers (struct window *w, Lisp_Object val) | |||
| 1004 | - WINDOW_SCROLL_BAR_AREA_HEIGHT (W) \ | 1026 | - WINDOW_SCROLL_BAR_AREA_HEIGHT (W) \ |
| 1005 | - WINDOW_MODE_LINE_HEIGHT (W)) | 1027 | - WINDOW_MODE_LINE_HEIGHT (W)) |
| 1006 | 1028 | ||
| 1007 | /* Pixel height of window W without mode and header line and bottom | 1029 | /* Pixel height of window W without mode and header/tab line and bottom |
| 1008 | divider. */ | 1030 | divider. */ |
| 1009 | #define WINDOW_BOX_TEXT_HEIGHT(W) \ | 1031 | #define WINDOW_BOX_TEXT_HEIGHT(W) \ |
| 1010 | (WINDOW_PIXEL_HEIGHT ((W)) \ | 1032 | (WINDOW_PIXEL_HEIGHT ((W)) \ |
| 1011 | - WINDOW_BOTTOM_DIVIDER_WIDTH (W) \ | 1033 | - WINDOW_BOTTOM_DIVIDER_WIDTH (W) \ |
| 1012 | - WINDOW_SCROLL_BAR_AREA_HEIGHT (W) \ | 1034 | - WINDOW_SCROLL_BAR_AREA_HEIGHT (W) \ |
| 1013 | - WINDOW_MODE_LINE_HEIGHT (W) \ | 1035 | - WINDOW_MODE_LINE_HEIGHT (W) \ |
| 1014 | - WINDOW_HEADER_LINE_HEIGHT (W)) | 1036 | - WINDOW_HEADER_LINE_HEIGHT (W) \ |
| 1037 | - WINDOW_TAB_LINE_HEIGHT (W)) | ||
| 1015 | 1038 | ||
| 1016 | /* Return the frame position where the horizontal scroll bar of window W | 1039 | /* Return the frame position where the horizontal scroll bar of window W |
| 1017 | starts. */ | 1040 | starts. */ |
| @@ -1068,7 +1091,7 @@ extern Lisp_Object minibuf_selected_window; | |||
| 1068 | 1091 | ||
| 1069 | extern Lisp_Object make_window (void); | 1092 | extern Lisp_Object make_window (void); |
| 1070 | extern Lisp_Object window_from_coordinates (struct frame *, int, int, | 1093 | extern Lisp_Object window_from_coordinates (struct frame *, int, int, |
| 1071 | enum window_part *, bool); | 1094 | enum window_part *, bool, bool); |
| 1072 | extern void resize_frame_windows (struct frame *, int, bool); | 1095 | extern void resize_frame_windows (struct frame *, int, bool); |
| 1073 | extern void restore_window_configuration (Lisp_Object); | 1096 | extern void restore_window_configuration (Lisp_Object); |
| 1074 | extern void delete_all_child_windows (Lisp_Object); | 1097 | extern void delete_all_child_windows (Lisp_Object); |
| @@ -1158,6 +1181,7 @@ extern bool compare_window_configurations (Lisp_Object, Lisp_Object, bool); | |||
| 1158 | extern void mark_window_cursors_off (struct window *); | 1181 | extern void mark_window_cursors_off (struct window *); |
| 1159 | extern bool window_wants_mode_line (struct window *); | 1182 | extern bool window_wants_mode_line (struct window *); |
| 1160 | extern bool window_wants_header_line (struct window *); | 1183 | extern bool window_wants_header_line (struct window *); |
| 1184 | extern bool window_wants_tab_line (struct window *); | ||
| 1161 | extern int window_internal_height (struct window *); | 1185 | extern int window_internal_height (struct window *); |
| 1162 | extern int window_body_width (struct window *w, bool); | 1186 | extern int window_body_width (struct window *w, bool); |
| 1163 | enum margin_unit { MARGIN_IN_LINES, MARGIN_IN_PIXELS }; | 1187 | enum margin_unit { MARGIN_IN_LINES, MARGIN_IN_PIXELS }; |
diff --git a/src/xdisp.c b/src/xdisp.c index 95895ec3acb..89a72ff7511 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -947,6 +947,8 @@ static int store_mode_line_string (const char *, Lisp_Object, bool, int, int, | |||
| 947 | Lisp_Object); | 947 | Lisp_Object); |
| 948 | static const char *decode_mode_spec (struct window *, int, int, Lisp_Object *); | 948 | static const char *decode_mode_spec (struct window *, int, int, Lisp_Object *); |
| 949 | static void display_menu_bar (struct window *); | 949 | static void display_menu_bar (struct window *); |
| 950 | static void display_tab_bar (struct window *); | ||
| 951 | static void update_tab_bar (struct frame *, bool); | ||
| 950 | static ptrdiff_t display_count_lines (ptrdiff_t, ptrdiff_t, ptrdiff_t, | 952 | static ptrdiff_t display_count_lines (ptrdiff_t, ptrdiff_t, ptrdiff_t, |
| 951 | ptrdiff_t *); | 953 | ptrdiff_t *); |
| 952 | static void pint2str (register char *, register int, register ptrdiff_t); | 954 | static void pint2str (register char *, register int, register ptrdiff_t); |
| @@ -1080,7 +1082,7 @@ window_box_height (struct window *w) | |||
| 1080 | height -= WINDOW_BOTTOM_DIVIDER_WIDTH (w); | 1082 | height -= WINDOW_BOTTOM_DIVIDER_WIDTH (w); |
| 1081 | height -= WINDOW_SCROLL_BAR_AREA_HEIGHT (w); | 1083 | height -= WINDOW_SCROLL_BAR_AREA_HEIGHT (w); |
| 1082 | 1084 | ||
| 1083 | /* Note: the code below that determines the mode-line/header-line | 1085 | /* Note: the code below that determines the mode-line/header-line/tab-line |
| 1084 | height is essentially the same as that contained in the macro | 1086 | height is essentially the same as that contained in the macro |
| 1085 | CURRENT_{MODE,HEADER}_LINE_HEIGHT, except that it checks whether | 1087 | CURRENT_{MODE,HEADER}_LINE_HEIGHT, except that it checks whether |
| 1086 | the appropriate glyph row has its `mode_line_p' flag set, | 1088 | the appropriate glyph row has its `mode_line_p' flag set, |
| @@ -1098,6 +1100,18 @@ window_box_height (struct window *w) | |||
| 1098 | height -= estimate_mode_line_height (f, CURRENT_MODE_LINE_FACE_ID (w)); | 1100 | height -= estimate_mode_line_height (f, CURRENT_MODE_LINE_FACE_ID (w)); |
| 1099 | } | 1101 | } |
| 1100 | 1102 | ||
| 1103 | if (window_wants_tab_line (w)) | ||
| 1104 | { | ||
| 1105 | struct glyph_row *tl_row | ||
| 1106 | = (w->current_matrix && w->current_matrix->rows | ||
| 1107 | ? MATRIX_TAB_LINE_ROW (w->current_matrix) | ||
| 1108 | : 0); | ||
| 1109 | if (tl_row && tl_row->mode_line_p) | ||
| 1110 | height -= tl_row->height; | ||
| 1111 | else | ||
| 1112 | height -= estimate_mode_line_height (f, TAB_LINE_FACE_ID); | ||
| 1113 | } | ||
| 1114 | |||
| 1101 | if (window_wants_header_line (w)) | 1115 | if (window_wants_header_line (w)) |
| 1102 | { | 1116 | { |
| 1103 | struct glyph_row *hl_row | 1117 | struct glyph_row *hl_row |
| @@ -1210,6 +1224,8 @@ window_box (struct window *w, enum glyph_row_area area, int *box_x, | |||
| 1210 | if (box_y) | 1224 | if (box_y) |
| 1211 | { | 1225 | { |
| 1212 | *box_y = WINDOW_TOP_EDGE_Y (w); | 1226 | *box_y = WINDOW_TOP_EDGE_Y (w); |
| 1227 | if (window_wants_tab_line (w)) | ||
| 1228 | *box_y += CURRENT_TAB_LINE_HEIGHT (w); | ||
| 1213 | if (window_wants_header_line (w)) | 1229 | if (window_wants_header_line (w)) |
| 1214 | *box_y += CURRENT_HEADER_LINE_HEIGHT (w); | 1230 | *box_y += CURRENT_HEADER_LINE_HEIGHT (w); |
| 1215 | } | 1231 | } |
| @@ -1435,13 +1451,14 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y, | |||
| 1435 | 1451 | ||
| 1436 | /* Some Lisp hook could call us in the middle of redisplaying this | 1452 | /* Some Lisp hook could call us in the middle of redisplaying this |
| 1437 | very window. If, by some bad luck, we are retrying redisplay | 1453 | very window. If, by some bad luck, we are retrying redisplay |
| 1438 | because we found that the mode-line height and/or header-line | 1454 | because we found that the mode-line height and/or tab/header-line |
| 1439 | height needs to be updated, the assignment of mode_line_height | 1455 | height needs to be updated, the assignment of mode_line_height |
| 1440 | and header_line_height below could disrupt that, due to the | 1456 | and header_line_height below could disrupt that, due to the |
| 1441 | selected/nonselected window dance during mode-line display, and | 1457 | selected/nonselected window dance during mode-line display, and |
| 1442 | we could infloop. Avoid that. */ | 1458 | we could infloop. Avoid that. */ |
| 1443 | int prev_mode_line_height = w->mode_line_height; | 1459 | int prev_mode_line_height = w->mode_line_height; |
| 1444 | int prev_header_line_height = w->header_line_height; | 1460 | int prev_header_line_height = w->header_line_height; |
| 1461 | int prev_tab_line_height = w->tab_line_height; | ||
| 1445 | /* Compute exact mode line heights. */ | 1462 | /* Compute exact mode line heights. */ |
| 1446 | if (window_wants_mode_line (w)) | 1463 | if (window_wants_mode_line (w)) |
| 1447 | { | 1464 | { |
| @@ -1455,6 +1472,18 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y, | |||
| 1455 | : window_mode_line_format); | 1472 | : window_mode_line_format); |
| 1456 | } | 1473 | } |
| 1457 | 1474 | ||
| 1475 | if (window_wants_tab_line (w)) | ||
| 1476 | { | ||
| 1477 | Lisp_Object window_tab_line_format | ||
| 1478 | = window_parameter (w, Qtab_line_format); | ||
| 1479 | |||
| 1480 | w->tab_line_height | ||
| 1481 | = display_mode_line (w, TAB_LINE_FACE_ID, | ||
| 1482 | NILP (window_tab_line_format) | ||
| 1483 | ? BVAR (current_buffer, tab_line_format) | ||
| 1484 | : window_tab_line_format); | ||
| 1485 | } | ||
| 1486 | |||
| 1458 | if (window_wants_header_line (w)) | 1487 | if (window_wants_header_line (w)) |
| 1459 | { | 1488 | { |
| 1460 | Lisp_Object window_header_line_format | 1489 | Lisp_Object window_header_line_format |
| @@ -1511,7 +1540,7 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y, | |||
| 1511 | glyph. */ | 1540 | glyph. */ |
| 1512 | int top_x = it.current_x; | 1541 | int top_x = it.current_x; |
| 1513 | int top_y = it.current_y; | 1542 | int top_y = it.current_y; |
| 1514 | int window_top_y = WINDOW_HEADER_LINE_HEIGHT (w); | 1543 | int window_top_y = WINDOW_TAB_LINE_HEIGHT (w) + WINDOW_HEADER_LINE_HEIGHT (w); |
| 1515 | int bottom_y; | 1544 | int bottom_y; |
| 1516 | struct it save_it; | 1545 | struct it save_it; |
| 1517 | void *save_it_data = NULL; | 1546 | void *save_it_data = NULL; |
| @@ -1779,7 +1808,8 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y, | |||
| 1779 | - it.last_visible_y)); | 1808 | - it.last_visible_y)); |
| 1780 | *rowh = max (0, (min (it2.current_y + it2.max_ascent + it2.max_descent, | 1809 | *rowh = max (0, (min (it2.current_y + it2.max_ascent + it2.max_descent, |
| 1781 | it.last_visible_y) | 1810 | it.last_visible_y) |
| 1782 | - max (it2.current_y, | 1811 | - max (max (it2.current_y, |
| 1812 | WINDOW_TAB_LINE_HEIGHT (w)), | ||
| 1783 | WINDOW_HEADER_LINE_HEIGHT (w)))); | 1813 | WINDOW_HEADER_LINE_HEIGHT (w)))); |
| 1784 | *vpos = it2.vpos; | 1814 | *vpos = it2.vpos; |
| 1785 | if (it2.bidi_it.paragraph_dir == R2L) | 1815 | if (it2.bidi_it.paragraph_dir == R2L) |
| @@ -1820,6 +1850,7 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y, | |||
| 1820 | /* Restore potentially overwritten values. */ | 1850 | /* Restore potentially overwritten values. */ |
| 1821 | w->mode_line_height = prev_mode_line_height; | 1851 | w->mode_line_height = prev_mode_line_height; |
| 1822 | w->header_line_height = prev_header_line_height; | 1852 | w->header_line_height = prev_header_line_height; |
| 1853 | w->tab_line_height = prev_tab_line_height; | ||
| 1823 | 1854 | ||
| 1824 | return visible_p; | 1855 | return visible_p; |
| 1825 | } | 1856 | } |
| @@ -2212,7 +2243,7 @@ get_glyph_string_clip_rects (struct glyph_string *s, NativeRectangle *rects, int | |||
| 2212 | intentionally draws over other lines. */ | 2243 | intentionally draws over other lines. */ |
| 2213 | if (s->for_overlaps) | 2244 | if (s->for_overlaps) |
| 2214 | { | 2245 | { |
| 2215 | r.y = WINDOW_HEADER_LINE_HEIGHT (s->w); | 2246 | r.y = WINDOW_TAB_LINE_HEIGHT (s->w) + WINDOW_HEADER_LINE_HEIGHT (s->w); |
| 2216 | r.height = window_text_bottom_y (s->w) - r.y; | 2247 | r.height = window_text_bottom_y (s->w) - r.y; |
| 2217 | 2248 | ||
| 2218 | /* Alas, the above simple strategy does not work for the | 2249 | /* Alas, the above simple strategy does not work for the |
| @@ -2239,7 +2270,7 @@ get_glyph_string_clip_rects (struct glyph_string *s, NativeRectangle *rects, int | |||
| 2239 | partially visible lines at the top of a window. */ | 2270 | partially visible lines at the top of a window. */ |
| 2240 | if (!s->row->full_width_p | 2271 | if (!s->row->full_width_p |
| 2241 | && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row)) | 2272 | && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row)) |
| 2242 | r.y = WINDOW_HEADER_LINE_HEIGHT (s->w); | 2273 | r.y = WINDOW_TAB_LINE_HEIGHT (s->w) + WINDOW_HEADER_LINE_HEIGHT (s->w); |
| 2243 | else | 2274 | else |
| 2244 | r.y = max (0, s->row->y); | 2275 | r.y = max (0, s->row->y); |
| 2245 | } | 2276 | } |
| @@ -2416,7 +2447,7 @@ get_phys_cursor_geometry (struct window *w, struct glyph_row *row, | |||
| 2416 | h = min (h, row->height); | 2447 | h = min (h, row->height); |
| 2417 | h0 = min (h0, ascent + glyph->descent); | 2448 | h0 = min (h0, ascent + glyph->descent); |
| 2418 | 2449 | ||
| 2419 | y0 = WINDOW_HEADER_LINE_HEIGHT (w); | 2450 | y0 = WINDOW_TAB_LINE_HEIGHT (w) + WINDOW_HEADER_LINE_HEIGHT (w); |
| 2420 | if (y < y0) | 2451 | if (y < y0) |
| 2421 | { | 2452 | { |
| 2422 | h = max (h - (y0 - y) + 1, h0); | 2453 | h = max (h - (y0 - y) + 1, h0); |
| @@ -2460,7 +2491,7 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect) | |||
| 2460 | goto virtual_glyph; | 2491 | goto virtual_glyph; |
| 2461 | } | 2492 | } |
| 2462 | else if (!f->glyphs_initialized_p | 2493 | else if (!f->glyphs_initialized_p |
| 2463 | || (window = window_from_coordinates (f, gx, gy, &part, false), | 2494 | || (window = window_from_coordinates (f, gx, gy, &part, false, false), |
| 2464 | NILP (window))) | 2495 | NILP (window))) |
| 2465 | { | 2496 | { |
| 2466 | width = FRAME_SMALLEST_CHAR_WIDTH (f); | 2497 | width = FRAME_SMALLEST_CHAR_WIDTH (f); |
| @@ -2495,11 +2526,14 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect) | |||
| 2495 | area = RIGHT_MARGIN_AREA; | 2526 | area = RIGHT_MARGIN_AREA; |
| 2496 | goto text_glyph; | 2527 | goto text_glyph; |
| 2497 | 2528 | ||
| 2529 | case ON_TAB_LINE: | ||
| 2498 | case ON_HEADER_LINE: | 2530 | case ON_HEADER_LINE: |
| 2499 | case ON_MODE_LINE: | 2531 | case ON_MODE_LINE: |
| 2500 | gr = (part == ON_HEADER_LINE | 2532 | gr = (part == ON_TAB_LINE |
| 2501 | ? MATRIX_HEADER_LINE_ROW (w->current_matrix) | 2533 | ? MATRIX_TAB_LINE_ROW (w->current_matrix) |
| 2502 | : MATRIX_MODE_LINE_ROW (w->current_matrix)); | 2534 | : (part == ON_HEADER_LINE |
| 2535 | ? MATRIX_HEADER_LINE_ROW (w->current_matrix) | ||
| 2536 | : MATRIX_MODE_LINE_ROW (w->current_matrix))); | ||
| 2503 | gy = gr->y; | 2537 | gy = gr->y; |
| 2504 | area = TEXT_AREA; | 2538 | area = TEXT_AREA; |
| 2505 | goto text_glyph_row_found; | 2539 | goto text_glyph_row_found; |
| @@ -2545,7 +2579,8 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect) | |||
| 2545 | gx += (x / width) * width; | 2579 | gx += (x / width) * width; |
| 2546 | } | 2580 | } |
| 2547 | 2581 | ||
| 2548 | if (part != ON_MODE_LINE && part != ON_HEADER_LINE) | 2582 | if (part != ON_MODE_LINE && part != ON_HEADER_LINE |
| 2583 | && part != ON_TAB_LINE) | ||
| 2549 | { | 2584 | { |
| 2550 | gx += window_box_left_offset (w, area); | 2585 | gx += window_box_left_offset (w, area); |
| 2551 | /* Don't expand over the modeline to make sure the vertical | 2586 | /* Don't expand over the modeline to make sure the vertical |
| @@ -2560,7 +2595,8 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect) | |||
| 2560 | gx = (x / width) * width; | 2595 | gx = (x / width) * width; |
| 2561 | y -= gy; | 2596 | y -= gy; |
| 2562 | gy += (y / height) * height; | 2597 | gy += (y / height) * height; |
| 2563 | if (part != ON_MODE_LINE && part != ON_HEADER_LINE) | 2598 | if (part != ON_MODE_LINE && part != ON_HEADER_LINE |
| 2599 | && part != ON_TAB_LINE) | ||
| 2564 | /* See comment above. */ | 2600 | /* See comment above. */ |
| 2565 | height = min (height, | 2601 | height = min (height, |
| 2566 | max (0, WINDOW_BOX_HEIGHT_NO_MODE_LINE (w) - gy)); | 2602 | max (0, WINDOW_BOX_HEIGHT_NO_MODE_LINE (w) - gy)); |
| @@ -2920,8 +2956,14 @@ init_iterator (struct it *it, struct window *w, | |||
| 2920 | if (base_face_id == MODE_LINE_FACE_ID | 2956 | if (base_face_id == MODE_LINE_FACE_ID |
| 2921 | || base_face_id == MODE_LINE_INACTIVE_FACE_ID) | 2957 | || base_face_id == MODE_LINE_INACTIVE_FACE_ID) |
| 2922 | row = MATRIX_MODE_LINE_ROW (w->desired_matrix); | 2958 | row = MATRIX_MODE_LINE_ROW (w->desired_matrix); |
| 2959 | else if (base_face_id == TAB_LINE_FACE_ID) | ||
| 2960 | row = MATRIX_TAB_LINE_ROW (w->desired_matrix); | ||
| 2923 | else if (base_face_id == HEADER_LINE_FACE_ID) | 2961 | else if (base_face_id == HEADER_LINE_FACE_ID) |
| 2924 | row = MATRIX_HEADER_LINE_ROW (w->desired_matrix); | 2962 | { |
| 2963 | /* Header line row depends on whether tab line is enabled. */ | ||
| 2964 | w->desired_matrix->tab_line_p = window_wants_tab_line (w); | ||
| 2965 | row = MATRIX_HEADER_LINE_ROW (w->desired_matrix); | ||
| 2966 | } | ||
| 2925 | } | 2967 | } |
| 2926 | 2968 | ||
| 2927 | /* Clear IT, and set it->object and other IT's Lisp objects to Qnil. | 2969 | /* Clear IT, and set it->object and other IT's Lisp objects to Qnil. |
| @@ -3097,8 +3139,9 @@ init_iterator (struct it *it, struct window *w, | |||
| 3097 | it->last_visible_x -= it->continuation_pixel_width; | 3139 | it->last_visible_x -= it->continuation_pixel_width; |
| 3098 | } | 3140 | } |
| 3099 | 3141 | ||
| 3142 | it->tab_line_p = window_wants_tab_line (w); | ||
| 3100 | it->header_line_p = window_wants_header_line (w); | 3143 | it->header_line_p = window_wants_header_line (w); |
| 3101 | body_height = WINDOW_HEADER_LINE_HEIGHT (w); | 3144 | body_height = WINDOW_TAB_LINE_HEIGHT (w) + WINDOW_HEADER_LINE_HEIGHT (w); |
| 3102 | it->current_y = body_height + w->vscroll; | 3145 | it->current_y = body_height + w->vscroll; |
| 3103 | } | 3146 | } |
| 3104 | 3147 | ||
| @@ -3201,7 +3244,7 @@ void | |||
| 3201 | start_display (struct it *it, struct window *w, struct text_pos pos) | 3244 | start_display (struct it *it, struct window *w, struct text_pos pos) |
| 3202 | { | 3245 | { |
| 3203 | struct glyph_row *row; | 3246 | struct glyph_row *row; |
| 3204 | bool first_vpos = window_wants_header_line (w); | 3247 | int first_vpos = window_wants_tab_line (w) + window_wants_header_line (w); |
| 3205 | 3248 | ||
| 3206 | row = w->desired_matrix->rows + first_vpos; | 3249 | row = w->desired_matrix->rows + first_vpos; |
| 3207 | init_iterator (it, w, CHARPOS (pos), BYTEPOS (pos), row, DEFAULT_FACE_ID); | 3250 | init_iterator (it, w, CHARPOS (pos), BYTEPOS (pos), row, DEFAULT_FACE_ID); |
| @@ -10413,11 +10456,16 @@ include the height of both, if present, in the return value. */) | |||
| 10413 | /* Subtract height of header-line which was counted automatically by | 10456 | /* Subtract height of header-line which was counted automatically by |
| 10414 | start_display. */ | 10457 | start_display. */ |
| 10415 | y = it.current_y + it.max_ascent + it.max_descent | 10458 | y = it.current_y + it.max_ascent + it.max_descent |
| 10416 | - WINDOW_HEADER_LINE_HEIGHT (w); | 10459 | - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w); |
| 10417 | /* Don't return more than Y-LIMIT. */ | 10460 | /* Don't return more than Y-LIMIT. */ |
| 10418 | if (y > max_y) | 10461 | if (y > max_y) |
| 10419 | y = max_y; | 10462 | y = max_y; |
| 10420 | 10463 | ||
| 10464 | if (EQ (mode_and_header_line, Qtab_line) | ||
| 10465 | || EQ (mode_and_header_line, Qt)) | ||
| 10466 | /* Re-add height of tab-line as requested. */ | ||
| 10467 | y = y + WINDOW_TAB_LINE_HEIGHT (w); | ||
| 10468 | |||
| 10421 | if (EQ (mode_and_header_line, Qheader_line) | 10469 | if (EQ (mode_and_header_line, Qheader_line) |
| 10422 | || EQ (mode_and_header_line, Qt)) | 10470 | || EQ (mode_and_header_line, Qt)) |
| 10423 | /* Re-add height of header-line as requested. */ | 10471 | /* Re-add height of header-line as requested. */ |
| @@ -12363,6 +12411,7 @@ prepare_menu_bars (void) | |||
| 12363 | continue; | 12411 | continue; |
| 12364 | 12412 | ||
| 12365 | menu_bar_hooks_run = update_menu_bar (f, false, menu_bar_hooks_run); | 12413 | menu_bar_hooks_run = update_menu_bar (f, false, menu_bar_hooks_run); |
| 12414 | update_tab_bar (f, false); | ||
| 12366 | #ifdef HAVE_WINDOW_SYSTEM | 12415 | #ifdef HAVE_WINDOW_SYSTEM |
| 12367 | update_tool_bar (f, false); | 12416 | update_tool_bar (f, false); |
| 12368 | #endif | 12417 | #endif |
| @@ -12374,6 +12423,7 @@ prepare_menu_bars (void) | |||
| 12374 | { | 12423 | { |
| 12375 | struct frame *sf = SELECTED_FRAME (); | 12424 | struct frame *sf = SELECTED_FRAME (); |
| 12376 | update_menu_bar (sf, true, false); | 12425 | update_menu_bar (sf, true, false); |
| 12426 | update_tab_bar (sf, true); | ||
| 12377 | #ifdef HAVE_WINDOW_SYSTEM | 12427 | #ifdef HAVE_WINDOW_SYSTEM |
| 12378 | update_tool_bar (sf, true); | 12428 | update_tool_bar (sf, true); |
| 12379 | #endif | 12429 | #endif |
| @@ -12490,8 +12540,10 @@ update_menu_bar (struct frame *f, bool save_match_data, bool hooks_run) | |||
| 12490 | return hooks_run; | 12540 | return hooks_run; |
| 12491 | } | 12541 | } |
| 12492 | 12542 | ||
| 12543 | |||
| 12544 | |||
| 12493 | /*********************************************************************** | 12545 | /*********************************************************************** |
| 12494 | Tool-bars | 12546 | Tab-bars |
| 12495 | ***********************************************************************/ | 12547 | ***********************************************************************/ |
| 12496 | 12548 | ||
| 12497 | #ifdef HAVE_WINDOW_SYSTEM | 12549 | #ifdef HAVE_WINDOW_SYSTEM |
| @@ -12510,6 +12562,871 @@ fast_set_selected_frame (Lisp_Object frame) | |||
| 12510 | } | 12562 | } |
| 12511 | } | 12563 | } |
| 12512 | 12564 | ||
| 12565 | #endif /* HAVE_WINDOW_SYSTEM */ | ||
| 12566 | |||
| 12567 | /* Update the tab-bar item list for frame F. This has to be done | ||
| 12568 | before we start to fill in any display lines. Called from | ||
| 12569 | prepare_menu_bars. If SAVE_MATCH_DATA, we must save | ||
| 12570 | and restore it here. */ | ||
| 12571 | |||
| 12572 | static void | ||
| 12573 | update_tab_bar (struct frame *f, bool save_match_data) | ||
| 12574 | { | ||
| 12575 | bool do_update = false; | ||
| 12576 | |||
| 12577 | #ifdef HAVE_WINDOW_SYSTEM | ||
| 12578 | if (FRAME_WINDOW_P (f) && WINDOWP (f->tab_bar_window)) { | ||
| 12579 | if (WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window)) > 0) | ||
| 12580 | do_update = true; | ||
| 12581 | } | ||
| 12582 | else | ||
| 12583 | #endif | ||
| 12584 | if (FRAME_TAB_BAR_LINES (f) > 0) | ||
| 12585 | do_update = true; | ||
| 12586 | |||
| 12587 | if (do_update) | ||
| 12588 | { | ||
| 12589 | Lisp_Object window; | ||
| 12590 | struct window *w; | ||
| 12591 | |||
| 12592 | window = FRAME_SELECTED_WINDOW (f); | ||
| 12593 | w = XWINDOW (window); | ||
| 12594 | |||
| 12595 | /* If the user has switched buffers or windows, we need to | ||
| 12596 | recompute to reflect the new bindings. But we'll | ||
| 12597 | recompute when update_mode_lines is set too; that means | ||
| 12598 | that people can use force-mode-line-update to request | ||
| 12599 | that the menu bar be recomputed. The adverse effect on | ||
| 12600 | the rest of the redisplay algorithm is about the same as | ||
| 12601 | windows_or_buffers_changed anyway. */ | ||
| 12602 | if (windows_or_buffers_changed | ||
| 12603 | || w->update_mode_line | ||
| 12604 | || update_mode_lines | ||
| 12605 | || window_buffer_changed (w)) | ||
| 12606 | { | ||
| 12607 | struct buffer *prev = current_buffer; | ||
| 12608 | ptrdiff_t count = SPECPDL_INDEX (); | ||
| 12609 | Lisp_Object new_tab_bar; | ||
| 12610 | int new_n_tab_bar; | ||
| 12611 | |||
| 12612 | /* Set current_buffer to the buffer of the selected | ||
| 12613 | window of the frame, so that we get the right local | ||
| 12614 | keymaps. */ | ||
| 12615 | set_buffer_internal_1 (XBUFFER (w->contents)); | ||
| 12616 | |||
| 12617 | /* Save match data, if we must. */ | ||
| 12618 | if (save_match_data) | ||
| 12619 | record_unwind_save_match_data (); | ||
| 12620 | |||
| 12621 | /* Make sure that we don't accidentally use bogus keymaps. */ | ||
| 12622 | if (NILP (Voverriding_local_map_menu_flag)) | ||
| 12623 | { | ||
| 12624 | specbind (Qoverriding_terminal_local_map, Qnil); | ||
| 12625 | specbind (Qoverriding_local_map, Qnil); | ||
| 12626 | } | ||
| 12627 | |||
| 12628 | /* We must temporarily set the selected frame to this frame | ||
| 12629 | before calling tab_bar_items, because the calculation of | ||
| 12630 | the tab-bar keymap uses the selected frame (see | ||
| 12631 | `tab-bar-make-keymap' in tab-bar.el). */ | ||
| 12632 | eassert (EQ (selected_window, | ||
| 12633 | /* Since we only explicitly preserve selected_frame, | ||
| 12634 | check that selected_window would be redundant. */ | ||
| 12635 | XFRAME (selected_frame)->selected_window)); | ||
| 12636 | #ifdef HAVE_WINDOW_SYSTEM | ||
| 12637 | Lisp_Object frame; | ||
| 12638 | record_unwind_protect (fast_set_selected_frame, selected_frame); | ||
| 12639 | XSETFRAME (frame, f); | ||
| 12640 | fast_set_selected_frame (frame); | ||
| 12641 | #endif | ||
| 12642 | |||
| 12643 | /* Build desired tab-bar items from keymaps. */ | ||
| 12644 | new_tab_bar | ||
| 12645 | = tab_bar_items (Fcopy_sequence (f->tab_bar_items), | ||
| 12646 | &new_n_tab_bar); | ||
| 12647 | |||
| 12648 | /* Redisplay the tab-bar if we changed it. */ | ||
| 12649 | if (new_n_tab_bar != f->n_tab_bar_items | ||
| 12650 | || NILP (Fequal (new_tab_bar, f->tab_bar_items))) | ||
| 12651 | { | ||
| 12652 | /* Redisplay that happens asynchronously due to an expose event | ||
| 12653 | may access f->tab_bar_items. Make sure we update both | ||
| 12654 | variables within BLOCK_INPUT so no such event interrupts. */ | ||
| 12655 | block_input (); | ||
| 12656 | fset_tab_bar_items (f, new_tab_bar); | ||
| 12657 | f->n_tab_bar_items = new_n_tab_bar; | ||
| 12658 | w->update_mode_line = true; | ||
| 12659 | unblock_input (); | ||
| 12660 | } | ||
| 12661 | |||
| 12662 | unbind_to (count, Qnil); | ||
| 12663 | set_buffer_internal_1 (prev); | ||
| 12664 | } | ||
| 12665 | } | ||
| 12666 | } | ||
| 12667 | |||
| 12668 | /* Redisplay the tab bar in the frame for window W. | ||
| 12669 | |||
| 12670 | The tab bar of X frames that don't have X toolkit support is | ||
| 12671 | displayed in a special window W->frame->tab_bar_window. | ||
| 12672 | |||
| 12673 | The tab bar of terminal frames is treated specially as far as | ||
| 12674 | glyph matrices are concerned. Tab bar lines are not part of | ||
| 12675 | windows, so the update is done directly on the frame matrix rows | ||
| 12676 | for the tab bar. */ | ||
| 12677 | |||
| 12678 | static void | ||
| 12679 | display_tab_bar (struct window *w) | ||
| 12680 | { | ||
| 12681 | struct frame *f = XFRAME (WINDOW_FRAME (w)); | ||
| 12682 | struct it it; | ||
| 12683 | Lisp_Object items; | ||
| 12684 | int i; | ||
| 12685 | |||
| 12686 | /* Don't do all this for graphical frames. */ | ||
| 12687 | #ifdef HAVE_NTGUI | ||
| 12688 | if (FRAME_W32_P (f)) | ||
| 12689 | return; | ||
| 12690 | #endif | ||
| 12691 | #if defined (USE_X_TOOLKIT) || defined (USE_GTK) | ||
| 12692 | if (FRAME_X_P (f)) | ||
| 12693 | return; | ||
| 12694 | #endif | ||
| 12695 | |||
| 12696 | #ifdef HAVE_NS | ||
| 12697 | if (FRAME_NS_P (f)) | ||
| 12698 | return; | ||
| 12699 | #endif /* HAVE_NS */ | ||
| 12700 | |||
| 12701 | #if defined (USE_X_TOOLKIT) || defined (USE_GTK) | ||
| 12702 | eassert (!FRAME_WINDOW_P (f)); | ||
| 12703 | init_iterator (&it, w, -1, -1, f->desired_matrix->rows | ||
| 12704 | + (FRAME_MENU_BAR_LINES (f) > 0 ? 1 : 0), | ||
| 12705 | TAB_BAR_FACE_ID); | ||
| 12706 | it.first_visible_x = 0; | ||
| 12707 | it.last_visible_x = FRAME_PIXEL_WIDTH (f); | ||
| 12708 | #elif defined (HAVE_X_WINDOWS) /* X without toolkit. */ | ||
| 12709 | if (FRAME_WINDOW_P (f)) | ||
| 12710 | { | ||
| 12711 | /* Tab bar lines are displayed in the desired matrix of the | ||
| 12712 | dummy window tab_bar_window. */ | ||
| 12713 | struct window *tab_w; | ||
| 12714 | tab_w = XWINDOW (f->tab_bar_window); | ||
| 12715 | init_iterator (&it, tab_w, -1, -1, tab_w->desired_matrix->rows, | ||
| 12716 | TAB_BAR_FACE_ID); | ||
| 12717 | it.first_visible_x = 0; | ||
| 12718 | it.last_visible_x = FRAME_PIXEL_WIDTH (f); | ||
| 12719 | } | ||
| 12720 | else | ||
| 12721 | #endif /* not USE_X_TOOLKIT and not USE_GTK */ | ||
| 12722 | { | ||
| 12723 | /* This is a TTY frame, i.e. character hpos/vpos are used as | ||
| 12724 | pixel x/y. */ | ||
| 12725 | init_iterator (&it, w, -1, -1, f->desired_matrix->rows | ||
| 12726 | + (FRAME_MENU_BAR_LINES (f) > 0 ? 1 : 0), | ||
| 12727 | TAB_BAR_FACE_ID); | ||
| 12728 | it.first_visible_x = 0; | ||
| 12729 | it.last_visible_x = FRAME_COLS (f); | ||
| 12730 | } | ||
| 12731 | |||
| 12732 | /* FIXME: This should be controlled by a user option. See the | ||
| 12733 | comments in redisplay_tool_bar and display_mode_line about | ||
| 12734 | this. */ | ||
| 12735 | it.paragraph_embedding = L2R; | ||
| 12736 | |||
| 12737 | /* Clear all rows of the tab bar. */ | ||
| 12738 | for (i = 0; i < FRAME_TAB_BAR_LINES (f); ++i) | ||
| 12739 | { | ||
| 12740 | struct glyph_row *row = it.glyph_row + i; | ||
| 12741 | clear_glyph_row (row); | ||
| 12742 | row->enabled_p = true; | ||
| 12743 | row->full_width_p = true; | ||
| 12744 | row->reversed_p = false; | ||
| 12745 | } | ||
| 12746 | |||
| 12747 | /* Display all items of the tab bar. */ | ||
| 12748 | items = it.f->tab_bar_items; | ||
| 12749 | for (i = 0; i < it.f->n_tab_bar_items; ++i) | ||
| 12750 | { | ||
| 12751 | Lisp_Object string; | ||
| 12752 | |||
| 12753 | /* Stop at nil string. */ | ||
| 12754 | string = AREF (items, i * TAB_BAR_ITEM_NSLOTS + TAB_BAR_ITEM_CAPTION); | ||
| 12755 | if (NILP (string)) | ||
| 12756 | break; | ||
| 12757 | |||
| 12758 | if (it.current_x < it.last_visible_x) | ||
| 12759 | display_string (NULL, string, Qnil, 0, 0, &it, | ||
| 12760 | SCHARS (string), 0, 0, STRING_MULTIBYTE (string)); | ||
| 12761 | } | ||
| 12762 | |||
| 12763 | /* Fill out the line with spaces. */ | ||
| 12764 | if (it.current_x < it.last_visible_x) | ||
| 12765 | display_string ("", Qnil, Qnil, 0, 0, &it, -1, 0, 0, -1); | ||
| 12766 | |||
| 12767 | /* Compute the total height of the lines. */ | ||
| 12768 | compute_line_metrics (&it); | ||
| 12769 | } | ||
| 12770 | |||
| 12771 | #ifdef HAVE_WINDOW_SYSTEM | ||
| 12772 | |||
| 12773 | /* Set F->desired_tab_bar_string to a Lisp string representing frame | ||
| 12774 | F's desired tab-bar contents. F->tab_bar_items must have | ||
| 12775 | been set up previously by calling prepare_menu_bars. */ | ||
| 12776 | |||
| 12777 | static void | ||
| 12778 | build_desired_tab_bar_string (struct frame *f) | ||
| 12779 | { | ||
| 12780 | int i; | ||
| 12781 | Lisp_Object caption; | ||
| 12782 | |||
| 12783 | caption = Qnil; | ||
| 12784 | |||
| 12785 | /* Prepare F->desired_tab_bar_string. Make a new string. */ | ||
| 12786 | fset_desired_tab_bar_string (f, build_string ("")); | ||
| 12787 | |||
| 12788 | /* Put a `display' property on the string for the captions to display, | ||
| 12789 | put a `menu_item' property on tab-bar items with a value that | ||
| 12790 | is the index of the item in F's tab-bar item vector. */ | ||
| 12791 | for (i = 0; i < f->n_tab_bar_items; ++i) | ||
| 12792 | { | ||
| 12793 | #define PROP(IDX) \ | ||
| 12794 | AREF (f->tab_bar_items, i * TAB_BAR_ITEM_NSLOTS + (IDX)) | ||
| 12795 | |||
| 12796 | caption = Fcopy_sequence (PROP (TAB_BAR_ITEM_CAPTION)); | ||
| 12797 | |||
| 12798 | /* Put a `display' text property on the string for the caption to | ||
| 12799 | display. Put a `menu-item' property on the string that gives | ||
| 12800 | the start of this item's properties in the tab-bar items | ||
| 12801 | vector. */ | ||
| 12802 | AUTO_LIST2 (props, Qmenu_item, make_fixnum (i * TAB_BAR_ITEM_NSLOTS)); | ||
| 12803 | |||
| 12804 | Fadd_text_properties (make_fixnum (0), make_fixnum (SCHARS (caption)), | ||
| 12805 | props, caption); | ||
| 12806 | |||
| 12807 | f->desired_tab_bar_string = | ||
| 12808 | concat2 (f->desired_tab_bar_string, caption); | ||
| 12809 | |||
| 12810 | #undef PROP | ||
| 12811 | } | ||
| 12812 | } | ||
| 12813 | |||
| 12814 | |||
| 12815 | /* Display one line of the tab-bar of frame IT->f. | ||
| 12816 | |||
| 12817 | HEIGHT specifies the desired height of the tab-bar line. | ||
| 12818 | If the actual height of the glyph row is less than HEIGHT, the | ||
| 12819 | row's height is increased to HEIGHT, and the icons are centered | ||
| 12820 | vertically in the new height. | ||
| 12821 | |||
| 12822 | If HEIGHT is -1, we are counting needed tab-bar lines, so don't | ||
| 12823 | count a final empty row in case the tab-bar width exactly matches | ||
| 12824 | the window width. | ||
| 12825 | */ | ||
| 12826 | |||
| 12827 | static void | ||
| 12828 | display_tab_bar_line (struct it *it, int height) | ||
| 12829 | { | ||
| 12830 | struct glyph_row *row = it->glyph_row; | ||
| 12831 | int max_x = it->last_visible_x; | ||
| 12832 | struct glyph *last; | ||
| 12833 | |||
| 12834 | /* Don't extend on a previously drawn tab bar items (Bug#16058). */ | ||
| 12835 | clear_glyph_row (row); | ||
| 12836 | row->enabled_p = true; | ||
| 12837 | row->y = it->current_y; | ||
| 12838 | |||
| 12839 | /* Note that this isn't made use of if the face hasn't a box, | ||
| 12840 | so there's no need to check the face here. */ | ||
| 12841 | it->start_of_box_run_p = true; | ||
| 12842 | |||
| 12843 | while (it->current_x < max_x) | ||
| 12844 | { | ||
| 12845 | int x, n_glyphs_before, i, nglyphs; | ||
| 12846 | struct it it_before; | ||
| 12847 | |||
| 12848 | /* Get the next display element. */ | ||
| 12849 | if (!get_next_display_element (it)) | ||
| 12850 | { | ||
| 12851 | /* Don't count empty row if we are counting needed tab-bar lines. */ | ||
| 12852 | if (height < 0 && !it->hpos) | ||
| 12853 | return; | ||
| 12854 | break; | ||
| 12855 | } | ||
| 12856 | |||
| 12857 | /* Produce glyphs. */ | ||
| 12858 | n_glyphs_before = row->used[TEXT_AREA]; | ||
| 12859 | it_before = *it; | ||
| 12860 | |||
| 12861 | PRODUCE_GLYPHS (it); | ||
| 12862 | |||
| 12863 | nglyphs = row->used[TEXT_AREA] - n_glyphs_before; | ||
| 12864 | i = 0; | ||
| 12865 | x = it_before.current_x; | ||
| 12866 | while (i < nglyphs) | ||
| 12867 | { | ||
| 12868 | struct glyph *glyph = row->glyphs[TEXT_AREA] + n_glyphs_before + i; | ||
| 12869 | |||
| 12870 | if (x + glyph->pixel_width > max_x) | ||
| 12871 | { | ||
| 12872 | /* Glyph doesn't fit on line. Backtrack. */ | ||
| 12873 | row->used[TEXT_AREA] = n_glyphs_before; | ||
| 12874 | *it = it_before; | ||
| 12875 | /* If this is the only glyph on this line, it will never fit on the | ||
| 12876 | tab-bar, so skip it. But ensure there is at least one glyph, | ||
| 12877 | so we don't accidentally disable the tab-bar. */ | ||
| 12878 | if (n_glyphs_before == 0 | ||
| 12879 | && (it->vpos > 0 || IT_STRING_CHARPOS (*it) < it->end_charpos-1)) | ||
| 12880 | break; | ||
| 12881 | goto out; | ||
| 12882 | } | ||
| 12883 | |||
| 12884 | ++it->hpos; | ||
| 12885 | x += glyph->pixel_width; | ||
| 12886 | ++i; | ||
| 12887 | } | ||
| 12888 | |||
| 12889 | /* Stop at line end. */ | ||
| 12890 | if (ITERATOR_AT_END_OF_LINE_P (it)) | ||
| 12891 | break; | ||
| 12892 | |||
| 12893 | set_iterator_to_next (it, true); | ||
| 12894 | } | ||
| 12895 | |||
| 12896 | out:; | ||
| 12897 | |||
| 12898 | row->displays_text_p = row->used[TEXT_AREA] != 0; | ||
| 12899 | |||
| 12900 | /* Use default face for the border below the tab bar. | ||
| 12901 | |||
| 12902 | FIXME: When auto-resize-tab-bars is grow-only, there is | ||
| 12903 | no additional border below the possibly empty tab-bar lines. | ||
| 12904 | So to make the extra empty lines look "normal", we have to | ||
| 12905 | use the tab-bar face for the border too. */ | ||
| 12906 | if (!MATRIX_ROW_DISPLAYS_TEXT_P (row) | ||
| 12907 | && !EQ (Vauto_resize_tab_bars, Qgrow_only)) | ||
| 12908 | it->face_id = DEFAULT_FACE_ID; | ||
| 12909 | |||
| 12910 | extend_face_to_end_of_line (it); | ||
| 12911 | last = row->glyphs[TEXT_AREA] + row->used[TEXT_AREA] - 1; | ||
| 12912 | last->right_box_line_p = true; | ||
| 12913 | if (last == row->glyphs[TEXT_AREA]) | ||
| 12914 | last->left_box_line_p = true; | ||
| 12915 | |||
| 12916 | /* Make line the desired height and center it vertically. */ | ||
| 12917 | if ((height -= it->max_ascent + it->max_descent) > 0) | ||
| 12918 | { | ||
| 12919 | /* Don't add more than one line height. */ | ||
| 12920 | height %= FRAME_LINE_HEIGHT (it->f); | ||
| 12921 | it->max_ascent += height / 2; | ||
| 12922 | it->max_descent += (height + 1) / 2; | ||
| 12923 | } | ||
| 12924 | |||
| 12925 | compute_line_metrics (it); | ||
| 12926 | |||
| 12927 | /* If line is empty, make it occupy the rest of the tab-bar. */ | ||
| 12928 | if (!MATRIX_ROW_DISPLAYS_TEXT_P (row)) | ||
| 12929 | { | ||
| 12930 | row->height = row->phys_height = it->last_visible_y - row->y; | ||
| 12931 | row->visible_height = row->height; | ||
| 12932 | row->ascent = row->phys_ascent = 0; | ||
| 12933 | row->extra_line_spacing = 0; | ||
| 12934 | } | ||
| 12935 | |||
| 12936 | row->full_width_p = true; | ||
| 12937 | row->continued_p = false; | ||
| 12938 | row->truncated_on_left_p = false; | ||
| 12939 | row->truncated_on_right_p = false; | ||
| 12940 | |||
| 12941 | it->current_x = it->hpos = 0; | ||
| 12942 | it->current_y += row->height; | ||
| 12943 | ++it->vpos; | ||
| 12944 | ++it->glyph_row; | ||
| 12945 | } | ||
| 12946 | |||
| 12947 | |||
| 12948 | /* Value is the number of pixels needed to make all tab-bar items of | ||
| 12949 | frame F visible. The actual number of glyph rows needed is | ||
| 12950 | returned in *N_ROWS if non-NULL. */ | ||
| 12951 | static int | ||
| 12952 | tab_bar_height (struct frame *f, int *n_rows, bool pixelwise) | ||
| 12953 | { | ||
| 12954 | struct window *w = XWINDOW (f->tab_bar_window); | ||
| 12955 | struct it it; | ||
| 12956 | /* tab_bar_height is called from redisplay_tab_bar after building | ||
| 12957 | the desired matrix, so use (unused) mode-line row as temporary row to | ||
| 12958 | avoid destroying the first tab-bar row. */ | ||
| 12959 | struct glyph_row *temp_row = MATRIX_MODE_LINE_ROW (w->desired_matrix); | ||
| 12960 | |||
| 12961 | /* Initialize an iterator for iteration over | ||
| 12962 | F->desired_tab_bar_string in the tab-bar window of frame F. */ | ||
| 12963 | init_iterator (&it, w, -1, -1, temp_row, TAB_BAR_FACE_ID); | ||
| 12964 | temp_row->reversed_p = false; | ||
| 12965 | it.first_visible_x = 0; | ||
| 12966 | it.last_visible_x = WINDOW_PIXEL_WIDTH (w); | ||
| 12967 | reseat_to_string (&it, NULL, f->desired_tab_bar_string, | ||
| 12968 | 0, 0, 0, STRING_MULTIBYTE (f->desired_tab_bar_string)); | ||
| 12969 | it.paragraph_embedding = L2R; | ||
| 12970 | |||
| 12971 | while (!ITERATOR_AT_END_P (&it)) | ||
| 12972 | { | ||
| 12973 | clear_glyph_row (temp_row); | ||
| 12974 | it.glyph_row = temp_row; | ||
| 12975 | display_tab_bar_line (&it, -1); | ||
| 12976 | } | ||
| 12977 | clear_glyph_row (temp_row); | ||
| 12978 | |||
| 12979 | /* f->n_tab_bar_rows == 0 means "unknown"; -1 means no tab-bar. */ | ||
| 12980 | if (n_rows) | ||
| 12981 | *n_rows = it.vpos > 0 ? it.vpos : -1; | ||
| 12982 | |||
| 12983 | if (pixelwise) | ||
| 12984 | return it.current_y; | ||
| 12985 | else | ||
| 12986 | return (it.current_y + FRAME_LINE_HEIGHT (f) - 1) / FRAME_LINE_HEIGHT (f); | ||
| 12987 | } | ||
| 12988 | |||
| 12989 | DEFUN ("tab-bar-height", Ftab_bar_height, Stab_bar_height, | ||
| 12990 | 0, 2, 0, | ||
| 12991 | doc: /* Return the number of lines occupied by the tab bar of FRAME. | ||
| 12992 | If FRAME is nil or omitted, use the selected frame. Optional argument | ||
| 12993 | PIXELWISE non-nil means return the height of the tab bar in pixels. */) | ||
| 12994 | (Lisp_Object frame, Lisp_Object pixelwise) | ||
| 12995 | { | ||
| 12996 | int height = 0; | ||
| 12997 | |||
| 12998 | struct frame *f = decode_any_frame (frame); | ||
| 12999 | |||
| 13000 | if (WINDOWP (f->tab_bar_window) | ||
| 13001 | && WINDOW_PIXEL_HEIGHT (XWINDOW (f->tab_bar_window)) > 0) | ||
| 13002 | { | ||
| 13003 | update_tab_bar (f, true); | ||
| 13004 | if (f->n_tab_bar_items) | ||
| 13005 | { | ||
| 13006 | build_desired_tab_bar_string (f); | ||
| 13007 | height = tab_bar_height (f, NULL, !NILP (pixelwise)); | ||
| 13008 | } | ||
| 13009 | } | ||
| 13010 | |||
| 13011 | return make_fixnum (height); | ||
| 13012 | } | ||
| 13013 | |||
| 13014 | |||
| 13015 | /* Display the tab-bar of frame F. Value is true if tab-bar's | ||
| 13016 | height should be changed. */ | ||
| 13017 | static bool | ||
| 13018 | redisplay_tab_bar (struct frame *f) | ||
| 13019 | { | ||
| 13020 | f->tab_bar_redisplayed = true; | ||
| 13021 | |||
| 13022 | struct window *w; | ||
| 13023 | struct it it; | ||
| 13024 | struct glyph_row *row; | ||
| 13025 | |||
| 13026 | /* If frame hasn't a tab-bar window or if it is zero-height, don't | ||
| 13027 | do anything. This means you must start with tab-bar-lines | ||
| 13028 | non-zero to get the auto-sizing effect. Or in other words, you | ||
| 13029 | can turn off tab-bars by specifying tab-bar-lines zero. */ | ||
| 13030 | if (!WINDOWP (f->tab_bar_window) | ||
| 13031 | || (w = XWINDOW (f->tab_bar_window), | ||
| 13032 | WINDOW_TOTAL_LINES (w) == 0)) | ||
| 13033 | return false; | ||
| 13034 | |||
| 13035 | /* Set up an iterator for the tab-bar window. */ | ||
| 13036 | init_iterator (&it, w, -1, -1, w->desired_matrix->rows, TAB_BAR_FACE_ID); | ||
| 13037 | it.first_visible_x = 0; | ||
| 13038 | it.last_visible_x = WINDOW_PIXEL_WIDTH (w); | ||
| 13039 | row = it.glyph_row; | ||
| 13040 | row->reversed_p = false; | ||
| 13041 | |||
| 13042 | /* Build a string that represents the contents of the tab-bar. */ | ||
| 13043 | build_desired_tab_bar_string (f); | ||
| 13044 | reseat_to_string (&it, NULL, f->desired_tab_bar_string, 0, 0, 0, | ||
| 13045 | STRING_MULTIBYTE (f->desired_tab_bar_string)); | ||
| 13046 | /* FIXME: This should be controlled by a user option. But it | ||
| 13047 | doesn't make sense to have an R2L tab bar if the menu bar cannot | ||
| 13048 | be drawn also R2L, and making the menu bar R2L is tricky due | ||
| 13049 | tabkit-specific code that implements it. If an R2L tab bar is | ||
| 13050 | ever supported, display_tab_bar_line should also be augmented to | ||
| 13051 | call unproduce_glyphs like display_line and display_string | ||
| 13052 | do. */ | ||
| 13053 | it.paragraph_embedding = L2R; | ||
| 13054 | |||
| 13055 | if (f->n_tab_bar_rows == 0) | ||
| 13056 | { | ||
| 13057 | int new_height = tab_bar_height (f, &f->n_tab_bar_rows, true); | ||
| 13058 | |||
| 13059 | if (new_height != WINDOW_PIXEL_HEIGHT (w)) | ||
| 13060 | { | ||
| 13061 | if (FRAME_TERMINAL (f)->change_tab_bar_height_hook) | ||
| 13062 | FRAME_TERMINAL (f)->change_tab_bar_height_hook (f, new_height); | ||
| 13063 | frame_default_tab_bar_height = new_height; | ||
| 13064 | /* Always do that now. */ | ||
| 13065 | clear_glyph_matrix (w->desired_matrix); | ||
| 13066 | f->fonts_changed = true; | ||
| 13067 | return true; | ||
| 13068 | } | ||
| 13069 | } | ||
| 13070 | |||
| 13071 | /* Display as many lines as needed to display all tab-bar items. */ | ||
| 13072 | |||
| 13073 | if (f->n_tab_bar_rows > 0) | ||
| 13074 | { | ||
| 13075 | int border, rows, height, extra; | ||
| 13076 | |||
| 13077 | if (TYPE_RANGED_FIXNUMP (int, Vtab_bar_border)) | ||
| 13078 | border = XFIXNUM (Vtab_bar_border); | ||
| 13079 | else if (EQ (Vtab_bar_border, Qinternal_border_width)) | ||
| 13080 | border = FRAME_INTERNAL_BORDER_WIDTH (f); | ||
| 13081 | else if (EQ (Vtab_bar_border, Qborder_width)) | ||
| 13082 | border = f->border_width; | ||
| 13083 | else | ||
| 13084 | border = 0; | ||
| 13085 | if (border < 0) | ||
| 13086 | border = 0; | ||
| 13087 | |||
| 13088 | rows = f->n_tab_bar_rows; | ||
| 13089 | height = max (1, (it.last_visible_y - border) / rows); | ||
| 13090 | extra = it.last_visible_y - border - height * rows; | ||
| 13091 | |||
| 13092 | while (it.current_y < it.last_visible_y) | ||
| 13093 | { | ||
| 13094 | int h = 0; | ||
| 13095 | if (extra > 0 && rows-- > 0) | ||
| 13096 | { | ||
| 13097 | h = (extra + rows - 1) / rows; | ||
| 13098 | extra -= h; | ||
| 13099 | } | ||
| 13100 | display_tab_bar_line (&it, height + h); | ||
| 13101 | } | ||
| 13102 | } | ||
| 13103 | else | ||
| 13104 | { | ||
| 13105 | while (it.current_y < it.last_visible_y) | ||
| 13106 | display_tab_bar_line (&it, 0); | ||
| 13107 | } | ||
| 13108 | |||
| 13109 | /* It doesn't make much sense to try scrolling in the tab-bar | ||
| 13110 | window, so don't do it. */ | ||
| 13111 | w->desired_matrix->no_scrolling_p = true; | ||
| 13112 | w->must_be_updated_p = true; | ||
| 13113 | |||
| 13114 | if (!NILP (Vauto_resize_tab_bars)) | ||
| 13115 | { | ||
| 13116 | bool change_height_p = true; | ||
| 13117 | |||
| 13118 | /* If we couldn't display everything, change the tab-bar's | ||
| 13119 | height if there is room for more. */ | ||
| 13120 | if (IT_STRING_CHARPOS (it) < it.end_charpos) | ||
| 13121 | change_height_p = true; | ||
| 13122 | |||
| 13123 | /* We subtract 1 because display_tab_bar_line advances the | ||
| 13124 | glyph_row pointer before returning to its caller. We want to | ||
| 13125 | examine the last glyph row produced by | ||
| 13126 | display_tab_bar_line. */ | ||
| 13127 | row = it.glyph_row - 1; | ||
| 13128 | |||
| 13129 | /* If there are blank lines at the end, except for a partially | ||
| 13130 | visible blank line at the end that is smaller than | ||
| 13131 | FRAME_LINE_HEIGHT, change the tab-bar's height. */ | ||
| 13132 | if (!MATRIX_ROW_DISPLAYS_TEXT_P (row) | ||
| 13133 | && row->height >= FRAME_LINE_HEIGHT (f)) | ||
| 13134 | change_height_p = true; | ||
| 13135 | |||
| 13136 | /* If row displays tab-bar items, but is partially visible, | ||
| 13137 | change the tab-bar's height. */ | ||
| 13138 | if (MATRIX_ROW_DISPLAYS_TEXT_P (row) | ||
| 13139 | && MATRIX_ROW_BOTTOM_Y (row) > it.last_visible_y) | ||
| 13140 | change_height_p = true; | ||
| 13141 | |||
| 13142 | /* Resize windows as needed by changing the `tab-bar-lines' | ||
| 13143 | frame parameter. */ | ||
| 13144 | if (change_height_p) | ||
| 13145 | { | ||
| 13146 | int nrows; | ||
| 13147 | int new_height = tab_bar_height (f, &nrows, true); | ||
| 13148 | |||
| 13149 | change_height_p = ((EQ (Vauto_resize_tab_bars, Qgrow_only) | ||
| 13150 | && !f->minimize_tab_bar_window_p) | ||
| 13151 | ? (new_height > WINDOW_PIXEL_HEIGHT (w)) | ||
| 13152 | : (new_height != WINDOW_PIXEL_HEIGHT (w))); | ||
| 13153 | f->minimize_tab_bar_window_p = false; | ||
| 13154 | |||
| 13155 | if (change_height_p) | ||
| 13156 | { | ||
| 13157 | if (FRAME_TERMINAL (f)->change_tab_bar_height_hook) | ||
| 13158 | FRAME_TERMINAL (f)->change_tab_bar_height_hook (f, new_height); | ||
| 13159 | frame_default_tab_bar_height = new_height; | ||
| 13160 | clear_glyph_matrix (w->desired_matrix); | ||
| 13161 | f->n_tab_bar_rows = nrows; | ||
| 13162 | f->fonts_changed = true; | ||
| 13163 | |||
| 13164 | return true; | ||
| 13165 | } | ||
| 13166 | } | ||
| 13167 | } | ||
| 13168 | |||
| 13169 | f->minimize_tab_bar_window_p = false; | ||
| 13170 | return false; | ||
| 13171 | } | ||
| 13172 | |||
| 13173 | /* Get information about the tab-bar item which is displayed in GLYPH | ||
| 13174 | on frame F. Return in *PROP_IDX the index where tab-bar item | ||
| 13175 | properties start in F->tab_bar_items. Value is false if | ||
| 13176 | GLYPH doesn't display a tab-bar item. */ | ||
| 13177 | |||
| 13178 | static bool | ||
| 13179 | tab_bar_item_info (struct frame *f, struct glyph *glyph, int *prop_idx, bool *close_p) | ||
| 13180 | { | ||
| 13181 | Lisp_Object prop; | ||
| 13182 | int charpos; | ||
| 13183 | |||
| 13184 | /* This function can be called asynchronously, which means we must | ||
| 13185 | exclude any possibility that Fget_text_property signals an | ||
| 13186 | error. */ | ||
| 13187 | charpos = min (SCHARS (f->current_tab_bar_string), glyph->charpos); | ||
| 13188 | charpos = max (0, charpos); | ||
| 13189 | |||
| 13190 | /* Get the text property `menu-item' at pos. The value of that | ||
| 13191 | property is the start index of this item's properties in | ||
| 13192 | F->tab_bar_items. */ | ||
| 13193 | prop = Fget_text_property (make_fixnum (charpos), | ||
| 13194 | Qmenu_item, f->current_tab_bar_string); | ||
| 13195 | if (! FIXNUMP (prop)) | ||
| 13196 | return false; | ||
| 13197 | *prop_idx = XFIXNUM (prop); | ||
| 13198 | |||
| 13199 | *close_p = !NILP (Fget_text_property (make_fixnum (charpos), | ||
| 13200 | Qclose_tab, | ||
| 13201 | f->current_tab_bar_string)); | ||
| 13202 | |||
| 13203 | return true; | ||
| 13204 | } | ||
| 13205 | |||
| 13206 | |||
| 13207 | /* Get information about the tab-bar item at position X/Y on frame F. | ||
| 13208 | Return in *GLYPH a pointer to the glyph of the tab-bar item in | ||
| 13209 | the current matrix of the tab-bar window of F, or NULL if not | ||
| 13210 | on a tab-bar item. Return in *PROP_IDX the index of the tab-bar | ||
| 13211 | item in F->tab_bar_items. Value is | ||
| 13212 | |||
| 13213 | -1 if X/Y is not on a tab-bar item | ||
| 13214 | 0 if X/Y is on the same item that was highlighted before. | ||
| 13215 | 1 otherwise. */ | ||
| 13216 | |||
| 13217 | static int | ||
| 13218 | get_tab_bar_item (struct frame *f, int x, int y, struct glyph **glyph, | ||
| 13219 | int *hpos, int *vpos, int *prop_idx, bool *close_p) | ||
| 13220 | { | ||
| 13221 | Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); | ||
| 13222 | struct window *w = XWINDOW (f->tab_bar_window); | ||
| 13223 | int area; | ||
| 13224 | |||
| 13225 | /* Find the glyph under X/Y. */ | ||
| 13226 | *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, 0, 0, &area); | ||
| 13227 | if (*glyph == NULL) | ||
| 13228 | return -1; | ||
| 13229 | |||
| 13230 | /* Get the start of this tab-bar item's properties in | ||
| 13231 | f->tab_bar_items. */ | ||
| 13232 | if (!tab_bar_item_info (f, *glyph, prop_idx, close_p)) | ||
| 13233 | return -1; | ||
| 13234 | |||
| 13235 | /* Is mouse on the highlighted item? */ | ||
| 13236 | if (EQ (f->tab_bar_window, hlinfo->mouse_face_window) | ||
| 13237 | && *vpos >= hlinfo->mouse_face_beg_row | ||
| 13238 | && *vpos <= hlinfo->mouse_face_end_row | ||
| 13239 | && (*vpos > hlinfo->mouse_face_beg_row | ||
| 13240 | || *hpos >= hlinfo->mouse_face_beg_col) | ||
| 13241 | && (*vpos < hlinfo->mouse_face_end_row | ||
| 13242 | || *hpos < hlinfo->mouse_face_end_col | ||
| 13243 | || hlinfo->mouse_face_past_end)) | ||
| 13244 | return 0; | ||
| 13245 | |||
| 13246 | return 1; | ||
| 13247 | } | ||
| 13248 | |||
| 13249 | |||
| 13250 | /* EXPORT: | ||
| 13251 | Handle mouse button event on the tab-bar of frame F, at | ||
| 13252 | frame-relative coordinates X/Y. DOWN_P is true for a button press, | ||
| 13253 | false for button release. MODIFIERS is event modifiers for button | ||
| 13254 | release. */ | ||
| 13255 | |||
| 13256 | void | ||
| 13257 | handle_tab_bar_click (struct frame *f, int x, int y, bool down_p, | ||
| 13258 | int modifiers) | ||
| 13259 | { | ||
| 13260 | Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); | ||
| 13261 | struct window *w = XWINDOW (f->tab_bar_window); | ||
| 13262 | int hpos, vpos, prop_idx; | ||
| 13263 | bool close_p; | ||
| 13264 | struct glyph *glyph; | ||
| 13265 | Lisp_Object enabled_p; | ||
| 13266 | int ts; | ||
| 13267 | |||
| 13268 | /* If not on the highlighted tab-bar item, and mouse-highlight is | ||
| 13269 | non-nil, return. This is so we generate the tab-bar button | ||
| 13270 | click only when the mouse button is released on the same item as | ||
| 13271 | where it was pressed. However, when mouse-highlight is disabled, | ||
| 13272 | generate the click when the button is released regardless of the | ||
| 13273 | highlight, since tab-bar items are not highlighted in that | ||
| 13274 | case. */ | ||
| 13275 | frame_to_window_pixel_xy (w, &x, &y); | ||
| 13276 | ts = get_tab_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx, &close_p); | ||
| 13277 | if (ts == -1 | ||
| 13278 | || (ts != 0 && !NILP (Vmouse_highlight))) | ||
| 13279 | return; | ||
| 13280 | |||
| 13281 | /* When mouse-highlight is off, generate the click for the item | ||
| 13282 | where the button was pressed, disregarding where it was | ||
| 13283 | released. */ | ||
| 13284 | if (NILP (Vmouse_highlight) && !down_p) | ||
| 13285 | prop_idx = f->last_tab_bar_item; | ||
| 13286 | |||
| 13287 | /* If item is disabled, do nothing. */ | ||
| 13288 | enabled_p = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_ENABLED_P); | ||
| 13289 | if (NILP (enabled_p)) | ||
| 13290 | return; | ||
| 13291 | |||
| 13292 | if (down_p) | ||
| 13293 | { | ||
| 13294 | /* Show item in pressed state. */ | ||
| 13295 | if (!NILP (Vmouse_highlight)) | ||
| 13296 | show_mouse_face (hlinfo, DRAW_IMAGE_SUNKEN); | ||
| 13297 | f->last_tab_bar_item = prop_idx; | ||
| 13298 | } | ||
| 13299 | else | ||
| 13300 | { | ||
| 13301 | Lisp_Object key, frame; | ||
| 13302 | struct input_event event; | ||
| 13303 | EVENT_INIT (event); | ||
| 13304 | |||
| 13305 | /* Show item in released state. */ | ||
| 13306 | if (!NILP (Vmouse_highlight)) | ||
| 13307 | show_mouse_face (hlinfo, DRAW_IMAGE_RAISED); | ||
| 13308 | |||
| 13309 | key = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_KEY); | ||
| 13310 | |||
| 13311 | XSETFRAME (frame, f); | ||
| 13312 | event.kind = TAB_BAR_EVENT; | ||
| 13313 | event.frame_or_window = frame; | ||
| 13314 | event.arg = frame; | ||
| 13315 | kbd_buffer_store_event (&event); | ||
| 13316 | |||
| 13317 | event.kind = TAB_BAR_EVENT; | ||
| 13318 | event.frame_or_window = frame; | ||
| 13319 | event.arg = key; | ||
| 13320 | event.modifiers = close_p ? ctrl_modifier | modifiers : modifiers; | ||
| 13321 | kbd_buffer_store_event (&event); | ||
| 13322 | f->last_tab_bar_item = -1; | ||
| 13323 | } | ||
| 13324 | } | ||
| 13325 | |||
| 13326 | |||
| 13327 | /* Possibly highlight a tab-bar item on frame F when mouse moves to | ||
| 13328 | tab-bar window-relative coordinates X/Y. Called from | ||
| 13329 | note_mouse_highlight. */ | ||
| 13330 | |||
| 13331 | static void | ||
| 13332 | note_tab_bar_highlight (struct frame *f, int x, int y) | ||
| 13333 | { | ||
| 13334 | Lisp_Object window = f->tab_bar_window; | ||
| 13335 | struct window *w = XWINDOW (window); | ||
| 13336 | Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f); | ||
| 13337 | Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); | ||
| 13338 | int hpos, vpos; | ||
| 13339 | struct glyph *glyph; | ||
| 13340 | struct glyph_row *row; | ||
| 13341 | int i; | ||
| 13342 | Lisp_Object enabled_p; | ||
| 13343 | int prop_idx; | ||
| 13344 | bool close_p; | ||
| 13345 | enum draw_glyphs_face draw = DRAW_IMAGE_RAISED; | ||
| 13346 | bool mouse_down_p; | ||
| 13347 | int rc; | ||
| 13348 | |||
| 13349 | /* Function note_mouse_highlight is called with negative X/Y | ||
| 13350 | values when mouse moves outside of the frame. */ | ||
| 13351 | if (x <= 0 || y <= 0) | ||
| 13352 | { | ||
| 13353 | clear_mouse_face (hlinfo); | ||
| 13354 | return; | ||
| 13355 | } | ||
| 13356 | |||
| 13357 | rc = get_tab_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx, &close_p); | ||
| 13358 | if (rc < 0) | ||
| 13359 | { | ||
| 13360 | /* Not on tab-bar item. */ | ||
| 13361 | clear_mouse_face (hlinfo); | ||
| 13362 | return; | ||
| 13363 | } | ||
| 13364 | else if (rc == 0) | ||
| 13365 | /* On same tab-bar item as before. */ | ||
| 13366 | goto set_help_echo; | ||
| 13367 | |||
| 13368 | clear_mouse_face (hlinfo); | ||
| 13369 | |||
| 13370 | #ifndef HAVE_NS | ||
| 13371 | /* Mouse is down, but on different tab-bar item? */ | ||
| 13372 | mouse_down_p = (gui_mouse_grabbed (dpyinfo) | ||
| 13373 | && f == dpyinfo->last_mouse_frame); | ||
| 13374 | |||
| 13375 | if (mouse_down_p && f->last_tab_bar_item != prop_idx) | ||
| 13376 | return; | ||
| 13377 | |||
| 13378 | draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED; | ||
| 13379 | #else | ||
| 13380 | draw = DRAW_IMAGE_RAISED; | ||
| 13381 | #endif /* HAVE_NS */ | ||
| 13382 | |||
| 13383 | /* If tab-bar item is not enabled, don't highlight it. */ | ||
| 13384 | enabled_p = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_ENABLED_P); | ||
| 13385 | if (!NILP (enabled_p) && !NILP (Vmouse_highlight)) | ||
| 13386 | { | ||
| 13387 | /* Compute the x-position of the glyph. In front and past the | ||
| 13388 | image is a space. We include this in the highlighted area. */ | ||
| 13389 | row = MATRIX_ROW (w->current_matrix, vpos); | ||
| 13390 | for (i = x = 0; i < hpos; ++i) | ||
| 13391 | x += row->glyphs[TEXT_AREA][i].pixel_width; | ||
| 13392 | |||
| 13393 | /* Record this as the current active region. */ | ||
| 13394 | hlinfo->mouse_face_beg_col = hpos; | ||
| 13395 | hlinfo->mouse_face_beg_row = vpos; | ||
| 13396 | hlinfo->mouse_face_beg_x = x; | ||
| 13397 | hlinfo->mouse_face_past_end = false; | ||
| 13398 | |||
| 13399 | hlinfo->mouse_face_end_col = hpos + 1; | ||
| 13400 | hlinfo->mouse_face_end_row = vpos; | ||
| 13401 | hlinfo->mouse_face_end_x = x + glyph->pixel_width; | ||
| 13402 | hlinfo->mouse_face_window = window; | ||
| 13403 | hlinfo->mouse_face_face_id = TAB_BAR_FACE_ID; | ||
| 13404 | |||
| 13405 | /* Display it as active. */ | ||
| 13406 | show_mouse_face (hlinfo, draw); | ||
| 13407 | } | ||
| 13408 | |||
| 13409 | set_help_echo: | ||
| 13410 | |||
| 13411 | /* Set help_echo_string to a help string to display for this tab-bar item. | ||
| 13412 | XTread_socket does the rest. */ | ||
| 13413 | help_echo_object = help_echo_window = Qnil; | ||
| 13414 | help_echo_pos = -1; | ||
| 13415 | help_echo_string = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_HELP); | ||
| 13416 | if (NILP (help_echo_string)) | ||
| 13417 | help_echo_string = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_CAPTION); | ||
| 13418 | } | ||
| 13419 | |||
| 13420 | #endif /* HAVE_WINDOW_SYSTEM */ | ||
| 13421 | |||
| 13422 | |||
| 13423 | |||
| 13424 | /*********************************************************************** | ||
| 13425 | Tool-bars | ||
| 13426 | ***********************************************************************/ | ||
| 13427 | |||
| 13428 | #ifdef HAVE_WINDOW_SYSTEM | ||
| 13429 | |||
| 12513 | /* Update the tool-bar item list for frame F. This has to be done | 13430 | /* Update the tool-bar item list for frame F. This has to be done |
| 12514 | before we start to fill in any display lines. Called from | 13431 | before we start to fill in any display lines. Called from |
| 12515 | prepare_menu_bars. If SAVE_MATCH_DATA, we must save | 13432 | prepare_menu_bars. If SAVE_MATCH_DATA, we must save |
| @@ -16265,7 +17182,8 @@ compute_window_start_on_continuation_line (struct window *w) | |||
| 16265 | 17182 | ||
| 16266 | /* Find the start of the continued line. This should be fast | 17183 | /* Find the start of the continued line. This should be fast |
| 16267 | because find_newline is fast (newline cache). */ | 17184 | because find_newline is fast (newline cache). */ |
| 16268 | row = w->desired_matrix->rows + window_wants_header_line (w); | 17185 | row = w->desired_matrix->rows + window_wants_tab_line (w) |
| 17186 | + window_wants_header_line (w); | ||
| 16269 | init_iterator (&it, w, CHARPOS (start_pos), BYTEPOS (start_pos), | 17187 | init_iterator (&it, w, CHARPOS (start_pos), BYTEPOS (start_pos), |
| 16270 | row, DEFAULT_FACE_ID); | 17188 | row, DEFAULT_FACE_ID); |
| 16271 | reseat_at_previous_visible_line_start (&it); | 17189 | reseat_at_previous_visible_line_start (&it); |
| @@ -16428,6 +17346,8 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, | |||
| 16428 | this_scroll_margin = window_scroll_margin (w, MARGIN_IN_PIXELS); | 17346 | this_scroll_margin = window_scroll_margin (w, MARGIN_IN_PIXELS); |
| 16429 | 17347 | ||
| 16430 | top_scroll_margin = this_scroll_margin; | 17348 | top_scroll_margin = this_scroll_margin; |
| 17349 | if (window_wants_tab_line (w)) | ||
| 17350 | top_scroll_margin += CURRENT_TAB_LINE_HEIGHT (w); | ||
| 16431 | if (window_wants_header_line (w)) | 17351 | if (window_wants_header_line (w)) |
| 16432 | top_scroll_margin += CURRENT_HEADER_LINE_HEIGHT (w); | 17352 | top_scroll_margin += CURRENT_HEADER_LINE_HEIGHT (w); |
| 16433 | 17353 | ||
| @@ -17197,13 +18117,14 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) | |||
| 17197 | margin, even though this part handles windows that didn't | 18117 | margin, even though this part handles windows that didn't |
| 17198 | scroll at all. */ | 18118 | scroll at all. */ |
| 17199 | int pixel_margin = margin * frame_line_height; | 18119 | int pixel_margin = margin * frame_line_height; |
| 18120 | bool tab_line = window_wants_tab_line (w); | ||
| 17200 | bool header_line = window_wants_header_line (w); | 18121 | bool header_line = window_wants_header_line (w); |
| 17201 | 18122 | ||
| 17202 | /* Note: We add an extra FRAME_LINE_HEIGHT, because the loop | 18123 | /* Note: We add an extra FRAME_LINE_HEIGHT, because the loop |
| 17203 | below, which finds the row to move point to, advances by | 18124 | below, which finds the row to move point to, advances by |
| 17204 | the Y coordinate of the _next_ row, see the definition of | 18125 | the Y coordinate of the _next_ row, see the definition of |
| 17205 | MATRIX_ROW_BOTTOM_Y. */ | 18126 | MATRIX_ROW_BOTTOM_Y. */ |
| 17206 | if (w->cursor.vpos < margin + header_line) | 18127 | if (w->cursor.vpos < margin + tab_line + header_line) |
| 17207 | { | 18128 | { |
| 17208 | w->cursor.vpos = -1; | 18129 | w->cursor.vpos = -1; |
| 17209 | clear_glyph_matrix (w->desired_matrix); | 18130 | clear_glyph_matrix (w->desired_matrix); |
| @@ -17213,6 +18134,8 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) | |||
| 17213 | { | 18134 | { |
| 17214 | int window_height = window_box_height (w); | 18135 | int window_height = window_box_height (w); |
| 17215 | 18136 | ||
| 18137 | if (tab_line) | ||
| 18138 | window_height += CURRENT_TAB_LINE_HEIGHT (w); | ||
| 17216 | if (header_line) | 18139 | if (header_line) |
| 17217 | window_height += CURRENT_HEADER_LINE_HEIGHT (w); | 18140 | window_height += CURRENT_HEADER_LINE_HEIGHT (w); |
| 17218 | if (w->cursor.y >= window_height - pixel_margin) | 18141 | if (w->cursor.y >= window_height - pixel_margin) |
| @@ -17544,7 +18467,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) | |||
| 17544 | centering_position -= pt_offset; | 18467 | centering_position -= pt_offset; |
| 17545 | centering_position -= | 18468 | centering_position -= |
| 17546 | (frame_line_height * (1 + margin + last_line_misfit) | 18469 | (frame_line_height * (1 + margin + last_line_misfit) |
| 17547 | + WINDOW_HEADER_LINE_HEIGHT (w)); | 18470 | + WINDOW_TAB_LINE_HEIGHT (w) + WINDOW_HEADER_LINE_HEIGHT (w)); |
| 17548 | /* Don't let point enter the scroll margin near top of | 18471 | /* Don't let point enter the scroll margin near top of |
| 17549 | the window. */ | 18472 | the window. */ |
| 17550 | if (centering_position < margin * frame_line_height) | 18473 | if (centering_position < margin * frame_line_height) |
| @@ -17772,7 +18695,8 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) | |||
| 17772 | && (w->column_number_displayed != current_column ()))) | 18695 | && (w->column_number_displayed != current_column ()))) |
| 17773 | /* This means that the window has a mode line. */ | 18696 | /* This means that the window has a mode line. */ |
| 17774 | && (window_wants_mode_line (w) | 18697 | && (window_wants_mode_line (w) |
| 17775 | || window_wants_header_line (w))) | 18698 | || window_wants_header_line (w) |
| 18699 | || window_wants_tab_line (w))) | ||
| 17776 | { | 18700 | { |
| 17777 | 18701 | ||
| 17778 | display_mode_lines (w); | 18702 | display_mode_lines (w); |
| @@ -17788,6 +18712,17 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) | |||
| 17788 | = DESIRED_MODE_LINE_HEIGHT (w); | 18712 | = DESIRED_MODE_LINE_HEIGHT (w); |
| 17789 | } | 18713 | } |
| 17790 | 18714 | ||
| 18715 | /* If tab line height has changed, arrange for a thorough | ||
| 18716 | immediate redisplay using the correct tab line height. */ | ||
| 18717 | if (window_wants_tab_line (w) | ||
| 18718 | && CURRENT_TAB_LINE_HEIGHT (w) != DESIRED_TAB_LINE_HEIGHT (w)) | ||
| 18719 | { | ||
| 18720 | f->fonts_changed = true; | ||
| 18721 | w->tab_line_height = -1; | ||
| 18722 | MATRIX_TAB_LINE_ROW (w->current_matrix)->height | ||
| 18723 | = DESIRED_TAB_LINE_HEIGHT (w); | ||
| 18724 | } | ||
| 18725 | |||
| 17791 | /* If header line height has changed, arrange for a thorough | 18726 | /* If header line height has changed, arrange for a thorough |
| 17792 | immediate redisplay using the correct header line height. */ | 18727 | immediate redisplay using the correct header line height. */ |
| 17793 | if (window_wants_header_line (w) | 18728 | if (window_wants_header_line (w) |
| @@ -17835,6 +18770,12 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) | |||
| 17835 | #ifdef HAVE_WINDOW_SYSTEM | 18770 | #ifdef HAVE_WINDOW_SYSTEM |
| 17836 | if (FRAME_WINDOW_P (f)) | 18771 | if (FRAME_WINDOW_P (f)) |
| 17837 | { | 18772 | { |
| 18773 | if (WINDOWP (f->tab_bar_window) | ||
| 18774 | && (FRAME_TAB_BAR_LINES (f) > 0 | ||
| 18775 | || !NILP (Vauto_resize_tab_bars)) | ||
| 18776 | && redisplay_tab_bar (f)) | ||
| 18777 | ignore_mouse_drag_p = true; | ||
| 18778 | |||
| 17838 | #ifdef HAVE_EXT_TOOL_BAR | 18779 | #ifdef HAVE_EXT_TOOL_BAR |
| 17839 | if (FRAME_EXTERNAL_TOOL_BAR (f)) | 18780 | if (FRAME_EXTERNAL_TOOL_BAR (f)) |
| 17840 | redisplay_tool_bar (f); | 18781 | redisplay_tool_bar (f); |
| @@ -17846,7 +18787,16 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) | |||
| 17846 | ignore_mouse_drag_p = true; | 18787 | ignore_mouse_drag_p = true; |
| 17847 | #endif | 18788 | #endif |
| 17848 | } | 18789 | } |
| 18790 | else | ||
| 18791 | { | ||
| 18792 | if ((FRAME_TAB_BAR_LINES (f) > 0)) | ||
| 18793 | display_tab_bar (w); | ||
| 18794 | } | ||
| 18795 | |||
| 17849 | gui_consider_frame_title (w->frame); | 18796 | gui_consider_frame_title (w->frame); |
| 18797 | #else | ||
| 18798 | if ((FRAME_TAB_BAR_LINES (f) > 0)) | ||
| 18799 | display_tab_bar (w); | ||
| 17850 | #endif | 18800 | #endif |
| 17851 | } | 18801 | } |
| 17852 | 18802 | ||
| @@ -18058,6 +19008,11 @@ try_window_reusing_current_matrix (struct window *w) | |||
| 18058 | return false; | 19008 | return false; |
| 18059 | 19009 | ||
| 18060 | /* If top-line visibility has changed, give up. */ | 19010 | /* If top-line visibility has changed, give up. */ |
| 19011 | if (window_wants_tab_line (w) | ||
| 19012 | != MATRIX_TAB_LINE_ROW (w->current_matrix)->mode_line_p) | ||
| 19013 | return false; | ||
| 19014 | |||
| 19015 | /* If top-line visibility has changed, give up. */ | ||
| 18061 | if (window_wants_header_line (w) | 19016 | if (window_wants_header_line (w) |
| 18062 | != MATRIX_HEADER_LINE_ROW (w->current_matrix)->mode_line_p) | 19017 | != MATRIX_HEADER_LINE_ROW (w->current_matrix)->mode_line_p) |
| 18063 | return false; | 19018 | return false; |
| @@ -18202,7 +19157,7 @@ try_window_reusing_current_matrix (struct window *w) | |||
| 18202 | (start_row + i)->enabled_p = false; | 19157 | (start_row + i)->enabled_p = false; |
| 18203 | 19158 | ||
| 18204 | /* Re-compute Y positions. */ | 19159 | /* Re-compute Y positions. */ |
| 18205 | min_y = WINDOW_HEADER_LINE_HEIGHT (w); | 19160 | min_y = WINDOW_TAB_LINE_HEIGHT (w) + WINDOW_HEADER_LINE_HEIGHT (w); |
| 18206 | max_y = it.last_visible_y; | 19161 | max_y = it.last_visible_y; |
| 18207 | for (row = start_row + nrows_scrolled; | 19162 | for (row = start_row + nrows_scrolled; |
| 18208 | row < bottom_row; | 19163 | row < bottom_row; |
| @@ -18229,7 +19184,7 @@ try_window_reusing_current_matrix (struct window *w) | |||
| 18229 | /* Disable lines in the current matrix which are now | 19184 | /* Disable lines in the current matrix which are now |
| 18230 | below the window. */ | 19185 | below the window. */ |
| 18231 | for (++row; row < bottom_row; ++row) | 19186 | for (++row; row < bottom_row; ++row) |
| 18232 | row->enabled_p = row->mode_line_p = false; | 19187 | row->enabled_p = row->mode_line_p = row->tab_line_p = false; |
| 18233 | } | 19188 | } |
| 18234 | 19189 | ||
| 18235 | /* Update window_end_pos etc.; last_reused_text_row is the last | 19190 | /* Update window_end_pos etc.; last_reused_text_row is the last |
| @@ -18307,7 +19262,7 @@ try_window_reusing_current_matrix (struct window *w) | |||
| 18307 | it.vpos = (MATRIX_ROW_VPOS (first_row_to_display, w->current_matrix) | 19262 | it.vpos = (MATRIX_ROW_VPOS (first_row_to_display, w->current_matrix) |
| 18308 | - nrows_scrolled); | 19263 | - nrows_scrolled); |
| 18309 | it.current_y = (first_row_to_display->y - first_reusable_row->y | 19264 | it.current_y = (first_row_to_display->y - first_reusable_row->y |
| 18310 | + WINDOW_HEADER_LINE_HEIGHT (w)); | 19265 | + WINDOW_TAB_LINE_HEIGHT (w) + WINDOW_HEADER_LINE_HEIGHT (w)); |
| 18311 | 19266 | ||
| 18312 | /* Display lines beginning with first_row_to_display in the | 19267 | /* Display lines beginning with first_row_to_display in the |
| 18313 | desired matrix. Set last_text_row to the last row displayed | 19268 | desired matrix. Set last_text_row to the last row displayed |
| @@ -18340,7 +19295,7 @@ try_window_reusing_current_matrix (struct window *w) | |||
| 18340 | 19295 | ||
| 18341 | /* Scroll the display. */ | 19296 | /* Scroll the display. */ |
| 18342 | run.current_y = first_reusable_row->y; | 19297 | run.current_y = first_reusable_row->y; |
| 18343 | run.desired_y = WINDOW_HEADER_LINE_HEIGHT (w); | 19298 | run.desired_y = WINDOW_TAB_LINE_HEIGHT (w) + WINDOW_HEADER_LINE_HEIGHT (w); |
| 18344 | run.height = it.last_visible_y - run.current_y; | 19299 | run.height = it.last_visible_y - run.current_y; |
| 18345 | dy = run.current_y - run.desired_y; | 19300 | dy = run.current_y - run.desired_y; |
| 18346 | 19301 | ||
| @@ -18358,7 +19313,7 @@ try_window_reusing_current_matrix (struct window *w) | |||
| 18358 | 19313 | ||
| 18359 | /* Adjust Y positions of reused rows. */ | 19314 | /* Adjust Y positions of reused rows. */ |
| 18360 | bottom_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w); | 19315 | bottom_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w); |
| 18361 | min_y = WINDOW_HEADER_LINE_HEIGHT (w); | 19316 | min_y = WINDOW_TAB_LINE_HEIGHT (w) + WINDOW_HEADER_LINE_HEIGHT (w); |
| 18362 | max_y = it.last_visible_y; | 19317 | max_y = it.last_visible_y; |
| 18363 | for (row = first_reusable_row; row < first_row_to_display; ++row) | 19318 | for (row = first_reusable_row; row < first_row_to_display; ++row) |
| 18364 | { | 19319 | { |
| @@ -19316,6 +20271,7 @@ try_window_id (struct window *w) | |||
| 19316 | = MATRIX_ROW_VPOS (first_unchanged_at_end_row, w->current_matrix); | 20271 | = MATRIX_ROW_VPOS (first_unchanged_at_end_row, w->current_matrix); |
| 19317 | int from = WINDOW_TOP_EDGE_LINE (w) + from_vpos; | 20272 | int from = WINDOW_TOP_EDGE_LINE (w) + from_vpos; |
| 19318 | int end = (WINDOW_TOP_EDGE_LINE (w) | 20273 | int end = (WINDOW_TOP_EDGE_LINE (w) |
| 20274 | + window_wants_tab_line (w) | ||
| 19319 | + window_wants_header_line (w) | 20275 | + window_wants_header_line (w) |
| 19320 | + window_internal_height (w)); | 20276 | + window_internal_height (w)); |
| 19321 | 20277 | ||
| @@ -19494,7 +20450,7 @@ try_window_id (struct window *w) | |||
| 19494 | { | 20450 | { |
| 19495 | /* Displayed to end of window, but no line containing text was | 20451 | /* Displayed to end of window, but no line containing text was |
| 19496 | displayed. Lines were deleted at the end of the window. */ | 20452 | displayed. Lines were deleted at the end of the window. */ |
| 19497 | bool first_vpos = window_wants_header_line (w); | 20453 | int first_vpos = window_wants_tab_line (w) + window_wants_header_line (w); |
| 19498 | int vpos = w->window_end_vpos; | 20454 | int vpos = w->window_end_vpos; |
| 19499 | struct glyph_row *current_row = current_matrix->rows + vpos; | 20455 | struct glyph_row *current_row = current_matrix->rows + vpos; |
| 19500 | struct glyph_row *desired_row = desired_matrix->rows + vpos; | 20456 | struct glyph_row *desired_row = desired_matrix->rows + vpos; |
| @@ -19866,6 +20822,39 @@ GLYPHS > 1 or omitted means dump glyphs in long form. */) | |||
| 19866 | } | 20822 | } |
| 19867 | 20823 | ||
| 19868 | 20824 | ||
| 20825 | DEFUN ("dump-tab-bar-row", Fdump_tab_bar_row, Sdump_tab_bar_row, 1, 2, "P", | ||
| 20826 | doc: /* Dump glyph row ROW of the tab-bar of the current frame to stderr. | ||
| 20827 | Interactively, ROW is the prefix numeric argument and defaults to zero. | ||
| 20828 | GLYPHS 0 means don't dump glyphs. | ||
| 20829 | GLYPHS 1 means dump glyphs in short form. | ||
| 20830 | GLYPHS > 1 or omitted means dump glyphs in long form. | ||
| 20831 | |||
| 20832 | If there's no tab-bar, or if the tab-bar is not drawn by Emacs, | ||
| 20833 | do nothing. */) | ||
| 20834 | (Lisp_Object row, Lisp_Object glyphs) | ||
| 20835 | { | ||
| 20836 | #if defined (HAVE_WINDOW_SYSTEM) | ||
| 20837 | struct frame *sf = SELECTED_FRAME (); | ||
| 20838 | struct glyph_matrix *m = WINDOWP (sf->tab_bar_window) | ||
| 20839 | ? XWINDOW (sf->tab_bar_window)->current_matrix | ||
| 20840 | : sf->current_matrix; | ||
| 20841 | EMACS_INT vpos; | ||
| 20842 | |||
| 20843 | if (NILP (row)) | ||
| 20844 | vpos = WINDOWP (sf->tab_bar_window) ? 0 : | ||
| 20845 | FRAME_MENU_BAR_LINES (sf) > 0 ? 1 : 0; | ||
| 20846 | else | ||
| 20847 | { | ||
| 20848 | CHECK_FIXNUM (row); | ||
| 20849 | vpos = XFIXNUM (row); | ||
| 20850 | } | ||
| 20851 | if (vpos >= 0 && vpos < m->nrows) | ||
| 20852 | dump_glyph_row (MATRIX_ROW (m, vpos), vpos, | ||
| 20853 | TYPE_RANGED_FIXNUMP (int, glyphs) ? XFIXNUM (glyphs) : 2); | ||
| 20854 | #endif | ||
| 20855 | return Qnil; | ||
| 20856 | } | ||
| 20857 | |||
| 19869 | DEFUN ("dump-tool-bar-row", Fdump_tool_bar_row, Sdump_tool_bar_row, 1, 2, "P", | 20858 | DEFUN ("dump-tool-bar-row", Fdump_tool_bar_row, Sdump_tool_bar_row, 1, 2, "P", |
| 19870 | doc: /* Dump glyph row ROW of the tool-bar of the current frame to stderr. | 20859 | doc: /* Dump glyph row ROW of the tool-bar of the current frame to stderr. |
| 19871 | Interactively, ROW is the prefix numeric argument and defaults to zero. | 20860 | Interactively, ROW is the prefix numeric argument and defaults to zero. |
| @@ -20233,7 +21222,7 @@ compute_line_metrics (struct it *it) | |||
| 20233 | /* Compute how much of the line is visible. */ | 21222 | /* Compute how much of the line is visible. */ |
| 20234 | row->visible_height = row->height; | 21223 | row->visible_height = row->height; |
| 20235 | 21224 | ||
| 20236 | min_y = WINDOW_HEADER_LINE_HEIGHT (it->w); | 21225 | min_y = WINDOW_TAB_LINE_HEIGHT (it->w) + WINDOW_HEADER_LINE_HEIGHT (it->w); |
| 20237 | max_y = WINDOW_BOX_HEIGHT_NO_MODE_LINE (it->w); | 21226 | max_y = WINDOW_BOX_HEIGHT_NO_MODE_LINE (it->w); |
| 20238 | 21227 | ||
| 20239 | if (row->y < min_y) | 21228 | if (row->y < min_y) |
| @@ -20547,6 +21536,8 @@ extend_face_to_end_of_line (struct it *it) | |||
| 20547 | /* Mode line and the header line don't have margins, and | 21536 | /* Mode line and the header line don't have margins, and |
| 20548 | likewise the frame's tool-bar window, if there is any. */ | 21537 | likewise the frame's tool-bar window, if there is any. */ |
| 20549 | if (!(it->glyph_row->mode_line_p | 21538 | if (!(it->glyph_row->mode_line_p |
| 21539 | || (WINDOWP (f->tab_bar_window) | ||
| 21540 | && it->w == XWINDOW (f->tab_bar_window)) | ||
| 20550 | #ifndef HAVE_EXT_TOOL_BAR | 21541 | #ifndef HAVE_EXT_TOOL_BAR |
| 20551 | || (WINDOWP (f->tool_bar_window) | 21542 | || (WINDOWP (f->tool_bar_window) |
| 20552 | && it->w == XWINDOW (f->tool_bar_window)) | 21543 | && it->w == XWINDOW (f->tool_bar_window)) |
| @@ -21743,9 +22734,10 @@ display_line (struct it *it, int cursor_vpos) | |||
| 21743 | ptrdiff_t min_pos = ZV + 1, max_pos = 0; | 22734 | ptrdiff_t min_pos = ZV + 1, max_pos = 0; |
| 21744 | ptrdiff_t min_bpos UNINIT, max_bpos UNINIT; | 22735 | ptrdiff_t min_bpos UNINIT, max_bpos UNINIT; |
| 21745 | bool pending_handle_line_prefix = false; | 22736 | bool pending_handle_line_prefix = false; |
| 22737 | int tab_line = window_wants_tab_line (it->w); | ||
| 21746 | int header_line = window_wants_header_line (it->w); | 22738 | int header_line = window_wants_header_line (it->w); |
| 21747 | bool hscroll_this_line = (cursor_vpos >= 0 | 22739 | bool hscroll_this_line = (cursor_vpos >= 0 |
| 21748 | && it->vpos == cursor_vpos - header_line | 22740 | && it->vpos == cursor_vpos - tab_line - header_line |
| 21749 | && hscrolling_current_line_p (it->w)); | 22741 | && hscrolling_current_line_p (it->w)); |
| 21750 | int first_visible_x = it->first_visible_x; | 22742 | int first_visible_x = it->first_visible_x; |
| 21751 | int last_visible_x = it->last_visible_x; | 22743 | int last_visible_x = it->last_visible_x; |
| @@ -23786,6 +24778,18 @@ display_mode_lines (struct window *w) | |||
| 23786 | ++n; | 24778 | ++n; |
| 23787 | } | 24779 | } |
| 23788 | 24780 | ||
| 24781 | if (window_wants_tab_line (w)) | ||
| 24782 | { | ||
| 24783 | Lisp_Object window_tab_line_format | ||
| 24784 | = window_parameter (w, Qtab_line_format); | ||
| 24785 | |||
| 24786 | display_mode_line (w, TAB_LINE_FACE_ID, | ||
| 24787 | NILP (window_tab_line_format) | ||
| 24788 | ? BVAR (current_buffer, tab_line_format) | ||
| 24789 | : window_tab_line_format); | ||
| 24790 | ++n; | ||
| 24791 | } | ||
| 24792 | |||
| 23789 | if (window_wants_header_line (w)) | 24793 | if (window_wants_header_line (w)) |
| 23790 | { | 24794 | { |
| 23791 | Lisp_Object window_header_line_format | 24795 | Lisp_Object window_header_line_format |
| @@ -23807,10 +24811,10 @@ display_mode_lines (struct window *w) | |||
| 23807 | } | 24811 | } |
| 23808 | 24812 | ||
| 23809 | 24813 | ||
| 23810 | /* Display mode or header line of window W. FACE_ID specifies which | 24814 | /* Display mode or header/tab line of window W. FACE_ID specifies which |
| 23811 | line to display; it is either MODE_LINE_FACE_ID or | 24815 | line to display; it is either MODE_LINE_FACE_ID, HEADER_LINE_FACE_ID or |
| 23812 | HEADER_LINE_FACE_ID. FORMAT is the mode/header line format to | 24816 | TAB_LINE_FACE_ID. FORMAT is the mode/header/tab line format to |
| 23813 | display. Value is the pixel height of the mode/header line | 24817 | display. Value is the pixel height of the mode/header/tab line |
| 23814 | displayed. */ | 24818 | displayed. */ |
| 23815 | 24819 | ||
| 23816 | static int | 24820 | static int |
| @@ -23827,6 +24831,8 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format) | |||
| 23827 | prepare_desired_row (w, it.glyph_row, true); | 24831 | prepare_desired_row (w, it.glyph_row, true); |
| 23828 | 24832 | ||
| 23829 | it.glyph_row->mode_line_p = true; | 24833 | it.glyph_row->mode_line_p = true; |
| 24834 | if (face_id == TAB_LINE_FACE_ID) | ||
| 24835 | it.glyph_row->tab_line_p = true; | ||
| 23830 | 24836 | ||
| 23831 | /* FIXME: This should be controlled by a user option. But | 24837 | /* FIXME: This should be controlled by a user option. But |
| 23832 | supporting such an option is not trivial, since the mode line is | 24838 | supporting such an option is not trivial, since the mode line is |
| @@ -24544,6 +25550,8 @@ are the selected window and the WINDOW's buffer). */) | |||
| 24544 | : EQ (face, Qmode_line) ? MODE_LINE_FACE_ID | 25550 | : EQ (face, Qmode_line) ? MODE_LINE_FACE_ID |
| 24545 | : EQ (face, Qmode_line_inactive) ? MODE_LINE_INACTIVE_FACE_ID | 25551 | : EQ (face, Qmode_line_inactive) ? MODE_LINE_INACTIVE_FACE_ID |
| 24546 | : EQ (face, Qheader_line) ? HEADER_LINE_FACE_ID | 25552 | : EQ (face, Qheader_line) ? HEADER_LINE_FACE_ID |
| 25553 | : EQ (face, Qtab_line) ? TAB_LINE_FACE_ID | ||
| 25554 | : EQ (face, Qtab_bar) ? TAB_BAR_FACE_ID | ||
| 24547 | : EQ (face, Qtool_bar) ? TOOL_BAR_FACE_ID | 25555 | : EQ (face, Qtool_bar) ? TOOL_BAR_FACE_ID |
| 24548 | : DEFAULT_FACE_ID; | 25556 | : DEFAULT_FACE_ID; |
| 24549 | 25557 | ||
| @@ -29475,7 +30483,7 @@ gui_clear_end_of_line (struct window *w, struct glyph_row *updated_row, | |||
| 29475 | to_x += area_left; | 30483 | to_x += area_left; |
| 29476 | } | 30484 | } |
| 29477 | 30485 | ||
| 29478 | min_y = WINDOW_HEADER_LINE_HEIGHT (w); | 30486 | min_y = WINDOW_TAB_LINE_HEIGHT (w) + WINDOW_HEADER_LINE_HEIGHT (w); |
| 29479 | from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, w->output_cursor.y)); | 30487 | from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, w->output_cursor.y)); |
| 29480 | to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y); | 30488 | to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y); |
| 29481 | 30489 | ||
| @@ -29985,6 +30993,7 @@ erase_phys_cursor (struct window *w) | |||
| 29985 | if (w->phys_cursor_type == HOLLOW_BOX_CURSOR) | 30993 | if (w->phys_cursor_type == HOLLOW_BOX_CURSOR) |
| 29986 | { | 30994 | { |
| 29987 | int x, y; | 30995 | int x, y; |
| 30996 | int tab_line_height = WINDOW_TAB_LINE_HEIGHT (w); | ||
| 29988 | int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w); | 30997 | int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w); |
| 29989 | int width; | 30998 | int width; |
| 29990 | 30999 | ||
| @@ -30000,7 +31009,7 @@ erase_phys_cursor (struct window *w) | |||
| 30000 | x = 0; | 31009 | x = 0; |
| 30001 | } | 31010 | } |
| 30002 | width = min (width, window_box_width (w, TEXT_AREA) - x); | 31011 | width = min (width, window_box_width (w, TEXT_AREA) - x); |
| 30003 | y = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, cursor_row->y)); | 31012 | y = WINDOW_TO_FRAME_PIXEL_Y (w, max (tab_line_height, max (header_line_height, cursor_row->y))); |
| 30004 | x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, x); | 31013 | x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, x); |
| 30005 | 31014 | ||
| 30006 | if (width > 0) | 31015 | if (width > 0) |
| @@ -30346,12 +31355,13 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw) | |||
| 30346 | /* Change the mouse cursor. */ | 31355 | /* Change the mouse cursor. */ |
| 30347 | if (FRAME_WINDOW_P (f) && NILP (track_mouse)) | 31356 | if (FRAME_WINDOW_P (f) && NILP (track_mouse)) |
| 30348 | { | 31357 | { |
| 30349 | #ifndef HAVE_EXT_TOOL_BAR | ||
| 30350 | if (draw == DRAW_NORMAL_TEXT | 31358 | if (draw == DRAW_NORMAL_TEXT |
| 30351 | && !EQ (hlinfo->mouse_face_window, f->tool_bar_window)) | 31359 | #ifndef HAVE_EXT_TOOL_BAR |
| 31360 | && !EQ (hlinfo->mouse_face_window, f->tool_bar_window) | ||
| 31361 | #endif | ||
| 31362 | && !EQ (hlinfo->mouse_face_window, f->tab_bar_window)) | ||
| 30352 | FRAME_RIF (f)->define_frame_cursor (f, FRAME_OUTPUT_DATA (f)->text_cursor); | 31363 | FRAME_RIF (f)->define_frame_cursor (f, FRAME_OUTPUT_DATA (f)->text_cursor); |
| 30353 | else | 31364 | else |
| 30354 | #endif | ||
| 30355 | if (draw == DRAW_MOUSE_FACE) | 31365 | if (draw == DRAW_MOUSE_FACE) |
| 30356 | FRAME_RIF (f)->define_frame_cursor (f, FRAME_OUTPUT_DATA (f)->hand_cursor); | 31366 | FRAME_RIF (f)->define_frame_cursor (f, FRAME_OUTPUT_DATA (f)->hand_cursor); |
| 30357 | else | 31367 | else |
| @@ -31347,7 +32357,7 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, | |||
| 31347 | struct glyph * glyph = NULL, * row_start_glyph = NULL; | 32357 | struct glyph * glyph = NULL, * row_start_glyph = NULL; |
| 31348 | struct glyph_row *row UNINIT; | 32358 | struct glyph_row *row UNINIT; |
| 31349 | 32359 | ||
| 31350 | if (area == ON_MODE_LINE || area == ON_HEADER_LINE) | 32360 | if (area == ON_MODE_LINE || area == ON_HEADER_LINE || area == ON_TAB_LINE) |
| 31351 | { | 32361 | { |
| 31352 | int x0; | 32362 | int x0; |
| 31353 | struct glyph *end; | 32363 | struct glyph *end; |
| @@ -31359,7 +32369,9 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, | |||
| 31359 | 32369 | ||
| 31360 | row = (area == ON_MODE_LINE | 32370 | row = (area == ON_MODE_LINE |
| 31361 | ? MATRIX_MODE_LINE_ROW (w->current_matrix) | 32371 | ? MATRIX_MODE_LINE_ROW (w->current_matrix) |
| 31362 | : MATRIX_HEADER_LINE_ROW (w->current_matrix)); | 32372 | : (area == ON_TAB_LINE |
| 32373 | ? MATRIX_TAB_LINE_ROW (w->current_matrix) | ||
| 32374 | : MATRIX_HEADER_LINE_ROW (w->current_matrix))); | ||
| 31363 | 32375 | ||
| 31364 | /* Find the glyph under the mouse pointer. */ | 32376 | /* Find the glyph under the mouse pointer. */ |
| 31365 | if (row->mode_line_p && row->enabled_p) | 32377 | if (row->mode_line_p && row->enabled_p) |
| @@ -31474,7 +32486,8 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, | |||
| 31474 | 32486 | ||
| 31475 | /* Change the mouse pointer according to what is under X/Y. */ | 32487 | /* Change the mouse pointer according to what is under X/Y. */ |
| 31476 | if (NILP (pointer) | 32488 | if (NILP (pointer) |
| 31477 | && (area == ON_MODE_LINE || area == ON_HEADER_LINE)) | 32489 | && (area == ON_MODE_LINE || area == ON_HEADER_LINE |
| 32490 | || area == ON_TAB_LINE)) | ||
| 31478 | { | 32491 | { |
| 31479 | Lisp_Object map; | 32492 | Lisp_Object map; |
| 31480 | 32493 | ||
| @@ -31500,7 +32513,8 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, | |||
| 31500 | { | 32513 | { |
| 31501 | mouse_face = Fget_text_property (pos, Qmouse_face, string); | 32514 | mouse_face = Fget_text_property (pos, Qmouse_face, string); |
| 31502 | if (!NILP (Vmouse_highlight) && !NILP (mouse_face) | 32515 | if (!NILP (Vmouse_highlight) && !NILP (mouse_face) |
| 31503 | && ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE)) | 32516 | && ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE) |
| 32517 | || (area == ON_TAB_LINE)) | ||
| 31504 | && glyph) | 32518 | && glyph) |
| 31505 | { | 32519 | { |
| 31506 | Lisp_Object b, e; | 32520 | Lisp_Object b, e; |
| @@ -31571,7 +32585,11 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, | |||
| 31571 | hpos = x - gpos; | 32585 | hpos = x - gpos; |
| 31572 | vpos = (area == ON_MODE_LINE | 32586 | vpos = (area == ON_MODE_LINE |
| 31573 | ? (w->current_matrix)->nrows - 1 | 32587 | ? (w->current_matrix)->nrows - 1 |
| 31574 | : 0); | 32588 | : (area == ON_TAB_LINE |
| 32589 | ? 0 | ||
| 32590 | : (w->current_matrix->tab_line_p | ||
| 32591 | ? 1 | ||
| 32592 | : 0))); | ||
| 31575 | 32593 | ||
| 31576 | /* If GLYPH's position is included in the region that is | 32594 | /* If GLYPH's position is included in the region that is |
| 31577 | already drawn in mouse face, we have nothing to do. */ | 32595 | already drawn in mouse face, we have nothing to do. */ |
| @@ -31627,7 +32645,8 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, | |||
| 31627 | 32645 | ||
| 31628 | /* If mouse-face doesn't need to be shown, clear any existing | 32646 | /* If mouse-face doesn't need to be shown, clear any existing |
| 31629 | mouse-face. */ | 32647 | mouse-face. */ |
| 31630 | if ((area == ON_MODE_LINE || area == ON_HEADER_LINE) && !mouse_face_shown) | 32648 | if ((area == ON_MODE_LINE || area == ON_HEADER_LINE |
| 32649 | || area == ON_TAB_LINE) && !mouse_face_shown) | ||
| 31631 | clear_mouse_face (hlinfo); | 32650 | clear_mouse_face (hlinfo); |
| 31632 | 32651 | ||
| 31633 | define_frame_cursor1 (f, cursor, pointer); | 32652 | define_frame_cursor1 (f, cursor, pointer); |
| @@ -31671,7 +32690,7 @@ note_mouse_highlight (struct frame *f, int x, int y) | |||
| 31671 | return; | 32690 | return; |
| 31672 | 32691 | ||
| 31673 | /* Which window is that in? */ | 32692 | /* Which window is that in? */ |
| 31674 | window = window_from_coordinates (f, x, y, &part, true); | 32693 | window = window_from_coordinates (f, x, y, &part, true, true); |
| 31675 | 32694 | ||
| 31676 | /* If displaying active text in another window, clear that. */ | 32695 | /* If displaying active text in another window, clear that. */ |
| 31677 | if (! EQ (window, hlinfo->mouse_face_window) | 32696 | if (! EQ (window, hlinfo->mouse_face_window) |
| @@ -31680,7 +32699,8 @@ note_mouse_highlight (struct frame *f, int x, int y) | |||
| 31680 | && !NILP (window) | 32699 | && !NILP (window) |
| 31681 | && part != ON_TEXT | 32700 | && part != ON_TEXT |
| 31682 | && part != ON_MODE_LINE | 32701 | && part != ON_MODE_LINE |
| 31683 | && part != ON_HEADER_LINE)) | 32702 | && part != ON_HEADER_LINE |
| 32703 | && part != ON_TAB_LINE)) | ||
| 31684 | clear_mouse_face (hlinfo); | 32704 | clear_mouse_face (hlinfo); |
| 31685 | 32705 | ||
| 31686 | /* Reset help_echo_string. It will get recomputed below. */ | 32706 | /* Reset help_echo_string. It will get recomputed below. */ |
| @@ -31748,6 +32768,16 @@ note_mouse_highlight (struct frame *f, int x, int y) | |||
| 31748 | w = XWINDOW (window); | 32768 | w = XWINDOW (window); |
| 31749 | frame_to_window_pixel_xy (w, &x, &y); | 32769 | frame_to_window_pixel_xy (w, &x, &y); |
| 31750 | 32770 | ||
| 32771 | #if defined (HAVE_WINDOW_SYSTEM) | ||
| 32772 | /* Handle tab-bar window differently since it doesn't display a | ||
| 32773 | buffer. */ | ||
| 32774 | if (EQ (window, f->tab_bar_window)) | ||
| 32775 | { | ||
| 32776 | note_tab_bar_highlight (f, x, y); | ||
| 32777 | return; | ||
| 32778 | } | ||
| 32779 | #endif | ||
| 32780 | |||
| 31751 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) | 32781 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) |
| 31752 | /* Handle tool-bar window differently since it doesn't display a | 32782 | /* Handle tool-bar window differently since it doesn't display a |
| 31753 | buffer. */ | 32783 | buffer. */ |
| @@ -31759,7 +32789,7 @@ note_mouse_highlight (struct frame *f, int x, int y) | |||
| 31759 | #endif | 32789 | #endif |
| 31760 | 32790 | ||
| 31761 | /* Mouse is on the mode, header line or margin? */ | 32791 | /* Mouse is on the mode, header line or margin? */ |
| 31762 | if (part == ON_MODE_LINE || part == ON_HEADER_LINE | 32792 | if (part == ON_MODE_LINE || part == ON_HEADER_LINE || part == ON_TAB_LINE |
| 31763 | || part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN) | 32793 | || part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN) |
| 31764 | { | 32794 | { |
| 31765 | note_mode_line_or_margin_highlight (window, x, y, part); | 32795 | note_mode_line_or_margin_highlight (window, x, y, part); |
| @@ -32774,6 +33804,10 @@ expose_frame (struct frame *f, int x, int y, int w, int h) | |||
| 32774 | r.x, r.y, r.width, r.height); | 33804 | r.x, r.y, r.width, r.height); |
| 32775 | mouse_face_overwritten_p = expose_window_tree (XWINDOW (f->root_window), &r); | 33805 | mouse_face_overwritten_p = expose_window_tree (XWINDOW (f->root_window), &r); |
| 32776 | 33806 | ||
| 33807 | if (WINDOWP (f->tab_bar_window)) | ||
| 33808 | mouse_face_overwritten_p | ||
| 33809 | |= expose_window (XWINDOW (f->tab_bar_window), &r); | ||
| 33810 | |||
| 32777 | #ifndef HAVE_EXT_TOOL_BAR | 33811 | #ifndef HAVE_EXT_TOOL_BAR |
| 32778 | if (WINDOWP (f->tool_bar_window)) | 33812 | if (WINDOWP (f->tool_bar_window)) |
| 32779 | mouse_face_overwritten_p | 33813 | mouse_face_overwritten_p |
| @@ -32914,11 +33948,13 @@ be let-bound around code that needs to disable messages temporarily. */); | |||
| 32914 | defsubr (&Sdump_frame_glyph_matrix); | 33948 | defsubr (&Sdump_frame_glyph_matrix); |
| 32915 | defsubr (&Sdump_glyph_matrix); | 33949 | defsubr (&Sdump_glyph_matrix); |
| 32916 | defsubr (&Sdump_glyph_row); | 33950 | defsubr (&Sdump_glyph_row); |
| 33951 | defsubr (&Sdump_tab_bar_row); | ||
| 32917 | defsubr (&Sdump_tool_bar_row); | 33952 | defsubr (&Sdump_tool_bar_row); |
| 32918 | defsubr (&Strace_redisplay); | 33953 | defsubr (&Strace_redisplay); |
| 32919 | defsubr (&Strace_to_stderr); | 33954 | defsubr (&Strace_to_stderr); |
| 32920 | #endif | 33955 | #endif |
| 32921 | #ifdef HAVE_WINDOW_SYSTEM | 33956 | #ifdef HAVE_WINDOW_SYSTEM |
| 33957 | defsubr (&Stab_bar_height); | ||
| 32922 | defsubr (&Stool_bar_height); | 33958 | defsubr (&Stool_bar_height); |
| 32923 | defsubr (&Slookup_image_map); | 33959 | defsubr (&Slookup_image_map); |
| 32924 | #endif | 33960 | #endif |
| @@ -33304,6 +34340,18 @@ make sure that (1) your window manager has focus follow the mouse and | |||
| 33304 | of your window manager. */); | 34340 | of your window manager. */); |
| 33305 | Vmouse_autoselect_window = Qnil; | 34341 | Vmouse_autoselect_window = Qnil; |
| 33306 | 34342 | ||
| 34343 | DEFVAR_LISP ("auto-resize-tab-bars", Vauto_resize_tab_bars, | ||
| 34344 | doc: /* Non-nil means automatically resize tab-bars. | ||
| 34345 | This dynamically changes the tab-bar's height to the minimum height | ||
| 34346 | that is needed to make all tab-bar items visible. | ||
| 34347 | If value is `grow-only', the tab-bar's height is only increased | ||
| 34348 | automatically; to decrease the tab-bar height, use \\[recenter]. */); | ||
| 34349 | Vauto_resize_tab_bars = Qt; | ||
| 34350 | |||
| 34351 | DEFVAR_BOOL ("auto-raise-tab-bar-buttons", auto_raise_tab_bar_buttons_p, | ||
| 34352 | doc: /* Non-nil means raise tab-bar buttons when the mouse moves over them. */); | ||
| 34353 | auto_raise_tab_bar_buttons_p = true; | ||
| 34354 | |||
| 33307 | DEFVAR_LISP ("auto-resize-tool-bars", Vauto_resize_tool_bars, | 34355 | DEFVAR_LISP ("auto-resize-tool-bars", Vauto_resize_tool_bars, |
| 33308 | doc: /* Non-nil means automatically resize tool-bars. | 34356 | doc: /* Non-nil means automatically resize tool-bars. |
| 33309 | This dynamically changes the tool-bar's height to the minimum height | 34357 | This dynamically changes the tool-bar's height to the minimum height |
| @@ -33326,6 +34374,27 @@ window, nil if it's okay to leave the cursor partially-visible. */); | |||
| 33326 | Vmake_cursor_line_fully_visible = Qt; | 34374 | Vmake_cursor_line_fully_visible = Qt; |
| 33327 | DEFSYM (Qmake_cursor_line_fully_visible, "make-cursor-line-fully-visible"); | 34375 | DEFSYM (Qmake_cursor_line_fully_visible, "make-cursor-line-fully-visible"); |
| 33328 | 34376 | ||
| 34377 | DEFSYM (Qclose_tab, "close-tab"); | ||
| 34378 | DEFVAR_LISP ("tab-bar-border", Vtab_bar_border, | ||
| 34379 | doc: /* Border below tab-bar in pixels. | ||
| 34380 | If an integer, use it as the height of the border. | ||
| 34381 | If it is one of `internal-border-width' or `border-width', use the | ||
| 34382 | value of the corresponding frame parameter. | ||
| 34383 | Otherwise, no border is added below the tab-bar. */); | ||
| 34384 | Vtab_bar_border = Qinternal_border_width; | ||
| 34385 | |||
| 34386 | DEFVAR_LISP ("tab-bar-button-margin", Vtab_bar_button_margin, | ||
| 34387 | doc: /* Margin around tab-bar buttons in pixels. | ||
| 34388 | If an integer, use that for both horizontal and vertical margins. | ||
| 34389 | Otherwise, value should be a pair of integers `(HORZ . VERT)' with | ||
| 34390 | HORZ specifying the horizontal margin, and VERT specifying the | ||
| 34391 | vertical margin. */); | ||
| 34392 | Vtab_bar_button_margin = make_fixnum (DEFAULT_TAB_BAR_BUTTON_MARGIN); | ||
| 34393 | |||
| 34394 | DEFVAR_INT ("tab-bar-button-relief", tab_bar_button_relief, | ||
| 34395 | doc: /* Relief thickness of tab-bar buttons. */); | ||
| 34396 | tab_bar_button_relief = DEFAULT_TAB_BAR_BUTTON_RELIEF; | ||
| 34397 | |||
| 33329 | DEFVAR_LISP ("tool-bar-border", Vtool_bar_border, | 34398 | DEFVAR_LISP ("tool-bar-border", Vtool_bar_border, |
| 33330 | doc: /* Border below tool-bar in pixels. | 34399 | doc: /* Border below tool-bar in pixels. |
| 33331 | If an integer, use it as the height of the border. | 34400 | If an integer, use it as the height of the border. |
diff --git a/src/xfaces.c b/src/xfaces.c index 946401b9e99..0c99eea1567 100644 --- a/src/xfaces.c +++ b/src/xfaces.c | |||
| @@ -4586,6 +4586,8 @@ lookup_basic_face (struct window *w, struct frame *f, int face_id) | |||
| 4586 | case MODE_LINE_FACE_ID: name = Qmode_line; break; | 4586 | case MODE_LINE_FACE_ID: name = Qmode_line; break; |
| 4587 | case MODE_LINE_INACTIVE_FACE_ID: name = Qmode_line_inactive; break; | 4587 | case MODE_LINE_INACTIVE_FACE_ID: name = Qmode_line_inactive; break; |
| 4588 | case HEADER_LINE_FACE_ID: name = Qheader_line; break; | 4588 | case HEADER_LINE_FACE_ID: name = Qheader_line; break; |
| 4589 | case TAB_LINE_FACE_ID: name = Qtab_line; break; | ||
| 4590 | case TAB_BAR_FACE_ID: name = Qtab_bar; break; | ||
| 4589 | case TOOL_BAR_FACE_ID: name = Qtool_bar; break; | 4591 | case TOOL_BAR_FACE_ID: name = Qtool_bar; break; |
| 4590 | case FRINGE_FACE_ID: name = Qfringe; break; | 4592 | case FRINGE_FACE_ID: name = Qfringe; break; |
| 4591 | case SCROLL_BAR_FACE_ID: name = Qscroll_bar; break; | 4593 | case SCROLL_BAR_FACE_ID: name = Qscroll_bar; break; |
| @@ -5293,6 +5295,8 @@ realize_basic_faces (struct frame *f) | |||
| 5293 | realize_named_face (f, Qwindow_divider_last_pixel, | 5295 | realize_named_face (f, Qwindow_divider_last_pixel, |
| 5294 | WINDOW_DIVIDER_LAST_PIXEL_FACE_ID); | 5296 | WINDOW_DIVIDER_LAST_PIXEL_FACE_ID); |
| 5295 | realize_named_face (f, Qinternal_border, INTERNAL_BORDER_FACE_ID); | 5297 | realize_named_face (f, Qinternal_border, INTERNAL_BORDER_FACE_ID); |
| 5298 | realize_named_face (f, Qtab_bar, TAB_BAR_FACE_ID); | ||
| 5299 | realize_named_face (f, Qtab_line, TAB_LINE_FACE_ID); | ||
| 5296 | 5300 | ||
| 5297 | /* Reflect changes in the `menu' face in menu bars. */ | 5301 | /* Reflect changes in the `menu' face in menu bars. */ |
| 5298 | if (FRAME_FACE_CACHE (f)->menu_face_changed_p) | 5302 | if (FRAME_FACE_CACHE (f)->menu_face_changed_p) |
| @@ -6579,7 +6583,9 @@ syms_of_xfaces (void) | |||
| 6579 | /* Names of basic faces. */ | 6583 | /* Names of basic faces. */ |
| 6580 | DEFSYM (Qdefault, "default"); | 6584 | DEFSYM (Qdefault, "default"); |
| 6581 | DEFSYM (Qtool_bar, "tool-bar"); | 6585 | DEFSYM (Qtool_bar, "tool-bar"); |
| 6586 | DEFSYM (Qtab_bar, "tab-bar"); | ||
| 6582 | DEFSYM (Qfringe, "fringe"); | 6587 | DEFSYM (Qfringe, "fringe"); |
| 6588 | DEFSYM (Qtab_line, "tab-line"); | ||
| 6583 | DEFSYM (Qheader_line, "header-line"); | 6589 | DEFSYM (Qheader_line, "header-line"); |
| 6584 | DEFSYM (Qscroll_bar, "scroll-bar"); | 6590 | DEFSYM (Qscroll_bar, "scroll-bar"); |
| 6585 | DEFSYM (Qmenu, "menu"); | 6591 | DEFSYM (Qmenu, "menu"); |
diff --git a/src/xfns.c b/src/xfns.c index 31ae4cc225b..20e63a26501 100644 --- a/src/xfns.c +++ b/src/xfns.c | |||
| @@ -1602,6 +1602,94 @@ x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) | |||
| 1602 | } | 1602 | } |
| 1603 | 1603 | ||
| 1604 | 1604 | ||
| 1605 | /* Set the number of lines used for the tab bar of frame F to VALUE. | ||
| 1606 | VALUE not an integer, or < 0 means set the lines to zero. OLDVAL | ||
| 1607 | is the old number of tab bar lines. This function changes the | ||
| 1608 | height of all windows on frame F to match the new tab bar height. | ||
| 1609 | The frame's height doesn't change. */ | ||
| 1610 | |||
| 1611 | static void | ||
| 1612 | x_set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) | ||
| 1613 | { | ||
| 1614 | int nlines; | ||
| 1615 | |||
| 1616 | /* Treat tab bars like menu bars. */ | ||
| 1617 | if (FRAME_MINIBUF_ONLY_P (f)) | ||
| 1618 | return; | ||
| 1619 | |||
| 1620 | /* Use VALUE only if an int >= 0. */ | ||
| 1621 | if (RANGED_FIXNUMP (0, value, INT_MAX)) | ||
| 1622 | nlines = XFIXNAT (value); | ||
| 1623 | else | ||
| 1624 | nlines = 0; | ||
| 1625 | |||
| 1626 | x_change_tab_bar_height (f, nlines * FRAME_LINE_HEIGHT (f)); | ||
| 1627 | } | ||
| 1628 | |||
| 1629 | |||
| 1630 | /* Set the pixel height of the tab bar of frame F to HEIGHT. */ | ||
| 1631 | void | ||
| 1632 | x_change_tab_bar_height (struct frame *f, int height) | ||
| 1633 | { | ||
| 1634 | int unit = FRAME_LINE_HEIGHT (f); | ||
| 1635 | int old_height = FRAME_TAB_BAR_HEIGHT (f); | ||
| 1636 | int lines = (height + unit - 1) / unit; | ||
| 1637 | Lisp_Object fullscreen; | ||
| 1638 | |||
| 1639 | /* Make sure we redisplay all windows in this frame. */ | ||
| 1640 | fset_redisplay (f); | ||
| 1641 | |||
| 1642 | /* Recalculate tab bar and frame text sizes. */ | ||
| 1643 | FRAME_TAB_BAR_HEIGHT (f) = height; | ||
| 1644 | FRAME_TAB_BAR_LINES (f) = lines; | ||
| 1645 | /* Store the `tab-bar-lines' and `height' frame parameters. */ | ||
| 1646 | store_frame_param (f, Qtab_bar_lines, make_fixnum (lines)); | ||
| 1647 | store_frame_param (f, Qheight, make_fixnum (FRAME_LINES (f))); | ||
| 1648 | |||
| 1649 | /* We also have to make sure that the internal border at the top of | ||
| 1650 | the frame, below the menu bar or tab bar, is redrawn when the | ||
| 1651 | tab bar disappears. This is so because the internal border is | ||
| 1652 | below the tab bar if one is displayed, but is below the menu bar | ||
| 1653 | if there isn't a tab bar. The tab bar draws into the area | ||
| 1654 | below the menu bar. */ | ||
| 1655 | if (FRAME_X_WINDOW (f) && FRAME_TAB_BAR_HEIGHT (f) == 0) | ||
| 1656 | { | ||
| 1657 | clear_frame (f); | ||
| 1658 | clear_current_matrices (f); | ||
| 1659 | } | ||
| 1660 | |||
| 1661 | if ((height < old_height) && WINDOWP (f->tab_bar_window)) | ||
| 1662 | clear_glyph_matrix (XWINDOW (f->tab_bar_window)->current_matrix); | ||
| 1663 | |||
| 1664 | /* Recalculate tabbar height. */ | ||
| 1665 | f->n_tab_bar_rows = 0; | ||
| 1666 | if (old_height == 0 | ||
| 1667 | && (!f->after_make_frame | ||
| 1668 | || NILP (frame_inhibit_implied_resize) | ||
| 1669 | || (CONSP (frame_inhibit_implied_resize) | ||
| 1670 | && NILP (Fmemq (Qtab_bar_lines, frame_inhibit_implied_resize))))) | ||
| 1671 | f->tab_bar_redisplayed = f->tab_bar_resized = false; | ||
| 1672 | |||
| 1673 | adjust_frame_size (f, -1, -1, | ||
| 1674 | ((!f->tab_bar_resized | ||
| 1675 | && (NILP (fullscreen = | ||
| 1676 | get_frame_param (f, Qfullscreen)) | ||
| 1677 | || EQ (fullscreen, Qfullwidth))) ? 1 | ||
| 1678 | : (old_height == 0 || height == 0) ? 2 | ||
| 1679 | : 4), | ||
| 1680 | false, Qtab_bar_lines); | ||
| 1681 | |||
| 1682 | f->tab_bar_resized = f->tab_bar_redisplayed; | ||
| 1683 | |||
| 1684 | /* adjust_frame_size might not have done anything, garbage frame | ||
| 1685 | here. */ | ||
| 1686 | adjust_frame_glyphs (f); | ||
| 1687 | SET_FRAME_GARBAGED (f); | ||
| 1688 | if (FRAME_X_WINDOW (f)) | ||
| 1689 | x_clear_under_internal_border (f); | ||
| 1690 | } | ||
| 1691 | |||
| 1692 | |||
| 1605 | /* Set the number of lines used for the tool bar of frame F to VALUE. | 1693 | /* Set the number of lines used for the tool bar of frame F to VALUE. |
| 1606 | VALUE not an integer, or < 0 means set the lines to zero. OLDVAL | 1694 | VALUE not an integer, or < 0 means set the lines to zero. OLDVAL |
| 1607 | is the old number of tool bar lines. This function changes the | 1695 | 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. */) | |||
| 3922 | NILP (Vmenu_bar_mode) | 4010 | NILP (Vmenu_bar_mode) |
| 3923 | ? make_fixnum (0) : make_fixnum (1), | 4011 | ? make_fixnum (0) : make_fixnum (1), |
| 3924 | NULL, NULL, RES_TYPE_NUMBER); | 4012 | NULL, NULL, RES_TYPE_NUMBER); |
| 4013 | gui_default_parameter (f, parms, Qtab_bar_lines, | ||
| 4014 | NILP (Vtab_bar_mode) | ||
| 4015 | ? make_fixnum (0) : make_fixnum (1), | ||
| 4016 | NULL, NULL, RES_TYPE_NUMBER); | ||
| 3925 | gui_default_parameter (f, parms, Qtool_bar_lines, | 4017 | gui_default_parameter (f, parms, Qtool_bar_lines, |
| 3926 | NILP (Vtool_bar_mode) | 4018 | NILP (Vtool_bar_mode) |
| 3927 | ? make_fixnum (0) : make_fixnum (1), | 4019 | ? make_fixnum (0) : make_fixnum (1), |
| @@ -3941,7 +4033,7 @@ This function is an internal primitive--use `make-frame' instead. */) | |||
| 3941 | RES_TYPE_BOOLEAN); | 4033 | RES_TYPE_BOOLEAN); |
| 3942 | 4034 | ||
| 3943 | /* Compute the size of the X window. */ | 4035 | /* Compute the size of the X window. */ |
| 3944 | window_prompting = gui_figure_window_size (f, parms, true, | 4036 | window_prompting = gui_figure_window_size (f, parms, true, true, |
| 3945 | &x_width, &x_height); | 4037 | &x_width, &x_height); |
| 3946 | 4038 | ||
| 3947 | tem = gui_display_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, | 4039 | tem = gui_display_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, |
| @@ -5060,6 +5152,7 @@ frame_geometry (Lisp_Object frame, Lisp_Object attribute) | |||
| 5060 | int internal_border_width; | 5152 | int internal_border_width; |
| 5061 | bool menu_bar_external = false, tool_bar_external = false; | 5153 | bool menu_bar_external = false, tool_bar_external = false; |
| 5062 | int menu_bar_height = 0, menu_bar_width = 0; | 5154 | int menu_bar_height = 0, menu_bar_width = 0; |
| 5155 | int tab_bar_height = 0, tab_bar_width = 0; | ||
| 5063 | int tool_bar_height = 0, tool_bar_width = 0; | 5156 | int tool_bar_height = 0, tool_bar_width = 0; |
| 5064 | 5157 | ||
| 5065 | if (FRAME_INITIAL_P (f) || !FRAME_X_P (f) || !FRAME_OUTER_WINDOW (f)) | 5158 | 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) | |||
| 5130 | #endif | 5223 | #endif |
| 5131 | menu_bar_width = menu_bar_height ? native_width : 0; | 5224 | menu_bar_width = menu_bar_height ? native_width : 0; |
| 5132 | 5225 | ||
| 5226 | tab_bar_height = FRAME_TAB_BAR_HEIGHT (f); | ||
| 5227 | tab_bar_width = (tab_bar_height | ||
| 5228 | ? native_width - 2 * internal_border_width | ||
| 5229 | : 0); | ||
| 5230 | inner_top += tab_bar_height; | ||
| 5231 | |||
| 5133 | #ifdef HAVE_EXT_TOOL_BAR | 5232 | #ifdef HAVE_EXT_TOOL_BAR |
| 5134 | tool_bar_external = true; | 5233 | tool_bar_external = true; |
| 5135 | if (EQ (FRAME_TOOL_BAR_POSITION (f), Qleft)) | 5234 | if (EQ (FRAME_TOOL_BAR_POSITION (f), Qleft)) |
| @@ -5198,6 +5297,9 @@ frame_geometry (Lisp_Object frame, Lisp_Object attribute) | |||
| 5198 | Fcons (Qmenu_bar_size, | 5297 | Fcons (Qmenu_bar_size, |
| 5199 | Fcons (make_fixnum (menu_bar_width), | 5298 | Fcons (make_fixnum (menu_bar_width), |
| 5200 | make_fixnum (menu_bar_height))), | 5299 | make_fixnum (menu_bar_height))), |
| 5300 | Fcons (Qtab_bar_size, | ||
| 5301 | Fcons (make_fixnum (tab_bar_width), | ||
| 5302 | make_fixnum (tab_bar_height))), | ||
| 5201 | Fcons (Qtool_bar_external, tool_bar_external ? Qt : Qnil), | 5303 | Fcons (Qtool_bar_external, tool_bar_external ? Qt : Qnil), |
| 5202 | Fcons (Qtool_bar_position, FRAME_TOOL_BAR_POSITION (f)), | 5304 | Fcons (Qtool_bar_position, FRAME_TOOL_BAR_POSITION (f)), |
| 5203 | Fcons (Qtool_bar_size, | 5305 | Fcons (Qtool_bar_size, |
| @@ -6331,7 +6433,7 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms) | |||
| 6331 | "inhibitDoubleBuffering", "InhibitDoubleBuffering", | 6433 | "inhibitDoubleBuffering", "InhibitDoubleBuffering", |
| 6332 | RES_TYPE_BOOLEAN); | 6434 | RES_TYPE_BOOLEAN); |
| 6333 | 6435 | ||
| 6334 | gui_figure_window_size (f, parms, false, &x_width, &x_height); | 6436 | gui_figure_window_size (f, parms, false, false, &x_width, &x_height); |
| 6335 | 6437 | ||
| 6336 | { | 6438 | { |
| 6337 | XSetWindowAttributes attrs; | 6439 | XSetWindowAttributes attrs; |
| @@ -7672,6 +7774,7 @@ frame_parm_handler x_frame_parm_handlers[] = | |||
| 7672 | gui_set_vertical_scroll_bars, | 7774 | gui_set_vertical_scroll_bars, |
| 7673 | gui_set_horizontal_scroll_bars, | 7775 | gui_set_horizontal_scroll_bars, |
| 7674 | gui_set_visibility, | 7776 | gui_set_visibility, |
| 7777 | x_set_tab_bar_lines, | ||
| 7675 | x_set_tool_bar_lines, | 7778 | x_set_tool_bar_lines, |
| 7676 | x_set_scroll_bar_foreground, | 7779 | x_set_scroll_bar_foreground, |
| 7677 | x_set_scroll_bar_background, | 7780 | x_set_scroll_bar_background, |
diff --git a/src/xterm.c b/src/xterm.c index 255b6c62d5a..5baa29a8466 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -3220,9 +3220,11 @@ x_draw_image_relief (struct glyph_string *s) | |||
| 3220 | if (s->hl == DRAW_IMAGE_SUNKEN | 3220 | if (s->hl == DRAW_IMAGE_SUNKEN |
| 3221 | || s->hl == DRAW_IMAGE_RAISED) | 3221 | || s->hl == DRAW_IMAGE_RAISED) |
| 3222 | { | 3222 | { |
| 3223 | thick = (tool_bar_button_relief < 0 | 3223 | thick = (tab_bar_button_relief < 0 |
| 3224 | ? DEFAULT_TOOL_BAR_BUTTON_RELIEF | 3224 | ? DEFAULT_TAB_BAR_BUTTON_RELIEF |
| 3225 | : min (tool_bar_button_relief, 1000000)); | 3225 | : (tool_bar_button_relief < 0 |
| 3226 | ? DEFAULT_TOOL_BAR_BUTTON_RELIEF | ||
| 3227 | : min (tool_bar_button_relief, 1000000))); | ||
| 3226 | raised_p = s->hl == DRAW_IMAGE_RAISED; | 3228 | raised_p = s->hl == DRAW_IMAGE_RAISED; |
| 3227 | } | 3229 | } |
| 3228 | else | 3230 | else |
| @@ -3235,6 +3237,19 @@ x_draw_image_relief (struct glyph_string *s) | |||
| 3235 | y1 = y + s->slice.height - 1; | 3237 | y1 = y + s->slice.height - 1; |
| 3236 | 3238 | ||
| 3237 | extra_x = extra_y = 0; | 3239 | extra_x = extra_y = 0; |
| 3240 | if (s->face->id == TAB_BAR_FACE_ID) | ||
| 3241 | { | ||
| 3242 | if (CONSP (Vtab_bar_button_margin) | ||
| 3243 | && FIXNUMP (XCAR (Vtab_bar_button_margin)) | ||
| 3244 | && FIXNUMP (XCDR (Vtab_bar_button_margin))) | ||
| 3245 | { | ||
| 3246 | extra_x = XFIXNUM (XCAR (Vtab_bar_button_margin)); | ||
| 3247 | extra_y = XFIXNUM (XCDR (Vtab_bar_button_margin)); | ||
| 3248 | } | ||
| 3249 | else if (FIXNUMP (Vtab_bar_button_margin)) | ||
| 3250 | extra_x = extra_y = XFIXNUM (Vtab_bar_button_margin); | ||
| 3251 | } | ||
| 3252 | |||
| 3238 | if (s->face->id == TOOL_BAR_FACE_ID) | 3253 | if (s->face->id == TOOL_BAR_FACE_ID) |
| 3239 | { | 3254 | { |
| 3240 | if (CONSP (Vtool_bar_button_margin) | 3255 | if (CONSP (Vtool_bar_button_margin) |
| @@ -8396,10 +8411,11 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 8396 | /* If mouse-highlight is an integer, input clears out | 8411 | /* If mouse-highlight is an integer, input clears out |
| 8397 | mouse highlighting. */ | 8412 | mouse highlighting. */ |
| 8398 | if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight) | 8413 | if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight) |
| 8399 | #if ! defined (USE_GTK) | ||
| 8400 | && (f == 0 | 8414 | && (f == 0 |
| 8401 | || !EQ (f->tool_bar_window, hlinfo->mouse_face_window)) | 8415 | #if ! defined (USE_GTK) |
| 8416 | || !EQ (f->tool_bar_window, hlinfo->mouse_face_window) | ||
| 8402 | #endif | 8417 | #endif |
| 8418 | || !EQ (f->tab_bar_window, hlinfo->mouse_face_window)) | ||
| 8403 | ) | 8419 | ) |
| 8404 | { | 8420 | { |
| 8405 | clear_mouse_face (hlinfo); | 8421 | clear_mouse_face (hlinfo); |
| @@ -8823,7 +8839,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 8823 | { | 8839 | { |
| 8824 | static Lisp_Object last_mouse_window; | 8840 | static Lisp_Object last_mouse_window; |
| 8825 | Lisp_Object window = window_from_coordinates | 8841 | Lisp_Object window = window_from_coordinates |
| 8826 | (f, event->xmotion.x, event->xmotion.y, 0, false); | 8842 | (f, event->xmotion.x, event->xmotion.y, 0, false, false); |
| 8827 | 8843 | ||
| 8828 | /* A window will be autoselected only when it is not | 8844 | /* A window will be autoselected only when it is not |
| 8829 | selected now and the last mouse movement event was | 8845 | selected now and the last mouse movement event was |
| @@ -9034,6 +9050,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 9034 | { | 9050 | { |
| 9035 | /* If we decide we want to generate an event to be seen | 9051 | /* If we decide we want to generate an event to be seen |
| 9036 | by the rest of Emacs, we put it here. */ | 9052 | by the rest of Emacs, we put it here. */ |
| 9053 | bool tab_bar_p = false; | ||
| 9037 | bool tool_bar_p = false; | 9054 | bool tool_bar_p = false; |
| 9038 | 9055 | ||
| 9039 | memset (&compose_status, 0, sizeof (compose_status)); | 9056 | memset (&compose_status, 0, sizeof (compose_status)); |
| @@ -9070,6 +9087,23 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 9070 | #endif | 9087 | #endif |
| 9071 | if (f) | 9088 | if (f) |
| 9072 | { | 9089 | { |
| 9090 | /* Is this in the tab-bar? */ | ||
| 9091 | if (WINDOWP (f->tab_bar_window) | ||
| 9092 | && WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window))) | ||
| 9093 | { | ||
| 9094 | Lisp_Object window; | ||
| 9095 | int x = event->xbutton.x; | ||
| 9096 | int y = event->xbutton.y; | ||
| 9097 | |||
| 9098 | window = window_from_coordinates (f, x, y, 0, true, true); | ||
| 9099 | tab_bar_p = EQ (window, f->tab_bar_window); | ||
| 9100 | |||
| 9101 | if (tab_bar_p && event->xbutton.button < 4) | ||
| 9102 | handle_tab_bar_click | ||
| 9103 | (f, x, y, event->xbutton.type == ButtonPress, | ||
| 9104 | x_x_to_emacs_modifiers (dpyinfo, event->xbutton.state)); | ||
| 9105 | } | ||
| 9106 | |||
| 9073 | #if ! defined (USE_GTK) | 9107 | #if ! defined (USE_GTK) |
| 9074 | /* Is this in the tool-bar? */ | 9108 | /* Is this in the tool-bar? */ |
| 9075 | if (WINDOWP (f->tool_bar_window) | 9109 | if (WINDOWP (f->tool_bar_window) |
| @@ -9079,7 +9113,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 9079 | int x = event->xbutton.x; | 9113 | int x = event->xbutton.x; |
| 9080 | int y = event->xbutton.y; | 9114 | int y = event->xbutton.y; |
| 9081 | 9115 | ||
| 9082 | window = window_from_coordinates (f, x, y, 0, true); | 9116 | window = window_from_coordinates (f, x, y, 0, true, true); |
| 9083 | tool_bar_p = EQ (window, f->tool_bar_window); | 9117 | tool_bar_p = EQ (window, f->tool_bar_window); |
| 9084 | 9118 | ||
| 9085 | if (tool_bar_p && event->xbutton.button < 4) | 9119 | if (tool_bar_p && event->xbutton.button < 4) |
| @@ -9089,7 +9123,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 9089 | } | 9123 | } |
| 9090 | #endif /* !USE_GTK */ | 9124 | #endif /* !USE_GTK */ |
| 9091 | 9125 | ||
| 9092 | if (!tool_bar_p) | 9126 | if (!tab_bar_p && !tool_bar_p) |
| 9093 | #if defined (USE_X_TOOLKIT) || defined (USE_GTK) | 9127 | #if defined (USE_X_TOOLKIT) || defined (USE_GTK) |
| 9094 | if (! popup_activated ()) | 9128 | if (! popup_activated ()) |
| 9095 | #endif | 9129 | #endif |
| @@ -9136,6 +9170,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 9136 | { | 9170 | { |
| 9137 | dpyinfo->grabbed |= (1 << event->xbutton.button); | 9171 | dpyinfo->grabbed |= (1 << event->xbutton.button); |
| 9138 | dpyinfo->last_mouse_frame = f; | 9172 | dpyinfo->last_mouse_frame = f; |
| 9173 | if (f && !tab_bar_p) | ||
| 9174 | f->last_tab_bar_item = -1; | ||
| 9139 | #if ! defined (USE_GTK) | 9175 | #if ! defined (USE_GTK) |
| 9140 | if (f && !tool_bar_p) | 9176 | if (f && !tool_bar_p) |
| 9141 | f->last_tool_bar_item = -1; | 9177 | f->last_tool_bar_item = -1; |
| @@ -10142,6 +10178,7 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset) | |||
| 10142 | int unit, font_ascent, font_descent; | 10178 | int unit, font_ascent, font_descent; |
| 10143 | #ifndef USE_X_TOOLKIT | 10179 | #ifndef USE_X_TOOLKIT |
| 10144 | int old_menu_bar_height = FRAME_MENU_BAR_HEIGHT (f); | 10180 | int old_menu_bar_height = FRAME_MENU_BAR_HEIGHT (f); |
| 10181 | int old_tab_bar_height = FRAME_TAB_BAR_HEIGHT (f); | ||
| 10145 | Lisp_Object fullscreen; | 10182 | Lisp_Object fullscreen; |
| 10146 | #endif | 10183 | #endif |
| 10147 | 10184 | ||
| @@ -10161,6 +10198,7 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset) | |||
| 10161 | 10198 | ||
| 10162 | #ifndef USE_X_TOOLKIT | 10199 | #ifndef USE_X_TOOLKIT |
| 10163 | FRAME_MENU_BAR_HEIGHT (f) = FRAME_MENU_BAR_LINES (f) * FRAME_LINE_HEIGHT (f); | 10200 | FRAME_MENU_BAR_HEIGHT (f) = FRAME_MENU_BAR_LINES (f) * FRAME_LINE_HEIGHT (f); |
| 10201 | FRAME_TAB_BAR_HEIGHT (f) = FRAME_TAB_BAR_LINES (f) * FRAME_LINE_HEIGHT (f); | ||
| 10164 | #endif | 10202 | #endif |
| 10165 | 10203 | ||
| 10166 | /* Compute character columns occupied by scrollbar. | 10204 | /* Compute character columns occupied by scrollbar. |
| @@ -10185,18 +10223,20 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset) | |||
| 10185 | FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3, | 10223 | FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3, |
| 10186 | false, Qfont); | 10224 | false, Qfont); |
| 10187 | #ifndef USE_X_TOOLKIT | 10225 | #ifndef USE_X_TOOLKIT |
| 10188 | if (FRAME_MENU_BAR_HEIGHT (f) != old_menu_bar_height | 10226 | if ((FRAME_MENU_BAR_HEIGHT (f) != old_menu_bar_height |
| 10227 | || FRAME_TAB_BAR_HEIGHT (f) != old_tab_bar_height) | ||
| 10189 | && !f->after_make_frame | 10228 | && !f->after_make_frame |
| 10190 | && (EQ (frame_inhibit_implied_resize, Qt) | 10229 | && (EQ (frame_inhibit_implied_resize, Qt) |
| 10191 | || (CONSP (frame_inhibit_implied_resize) | 10230 | || (CONSP (frame_inhibit_implied_resize) |
| 10192 | && NILP (Fmemq (Qfont, frame_inhibit_implied_resize)))) | 10231 | && NILP (Fmemq (Qfont, frame_inhibit_implied_resize)))) |
| 10193 | && (NILP (fullscreen = get_frame_param (f, Qfullscreen)) | 10232 | && (NILP (fullscreen = get_frame_param (f, Qfullscreen)) |
| 10194 | || EQ (fullscreen, Qfullwidth))) | 10233 | || EQ (fullscreen, Qfullwidth))) |
| 10195 | /* If the menu bar height changes, try to keep text height | 10234 | /* If the menu/tab bar height changes, try to keep text height |
| 10196 | constant. */ | 10235 | constant. */ |
| 10197 | adjust_frame_size | 10236 | adjust_frame_size |
| 10198 | (f, -1, FRAME_TEXT_HEIGHT (f) + FRAME_MENU_BAR_HEIGHT (f) | 10237 | (f, -1, FRAME_TEXT_HEIGHT (f) + FRAME_MENU_BAR_HEIGHT (f) |
| 10199 | - old_menu_bar_height, 1, false, Qfont); | 10238 | + FRAME_TAB_BAR_HEIGHT (f) |
| 10239 | - old_menu_bar_height - old_tab_bar_height, 1, false, Qfont); | ||
| 10200 | #endif /* USE_X_TOOLKIT */ | 10240 | #endif /* USE_X_TOOLKIT */ |
| 10201 | } | 10241 | } |
| 10202 | } | 10242 | } |
| @@ -13466,6 +13506,7 @@ x_create_terminal (struct x_display_info *dpyinfo) | |||
| 13466 | #if defined (USE_X_TOOLKIT) || defined (USE_GTK) | 13506 | #if defined (USE_X_TOOLKIT) || defined (USE_GTK) |
| 13467 | terminal->popup_dialog_hook = xw_popup_dialog; | 13507 | terminal->popup_dialog_hook = xw_popup_dialog; |
| 13468 | #endif | 13508 | #endif |
| 13509 | terminal->change_tab_bar_height_hook = x_change_tab_bar_height; | ||
| 13469 | #ifndef HAVE_EXT_TOOL_BAR | 13510 | #ifndef HAVE_EXT_TOOL_BAR |
| 13470 | terminal->change_tool_bar_height_hook = x_change_tool_bar_height; | 13511 | terminal->change_tool_bar_height_hook = x_change_tool_bar_height; |
| 13471 | #endif | 13512 | #endif |
diff --git a/src/xterm.h b/src/xterm.h index 985648a1d98..69af552e078 100644 --- a/src/xterm.h +++ b/src/xterm.h | |||
| @@ -1178,6 +1178,7 @@ extern void initial_set_up_x_back_buffer (struct frame *f); | |||
| 1178 | 1178 | ||
| 1179 | /* Defined in xfns.c. */ | 1179 | /* Defined in xfns.c. */ |
| 1180 | extern void x_real_positions (struct frame *, int *, int *); | 1180 | extern void x_real_positions (struct frame *, int *, int *); |
| 1181 | extern void x_change_tab_bar_height (struct frame *, int); | ||
| 1181 | extern void x_change_tool_bar_height (struct frame *, int); | 1182 | extern void x_change_tool_bar_height (struct frame *, int); |
| 1182 | extern void x_implicitly_set_name (struct frame *, Lisp_Object, Lisp_Object); | 1183 | extern void x_implicitly_set_name (struct frame *, Lisp_Object, Lisp_Object); |
| 1183 | extern void x_set_scroll_bar_default_width (struct frame *); | 1184 | extern void x_set_scroll_bar_default_width (struct frame *); |