Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,35 @@

### Notes
- No API or ABI changes
- Safe upgrade from **v1.0** - just rebuild your project after updating.
- Safe upgrade from **v1.0** - just rebuild your project after updating.

## [1.1.0] - 2025-10-17

### Features
- **Build:** Added Linux platform support across all modules.
- **Core:** Added Linux backend support.
- **Video:** Added X11-based backend support.
- **Thread:** Added Linux backend support.
- **Opengl:** Added Linux backend support.
- **System:** Added Linux backend support.
- **Video:** Added **palCreateCursorFrom()** to create system cursors.
- **Video:** Added **palSetFBConfig()** to select window FBConfig.
- **Video:** Added **PAL_VIDEO_FEATURE_WINDOW_SET_ICON** to `PalVideoFeatures` enum.
- **System:** Added **PAL_PLATFORM_API_COCOA** to `PalPlatformApiType` enum.
- **System:** Added **PAL_PLATFORM_API_ANDRIOD** to `PalPlatformApiType` enum.
- **System:** Added **PAL_PLATFORM_API_UIKIT** to `PalPlatformApiType` enum.
- **System:** Added **PAL_PLATFORM_API_HEADLESS** to `PalPlatformApiType` enum.
- **Core:** Added **PAL_RESULT_INVALID_FBCONFIG_BACKEND** to `PalResult` enum.

### Changed
- **System:** `PalCPUInfo.architecture` is now determined at runtime instead of build time.
- **Opengl:** **palEnumerateGLFBConfigs()** now does not use the `glWindow` paramter. Set to `nullptr`

### Fixed
- Fixed a bug where **enter modal mode and exit modal mode** operations triggered only one event.
- Fixed repeated window state event (**minimized**, **maximized**, **restore**).

### Notes
- No API or ABI changes - existing Windows code remains compatible.
- Linux video support currently targets **X11** only: **Wayland** is planned for future releases.
- Safe upgrade from **v1.0.1** - just rebuild your project after updating.
30 changes: 27 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@

PAL is a lightweight, low-level, cross-platform abstraction layer in **C**, designed to be **explicit** and as close to the **OS** as possible — similar in philosophy to Vulkan. It gives you precise control without hidden behavior, making it ideal for developers who want performance and predictability.

PAL is transparent. All queries — window size, position, monitor info, and more — reflect the current platform state. Using PAL is like working directly with the OS: it applies no hidden logic, makes no assumptions, and leaves behavior fully in your control.

This approach gives you total control: you handle events, manage resources, and cache state explicitly. PAL provides the building blocks; how you use them — whether for simple applications or advanced frameworks — is entirely up to you.

Example – Get Window Size
```c
// Direct query from the platform — not cached by PAL
palGetWindowSize(window, &w, &h);
```
> Note: palGetWindowSize queries the OS directly. If your application needs continuous updates (e.g., window moves or resizes frequently), it is more efficient to listen to PAL events rather than repeatedly querying the OS. This ensures your app stays performant.

---

## Why PAL?
Expand Down Expand Up @@ -60,7 +71,11 @@ For more detailed examples, see the [tests folder](./tests) tests folder, which
---

## Philosophy

- PAL is a thin layer over the OS, not a framework or library.
- Queries return the current platform state, reflecting any changes made through direct OS calls.
- Developers are responsible for state tracking, caching, and event handling.
- PAL enables cross-platform consistency while preserving full OS behavior and control.
- Advanced users can build libraries or frameworks on top of PAL.
- Minimal overhead (close to raw OS calls)
- Explicit API (no hidden behavior or defaults)
- Event system supporting both polling and callbacks
Expand All @@ -73,9 +88,10 @@ For more detailed examples, see the [tests folder](./tests) tests folder, which

## Supported Platforms
- Windows (Vista+)
- Linux (X11)

