-# gui
\ No newline at end of file
+# D-Modem desktop apps
+
+Native apps for D-Modem on Windows, macOS and Linux.
+
+Each app starts dmodemd (or reaches one that already runs), and shows the
+modem as a desktop program should: dial and answer from a window, change
+its settings without AT commands, and see how the last call went. All three
+are thin native shells over one small C library, libdmodemctl, so they
+behave the same.
+
+- **Modem**: the call's state, dial, answer and hang up, and the line it uses
+- **Terminal**: the AT console, and the modem's own setup screens (AT!CF, AT!CT)
+- **Settings**: every modem setting as a native control, from AT!M
+- **Call Stats**: the last call's rate, modulation, error control and line figures (AT#UD, ATI11)
+- **Line settings**: a SIP account, a USB modem, or a modem that already runs
+- **Windows 95 and later**: plain Win32, built with Open Watcom; on Windows 9x it reaches a modem over TCP or a COM port
+
+| | Windows | macOS | Linux |
+| --- | --- | --- | --- |
+| Toolkit | Win32, C++ | SwiftUI | GTK 4, libadwaita, VTE |
+| Runs on | Windows 95 and later | macOS 13 and later | GTK 4.10, libadwaita 1.5 and VTE 0.76 or later (Ubuntu 24.04, Fedora 40) |
+
+
+
+## Quick start
+
+Linux:
+
+ sudo apt install cmake libgtk-4-dev libadwaita-1-dev libvte-2.91-gtk4-dev
+ cmake -S . -B build && cmake --build build && ./build/linux/dmodem-gui
+
+Windows: `cmake -S . -B build -A Win32 && cmake --build build --config Release`,
+or for Windows 95 and later, `windows/build-watcom.sh` with Open Watcom 2.0.
+
+macOS: `brew install xcodegen && cd macos && xcodegen && open DModem.xcodeproj`.
+
+The Settings page needs a dmodemd with AT!M (D-Modem's main branch since
+D-Modem/D-Modem#103); the other pages work with any D-Modem 1.0.
+
+## Documentation
+
+- [Design](docs/design.md): how the apps are built, what they share, and the Windows 9x notes
+- [libdmodemctl](core/include/dmodemctl.h): the library's API
+
+## The D-Modem suite
+
+| Repository | What it is |
+| --- | --- |
+| [D-Modem](https://github.com/D-Modem/D-Modem) | The open V.92 softmodem: dmodemd, libdmodem and the Asterisk, FreeSWITCH and ARI modules |
+| [app](https://github.com/D-Modem/app) | The D-Modem app for Android and iOS: a dial-up modem on a SIP call |
+| [gui](https://github.com/D-Modem/gui) | D-Modem on the desktop: native apps for Windows, macOS and Linux |
+| [hardware](https://github.com/D-Modem/hardware) | pico-serial: RP2040 serial adapters and phone-line USB sticks |
+| [menu](https://github.com/D-Modem/menu) | modemmenu: the login and menu dial-up callers reach |
+| [bbs](https://github.com/D-Modem/bbs) | A bulletin board for telnet, SSH, TN3270 and modem callers |
+| [go3270](https://github.com/D-Modem/go3270) | A Go library for 3270 terminal servers, used by bbs |
+| [brand](https://github.com/D-Modem/brand) | Logos, colours, type and the naming guide |
+
+## Licence
+
+BSD 3-Clause ([LICENSE](LICENSE)).
diff --git a/assets/dmodem.svg b/assets/dmodem.svg
new file mode 100644
index 0000000..66401ab
--- /dev/null
+++ b/assets/dmodem.svg
@@ -0,0 +1,5 @@
+
diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt
new file mode 100644
index 0000000..02d1da5
--- /dev/null
+++ b/core/CMakeLists.txt
@@ -0,0 +1,26 @@
+# libdmodemctl: what the desktop apps share, in plain C with no
+# dependencies. Static for the Linux app; a DLL for the Windows app's
+# P/Invoke (-DDMODEMCTL_SHARED=ON).
+option(DMODEMCTL_SHARED "Build libdmodemctl as a shared library" OFF)
+
+set(DMODEMCTL_SOURCES
+ src/session.c
+ src/model.c
+ src/diag.c
+ src/vt.c
+ src/daemon.c
+ src/util.c)
+
+if(DMODEMCTL_SHARED)
+ add_library(dmodemctl SHARED ${DMODEMCTL_SOURCES})
+ target_compile_definitions(dmodemctl PRIVATE DMC_BUILD_DLL)
+ set_target_properties(dmodemctl PROPERTIES C_VISIBILITY_PRESET hidden)
+else()
+ add_library(dmodemctl STATIC ${DMODEMCTL_SOURCES})
+endif()
+target_include_directories(dmodemctl PUBLIC include)
+if(MSVC)
+ target_compile_options(dmodemctl PRIVATE /W4 /wd4996)
+else()
+ target_compile_options(dmodemctl PRIVATE -Wall -Wextra -Wshadow)
+endif()
diff --git a/core/include/dmodemctl.h b/core/include/dmodemctl.h
new file mode 100644
index 0000000..b5999f9
--- /dev/null
+++ b/core/include/dmodemctl.h
@@ -0,0 +1,298 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2026, D-Modem
+ *
+ * dmodemctl.h - the part of D-Modem's desktop apps that is not drawing.
+ *
+ * The Windows, macOS and Linux apps are thin native shells over this
+ * small C library, so that each of them is only views. It does no I/O
+ * of its own and starts no threads: each app opens the modem's DTE (a
+ * pty, a TCP socket) in its own way, hands the bytes it reads to
+ * dmc_feed(), writes what dmc_output() gives it, and calls dmc_poll()
+ * from a timer. That keeps it simple to call from C (GTK), C#
+ * (P/Invoke) and Swift.
+ *
+ * Its parts:
+ * - dmc_session: the AT conversation with dmodemd: commands and their
+ * responses, the call's state from the result codes (RING, CONNECT,
+ * NO CARRIER), the escape to command mode and hanging up, and the
+ * stream for the app's terminal view.
+ * - dmc_model: the modem's settings, from AT!M, for a native settings
+ * page.
+ * - dmc_diag: the last call's statistics, from AT#UD (Microsoft's
+ * Unimodem diagnostics), as labelled rows.
+ * - dmc_vt: a small ANSI terminal screen, for the apps whose toolkit
+ * has no terminal widget (Windows and macOS): the AT console and the
+ * full-screen configurator (AT!CF).
+ * - dmc_daemon_*: starting dmodemd and reading what it prints.
+ *
+ * Strings are UTF-8. A const char * the library returns stays valid
+ * until the next call on the same object.
+ */
+#ifndef DMODEMCTL_H
+#define DMODEMCTL_H
+
+#include