Compare commits
12 Commits
9986fafa80
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 16b08862fa | |||
| 6b876422c8 | |||
| c1dd386835 | |||
| 9dc32c854b | |||
| 93e400304d | |||
| b315a55dae | |||
| b5361d8e21 | |||
| 2a360721b6 | |||
| 9297b4c062 | |||
| 3487bdfb1f | |||
| a395470d88 | |||
| 176f33f6de |
@@ -2,27 +2,48 @@
|
|||||||
|
|
||||||
> View images fast and without any hocus pocus, sometimes less is better
|
> View images fast and without any hocus pocus, sometimes less is better
|
||||||
|
|
||||||
## Disclaimer
|
## About
|
||||||
The inspiration was a YouTube video, I've watched the beginning and though to myself that this cannot be that hard to implement.
|
|
||||||
Of course it is not without usage, I will prepare the app to be hooked in Hyprland to launch the current photo stored in clipboard.
|
The inspiration was a YouTube video. I watched the beginning and thought to myself that this cannot be that hard to implement.
|
||||||
|
|
||||||
|
A Hyprland integration is included to open an image from the clipboard, either as a file path or as image data.
|
||||||
|
|
||||||
|
## Disclaimer for Wayland / Hyprland users
|
||||||
|
|
||||||
|
Under Wayland, window placement is controlled by the compositor, so moving the window with the viewer's left-button drag does not work. The compositor may also override the requested window size. See the [SDL Wayland notes](https://wiki.libsdl.org/SDL3/README-wayland) for details.
|
||||||
|
|
||||||
|
Mouse-wheel zoom and right-button dragging operate on the image inside the window. On Hyprland, use your configured compositor bindings to move or resize the window, and configure it as floating if you want free window placement.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- SDL3
|
- SDL3
|
||||||
|
|
||||||
## Installations
|
## Installations
|
||||||
> As of now the only like-indented working implementation is for macOS. Wayland ignores the desired window states (resize, position).
|
|
||||||
|
|
||||||
#### macOS
|
### macOS
|
||||||
|
|
||||||
- `brew install sdl3`
|
- `brew install sdl3`
|
||||||
- clone this repo and navigate into it
|
- clone this repo and navigate into it
|
||||||
- `gcc SimpleImageViewer.c -o SimpleImageViewer -Wall -Werror -o3 $(pkg-config --cflags --libs sdl3)` or with `clang`
|
- `gcc SimpleImageViewer.c -o SimpleImageViewer -Wall -Werror $(pkg-config --cflags --libs sdl3)` or with `clang`
|
||||||
- additional compiler arguments for ide: `-I/opt/homebrew/include -L/opt/homebrew/lib -Wl,-rpath,/opt/homebrew/lib -lSDL3`
|
- additional compiler arguments for ide: `-I/opt/homebrew/include -L/opt/homebrew/lib -Wl,-rpath,/opt/homebrew/lib -lSDL3`
|
||||||
|
|
||||||
#### Linux
|
### Linux
|
||||||
|
|
||||||
- `sudo pacman -S sdl3 --noconfirm`
|
- `sudo pacman -S sdl3 --noconfirm`
|
||||||
- `gcc SimpleImageViewer.c -o SimpleImageViewer -Wall -Werror -o3 $(pkg-config --cflags --libs sdl3) -lm` or with `clang`
|
- `gcc SimpleImageViewer.c -o SimpleImageViewer -Wall -Werror $(pkg-config --cflags --libs sdl3) -lm` or with `clang`
|
||||||
- when using Hyprland, move the scripts folder into your `~/.config/hypr/`
|
- when using Hyprland, move the scripts folder into your `~/.config/hypr/`
|
||||||
- in `simple-image-viewer-clipboard.sh`: set `viewer`, I placed my binary beside this script
|
- in `simple-image-viewer-clipboard.sh`: set `viewer` to the binary path gcc created, I placed my binary beside this script
|
||||||
- move the `hypr_simpleimageviewer.lua` file into `~/.config/hypr/`
|
- move the `hypr_simpleimageviewer.lua` file into `~/.config/hypr/`
|
||||||
- replace [USER] with your user
|
- open the file and replace [USER] with your user
|
||||||
- add `require(hypr_simpleimageviewer)` at the top of your Hyprland config
|
- add `require(hypr_simpleimageviewer)` at the top of your Hyprland config
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
If installed via Hyprland binding, `SUPER + I` is used to parse a file from clipboard (path or binary) as argument into SimpleImageViewer.
|
||||||
|
Via commandline `./SimpleImageViewer [path_to_image]`.
|
||||||
|
|
||||||
|
Mouse-/Keybinds:
|
||||||
|
|
||||||
|
- Close: `ESC, Enter, Space`
|
||||||
|
- Move image: press `right mouse button` and `drag`
|
||||||
|
- Zoom image: `scroll mouse wheel`
|
||||||
|
|||||||
+174
-56
@@ -1,3 +1,5 @@
|
|||||||
|
#include <SDL3/SDL_keycode.h>
|
||||||
|
#include <SDL3/SDL_pixels.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
@@ -5,35 +7,49 @@
|
|||||||
#include <SDL3/SDL_mouse.h>
|
#include <SDL3/SDL_mouse.h>
|
||||||
#include <SDL3/SDL_keyboard.h>
|
#include <SDL3/SDL_keyboard.h>
|
||||||
#include <SDL3/SDL_events.h>
|
#include <SDL3/SDL_events.h>
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include "stb_image.h"
|
#include "stb_image.h"
|
||||||
|
|
||||||
#define DESIRED_IMAGE_CHANNELS 4
|
#define DESIRED_IMAGE_CHANNELS 4
|
||||||
|
#define MAX_IMAGE_SCALE 10
|
||||||
|
#define MIN_IMAGE_SCALE 0.01
|
||||||
|
|
||||||
typedef struct Image{
|
typedef struct Image{
|
||||||
int x;
|
int x;
|
||||||
int y;
|
int y;
|
||||||
int channels;
|
int channels;
|
||||||
unsigned char* pixels;
|
unsigned char* pixels;
|
||||||
|
SDL_Surface* surface;
|
||||||
|
SDL_Texture* texture;
|
||||||
} Image;
|
} Image;
|
||||||
|
|
||||||
Image load_image(const char* filepath){
|
void error_exit(const char* msg){
|
||||||
|
printf("%s\n", msg);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void error_continue(const char* msg){
|
||||||
|
printf("%s\n", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
Image load_image_pixels_from_file(const char* filepath){
|
||||||
Image image;
|
Image image;
|
||||||
image.pixels = stbi_load(filepath, &image.x, &image.y, &image.channels, DESIRED_IMAGE_CHANNELS);
|
image.pixels = stbi_load(filepath, &image.x, &image.y, &image.channels, DESIRED_IMAGE_CHANNELS);
|
||||||
|
if(!image.pixels) error_exit("Failed to load image from file!");
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_image(Image* image){
|
void free_image_pixels_buffer(Image* image){
|
||||||
if(image->pixels) stbi_image_free(image->pixels);
|
if(image->pixels) stbi_image_free(image->pixels);
|
||||||
|
image->pixels = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Window* create_window(const char* title, int w, int h){
|
static SDL_Window* create_window(const char* title, int w, int h){
|
||||||
const SDL_InitFlags init_flags = SDL_INIT_VIDEO | SDL_INIT_EVENTS;
|
const SDL_InitFlags init_flags = SDL_INIT_VIDEO | SDL_INIT_EVENTS;
|
||||||
const SDL_WindowFlags window_flags = SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE;
|
const SDL_WindowFlags window_flags = SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE;
|
||||||
|
|
||||||
SDL_Init(init_flags);
|
if(!SDL_Init(init_flags)) error_exit("Failed to initialize SDL!");
|
||||||
|
|
||||||
/* Used when a larger window is wanted, image displaying is dynamically calculated
|
/* Used when a larger window is wanted, image displaying is dynamically calculated
|
||||||
int display_count;
|
int display_count;
|
||||||
@@ -52,23 +68,27 @@ SDL_Window* create_window(const char* title, int w, int h){
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
SDL_Window* window = SDL_CreateWindow(title, w, h, window_flags);
|
SDL_Window* window = SDL_CreateWindow(title, w, h, window_flags);
|
||||||
SDL_SetWindowAspectRatio(window, (float)w / (float)h, (float)w / (float)h);
|
if(!window) error_exit("Failed to create window!");
|
||||||
|
if(SDL_SetWindowAspectRatio(window, (float)w / (float)h, (float)w / (float)h)) error_continue("Failed to set window aspect ratio! Continuing...");
|
||||||
|
|
||||||
return window;
|
return window;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Surface* get_surface_from_window(SDL_Window* window){
|
static bool populate_image(SDL_Window* window, Image* image){
|
||||||
return SDL_GetWindowSurface(window);
|
SDL_Surface* surface = SDL_GetWindowSurface(window);
|
||||||
|
image->surface = SDL_CreateSurface(image->x, image->y, SDL_PIXELFORMAT_RGBA32);
|
||||||
|
if(!image->surface) {
|
||||||
|
error_continue("Failed to create image surface! Cleaning up and exiting...");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_image(SDL_Surface* surface, Image* image){
|
|
||||||
SDL_Rect pixel = { 0, 0, 1, 1 };
|
SDL_Rect pixel = { 0, 0, 1, 1 };
|
||||||
|
|
||||||
int center_x = ((surface->w + 1) / 2 - 1);
|
int center_x = ((surface->w + 1) / 2 - 1);
|
||||||
int center_y = ((surface->h + 1) / 2 - 1);
|
int center_y = ((surface->h + 1) / 2 - 1);
|
||||||
|
|
||||||
int dst_x = center_x - image->x / 2;
|
int dst_x = (center_x - image->x / 2);
|
||||||
int dst_y = center_y - image->y / 2;
|
int dst_y = (center_y - image->y / 2);
|
||||||
|
|
||||||
for(int x = 0; x < image->x; x++){
|
for(int x = 0; x < image->x; x++){
|
||||||
pixel.x = dst_x + x;
|
pixel.x = dst_x + x;
|
||||||
@@ -76,15 +96,63 @@ void draw_image(SDL_Surface* surface, Image* image){
|
|||||||
pixel.y = dst_y + y;
|
pixel.y = dst_y + y;
|
||||||
const int current_pixel_idx = (y * image->x + x) * DESIRED_IMAGE_CHANNELS;
|
const int current_pixel_idx = (y * image->x + x) * DESIRED_IMAGE_CHANNELS;
|
||||||
|
|
||||||
Uint32 color = SDL_MapSurfaceRGBA(surface,
|
Uint32 color = SDL_MapSurfaceRGBA(image->surface,
|
||||||
image->pixels[current_pixel_idx + 0],
|
image->pixels[current_pixel_idx + 0],
|
||||||
image->pixels[current_pixel_idx + 1],
|
image->pixels[current_pixel_idx + 1],
|
||||||
image->pixels[current_pixel_idx + 2],
|
image->pixels[current_pixel_idx + 2],
|
||||||
image->pixels[current_pixel_idx + 3]);
|
image->pixels[current_pixel_idx + 3]);
|
||||||
|
|
||||||
SDL_FillSurfaceRect(surface, &pixel, color);
|
if(!SDL_FillSurfaceRect(image->surface, &pixel, color)) error_continue("Failed to fill surface rectangle! Trying to continue...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
image->texture = SDL_CreateTextureFromSurface(SDL_GetRenderer(window), image->surface);
|
||||||
|
if(!image->texture){
|
||||||
|
error_continue("Failed to create texture from surface! Cleaning up and exiting...");
|
||||||
|
SDL_DestroySurface(image->surface);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool draw_image(SDL_Window* window, Image* image, float pixel_size_delta, int image_start_x, int image_start_y){
|
||||||
|
SDL_Surface* surface = SDL_GetWindowSurface(window);
|
||||||
|
if(!surface){
|
||||||
|
error_continue("Failed to get window surface! Cleaning up and exiting...");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float pixel_size = pixel_size_delta;
|
||||||
|
|
||||||
|
int center_x = ((surface->w + 1) / 2 - 1);
|
||||||
|
int center_y = ((surface->h + 1) / 2 - 1);
|
||||||
|
|
||||||
|
Uint64 start = SDL_GetTicksNS();
|
||||||
|
|
||||||
|
SDL_FRect dst = { center_x - (image->x * pixel_size / 2) + image_start_x, center_y - (image->y * pixel_size / 2) + image_start_y, image->x * pixel_size, image->y * pixel_size };
|
||||||
|
SDL_Renderer* renderer = SDL_GetRenderer(window);
|
||||||
|
if(!renderer){
|
||||||
|
error_continue("Failed to get window renderer! Cleaning up and exiting...");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!SDL_RenderClear(renderer)){
|
||||||
|
error_continue("Failed to clear renderer! Cleaning up and exiting...");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(!SDL_RenderTexture(renderer, image->texture, NULL, &dst)){
|
||||||
|
error_continue("Failed to render texture! Cleaning up and exiting...");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(!SDL_RenderPresent(renderer)){
|
||||||
|
error_continue("Failed to present renderer! Cleaning up and exiting...");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Redraw time: %.3fms\n", (SDL_GetTicksNS() - start) / 1000000.0);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int clamp(const int in, const int low, const int high){
|
int clamp(const int in, const int low, const int high){
|
||||||
@@ -95,11 +163,12 @@ int clamp_low(const int in, const int low){
|
|||||||
return in < low ? low : in;
|
return in < low ? low : in;
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_wheel(SDL_Event* event, SDL_Window* window) {
|
static __attribute__((unused)) void on_wheel (SDL_Event* event, SDL_Window* window){
|
||||||
int last_w, last_h;
|
int last_w, last_h;
|
||||||
SDL_GetWindowSize(window, &last_w, &last_h);
|
SDL_GetWindowSize(window, &last_w, &last_h);
|
||||||
|
|
||||||
int step = event->wheel.y * 25;
|
int multiplier = 25;
|
||||||
|
int step = event->wheel.y * multiplier;
|
||||||
int new_w = clamp_low(last_w + step, 50);
|
int new_w = clamp_low(last_w + step, 50);
|
||||||
int new_h = new_w * last_h / last_w;
|
int new_h = new_w * last_h / last_w;
|
||||||
|
|
||||||
@@ -116,6 +185,80 @@ void on_wheel(SDL_Event* event, SDL_Window* window) {
|
|||||||
SDL_SetWindowSize(window, new_w, new_h);
|
SDL_SetWindowSize(window, new_w, new_h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void loop(SDL_Window* window, Image* image){
|
||||||
|
bool drag_left_mouse = false;
|
||||||
|
bool drag_right_mouse = false;
|
||||||
|
int last_pointer_x = 0;
|
||||||
|
int last_pointer_y = 0;
|
||||||
|
|
||||||
|
SDL_Event event;
|
||||||
|
bool run = true;
|
||||||
|
|
||||||
|
float pixel_size_delta = 1.0f;
|
||||||
|
int current_image_start_x = 0, current_image_start_y = 0;
|
||||||
|
int image_start_at_drag_x = 0, image_start_at_drag_y = 0;
|
||||||
|
|
||||||
|
bool redraw = false;
|
||||||
|
|
||||||
|
while(run){
|
||||||
|
if(!SDL_WaitEvent(&event)) continue;
|
||||||
|
|
||||||
|
do{
|
||||||
|
if (event.type == SDL_EVENT_KEY_UP){
|
||||||
|
switch(event.key.key){
|
||||||
|
case SDLK_ESCAPE: case SDLK_SPACE: case SDLK_RETURN:
|
||||||
|
run = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(event.type == SDL_EVENT_QUIT || event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED) run = false;
|
||||||
|
if(event.type == SDL_EVENT_MOUSE_BUTTON_DOWN){
|
||||||
|
if(event.button.button == SDL_BUTTON_LEFT) drag_left_mouse = true;
|
||||||
|
if(event.button.button == SDL_BUTTON_RIGHT) drag_right_mouse = true;
|
||||||
|
|
||||||
|
last_pointer_x = (int)event.button.x;
|
||||||
|
last_pointer_y = (int)event.button.y;
|
||||||
|
image_start_at_drag_x = current_image_start_x;
|
||||||
|
image_start_at_drag_y = current_image_start_y;
|
||||||
|
}
|
||||||
|
if(event.type == SDL_EVENT_MOUSE_BUTTON_UP && event.button.button == SDL_BUTTON_LEFT) drag_left_mouse = false;
|
||||||
|
if(event.type == SDL_EVENT_MOUSE_BUTTON_UP && event.button.button == SDL_BUTTON_RIGHT) drag_right_mouse = false;
|
||||||
|
if(event.type == SDL_EVENT_MOUSE_MOTION){
|
||||||
|
if(drag_left_mouse){
|
||||||
|
int last_x, last_y;
|
||||||
|
if(!SDL_GetWindowPosition(window, &last_x, &last_y)) error_continue("Failed to get window position!");
|
||||||
|
else if(!SDL_SetWindowPosition(window, last_x + (int)event.motion.x - last_pointer_x, last_y + (int)event.motion.y - last_pointer_y)) error_continue("Failed to set window position!");
|
||||||
|
}
|
||||||
|
if(drag_right_mouse){
|
||||||
|
int image_start_x = (int)event.motion.x - last_pointer_x + image_start_at_drag_x;
|
||||||
|
int image_start_y = (int)event.motion.y - last_pointer_y + image_start_at_drag_y;
|
||||||
|
|
||||||
|
current_image_start_x = image_start_x;
|
||||||
|
current_image_start_y = image_start_y;
|
||||||
|
|
||||||
|
redraw = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(event.type == SDL_EVENT_MOUSE_WHEEL){
|
||||||
|
float last_pixel_size_delta = pixel_size_delta;
|
||||||
|
pixel_size_delta += event.wheel.y * 0.1f * pixel_size_delta;
|
||||||
|
if(pixel_size_delta < MIN_IMAGE_SCALE) pixel_size_delta = MIN_IMAGE_SCALE;
|
||||||
|
else if(pixel_size_delta > MAX_IMAGE_SCALE) pixel_size_delta = MAX_IMAGE_SCALE;
|
||||||
|
|
||||||
|
if(last_pixel_size_delta != pixel_size_delta) redraw = true;
|
||||||
|
|
||||||
|
// on_wheel(&event, window);
|
||||||
|
}
|
||||||
|
if(event.type == SDL_EVENT_WINDOW_RESIZED) redraw = true;
|
||||||
|
} while(SDL_PollEvent(&event));
|
||||||
|
|
||||||
|
if(redraw){
|
||||||
|
redraw = false;
|
||||||
|
if(!draw_image(window, image, pixel_size_delta, current_image_start_x, current_image_start_y)) error_continue("Failed to draw image! Trying to continue...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv){
|
int main(int argc, char** argv){
|
||||||
if(argc < 2){
|
if(argc < 2){
|
||||||
printf("Usage: %s [image filepath]\n", argv[0]);
|
printf("Usage: %s [image filepath]\n", argv[0]);
|
||||||
@@ -129,7 +272,7 @@ int main(int argc, char** argv){
|
|||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
Image image = load_image(filepath);
|
Image image = load_image_pixels_from_file(filepath);
|
||||||
if(image.pixels == NULL){
|
if(image.pixels == NULL){
|
||||||
printf("Failed to load image!");
|
printf("Failed to load image!");
|
||||||
exit(3);
|
exit(3);
|
||||||
@@ -138,53 +281,28 @@ int main(int argc, char** argv){
|
|||||||
SDL_Window* window = create_window("SimpleImageViewer", image.x, image.y);
|
SDL_Window* window = create_window("SimpleImageViewer", image.x, image.y);
|
||||||
if(!window){
|
if(!window){
|
||||||
printf("Failed to create window!");
|
printf("Failed to create window!");
|
||||||
|
free_image_pixels_buffer(&image);
|
||||||
exit(4);
|
exit(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Surface* surface = get_surface_from_window(window);
|
if(!populate_image(window, &image)){
|
||||||
if(!surface){
|
printf("Failed to populate image!");
|
||||||
printf("Failed to get surface!");
|
free_image_pixels_buffer(&image);
|
||||||
exit(5);
|
SDL_DestroyWindow(window);
|
||||||
|
exit(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_image(surface, &image);
|
free_image_pixels_buffer(&image);
|
||||||
|
|
||||||
free_image(&image);
|
if(!draw_image(window, &image, 1.0f, 0, 0)){
|
||||||
|
printf("Failed to draw image!");
|
||||||
SDL_UpdateWindowSurface(window);
|
SDL_DestroyWindow(window);
|
||||||
|
exit(7);
|
||||||
bool drag_mouse = false;
|
|
||||||
int last_pointer_x = 0;
|
|
||||||
int last_pointer_y = 0;
|
|
||||||
|
|
||||||
SDL_Event event;
|
|
||||||
bool run = true;
|
|
||||||
while(run){
|
|
||||||
while (SDL_PollEvent(&event)) {
|
|
||||||
if (event.type == SDL_EVENT_KEY_UP){
|
|
||||||
switch(event.key.key){
|
|
||||||
case SDLK_ESCAPE: case SDLK_SPACE: case SDLK_RETURN:
|
|
||||||
run = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(event.type == SDL_EVENT_QUIT || event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED) run = false;
|
|
||||||
if(event.type == SDL_EVENT_MOUSE_BUTTON_DOWN && event.button.button == SDL_BUTTON_LEFT){
|
|
||||||
drag_mouse = true;
|
|
||||||
last_pointer_x = (int)event.button.x;
|
|
||||||
last_pointer_y = (int)event.button.y;
|
|
||||||
}
|
|
||||||
if(event.type == SDL_EVENT_MOUSE_BUTTON_UP && event.button.button == SDL_BUTTON_LEFT) drag_mouse = false;
|
|
||||||
if(event.type == SDL_EVENT_MOUSE_MOTION && drag_mouse){
|
|
||||||
int last_x, last_y;
|
|
||||||
SDL_GetWindowPosition(window, &last_x, &last_y);
|
|
||||||
SDL_SetWindowPosition(window, last_x + (int)event.button.x - last_pointer_x, last_y + (int)event.button.y - last_pointer_y);
|
|
||||||
}
|
|
||||||
if(event.type == SDL_EVENT_MOUSE_WHEEL){
|
|
||||||
on_wheel(&event, window);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loop(window, &image);
|
||||||
|
|
||||||
|
SDL_DestroyTexture(image.texture);
|
||||||
|
SDL_DestroySurface(image.surface);
|
||||||
SDL_DestroyWindow(window);
|
SDL_DestroyWindow(window);
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
viewer=
|
viewer="/path/to/SimpleImageViewer"
|
||||||
|
|
||||||
notify() {
|
notify() {
|
||||||
if [ -x /usr/bin/notify-send ]; then
|
if [ -x /usr/bin/notify-send ]; then
|
||||||
|
|||||||
Reference in New Issue
Block a user