summaryrefslogtreecommitdiff
path: root/docs/handbook/mnv/gui-extension.md
blob: c815503f8059adf52f5bf02f5a3f8b163b8dfd9d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
# MNV — GUI Extension

## Overview

MNV supports a **graphical user interface (GUI)** through a toolkit-agnostic
abstraction layer.  The GUI is optional — MNV works perfectly as a terminal
application — but when enabled it adds menus, toolbars, scrollbars, tearoff
menus, tablines, font selection, direct mouse integration, drag-and-drop, and
balloon-eval tooltips.

The GUI is activated by:
- Invoking the binary as `gmnv` (via symlink).
- Running `:gui` from within terminal MNV.
- Compiling with `FEAT_GUI` and having no `--nofork` / `-f` flag.

The compile-time guard for all GUI code is:

```c
#if defined(FEAT_GUI_MOTIF) \
    || defined(FEAT_GUI_GTK) \
    || defined(FEAT_GUI_HAIKU) \
    || defined(FEAT_GUI_MSWIN) \
    || defined(FEAT_GUI_PHOTON)
# if !defined(FEAT_GUI) && !defined(NO_X11_INCLUDES)
#  define FEAT_GUI
# endif
#endif
```

---

## Architecture

### Abstraction Layer: `gui.c` / `gui.h`

The file `src/gui.c` is the **core GUI dispatcher**.  It owns the global
`gui_T gui` struct and provides toolkit-independent functions that delegate to
`gui_mch_*()` ("machine-specific") callbacks implemented in each backend.

```c
// src/gui.c
gui_T gui;
```

Key functions in `gui.c`:

| Function | Purpose |
|---|---|
| `gui_start()` | Entry point — init toolkit, fork if needed, start event loop. |
| `gui_attempt_start()` | Try to initialise the GUI; fall back to terminal on failure. |
| `gui_do_fork()` | Fork the process so `gmnv file` detaches from the shell. |
| `gui_read_child_pipe()` | IPC between parent and GUI child after fork. |
| `gui_check_pos()` | Clamp cursor within drawable area. |
| `gui_reset_scroll_region()` | Reset the scrollable region to full screen. |
| `gui_outstr()` | Output a string to the GUI display. |
| `gui_screenchar()` | Draw a single character at a screen position. |
| `gui_outstr_nowrap()` | Draw a string without line wrapping. |
| `gui_delete_lines()` / `gui_insert_lines()` | Scroll line ranges. |
| `gui_xy2colrow()` | Convert pixel coordinates to character row/column. |
| `gui_do_scrollbar()` | Enable/disable a scrollbar for a window. |
| `gui_update_horiz_scrollbar()` | Refresh horizontal scrollbar state. |
| `gui_set_fg_color()` / `gui_set_bg_color()` | Set foreground/background. |
| `init_gui_options()` | Initialise GUI-related option defaults. |
| `xy2win()` | Find which window a pixel coordinate falls in. |

### The `gui_T` Data Structure

Declared in `src/gui.h`, `gui_T` holds all mutable GUI state.  Its fields
include (representative, not exhaustive):

- Widget/window handles (toolkit-specific, cast to `void *` or typed per
  backend).
- `gui.in_use` — boolean, TRUE when GUI is active.
- `gui.starting` — TRUE during initialisation.
- `gui.dofork` — whether to fork on startup.
- `gui.char_width` / `gui.char_height` / `gui.char_ascent` — font metrics.
- `gui.border_offset` — pixel offset for the text area border.
- `gui.num_rows` / `gui.num_cols` — grid dimensions.
- Scrollbar state arrays.
- Colour values for foreground, background, scrollbar, menu.
- Tabline widget handles (for `FEAT_GUI_TABLINE`).

### Coordinate Macros

`gui.h` defines macros for converting between character cells and pixel
coordinates:

```c
// Non-MSWIN (X11/GTK/Motif/Haiku/Photon):
#define TEXT_X(col)   ((col) * gui.char_width  + gui.border_offset)
#define TEXT_Y(row)   ((row) * gui.char_height + gui.char_ascent + gui.border_offset)
#define FILL_X(col)   ((col) * gui.char_width  + gui.border_offset)
#define FILL_Y(row)   ((row) * gui.char_height + gui.border_offset)
#define X_2_COL(x)    (((x) - gui.border_offset) / gui.char_width)
#define Y_2_ROW(y)    (((y) - gui.border_offset) / gui.char_height)

// MSWIN:
#define TEXT_X(col)   ((col) * gui.char_width)
#define TEXT_Y(row)   ((row) * gui.char_height + gui.char_ascent)
// etc.
```

