Skip to content

Commit

Permalink
Merge branch 'main' into beta
Browse files Browse the repository at this point in the history
  • Loading branch information
dacap committed Jun 19, 2024
2 parents 580fb80 + 36abe03 commit 188d31f
Show file tree
Hide file tree
Showing 20 changed files with 245 additions and 115 deletions.
34 changes: 34 additions & 0 deletions base/fs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,40 @@ std::string get_file_title_with_path(const std::string& filename)
return filename;
}

std::string get_relative_path(const std::string& filename, const std::string& base_path)
{
std::vector<std::string> baseDirs;
split_string(base_path, baseDirs, "/\\");

std::vector<std::string> toParts;
split_string(filename, toParts, "/\\");

// Find the common prefix
auto itFrom = baseDirs.begin();
auto itTo = toParts.begin();

while (itFrom != baseDirs.end() && itTo != toParts.end() && *itFrom == *itTo) {
++itFrom;
++itTo;
}

if (itFrom == baseDirs.begin() && itTo == toParts.begin()) {
// No common prefix
return filename;
}

// Calculate the number of directories to go up from base path
std::string relativePath;
for (auto it = itFrom; it != baseDirs.end(); ++it)
relativePath = base::join_path(relativePath, "..");

// Append the remaining part of 'toPath'
for (auto it = itTo; it != toParts.end(); ++it)
relativePath = base::join_path(relativePath, *it);

return relativePath;
}

