feat: jpeg image rendering, desktop backgrounds, fix memory regression
This commit is contained in:
@@ -16,6 +16,8 @@ endif
|
||||
# ---- Paths ----
|
||||
|
||||
PROG_INC := ../../include
|
||||
JPEG_LIB := ../../lib/libjpeg
|
||||
LIBC_LIB := ../../lib/libc
|
||||
LINK_LD := ../../link.ld
|
||||
BINDIR := ../../bin
|
||||
OBJDIR := obj
|
||||
@@ -72,9 +74,13 @@ TARGET := $(BINDIR)/os/desktop.elf
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJS) $(LINK_LD) Makefile
|
||||
# ---- Libraries ----
|
||||
|
||||
LIBS := $(JPEG_LIB)/libjpeg.a $(LIBC_LIB)/liblibc.a
|
||||
|
||||
$(TARGET): $(OBJS) $(LIBS) $(LINK_LD) Makefile
|
||||
mkdir -p $(BINDIR)/os
|
||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) -o $@
|
||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
|
||||
|
||||
# C++ sources
|
||||
$(OBJDIR)/%.o: %.cpp Makefile
|
||||
|
||||
@@ -57,6 +57,10 @@ static bool str_ends_with(const char* s, const char* suffix) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_image_file(const char* name) {
|
||||
return str_ends_with(name, ".jpg") || str_ends_with(name, ".jpeg");
|
||||
}
|
||||
|
||||
static int detect_file_type(const char* name, bool is_dir) {
|
||||
if (is_dir) return 1;
|
||||
if (str_ends_with(name, ".elf")) return 2;
|
||||
@@ -545,7 +549,9 @@ static void filemanager_on_mouse(Window* win, MouseEvent& ev) {
|
||||
str_append(fullpath, "/", 512);
|
||||
}
|
||||
str_append(fullpath, fm->entry_names[clicked_idx], 512);
|
||||
if (fm->desktop) {
|
||||
if (is_image_file(fm->entry_names[clicked_idx])) {
|
||||
zenith::spawn("0:/os/imageviewer.elf", fullpath);
|
||||
} else if (fm->desktop) {
|
||||
open_texteditor_with_file(fm->desktop, fullpath);
|
||||
}
|
||||
}
|
||||
@@ -574,7 +580,7 @@ static void filemanager_on_mouse(Window* win, MouseEvent& ev) {
|
||||
if (fm->is_dir[clicked_idx]) {
|
||||
filemanager_navigate(fm, fm->entry_names[clicked_idx]);
|
||||
} else {
|
||||
// Open file in text editor
|
||||
// Open file in appropriate viewer
|
||||
char fullpath[512];
|
||||
zenith::strcpy(fullpath, fm->current_path);
|
||||
int plen = zenith::slen(fullpath);
|
||||
@@ -582,7 +588,9 @@ static void filemanager_on_mouse(Window* win, MouseEvent& ev) {
|
||||
str_append(fullpath, "/", 512);
|
||||
}
|
||||
str_append(fullpath, fm->entry_names[clicked_idx], 512);
|
||||
if (fm->desktop) {
|
||||
if (is_image_file(fm->entry_names[clicked_idx])) {
|
||||
zenith::spawn("0:/os/imageviewer.elf", fullpath);
|
||||
} else if (fm->desktop) {
|
||||
open_texteditor_with_file(fm->desktop, fullpath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "apps_common.hpp"
|
||||
#include "wallpaper.hpp"
|
||||
|
||||
// ============================================================================
|
||||
// Settings state
|
||||
@@ -15,6 +16,8 @@ struct SettingsState {
|
||||
int active_tab; // 0=Appearance, 1=Display, 2=About
|
||||
Zenith::SysInfo sys_info;
|
||||
uint64_t uptime_ms;
|
||||
WallpaperFileList wp_files;
|
||||
bool wp_scanned;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
@@ -130,9 +133,12 @@ static void draw_toggle_btn(Canvas& c, int x, int y, int bw, int bh,
|
||||
c.text(x + (bw - tw) / 2, y + (bh - fh) / 2, label, fg);
|
||||
}
|
||||
|
||||
static constexpr int WP_ITEM_H = 24;
|
||||
|
||||
static void settings_draw_appearance(Canvas& c, SettingsState* st) {
|
||||
DesktopSettings& s = st->desktop->settings;
|
||||
Color accent = s.accent_color;
|
||||
Color dim = Color::from_rgb(0x88, 0x88, 0x88);
|
||||
int x = 16;
|
||||
int y = 12;
|
||||
int sfh = system_font_height();
|
||||
@@ -142,27 +148,80 @@ static void settings_draw_appearance(Canvas& c, SettingsState* st) {
|
||||
c.text(x, y, "Background", colors::TEXT_COLOR);
|
||||
y += line_h;
|
||||
|
||||
// Radio buttons: Gradient / Solid
|
||||
draw_radio(c, x, y, s.bg_gradient, accent);
|
||||
// Radio buttons: Gradient / Solid Color / Image
|
||||
bool mode_grad = s.bg_gradient && !s.bg_image;
|
||||
bool mode_solid = !s.bg_gradient && !s.bg_image;
|
||||
bool mode_image = s.bg_image;
|
||||
|
||||
draw_radio(c, x, y, mode_grad, accent);
|
||||
c.text(x + 20, y + 2, "Gradient", colors::TEXT_COLOR);
|
||||
|
||||
draw_radio(c, x + 120, y, !s.bg_gradient, accent);
|
||||
c.text(x + 140, y + 2, "Solid Color", colors::TEXT_COLOR);
|
||||
draw_radio(c, x + 120, y, mode_solid, accent);
|
||||
c.text(x + 140, y + 2, "Solid", colors::TEXT_COLOR);
|
||||
|
||||
draw_radio(c, x + 220, y, mode_image, accent);
|
||||
c.text(x + 240, y + 2, "Image", colors::TEXT_COLOR);
|
||||
y += line_h + 4;
|
||||
|
||||
if (s.bg_gradient) {
|
||||
if (mode_image) {
|
||||
// Scan for images lazily
|
||||
if (!st->wp_scanned) {
|
||||
wallpaper_scan_dir("0:/home", &st->wp_files);
|
||||
st->wp_scanned = true;
|
||||
}
|
||||
|
||||
c.text(x, y, "Images in 0:/home/", dim);
|
||||
y += sfh + 6;
|
||||
|
||||
if (st->wp_files.count == 0) {
|
||||
c.text(x + 8, y, "No .jpg files found", dim);
|
||||
y += WP_ITEM_H;
|
||||
} else {
|
||||
for (int i = 0; i < st->wp_files.count && i < 8; i++) {
|
||||
// Build full path for comparison
|
||||
char fullpath[256];
|
||||
zenith::strcpy(fullpath, "0:/home/");
|
||||
str_append(fullpath, st->wp_files.names[i], 256);
|
||||
|
||||
bool selected = s.bg_image &&
|
||||
zenith::streq(s.bg_image_path, fullpath);
|
||||
|
||||
if (selected) {
|
||||
c.fill_rounded_rect(x, y, c.w - 2 * x, WP_ITEM_H, 3, accent);
|
||||
}
|
||||
|
||||
// Truncate long filenames
|
||||
char label[40];
|
||||
int nlen = zenith::slen(st->wp_files.names[i]);
|
||||
if (nlen > 35) {
|
||||
zenith::strncpy(label, st->wp_files.names[i], 32);
|
||||
label[32] = '.';
|
||||
label[33] = '.';
|
||||
label[34] = '.';
|
||||
label[35] = '\0';
|
||||
} else {
|
||||
zenith::strncpy(label, st->wp_files.names[i], 39);
|
||||
}
|
||||
|
||||
Color tc = selected ? colors::WHITE : colors::TEXT_COLOR;
|
||||
c.text(x + 8, y + (WP_ITEM_H - sfh) / 2, label, tc);
|
||||
y += WP_ITEM_H;
|
||||
}
|
||||
}
|
||||
y += 6;
|
||||
} else if (mode_grad) {
|
||||
// Top color swatches
|
||||
c.text(x, y + 4, "Top", Color::from_rgb(0x88, 0x88, 0x88));
|
||||
c.text(x, y + 4, "Top", dim);
|
||||
draw_swatch_row(c, x + 70, y, bg_palette, s.bg_grad_top, accent);
|
||||
y += SWATCH_SIZE + 14;
|
||||
|
||||
// Bottom color swatches
|
||||
c.text(x, y + 4, "Bottom", Color::from_rgb(0x88, 0x88, 0x88));
|
||||
c.text(x, y + 4, "Bottom", dim);
|
||||
draw_swatch_row(c, x + 70, y, bg_palette, s.bg_grad_bottom, accent);
|
||||
y += SWATCH_SIZE + 14;
|
||||
} else {
|
||||
// Solid color swatches
|
||||
c.text(x, y + 4, "Color", Color::from_rgb(0x88, 0x88, 0x88));
|
||||
c.text(x, y + 4, "Color", dim);
|
||||
draw_swatch_row(c, x + 70, y, bg_palette, s.bg_solid, accent);
|
||||
y += SWATCH_SIZE + 14;
|
||||
}
|
||||
@@ -363,23 +422,58 @@ static void settings_on_mouse(Window* win, MouseEvent& ev) {
|
||||
int line_h = sfh + 10;
|
||||
int y = 12;
|
||||
|
||||
bool mode_grad = s.bg_gradient && !s.bg_image;
|
||||
bool mode_image = s.bg_image;
|
||||
|
||||
// "Background" label
|
||||
y += line_h;
|
||||
|
||||
// Radio: Gradient
|
||||
if (mx >= x && mx < x + 100 && cy >= y && cy < y + 16) {
|
||||
s.bg_gradient = true;
|
||||
s.bg_image = false;
|
||||
return;
|
||||
}
|
||||
// Radio: Solid
|
||||
if (mx >= x + 120 && mx < x + 260 && cy >= y && cy < y + 16) {
|
||||
if (mx >= x + 120 && mx < x + 210 && cy >= y && cy < y + 16) {
|
||||
s.bg_gradient = false;
|
||||
s.bg_image = false;
|
||||
return;
|
||||
}
|
||||
// Radio: Image
|
||||
if (mx >= x + 220 && mx < x + 320 && cy >= y && cy < y + 16) {
|
||||
s.bg_image = true;
|
||||
s.bg_gradient = false;
|
||||
if (!st->wp_scanned) {
|
||||
wallpaper_scan_dir("0:/home", &st->wp_files);
|
||||
st->wp_scanned = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
y += line_h + 4;
|
||||
|
||||
int idx;
|
||||
if (s.bg_gradient) {
|
||||
if (mode_image) {
|
||||
// "Images in 0:/home/" label
|
||||
y += sfh + 6;
|
||||
|
||||
// File list clicks
|
||||
for (int i = 0; i < st->wp_files.count && i < 8; i++) {
|
||||
if (cy >= y && cy < y + WP_ITEM_H &&
|
||||
mx >= x && mx < win->content_w - x) {
|
||||
// Build full path and load wallpaper
|
||||
char fullpath[256];
|
||||
zenith::strcpy(fullpath, "0:/home/");
|
||||
str_append(fullpath, st->wp_files.names[i], 256);
|
||||
wallpaper_load(&s, fullpath,
|
||||
st->desktop->screen_w, st->desktop->screen_h);
|
||||
return;
|
||||
}
|
||||
y += WP_ITEM_H;
|
||||
}
|
||||
if (st->wp_files.count == 0) y += WP_ITEM_H;
|
||||
y += 6;
|
||||
} else if (mode_grad) {
|
||||
// Top swatches
|
||||
if (swatch_hit(mx, cy, x + 70, y, &idx)) {
|
||||
s.bg_grad_top = bg_palette[idx];
|
||||
@@ -504,6 +598,8 @@ void open_settings(DesktopState* ds) {
|
||||
st->active_tab = 0;
|
||||
zenith::get_info(&st->sys_info);
|
||||
st->uptime_ms = zenith::get_milliseconds();
|
||||
st->wp_scanned = false;
|
||||
st->wp_files.count = 0;
|
||||
|
||||
win->app_data = st;
|
||||
win->on_draw = settings_on_draw;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "apps_common.hpp"
|
||||
#include "wallpaper.hpp"
|
||||
|
||||
// ============================================================================
|
||||
// Desktop Implementation
|
||||
@@ -71,14 +72,23 @@ void gui::desktop_init(DesktopState* ds) {
|
||||
|
||||
// Settings defaults
|
||||
ds->settings.bg_gradient = true;
|
||||
ds->settings.bg_image = false;
|
||||
ds->settings.bg_grad_top = Color::from_rgb(0xD0, 0xD8, 0xE8);
|
||||
ds->settings.bg_grad_bottom = Color::from_rgb(0xA0, 0xA8, 0xB8);
|
||||
ds->settings.bg_solid = Color::from_rgb(0xD0, 0xD8, 0xE8);
|
||||
ds->settings.panel_color = colors::PANEL_BG;
|
||||
ds->settings.bg_image_path[0] = '\0';
|
||||
ds->settings.bg_wallpaper = nullptr;
|
||||
ds->settings.bg_wallpaper_w = 0;
|
||||
ds->settings.bg_wallpaper_h = 0;
|
||||
ds->settings.panel_color = Color::from_rgb(0x10, 0x10, 0x10);
|
||||
ds->settings.accent_color = colors::ACCENT;
|
||||
ds->settings.show_shadows = true;
|
||||
ds->settings.clock_24h = true;
|
||||
ds->settings.ui_scale = 1;
|
||||
|
||||
// Try to load default wallpaper
|
||||
wallpaper_load(&ds->settings, "0:/home/troy-olson-MhYIwOiyZpM-unsplash.jpg",
|
||||
ds->screen_w, ds->screen_h);
|
||||
zenith::win_setscale(1);
|
||||
|
||||
ds->ctx_menu_open = false;
|
||||
@@ -299,8 +309,10 @@ void gui::desktop_draw_panel(DesktopState* ds) {
|
||||
fb.fill_rect(0, y, sw, 1, Color::from_rgb(r, g, b));
|
||||
}
|
||||
|
||||
// Bottom highlight line
|
||||
fb.fill_rect(0, PANEL_HEIGHT - 1, sw, 1, Color::from_rgba(0xFF, 0xFF, 0xFF, 0x10));
|
||||
// Bottom highlight line (skip when wallpaper is set — the white bleeds through)
|
||||
if (!ds->settings.bg_image) {
|
||||
fb.fill_rect(0, PANEL_HEIGHT - 1, sw, 1, Color::from_rgba(0xFF, 0xFF, 0xFF, 0x10));
|
||||
}
|
||||
|
||||
// App menu button (left side)
|
||||
int btn_x = 4;
|
||||
@@ -880,7 +892,12 @@ void gui::desktop_compose(DesktopState* ds) {
|
||||
|
||||
for (int y = 0; y < sh; y++) {
|
||||
uint32_t* row = (uint32_t*)((uint8_t*)buf + y * pitch);
|
||||
if (y < grad_start) {
|
||||
if (ds->settings.bg_image && ds->settings.bg_wallpaper) {
|
||||
// Wallpaper covers the entire screen; panel draws on top
|
||||
uint32_t* wp = ds->settings.bg_wallpaper + y * ds->settings.bg_wallpaper_w;
|
||||
int cw = sw < ds->settings.bg_wallpaper_w ? sw : ds->settings.bg_wallpaper_w;
|
||||
for (int x = 0; x < cw; x++) row[x] = wp[x];
|
||||
} else if (y < grad_start) {
|
||||
// Panel area - will be overwritten by panel drawing
|
||||
uint32_t px = ds->settings.panel_color.to_pixel();
|
||||
for (int x = 0; x < sw; x++) row[x] = px;
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* wallpaper.hpp
|
||||
* ZenithOS Desktop - JPEG wallpaper loading, scaling, and directory scanning
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <zenith/syscall.h>
|
||||
#include <zenith/string.h>
|
||||
#include <zenith/heap.h>
|
||||
#include <gui/gui.hpp>
|
||||
#include <gui/desktop.hpp>
|
||||
|
||||
// Forward-declare stb_image functions (implementation in libjpeg.a).
|
||||
// We avoid including stb_image.h directly because its declaration section
|
||||
// pulls in <stdlib.h> which is unavailable in the desktop's freestanding build.
|
||||
extern "C" {
|
||||
unsigned char* stbi_load_from_memory(const unsigned char* buffer, int len,
|
||||
int* x, int* y, int* channels_in_file,
|
||||
int desired_channels);
|
||||
void stbi_image_free(void* retval_from_stbi_load);
|
||||
const char* stbi_failure_reason(void);
|
||||
}
|
||||
|
||||
namespace gui {
|
||||
|
||||
// ============================================================================
|
||||
// Wallpaper loading
|
||||
// ============================================================================
|
||||
|
||||
// Load a JPEG file and scale it to cover the given screen dimensions.
|
||||
// Stores the scaled ARGB pixel buffer in settings. Returns true on success.
|
||||
inline bool wallpaper_load(DesktopSettings* s, const char* path,
|
||||
int screen_w, int screen_h) {
|
||||
// Free existing wallpaper
|
||||
if (s->bg_wallpaper) {
|
||||
zenith::mfree(s->bg_wallpaper);
|
||||
s->bg_wallpaper = nullptr;
|
||||
s->bg_wallpaper_w = 0;
|
||||
s->bg_wallpaper_h = 0;
|
||||
}
|
||||
|
||||
// Read file
|
||||
int fd = zenith::open(path);
|
||||
if (fd < 0) return false;
|
||||
|
||||
uint64_t size = zenith::getsize(fd);
|
||||
if (size == 0 || size > 16 * 1024 * 1024) {
|
||||
zenith::close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t* filedata = (uint8_t*)zenith::malloc(size);
|
||||
if (!filedata) { zenith::close(fd); return false; }
|
||||
|
||||
int bytes_read = zenith::read(fd, filedata, 0, size);
|
||||
zenith::close(fd);
|
||||
if (bytes_read <= 0) { zenith::mfree(filedata); return false; }
|
||||
|
||||
// Decode JPEG
|
||||
int img_w, img_h, channels;
|
||||
unsigned char* rgb = stbi_load_from_memory(filedata, bytes_read,
|
||||
&img_w, &img_h, &channels, 3);
|
||||
zenith::mfree(filedata);
|
||||
if (!rgb) return false;
|
||||
|
||||
// Scale to cover screen (crop to fill, maintain aspect ratio)
|
||||
int dst_w = screen_w;
|
||||
int dst_h = screen_h;
|
||||
|
||||
uint32_t* scaled = (uint32_t*)zenith::malloc((uint64_t)dst_w * dst_h * 4);
|
||||
if (!scaled) { stbi_image_free(rgb); return false; }
|
||||
|
||||
// Compute source crop region for "cover" scaling
|
||||
int src_crop_w, src_crop_h, src_x0, src_y0;
|
||||
if ((int64_t)img_w * dst_h > (int64_t)img_h * dst_w) {
|
||||
// Image is wider — crop sides
|
||||
src_crop_h = img_h;
|
||||
src_crop_w = (int)((int64_t)img_h * dst_w / dst_h);
|
||||
src_x0 = (img_w - src_crop_w) / 2;
|
||||
src_y0 = 0;
|
||||
} else {
|
||||
// Image is taller — crop top/bottom
|
||||
src_crop_w = img_w;
|
||||
src_crop_h = (int)((int64_t)img_w * dst_h / dst_w);
|
||||
src_x0 = 0;
|
||||
src_y0 = (img_h - src_crop_h) / 2;
|
||||
}
|
||||
|
||||
// Nearest-neighbor scale from cropped region to destination
|
||||
for (int y = 0; y < dst_h; y++) {
|
||||
int sy = src_y0 + (int)((int64_t)y * src_crop_h / dst_h);
|
||||
if (sy < 0) sy = 0;
|
||||
if (sy >= img_h) sy = img_h - 1;
|
||||
for (int x = 0; x < dst_w; x++) {
|
||||
int sx = src_x0 + (int)((int64_t)x * src_crop_w / dst_w);
|
||||
if (sx < 0) sx = 0;
|
||||
if (sx >= img_w) sx = img_w - 1;
|
||||
int si = (sy * img_w + sx) * 3;
|
||||
scaled[y * dst_w + x] = 0xFF000000u
|
||||
| ((uint32_t)rgb[si] << 16)
|
||||
| ((uint32_t)rgb[si + 1] << 8)
|
||||
| (uint32_t)rgb[si + 2];
|
||||
}
|
||||
}
|
||||
|
||||
stbi_image_free(rgb);
|
||||
|
||||
s->bg_wallpaper = scaled;
|
||||
s->bg_wallpaper_w = dst_w;
|
||||
s->bg_wallpaper_h = dst_h;
|
||||
zenith::strncpy(s->bg_image_path, path, 127);
|
||||
s->bg_image = true;
|
||||
s->bg_gradient = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void wallpaper_free(DesktopSettings* s) {
|
||||
if (s->bg_wallpaper) {
|
||||
zenith::mfree(s->bg_wallpaper);
|
||||
s->bg_wallpaper = nullptr;
|
||||
s->bg_wallpaper_w = 0;
|
||||
s->bg_wallpaper_h = 0;
|
||||
}
|
||||
s->bg_image_path[0] = '\0';
|
||||
s->bg_image = false;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Directory scanning for JPEG files
|
||||
// ============================================================================
|
||||
|
||||
static constexpr int WALLPAPER_MAX_FILES = 16;
|
||||
|
||||
struct WallpaperFileList {
|
||||
char names[WALLPAPER_MAX_FILES][64];
|
||||
int count;
|
||||
};
|
||||
|
||||
inline void wallpaper_scan_dir(const char* dir_path, WallpaperFileList* list) {
|
||||
list->count = 0;
|
||||
|
||||
const char* raw_names[64];
|
||||
int total = zenith::readdir(dir_path, raw_names, 64);
|
||||
if (total <= 0) return;
|
||||
|
||||
// Compute prefix to strip (readdir returns full paths from VFS root)
|
||||
const char* after_drive = dir_path;
|
||||
for (int k = 0; after_drive[k]; k++) {
|
||||
if (after_drive[k] == ':' && after_drive[k + 1] == '/') {
|
||||
after_drive += k + 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
char prefix[256] = {0};
|
||||
int prefix_len = 0;
|
||||
if (after_drive[0] != '\0') {
|
||||
zenith::strcpy(prefix, after_drive);
|
||||
prefix_len = zenith::slen(prefix);
|
||||
if (prefix_len > 0 && prefix[prefix_len - 1] != '/') {
|
||||
prefix[prefix_len++] = '/';
|
||||
prefix[prefix_len] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
auto to_lower = [](char c) -> char {
|
||||
return (c >= 'A' && c <= 'Z') ? (char)(c + 32) : c;
|
||||
};
|
||||
|
||||
for (int i = 0; i < total && list->count < WALLPAPER_MAX_FILES; i++) {
|
||||
const char* name = raw_names[i];
|
||||
|
||||
// Strip prefix
|
||||
if (prefix_len > 0) {
|
||||
bool match = true;
|
||||
for (int k = 0; k < prefix_len; k++) {
|
||||
if (name[k] != prefix[k]) { match = false; break; }
|
||||
}
|
||||
if (match) name += prefix_len;
|
||||
}
|
||||
|
||||
int nlen = zenith::slen(name);
|
||||
|
||||
// Skip directories
|
||||
if (nlen > 0 && name[nlen - 1] == '/') continue;
|
||||
|
||||
// Check for .jpg
|
||||
bool is_jpeg = false;
|
||||
if (nlen >= 4 &&
|
||||
to_lower(name[nlen - 4]) == '.' &&
|
||||
to_lower(name[nlen - 3]) == 'j' &&
|
||||
to_lower(name[nlen - 2]) == 'p' &&
|
||||
to_lower(name[nlen - 1]) == 'g') {
|
||||
is_jpeg = true;
|
||||
}
|
||||
// Check for .jpeg
|
||||
if (!is_jpeg && nlen >= 5 &&
|
||||
to_lower(name[nlen - 5]) == '.' &&
|
||||
to_lower(name[nlen - 4]) == 'j' &&
|
||||
to_lower(name[nlen - 3]) == 'p' &&
|
||||
to_lower(name[nlen - 2]) == 'e' &&
|
||||
to_lower(name[nlen - 1]) == 'g') {
|
||||
is_jpeg = true;
|
||||
}
|
||||
|
||||
if (is_jpeg) {
|
||||
zenith::strncpy(list->names[list->count], name, 63);
|
||||
list->count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gui
|
||||
Reference in New Issue
Block a user