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; -}