std::string join_path(const std::string& path, const std::string& file)
{
std::string result(path);
Expand Down
3 changes: 3 additions & 0 deletions base/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ namespace base {
std::string get_file_title(const std::string& filename);
std::string get_file_title_with_path(const std::string& filename);

// Returns the relative path of the given filename from the base_path.
std::string get_relative_path(const std::string& filename, const std::string& base_path);

// Joins two paths or a path and a file name with a path-separator.
std::string join_path(const std::string& path, const std::string& file);

Expand Down
17 changes: 17 additions & 0 deletions base/fs_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,23 @@ TEST(FS, GetFileTitleWithPath)
EXPECT_EQ("C:\\", get_file_title_with_path("C:\\.cpp"));
}

TEST(FS, GetRelativePath)
{
EXPECT_EQ("C:\\foo\\bar\\test.file", get_relative_path("C:\\foo\\bar\\test.file", "D:\\another\\disk"));

#if LAF_WINDOWS
EXPECT_EQ("bar\\test.file", get_relative_path("C:\\foo\\bar\\test.file", "C:\\foo"));
EXPECT_EQ("C:\\foo\\bar\\test.file", get_relative_path("C:\\foo\\bar\\test.file", "D:\\another\\disk"));
EXPECT_EQ("..\\bar\\test.file", get_relative_path("C:\\foo\\bar\\test.file", "C:\\foo\\another"));
EXPECT_EQ("..\\..\\bar\\test.file", get_relative_path("C:\\foo\\bar\\test.file", "C:\\foo\\a\\b"));
#else
EXPECT_EQ("bar/test.file", get_relative_path("C:/foo/bar/test.file", "C:/foo"));
EXPECT_EQ("C:/foo/bar/test.file", get_relative_path("C:/foo/bar/test.file", "D:/another/disk"));
EXPECT_EQ("../bar/test.file", get_relative_path("/foo/bar/test.file", "/foo/another"));
EXPECT_EQ("../../bar/test.file", get_relative_path("/foo/bar/test.file", "/foo/a/b"));
#endif
}

TEST(FS, JoinPath)
{
std::string sep;
Expand Down
15 changes: 7 additions & 8 deletions os/common/system.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ class CommonSystem : public System {
CommonSystem();
~CommonSystem();

void setAppName(const std::string& appName) override { }
const std::string& appName() const override { return m_appName; }
void setAppName(const std::string& appName) override { m_appName = appName; }
void setAppMode(AppMode appMode) override { }

void markCliFileAsProcessed(const std::string& fn) override { }
Expand All @@ -31,13 +32,10 @@ class CommonSystem : public System {
return (Capabilities)0;
}

void setTabletAPI(TabletAPI api) override {
// Do nothing by default
}

TabletAPI tabletAPI() const override {
return TabletAPI::Default;
}
// Do nothing options (these functions are for Windows-only at the
// moment)
void setTabletOptions(const TabletOptions&) override { }
TabletOptions tabletOptions() const override { return TabletOptions(); }

void errorMessage(const char* msg) override;

Expand Down Expand Up @@ -87,6 +85,7 @@ class CommonSystem : public System {
void destroyInstance();

private:
std::string m_appName;
Ref<NativeDialogs> m_nativeDialogs;
};

Expand Down
1 change: 1 addition & 0 deletions os/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "os/surface.h"
#include "os/surface_format.h"
#include "os/system.h"
#include "os/tablet_options.h"
#include "os/window.h"
#include "os/window_spec.h"

Expand Down
7 changes: 7 additions & 0 deletions os/skia/skia_surface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,10 @@ const SkImage* SkiaSurface::getOrCreateTextureImage() const
if (!win || !win->sk_grCtx())
return nullptr;

// Invalidate the cached texture if the bitmap pixels were modified.
if (m_cachedGen && m_cachedGen != m_bitmap.getGenerationID())
m_image.reset();

if (m_image && m_image->isValid(win->sk_grCtx()))
return m_image.get();
if (uploadBitmapAsTexture() &&
Expand Down Expand Up @@ -856,6 +860,9 @@ bool SkiaSurface::uploadBitmapAsTexture() const
ii.alphaType(),
nullptr);

if (m_image)
m_cachedGen = m_bitmap.getGenerationID();

return (m_image != nullptr);
}

Expand Down
2 changes: 2 additions & 0 deletions os/skia/skia_surface.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ class SkiaSurface final : public Surface {

SkBitmap m_bitmap;
#if SK_SUPPORT_GPU
// Cached m_bitmap generation in the GPU texture.
mutable uint32_t m_cachedGen = 0;
mutable sk_sp<SkImage> m_image;
#endif
sk_sp<SkSurface> m_surface;
Expand Down
7 changes: 4 additions & 3 deletions os/skia/skia_system.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,12 @@ class SkiaSystem final : public SkiaSystemBase {
);
}

void setTabletAPI(TabletAPI api) override {
void setTabletOptions(const TabletOptions& options) override {
#if LAF_WINDOWS
SkiaSystemBase::setTabletAPI(api);
SkiaSystemBase::setTabletOptions(options);
if (SkiaWindow* window = dynamic_cast<SkiaWindow*>(defaultWindow())) {
window->onTabletAPIChange();
// TODO notify all windows
window->onTabletOptionsChange();
}
#endif
}
Expand Down
47 changes: 16 additions & 31 deletions os/system.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "os/keys.h"
#include "os/ref.h"
#include "os/screen.h"
#include "os/tablet_options.h"
#include "os/window.h"
#include "os/window_spec.h"

Expand Down Expand Up @@ -50,27 +51,6 @@ namespace os {
: std::runtime_error(msg) { }
};

// Windows-specific details: API to use to get tablet input information.
enum class TabletAPI {
// Default tablet API to use in the system (Windows Ink on
// Windows; only valid value on other systems).
Default = 0,

// Use Windows 8/10 pointer messages (Windows Ink).
WindowsPointerInput = 0,

// Use the Wintab API to get pressure information from packets but
// mouse movement from Windows system messages
// (WM_MOUSEMOVE).
Wintab = 1,

// Use the Wintab API processing packets directly (pressure and
// stylus movement information). With this we might get more
// precision from the device (but still work-in-progress, some
// messages might be mixed up).
WintabPackets = 2,
};

class System : public RefCount {
protected:
virtual ~System() { }
Expand All @@ -92,11 +72,15 @@ namespace os {
[[nodiscard]] static SystemRef makeSkia();
#endif

// Windows-specific: The app name at the moment is used to receive
// DDE messages (WM_DDE_INITIATE) and convert WM_DDE_EXECUTE
// messages into Event::DropFiles. This allows to the user
// double-click files in the File Explorer and open the file in a
// running instance of your app.
// The app name is used in several places.
//
// For X11 it's used for the WM_CLASS name of the main window.
//
// For Windows it's used for 1) the main window class name, and
// 2) to receive DDE messages (WM_DDE_INITIATE) and convert
// WM_DDE_EXECUTE messages into Event::DropFiles. This allows to
// the user double-click files in the File Explorer and open the
// file in a running instance of your app.
//
// To receive DDE messages you have to configure the registry in
// this way (HKCR=HKEY_CLASSES_ROOT):
Expand All @@ -110,6 +94,7 @@ namespace os {
//
// The default value of "HKCR\AppFile\shell\open\ddeexec\application"
// must match the "appName" given in this function.
virtual const std::string& appName() const = 0;
virtual void setAppName(const std::string& appName) = 0;

// We can use this function to create an application that can run
Expand Down Expand Up @@ -145,14 +130,14 @@ namespace os {
return (int(capabilities()) & int(c)) == int(c);
}

// Sets the specific API to use to process tablet/stylus/pen
// messages.
// Sets the specific API/Options to use to process
// tablet/stylus/pen messages.
//
// It can be used to avoid loading wintab32.dll too (sometimes a
// program can be locked when we load the wintab32.dll, so we need
// program can crash when we load a buggy wintab32.dll, so we need
// a way to opt-out loading this library.)
virtual void setTabletAPI(TabletAPI api) = 0;
virtual TabletAPI tabletAPI() const = 0;
virtual void setTabletOptions(const TabletOptions& opts) = 0;
virtual TabletOptions tabletOptions() const = 0;

// Error logging.
virtual void errorMessage(const char* msg) = 0;
Expand Down
55 changes: 55 additions & 0 deletions os/tablet_options.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// LAF OS Library
// Copyright (c) 2024 Igara Studio S.A.
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.

#ifndef OS_TABLET_OPTIONS_H_INCLUDED
#define OS_TABLET_OPTIONS_H_INCLUDED
#pragma once

namespace os {

// Windows-specific details: API to use to get tablet input
// information.
enum class TabletAPI {
// Default tablet API to use in the system (Windows Ink on
// Windows; only valid value on other systems).
Default = 0,

// Use Windows 8/10 pointer messages (Windows Ink).
WindowsPointerInput = 0,

// Use the Wintab API to get pressure information from packets but
// mouse movement from Windows system messages
// (WM_MOUSEMOVE).
Wintab = 1,

// Use the Wintab API processing packets directly (pressure and
// stylus movement information). With this we might get more
// precision from the device (but still work-in-progress, some
// messages might be mixed up).
WintabPackets = 2,
};

struct TabletOptions {
#if LAF_WINDOWS
// Windows API to get stylus/digital tablet position of the pen
// (Windows Pointer API, legacy Wintab, etc.).
TabletAPI api = TabletAPI::Default;

// Use a fix for live streaming software like OBS to set the
// cursor position each time we receive a pointer event like
bool setCursorFix = false;
#endif

#if LAF_LINUX
// An user-defined string to detect the stylus device from
// "xinput --list" command.
std::string detectStylusPattern;
#endif
};

} // namespace os

#endif
15 changes: 5 additions & 10 deletions os/win/system.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// LAF OS Library
// Copyright (C) 2020-2023 Igara Studio S.A.
// Copyright (C) 2020-2024 Igara Studio S.A.
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
Expand Down Expand Up @@ -175,19 +175,14 @@ void SystemWin::setAppMode(AppMode appMode)
}
}

void SystemWin::setAppName(const std::string& appName)
void SystemWin::setTabletOptions(const TabletOptions& options)
{
m_appName = appName;
}

void SystemWin::setTabletAPI(TabletAPI api)
{
m_tabletAPI = api;
m_tabletOptions = options;

// If the user selects the wintab API again, we remove any possible
// file indicating a crash in the past.
if (m_tabletAPI == TabletAPI::Wintab ||
m_tabletAPI == TabletAPI::WintabPackets) {
if (m_tabletOptions.api == TabletAPI::Wintab ||
m_tabletOptions.api == TabletAPI::WintabPackets) {
m_wintabApi.resetCrashFileIfPresent();
}
}
Expand Down
10 changes: 3 additions & 7 deletions os/win/system.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,8 @@ class SystemWin : public CommonSystem {
WinAPI& winApi() { return m_winApi; }
WintabAPI& wintabApi() { return m_wintabApi; }

void setAppName(const std::string& appName) override;
std::string appName() const { return m_appName; }

void setTabletAPI(TabletAPI api) override;
TabletAPI tabletAPI() const override { return m_tabletAPI; }
void setTabletOptions(const TabletOptions& options) override;
TabletOptions tabletOptions() const override { return m_tabletOptions; }

bool isKeyPressed(KeyScancode scancode) override;
int getUnicodeFromScancode(KeyScancode scancode) override;
Expand All @@ -60,8 +57,7 @@ class SystemWin : public CommonSystem {
void _setInternalMousePosition(const Event& ev);

private:
std::string m_appName;
TabletAPI m_tabletAPI = TabletAPI::Default;
TabletOptions m_tabletOptions;
WinAPI m_winApi;
WintabAPI m_wintabApi;
gfx::Point m_screenMousePos;
Expand Down
Loading

0 comments on commit 188d31f

Please sign in to comment.