## Planned Platforms
- Linux (X11/Wayland)
- Linux (Wayland)
- macOS (Cocoa)
- Android
- iOS
Expand All @@ -84,6 +100,8 @@ For more detailed examples, see the [tests folder](./tests) tests folder, which
- Standard C library
- Platform SDKs (Win32, X11, Cocoa, etc.)
- [Make for Windows](https://www.gnu.org/software/make/) (if not using Visual Studio)
- XRandR (1.2+) for X11
- libXcursor for X11

## Compilers
- GCC
Expand All @@ -97,6 +115,7 @@ For more detailed examples, see the [tests folder](./tests) tests folder, which
PAL is written in **C99** and uses **Premake** as its build system. Configure modules via [pal_config.lua](./pal_config.lua).
See [pal_config.h](./include/pal/pal_config.h) to see the reflection of modules that will be built.

**Windows**
```bash
premake\premake5.exe gmake2 # generate Makefiles (default: GCC)
premake\premake5.exe gmake2 --compiler=clang
Expand All @@ -105,6 +124,11 @@ premake\premake5.exe vs2022 # generate Visual Studio project (default: MS
premake\premake5.exe vs2022 --compiler=clang
```

**Linux**
```bash
./premake/premake5 gmake # generate Makefiles (default: GCC)
```

Enable tests in `pal_config.lua` by setting `PAL_BUILD_TESTS = true`.

---
Expand Down Expand Up @@ -132,7 +156,7 @@ PAL uses [Doxygen](https://www.doxygen.nl/) for generating API documentation.

```bash
cd docs
make doxygen
doxygen doxyfile
```

The generated HTML docs will be available in `docs/html/`.
Expand Down
3 changes: 2 additions & 1 deletion include/pal/pal_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,8 @@ typedef enum {
PAL_RESULT_INVALID_GL_FBCONFIG,
PAL_RESULT_INVALID_GL_VERSION,
PAL_RESULT_INVALID_GL_PROFILE,
PAL_RESULT_INVALID_GL_CONTEXT
PAL_RESULT_INVALID_GL_CONTEXT,
PAL_RESULT_INVALID_FBCONFIG_BACKEND
} PalResult;

/**
Expand Down
9 changes: 4 additions & 5 deletions include/pal/pal_opengl.h
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ PAL_API const PalGLInfo* PAL_CALL palGetGLInfo();
* If the count is 0 and the PalGLFBConfigs array is nullptr, the function fails
* and returns `PAL_RESULT_INSUFFICIENT_BUFFER`.
*
* @param[in] glWindow Pointer to the opengl window.
* @param[in] glWindow Set to nullptr.
* @param[in] count Capacity of the PalGLFBConfig array.
* @param[out] configs User allocated array of PalGLFBConfig.
*
Expand Down Expand Up @@ -313,10 +313,9 @@ PAL_API const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig(
* The opengl system must be initialized before this call. The created context
* will not be made current.
*
* After this call, the provided PalGLFBConfig will be set to the window
* permanently and cannot be changed. To change it, you must destroy the window
* and recreate it. If the window already has a PalGLFBConfig, the opengl system
* will use that and discard the provided one.
* The provided PalGLFBConfig must be the same as the one used to create the
* window. Once set, it cannot be changed. To change it, you must destroy the
* window and recreate it.
*
* @param[in] info Pointer to a PalGLContextCreateInfo struct that specifies
* paramters. Must not be nullptr.
Expand Down
6 changes: 5 additions & 1 deletion include/pal/pal_system.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,11 @@ typedef enum {
typedef enum {
PAL_PLATFORM_API_WIN32,
PAL_PLATFORM_API_WAYLAND,
PAL_PLATFORM_API_X11
PAL_PLATFORM_API_X11,
PAL_PLATFORM_API_COCOA,
PAL_PLATFORM_API_ANDRIOD,
PAL_PLATFORM_API_UIKIT,
PAL_PLATFORM_API_HEADLESS
} PalPlatformApiType;

/**
Expand Down
103 changes: 100 additions & 3 deletions include/pal/pal_video.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ typedef enum {
PAL_VIDEO_FEATURE_WINDOW_GET_STYLE = PAL_BIT(28),
PAL_VIDEO_FEATURE_CURSOR_SET_POS = PAL_BIT(29),
PAL_VIDEO_FEATURE_CURSOR_GET_POS = PAL_BIT(30),
PAL_VIDEO_FEATURE_WINDOW_SET_ICON = PAL_BIT(31),
} PalVideoFeatures;

/**
Expand Down Expand Up @@ -186,6 +187,23 @@ typedef enum {
PAL_FLASH_TRAY = PAL_BIT(1) /**< Flash the icon of the window.*/
} PalFlashFlag;

/**
* @enum PalFBConfigBackend
* @brief Represents the backend of a FBConfig.
*
* All FBConfig backends follow the format `PAL_CONFIG_BACKEND**` for
* consistency and API use.
*
* @since 1.1
* @ingroup pal_video
*/
typedef enum {
PAL_CONFIG_BACKEND_EGL,
PAL_CONFIG_BACKEND_GLX,
PAL_CONFIG_BACKEND_WGL,
PAL_CONFIG_BACKEND_PAL_OPENGL /**< Use PAL opengl module backend.*/
} PalFBConfigBackend;

/**
* @enum PalScancode
* @brief scancodes (layout independent keys) of a keyboard.
Expand Down Expand Up @@ -466,6 +484,26 @@ typedef enum {
PAL_MOUSE_BUTTON_MAX
} PalMouseButton;

/**
* @enum PalCursorType
* @brief System cursor types.
*
* All cursor types follow the format `PAL_CURSOR_**` for
* consistency and API use.
*
* @since 1.1
* @ingroup pal_video
*/
typedef enum {
PAL_CURSOR_ARROW,
PAL_CURSOR_HAND,
PAL_CURSOR_CROSS,
PAL_CURSOR_IBEAM,
PAL_CURSOR_WAIT,

PAL_CURSOR_MAX
} PalCursorType;

/**
* @struct PalMonitorInfo
* @brief Information about a monitor.
Expand Down Expand Up @@ -651,6 +689,41 @@ PAL_API void PAL_CALL palUpdateVideo();
*/
PAL_API PalVideoFeatures PAL_CALL palGetVideoFeatures();

/**
* @brief Set the FBConfig for the video system.
*
* The video system must be initialized before this call.
* The provided FBConfig will be used for all created windows after this call.
* The `index` is the loop index from the drivers
* supported FBConfigs.
*
* The `backend` is used to tell the video system, the source of the index.
* Examples: PAL_CONFIG_BACKEND_EGL tells the video system, we got this loop
* index from EGL. This will enable the video system to find your FBConfig.
*
* Example Flow:
* Enumerate and select your FBConfig using any backend(EGL, GLX, WGL, etc)
* and just let the video system know which one you used.
*
* If the backend passed is not the same as the one used,
* the video system might still get a FBConfig but it will not be the
* one requested.
*
* @param[in] index The FBConfig driver index.
* @param[in] backend The FBConfig backend or source.
*
* @return `PAL_RESULT_SUCCESS` on success or a result code on
* failure. Call palFormatResult() for more information.
*
* Thread safety: This function must be called from the main thread.
*
* @since 1.1
* @ingroup pal_video
*/
PAL_API PalResult PAL_CALL palSetFBConfig(
const int index,
PalFBConfigBackend backend);

/**
* @brief Return a list of all connected monitors.
*
Expand Down Expand Up @@ -1451,6 +1524,7 @@ PAL_API PalResult PAL_CALL palSetFocusWindow(PalWindow* window);
* @brief Create an icon.
*
* The video system must be initialized before this call.
* `PAL_VIDEO_FEATURE_WINDOW_SET_ICON` must be supported.
*
* @param[in] info Pointer to a PalIconCreateInfo struct that specifies
* paramters. Must not be nullptr.
Expand Down Expand Up @@ -1492,9 +1566,10 @@ PAL_API void PAL_CALL palDestroyIcon(PalIcon* icon);
* @brief Set the icon for the provided window.
*
* The video system must be initialized before this call.
* `PAL_VIDEO_FEATURE_WINDOW_SET_ICON` must be supported.
*
* @param[in] window Pointer to the window.
* @param[in] icon Pointer to the icon.
* @param[in] icon Pointer to the icon. Set to nullptr to revert.
*
* @return `PAL_RESULT_SUCCESS` on success or a result code on
* failure. Call palFormatResult() for more information.
Expand Down Expand Up @@ -1531,6 +1606,28 @@ PAL_API PalResult PAL_CALL palCreateCursor(
const PalCursorCreateInfo* info,
PalCursor** outCursor);

/**
* @brief Create a system cursor.
*
* The video system must be initialized before this call.
*
* @param[in] type The system cursor type to create. Must not be nullptr.
* @param[out] outCursor Pointer to a PalCursor to recieve the created
* cursor. Must not be nullptr.
*
* @return `PAL_RESULT_SUCCESS` on success or a result code on
* failure. Call palFormatResult() for more information.
*
* Thread safety: This function must only be called from the main thread.
*
* @since 1.1
* @ingroup pal_video
* @sa palDestroyCursor
*/
PAL_API PalResult PAL_CALL palCreateCursorFrom(
PalCursorType type,
PalCursor** outCursor);

/**
* @brief Destroy the provided cursor.
*
Expand All @@ -1550,7 +1647,7 @@ PAL_API PalResult PAL_CALL palCreateCursor(
PAL_API void PAL_CALL palDestroyCursor(PalCursor* cursor);

/**
* @brief Show or hide the provided cursor.
* @brief Show or hide the cursor.
*
* The video system must be initialized before this call.
* This affects all created cursors since the platform (OS) merges all cursors
Expand Down Expand Up @@ -1646,7 +1743,7 @@ PAL_API PalResult PAL_CALL palSetCursorPos(
* The video system must be initialized before this call.
*
* @param[in] window Pointer to the window.
* @param[in] cursor Pointer to the cursor.
* @param[in] cursor Pointer to the cursor. Set to nullptr to revert.
*
* @return `PAL_RESULT_SUCCESS` on success or a result code on
* failure. Call palFormatResult() for more information.
Expand Down
44 changes: 40 additions & 4 deletions pal.lua
Original file line number Diff line number Diff line change
Expand Up @@ -61,25 +61,61 @@ project "PAL"

if (PAL_BUILD_SYSTEM) then
filter {"system:windows", "configurations:*"}
files { "src/system/pal_system_win32.c" }
files { "src/system/pal_system_win32.c" }

filter {"system:linux", "configurations:*"}
files { "src/system/pal_system_linux.c" }
filter {}
end

if (PAL_BUILD_THREAD) then
filter {"system:windows", "configurations:*"}
files { "src/thread/pal_thread_win32.c" }
files { "src/thread/pal_thread_win32.c" }

filter {"system:linux", "configurations:*"}
files { "src/thread/pal_thread_linux.c" }

filter {}
end

if (PAL_BUILD_VIDEO) then
filter {"system:windows", "configurations:*"}
files { "src/video/pal_video_win32.c" }
files { "src/video/pal_video_win32.c" }

filter {"system:linux", "configurations:*"}
files { "src/video/pal_video_linux.c" }

-- check for wayland support. This is cross compiler
local paths = {
"/usr/include/wayland-client.h",
"/usr/include/x86_64-linux-gnu/wayland-client.h"
}

local found = false
for _, path in ipairs(paths) do
local file = io.open(path, "r")
if file then
file:close()
found = true
break
end
end

if found then
defines { "PAL_HAS_WAYLAND=1" }
else
defines { "PAL_HAS_WAYLAND=0" }
end

filter {}
end

if (PAL_BUILD_OPENGL) then
filter {"system:windows", "configurations:*"}
files { "src/opengl/pal_opengl_win32.c" }
files { "src/opengl/pal_opengl_win32.c" }

filter {"system:linux", "configurations:*"}
files { "src/opengl/pal_opengl_linux.c" }
filter {}
end

Expand Down
Binary file added premake/premake5
Binary file not shown.
Loading