summaryrefslogtreecommitdiffstats
path: root/minui
diff options
context:
space:
mode:
Diffstat (limited to 'minui')
-rw-r--r--minui/events.cpp124
-rw-r--r--minui/graphics.cpp4
-rw-r--r--minui/graphics_drm.cpp4
-rw-r--r--minui/include/minui/minui.h1
-rw-r--r--minui/resources.cpp24
5 files changed, 129 insertions, 28 deletions
diff --git a/minui/events.cpp b/minui/events.cpp
index 7d0250e97..f331ed68a 100644
--- a/minui/events.cpp
+++ b/minui/events.cpp
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
+#include <sys/inotify.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <unistd.h>
@@ -33,6 +34,8 @@
#include "minui/minui.h"
+constexpr const char* INPUT_DEV_DIR = "/dev/input";
+
constexpr size_t MAX_DEVICES = 16;
constexpr size_t MAX_MISC_FDS = 16;
@@ -46,6 +49,8 @@ struct FdInfo {
ev_callback cb;
};
+static bool g_allow_touch_inputs = true;
+static ev_callback g_saved_input_cb;
static android::base::unique_fd g_epoll_fd;
static epoll_event g_polled_events[MAX_DEVICES + MAX_MISC_FDS];
static int g_polled_events_count;
@@ -60,6 +65,78 @@ static bool test_bit(size_t bit, unsigned long* array) { // NOLINT
return (array[bit / BITS_PER_LONG] & (1UL << (bit % BITS_PER_LONG))) != 0;
}
+static bool should_add_input_device(int fd, bool allow_touch_inputs) {
+ // Use unsigned long to match ioctl's parameter type.
+ unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; // NOLINT
+
+ // Read the evbits of the input device.
+ if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
+ return false;
+ }
+
+ // We assume that only EV_KEY, EV_REL, and EV_SW event types are ever needed. EV_ABS is also
+ // allowed if allow_touch_inputs is set.
+ if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits) && !test_bit(EV_SW, ev_bits)) {
+ if (!allow_touch_inputs || !test_bit(EV_ABS, ev_bits)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static int inotify_cb(int fd, __unused uint32_t epevents) {
+ if (g_saved_input_cb == nullptr) return -1;
+
+ // The inotify will put one or several complete events.
+ // Should not read part of one event.
+ size_t event_len;
+ int ret = ioctl(fd, FIONREAD, &event_len);
+ if (ret != 0) return -1;
+
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(INPUT_DEV_DIR), closedir);
+ if (!dir) {
+ return -1;
+ }
+
+ std::vector<int8_t> buf(event_len);
+
+ ssize_t r = TEMP_FAILURE_RETRY(read(fd, buf.data(), event_len));
+ if (r != event_len) {
+ return -1;
+ }
+
+ size_t offset = 0;
+ while (offset < event_len) {
+ struct inotify_event* pevent = reinterpret_cast<struct inotify_event*>(buf.data() + offset);
+ if (offset + sizeof(inotify_event) + pevent->len > event_len) {
+ // The pevent->len is too large and buffer will over flow.
+ // In general, should not happen, just make more stable.
+ return -1;
+ }
+ offset += sizeof(inotify_event) + pevent->len;
+
+ pevent->name[pevent->len] = '\0';
+ if (strncmp(pevent->name, "event", 5)) {
+ continue;
+ }
+
+ android::base::unique_fd dfd(openat(dirfd(dir.get()), pevent->name, O_RDONLY));
+ if (dfd == -1) {
+ break;
+ }
+
+ if (!should_add_input_device(dfd, g_allow_touch_inputs)) {
+ continue;
+ }
+
+ // Only add, we assume the user will not plug out and plug in USB device again and again :)
+ ev_add_fd(std::move(dfd), g_saved_input_cb);
+ }
+
+ return 0;
+}
+
int ev_init(ev_callback input_cb, bool allow_touch_inputs) {
g_epoll_fd.reset();
@@ -68,7 +145,16 @@ int ev_init(ev_callback input_cb, bool allow_touch_inputs) {
return -1;
}
- std::unique_ptr<DIR, decltype(&closedir)> dir(opendir("/dev/input"), closedir);
+ android::base::unique_fd inotify_fd(inotify_init1(IN_CLOEXEC));
+ if (inotify_fd.get() == -1) {
+ return -1;
+ }
+
+ if (inotify_add_watch(inotify_fd, INPUT_DEV_DIR, IN_CREATE) < 0) {
+ return -1;
+ }
+
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(INPUT_DEV_DIR), closedir);
if (!dir) {
return -1;
}
@@ -80,22 +166,10 @@ int ev_init(ev_callback input_cb, bool allow_touch_inputs) {
android::base::unique_fd fd(openat(dirfd(dir.get()), de->d_name, O_RDONLY | O_CLOEXEC));
if (fd == -1) continue;
- // Use unsigned long to match ioctl's parameter type.
- unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; // NOLINT
-
- // Read the evbits of the input device.
- if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
+ if (!should_add_input_device(fd, allow_touch_inputs)) {
continue;
}
- // We assume that only EV_KEY, EV_REL, and EV_SW event types are ever needed. EV_ABS is also
- // allowed if allow_touch_inputs is set.
- if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits) && !test_bit(EV_SW, ev_bits)) {
- if (!allow_touch_inputs || !test_bit(EV_ABS, ev_bits)) {
- continue;
- }
- }
-
epoll_event ev;
ev.events = EPOLLIN | EPOLLWAKEUP;
ev.data.ptr = &ev_fdinfo[g_ev_count];
@@ -116,6 +190,11 @@ int ev_init(ev_callback input_cb, bool allow_touch_inputs) {
}
g_epoll_fd.reset(epoll_fd.release());
+
+ g_saved_input_cb = input_cb;
+ g_allow_touch_inputs = allow_touch_inputs;
+ ev_add_fd(std::move(inotify_fd), inotify_cb);
+
return 0;
}
@@ -148,6 +227,7 @@ void ev_exit(void) {
}
g_ev_misc_count = 0;
g_ev_dev_count = 0;
+ g_saved_input_cb = nullptr;
g_epoll_fd.reset();
}
@@ -170,13 +250,17 @@ void ev_dispatch(void) {
}
int ev_get_input(int fd, uint32_t epevents, input_event* ev) {
- if (epevents & EPOLLIN) {
- ssize_t r = TEMP_FAILURE_RETRY(read(fd, ev, sizeof(*ev)));
- if (r == sizeof(*ev)) {
- return 0;
- }
+ if (epevents & EPOLLIN) {
+ ssize_t r = TEMP_FAILURE_RETRY(read(fd, ev, sizeof(*ev)));
+ if (r == sizeof(*ev)) {
+ return 0;
}
- return -1;
+ }
+ if (epevents & EPOLLHUP) {
+ // Delete this watch
+ epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, fd, nullptr);
+ }
+ return -1;
}
int ev_sync_key_state(const ev_set_key_callback& set_key_cb) {
diff --git a/minui/graphics.cpp b/minui/graphics.cpp
index 4d1f9b2d2..d34da5674 100644
--- a/minui/graphics.cpp
+++ b/minui/graphics.cpp
@@ -209,7 +209,7 @@ void gr_texticon(int x, int y, const GRSurface* icon) {
void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a) {
uint32_t r32 = r, g32 = g, b32 = b, a32 = a;
- if (pixel_format == PixelFormat::ABGR || pixel_format == PixelFormat::BGRA) {
+ if (pixel_format == PixelFormat::ARGB || pixel_format == PixelFormat::BGRA) {
gr_current = (a32 << 24) | (r32 << 16) | (g32 << 8) | b32;
} else {
gr_current = (a32 << 24) | (b32 << 16) | (g32 << 8) | r32;
@@ -348,6 +348,8 @@ int gr_init() {
pixel_format = PixelFormat::ABGR;
} else if (format == "RGBX_8888") {
pixel_format = PixelFormat::RGBX;
+ } else if (format == "ARGB_8888") {
+ pixel_format = PixelFormat::ARGB;
} else if (format == "BGRA_8888") {
pixel_format = PixelFormat::BGRA;
} else {
diff --git a/minui/graphics_drm.cpp b/minui/graphics_drm.cpp
index 7b2eed15d..95759e382 100644
--- a/minui/graphics_drm.cpp
+++ b/minui/graphics_drm.cpp
@@ -62,6 +62,8 @@ static int drm_format_to_bpp(uint32_t format) {
case DRM_FORMAT_ABGR8888:
case DRM_FORMAT_BGRA8888:
case DRM_FORMAT_RGBX8888:
+ case DRM_FORMAT_RGBA8888:
+ case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_BGRX8888:
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_XRGB8888:
@@ -87,6 +89,8 @@ std::unique_ptr<GRSurfaceDrm> GRSurfaceDrm::Create(int drm_fd, int width, int he
format = DRM_FORMAT_ARGB8888;
} else if (pixel_format == PixelFormat::RGBX) {
format = DRM_FORMAT_XBGR8888;
+ } else if (pixel_format == PixelFormat::ARGB) {
+ format = DRM_FORMAT_BGRA8888;
} else {
format = DRM_FORMAT_RGB565;
}
diff --git a/minui/include/minui/minui.h b/minui/include/minui/minui.h
index 36bdcf103..163e41dc6 100644
--- a/minui/include/minui/minui.h
+++ b/minui/include/minui/minui.h
@@ -101,6 +101,7 @@ enum class PixelFormat : int {
ABGR = 1,
RGBX = 2,
BGRA = 3,
+ ARGB = 4,
};
// Initializes the graphics backend and loads font file. Returns 0 on success, or -1 on error. Note
diff --git a/minui/resources.cpp b/minui/resources.cpp
index 069a49529..f635acd1a 100644
--- a/minui/resources.cpp
+++ b/minui/resources.cpp
@@ -199,7 +199,7 @@ int res_create_display_surface(const char* name, GRSurface** pSurface) {
}
PixelFormat pixel_format = gr_pixel_format();
- if (pixel_format == PixelFormat::ABGR || pixel_format == PixelFormat::BGRA) {
+ if (pixel_format == PixelFormat::ARGB || pixel_format == PixelFormat::BGRA) {
png_set_bgr(png_ptr);
}
@@ -271,7 +271,7 @@ int res_create_multi_display_surface(const char* name, int* frames, int* fps,
surface[i] = created_surface.release();
}
- if (gr_pixel_format() == PixelFormat::ABGR || gr_pixel_format() == PixelFormat::BGRA) {
+ if (gr_pixel_format() == PixelFormat::ARGB || gr_pixel_format() == PixelFormat::BGRA) {
png_set_bgr(png_ptr);
}
@@ -317,7 +317,7 @@ int res_create_alpha_surface(const char* name, GRSurface** pSurface) {
}
PixelFormat pixel_format = gr_pixel_format();
- if (pixel_format == PixelFormat::ABGR || pixel_format == PixelFormat::BGRA) {
+ if (pixel_format == PixelFormat::ARGB || pixel_format == PixelFormat::BGRA) {
png_set_bgr(png_ptr);
}
@@ -347,6 +347,10 @@ bool matches_locale(const std::string& prefix, const std::string& locale) {
// match the locale string without the {script} section.
// For instance, prefix == "en" matches locale == "en-US", prefix == "sr-Latn" matches locale
// == "sr-Latn-BA", and prefix == "zh-CN" matches locale == "zh-Hans-CN".
+ if (prefix.empty()) {
+ return false;
+ }
+
if (android::base::StartsWith(locale, prefix)) {
return true;
}
@@ -414,12 +418,18 @@ int res_create_localized_alpha_surface(const char* name,
__unused int len = row[4];
char* loc = reinterpret_cast<char*>(&row[5]);
- if (y + 1 + h >= height || matches_locale(loc, locale)) {
+ // We need to include one additional line for the metadata of the localized image.
+ if (y + 1 + h > height) {
+ printf("Read exceeds the image boundary, y %u, h %d, height %u\n", y, h, height);
+ return -8;
+ }
+
+ if (matches_locale(loc, locale)) {
printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y);
auto surface = GRSurface::Create(w, h, w, 1);
if (!surface) {
- return -8;
+ return -9;
}
for (int i = 0; i < h; ++i, ++y) {
@@ -428,7 +438,7 @@ int res_create_localized_alpha_surface(const char* name,
}
*pSurface = surface.release();
- break;
+ return 0;
}
for (int i = 0; i < h; ++i, ++y) {
@@ -436,7 +446,7 @@ int res_create_localized_alpha_surface(const char* name,
}
}
- return 0;
+ return -10;
}
void res_free_surface(GRSurface* surface) {