diff --git a/.gitignore b/.gitignore
index 8ec5a32..65106e7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,10 @@
resource.rc
.DS_Store
+compile_commands.json
+
+.cache
+
data/
build/
*.res
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2b839e4..79bc261 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.13)
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
project(lwp
LANGUAGES C)
@@ -35,13 +37,17 @@ if(NOT DEFINED PROGRAM_VERSION)
message(WARNING "Can't determine Layered WallPaper version")
endif()
-set(_SOURCE_FILES
- main.c
- debug.c
- parser.c
- wallpaper.c
- window.c
+set(_CORE_SOURCE_FILES
+ core/main.c
+ core/debug.c
+ core/parser.c
+ core/wallpaper.c
+ core/window.c
)
+
+set(_CONTROL_SOURCE_FILES
+ control_panel/main.c
+ )
# Windows resource file
if(_UNAME STREQUAL "WIN32")
@@ -54,24 +60,29 @@ if(_UNAME STREQUAL "WIN32")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resource.template.rc ${CMAKE_CURRENT_SOURCE_DIR}/resource.rc
@ONLY)
- list(APPEND _SOURCE_FILES "resource.rc")
+ list(APPEND _CORE_SOURCE_FILES "resource.rc")
endif()
# SDL2 dependency
find_package(SDL2 REQUIRED CONFIG)
-set(_INCLUDE_DIRS ${SDL2_INCLUDE_DIRS})
-set(_LIBS ${SDL2_LIBRARIES})
+set(_CORE_INCLUDE_DIRS ${SDL2_CORE_INCLUDE_DIRS})
+set(_CORE_LIBS ${SDL2_LIBRARIES})
+
+# GTK4 depenency
+find_package(PkgConfig REQUIRED)
+pkg_check_modules(GTK4 REQUIRED IMPORTED_TARGET gtk4)
+set(_CONTROL_LIBS PkgConfig::GTK4)
if (_UNAME STREQUAL "DARWIN")
# MacOSX framework dependencies
- list(APPEND _LIBS "-framework CoreGraphics" "-framework Foundation")
+ list(APPEND _CORE_LIBS "-framework CoreGraphics" "-framework Foundation")
endif()
if (_UNAME STREQUAL "LINUX")
# X11 dependency
find_package(X11 REQUIRED)
- list(APPEND _INCLUDE_DIRS ${X11_INCLUDE_DIR})
- list(APPEND _LIBS ${X11_LIBRARIES})
+ list(APPEND _CORE_INCLUDE_DIRS ${X11_INCLUDE_DIR})
+ list(APPEND _CORE_LIBS ${X11_LIBRARIES})
endif()
option(LWP_INSTALL_LAUNCHD "Launch lwp on login (MacOSX only)" OFF)
@@ -85,13 +96,16 @@ if (_UNAME STREQUAL "DARWIN")
set(_DEFAULT_CONFIG_FILE defaultMac.cfg)
endif()
-# Main executable
+# Core executable
if (_UNAME STREQUAL "DARWIN")
- add_executable(lwp MACOSX_BUNDLE ${_SOURCE_FILES})
+ add_executable(lwpwlp MACOSX_BUNDLE ${_CORE_SOURCE_FILES})
else()
- add_executable(lwp ${_SOURCE_FILES})
+ add_executable(lwpwlp ${_CORE_SOURCE_FILES})
endif()
+# Control executable
+add_executable(lwp ${_CONTROL_SOURCE_FILES})
+
# Windows specific properties for executable
if(_UNAME STREQUAL "WIN32")
set_property(TARGET lwp PROPERTY VS_DPI_AWARE "PerMonitor")
@@ -101,14 +115,19 @@ if(MSVC)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS")
endif()
-target_compile_definitions(lwp PUBLIC __${_UNAME})
-target_include_directories(lwp PUBLIC ${_INCLUDE_DIRS})
-target_link_libraries(lwp PRIVATE ${_LIBS})
+target_compile_definitions(lwpwlp PUBLIC __${_UNAME} VER="${PROGRAM_VERSION}")
+target_include_directories(lwpwlp PUBLIC ${_CORE_INCLUDE_DIRS})
+target_link_libraries(lwpwlp PRIVATE ${_CORE_LIBS})
+
+target_compile_definitions(lwp PUBLIC __${_UNAME} VER="${PROGRAM_VERSION}")
+target_link_libraries(lwp PRIVATE ${_CONTROL_LIBS})
# Installation rules
if(_UNAME STREQUAL "WIN32")
install(TARGETS lwp
DESTINATION .)
+ install(TARGETS lwpwlp
+ DESTINATION .)
install(DIRECTORY wallpapers
DESTINATION .)
install(FILES LICENSE.txt
@@ -122,6 +141,8 @@ if(_UNAME STREQUAL "WIN32")
elseif(_UNAME STREQUAL "LINUX")
install(TARGETS lwp
DESTINATION usr/local/bin)
+ install(TARGETS lwpwlp
+ DESTINATION usr/local/bin)
install(DIRECTORY wallpapers
DESTINATION usr/local/share/lwp)
install(FILES LICENSE.txt
@@ -132,6 +153,8 @@ elseif(_UNAME STREQUAL "LINUX")
else()
install(TARGETS lwp
DESTINATION Layered_WallPaper)
+ install(TARGETS lwpwlp
+ DESTINATION Layered_WallPaper)
install(DIRECTORY wallpapers
DESTINATION Layered_WallPaper)
install(FILES LICENSE.txt
diff --git a/README.md b/README.md
index 1202b64..364df25 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,14 @@
-# LWP
+# Layered WallPaper
-LWP allows You to create multi-layered parallax wallpapers.
+Layered WallPaper allows You to create multi-layered parallax wallpapers.
Each layer moves with Your mouse cursor, creating this beautiful effect.
[![](https://img.shields.io/github/v/release/jszczerbinsky/lwp?style=for-the-badge)](https://github.com/jszczerbinsky/lwp/releases/latest)
[![](https://img.shields.io/github/downloads/jszczerbinsky/lwp/total?style=for-the-badge)](https://github.com/jszczerbinsky/lwp/releases/latest)
[![](https://img.shields.io/github/actions/workflow/status/jszczerbinsky/lwp/build.yml?style=for-the-badge)](https://github.com/jszczerbinsky/lwp)
-[![](https://img.shields.io/discord/1077955077974794322?label=DISCORD&style=for-the-badge)](https://discord.gg/gHpbkXJD)
+[![](https://img.shields.io/discord/1077955077974794322?label=DISCORD&style=for-the-badge)](https://discord.gg/JmkCqjYFQa)
[Installation](#installation) •
[Configuration](#configuration) •
@@ -34,9 +34,9 @@ https://user-images.githubusercontent.com/38699473/220888934-09788a6b-873c-469b-
```shell
sudo tar -o -xvf [archive name].tar.gz --directory /
```
- - Test lwp by running `lwp`
+ - Test Layered WallPaper by running `lwp`
- Setting `reload_rootwindow=1` in config file may be necessary on some distributions for Layered WallPaper to work properly (see [configuration](#configuration))
- - To make lwp run on startup, add `lwp &` command to Your desktop enviroment `.rc` file
+ - To make Layered WallPaper run on startup, add `lwp &` command to Your desktop enviroment `.rc` file
#### Build from source instead
- Install `SDL2` using Your package manager. On some distributions `SDL2` doesn't contain development files, so it may be also necessary to install development version of `SDL2`
@@ -60,9 +60,9 @@ https://user-images.githubusercontent.com/38699473/220888934-09788a6b-873c-469b-
```shell
sudo tar -o -xvf [archive name].tar.gz --directory /
```
- - Test lwp by running `lwp`
+ - Test Layered WallPaper by running `lwp`
- Setting `reload_rootwindow=1` in config file may be necessary on some distributions for Layered WallPaper to work properly (see [configuration](#configuration))
- - To make lwp run on startup, add `lwp &` command to Your desktop enviroment `.rc` file
+ - To make Layered WallPaper run on startup, add `lwp &` command to Your desktop enviroment `.rc` file
@@ -196,11 +196,11 @@ https://user-images.githubusercontent.com/38699473/220888934-09788a6b-873c-469b-
## Creating Wallpapers
-Want to share Your wallpaper? Join our [discord](https://discord.gg/gHpbkXJD)!
+Want to share Your wallpaper? Join our [discord](https://discord.gg/JmkCqjYFQa)!
Parallax wallpapers are not popular. Because of this if You want some cool parallax wallpaper, You have to either find a parallax game background on the internet and use it as a wallpaper or cut some real wallpaper into layers using Gimp or Photoshop.
-#### How to create a wallpaper for lwp
+#### How to create a wallpaper for Layered WallPaper
- Create a directory for Your wallpaper
- Save each layer to this directory as `.bmp` file and name them `1.bmp`, `2.bmp` ... (`1.bmp` is bottom most layer)
- Create a wallpaper config file and name it `wallpaper.cfg` (You can make a copy from `C:\Program Files\lwp\wallpapers\default-fullhd\wallpaper.cfg`)
diff --git a/control_panel/main.c b/control_panel/main.c
new file mode 100644
index 0000000..f2743a6
--- /dev/null
+++ b/control_panel/main.c
@@ -0,0 +1,67 @@
+#include
+#include
+
+static FILE *proc;
+static GtkWidget *window = NULL;
+
+static void apply_btn_click(GtkWidget *widget, gpointer data)
+{
+ pclose(proc);
+ proc = popen("./lwpwlp", "r");
+}
+static void close_btn_click(GtkWidget *widget, gpointer data) {}
+
+static void startup(GtkApplication *app, gpointer user_data)
+{
+ GtkWidget *box;
+ GtkWidget *btn_box;
+ GtkWidget *version_label;
+ GtkWidget *apply_btn;
+ GtkWidget *close_btn;
+
+ window = gtk_application_window_new(app);
+ gtk_window_set_title(GTK_WINDOW(window), "LayeredWallpaper Control Panel");
+ gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
+ gtk_window_set_hide_on_close(GTK_WINDOW(window), TRUE);
+
+ char version_label_str[1024];
+ sprintf(version_label_str, "Layered WallPaper version: %s", VER);
+
+ version_label = gtk_label_new(version_label_str);
+ box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+ btn_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_window_set_child(GTK_WINDOW(window), box);
+
+ gtk_box_append(GTK_BOX(box), version_label);
+
+ apply_btn = gtk_button_new_with_label("Apply");
+ close_btn = gtk_button_new_with_label("Close");
+ g_signal_connect(apply_btn, "clicked", G_CALLBACK(apply_btn_click), NULL);
+ g_signal_connect(close_btn, "clicked", G_CALLBACK(close_btn_click), app);
+ gtk_box_append(GTK_BOX(btn_box), apply_btn);
+ gtk_box_append(GTK_BOX(btn_box), close_btn);
+
+ gtk_box_append(GTK_BOX(box), btn_box);
+
+ gtk_window_present(GTK_WINDOW(window));
+
+ gtk_widget_hide(window);
+
+ proc = popen("./lwpwlp", "r");
+}
+
+static void activate(GtkApplication *app, gpointer user_data) { gtk_widget_show(window); }
+
+int main(int argc, char *argv[])
+{
+ GtkApplication *app;
+ int status;
+
+ app = gtk_application_new("com.github.jszczerbinsky.lwp", G_APPLICATION_DEFAULT_FLAGS);
+ g_signal_connect(app, "startup", G_CALLBACK(startup), NULL);
+ g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
+ status = g_application_run(G_APPLICATION(app), argc, argv);
+ g_object_unref(app);
+
+ return status;
+}
diff --git a/debug.c b/core/debug.c
similarity index 100%
rename from debug.c
rename to core/debug.c
diff --git a/debug.h b/core/debug.h
similarity index 100%
rename from debug.h
rename to core/debug.h
diff --git a/core/main.c b/core/main.c
new file mode 100644
index 0000000..340bb77
--- /dev/null
+++ b/core/main.c
@@ -0,0 +1,244 @@
+#include "main.h"
+
+#include "debug.h"
+#include "parser.h"
+#include "platform_guard.h"
+#include "wallpaper.h"
+#include "window.h"
+
+static int lerp(int a, int b, float t)
+{
+ if (t > 1) t = 1;
+ return (int)((float)a + (float)t * ((float)b - (float)a));
+}
+
+static int init(App *app, Config *cfg)
+{
+ if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0)
+ {
+ lwpLog(LOG_ERROR, "%s", SDL_GetError());
+ return 0;
+ }
+
+ initWindow(app, cfg);
+
+ app->renderer =
+ SDL_CreateRenderer(app->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
+ if (app->renderer == NULL)
+ {
+ lwpLog(LOG_ERROR, "%s", SDL_GetError());
+ return 0;
+ }
+
+ return 1;
+}
+
+#ifdef __WIN32
+static void initCmd()
+{
+ // Create console
+ AllocConsole();
+ AttachConsole(ATTACH_PARENT_PROCESS);
+ freopen("CONOUT$", "w", stdout);
+ HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
+ DWORD dwMode = 0;
+ GetConsoleMode(hOut, &dwMode);
+ SetConsoleMode(hOut, dwMode | 0x0004);
+
+ // Remove closing button (because closing it closes the entire app)
+ HWND hwnd = GetConsoleWindow();
+ HMENU hMenu = GetSystemMenu(hwnd, FALSE);
+ DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
+
+ // Set console title
+ SetConsoleTitle("Layered WallPaper");
+}
+BOOL monitorenumproc(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM param)
+{
+ int px = GetSystemMetrics(SM_XVIRTUALSCREEN);
+ int py = GetSystemMetrics(SM_YVIRTUALSCREEN);
+
+ MONITORINFO monitorInfo;
+ monitorInfo.cbSize = sizeof(MONITORINFO);
+
+ GetMonitorInfo(monitor, &monitorInfo);
+ lwpLog(
+ LOG_INFO,
+ " Monitor: position %ldx%ld, size %ldx%ld %s",
+ monitorInfo.rcMonitor.left - px,
+ monitorInfo.rcMonitor.top - py,
+ monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left,
+ monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top,
+ (monitorInfo.dwFlags & MONITORINFOF_PRIMARY) == MONITORINFOF_PRIMARY ? "primary" : ""
+ );
+
+ return TRUE;
+}
+static void scanMonitors()
+{
+ lwpLog(LOG_INFO, "Scanning monitors...");
+ EnumDisplayMonitors(NULL, NULL, &monitorenumproc, NULL);
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+ if (argc >= 2 && strcmp(argv[1], "--version") == 0)
+ {
+ printf("%s\n", VER);
+ return 0;
+ }
+
+ lwpLog(LOG_INFO, "Starting Layered WallPaper");
+
+#ifdef __WIN32
+ if (argc == 2 && strcmp(argv[1], "/console") == 0) initCmd();
+ initTrayIcon();
+
+ scanMonitors();
+#endif
+
+ App app;
+ Config cfg;
+
+ int canRender = 1;
+
+ if (!parseConfig(&app, &cfg) || !init(&app, &cfg) || !loadMonitors(&app, &cfg)) canRender = 0;
+
+ SDL_Event event;
+ int quit = 0;
+
+ int mx = 0;
+ int my = 0;
+
+ while (!quit)
+ {
+ if (canRender)
+ {
+ static int currentX = 0;
+ static int currentY = 0;
+
+ static int lastTicks = 0;
+
+ int ticks = SDL_GetTicks();
+ float dT = (ticks - lastTicks) / 1000.0f;
+ lastTicks = ticks;
+
+#ifdef __WIN32
+ POINT mPos;
+ GetCursorPos(&mPos);
+ mx = mPos.x - GetSystemMetrics(SM_XVIRTUALSCREEN);
+ my = mPos.y - GetSystemMetrics(SM_YVIRTUALSCREEN);
+#else
+ SDL_GetGlobalMouseState(&mx, &my);
+#endif
+
+ while (SDL_PollEvent(&event))
+ if (event.type == SDL_QUIT) quit = 1;
+
+ currentX = lerp(currentX, mx, dT * cfg.smooth);
+ currentY = lerp(currentY, my, dT * cfg.smooth);
+
+ for (int m = 0; m < cfg.monitorsCount; m++)
+ {
+ int relativeCurrentX = currentX - cfg.monitors[m].x;
+ int relativeCurrentY = currentY - cfg.monitors[m].y;
+
+ if (relativeCurrentX < 0) relativeCurrentX = 0;
+ if (relativeCurrentY < 0) relativeCurrentY = 0;
+ if (relativeCurrentX > cfg.monitors[m].w) relativeCurrentX = cfg.monitors[m].w;
+ if (relativeCurrentY > cfg.monitors[m].h) relativeCurrentY = cfg.monitors[m].h;
+
+ SDL_SetRenderTarget(app.renderer, cfg.monitors[m].wallpaper.tex);
+ SDL_RenderClear(app.renderer);
+
+ for (int i = 0; i < cfg.monitors[m].wallpaper.layersCount; i++)
+ {
+ SDL_Rect src = {
+ .x = 0,
+ .y = 0,
+ .w = cfg.monitors[m].wallpaper.originalW,
+ .h = cfg.monitors[m].wallpaper.originalH,
+ };
+
+ int x =
+ -((relativeCurrentX - cfg.monitors[m].w / 2) *
+ cfg.monitors[m].wallpaper.layers[i].sensitivityX);
+ int y =
+ -((relativeCurrentY - cfg.monitors[m].h / 2) *
+ cfg.monitors[m].wallpaper.layers[i].sensitivityY);
+
+ for (int k = -cfg.monitors[m].wallpaper.repeatY; k <= cfg.monitors[m].wallpaper.repeatY;
+ k++)
+ {
+ for (int j = -cfg.monitors[m].wallpaper.repeatX; j <= cfg.monitors[m].wallpaper.repeatX;
+ j++)
+ {
+ SDL_Rect dest = {
+ .x = x + j * cfg.monitors[m].wallpaperW,
+ .y = y + k * cfg.monitors[m].wallpaperH,
+ .w = cfg.monitors[m].wallpaperW,
+ .h = cfg.monitors[m].wallpaperH,
+ };
+
+ SDL_RenderCopy(app.renderer, cfg.monitors[m].wallpaper.layers[i].tex, &src, &dest);
+ }
+ }
+ }
+
+ SDL_SetRenderTarget(app.renderer, cfg.monitors[m].tex);
+
+ SDL_Rect src = {
+ .x = 0,
+ .y = 0,
+ .w = cfg.monitors[m].wallpaperW,
+ .h = cfg.monitors[m].wallpaperH,
+ };
+
+ SDL_Rect dest = {
+ .x = cfg.monitors[m].wallpaperX,
+ .y = cfg.monitors[m].wallpaperY,
+ .w = cfg.monitors[m].wallpaperW,
+ .h = cfg.monitors[m].wallpaperH,
+ };
+
+ SDL_RenderCopy(app.renderer, cfg.monitors[m].wallpaper.tex, &src, &dest);
+
+ SDL_SetRenderTarget(app.renderer, NULL);
+
+ SDL_Rect finalSrc = {
+ .x = 0,
+ .y = 0,
+ .w = cfg.monitors[m].w,
+ .h = cfg.monitors[m].h,
+ };
+
+ SDL_Rect finalDest = {
+ .x = cfg.monitors[m].x,
+ .y = cfg.monitors[m].y,
+ .w = cfg.monitors[m].w,
+ .h = cfg.monitors[m].h,
+ };
+
+ SDL_RenderCopy(app.renderer, cfg.monitors[m].tex, &finalSrc, &finalDest);
+ }
+ SDL_RenderPresent(app.renderer);
+ }
+ SDL_Delay(1000 / cfg.targetFPS);
+#ifdef __WIN32
+ if (!updateTrayIcon()) quit = 1;
+#endif
+ }
+
+#ifdef __WIN32
+ removeTrayIcon();
+#endif
+
+ freeConfig(&cfg);
+
+ SDL_DestroyRenderer(app.renderer);
+ SDL_DestroyWindow(app.window);
+ SDL_Quit();
+
+ return 0;
+}
diff --git a/main.h b/core/main.h
similarity index 100%
rename from main.h
rename to core/main.h
diff --git a/parser.c b/core/parser.c
similarity index 100%
rename from parser.c
rename to core/parser.c
diff --git a/parser.h b/core/parser.h
similarity index 100%
rename from parser.h
rename to core/parser.h
diff --git a/platform_guard.h b/core/platform_guard.h
similarity index 100%
rename from platform_guard.h
rename to core/platform_guard.h
diff --git a/wallpaper.c b/core/wallpaper.c
similarity index 100%
rename from wallpaper.c
rename to core/wallpaper.c
diff --git a/wallpaper.h b/core/wallpaper.h
similarity index 100%
rename from wallpaper.h
rename to core/wallpaper.h
diff --git a/window.c b/core/window.c
similarity index 100%
rename from window.c
rename to core/window.c
diff --git a/window.h b/core/window.h
similarity index 100%
rename from window.h
rename to core/window.h
diff --git a/defaultMac.cfg b/defaultMac.cfg
deleted file mode 100644
index 88372be..0000000
--- a/defaultMac.cfg
+++ /dev/null
@@ -1,36 +0,0 @@
-# ██╗ ██╗ ██╗██████╗
-# ██║ ██║ ██║██╔══██╗
-# ██║ ██║ █╗ ██║██████╔╝
-# ██║ ██║███╗██║██╔═══╝
-# ███████╗╚███╔███╔╝██║
-# ╚══════╝ ╚══╝╚══╝ ╚═╝
-
-# Smooth movement
-# Increasing this value will make the wallpaper layers move faster
-smooth=8.0
-
-# Monitors count
-monitors=1
-
-# Monitor position
-monitor1_x=0
-monitor1_y=0
-
-# Monitor resolution
-monitor1_w=1920
-monitor1_h=1080
-
-# Absolute path to the wallpaper directory
-# Leave the value as empty to use the default wallpaper
-monitor1_wallpaper=/Applications/Layered_WallPaper/wallpapers/default-fullhd
-
-# Wallpaper size and position relative to Your monitor
-# Wallpaper resolution ratio should be the same as in original image
-monitor1_wallpaper_x=0
-monitor1_wallpaper_y=0
-monitor1_wallpaper_w=1920
-monitor1_wallpaper_h=1080
-
-# How many times per second should the wallpaper render
-# (imprecise, but accurate enough)
-target_fps=60
diff --git a/defaultWin.cfg b/defaultWin.cfg
deleted file mode 100644
index 761e0fc..0000000
--- a/defaultWin.cfg
+++ /dev/null
@@ -1,36 +0,0 @@
-# ██╗ ██╗ ██╗██████╗
-# ██║ ██║ ██║██╔══██╗
-# ██║ ██║ █╗ ██║██████╔╝
-# ██║ ██║███╗██║██╔═══╝
-# ███████╗╚███╔███╔╝██║
-# ╚══════╝ ╚══╝╚══╝ ╚═╝
-
-# Smooth movement
-# Increasing this value will make the wallpaper layers move faster
-smooth=8.0
-
-# Monitors count
-monitors=1
-
-# Monitor position
-monitor1_x=0
-monitor1_y=0
-
-# Monitor resolution
-monitor1_w=1920
-monitor1_h=1080
-
-# Absolute path to the wallpaper directory
-# Leave the value as empty to use the default wallpaper
-monitor1_wallpaper=
-
-# Wallpaper size and position relative to Your monitor
-# Wallpaper resolution ratio should be the same as in original image
-monitor1_wallpaper_x=0
-monitor1_wallpaper_y=0
-monitor1_wallpaper_w=1920
-monitor1_wallpaper_h=1080
-
-# How many times per second should the wallpaper render
-# (imprecise, but accurate enough)
-target_fps=60
diff --git a/main.c b/main.c
deleted file mode 100644
index def3652..0000000
--- a/main.c
+++ /dev/null
@@ -1,240 +0,0 @@
-#include "main.h"
-
-#include "debug.h"
-#include "parser.h"
-#include "platform_guard.h"
-#include "wallpaper.h"
-#include "window.h"
-
-static int lerp(int a, int b, float t)
-{
- if (t > 1) t = 1;
- return (int)((float)a + (float)t * ((float)b - (float)a));
-}
-
-static int init(App *app, Config *cfg)
-{
- if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0)
- {
- lwpLog(LOG_ERROR, "%s", SDL_GetError());
- return 0;
- }
-
- initWindow(app, cfg);
-
- app->renderer =
- SDL_CreateRenderer(app->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
- if (app->renderer == NULL)
- {
- lwpLog(LOG_ERROR, "%s", SDL_GetError());
- return 0;
- }
-
- return 1;
-}
-
-#ifdef __WIN32
-static void initCmd()
-{
- // Create console
- AllocConsole();
- AttachConsole(ATTACH_PARENT_PROCESS);
- freopen("CONOUT$", "w", stdout);
- HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
- DWORD dwMode = 0;
- GetConsoleMode(hOut, &dwMode);
- SetConsoleMode(hOut, dwMode | 0x0004);
-
- // Remove closing button (because closing it closes the entire app)
- HWND hwnd = GetConsoleWindow();
- HMENU hMenu = GetSystemMenu(hwnd, FALSE);
- DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
-
- // Set console title
- SetConsoleTitle("Layered WallPaper");
-}
-BOOL monitorenumproc(
- HMONITOR monitor,
- HDC hdc,
- LPRECT rect,
- LPARAM param
-)
-{
-
- int px = GetSystemMetrics(SM_XVIRTUALSCREEN);
- int py = GetSystemMetrics(SM_YVIRTUALSCREEN);
-
- MONITORINFO monitorInfo;
- monitorInfo.cbSize = sizeof(MONITORINFO);
-
- GetMonitorInfo(monitor, &monitorInfo);
- lwpLog(LOG_INFO, " Monitor: position %ldx%ld, size %ldx%ld %s",
- monitorInfo.rcMonitor.left - px,
- monitorInfo.rcMonitor.top - py,
- monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left,
- monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top,
- (monitorInfo.dwFlags & MONITORINFOF_PRIMARY) == MONITORINFOF_PRIMARY ? "primary" : ""
- );
-
- return TRUE;
-}
-static void scanMonitors()
-{
- lwpLog(LOG_INFO, "Scanning monitors...");
- EnumDisplayMonitors(NULL, NULL, &monitorenumproc, NULL);
-}
-#endif
-
-int main(int argc, char *argv[])
-{
- lwpLog(LOG_INFO, "Starting Layered WallPaper");
-
-#ifdef __WIN32
- if (argc == 2 && strcmp(argv[1], "/console") == 0) initCmd();
- initTrayIcon();
-
- scanMonitors();
-#endif
-
- App app;
- Config cfg;
-
- int canRender = 1;
-
- if (!parseConfig(&app, &cfg) || !init(&app, &cfg) || !loadMonitors(&app, &cfg)) canRender = 0;
-
- SDL_Event event;
- int quit = 0;
-
- int mx = 0;
- int my = 0;
-
- while (!quit)
- {
- if(canRender)
- {
- static int currentX = 0;
- static int currentY = 0;
-
- static int lastTicks = 0;
-
- int ticks = SDL_GetTicks();
- float dT = (ticks - lastTicks) / 1000.0f;
- lastTicks = ticks;
-
- #ifdef __WIN32
- POINT mPos;
- GetCursorPos(&mPos);
- mx = mPos.x - GetSystemMetrics(SM_XVIRTUALSCREEN);
- my = mPos.y - GetSystemMetrics(SM_YVIRTUALSCREEN);
- #else
- SDL_GetGlobalMouseState(&mx, &my);
- #endif
-
- while (SDL_PollEvent(&event))
- if (event.type == SDL_QUIT) quit = 1;
-
- currentX = lerp(currentX, mx, dT * cfg.smooth);
- currentY = lerp(currentY, my, dT * cfg.smooth);
-
- for (int m = 0; m < cfg.monitorsCount; m++)
- {
- int relativeCurrentX = currentX - cfg.monitors[m].x;
- int relativeCurrentY = currentY - cfg.monitors[m].y;
-
- if (relativeCurrentX < 0) relativeCurrentX = 0;
- if (relativeCurrentY < 0) relativeCurrentY = 0;
- if (relativeCurrentX > cfg.monitors[m].w) relativeCurrentX = cfg.monitors[m].w;
- if (relativeCurrentY > cfg.monitors[m].h) relativeCurrentY = cfg.monitors[m].h;
-
- SDL_SetRenderTarget(app.renderer, cfg.monitors[m].wallpaper.tex);
- SDL_RenderClear(app.renderer);
-
- for (int i = 0; i < cfg.monitors[m].wallpaper.layersCount; i++)
- {
- SDL_Rect src = {
- .x = 0,
- .y = 0,
- .w = cfg.monitors[m].wallpaper.originalW,
- .h = cfg.monitors[m].wallpaper.originalH,
- };
-
- int x = -((relativeCurrentX - cfg.monitors[m].w / 2) *
- cfg.monitors[m].wallpaper.layers[i].sensitivityX);
- int y = -((relativeCurrentY - cfg.monitors[m].h / 2) *
- cfg.monitors[m].wallpaper.layers[i].sensitivityY);
-
- for (int k = -cfg.monitors[m].wallpaper.repeatY; k <= cfg.monitors[m].wallpaper.repeatY;
- k++)
- {
- for (int j = -cfg.monitors[m].wallpaper.repeatX; j <= cfg.monitors[m].wallpaper.repeatX;
- j++)
- {
- SDL_Rect dest = {
- .x = x + j * cfg.monitors[m].wallpaperW,
- .y = y + k * cfg.monitors[m].wallpaperH,
- .w = cfg.monitors[m].wallpaperW,
- .h = cfg.monitors[m].wallpaperH,
- };
-
- SDL_RenderCopy(app.renderer, cfg.monitors[m].wallpaper.layers[i].tex, &src, &dest);
- }
- }
- }
-
- SDL_SetRenderTarget(app.renderer, cfg.monitors[m].tex);
-
- SDL_Rect src = {
- .x = 0,
- .y = 0,
- .w = cfg.monitors[m].wallpaperW,
- .h = cfg.monitors[m].wallpaperH,
- };
-
- SDL_Rect dest = {
- .x = cfg.monitors[m].wallpaperX,
- .y = cfg.monitors[m].wallpaperY,
- .w = cfg.monitors[m].wallpaperW,
- .h = cfg.monitors[m].wallpaperH,
- };
-
- SDL_RenderCopy(app.renderer, cfg.monitors[m].wallpaper.tex, &src, &dest);
-
- SDL_SetRenderTarget(app.renderer, NULL);
-
- SDL_Rect finalSrc = {
- .x = 0,
- .y = 0,
- .w = cfg.monitors[m].w,
- .h = cfg.monitors[m].h,
- };
-
- SDL_Rect finalDest = {
- .x = cfg.monitors[m].x,
- .y = cfg.monitors[m].y,
- .w = cfg.monitors[m].w,
- .h = cfg.monitors[m].h,
- };
-
- SDL_RenderCopy(app.renderer, cfg.monitors[m].tex, &finalSrc, &finalDest);
- }
- SDL_RenderPresent(app.renderer);
- }
- SDL_Delay(1000 / cfg.targetFPS);
-#ifdef __WIN32
- if(!updateTrayIcon()) quit = 1;
-#endif
- }
-
-#ifdef __WIN32
- removeTrayIcon();
-#endif
-
- freeConfig(&cfg);
-
- SDL_DestroyRenderer(app.renderer);
- SDL_DestroyWindow(app.window);
- SDL_Quit();
-
- return 0;
-}