### Scrollbar Constants

```c
#define SBAR_NONE       (-1)
#define SBAR_LEFT       0
#define SBAR_RIGHT      1
#define SBAR_BOTTOM     2
```

---

## GUI Backends

### GTK 2 / GTK 3  (`gui_gtk.c`, `gui_gtk_f.c`, `gui_gtk_x11.c`)

The GTK backend is the most actively maintained Linux GUI.  It consists of
three files:

**`gui_gtk.c`** — High-level GTK widget management:

- Toolbar creation and tearoff support.
- Find/Replace dialog (`find_replace_cb()`).
- Dialog entry callbacks: `entry_activate_cb()`, `entry_changed_cb()`.

It includes GTK headers conditionally:

```c
#ifdef FEAT_GUI_GTK
# if GTK_CHECK_VERSION(3,0,0)
#  include <gdk/gdkkeysyms-compat.h>
# else
#  include <gdk/gdkkeysyms.h>
# endif
# include <gdk/gdk.h>
# include <gtk/gtk.h>
#endif
```

**`gui_gtk_f.c` / `gui_gtk_f.h`** — A custom GTK container widget (the "form
widget") that manages the drawing area, scrollbars, and toolbar layout.  This
replaces GTK's standard layout containers with one optimised for MNV's needs.

**`gui_gtk_x11.c`** — Low-level integration with X11 under GTK:

- Display connection and window management.
- Keyboard input translation (GDK key events → MNV key codes).
- X selection handling (clipboard).
- Drag-and-drop (`FEAT_DND`).
- Input method support via `gui_xim.c`.

**CMake source list for GTK:**

```cmake
set(GUI_SRC
    gui.c
    gui_gtk.c
    gui_gtk_f.c
    gui_gtk_x11.c
    gui_beval.c
)
```

**GTK 3 vs GTK 2 detection:**

```cmake
if(MNV_GUI STREQUAL "auto" OR MNV_GUI STREQUAL "gtk3")
    pkg_check_modules(GTK3 QUIET gtk+-3.0)
    if(GTK3_FOUND)
        set(USE_GTK3 1)
        set(FEAT_GUI_GTK 1)
        ...
    endif()
endif()
```

GTK 3 support was added by Kazunobu Kuriyama (2016) and is now the default.

### Motif (`gui_motif.c`, `gui_x11.c`, `gui_xmdlg.c`, `gui_xmebw.c`)

The Motif backend uses the Xt/Motif widget set:

```cmake
set(GUI_SRC
    gui.c
    gui_motif.c
    gui_x11.c
    gui_beval.c
    gui_xmdlg.c
    gui_xmebw.c
)
```

- `gui_motif.c` — Motif menus, toolbar, scrollbars.
- `gui_x11.c` — Raw X11 drawing, event loop, selection.
- `gui_xmdlg.c` — Motif dialogs (file selection, font picker).
- `gui_xmebw.c` / `gui_xmebw.h` / `gui_xmebwp.h` — "Enhanced Button
  Widget" — a custom Motif widget for toolbar buttons with icons.

### Win32 (`gui_w32.c`)

The native Windows GUI uses the Win32 API directly (no toolkit):

- `gui_w32.c` — window creation, message loop, menus, scrollbars, Direct2D
  text rendering.
- `gui_dwrite.cpp` / `gui_dwrite.h` — DirectWrite rendering for high-quality
  font display on Windows (controlled by `FEAT_DIRECTX` / `FEAT_RENDER_OPTIONS`).
- `gui_w32_rc.h` — resource header for the Windows resource file (`mnv.rc`).

### Haiku (`gui_haiku.cc`, `gui_haiku.h`)

BeOS/Haiku GUI backend using the native BApplication/BWindow/BView API:

```c
#ifdef FEAT_GUI_HAIKU
# include "gui_haiku.h"
#endif
```

Supports drag-and-drop (`HAVE_DROP_FILE`).

### Photon (`gui_photon.c`)

QNX Photon microGUI backend.  Legacy, for QNX RTOS systems:

```c
#ifdef FEAT_GUI_PHOTON
# include <Ph.h>
# include <Pt.h>
# include "photon/PxProto.h"
#endif
```

---

## GUI Features

### On-the-Fly Scrolling

GTK and Win32 support immediate scroll redraw rather than deferring to the
main loop:

```c
#if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_GTK)
# define USE_ON_FLY_SCROLL
#endif
```

### Drag and Drop

File dropping is enabled for GTK (with `FEAT_DND`), Win32, and Haiku:

```c
#if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \
        || defined(FEAT_GUI_MSWIN) \
        || defined(FEAT_GUI_HAIKU)
# define HAVE_DROP_FILE
#endif
```

### Balloon Evaluation (Tooltips)

`gui_beval.c` implements balloon-eval — hover tooltips used for debugger
variable inspection, function signatures, and similar features.  Controlled
by `FEAT_BEVAL` / `FEAT_BEVAL_TIP`.

### Tab Page Line

When `FEAT_GUI_TABLINE` is defined, the GUI displays a tab bar at the top of
the window for switching between tab pages.

```c
#if defined(FEAT_GUI_TABLINE)
static int gui_has_tabline(void);
#endif
```

### X Input Method (XIM)

`gui_xim.c` integrates X Input Methods for composing complex characters
(CJK, etc.) on X11.  Controlled by `FEAT_XIM`:

```c
#ifdef FEAT_XIM
# ifdef FEAT_GUI_GTK
   // GTK handles XIM through GtkIMContext
# else
   // Direct XIM protocol for Motif/X11
# endif
#endif
```

### GUI Forking

On Unix when `gmnv` starts, it forks so the parent shell returns to the
prompt while the child continues as the editor.  This happens in
`gui_do_fork()`:

```c
#ifdef GUI_MAY_FORK
static void gui_do_fork(void);

static int gui_read_child_pipe(int fd);

enum {
    GUI_CHILD_IO_ERROR,
    GUI_CHILD_OK,
    GUI_CHILD_FAILED
};
#endif
```

The fork is skipped when:
- `-f` flag is given.
- `'f'` is in `'guioptions'` (`p_go`).
- A background job is running (`job_any_running()`).

### Menus

Menu definitions are loaded from `runtime/menu.mnv` and `runtime/synmenu.mnv`.
The `:menu` command adds items to the menu bar.  GUI backends render menus
using platform-native widgets.

### Fonts

GUI font handling is integrated with the `'guifont'` and `'guifontwide'`
options.  Character metrics stored in `gui.char_width`, `gui.char_height`, and
`gui.char_ascent` are critical for all coordinate conversions.

---

## CMake GUI Detection

The CMake build tries toolkits in order:

```
1. GTK 3  (pkg-config: gtk+-3.0)
2. GTK 2  (pkg-config: gtk+-2.0)
3. Motif  (FindMotif)
4. none
```

If `MNV_GUI` is set to a specific toolkit and it's not found, the build fails:

```cmake
if(NOT _gui_found)
    if(MNV_GUI STREQUAL "none" OR MNV_GUI STREQUAL "auto")
        message(STATUS "GUI: disabled")
    else()
        message(FATAL_ERROR "Requested GUI '${MNV_GUI}' not found")
    endif()
endif()
```

---

## GUI Symlinks

When the GUI is compiled in, the install step creates additional symlinks:

```cmake
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink mnv ${_bindir}/gmnv)
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink mnv ${_bindir}/gview)
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink mnv ${_bindir}/gmnvdiff)
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink mnv ${_bindir}/rgmnv)
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink mnv ${_bindir}/rgview)
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink mnv ${_bindir}/emnv)
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink mnv ${_bindir}/eview)
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink mnv ${_bindir}/gvi)
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink mnv ${_bindir}/gvim)
```

Desktop files and icons are also installed:

```cmake
install(FILES runtime/mnv.desktop  DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
install(FILES runtime/gmnv.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
```

Icons at 16×16, 32×32, 48×48, and 128×128 plus a scalable SVG are placed in
the hicolor icon theme.

---

## Runtime Configuration

GUI behaviour is customised via options in `.mnvrc` or `.gmnvrc`:

| Option | Purpose |
|---|---|
| `'guifont'` | Font face and size |
| `'guifontwide'` | Font for double-width characters |
| `'guioptions'` | Flags controlling which GUI elements are shown |
| `'guicursor'` | Cursor shape in different modes |
| `'guitablabel'` | Tab page label format |
| `'guitabtooltip'` | Tab page tooltip format |
| `'linespace'` | Extra pixels between lines |
| `'columns'` / `'lines'` | Window dimensions |
| `'toolbar'` | Toolbar display flags |

The `'guioptions'` string (aliased `p_go` in `option.h`) controls flags
like `f` (foreground — don't fork), `m` (menu bar), `T` (toolbar), `r`/`l`
(scrollbars), etc.

The `runtime/gmnvrc_example.mnv` file provides a starting template.

---

*This document describes MNV 10.0 as of build 287 (2026-04-03).*