summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/3rdparty/cdl.c96
-rw-r--r--lib/3rdparty/cdl.h10
-rw-r--r--lib/3rdparty/tinydir.h548
-rw-r--r--lib/CMakeLists.txt5
-rw-r--r--lib/bemenu.h339
-rw-r--r--lib/draw/curses.c498
-rw-r--r--lib/filter.c141
-rw-r--r--lib/internal.h172
-rw-r--r--lib/item.c76
-rw-r--r--lib/library.c152
-rw-r--r--lib/list.c121
-rw-r--r--lib/menu.c577
-rw-r--r--lib/renderers/CMakeLists.txt10
-rw-r--r--lib/renderers/curses/CMakeLists.txt6
-rw-r--r--lib/renderers/curses/curses.c379
-rw-r--r--lib/util.c133
-rw-r--r--lib/version.h.in1
17 files changed, 1898 insertions, 1366 deletions
diff --git a/lib/3rdparty/cdl.c b/lib/3rdparty/cdl.c
new file mode 100644
index 0000000..d7a226a
--- /dev/null
+++ b/lib/3rdparty/cdl.c
@@ -0,0 +1,96 @@
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#ifndef size_t
+# include <stddef.h>
+#endif
+
+#if defined(_WIN32) || defined(_WIN64)
+# include <windows.h>
+#elif defined(__posix__) || defined(__unix__) || defined(__linux__) || defined(__APPLE__)
+# include <dlfcn.h>
+#else
+# warning "cdl: unsupported os"
+#endif
+
+void* chckDlLoad(const char *file, const char **outError)
+{
+ assert(file);
+ void *handle = NULL;
+ const char *error = NULL;
+
+#if defined(_WIN32) || defined(_WIN64)
+#if defined(__WINRT__)
+ /**
+ * WinRT only publically supports LoadPackagedLibrary() for loading .dll
+ * files. LoadLibrary() is a private API, and not available for apps
+ * (that can be published to MS' Windows Store.)
+ */
+ handle = (void*)LoadPackagedLibrary(file, 0);
+#else
+ handle = (void*)LoadLibrary(file);
+#endif
+
+ if (!handle)
+ error = "Failed to load dll file.";
+#elif defined(__posix__) || defined(__unix__) || defined(__linux__) || defined(__APPLE__)
+ if (!(handle = dlopen(file, RTLD_NOW | RTLD_LOCAL)))
+ error = dlerror();
+#else
+ error = "cdl: unsupported os";
+#endif
+
+ if (outError)
+ *outError = error;
+
+ return handle;
+}
+
+void* chckDlLoadSymbol(void *handle, const char *name, const char **outError)
+{
+ assert(handle);
+ void *symbol = NULL;
+ const char *error = NULL;
+
+#if defined(_WIN32) || defined(_WIN64)
+ if (!(symbol = (void*)GetProcAddress((HMODULE)handle, name)))
+ error = "Failed to load symbol.";
+#elif defined(__posix__) || defined(__unix__) || defined(__linux__) || defined(__APPLE__)
+ if (!(symbol = dlsym(handle, name))) {
+ size_t len = strlen(name) + 1;
+ char *nname = calloc(1, len + 1);
+
+ if (nname) {
+ /* append an underscore for platforms that need that. */
+ nname[0] = '_';
+ memcpy(nname + 1, name, len);
+ symbol = dlsym(handle, nname);
+ free(nname);
+ }
+ }
+
+ if (!symbol)
+ error = dlerror();
+#else
+ error = "cdl: unsupported os";
+#endif
+
+ if (outError)
+ *outError = error;
+
+ return symbol;
+}
+
+void chckDlUnload(void *handle)
+{
+ assert(handle);
+
+#if defined(_WIN32) || defined(_WIN64)
+ FreeLibrary((HMODULE)handle);
+#elif defined(__posix__) || defined(__unix__) || defined(__linux__) || defined(__APPLE__)
+ dlclose(handle);
+#endif
+}
+
+/* vim: set ts=8 sw=3 tw=0 :*/
diff --git a/lib/3rdparty/cdl.h b/lib/3rdparty/cdl.h
new file mode 100644
index 0000000..9255654
--- /dev/null
+++ b/lib/3rdparty/cdl.h
@@ -0,0 +1,10 @@
+#ifndef __chck_cdl__
+#define __chck_cdl__
+
+void* chckDlLoad(const char *file, const char **outError);
+void* chckDlLoadSymbol(void *handle, const char *name, const char **outError);
+void chckDlUnload(void *handle);
+
+#endif /* __chck_cdl__ */
+
+/* vim: set ts=8 sw=3 tw=0 :*/
diff --git a/lib/3rdparty/tinydir.h b/lib/3rdparty/tinydir.h
new file mode 100644
index 0000000..db11e8e
--- /dev/null
+++ b/lib/3rdparty/tinydir.h
@@ -0,0 +1,548 @@
+/*
+Copyright (c) 2013-2014, Cong Xu, Baudouin Feildel
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef TINYDIR_H
+#define TINYDIR_H
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _MSC_VER
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#pragma warning (disable : 4996)
+#else
+#include <dirent.h>
+#include <libgen.h>
+#include <sys/stat.h>
+#endif
+
+
+/* types */
+
+#define _TINYDIR_PATH_MAX 4096
+#ifdef _MSC_VER
+/* extra chars for the "\\*" mask */
+#define _TINYDIR_PATH_EXTRA 2
+#else
+#define _TINYDIR_PATH_EXTRA 0
+#endif
+#define _TINYDIR_FILENAME_MAX 256
+
+#ifdef _MSC_VER
+#define _TINYDIR_FUNC static __inline
+#else
+#define _TINYDIR_FUNC static __inline__
+#endif
+
+typedef struct
+{
+ char path[_TINYDIR_PATH_MAX];
+ char name[_TINYDIR_FILENAME_MAX];
+ char *extension;
+ int is_dir;
+ int is_reg;
+
+#ifdef _MSC_VER
+#else
+ struct stat _s;
+#endif
+} tinydir_file;
+
+typedef struct
+{
+ char path[_TINYDIR_PATH_MAX];
+ int has_next;
+ size_t n_files;
+
+ tinydir_file *_files;
+#ifdef _MSC_VER
+ HANDLE _h;
+ WIN32_FIND_DATA _f;
+#else
+ DIR *_d;
+ struct dirent *_e;
+#endif
+} tinydir_dir;
+
+
+/* declarations */
+
+_TINYDIR_FUNC
+int tinydir_open(tinydir_dir *dir, const char *path);
+_TINYDIR_FUNC
+int tinydir_open_sorted(tinydir_dir *dir, const char *path);
+_TINYDIR_FUNC
+void tinydir_close(tinydir_dir *dir);
+
+_TINYDIR_FUNC
+int tinydir_next(tinydir_dir *dir);
+_TINYDIR_FUNC
+int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file);
+_TINYDIR_FUNC
+int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i);
+_TINYDIR_FUNC
+int tinydir_open_subdir_n(tinydir_dir *dir, size_t i);
+
+_TINYDIR_FUNC
+void _tinydir_get_ext(tinydir_file *file);
+_TINYDIR_FUNC
+int _tinydir_file_cmp(const void *a, const void *b);
+
+
+/* definitions*/
+
+_TINYDIR_FUNC
+int tinydir_open(tinydir_dir *dir, const char *path)
+{
+ if (dir == NULL || path == NULL || strlen(path) == 0)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ if (strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
+ {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ /* initialise dir */
+ dir->_files = NULL;
+#ifdef _MSC_VER
+ dir->_h = INVALID_HANDLE_VALUE;
+#else
+ dir->_d = NULL;
+#endif
+ tinydir_close(dir);
+
+ strcpy(dir->path, path);
+#ifdef _MSC_VER
+ strcat(dir->path, "\\*");
+ dir->_h = FindFirstFile(dir->path, &dir->_f);
+ dir->path[strlen(dir->path) - 2] = '\0';
+ if (dir->_h == INVALID_HANDLE_VALUE)
+#else
+ dir->_d = opendir(path);
+ if (dir->_d == NULL)
+#endif
+ {
+ errno = ENOENT;
+ goto bail;
+ }
+
+ /* read first file */
+ dir->has_next = 1;
+#ifndef _MSC_VER
+ dir->_e = readdir(dir->_d);
+ if (dir->_e == NULL)
+ {
+ dir->has_next = 0;
+ }
+#endif
+
+ return 0;
+
+bail:
+ tinydir_close(dir);
+ return -1;
+}
+
+_TINYDIR_FUNC
+int tinydir_open_sorted(tinydir_dir *dir, const char *path)
+{
+ /* Count the number of files first, to pre-allocate the files array */
+ size_t n_files = 0;
+ if (tinydir_open(dir, path) == -1)
+ {
+ return -1;
+ }
+ while (dir->has_next)
+ {
+ n_files++;
+ if (tinydir_next(dir) == -1)
+ {
+ goto bail;
+ }
+ }
+ tinydir_close(dir);
+
+ if (tinydir_open(dir, path) == -1)
+ {
+ return -1;
+ }
+
+ dir->n_files = 0;
+ dir->_files = (tinydir_file *)malloc(sizeof *dir->_files * n_files);
+ if (dir->_files == NULL)
+ {
+ errno = ENOMEM;
+ goto bail;
+ }
+ while (dir->has_next)
+ {
+ tinydir_file *p_file;
+ dir->n_files++;
+
+ p_file = &dir->_files[dir->n_files - 1];
+ if (tinydir_readfile(dir, p_file) == -1)
+ {
+ goto bail;
+ }
+
+ if (tinydir_next(dir) == -1)
+ {
+ goto bail;
+ }
+
+ /* Just in case the number of files has changed between the first and
+ second reads, terminate without writing into unallocated memory */
+ if (dir->n_files == n_files)
+ {
+ break;
+ }
+ }
+
+ qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp);
+
+ return 0;
+
+bail:
+ tinydir_close(dir);
+ return -1;
+}
+
+_TINYDIR_FUNC
+void tinydir_close(tinydir_dir *dir)
+{
+ if (dir == NULL)
+ {
+ return;
+ }
+
+ memset(dir->path, 0, sizeof(dir->path));
+ dir->has_next = 0;
+ dir->n_files = 0;
+ if (dir->_files != NULL)
+ {
+ free(dir->_files);
+ }
+ dir->_files = NULL;
+#ifdef _MSC_VER
+ if (dir->_h != INVALID_HANDLE_VALUE)
+ {
+ FindClose(dir->_h);
+ }
+ dir->_h = INVALID_HANDLE_VALUE;
+#else
+ if (dir->_d)
+ {
+ closedir(dir->_d);
+ }
+ dir->_d = NULL;
+ dir->_e = NULL;
+#endif
+}
+
+_TINYDIR_FUNC
+int tinydir_next(tinydir_dir *dir)
+{
+ if (dir == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ if (!dir->has_next)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+#ifdef _MSC_VER
+ if (FindNextFile(dir->_h, &dir->_f) == 0)
+#else
+ dir->_e = readdir(dir->_d);
+ if (dir->_e == NULL)
+#endif
+ {
+ dir->has_next = 0;
+#ifdef _MSC_VER
+ if (GetLastError() != ERROR_SUCCESS &&
+ GetLastError() != ERROR_NO_MORE_FILES)
+ {
+ tinydir_close(dir);
+ errno = EIO;
+ return -1;
+ }
+#endif
+ }
+
+ return 0;
+}
+
+_TINYDIR_FUNC
+int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
+{
+ if (dir == NULL || file == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+#ifdef _MSC_VER
+ if (dir->_h == INVALID_HANDLE_VALUE)
+#else
+ if (dir->_e == NULL)
+#endif
+ {
+ errno = ENOENT;
+ return -1;
+ }
+ if (strlen(dir->path) +
+ strlen(
+#ifdef _MSC_VER
+ dir->_f.cFileName
+#else
+ dir->_e->d_name
+#endif
+ ) + 1 + _TINYDIR_PATH_EXTRA >=
+ _TINYDIR_PATH_MAX)
+ {
+ /* the path for the file will be too long */
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ if (strlen(
+#ifdef _MSC_VER
+ dir->_f.cFileName
+#else
+ dir->_e->d_name
+#endif
+ ) >= _TINYDIR_FILENAME_MAX)
+ {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ strcpy(file->path, dir->path);
+ strcat(file->path, "/");
+ strcpy(file->name,
+#ifdef _MSC_VER
+ dir->_f.cFileName
+#else
+ dir->_e->d_name
+#endif
+ );
+ strcat(file->path, file->name);
+#ifndef _MSC_VER
+ if (stat(file->path, &file->_s) == -1)
+ {
+ return -1;
+ }
+#endif
+ _tinydir_get_ext(file);
+
+ file->is_dir =
+#ifdef _MSC_VER
+ !!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
+#else
+ S_ISDIR(file->_s.st_mode);
+#endif
+ file->is_reg =
+#ifdef _MSC_VER
+ !!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
+ (
+ !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) &&
+ !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
+ !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
+#ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
+ !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) &&
+#endif
+#ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
+ !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) &&
+#endif
+ !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) &&
+ !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY));
+#else
+ S_ISREG(file->_s.st_mode);
+#endif
+
+ return 0;
+}
+
+_TINYDIR_FUNC
+int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i)
+{
+ if (dir == NULL || file == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ if (i >= dir->n_files)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ memcpy(file, &dir->_files[i], sizeof(tinydir_file));
+ _tinydir_get_ext(file);
+
+ return 0;
+}
+
+_TINYDIR_FUNC
+int tinydir_open_subdir_n(tinydir_dir *dir, size_t i)
+{
+ char path[_TINYDIR_PATH_MAX];
+ if (dir == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ if (i >= dir->n_files || !dir->_files[i].is_dir)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ strcpy(path, dir->_files[i].path);
+ tinydir_close(dir);
+ if (tinydir_open_sorted(dir, path) == -1)
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Open a single file given its path */
+_TINYDIR_FUNC
+int tinydir_file_open(tinydir_file *file, const char *path)
+{
+ tinydir_dir dir;
+ int result = 0;
+ int found = 0;
+ char dir_name_buf[_TINYDIR_PATH_MAX];
+ char file_name_buf[_TINYDIR_FILENAME_MAX];
+ char *dir_name;
+ char *base_name;
+#ifdef _MSC_VER
+ char drive_buf[_TINYDIR_PATH_MAX];
+ char ext_buf[_TINYDIR_FILENAME_MAX];
+#endif
+
+ if (file == NULL || path == NULL || strlen(path) == 0)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ if (strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
+ {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ /* Get the parent path */
+#ifdef _MSC_VER
+ if (_splitpath_s(
+ path,
+ drive_buf, sizeof drive_buf,
+ dir_name_buf, sizeof dir_name_buf,
+ file_name_buf, sizeof file_name_buf,
+ ext_buf, sizeof ext_buf))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ /* Concatenate the drive letter and dir name to form full dir name */
+ strcat(drive_buf, dir_name_buf);
+ dir_name = drive_buf;
+ /* Concatenate the file name and extension to form base name */
+ strcat(file_name_buf, ext_buf);
+ base_name = file_name_buf;
+#else
+ strcpy(dir_name_buf, path);
+ dir_name = dirname(dir_name_buf);
+ strcpy(file_name_buf, path);
+ base_name = basename(file_name_buf);
+#endif
+
+ /* Open the parent directory */
+ if (tinydir_open(&dir, dir_name) == -1)
+ {
+ return -1;
+ }
+
+ /* Read through the parent directory and look for the file */
+ while (dir.has_next)
+ {
+ if (tinydir_readfile(&dir, file) == -1)
+ {
+ result = -1;
+ goto bail;
+ }
+ if (strcmp(file->name, base_name) == 0)
+ {
+ /* File found */
+ found = 1;
+ goto bail;
+ }
+ tinydir_next(&dir);
+ }
+ if (!found)
+ {
+ result = -1;
+ errno = ENOENT;
+ }
+
+bail:
+ tinydir_close(&dir);
+ return result;
+}
+
+_TINYDIR_FUNC
+void _tinydir_get_ext(tinydir_file *file)
+{
+ char *period = strrchr(file->name, '.');
+ if (period == NULL)
+ {
+ file->extension = &(file->name[strlen(file->name)]);
+ }
+ else
+ {
+ file->extension = period + 1;
+ }
+}
+
+_TINYDIR_FUNC
+int _tinydir_file_cmp(const void *a, const void *b)
+{
+ const tinydir_file *fa = (const tinydir_file *)a;
+ const tinydir_file *fb = (const tinydir_file *)b;
+ if (fa->is_dir != fb->is_dir)
+ {
+ return -(fa->is_dir - fb->is_dir);
+ }
+ return strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX);
+}
+
+#endif
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index a52bc7b..416f8d1 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -6,7 +6,7 @@ SET(BEMENU_SOURCE
util.c
filter.c
library.c
- draw/curses.c
+ 3rdparty/cdl.c
)
# Configure
@@ -29,6 +29,9 @@ ENDIF ()
STRING(REGEX MATCHALL "[0-9]+" VERSION_COMPONENTS ${BEMENU_VERSION})
LIST(GET VERSION_COMPONENTS 0 SOVERSION)
+# Compile renderer plugins
+ADD_SUBDIRECTORY(renderers)
+
# Compile
INCLUDE_DIRECTORIES(${BEMENU_INCLUDE} ${CMAKE_CURRENT_BINARY_DIR})
ADD_LIBRARY(bemenu SHARED ${BEMENU_SOURCE})
diff --git a/lib/bemenu.h b/lib/bemenu.h
index 5457cca..a58dcb3 100644
--- a/lib/bemenu.h
+++ b/lib/bemenu.h
@@ -4,8 +4,12 @@
* Public API header.
*/
-typedef struct _bmMenu bmMenu;
-typedef struct _bmItem bmItem;
+struct bm_renderer;
+struct bm_menu;
+struct bm_item;
+
+#include <stdbool.h>
+#include <stdint.h>
/**
* @defgroup Library
@@ -33,6 +37,28 @@ typedef struct _bmItem bmItem;
* @{ */
/**
+ * @name Library Initialization
+ * @{ */
+
+/**
+ * Init bemenu.
+ * Loads up the renderers.
+ *
+ * @return true on success, false on failure.
+ */
+bool bm_init(void);
+
+/**
+ * Get list of available renderers.
+ *
+ * @param out_nmemb Reference to uint32_t where total count of returned renderers will be stored.
+ * @return Pointer to array of bm_renderer instances.
+ */
+const struct bm_renderer** bm_get_renderers(uint32_t *out_nmemb);
+
+/** @} Library Initialization */
+
+/**
* @name Library Version
* @{ */
@@ -43,59 +69,62 @@ typedef struct _bmItem bmItem;
*
* @return Null terminated C "string" to version string.
*/
-const char* bmVersion(void);
+const char* bm_version(void);
/** @} Library Version */
/** @} Library */
/**
- * @addtogroup Menu
+ * @addtogroup Renderer
* @{ */
/**
- * Draw mode constants for bmMenu instance draw mode.
+ * Get name of the renderer.
*
- * @link ::bmDrawMode BM_DRAW_MODE_LAST @endlink is provided for enumerating draw modes.
- * Instancing with it however provides exactly same functionality as BM_DRAW_MODE_NONE.
+ * @param renderer bm_renderer instance.
+ * @return Null terminated C "string" to renderer's name.
*/
-typedef enum bmDrawMode {
- BM_DRAW_MODE_NONE,
- BM_DRAW_MODE_CURSES,
- BM_DRAW_MODE_LAST
-} bmDrawMode;
+const char* bm_renderer_get_name(const struct bm_renderer *renderer);
+
+/**
+ * @} Renderer */
+
+/**
+ * @addtogroup Menu
+ * @{ */
/**
- * Filter mode constants for bmMenu instance filter mode.
+ * Filter mode constants for bm_menu instance filter mode.
*
- * @link ::bmFilterMode BM_FILTER_MODE_LAST @endlink is provided for enumerating filter modes.
+ * @link ::bm_filter_mode BM_FILTER_MODE_LAST @endlink is provided for enumerating filter modes.
* Using it as filter mode however provides exactly same functionality as BM_FILTER_MODE_DMENU.
*/
-typedef enum bmFilterMode {
+enum bm_filter_mode {
BM_FILTER_MODE_DMENU,
BM_FILTER_MODE_DMENU_CASE_INSENSITIVE,
BM_FILTER_MODE_LAST
-} bmFilterMode;
+};
/**
- * Result constants from bmMenuRunWithKey function.
+ * Result constants from bm_menu_run_with_key function.
*
- * - @link ::bmRunResult BM_RUN_RESULT_RUNNING @endlink means that menu is running and thus should be still renderer && ran.
- * - @link ::bmRunResult BM_RUN_RESULT_SELECTED @endlink means that menu was closed and items were selected.
- * - @link ::bmRunResult BM_RUN_RESULT_CANCEL @endlink means that menu was closed and selection was canceled.
+ * - @link ::bm_run_result BM_RUN_RESULT_RUNNING @endlink means that menu is running and thus should be still renderer && ran.
+ * - @link ::bm_run_result BM_RUN_RESULT_SELECTED @endlink means that menu was closed and items were selected.
+ * - @link ::bm_run_result BM_RUN_RESULT_CANCEL @endlink means that menu was closed and selection was canceled.
*/
-typedef enum bmRunResult {
+enum bm_run_result {
BM_RUN_RESULT_RUNNING,
BM_RUN_RESULT_SELECTED,
BM_RUN_RESULT_CANCEL,
-} bmRunResult;
+};
/**
* Key constants.
*
- * @link ::bmKey BM_KEY_LAST @endlink is provided for enumerating keys.
+ * @link ::bm_key BM_KEY_LAST @endlink is provided for enumerating keys.
*/
-typedef enum bmKey {
+enum bm_key {
BM_KEY_NONE,
BM_KEY_UP,
BM_KEY_DOWN,
@@ -119,33 +148,33 @@ typedef enum bmKey {
BM_KEY_CONTROL_RETURN,
BM_KEY_UNICODE,
BM_KEY_LAST
-} bmKey;
+};
/**
* @name Menu Memory
* @{ */
/**
- * Create new bmMenu instance.
+ * Create new bm_menu instance.
*
- * @param drawMode Render method to be used for this menu instance.
- * @return bmMenu for new menu instance, **NULL** if creation failed.
+ * @param renderer Name of renderer to be used for this instance, pass **NULL** for auto-detection.
+ * @return bm_menu for new menu instance, **NULL** if creation failed.
*/
-bmMenu* bmMenuNew(bmDrawMode drawMode);
+struct bm_menu* bm_menu_new(const char *renderer);
/**
- * Release bmMenu instance.
+ * Release bm_menu instance.
*
- * @param menu bmMenu instance to be freed from memory.
+ * @param menu bm_menu instance to be freed from memory.
*/
-void bmMenuFree(bmMenu *menu);
+void bm_menu_free(struct bm_menu *menu);
/**
- * Release items inside bmMenu instance.
+ * Release items inside bm_menu instance.
*
- * @param menu bmMenu instance which items will be freed from memory.
+ * @param menu bm_menu instance which items will be freed from memory.
*/
-void bmMenuFreeItems(bmMenu *menu);
+void bm_menu_free_items(struct bm_menu *menu);
/** @} Menu Memory */
@@ -154,85 +183,86 @@ void bmMenuFreeItems(bmMenu *menu);
* @{ */
/**
- * Set userdata pointer to bmMenu instance.
+ * Set userdata pointer to bm_menu instance.
* Userdata will be carried unmodified by the instance.
*
- * @param menu bmMenu instance where to set userdata pointer.
+ * @param menu bm_menu instance where to set userdata pointer.
* @param userdata Pointer to userdata.
*/
-void bmMenuSetUserdata(bmMenu *menu, void *userdata);
+void bm_menu_set_userdata(struct bm_menu *menu, void *userdata);
/**
- * Get userdata pointer from bmMenu instance.
+ * Get userdata pointer from bm_menu instance.
*
- * @param menu bmMenu instance which userdata pointer to get.
+ * @param menu bm_menu instance which userdata pointer to get.
* @return Pointer for unmodified userdata.
*/
-void* bmMenuGetUserdata(bmMenu *menu);
+void* bm_menu_get_userdata(struct bm_menu *menu);
/**
- * Set filter text to bmMenu instance.
+ * Set filter text to bm_menu instance.
*
- * @param menu bmMenu instance where to set filter.
+ * @param menu bm_menu instance where to set filter.
* @param filter Null terminated C "string" to act as filter.
*/
-void bmMenuSetFilter(bmMenu *menu, const char *filter);
+void bm_menu_set_filter(struct bm_menu *menu, const char *filter);
/**
- * Get filter text from bmMenu instance.
+ * Get filter text from bm_menu instance.
*
- * @param menu bmMenu instance where to get filter.
+ * @param menu bm_menu instance where to get filter.
* @return Const pointer to current filter text, may be **NULL** if empty.
*/
-const char* bmMenuGetFilter(bmMenu *menu);
+const char* bm_menu_get_filter(struct bm_menu *menu);
/**
- * Set active filter mode to bmMenu instance.
+ * Set active filter mode to bm_menu instance.
*
- * @param menu bmMenu instance where to set filter mode.
- * @param mode bmFilterMode constant.
+ * @param menu bm_menu instance where to set filter mode.
+ * @param mode bm_filter_mode constant.
*/
-void bmMenuSetFilterMode(bmMenu *menu, bmFilterMode mode);
+void bm_menu_set_filter_mode(struct bm_menu *menu, enum bm_filter_mode mode);
/**
- * Get active filter mode from bmMenu instance.
+ * Get active filter mode from bm_menu instance.
*
- * @param menu bmMenu instance where to get filter mode.
- * @return bmFilterMode constant.
+ * @param menu bm_menu instance where to get filter mode.
+ * @return bm_filter_mode constant.
*/
-bmFilterMode bmMenuGetFilterMode(const bmMenu *menu);
+enum bm_filter_mode bm_menu_get_filter_mode(const struct bm_menu *menu);
/**
* Set selection wrapping on/off.
*
- * @param menu bmMenu instance where to toggle selection wrapping.
- * @param int 1 == on, 0 == off.
+ * @param menu bm_menu instance where to toggle selection wrapping.
+ * @param bool true/false.
*/
-void bmMenuSetWrap(bmMenu *menu, int wrap);
+void bm_menu_set_wrap(struct bm_menu *menu, bool wrap);
/**
* Get selection wrapping state.
*
- * @param menu bmMenu instance where to get selection wrapping state.
+ * @param menu bm_menu instance where to get selection wrapping state.
* @return int for wrap state.
*/
-int bmMenuGetWrap(const bmMenu *menu);
+bool bm_menu_get_wrap(const struct bm_menu *menu);
/**
- * Set title to bmMenu instance.
+ * Set title to bm_menu instance.
*
- * @param menu bmMenu instance where to set title.
+ * @param menu bm_menu instance where to set title.
* @param title C "string" to set as title, can be **NULL** for empty title.
+ * @return true if set was succesful, false if out of memory.
*/
-int bmMenuSetTitle(bmMenu *menu, const char *title);
+bool bm_menu_set_title(struct bm_menu *menu, const char *title);
/**
- * Get title from bmMenu instance.
+ * Get title from bm_menu instance.
*
- * @param menu bmMenu instance where to get title from.
+ * @param menu bm_menu instance where to get title from.
* @return Pointer to null terminated C "string", can be **NULL** for empty title.
*/
-const char* bmMenuGetTitle(const bmMenu *menu);
+const char* bm_menu_get_title(const struct bm_menu *menu);
/** @} Properties */
@@ -241,130 +271,130 @@ const char* bmMenuGetTitle(const bmMenu *menu);
* @{ */
/**
- * Add item to bmMenu instance at specific index.
+ * Add item to bm_menu instance at specific index.
*
- * @param menu bmMenu instance where item will be added.
- * @param item bmItem instance to add.
+ * @param menu bm_menu instance where item will be added.
+ * @param item bm_item instance to add.
* @param index Index where item will be added.
- * @return 1 on successful add, 0 on failure.
+ * @return true on successful add, false on failure.
*/
-int bmMenuAddItemAt(bmMenu *menu, bmItem *item, unsigned int index);
+bool bm_menu_add_item_at(struct bm_menu *menu, struct bm_item *item, uint32_t index);
/**
- * Add item to bmMenu instance.
+ * Add item to bm_menu instance.
*
- * @param menu bmMenu instance where item will be added.
- * @param item bmItem instance to add.
- * @return 1 on successful add, 0 on failure.
+ * @param menu bm_menu instance where item will be added.
+ * @param item bm_item instance to add.
+ * @return true on successful add, false on failure.
*/
-int bmMenuAddItem(bmMenu *menu, bmItem *item);
+bool bm_menu_add_item(struct bm_menu *menu, struct bm_item *item);
/**
- * Remove item from bmMenu instance at specific index.
+ * Remove item from bm_menu instance at specific index.
*
- * @warning The item won't be freed, use bmItemFree to do that.
+ * @warning The item won't be freed, use bm_item_free to do that.
*
- * @param menu bmMenu instance from where item will be removed.
+ * @param menu bm_menu instance from where item will be removed.
* @param index Index of item to remove.
- * @return 1 on successful add, 0 on failure.
+ * @return true on successful add, false on failure.
*/
-int bmMenuRemoveItemAt(bmMenu *menu, unsigned int index);
+bool bm_menu_remove_item_at(struct bm_menu *menu, uint32_t index);
/**
- * Remove item from bmMenu instance.
+ * Remove item from bm_menu instance.
*
- * @warning The item won't be freed, use bmItemFree to do that.
+ * @warning The item won't be freed, use bm_item_free to do that.
*
- * @param menu bmMenu instance from where item will be removed.
- * @param item bmItem instance to remove.
- * @return 1 on successful add, 0 on failure.
+ * @param menu bm_menu instance from where item will be removed.
+ * @param item bm_item instance to remove.
+ * @return true on successful add, false on failure.
*/
-int bmMenuRemoveItem(bmMenu *menu, bmItem *item);
+bool bm_menu_remove_item(struct bm_menu *menu, struct bm_item *item);
/**
* Highlight item in menu by index.
*
- * @param menu bmMenu instance from where to highlight item.
+ * @param menu bm_menu instance from where to highlight item.
* @param index Index of item to highlight.
- * @return 1 on successful highlight, 0 on failure.
+ * @return true on successful highlight, false on failure.
*/
-int bmMenuSetHighlightedIndex(bmMenu *menu, unsigned int index);
+bool bm_menu_set_highlighted_index(struct bm_menu *menu, uint32_t index);
/**
* Highlight item in menu.
*
- * @param menu bmMenu instance from where to highlight item.
- * @param item bmItem instance to highlight.
- * @return 1 on successful highlight, 0 on failure.
+ * @param menu bm_menu instance from where to highlight item.
+ * @param item bm_item instance to highlight.
+ * @return true on successful highlight, false on failure.
*/
-int bmMenuSetHighlighted(bmMenu *menu, bmItem *item);
+bool bm_menu_set_highlighted_item(struct bm_menu *menu, struct bm_item *item);
/**
- * Get highlighted item from bmMenu instance.
+ * Get highlighted item from bm_menu instance.
*
* @warning The pointer returned by this function may be invalid after items change.
*
- * @param menu bmMenu instance from where to get highlighted item.
- * @return Selected bmItem instance, **NULL** if none highlighted.
+ * @param menu bm_menu instance from where to get highlighted item.
+ * @return Selected bm_item instance, **NULL** if none highlighted.
*/
-bmItem* bmMenuGetHighlightedItem(const bmMenu *menu);
+struct bm_item* bm_menu_get_highlighted_item(const struct bm_menu *menu);
/**
- * Set selected items to bmMenu instance.
+ * Set selected items to bm_menu instance.
*
- * @param menu bmMenu instance where items will be set.
- * @param items Array of bmItem pointers to set.
+ * @param menu bm_menu instance where items will be set.
+ * @param items Array of bm_item pointers to set.
* @param nmemb Total count of items in array.
- * @return 1 on successful set, 0 on failure.
+ * @return true on successful set, false on failure.
*/
-int bmMenuSetSelectedItems(bmMenu *menu, bmItem **items, unsigned int nmemb);
+bool bm_menu_set_selected_items(struct bm_menu *menu, struct bm_item **items, uint32_t nmemb);
/**
- * Get selected items from bmMenu instance.
+ * Get selected items from bm_menu instance.
*
* @warning The pointer returned by this function may be invalid after selection or items change.
*
- * @param menu bmMenu instance from where to get selected items.
- * @param outNmemb Reference to unsigned int where total count of returned items will be stored.
- * @return Pointer to array of bmItem pointers.
+ * @param menu bm_menu instance from where to get selected items.
+ * @param out_nmemb Reference to uint32_t where total count of returned items will be stored.
+ * @return Pointer to array of bm_item pointers.
*/
-bmItem** bmMenuGetSelectedItems(const bmMenu *menu, unsigned int *outNmemb);
+struct bm_item** bm_menu_get_selected_items(const struct bm_menu *menu, uint32_t *out_nmemb);
/**
- * Set items to bmMenu instance.
- * Will replace all the old items on bmMenu instance.
+ * Set items to bm_menu instance.
+ * Will replace all the old items on bm_menu instance.
*
* If items is **NULL**, or nmemb is zero, all items will be freed from the menu.
*
- * @param menu bmMenu instance where items will be set.
- * @param items Array of bmItem pointers to set.
+ * @param menu bm_menu instance where items will be set.
+ * @param items Array of bm_item pointers to set.
* @param nmemb Total count of items in array.
- * @return 1 on successful set, 0 on failure.
+ * @return true on successful set, false on failure.
*/
-int bmMenuSetItems(bmMenu *menu, const bmItem **items, unsigned int nmemb);
+bool bm_menu_set_items(struct bm_menu *menu, const struct bm_item **items, uint32_t nmemb);
/**
- * Get items from bmMenu instance.
+ * Get items from bm_menu instance.
*
* @warning The pointer returned by this function may be invalid after removing or adding new items.
*
- * @param menu bmMenu instance from where to get items.
- * @param outNmemb Reference to unsigned int where total count of returned items will be stored.
- * @return Pointer to array of bmItem pointers.
+ * @param menu bm_menu instance from where to get items.
+ * @param out_nmemb Reference to uint32_t where total count of returned items will be stored.
+ * @return Pointer to array of bm_item pointers.
*/
-bmItem** bmMenuGetItems(const bmMenu *menu, unsigned int *outNmemb);
+struct bm_item** bm_menu_get_items(const struct bm_menu *menu, uint32_t *out_nmemb);
/**
- * Get filtered (displayed) items from bmMenu instance.
+ * Get filtered (displayed) items from bm_menu instance.
*
* @warning The pointer returned by this function _will_ be invalid when menu internally filters its list again.
* Do not store this pointer.
*
- * @param menu bmMenu instance from where to get filtered items.
- * @param outNmemb Reference to unsigned int where total count of returned items will be stored.
- * @return Pointer to array of bmItem pointers.
+ * @param menu bm_menu instance from where to get filtered items.
+ * @param out_nmemb Reference to uint32_t where total count of returned items will be stored.
+ * @return Pointer to array of bm_item pointers.
*/
-bmItem** bmMenuGetFilteredItems(const bmMenu *menu, unsigned int *outNmemb);
+struct bm_item** bm_menu_get_filtered_items(const struct bm_menu *menu, uint32_t *out_nmemb);
/** @} Menu Items */
@@ -373,11 +403,11 @@ bmItem** bmMenuGetFilteredItems(const bmMenu *menu, unsigned int *outNmemb);
* @{ */
/**
- * Render bmMenu instance using chosen draw method.
+ * Render bm_menu instance using chosen renderer.
*
- * @param menu bmMenu instance to be rendered.
+ * @param menu bm_menu instance to be rendered.
*/
-void bmMenuRender(const bmMenu *menu);
+void bm_menu_render(const struct bm_menu *menu);
/**
* Trigger filtering of menu manually.
@@ -386,30 +416,30 @@ void bmMenuRender(const bmMenu *menu);
* Do note that filtering might be heavy, so you should only call it after batch manipulation of items.
* Not after manipulation of each single item.
*
- * @param menu bmMenu instance which to filter.
+ * @param menu bm_menu instance which to filter.
*/
-void bmMenuFilter(bmMenu *menu);
+void bm_menu_filter(struct bm_menu *menu);
/**
* Poll key and unicode from underlying UI toolkit.
*
- * This function will block on @link ::bmDrawMode BM_DRAW_MODE_CURSES @endlink draw mode.
+ * This function will block on **curses** renderer.
*
- * @param menu bmMenu instance from which to poll.
- * @param outUnicode Reference to unsigned int.
- * @return bmKey for polled key.
+ * @param menu bm_menu instance from which to poll.
+ * @param out_unicode Reference to uint32_t.
+ * @return bm_key for polled key.
*/
-bmKey bmMenuGetKey(bmMenu *menu, unsigned int *outUnicode);
+enum bm_key bm_menu_poll_key(struct bm_menu *menu, uint32_t *out_unicode);
/**
* Advances menu logic with key and unicode as input.
*
- * @param menu bmMenu instance to be advanced.
+ * @param menu bm_menu instance to be advanced.
* @param key Key input that will advance menu logic.
* @param unicode Unicode input that will advance menu logic.
- * @return bmRunResult for menu state.
+ * @return bm_run_result for menu state.
*/
-bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode);
+enum bm_run_result bm_menu_run_with_key(struct bm_menu *menu, enum bm_key key, uint32_t unicode);
/** @} Menu Logic */
@@ -427,16 +457,16 @@ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode);
* Allocate a new item.
*
* @param text Pointer to null terminated C "string", can be **NULL** for empty text.
- * @return bmItem for new item instance, **NULL** if creation failed.
+ * @return bm_item for new item instance, **NULL** if creation failed.
*/
-bmItem* bmItemNew(const char *text);
+struct bm_item* bm_item_new(const char *text);
/**
- * Release bmItem instance.
+ * Release bm_item instance.
*
- * @param item bmItem instance to be freed from memory.
+ * @param item bm_item instance to be freed from memory.
*/
-void bmItemFree(bmItem *item);
+void bm_item_free(struct bm_item *item);
/** @} Item Memory */
@@ -445,37 +475,38 @@ void bmItemFree(bmItem *item);
* @{ */
/**
- * Set userdata pointer to bmItem instance.
+ * Set userdata pointer to bm_item instance.
* Userdata will be carried unmodified by the instance.
*
- * @param item bmItem instance where to set userdata pointer.
+ * @param item bm_item instance where to set userdata pointer.
* @param userdata Pointer to userdata.
*/
-void bmItemSetUserdata(bmItem *item, void *userdata);
+void bm_item_set_userdata(struct bm_item *item, void *userdata);
/**
- * Get userdata pointer from bmItem instance.
+ * Get userdata pointer from bm_item instance.
*
- * @param item bmItem instance which userdata pointer to get.
+ * @param item bm_item instance which userdata pointer to get.
* @return Pointer for unmodified userdata.
*/
-void* bmItemGetUserdata(bmItem *item);
+void* bm_item_get_userdata(struct bm_item *item);
/**
- * Set text to bmItem instance.
+ * Set text to bm_item instance.
*
- * @param item bmItem instance where to set text.
+ * @param item bm_item instance where to set text.
* @param text C "string" to set as text, can be **NULL** for empty text.
+ * @return true if set was succesful, false if out of memory.
*/
-int bmItemSetText(bmItem *item, const char *text);
+bool bm_item_set_text(struct bm_item *item, const char *text);
/**
- * Get text from bmItem instance.
+ * Get text from bm_item instance.
*
- * @param item bmItem instance where to get text from.
+ * @param item bm_item instance where to get text from.
* @return Pointer to null terminated C "string", can be **NULL** for empty text.
*/
-const char* bmItemGetText(const bmItem *item);
+const char* bm_item_get_text(const struct bm_item *item);
/** @} Item Properties */
diff --git a/lib/draw/curses.c b/lib/draw/curses.c
deleted file mode 100644
index a1f23ef..0000000
--- a/lib/draw/curses.c
+++ /dev/null
@@ -1,498 +0,0 @@
-#include "../internal.h"
-
-#if __APPLE__
-# define _C99_SOURCE
-# include <stdio.h> /* vsnprintf */
-# undef _C99_SOURCE
-#endif
-
-#define _XOPEN_SOURCE 500
-#include <signal.h> /* sigaction */
-#include <stdarg.h> /* vsnprintf */
-#undef _XOPEN_SOURCE
-
-#include <wchar.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <locale.h>
-#include <ncurses.h>
-#include <dlfcn.h>
-#include <assert.h>
-
-#if _WIN32
-static const char *TTY = "CON";
-#else
-static const char *TTY = "/dev/tty";
-#endif
-
-#if __APPLE__
- const char *DL_PATH[] = {
- "libncursesw.5.dylib",
- "libncurses.5.dylib",
- NULL
- };
-#elif _WIN32
-# error FIXME: Compile with windows... or use relative path?
-#else
- const char *DL_PATH[] = {
- "libncursesw.so.5",
- "libncurses.so.5",
- NULL
- };
-#endif
-
-/* these are implemented as macros in older curses */
-#ifndef NCURSES_OPAQUE
-static int wrap_getmaxx(WINDOW *win) { return getmaxx(win); }
-static int wrap_getmaxy(WINDOW *win) { return getmaxy(win); }
-#endif
-
-/* ncurses.h likes to define stuff for us.
- * This unforunately mangles with our struct. */
-#undef erase
-#undef getch
-#undef get_wch
-#undef refresh
-#undef mvprintw
-#undef move
-#undef init_pair
-#undef attroff
-#undef attron
-#undef getmaxx
-#undef getmaxy
-
-/**
- * Dynamically loaded curses API.
- */
-static struct curses {
- struct sigaction abrtAction;
- struct sigaction segvAction;
- struct sigaction winchAction;
- void *handle;
- WINDOW *stdscr;
- WINDOW* (*initscr)(void);
- int (*endwin)(void);
- int (*refresh)(void);
- int (*erase)(void);
- int (*getch)(void);
- int (*get_wch)(wint_t *wch);
- int (*mvprintw)(int x, int y, const char *fmt, ...);
- int (*move)(int x, int y);
- int (*init_pair)(short color, short f, short b);
- int (*attroff)(int attrs);
- int (*attron)(int attrs);
- int (*start_color)(void);
- int (*use_default_colors)(void);
- int (*getmaxx)(WINDOW *win);
- int (*getmaxy)(WINDOW *win);
- int (*keypad)(WINDOW *win, bool bf);
- int (*curs_set)(int visibility);
- int (*flushinp)(void);
- int (*noecho)(void);
- int (*raw)(void);
- int *ESCDELAY;
- int oldStdin;
- int oldStdout;
-} curses;
-
-static int _bmDrawCursesResizeBuffer(char **buffer, size_t *osize, size_t nsize)
-{
- assert(buffer);
- assert(osize);
-
- if (nsize == 0 || nsize <= *osize)
- return 0;
-
- void *tmp;
- if (!*buffer || !(tmp = realloc(*buffer, nsize))) {
- if (!(tmp = malloc(nsize)))
- return 0;
-
- if (*buffer) {
- memcpy(tmp, *buffer, *osize);
- free(*buffer);
- }
- }
-
- *buffer = tmp;
- *osize = nsize;
- return 1;
-}
-
-#if __GNUC__
-__attribute__((format(printf, 3, 4)))
-#endif
-static void _bmDrawCursesDrawLine(int pair, int y, const char *format, ...)
-{
- static size_t blen = 0;
- static char *buffer = NULL;
-
- size_t ncols = curses.getmaxx(curses.stdscr);
- if (ncols <= 0)
- return;
-
- va_list args;
- va_start(args, format);
- size_t nlen = vsnprintf(NULL, 0, format, args);
- va_end(args);
-
- if ((!buffer || nlen > blen) && !_bmDrawCursesResizeBuffer(&buffer, &blen, nlen + 1))
- return;
-
- va_start(args, format);
- vsnprintf(buffer, blen - 1, format, args);
- va_end(args);
-
- size_t dw = 0, i = 0;
- while (dw < ncols && i < nlen) {
- if (buffer[i] == '\t') buffer[i] = ' ';
- int next = _bmUtf8RuneNext(buffer, i);
- dw += _bmUtf8RuneWidth(buffer + i, next);
- i += (next ? next : 1);
- }
-
- if (dw < ncols) {
- /* line is too short, widen it */
- size_t offset = i + (ncols - dw);
- if (blen <= offset && !_bmDrawCursesResizeBuffer(&buffer, &blen, offset + 1))
- return;
-
- memset(buffer + nlen, ' ', offset - nlen);
- buffer[offset] = 0;
- } else if (i < blen) {
- /* line is too long, shorten it */
- i -= _bmUtf8RunePrev(buffer, i - (dw - ncols)) - 1;
- size_t cc = dw - (dw - ncols);
-
- size_t offset = i - (dw - ncols) + (ncols - cc) + 1;
- if (blen <= offset) {
- int diff = offset - blen + 1;
- if (!_bmDrawCursesResizeBuffer(&buffer, &blen, blen + diff))
- return;
- }
-
- memset(buffer + i - (dw - ncols), ' ', (ncols - cc) + 1);
- buffer[offset] = 0;
- }
-
- if (pair > 0)
- curses.attron(COLOR_PAIR(pair));
-
- curses.mvprintw(y, 0, "%s", buffer);
-
- if (pair > 0)
- curses.attroff(COLOR_PAIR(pair));
-}
-
-static void _bmDrawCursesRender(const bmMenu *menu)
-{
- if (!curses.stdscr) {
- curses.oldStdin = dup(STDIN_FILENO);
- curses.oldStdout = dup(STDOUT_FILENO);
-
- freopen(TTY, "w", stdout);
- freopen(TTY, "r", stdin);
-
- setlocale(LC_CTYPE, "");
-
- if ((curses.stdscr = curses.initscr()) == NULL)
- return;
-
- *curses.ESCDELAY = 25;
- curses.flushinp();
- curses.keypad(curses.stdscr, true);
- curses.curs_set(1);
- curses.noecho();
- curses.raw();
-
- curses.start_color();
- curses.use_default_colors();
- curses.init_pair(1, COLOR_BLACK, COLOR_RED);
- curses.init_pair(2, COLOR_RED, -1);
- }
-
- const unsigned int lines = curses.getmaxy(curses.stdscr);
- curses.erase();
-
- unsigned int ncols = curses.getmaxx(curses.stdscr);
- unsigned int titleLen = (menu->title ? strlen(menu->title) + 1 : 0);
-
- if (titleLen >= ncols)
- titleLen = 0;
-
- unsigned int ccols = ncols - titleLen - 1;
- unsigned int dcols = 0, doffset = menu->cursor;
-
- while (doffset > 0 && dcols < ccols) {
- int prev = _bmUtf8RunePrev(menu->filter, doffset);
- dcols += _bmUtf8RuneWidth(menu->filter + doffset - prev, prev);
- doffset -= (prev ? prev : 1);
- }
-
- _bmDrawCursesDrawLine(0, 0, "%*s%s", titleLen, "", (menu->filter ? menu->filter + doffset : ""));
-
- if (menu->title && titleLen > 0) {
- curses.attron(COLOR_PAIR(1));
- curses.mvprintw(0, 0, menu->title);
- curses.attroff(COLOR_PAIR(1));
- }
-
- unsigned int i, cl = 1;
- unsigned int itemsCount;
- bmItem **items = bmMenuGetFilteredItems(menu, &itemsCount);
- for (i = (menu->index / (lines - 1)) * (lines - 1); i < itemsCount && cl < lines; ++i) {
- int highlighted = (items[i] == bmMenuGetHighlightedItem(menu));
- int color = (highlighted ? 2 : (_bmMenuItemIsSelected(menu, items[i]) ? 1 : 0));
- _bmDrawCursesDrawLine(color, cl++, "%s%s", (highlighted ? ">> " : " "), (items[i]->text ? items[i]->text : ""));
- }
-
- curses.move(0, titleLen + (menu->cursesCursor < ccols ? menu->cursesCursor : ccols));
- curses.refresh();
-}
-
-static unsigned int _bmDrawCursesDisplayedCount(const bmMenu *menu)
-{
- (void)menu;
- return (curses.stdscr ? curses.getmaxy(curses.stdscr) : 0);
-}
-
-static void _bmDrawCursesEndWin(void)
-{
- if (!curses.stdscr)
- return;
-
- freopen(TTY, "w", stdout);
-
- if (curses.refresh)
- curses.refresh();
-
- if (curses.endwin)
- curses.endwin();
-
- dup2(curses.oldStdin, STDIN_FILENO);
- dup2(curses.oldStdout, STDOUT_FILENO);
- close(curses.oldStdin);
- close(curses.oldStdout);
-
- curses.stdscr = NULL;
-}
-
-static bmKey _bmDrawCursesGetKey(unsigned int *unicode)
-{
- assert(unicode);
- *unicode = 0;
-
- if (!curses.stdscr)
- return BM_KEY_NONE;
-
- if (curses.get_wch)
- curses.get_wch((wint_t*)unicode);
- else if (curses.getch)
- *unicode = curses.getch();
-
- switch (*unicode) {
-#if KEY_RESIZE
- case KEY_RESIZE:
- return BM_KEY_NONE;
-#endif
-
- case 16: /* C-p */
- case KEY_UP:
- return BM_KEY_UP;
-
- case 14: /* C-n */
- case KEY_DOWN:
- return BM_KEY_DOWN;
-
- case 2: /* C-b */
- case KEY_LEFT:
- return BM_KEY_LEFT;
-
- case 6: /* C-f */
- case KEY_RIGHT:
- return BM_KEY_RIGHT;
-
- case 1: /* C-a */
- case 391: /* S-Home */
- case KEY_HOME:
- return BM_KEY_HOME;
-
- case 5: /* C-e */
- case 386: /* S-End */
- case KEY_END:
- return BM_KEY_END;
-
- case KEY_PPAGE: /* Page up */
- return BM_KEY_PAGE_UP;
-
- case KEY_NPAGE: /* Page down */
- return BM_KEY_PAGE_DOWN;
-
- case 550: /* C-Page up */
- case 398: /* S-Page up */
- return BM_KEY_SHIFT_PAGE_UP;
-
- case 545: /* C-Page down */
- case 396: /* S-Page down */
- return BM_KEY_SHIFT_PAGE_DOWN;
-
- case 8: /* C-h */
- case 127: /* Delete */
- case KEY_BACKSPACE:
- return BM_KEY_BACKSPACE;
-
- case 4: /* C-d */
- case KEY_DC:
- return BM_KEY_DELETE;
-
- case 383: /* S-Del */
- case 21: /* C-u */
- return BM_KEY_LINE_DELETE_LEFT;
-
- case 11: /* C-k */
- return BM_KEY_LINE_DELETE_RIGHT;
-
- case 23: /* C-w */
- return BM_KEY_WORD_DELETE;
-
- case 9: /* Tab */
- return BM_KEY_TAB;
-
- case 18: /* C-r */
- return BM_KEY_CONTROL_RETURN;
-
- case 20: /* C-t */
- case 331: /* Insert */
- _bmDrawCursesEndWin();
- return BM_KEY_SHIFT_RETURN;
-
- case 10: /* Return */
- _bmDrawCursesEndWin();
- return BM_KEY_RETURN;
-
- case 7: /* C-g */
- case 27: /* Escape */
- _bmDrawCursesEndWin();
- return BM_KEY_ESCAPE;
-
- default: break;
- }
-
- return BM_KEY_UNICODE;
-}
-
-static void _bmDrawCursesFree(void)
-{
- _bmDrawCursesEndWin();
-
- if (curses.handle)
- dlclose(curses.handle);
-
- sigaction(SIGABRT, &curses.abrtAction, NULL);
- sigaction(SIGSEGV, &curses.segvAction, NULL);
- sigaction(SIGWINCH, &curses.winchAction, NULL);
- memset(&curses, 0, sizeof(curses));
-}
-
-static void _bmDrawCursesCrashHandler(int sig)
-{
- (void)sig;
- _bmDrawCursesFree();
-}
-
-static void _bmDrawCursesResizeHandler(int sig)
-{
- (void)sig;
- if (!curses.stdscr)
- return;
-
- curses.endwin();
- curses.refresh();
-}
-
-int _bmDrawCursesInit(struct _bmRenderApi *api)
-{
- memset(&curses, 0, sizeof(curses));
- const char *lib = NULL, *func = NULL;
-
- unsigned int i;
- for (i = 0; DL_PATH[i] && !curses.handle; ++i)
- curses.handle = dlopen((lib = DL_PATH[i]), RTLD_LAZY);
-
- if (!curses.handle)
- return 0;
-
-#define bmLoadFunction(x) (curses.x = dlsym(curses.handle, (func = #x)))
-
- if (!bmLoadFunction(initscr))
- goto function_pointer_exception;
- if (!bmLoadFunction(endwin))
- goto function_pointer_exception;
- if (!bmLoadFunction(refresh))
- goto function_pointer_exception;
- if (!bmLoadFunction(get_wch) && !bmLoadFunction(getch))
- goto function_pointer_exception;
- if (!bmLoadFunction(erase))
- goto function_pointer_exception;
- if (!bmLoadFunction(mvprintw))
- goto function_pointer_exception;
- if (!bmLoadFunction(move))
- goto function_pointer_exception;
- if (!bmLoadFunction(init_pair))
- goto function_pointer_exception;
- if (!bmLoadFunction(attroff))
- goto function_pointer_exception;
- if (!bmLoadFunction(attron))
- goto function_pointer_exception;
- if (!bmLoadFunction(start_color))
- goto function_pointer_exception;
- if (!bmLoadFunction(use_default_colors))
- goto function_pointer_exception;
- if (!bmLoadFunction(keypad))
- goto function_pointer_exception;
- if (!bmLoadFunction(curs_set))
- goto function_pointer_exception;
- if (!bmLoadFunction(flushinp))
- goto function_pointer_exception;
- if (!bmLoadFunction(noecho))
- goto function_pointer_exception;
- if (!bmLoadFunction(raw))
- goto function_pointer_exception;
- if (!bmLoadFunction(ESCDELAY))
- goto function_pointer_exception;
-
-#ifndef NCURSES_OPAQUE
- curses.getmaxx = wrap_getmaxx;
- curses.getmaxy = wrap_getmaxy;
-#else
- if (!bmLoadFunction(getmaxx))
- goto function_pointer_exception;
- if (!bmLoadFunction(getmaxy))
- goto function_pointer_exception;
-#endif
-
-#undef bmLoadFunction
-
- api->displayedCount = _bmDrawCursesDisplayedCount;
- api->getKey = _bmDrawCursesGetKey;
- api->render = _bmDrawCursesRender;
- api->free = _bmDrawCursesFree;
-
- struct sigaction action;
- memset(&action, 0, sizeof(struct sigaction));
- action.sa_handler = _bmDrawCursesCrashHandler;
- sigaction(SIGABRT, &action, &curses.abrtAction);
- sigaction(SIGSEGV, &action, &curses.segvAction);
-
- action.sa_handler = _bmDrawCursesResizeHandler;
- sigaction(SIGWINCH, &action, &curses.winchAction);
- return 1;
-
-function_pointer_exception:
- fprintf(stderr, "-!- Could not load function '%s' from '%s'\n", func, lib);
- _bmDrawCursesFree();
- return 0;
-}
-
-/* vim: set ts=8 sw=4 tw=0 :*/
diff --git a/lib/filter.c b/lib/filter.c
index 421fab1..605a740 100644
--- a/lib/filter.c
+++ b/lib/filter.c
@@ -4,54 +4,54 @@
#include <string.h>
/**
- * Shrink bmItem** list pointer.
+ * Shrink struct bm_item** list pointer.
*
* Useful helper function for filter functions.
*
- * @param list Pointer to pointer to list of bmItem pointers.
+ * @param in_out_list Pointer to pointer to list of bm_item pointers.
* @param osize Current size of the list.
* @param nsize New size the list will be shrinked to.
- * @return Pointer to list of bmItem pointers.
+ * @return Pointer to list of bm_item pointers.
*/
-static bmItem** _bmFilterShrinkList(bmItem ***inOutList, size_t osize, size_t nsize)
+static struct bm_item**
+shrink_list(struct bm_item ***in_out_list, size_t osize, size_t nsize)
{
- assert(inOutList);
+ assert(in_out_list);
if (nsize == 0) {
- free(*inOutList);
- return (*inOutList = NULL);
+ free(*in_out_list);
+ return (*in_out_list = NULL);
}
if (nsize >= osize)
- return *inOutList;
+ return *in_out_list;
- void *tmp = malloc(sizeof(bmItem*) * nsize);
+ void *tmp = malloc(sizeof(struct bm_item*) * nsize);
if (!tmp)
- return *inOutList;
+ return *in_out_list;
- memcpy(tmp, *inOutList, sizeof(bmItem*) * nsize);
- free(*inOutList);
- return (*inOutList = tmp);
+ memcpy(tmp, *in_out_list, sizeof(struct bm_item*) * nsize);
+ free(*in_out_list);
+ return (*in_out_list = tmp);
}
/**
* Text filter tokenizer helper.
*
- * @param menu bmMenu instance which filter to tokenize.
- * @param outTokv char pointer reference to list of tokens, this should be freed after use.
- * @param outTokc unsigned int reference to number of tokens.
+ * @param menu bm_menu instance which filter to tokenize.
+ * @param out_tokv char pointer reference to list of tokens, this should be freed after use.
+ * @param out_tokc uint32_t reference to number of tokens.
* @return Pointer to buffer that contains tokenized string, this should be freed after use.
*/
-static char* _bmFilterTokenize(bmMenu *menu, char ***outTokv, unsigned int *outTokc)
+static char*
+tokenize(struct bm_menu *menu, char ***out_tokv, uint32_t *out_tokc)
{
- assert(menu);
- assert(outTokv);
- assert(outTokc);
- *outTokv = NULL;
- *outTokc = 0;
+ assert(menu && out_tokv && out_tokc);
+ *out_tokv = NULL;
+ *out_tokc = 0;
char **tokv = NULL, *buffer = NULL;
- if (!(buffer = _bmStrdup(menu->filter)))
+ if (!(buffer = bm_strdup(menu->filter)))
goto fail;
char *s;
@@ -59,8 +59,8 @@ static char* _bmFilterTokenize(bmMenu *menu, char ***outTokv, unsigned int *outT
char **tmp = NULL;
size_t pos = 0, next;
- unsigned int tokc = 0, tokn = 0;
- for (; (pos = _bmStripToken(s, " ", &next)) > 0; tokv = tmp) {
+ uint32_t tokc = 0, tokn = 0;
+ for (; (pos = bm_strip_token(s, " ", &next)) > 0; tokv = tmp) {
if (++tokc > tokn && !(tmp = realloc(tokv, ++tokn * sizeof(char*))))
goto fail;
@@ -69,74 +69,70 @@ static char* _bmFilterTokenize(bmMenu *menu, char ***outTokv, unsigned int *outT
for (; *s && *s == ' '; ++s);
}
- *outTokv = tmp;
- *outTokc = tokc;
+ *out_tokv = tmp;
+ *out_tokc = tokc;
return buffer;
fail:
- if (buffer)
- free(buffer);
- if (tokv)
- free(tokv);
+ free(buffer);
+ free(tokv);
return NULL;
}
/**
* Dmenu filterer that accepts substring function.
*
- * @param menu bmMenu instance to filter.
+ * @param menu bm_menu instance to filter.
* @param addition This will be 1, if filter is same as previous filter with something appended.
* @param fstrstr Substring function used to match items.
- * @param outNmemb unsigned int reference to filtered items outNmemb.
- * @return Pointer to array of bmItem pointers.
+ * @param out_nmemb uint32_t reference to filtered items count.
+ * @return Pointer to array of bm_item pointers.
*/
-bmItem** _bmFilterDmenuFun(bmMenu *menu, char addition, char* (*fstrstr)(const char *a, const char *b), int (*fstrncmp)(const char *a, const char *b, size_t len), unsigned int *outNmemb)
+struct bm_item**
+filter_dmenu_fun(struct bm_menu *menu, char addition, char* (*fstrstr)(const char *a, const char *b), int (*fstrncmp)(const char *a, const char *b, size_t len), uint32_t *out_nmemb)
{
- assert(menu);
- assert(fstrstr);
- assert(fstrncmp);
- assert(outNmemb);
- *outNmemb = 0;
+ assert(menu && fstrstr && fstrncmp && out_nmemb);
+ *out_nmemb = 0;
- unsigned int itemsCount;
- bmItem **items;
+ uint32_t count;
+ struct bm_item **items;
if (addition) {
- items = bmMenuGetFilteredItems(menu, &itemsCount);
+ items = bm_menu_get_filtered_items(menu, &count);
} else {
- items = bmMenuGetItems(menu, &itemsCount);
+ items = bm_menu_get_items(menu, &count);
}
char *buffer = NULL;
- bmItem **filtered = calloc(itemsCount, sizeof(bmItem*));
- if (!filtered)
+ struct bm_item **filtered;
+ if (!(filtered = calloc(count, sizeof(struct bm_item*))))
goto fail;
char **tokv;
- unsigned int tokc;
- if (!(buffer = _bmFilterTokenize(menu, &tokv, &tokc)))
+ uint32_t tokc;
+ if (!(buffer = tokenize(menu, &tokv, &tokc)))
goto fail;
size_t len = (tokc ? strlen(tokv[0]) : 0);
- unsigned int i, f, e;
- for (e = f = i = 0; i < itemsCount; ++i) {
- bmItem *item = items[i];
+ uint32_t i, f, e;
+ for (e = f = i = 0; i < count; ++i) {
+ struct bm_item *item = items[i];
if (!item->text && tokc != 0)
continue;
if (tokc && item->text) {
- unsigned int t;
+ uint32_t t;
for (t = 0; t < tokc && fstrstr(item->text, tokv[t]); ++t);
if (t < tokc)
continue;
}
if (tokc && item->text && !fstrncmp(tokv[0], item->text, len + 1)) { /* exact matches */
- memmove(&filtered[1], filtered, f * sizeof(bmItem*));
+ memmove(&filtered[1], filtered, f * sizeof(struct bm_item*));
filtered[0] = item;
e++; /* where do exact matches end */
} else if (tokc && item->text && !fstrncmp(tokv[0], item->text, len)) { /* prefixes */
- memmove(&filtered[e + 1], &filtered[e], (f - e) * sizeof(bmItem*));
+ memmove(&filtered[e + 1], &filtered[e], (f - e) * sizeof(struct bm_item*));
filtered[e] = item;
e++; /* where do exact matches end */
} else {
@@ -145,45 +141,42 @@ bmItem** _bmFilterDmenuFun(bmMenu *menu, char addition, char* (*fstrstr)(const c
f++; /* where do all matches end */
}
- if (buffer)
- free(buffer);
- if (tokv)
- free(tokv);
-
- return _bmFilterShrinkList(&filtered, menu->items.count, (*outNmemb = f));
+ free(buffer);
+ free(tokv);
+ return shrink_list(&filtered, menu->items.count, (*out_nmemb = f));
fail:
- if (filtered)
- free(filtered);
- if (buffer)
- free(buffer);
+ free(filtered);
+ free(buffer);
return NULL;
}
/**
* Filter that mimics the vanilla dmenu filtering.
*
- * @param menu bmMenu instance to filter.
+ * @param menu bm_menu instance to filter.
* @param addition This will be 1, if filter is same as previous filter with something appended.
- * @param outNmemb unsigned int reference to filtered items outNmemb.
- * @return Pointer to array of bmItem pointers.
+ * @param outNmemb uint32_t reference to filtered items count.
+ * @return Pointer to array of bm_item pointers.
*/
-bmItem** _bmFilterDmenu(bmMenu *menu, char addition, unsigned int *outNmemb)
+struct bm_item**
+bm_filter_dmenu(struct bm_menu *menu, bool addition, uint32_t *out_nmemb)
{
- return _bmFilterDmenuFun(menu, addition, strstr, strncmp, outNmemb);
+ return filter_dmenu_fun(menu, addition, strstr, strncmp, out_nmemb);
}
/**
* Filter that mimics the vanilla case-insensitive dmenu filtering.
*
- * @param menu bmMenu instance to filter.
+ * @param menu bm_menu instance to filter.
* @param addition This will be 1, if filter is same as previous filter with something appended.
- * @param outNmemb unsigned int reference to filtered items outNmemb.
- * @return Pointer to array of bmItem pointers.
+ * @param outNmemb uint32_t reference to filtered items count.
+ * @return Pointer to array of bm_item pointers.
*/
-bmItem** _bmFilterDmenuCaseInsensitive(bmMenu *menu, char addition, unsigned int *outNmemb)
+struct bm_item**
+bm_filter_dmenu_case_insensitive(struct bm_menu *menu, bool addition, uint32_t *out_nmemb)
{
- return _bmFilterDmenuFun(menu, addition, _bmStrupstr, _bmStrnupcmp, outNmemb);
+ return filter_dmenu_fun(menu, addition, bm_strupstr, bm_strnupcmp, out_nmemb);
}
/* vim: set ts=8 sw=4 tw=0 :*/
diff --git a/lib/internal.h b/lib/internal.h
index 2fc9393..dd232d2 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -5,71 +5,109 @@
#endif
/**
- * Internal bmItem struct that is not exposed to public.
- * Represents a single item in menu.
+ * Destructor function pointer for some list calls.
+ */
+typedef void (*list_free_fun)(void*);
+
+/**
+ * List type
*/
-struct _bmItem {
+struct list {
/**
- * Userdata pointer.
- * This pointer will be passed around with the item untouched.
+ * Items in the list.
*/
- void *userdata;
+ void **items;
/**
- * Primary text shown on item as null terminated C "string".
- * Matching will be done against this text as well.
+ * Number of items.
*/
- char *text;
+ uint32_t count;
+
+ /**
+ * Number of allocated items.
+ */
+ uint32_t allocated;
};
/**
- * Internal bmRenderApi struct.
+ * Internal render api struct.
* Renderers should be able to fill this one as they see fit.
*/
-struct _bmRenderApi {
+struct render_api {
+ /**
+ * Create underlying renderer.
+ */
+ void (*constructor)(void);
+
+ /**
+ * Release underlying renderer.
+ */
+ void (*destructor)(void);
+
/**
* Get count of displayed items by the underlying renderer.
*/
- unsigned int (*displayedCount)(const bmMenu *menu);
+ uint32_t (*get_displayed_count)(const struct bm_menu *menu);
/**
* If the underlying renderer is a UI toolkit. (curses, etc...)
* There might be possibility to get user input, and this should be thus implemented.
*/
- bmKey (*getKey)(unsigned int *unicode);
+ enum bm_key (*poll_key)(uint32_t *unicode);
/**
* Tells underlying renderer to draw the menu.
*/
- void (*render)(const bmMenu *menu);
+ void (*render)(const struct bm_menu *menu);
+};
+
+/**
+ * Internal bm_renderer struct.
+ */
+struct bm_renderer {
+ /**
+ * Name of the renderer.
+ */
+ char *name;
/**
- * Release underlying renderer.
+ * File path of the renderer.
*/
- void (*free)(void);
-};
+ char *file;
-struct _bmItemList {
/**
- * Items in the list.
+ * Open handle to the plugin file of this renderer.
*/
- struct _bmItem **list;
+ void *handle;
/**
- * Number of items.
+ * API
*/
- unsigned int count;
+ struct render_api api;
+};
+/**
+ * Internal bm_item struct that is not exposed to public.
+ * Represents a single item in menu.
+ */
+struct bm_item {
/**
- * Number of allocated items.
+ * Userdata pointer.
+ * This pointer will be passed around with the item untouched.
+ */
+ void *userdata;
+
+ /**
+ * Primary text shown on item as null terminated C "string".
+ * Matching will be done against this text as well.
*/
- unsigned int allocated;
+ char *text;
};
/**
- * Internal bmMenu struct that is not exposed to public.
+ * Internal bm_menu struct that is not exposed to public.
*/
-struct _bmMenu {
+struct bm_menu {
/**
* Userdata pointer.
* This pointer will be passed around with the menu untouched.
@@ -79,22 +117,22 @@ struct _bmMenu {
/**
* Underlying renderer access.
*/
- struct _bmRenderApi renderApi;
+ const struct bm_renderer *renderer;
/**
* Items contained in menu instance.
*/
- struct _bmItemList items;
+ struct list items;
/**
* Filtered/displayed items contained in menu instance.
*/
- struct _bmItemList filtered;
+ struct list filtered;
/**
* Selected items.
*/
- struct _bmItemList selection;
+ struct list selection;
/**
* Menu instance title.
@@ -109,80 +147,74 @@ struct _bmMenu {
/**
* Used as optimization.
*/
- char *oldFilter;
+ char *old_filter;
/**
* Size of filter buffer
*/
- size_t filterSize;
+ size_t filter_size;
/**
* Current byte offset on filter text.
*/
- unsigned int cursor;
+ uint32_t cursor;
/**
* Current column/cursor position on filter text.
*/
- unsigned int cursesCursor;
+ uint32_t curses_cursor;
/**
* Current filtered/highlighted item index in menu instance.
* This index is valid for the list returned by bmMenuGetFilteredItems.
*/
- unsigned int index;
+ uint32_t index;
/**
* Current filtering method in menu instance.
*/
- bmFilterMode filterMode;
-
- /**
- * Drawing mode used in menu instance.
- */
- bmDrawMode drawMode;
+ enum bm_filter_mode filter_mode;
/**
* Should selection be wrapped?
*/
- char wrap;
+ bool wrap;
};
-/* draw/curses.c */
-int _bmDrawCursesInit(struct _bmRenderApi *api);
+/* library.c */
+bool bm_renderer_activate(struct bm_renderer *renderer);
/* menu.c */
-int _bmMenuItemIsSelected(const bmMenu *menu, const bmItem *item);
+bool bm_menu_item_is_selected(const struct bm_menu *menu, const struct bm_item *item);
/* filter.c */
-bmItem** _bmFilterDmenu(bmMenu *menu, char addition, unsigned int *outNmemb);
-bmItem** _bmFilterDmenuCaseInsensitive(bmMenu *menu, char addition, unsigned int *outNmemb);
+struct bm_item** bm_filter_dmenu(struct bm_menu *menu, bool addition, uint32_t *out_nmemb);
+struct bm_item** bm_filter_dmenu_case_insensitive(struct bm_menu *menu, bool addition, uint32_t *out_nmemb);
/* list.c */
-void _bmItemListFreeList(struct _bmItemList *list);
-void _bmItemListFreeItems(struct _bmItemList *list);
-bmItem** _bmItemListGetItems(const struct _bmItemList *list, unsigned int *outNmemb);
-int _bmItemListSetItemsNoCopy(struct _bmItemList *list, bmItem **items, unsigned int nmemb);
-int _bmItemListSetItems(struct _bmItemList *list, const bmItem **items, unsigned int nmemb);
-int _bmItemListGrow(struct _bmItemList *list, unsigned int step);
-int _bmItemListAddItemAt(struct _bmItemList *list, bmItem *item, unsigned int index);
-int _bmItemListAddItem(struct _bmItemList *list, bmItem *item);
-int _bmItemListRemoveItemAt(struct _bmItemList *list, unsigned int index);
-int _bmItemListRemoveItem(struct _bmItemList *list, const bmItem *item);
+void list_free_list(struct list *list);
+void list_free_items(struct list *list, list_free_fun destructor);
+void* list_get_items(const struct list *list, uint32_t *out_nmemb);
+bool list_set_items_no_copy(struct list *list, void *items, uint32_t nmemb);
+bool list_set_items(struct list *list, const void *items, uint32_t nmemb, list_free_fun destructor);
+bool list_grow(struct list *list, uint32_t step);
+bool list_add_item_at(struct list *list, void *item, uint32_t index);
+bool list_add_item(struct list *list, void *item);
+bool list_remove_item_at(struct list *list, uint32_t index);
+bool list_remove_item(struct list *list, const void *item);
/* util.c */
-char* _bmStrdup(const char *s);
-size_t _bmStripToken(char *string, const char *token, size_t *outNext);
-int _bmStrupcmp(const char *hay, const char *needle);
-int _bmStrnupcmp(const char *hay, const char *needle, size_t len);
-char* _bmStrupstr(const char *hay, const char *needle);
-bmItem** _bmShrinkItemList(bmItem ***inOutList, size_t osize, size_t nsize);
-int _bmUtf8StringScreenWidth(const char *string);
-size_t _bmUtf8RuneNext(const char *string, size_t start);
-size_t _bmUtf8RunePrev(const char *string, size_t start);
-size_t _bmUtf8RuneWidth(const char *rune, unsigned int u8len);
-size_t _bmUtf8RuneRemove(char *string, size_t start, size_t *outRuneWidth);
-size_t _bmUtf8RuneInsert(char **string, size_t *bufSize, size_t start, const char *rune, unsigned int u8len, size_t *outRuneWidth);
-size_t _bmUnicodeInsert(char **string, size_t *bufSize, size_t start, unsigned int unicode, size_t *outRuneWidth);
+char* bm_strdup(const char *s);
+size_t bm_strip_token(char *string, const char *token, size_t *out_next);
+int bm_strupcmp(const char *hay, const char *needle);
+int bm_strnupcmp(const char *hay, const char *needle, size_t len);
+char* bm_strupstr(const char *hay, const char *needle);
+int32_t bm_utf8_string_screen_width(const char *string);
+size_t bm_utf8_rune_next(const char *string, size_t start);
+size_t bm_utf8_rune_prev(const char *string, size_t start);
+size_t bm_utf8_rune_width(const char *rune, uint32_t u8len);
+size_t bm_utf8_rune_remove(char *string, size_t start, size_t *out_rune_width);
+size_t bm_utf8_rune_insert(char **string, size_t *bufSize, size_t start, const char *rune, uint32_t u8len, size_t *out_rune_width);
+size_t bm_unicode_insert(char **string, size_t *bufSize, size_t start, uint32_t unicode, size_t *out_rune_width);
/* vim: set ts=8 sw=4 tw=0 :*/
diff --git a/lib/item.c b/lib/item.c
index f2a879a..1d12357 100644
--- a/lib/item.c
+++ b/lib/item.c
@@ -3,91 +3,55 @@
#include <assert.h>
#include <string.h>
-/**
- * Allocate a new item.
- *
- * @param text Pointer to null terminated C "string", can be **NULL** for empty text.
- * @return bmItem for new item instance, **NULL** if creation failed.
- */
-bmItem* bmItemNew(const char *text)
+struct bm_item*
+bm_item_new(const char *text)
{
- bmItem *item = calloc(1, sizeof(bmItem));
-
- if (!item)
+ struct bm_item *item;
+ if (!(item = calloc(1, sizeof(struct bm_item))))
return NULL;
- bmItemSetText(item, text);
+ bm_item_set_text(item, text);
return item;
}
-/**
- * Release bmItem instance.
- *
- * @param item bmItem instance to be freed from memory.
- */
-void bmItemFree(bmItem *item)
+void
+bm_item_free(struct bm_item *item)
{
assert(item);
-
- if (item->text)
- free(item->text);
-
+ free(item->text);
free(item);
}
-/**
- * Set userdata pointer to bmItem instance.
- * Userdata will be carried unmodified by the instance.
- *
- * @param item bmItem instance where to set userdata pointer.
- * @param userdata Pointer to userdata.
- */
-void bmItemSetUserdata(bmItem *item, void *userdata)
+void
+bm_item_set_userdata(struct bm_item *item, void *userdata)
{
assert(item);
item->userdata = userdata;
}
-/**
- * Get userdata pointer from bmItem instance.
- *
- * @param item bmItem instance which userdata pointer to get.
- * @return Pointer for unmodified userdata.
- */
-void* bmItemGetUserdata(bmItem *item)
+void*
+bm_item_get_userdata(struct bm_item *item)
{
assert(item);
return item->userdata;
}
-/**
- * Set text to bmItem instance.
- *
- * @param item bmItem instance where to set text.
- * @param text C "string" to set as text, can be **NULL** for empty text.
- */
-int bmItemSetText(bmItem *item, const char *text)
+bool
+bm_item_set_text(struct bm_item *item, const char *text)
{
assert(item);
char *copy = NULL;
- if (text && !(copy = _bmStrdup(text)))
- return 0;
-
- if (item->text)
- free(item->text);
+ if (text && !(copy = bm_strdup(text)))
+ return false;
+ free(item->text);
item->text = copy;
- return 1;
+ return true;
}
-/**
- * Get text from bmItem instance.
- *
- * @param item bmItem instance where to get text from.
- * @return Pointer to null terminated C "string", can be **NULL** for empty text.
- */
-const char* bmItemGetText(const bmItem *item)
+const char*
+bm_item_get_text(const struct bm_item *item)
{
assert(item);
return item->text;
diff --git a/lib/library.c b/lib/library.c
index f432eda..6544086 100644
--- a/lib/library.c
+++ b/lib/library.c
@@ -1,15 +1,151 @@
+#include "internal.h"
#include "version.h"
-/**
- * Get version of the library in 'major.minor.patch' format.
- *
- * @see @link http://semver.org/ Semantic Versioning @endlink
- *
- * @return Null terminated C "string" to version string.
- */
-const char *bmVersion(void)
+#include "3rdparty/tinydir.h"
+#include "3rdparty/cdl.h"
+
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+
+static struct list renderers;
+
+static void
+bm_renderer_free(struct bm_renderer *renderer)
+{
+ assert(renderer);
+
+ if (renderer->handle)
+ chckDlUnload(renderer->handle);
+
+ free(renderer->name);
+ free(renderer->file);
+ free(renderer);
+}
+
+static bool
+load(const char *file, struct bm_renderer *renderer)
+{
+ void *handle;
+ const char *error = NULL;
+
+ if (!(handle = chckDlLoad(file, &error)))
+ goto fail;
+
+ const char* (*regfun)(struct render_api*);
+ if (!(regfun = chckDlLoadSymbol(handle, "register_renderer", &error)))
+ goto fail;
+
+ renderer->file = bm_strdup(file);
+ renderer->handle = handle;
+ const char *name = regfun(&renderer->api);
+ renderer->name = (name ? bm_strdup(name) : NULL);
+ return true;
+
+fail:
+ if (handle)
+ chckDlUnload(handle);
+ fprintf(stderr, "%s\n", error);
+ return false;
+}
+
+static bool
+load_to_list(const char *file)
+{
+ struct bm_renderer *renderer;
+ if (!(renderer = calloc(1, sizeof(struct bm_renderer))))
+ goto fail;
+
+ if (!load(file, renderer))
+ goto fail;
+
+ chckDlUnload(renderer->handle);
+ return list_add_item(&renderers, renderer);
+
+fail:
+ if (renderer)
+ bm_renderer_free(renderer);
+ return false;
+}
+
+bool
+bm_renderer_activate(struct bm_renderer *renderer)
+{
+ assert(renderer);
+
+ if (!load(renderer->file, renderer))
+ return false;
+
+ return true;
+}
+
+bool
+bm_init(void)
+{
+ static const char *rpath = INSTALL_PREFIX "/lib/bemenu";
+
+ const char *path = getenv("BEMENU_RENDERER");
+
+ if (path)
+ return load_to_list(path);
+
+ path = getenv("BEMENU_RENDERERS");
+
+ if (!path || access(path, R_OK) == -1)
+ path = rpath;
+
+ tinydir_dir dir;
+ if (tinydir_open(&dir, path) == -1)
+ goto fail;
+
+ size_t registered = 0;
+ while (dir.has_next) {
+ tinydir_file file;
+ memset(&file, 0, sizeof(file));
+ tinydir_readfile(&dir, &file);
+
+ if (!file.is_dir && !strncmp(file.name, "bemenu-renderer-", strlen("bemenu-renderer-"))) {
+ size_t len = snprintf(NULL, 0, "%s/%s", file.name, path);
+
+ char *fpath;
+ if ((fpath = calloc(1, len + 1))) {
+ sprintf(fpath, "%s/%s", path, file.name);
+
+ if (load_to_list(fpath))
+ registered++;
+
+ free(fpath);
+ }
+ }
+
+ tinydir_next(&dir);
+ }
+
+ tinydir_close(&dir);
+ return (registered > 0 ? true : false);
+
+fail:
+ return false;
+}
+
+const struct bm_renderer**
+bm_get_renderers(uint32_t *out_nmemb)
+{
+ assert(out_nmemb);
+ return list_get_items(&renderers, out_nmemb);
+}
+
+const char*
+bm_version(void)
{
return BM_VERSION;
}
+const char*
+bm_renderer_get_name(const struct bm_renderer *renderer)
+{
+ assert(renderer);
+ return renderer->name;
+}
+
/* vim: set ts=8 sw=4 tw=0 :*/
diff --git a/lib/list.c b/lib/list.c
index 203adf2..918e830 100644
--- a/lib/list.c
+++ b/lib/list.c
@@ -3,137 +3,142 @@
#include <string.h>
#include <assert.h>
-void _bmItemListFreeList(struct _bmItemList *list)
+void
+list_free_list(struct list *list)
{
assert(list);
-
- if (list->list)
- free(list->list);
-
+ free(list->items);
list->allocated = list->count = 0;
- list->list = NULL;
+ list->items = NULL;
}
-void _bmItemListFreeItems(struct _bmItemList *list)
+void
+list_free_items(struct list *list, list_free_fun destructor)
{
assert(list);
- unsigned int i;
- for (i = 0; i < list->count; ++i)
- bmItemFree(list->list[i]);
+ for (uint32_t i = 0; i < list->count; ++i)
+ destructor(list->items[i]);
- _bmItemListFreeList(list);
+ list_free_list(list);
}
-bmItem** _bmItemListGetItems(const struct _bmItemList *list, unsigned int *outNmemb)
+void*
+list_get_items(const struct list *list, uint32_t *out_nmemb)
{
assert(list);
- if (outNmemb)
- *outNmemb = list->count;
+ if (out_nmemb)
+ *out_nmemb = list->count;
- return list->list;
+ return list->items;
}
/** !!! Frees the old list, not items !!! */
-int _bmItemListSetItemsNoCopy(struct _bmItemList *list, bmItem **items, unsigned int nmemb)
+bool
+list_set_items_no_copy(struct list *list, void *items, uint32_t nmemb)
{
assert(list);
- _bmItemListFreeList(list);
+ list_free_list(list);
if (!items || nmemb == 0) {
items = NULL;
nmemb = 0;
}
- list->list = items;
+ list->items = items;
list->allocated = list->count = nmemb;
- return 1;
+ return true;
}
/** !!! Frees the old items and list !!! */
-int _bmItemListSetItems(struct _bmItemList *list, const bmItem **items, unsigned int nmemb)
+bool
+list_set_items(struct list *list, const void *items, uint32_t nmemb, list_free_fun destructor)
{
assert(list);
if (!items || nmemb == 0) {
- _bmItemListFreeItems(list);
- return 1;
+ list_free_items(list, destructor);
+ return true;
}
- bmItem **newItems;
- if (!(newItems = calloc(sizeof(bmItem*), nmemb)))
- return 0;
+ void *new_items;
+ if (!(new_items = calloc(sizeof(void*), nmemb)))
+ return false;
- memcpy(newItems, items, sizeof(bmItem*) * nmemb);
- return _bmItemListSetItemsNoCopy(list, newItems, nmemb);
+ memcpy(new_items, items, sizeof(void*) * nmemb);
+ return list_set_items_no_copy(list, new_items, nmemb);
}
-int _bmItemListGrow(struct _bmItemList *list, unsigned int step)
+bool
+list_grow(struct list *list, uint32_t step)
{
assert(list);
void *tmp;
- unsigned int nsize = sizeof(bmItem*) * (list->allocated + step);
+ uint32_t nsize = sizeof(struct bm_item*) * (list->allocated + step);
- if (!list->list || !(tmp = realloc(list->list, nsize))) {
+ if (!list->items || !(tmp = realloc(list->items, nsize))) {
if (!(tmp = malloc(nsize)))
- return 0;
+ return false;
- if (list->list) {
- memcpy(tmp, list->list, sizeof(bmItem*) * list->allocated);
- free(list->list);
+ if (list->items) {
+ memcpy(tmp, list->items, sizeof(struct bm_item*) * list->allocated);
+ free(list->items);
}
}
- list->list = tmp;
+ list->items = tmp;
list->allocated += step;
- memset(&list->list[list->count], 0, sizeof(bmItem*) * (list->allocated - list->count));
- return 1;
+ memset(&list->items[list->count], 0, sizeof(struct bm_item*) * (list->allocated - list->count));
+ return true;
}
-int _bmItemListAddItemAt(struct _bmItemList *list, bmItem *item, unsigned int index)
+bool
+list_add_item_at(struct list *list, void *item, uint32_t index)
{
- assert(list);
- assert(item);
+ assert(list && item);
- if ((!list->list || list->allocated <= list->count) && !_bmItemListGrow(list, 32))
- return 0;
+ if ((!list->items || list->allocated <= list->count) && !list_grow(list, 32))
+ return false;
if (index + 1 != list->count) {
- unsigned int i = index;
- memmove(&list->list[i + 1], &list->list[i], sizeof(bmItem*) * (list->count - i));
+ uint32_t i = index;
+ memmove(&list->items[i + 1], &list->items[i], sizeof(struct bm_item*) * (list->count - i));
}
- list->list[index] = item;
+ list->items[index] = item;
list->count++;
- return 1;
+ return true;
}
-int _bmItemListAddItem(struct _bmItemList *list, bmItem *item)
+bool
+list_add_item(struct list *list, void *item)
{
assert(list);
- return _bmItemListAddItemAt(list, item, list->count);
+ return list_add_item_at(list, item, list->count);
}
-int _bmItemListRemoveItemAt(struct _bmItemList *list, unsigned int index)
+bool
+list_remove_item_at(struct list *list, uint32_t index)
{
assert(list);
- unsigned int i = index;
- if (!list->list || list->count <= i)
- return 0;
+ uint32_t i = index;
+ if (!list->items || list->count <= i)
+ return false;
- memmove(&list->list[i], &list->list[i], sizeof(bmItem*) * (list->count - i));
- return 1;
+ memmove(&list->items[i], &list->items[i], sizeof(void*) * (list->count - i));
+ return true;
}
-int _bmItemListRemoveItem(struct _bmItemList *list, const bmItem *item)
+bool
+list_remove_item(struct list *list, const void *item)
{
- unsigned int i;
- for (i = 0; i < list->count && list->list[i] != item; ++i);
- return _bmItemListRemoveItemAt(list, i);
+ uint32_t i;
+ for (i = 0; i < list->count && list->items[i] != item; ++i);
+ return list_remove_item_at(list, i);
}
/* vim: set ts=8 sw=4 tw=0 :*/
diff --git a/lib/menu.c b/lib/menu.c
index b7ab021..a8390fa 100644
--- a/lib/menu.c
+++ b/lib/menu.c
@@ -7,359 +7,241 @@
/**
* Filter function map.
*/
-static bmItem** (*filterFunc[BM_FILTER_MODE_LAST])(bmMenu *menu, char addition, unsigned int *outNmemb) = {
- _bmFilterDmenu, /* BM_FILTER_DMENU */
- _bmFilterDmenuCaseInsensitive /* BM_FILTER_DMENU_CASE_INSENSITIVE */
+static struct bm_item** (*filter_func[BM_FILTER_MODE_LAST])(struct bm_menu *menu, bool addition, uint32_t *out_nmemb) = {
+ bm_filter_dmenu, /* BM_FILTER_DMENU */
+ bm_filter_dmenu_case_insensitive /* BM_FILTER_DMENU_CASE_INSENSITIVE */
};
-int _bmMenuItemIsSelected(const bmMenu *menu, const bmItem *item)
+bool
+bm_menu_item_is_selected(const struct bm_menu *menu, const struct bm_item *item)
{
assert(menu);
assert(item);
- unsigned int i, count;
- bmItem **items = bmMenuGetSelectedItems(menu, &count);
+ uint32_t i, count;
+ struct bm_item **items = bm_menu_get_selected_items(menu, &count);
for (i = 0; i < count && items[i] != item; ++i);
return (i < count);
}
-/**
- * Create new bmMenu instance.
- *
- * @param drawMode Render method to be used for this menu instance.
- * @return bmMenu for new menu instance, **NULL** if creation failed.
- */
-bmMenu* bmMenuNew(bmDrawMode drawMode)
+struct bm_menu*
+bm_menu_new(const char *renderer)
{
- bmMenu *menu = calloc(1, sizeof(bmMenu));
-
- menu->drawMode = drawMode;
-
- if (!menu)
+ struct bm_menu *menu;
+ if (!(menu = calloc(1, sizeof(struct bm_menu))))
return NULL;
- int status = 1;
+ uint32_t count;
+ const struct bm_renderer **renderers = bm_get_renderers(&count);
- switch (menu->drawMode) {
- case BM_DRAW_MODE_CURSES:
- status = _bmDrawCursesInit(&menu->renderApi);
- break;
+ bool status = false;
+ for (uint32_t i = 0; i < count; ++i) {
+ if (renderer && strcmp(renderer, renderers[i]->name))
+ continue;
- default: break;
+ if (bm_renderer_activate((struct bm_renderer*)renderers[i])) {
+ status = true;
+ menu->renderer = renderers[i];
+ break;
+ }
}
- if (status == 0) {
- bmMenuFree(menu);
+ if (!status) {
+ bm_menu_free(menu);
return NULL;
}
return menu;
}
-/**
- * Release bmMenu instance.
- *
- * @param menu bmMenu instance to be freed from memory.
- */
-void bmMenuFree(bmMenu *menu)
+void
+bm_menu_free(struct bm_menu *menu)
{
assert(menu);
- if (menu->renderApi.free)
- menu->renderApi.free();
-
- if (menu->title)
- free(menu->title);
+ if (menu->renderer && menu->renderer->api.destructor)
+ menu->renderer->api.destructor();
- if (menu->filter)
- free(menu->filter);
+ free(menu->title);
+ free(menu->filter);
+ free(menu->old_filter);
- if (menu->oldFilter)
- free(menu->oldFilter);
-
- bmMenuFreeItems(menu);
+ bm_menu_free_items(menu);
free(menu);
}
-/**
- * Release items inside bmMenu instance.
- *
- * @param menu bmMenu instance which items will be freed from memory.
- */
-void bmMenuFreeItems(bmMenu *menu)
+void
+bm_menu_free_items(struct bm_menu *menu)
{
assert(menu);
- _bmItemListFreeList(&menu->selection);
- _bmItemListFreeList(&menu->filtered);
- _bmItemListFreeItems(&menu->items);
+ list_free_list(&menu->selection);
+ list_free_list(&menu->filtered);
+ list_free_items(&menu->items, (list_free_fun)bm_item_free);
}
-/**
- * Set userdata pointer to bmMenu instance.
- * Userdata will be carried unmodified by the instance.
- *
- * @param menu bmMenu instance where to set userdata pointer.
- * @param userdata Pointer to userdata.
- */
-void bmMenuSetUserdata(bmMenu *menu, void *userdata)
+void
+bm_menu_set_userdata(struct bm_menu *menu, void *userdata)
{
assert(menu);
menu->userdata = userdata;
}
-/**
- * Get userdata pointer from bmMenu instance.
- *
- * @param menu bmMenu instance which userdata pointer to get.
- * @return Pointer for unmodified userdata.
- */
-void* bmMenuGetUserdata(bmMenu *menu)
+void*
+bm_menu_get_userdata(struct bm_menu *menu)
{
assert(menu);
return menu->userdata;
}
-/**
- * Set filter text to bmMenu instance.
- *
- * @param menu bmMenu instance where to set filter.
- * @param filter Null terminated C "string" to act as filter.
- */
-void bmMenuSetFilter(bmMenu *menu, const char *filter)
+void
+bm_menu_set_filter(struct bm_menu *menu, const char *filter)
{
assert(menu);
- if (menu->filter)
- free(menu->filter);
-
- menu->filter = (filter ? _bmStrdup(filter) : NULL);
- menu->filterSize = (filter ? strlen(filter) : 0);
+ free(menu->filter);
+ menu->filter = (filter ? bm_strdup(filter) : NULL);
+ menu->filter_size = (filter ? strlen(filter) : 0);
}
-/**
- * Get filter text from bmMenu instance.
- *
- * @param menu bmMenu instance where to get filter.
- * @return Const pointer to current filter text, may be **NULL** if empty.
- */
-const char* bmMenuGetFilter(bmMenu *menu)
+const char*
+bm_menu_get_filter(struct bm_menu *menu)
{
assert(menu);
return menu->filter;
}
-/**
- * Set active filter mode to bmMenu instance.
- *
- * @param menu bmMenu instance where to set filter mode.
- * @param mode bmFilterMode constant.
- */
-void bmMenuSetFilterMode(bmMenu *menu, bmFilterMode mode)
+void
+bm_menu_set_filter_mode(struct bm_menu *menu, enum bm_filter_mode mode)
{
assert(menu);
- menu->filterMode = (mode >= BM_FILTER_MODE_LAST ? BM_FILTER_MODE_DMENU : mode);
+ menu->filter_mode = (mode >= BM_FILTER_MODE_LAST ? BM_FILTER_MODE_DMENU : mode);
}
-/**
- * Get active filter mode from bmMenu instance.
- *
- * @param menu bmMenu instance where to get filter mode.
- * @return bmFilterMode constant.
- */
-bmFilterMode bmMenuGetFilterMode(const bmMenu *menu)
+enum bm_filter_mode
+bm_menu_get_filter_mode(const struct bm_menu *menu)
{
assert(menu);
- return menu->filterMode;
+ return menu->filter_mode;
}
-/**
- * Set selection wrapping on/off.
- *
- * @param menu bmMenu instance where to toggle selection wrapping.
- * @param int 1 == on, 0 == off.
- */
-void bmMenuSetWrap(bmMenu *menu, int wrap)
+void
+bm_menu_set_wrap(struct bm_menu *menu, bool wrap)
{
assert(menu);
- menu->wrap = (wrap ? 1 : 0);
+ menu->wrap = wrap;
}
-/**
- * Get selection wrapping state.
- *
- * @param menu bmMenu instance where to get selection wrapping state.
- * @return int for wrap state.
- */
-int bmMenuGetWrap(const bmMenu *menu)
+bool
+bm_menu_get_wrap(const struct bm_menu *menu)
{
assert(menu);
return menu->wrap;
}
-/**
- * Set title to bmMenu instance.
- *
- * @param menu bmMenu instance where to set title.
- * @param title C "string" to set as title, can be **NULL** for empty title.
- */
-int bmMenuSetTitle(bmMenu *menu, const char *title)
+bool
+bm_menu_set_title(struct bm_menu *menu, const char *title)
{
assert(menu);
char *copy = NULL;
- if (title && !(copy = _bmStrdup(title)))
- return 0;
-
- if (menu->title)
- free(menu->title);
+ if (title && !(copy = bm_strdup(title)))
+ return false;
+ free(menu->title);
menu->title = copy;
- return 1;
+ return true;
}
-/**
- * Get title from bmMenu instance.
- *
- * @param menu bmMenu instance where to get title from.
- * @return Pointer to null terminated C "string", can be **NULL** for empty title.
- */
-const char* bmMenuGetTitle(const bmMenu *menu)
+const char*
+bm_menu_get_title(const struct bm_menu *menu)
{
assert(menu);
return menu->title;
}
-/**
- * Add item to bmMenu instance at specific index.
- *
- * @param menu bmMenu instance where item will be added.
- * @param item bmItem instance to add.
- * @param index Index where item will be added.
- * @return 1 on successful add, 0 on failure.
- */
-int bmMenuAddItemAt(bmMenu *menu, bmItem *item, unsigned int index)
+bool
+bm_menu_add_items_at(struct bm_menu *menu, struct bm_item *item, uint32_t index)
{
assert(menu);
- return _bmItemListAddItemAt(&menu->items, item, index);
+ return list_add_item_at(&menu->items, item, index);
}
-/**
- * Add item to bmMenu instance.
- *
- * @param menu bmMenu instance where item will be added.
- * @param item bmItem instance to add.
- * @return 1 on successful add, 0 on failure.
- */
-int bmMenuAddItem(bmMenu *menu, bmItem *item)
+bool
+bm_menu_add_item(struct bm_menu *menu, struct bm_item *item)
{
- return _bmItemListAddItem(&menu->items, item);
+ return list_add_item(&menu->items, item);
}
-/**
- * Remove item from bmMenu instance at specific index.
- *
- * @warning The item won't be freed, use bmItemFree to do that.
- *
- * @param menu bmMenu instance from where item will be removed.
- * @param index Index of item to remove.
- * @return 1 on successful add, 0 on failure.
- */
-int bmMenuRemoveItemAt(bmMenu *menu, unsigned int index)
+bool
+bm_menu_remove_item_at(struct bm_menu *menu, uint32_t index)
{
assert(menu);
- if (!menu->items.list || menu->items.count <= index)
+ if (!menu->items.items || menu->items.count <= index)
return 0;
- bmItem *item = menu->items.list[index];
- int ret = _bmItemListRemoveItemAt(&menu->items, index);
+ bool ret = list_remove_item_at(&menu->items, index);
if (ret) {
- _bmItemListRemoveItem(&menu->selection, item);
- _bmItemListRemoveItem(&menu->filtered, item);
+ struct bm_item *item = ((struct bm_item**)menu->items.items)[index];
+ list_remove_item(&menu->selection, item);
+ list_remove_item(&menu->filtered, item);
}
return ret;
}
-/**
- * Remove item from bmMenu instance.
- *
- * @warning The item won't be freed, use bmItemFree to do that.
- *
- * @param menu bmMenu instance from where item will be removed.
- * @param item bmItem instance to remove.
- * @return 1 on successful add, 0 on failure.
- */
-int bmMenuRemoveItem(bmMenu *menu, bmItem *item)
+bool
+bm_menu_remove_item(struct bm_menu *menu, struct bm_item *item)
{
assert(menu);
- int ret = _bmItemListRemoveItem(&menu->items, item);
+ bool ret = list_remove_item(&menu->items, item);
if (ret) {
- _bmItemListRemoveItem(&menu->selection, item);
- _bmItemListRemoveItem(&menu->filtered, item);
+ list_remove_item(&menu->selection, item);
+ list_remove_item(&menu->filtered, item);
}
return ret;
}
-/**
- * Highlight item in menu by index.
- *
- * @param menu bmMenu instance from where to highlight item.
- * @param index Index of item to highlight.
- * @return 1 on successful highlight, 0 on failure.
- */
-int bmMenuSetHighlightedIndex(bmMenu *menu, unsigned int index)
+bool
+bm_menu_set_highlighted_index(struct bm_menu *menu, uint32_t index)
{
assert(menu);
- unsigned int itemsCount;
- bmMenuGetFilteredItems(menu, &itemsCount);
+ uint32_t count;
+ bm_menu_get_filtered_items(menu, &count);
- if (itemsCount <= index)
+ if (count <= index)
return 0;
return (menu->index = index);
}
-/**
- * Highlight item in menu.
- *
- * @param menu bmMenu instance from where to highlight item.
- * @param item bmItem instance to highlight.
- * @return 1 on successful highlight, 0 on failure.
- */
-int bmMenuSetHighlighted(bmMenu *menu, bmItem *item)
+bool
+bm_menu_set_highlighted_item(struct bm_menu *menu, struct bm_item *item)
{
assert(menu);
- unsigned int i, itemsCount;
- bmItem **items = bmMenuGetFilteredItems(menu, &itemsCount);
- for (i = 0; i < itemsCount && items[i] != item; ++i);
+ uint32_t i, count;
+ struct bm_item **items = bm_menu_get_filtered_items(menu, &count);
+ for (i = 0; i < count && items[i] != item; ++i);
- if (itemsCount <= i)
+ if (count <= i)
return 0;
return (menu->index = i);
}
-/**
- * Get highlighted item from bmMenu instance.
- *
- * @warning The pointer returned by this function may be invalid after items change.
- *
- * @param menu bmMenu instance from where to get highlighted item.
- * @return Selected bmItem instance, **NULL** if none highlighted.
- */
-bmItem* bmMenuGetHighlightedItem(const bmMenu *menu)
+struct bm_item*
+bm_menu_get_highlighted_item(const struct bm_menu *menu)
{
assert(menu);
- unsigned int count;
- bmItem **items = bmMenuGetFilteredItems(menu, &count);
+ uint32_t count;
+ struct bm_item **items = bm_menu_get_filtered_items(menu, &count);
if (!items || count <= menu->index)
return NULL;
@@ -367,244 +249,169 @@ bmItem* bmMenuGetHighlightedItem(const bmMenu *menu)
return items[menu->index];
}
-/**
- * Set selected items to bmMenu instance.
- *
- * @param menu bmMenu instance where items will be set.
- * @param items Array of bmItem pointers to set.
- * @param nmemb Total count of items in array.
- * @return 1 on successful set, 0 on failure.
- */
-int bmMenuSetSelectedItems(bmMenu *menu, bmItem **items, unsigned int nmemb)
+bool
+bm_menu_set_selected_items(struct bm_menu *menu, struct bm_item **items, uint32_t nmemb)
{
assert(menu);
- bmItem **newItems;
- if (!(newItems = calloc(sizeof(bmItem*), nmemb)))
+ struct bm_item **new_items;
+ if (!(new_items = calloc(sizeof(struct bm_item*), nmemb)))
return 0;
- memcpy(newItems, items, sizeof(bmItem*) * nmemb);
- return _bmItemListSetItemsNoCopy(&menu->selection, newItems, nmemb);
+ memcpy(new_items, items, sizeof(struct bm_item*) * nmemb);
+ return list_set_items_no_copy(&menu->selection, new_items, nmemb);
}
-/**
- * Get selected items from bmMenu instance.
- *
- * @warning The pointer returned by this function may be invalid after selection or items change.
- *
- * @param menu bmMenu instance from where to get selected items.
- * @param outNmemb Reference to unsigned int where total count of returned items will be stored.
- * @return Pointer to array of bmItem pointers.
- */
-bmItem** bmMenuGetSelectedItems(const bmMenu *menu, unsigned int *outNmemb)
+struct bm_item**
+bm_menu_get_selected_items(const struct bm_menu *menu, uint32_t *out_nmemb)
{
assert(menu);
- return _bmItemListGetItems(&menu->selection, outNmemb);
+ return list_get_items(&menu->selection, out_nmemb);
}
-/**
- * Set items to bmMenu instance.
- * Will replace all the old items on bmMenu instance.
- *
- * If items is **NULL**, or nmemb is zero, all items will be freed from the menu.
- *
- * @param menu bmMenu instance where items will be set.
- * @param items Array of bmItem pointers to set.
- * @param nmemb Total count of items in array.
- * @return 1 on successful set, 0 on failure.
- */
-int bmMenuSetItems(bmMenu *menu, const bmItem **items, unsigned int nmemb)
+bool
+bm_menu_set_items(struct bm_menu *menu, const struct bm_item **items, uint32_t nmemb)
{
assert(menu);
- int ret = _bmItemListSetItems(&menu->items, items, nmemb);
+ bool ret = list_set_items(&menu->items, items, nmemb, (list_free_fun)bm_item_free);
if (ret) {
- _bmItemListFreeList(&menu->selection);
- _bmItemListFreeList(&menu->filtered);
+ list_free_list(&menu->selection);
+ list_free_list(&menu->filtered);
}
return ret;
}
-/**
- * Get items from bmMenu instance.
- *
- * @warning The pointer returned by this function may be invalid after removing or adding new items.
- *
- * @param menu bmMenu instance from where to get items.
- * @param outNmemb Reference to unsigned int where total count of returned items will be stored.
- * @return Pointer to array of bmItem pointers.
- */
-bmItem** bmMenuGetItems(const bmMenu *menu, unsigned int *outNmemb)
+struct bm_item**
+bm_menu_get_items(const struct bm_menu *menu, uint32_t *out_nmemb)
{
assert(menu);
- return _bmItemListGetItems(&menu->items, outNmemb);
+ return list_get_items(&menu->items, out_nmemb);
}
-/**
- * Get filtered (displayed) items from bmMenu instance.
- *
- * @warning The pointer returned by this function _will_ be invalid when menu internally filters its list again.
- * Do not store this pointer.
- *
- * @param menu bmMenu instance from where to get filtered items.
- * @param outNmemb Reference to unsigned int where total count of returned items will be stored.
- * @return Pointer to array of bmItem pointers.
- */
-bmItem** bmMenuGetFilteredItems(const bmMenu *menu, unsigned int *outNmemb)
+struct bm_item**
+bm_menu_get_filtered_items(const struct bm_menu *menu, uint32_t *out_nmemb)
{
assert(menu);
if (menu->filter && strlen(menu->filter))
- return _bmItemListGetItems(&menu->filtered, outNmemb);
+ return list_get_items(&menu->filtered, out_nmemb);
- return _bmItemListGetItems(&menu->items, outNmemb);
+ return list_get_items(&menu->items, out_nmemb);
}
-/**
- * Render bmMenu instance using chosen draw method.
- *
- * @param menu bmMenu instance to be rendered.
- */
-void bmMenuRender(const bmMenu *menu)
+void
+bm_menu_render(const struct bm_menu *menu)
{
assert(menu);
- if (menu->renderApi.render)
- menu->renderApi.render(menu);
+ if (menu->renderer->api.render)
+ menu->renderer->api.render(menu);
}
-/**
- * Trigger filtering of menu manually.
- * This is useful when adding new items and want to dynamically see them filtered.
- *
- * Do note that filtering might be heavy, so you should only call it after batch manipulation of items.
- * Not after manipulation of each single item.
- *
- * @param menu bmMenu instance which to filter.
- */
-void bmMenuFilter(bmMenu *menu)
+void
+bm_menu_filter(struct bm_menu *menu)
{
assert(menu);
char addition = 0;
size_t len = (menu->filter ? strlen(menu->filter) : 0);
- if (!len || !menu->items.list || menu->items.count <= 0) {
- _bmItemListFreeList(&menu->filtered);
-
- if (menu->oldFilter)
- free(menu->oldFilter);
-
- menu->oldFilter = NULL;
+ if (!len || !menu->items.items || menu->items.count <= 0) {
+ list_free_list(&menu->filtered);
+ free(menu->old_filter);
+ menu->old_filter = NULL;
return;
}
- if (menu->oldFilter) {
- size_t oldLen = strlen(menu->oldFilter);
- addition = (oldLen < len && !memcmp(menu->oldFilter, menu->filter, oldLen));
+ if (menu->old_filter) {
+ size_t oldLen = strlen(menu->old_filter);
+ addition = (oldLen < len && !memcmp(menu->old_filter, menu->filter, oldLen));
}
- if (menu->oldFilter && addition && menu->filtered.count <= 0)
+ if (menu->old_filter && addition && menu->filtered.count <= 0)
return;
- if (menu->oldFilter && !strcmp(menu->filter, menu->oldFilter))
+ if (menu->old_filter && !strcmp(menu->filter, menu->old_filter))
return;
- unsigned int count;
- bmItem **filtered = filterFunc[menu->filterMode](menu, addition, &count);
+ uint32_t count;
+ struct bm_item **filtered = filter_func[menu->filter_mode](menu, addition, &count);
- _bmItemListSetItemsNoCopy(&menu->filtered, filtered, count);
+ list_set_items_no_copy(&menu->filtered, filtered, count);
menu->index = 0;
- if (menu->oldFilter)
- free(menu->oldFilter);
-
- menu->oldFilter = _bmStrdup(menu->filter);
+ free(menu->old_filter);
+ menu->old_filter = bm_strdup(menu->filter);
}
-/**
- * Poll key and unicode from underlying UI toolkit.
- *
- * This function will block on @link ::bmDrawMode BM_DRAW_MODE_CURSES @endlink draw mode.
- *
- * @param menu bmMenu instance from which to poll.
- * @param outUnicode Reference to unsigned int.
- * @return bmKey for polled key.
- */
-bmKey bmMenuGetKey(bmMenu *menu, unsigned int *outUnicode)
+enum bm_key
+bm_menu_poll_key(struct bm_menu *menu, uint32_t *out_unicode)
{
- assert(menu);
- assert(outUnicode);
+ assert(menu && out_unicode);
- *outUnicode = 0;
- bmKey key = BM_KEY_NONE;
+ *out_unicode = 0;
+ enum bm_key key = BM_KEY_NONE;
- if (menu->renderApi.getKey)
- key = menu->renderApi.getKey(outUnicode);
+ if (menu->renderer->api.poll_key)
+ key = menu->renderer->api.poll_key(out_unicode);
return key;
}
-/**
- * Advances menu logic with key and unicode as input.
- *
- * @param menu bmMenu instance to be advanced.
- * @param key Key input that will advance menu logic.
- * @param unicode Unicode input that will advance menu logic.
- * @return bmRunResult for menu state.
- */
-bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode)
+enum bm_run_result
+bm_menu_run_with_key(struct bm_menu *menu, enum bm_key key, uint32_t unicode)
{
assert(menu);
- unsigned int itemsCount;
- bmMenuGetFilteredItems(menu, &itemsCount);
+ uint32_t count;
+ bm_menu_get_filtered_items(menu, &count);
- unsigned int displayed = 0;
- if (menu->renderApi.displayedCount)
- displayed = menu->renderApi.displayedCount(menu);
+ uint32_t displayed = 0;
+ if (menu->renderer->api.get_displayed_count)
+ displayed = menu->renderer->api.get_displayed_count(menu);
if (!displayed)
- displayed = itemsCount;
+ displayed = count;
switch (key) {
case BM_KEY_LEFT:
if (menu->filter) {
- unsigned int oldCursor = menu->cursor;
- menu->cursor -= _bmUtf8RunePrev(menu->filter, menu->cursor);
- menu->cursesCursor -= _bmUtf8RuneWidth(menu->filter + menu->cursor, oldCursor - menu->cursor);
+ uint32_t oldCursor = menu->cursor;
+ menu->cursor -= bm_utf8_rune_prev(menu->filter, menu->cursor);
+ menu->curses_cursor -= bm_utf8_rune_width(menu->filter + menu->cursor, oldCursor - menu->cursor);
}
break;
case BM_KEY_RIGHT:
if (menu->filter) {
- unsigned int oldCursor = menu->cursor;
- menu->cursor += _bmUtf8RuneNext(menu->filter, menu->cursor);
- menu->cursesCursor += _bmUtf8RuneWidth(menu->filter + oldCursor, menu->cursor - oldCursor);
+ uint32_t oldCursor = menu->cursor;
+ menu->cursor += bm_utf8_rune_next(menu->filter, menu->cursor);
+ menu->curses_cursor += bm_utf8_rune_width(menu->filter + oldCursor, menu->cursor - oldCursor);
}
break;
case BM_KEY_HOME:
- menu->cursesCursor = menu->cursor = 0;
+ menu->curses_cursor = menu->cursor = 0;
break;
case BM_KEY_END:
menu->cursor = (menu->filter ? strlen(menu->filter) : 0);
- menu->cursesCursor = (menu->filter ? _bmUtf8StringScreenWidth(menu->filter) : 0);
+ menu->curses_cursor = (menu->filter ? bm_utf8_string_screen_width(menu->filter) : 0);
break;
case BM_KEY_UP:
if (menu->index > 0) {
menu->index--;
} else if (menu->wrap) {
- menu->index = itemsCount - 1;
+ menu->index = count - 1;
}
break;
case BM_KEY_DOWN:
- if (menu->index < itemsCount - 1) {
+ if (menu->index < count - 1) {
menu->index++;
} else if (menu->wrap) {
menu->index = 0;
@@ -616,7 +423,7 @@ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode)
break;
case BM_KEY_PAGE_DOWN:
- menu->index = (menu->index + displayed >= itemsCount ? itemsCount - 1 : menu->index + (displayed - 1));
+ menu->index = (menu->index + displayed >= count ? count - 1 : menu->index + (displayed - 1));
break;
case BM_KEY_SHIFT_PAGE_UP:
@@ -624,28 +431,28 @@ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode)
break;
case BM_KEY_SHIFT_PAGE_DOWN:
- menu->index = itemsCount - 1;
+ menu->index = count - 1;
break;
case BM_KEY_BACKSPACE:
if (menu->filter) {
size_t width;
- menu->cursor -= _bmUtf8RuneRemove(menu->filter, menu->cursor, &width);
- menu->cursesCursor -= width;
+ menu->cursor -= bm_utf8_rune_remove(menu->filter, menu->cursor, &width);
+ menu->curses_cursor -= width;
}
break;
case BM_KEY_DELETE:
if (menu->filter)
- _bmUtf8RuneRemove(menu->filter, menu->cursor + 1, NULL);
+ bm_utf8_rune_remove(menu->filter, menu->cursor + 1, NULL);
break;
case BM_KEY_LINE_DELETE_LEFT:
if (menu->filter) {
while (menu->cursor > 0) {
size_t width;
- menu->cursor -= _bmUtf8RuneRemove(menu->filter, menu->cursor, &width);
- menu->cursesCursor -= width;
+ menu->cursor -= bm_utf8_rune_remove(menu->filter, menu->cursor, &width);
+ menu->curses_cursor -= width;
}
}
break;
@@ -658,19 +465,19 @@ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode)
case BM_KEY_WORD_DELETE:
if (menu->filter) {
while (menu->cursor < strlen(menu->filter) && !isspace(menu->filter[menu->cursor])) {
- unsigned int oldCursor = menu->cursor;
- menu->cursor += _bmUtf8RuneNext(menu->filter, menu->cursor);
- menu->cursesCursor += _bmUtf8RuneWidth(menu->filter + oldCursor, menu->cursor - oldCursor);
+ uint32_t oldCursor = menu->cursor;
+ menu->cursor += bm_utf8_rune_next(menu->filter, menu->cursor);
+ menu->curses_cursor += bm_utf8_rune_width(menu->filter + oldCursor, menu->cursor - oldCursor);
}
while (menu->cursor > 0 && isspace(menu->filter[menu->cursor - 1])) {
- unsigned int oldCursor = menu->cursor;
- menu->cursor -= _bmUtf8RunePrev(menu->filter, menu->cursor);
- menu->cursesCursor -= _bmUtf8RuneWidth(menu->filter + menu->cursor, oldCursor - menu->cursor);
+ uint32_t oldCursor = menu->cursor;
+ menu->cursor -= bm_utf8_rune_prev(menu->filter, menu->cursor);
+ menu->curses_cursor -= bm_utf8_rune_width(menu->filter + menu->cursor, oldCursor - menu->cursor);
}
while (menu->cursor > 0 && !isspace(menu->filter[menu->cursor - 1])) {
size_t width;
- menu->cursor -= _bmUtf8RuneRemove(menu->filter, menu->cursor, &width);
- menu->cursesCursor -= width;
+ menu->cursor -= bm_utf8_rune_remove(menu->filter, menu->cursor, &width);
+ menu->curses_cursor -= width;
}
}
break;
@@ -678,19 +485,19 @@ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode)
case BM_KEY_UNICODE:
{
size_t width;
- menu->cursor += _bmUnicodeInsert(&menu->filter, &menu->filterSize, menu->cursor, unicode, &width);
- menu->cursesCursor += width;
+ menu->cursor += bm_unicode_insert(&menu->filter, &menu->filter_size, menu->cursor, unicode, &width);
+ menu->curses_cursor += width;
}
break;
case BM_KEY_TAB:
{
const char *text;
- bmItem *highlighted = bmMenuGetHighlightedItem(menu);
- if (highlighted && (text = bmItemGetText(highlighted))) {
- bmMenuSetFilter(menu, text);
+ struct bm_item *highlighted = bm_menu_get_highlighted_item(menu);
+ if (highlighted && (text = bm_item_get_text(highlighted))) {
+ bm_menu_set_filter(menu, text);
menu->cursor = (menu->filter ? strlen(menu->filter) : 0);
- menu->cursesCursor = (menu->filter ? _bmUtf8StringScreenWidth(menu->filter) : 0);
+ menu->curses_cursor = (menu->filter ? bm_utf8_string_screen_width(menu->filter) : 0);
}
}
break;
@@ -698,21 +505,21 @@ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode)
case BM_KEY_CONTROL_RETURN:
case BM_KEY_RETURN:
{
- bmItem *highlighted = bmMenuGetHighlightedItem(menu);
- if (highlighted && !_bmMenuItemIsSelected(menu, highlighted))
- _bmItemListAddItem(&menu->selection, highlighted);
+ struct bm_item *highlighted = bm_menu_get_highlighted_item(menu);
+ if (highlighted && !bm_menu_item_is_selected(menu, highlighted))
+ list_add_item(&menu->selection, highlighted);
}
break;
case BM_KEY_SHIFT_RETURN:
case BM_KEY_ESCAPE:
- _bmItemListFreeList(&menu->selection);
+ list_free_list(&menu->selection);
break;
default: break;
}
- bmMenuFilter(menu);
+ bm_menu_filter(menu);
switch (key) {
case BM_KEY_SHIFT_RETURN:
diff --git a/lib/renderers/CMakeLists.txt b/lib/renderers/CMakeLists.txt
new file mode 100644
index 0000000..0bc4733
--- /dev/null
+++ b/lib/renderers/CMakeLists.txt
@@ -0,0 +1,10 @@
+SET(RENDERERS
+ "curses"
+)
+
+SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/renderers)
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/..)
+FOREACH (renderer ${RENDERERS})
+ ADD_SUBDIRECTORY(${renderer})
+ENDFOREACH()
diff --git a/lib/renderers/curses/CMakeLists.txt b/lib/renderers/curses/CMakeLists.txt
new file mode 100644
index 0000000..1d2abec
--- /dev/null
+++ b/lib/renderers/curses/CMakeLists.txt
@@ -0,0 +1,6 @@
+SET(CURSES_NEED_NCURSES TRUE)
+FIND_PACKAGE(Curses)
+ADD_LIBRARY(bemenu-renderer-curses SHARED curses.c)
+SET_TARGET_PROPERTIES(bemenu-renderer-curses PROPERTIES PREFIX "")
+TARGET_LINK_LIBRARIES(bemenu-renderer-curses ${CURSES_LIBRARY})
+INSTALL(TARGETS bemenu-renderer-curses DESTINATION lib/bemenu)
diff --git a/lib/renderers/curses/curses.c b/lib/renderers/curses/curses.c
new file mode 100644
index 0000000..0ba763e
--- /dev/null
+++ b/lib/renderers/curses/curses.c
@@ -0,0 +1,379 @@
+#if __APPLE__
+# define _C99_SOURCE
+# include <stdio.h> /* vsnprintf */
+# undef _C99_SOURCE
+#endif
+
+#define _XOPEN_SOURCE 500
+#include <signal.h> /* sigaction */
+#include <stdarg.h> /* vsnprintf */
+#undef _XOPEN_SOURCE
+
+#include "internal.h"
+
+#include <wchar.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <ncurses.h>
+#include <dlfcn.h>
+#include <assert.h>
+
+#if _WIN32
+static const char *TTY = "CON";
+#else
+static const char *TTY = "/dev/tty";
+#endif
+
+/**
+ * Dynamically loaded curses API.
+ */
+static struct curses {
+ WINDOW *stdscr;
+ struct sigaction abrt_action;
+ struct sigaction segv_action;
+ struct sigaction winch_action;
+ int old_stdin;
+ int old_stdout;
+} curses;
+
+static void
+terminate(void)
+{
+ if (!curses.stdscr)
+ return;
+
+ freopen(TTY, "w", stdout);
+
+ refresh();
+ endwin();
+
+ dup2(curses.old_stdin, STDIN_FILENO);
+ dup2(curses.old_stdout, STDOUT_FILENO);
+ close(curses.old_stdin);
+ close(curses.old_stdout);
+
+ curses.stdscr = NULL;
+}
+
+static void
+crash_handler(int sig)
+{
+ (void)sig;
+ terminate();
+}
+
+static void resize_handler(int sig)
+{
+ (void)sig;
+ if (!curses.stdscr)
+ return;
+
+ endwin();
+ refresh();
+}
+
+static bool
+resize_buffer(char **buffer, size_t *osize, size_t nsize)
+{
+ assert(buffer);
+ assert(osize);
+
+ if (nsize == 0 || nsize <= *osize)
+ return false;
+
+ void *tmp;
+ if (!*buffer || !(tmp = realloc(*buffer, nsize))) {
+ if (!(tmp = malloc(nsize)))
+ return 0;
+
+ if (*buffer) {
+ memcpy(tmp, *buffer, *osize);
+ free(*buffer);
+ }
+ }
+
+ *buffer = tmp;
+ *osize = nsize;
+ return true;
+}
+
+#if __GNUC__
+__attribute__((format(printf, 3, 4)))
+#endif
+static void
+draw_line(int32_t pair, int32_t y, const char *format, ...)
+{
+ static size_t blen = 0;
+ static char *buffer = NULL;
+
+ size_t ncols;
+ if ((ncols = getmaxx(curses.stdscr)) <= 0)
+ return;
+
+ va_list args;
+ va_start(args, format);
+ size_t nlen = vsnprintf(NULL, 0, format, args);
+ va_end(args);
+
+ if ((!buffer || nlen > blen) && !resize_buffer(&buffer, &blen, nlen + 1))
+ return;
+
+ va_start(args, format);
+ vsnprintf(buffer, blen - 1, format, args);
+ va_end(args);
+
+ size_t dw = 0, i = 0;
+ while (dw < ncols && i < nlen) {
+ if (buffer[i] == '\t') buffer[i] = ' ';
+ int32_t next = bm_utf8_rune_next(buffer, i);
+ dw += bm_utf8_rune_width(buffer + i, next);
+ i += (next ? next : 1);
+ }
+
+ if (dw < ncols) {
+ /* line is too short, widen it */
+ size_t offset = i + (ncols - dw);
+ if (blen <= offset && !resize_buffer(&buffer, &blen, offset + 1))
+ return;
+
+ memset(buffer + nlen, ' ', offset - nlen);
+ buffer[offset] = 0;
+ } else if (i < blen) {
+ /* line is too long, shorten it */
+ i -= bm_utf8_rune_prev(buffer, i - (dw - ncols)) - 1;
+ size_t cc = dw - (dw - ncols);
+
+ size_t offset = i - (dw - ncols) + (ncols - cc) + 1;
+ if (blen <= offset) {
+ int32_t diff = offset - blen + 1;
+ if (!resize_buffer(&buffer, &blen, blen + diff))
+ return;
+ }
+
+ memset(buffer + i - (dw - ncols), ' ', (ncols - cc) + 1);
+ buffer[offset] = 0;
+ }
+
+ if (pair > 0)
+ attron(COLOR_PAIR(pair));
+
+ mvprintw(y, 0, "%s", buffer);
+
+ if (pair > 0)
+ attroff(COLOR_PAIR(pair));
+}
+
+static void
+render(const struct bm_menu *menu)
+{
+ if (!curses.stdscr) {
+ curses.old_stdin = dup(STDIN_FILENO);
+ curses.old_stdout = dup(STDOUT_FILENO);
+
+ freopen(TTY, "w", stdout);
+ freopen(TTY, "r", stdin);
+
+ setlocale(LC_CTYPE, "");
+
+ if ((curses.stdscr = initscr()) == NULL)
+ return;
+
+ ESCDELAY = 25;
+ flushinp();
+ keypad(curses.stdscr, true);
+ curs_set(1);
+ noecho();
+ raw();
+
+ start_color();
+ use_default_colors();
+ init_pair(1, COLOR_BLACK, COLOR_RED);
+ init_pair(2, COLOR_RED, -1);
+ }
+
+ const uint32_t lines = getmaxy(curses.stdscr);
+ erase();
+
+ uint32_t ncols = getmaxx(curses.stdscr);
+ uint32_t title_len = (menu->title ? strlen(menu->title) + 1 : 0);
+
+ if (title_len >= ncols)
+ title_len = 0;
+
+ uint32_t ccols = ncols - title_len - 1;
+ uint32_t dcols = 0, doffset = menu->cursor;
+
+ while (doffset > 0 && dcols < ccols) {
+ int prev = bm_utf8_rune_prev(menu->filter, doffset);
+ dcols += bm_utf8_rune_width(menu->filter + doffset - prev, prev);
+ doffset -= (prev ? prev : 1);
+ }
+
+ draw_line(0, 0, "%*s%s", title_len, "", (menu->filter ? menu->filter + doffset : ""));
+
+ if (menu->title && title_len > 0) {
+ attron(COLOR_PAIR(1));
+ mvprintw(0, 0, menu->title);
+ attroff(COLOR_PAIR(1));
+ }
+
+ uint32_t count, cl = 1;
+ struct bm_item **items = bm_menu_get_filtered_items(menu, &count);
+ for (uint32_t i = (menu->index / (lines - 1)) * (lines - 1); i < count && cl < lines; ++i) {
+ bool highlighted = (items[i] == bm_menu_get_highlighted_item(menu));
+ int32_t color = (highlighted ? 2 : (bm_menu_item_is_selected(menu, items[i]) ? 1 : 0));
+ draw_line(color, cl++, "%s%s", (highlighted ? ">> " : " "), (items[i]->text ? items[i]->text : ""));
+ }
+
+ move(0, title_len + (menu->curses_cursor < ccols ? menu->curses_cursor : ccols));
+ refresh();
+}
+
+static uint32_t
+get_displayed_count(const struct bm_menu *menu)
+{
+ (void)menu;
+ return (curses.stdscr ? getmaxy(curses.stdscr) : 0);
+}
+
+static enum bm_key
+poll_key(uint32_t *unicode)
+{
+ assert(unicode);
+ *unicode = 0;
+
+ if (!curses.stdscr)
+ return BM_KEY_NONE;
+
+ *unicode = getch();
+
+ switch (*unicode) {
+#if KEY_RESIZE
+ case KEY_RESIZE:
+ return BM_KEY_NONE;
+#endif
+
+ case 16: /* C-p */
+ case KEY_UP:
+ return BM_KEY_UP;
+
+ case 14: /* C-n */
+ case KEY_DOWN:
+ return BM_KEY_DOWN;
+
+ case 2: /* C-b */
+ case KEY_LEFT:
+ return BM_KEY_LEFT;
+
+ case 6: /* C-f */
+ case KEY_RIGHT:
+ return BM_KEY_RIGHT;
+
+ case 1: /* C-a */
+ case 391: /* S-Home */
+ case KEY_HOME:
+ return BM_KEY_HOME;
+
+ case 5: /* C-e */
+ case 386: /* S-End */
+ case KEY_END:
+ return BM_KEY_END;
+
+ case KEY_PPAGE: /* Page up */
+ return BM_KEY_PAGE_UP;
+
+ case KEY_NPAGE: /* Page down */
+ return BM_KEY_PAGE_DOWN;
+
+ case 550: /* C-Page up */
+ case 398: /* S-Page up */
+ return BM_KEY_SHIFT_PAGE_UP;
+
+ case 545: /* C-Page down */
+ case 396: /* S-Page down */
+ return BM_KEY_SHIFT_PAGE_DOWN;
+
+ case 8: /* C-h */
+ case 127: /* Delete */
+ case KEY_BACKSPACE:
+ return BM_KEY_BACKSPACE;
+
+ case 4: /* C-d */
+ case KEY_DC:
+ return BM_KEY_DELETE;
+
+ case 383: /* S-Del */
+ case 21: /* C-u */
+ return BM_KEY_LINE_DELETE_LEFT;
+
+ case 11: /* C-k */
+ return BM_KEY_LINE_DELETE_RIGHT;
+
+ case 23: /* C-w */
+ return BM_KEY_WORD_DELETE;
+
+ case 9: /* Tab */
+ return BM_KEY_TAB;
+
+ case 18: /* C-r */
+ return BM_KEY_CONTROL_RETURN;
+
+ case 20: /* C-t */
+ case 331: /* Insert */
+ terminate();
+ return BM_KEY_SHIFT_RETURN;
+
+ case 10: /* Return */
+ terminate();
+ return BM_KEY_RETURN;
+
+ case 7: /* C-g */
+ case 27: /* Escape */
+ terminate();
+ return BM_KEY_ESCAPE;
+
+ default: break;
+ }
+
+ return BM_KEY_UNICODE;
+}
+
+static void
+destructor(void)
+{
+ terminate();
+ sigaction(SIGABRT, &curses.abrt_action, NULL);
+ sigaction(SIGSEGV, &curses.segv_action, NULL);
+ sigaction(SIGWINCH, &curses.winch_action, NULL);
+ memset(&curses, 0, sizeof(curses));
+}
+
+static void
+constructor(void)
+{
+ memset(&curses, 0, sizeof(curses));
+
+ struct sigaction action;
+ memset(&action, 0, sizeof(struct sigaction));
+ action.sa_handler = crash_handler;
+ sigaction(SIGABRT, &action, &curses.abrt_action);
+ sigaction(SIGSEGV, &action, &curses.segv_action);
+
+ action.sa_handler = resize_handler;
+ sigaction(SIGWINCH, &action, &curses.winch_action);
+}
+
+extern const char*
+register_renderer(struct render_api *api)
+{
+ api->constructor = constructor;
+ api->destructor = destructor;
+ api->get_displayed_count = get_displayed_count;
+ api->poll_key = poll_key;
+ api->render = render;
+ return "curses";
+}
+
+/* vim: set ts=8 sw=4 tw=0 :*/
diff --git a/lib/util.c b/lib/util.c
index a47ff8d..246e102 100644
--- a/lib/util.c
+++ b/lib/util.c
@@ -1,9 +1,9 @@
-#include "internal.h"
-
#define _XOPEN_SOURCE
#include <wchar.h> /* wcswidth */
#undef _XOPEN_SOURCE
+#include "internal.h"
+
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
@@ -15,7 +15,8 @@
* @param string C "string" to copy.
* @return Copy of the given C "string".
*/
-char* _bmStrdup(const char *string)
+char*
+bm_strdup(const char *string)
{
assert(string);
@@ -34,15 +35,16 @@ char* _bmStrdup(const char *string)
* Replaces next token in string with '\0' and returns position for the replaced token.
*
* @param string C "string" where token will be replaced.
- * @param outNext Reference to position of next delimiter, or 0 if none.
+ * @param out_next Reference to position of next delimiter, or 0 if none.
* @return Position of the replaced token.
*/
-size_t _bmStripToken(char *string, const char *token, size_t *outNext)
+size_t
+bm_strip_token(char *string, const char *token, size_t *out_next)
{
size_t len = strcspn(string, token);
- if (outNext)
- *outNext = len + (string[len] != 0);
+ if (out_next)
+ *out_next = len + (string[len] != 0);
string[len] = 0;
return len;
@@ -55,9 +57,10 @@ size_t _bmStripToken(char *string, const char *token, size_t *outNext)
* @param needle C "string" to match.
* @return Less than, equal to or greater than zero if hay is lexicographically less than, equal to or greater than needle.
*/
-int _bmStrupcmp(const char *hay, const char *needle)
+int
+bm_strupcmp(const char *hay, const char *needle)
{
- return _bmStrnupcmp(hay, needle, strlen(hay));
+ return bm_strnupcmp(hay, needle, strlen(hay));
}
/**
@@ -67,15 +70,14 @@ int _bmStrupcmp(const char *hay, const char *needle)
* @param needle C "string" to match.
* @return Less than, equal to or greater than zero if hay is lexicographically less than, equal to or greater than needle.
*/
-int _bmStrnupcmp(const char *hay, const char *needle, size_t len)
+int
+bm_strnupcmp(const char *hay, const char *needle, size_t len)
{
- size_t i = 0;
- unsigned char a = 0, b = 0;
-
const unsigned char *p1 = (const unsigned char*)hay;
const unsigned char *p2 = (const unsigned char*)needle;
- for (i = 0; len > 0; --len, ++i)
+ unsigned char a = 0, b = 0;
+ for (size_t i = 0; len > 0; --len, ++i)
if ((a = toupper(*p1++)) != (b = toupper(*p2++)))
return a - b;
@@ -88,17 +90,18 @@ int _bmStrnupcmp(const char *hay, const char *needle, size_t len)
* @param hay C "string" to substring against.
* @param needle C "string" to substring.
*/
-char* _bmStrupstr(const char *hay, const char *needle)
+char*
+bm_strupstr(const char *hay, const char *needle)
{
- size_t i, r = 0, p = 0, len, len2;
+ size_t r = 0, p = 0, len, len2;
if ((len = strlen(hay)) < (len2 = strlen(needle)))
return NULL;
- if (!_bmStrnupcmp(hay, needle, len2))
+ if (!bm_strnupcmp(hay, needle, len2))
return (char*)hay;
- for (i = 0; i < len; ++i) {
+ for (size_t i = 0; i < len; ++i) {
if (p == len2)
return (char*)hay + r;
@@ -121,12 +124,13 @@ char* _bmStrupstr(const char *hay, const char *needle)
* @param string C "string" to determite.
* @return Number of columns, or -1 on failure.
*/
-int _bmUtf8StringScreenWidth(const char *string)
+int32_t
+bm_utf8_string_screen_width(const char *string)
{
assert(string);
- char *mstr = _bmStrdup(string);
- if (!mstr)
+ char *mstr;
+ if (!(mstr = bm_strdup(string)))
return strlen(string);
char *s;
@@ -142,7 +146,7 @@ int _bmUtf8StringScreenWidth(const char *string)
return len;
}
- int length = wcswidth(wstring, num_char);
+ int32_t length = wcswidth(wstring, num_char);
free(wstring);
free(mstr);
return length;
@@ -155,7 +159,8 @@ int _bmUtf8StringScreenWidth(const char *string)
* @param start Offset where to figure out next rune. (cursor)
* @return Number of bytes to next UTF8 rune.
*/
-size_t _bmUtf8RuneNext(const char *string, size_t start)
+size_t
+bm_utf8_rune_next(const char *string, size_t start)
{
assert(string);
@@ -174,7 +179,8 @@ size_t _bmUtf8RuneNext(const char *string, size_t start)
* @param start Offset where to figure out previous rune. (cursor)
* @return Number of bytes to previous UTF8 rune.
*/
-size_t _bmUtf8RunePrev(const char *string, size_t start)
+size_t
+bm_utf8_rune_prev(const char *string, size_t start)
{
assert(string);
@@ -193,12 +199,13 @@ size_t _bmUtf8RunePrev(const char *string, size_t start)
* @param u8len Byte length of the rune.
* @return Number of columns, or -1 on failure.
*/
-size_t _bmUtf8RuneWidth(const char *rune, unsigned int u8len)
+size_t
+bm_utf8_rune_width(const char *rune, uint32_t u8len)
{
assert(rune);
char mb[5] = { 0, 0, 0, 0, 0 };
memcpy(mb, rune, (u8len > 4 ? 4 : u8len));
- return _bmUtf8StringScreenWidth(mb);
+ return bm_utf8_string_screen_width(mb);
}
/**
@@ -206,24 +213,25 @@ size_t _bmUtf8RuneWidth(const char *rune, unsigned int u8len)
*
* @param string Null terminated C "string".
* @param start Start offset where to delete from. (cursor)
- * @param outRuneWidth Reference to size_t, return number of columns for removed rune, or -1 on failure.
+ * @param out_rune_width Reference to size_t, return number of columns for removed rune, or -1 on failure.
* @return Number of bytes removed from buffer.
*/
-size_t _bmUtf8RuneRemove(char *string, size_t start, size_t *outRuneWidth)
+size_t
+bm_utf8_rune_remove(char *string, size_t start, size_t *out_rune_width)
{
assert(string);
- if (outRuneWidth)
- *outRuneWidth = 0;
+ if (out_rune_width)
+ *out_rune_width = 0;
size_t len = strlen(string), oldStart = start;
if (len == 0 || len < start || !*string)
return 0;
- start -= _bmUtf8RunePrev(string, start);
+ start -= bm_utf8_rune_prev(string, start);
- if (outRuneWidth)
- *outRuneWidth = _bmUtf8RuneWidth(string + start, oldStart - start);
+ if (out_rune_width)
+ *out_rune_width = bm_utf8_rune_width(string + start, oldStart - start);
memmove(string + start, string + oldStart, len - oldStart);
string[len - (oldStart - start)] = 0;
@@ -233,68 +241,69 @@ size_t _bmUtf8RuneRemove(char *string, size_t start, size_t *outRuneWidth)
/**
* Insert UTF8 rune to buffer.
*
- * @param inOutString Reference to buffer.
- * @param inOutBufSize Reference to size of the buffer.
+ * @param in_out_string Reference to buffer.
+ * @param in_out_buf_size Reference to size of the buffer.
* @param start Start offset where to insert to. (cursor)
* @param rune Buffer to insert to string.
* @param u8len Byte length of the rune.
- * @param outRuneWidth Reference to size_t, return number of columns for inserted rune, or -1 on failure.
+ * @param out_rune_width Reference to size_t, return number of columns for inserted rune, or -1 on failure.
* @return Number of bytes inserted to buffer.
*/
-size_t _bmUtf8RuneInsert(char **inOutString, size_t *inOutBufSize, size_t start, const char *rune, unsigned int u8len, size_t *outRuneWidth)
+size_t
+bm_utf8_rune_insert(char **in_out_string, size_t *in_out_buf_size, size_t start, const char *rune, uint32_t u8len, size_t *out_rune_width)
{
- assert(inOutString);
- assert(inOutBufSize);
+ assert(in_out_string);
+ assert(in_out_buf_size);
- if (outRuneWidth)
- *outRuneWidth = 0;
+ if (out_rune_width)
+ *out_rune_width = 0;
if (u8len == 1 && !isprint(*rune))
return 0;
- size_t len = (*inOutString ? strlen(*inOutString) : 0);
- if (!*inOutString && !(*inOutString = calloc(1, (*inOutBufSize = u8len + 1))))
+ size_t len = (*in_out_string ? strlen(*in_out_string) : 0);
+ if (!*in_out_string && !(*in_out_string = calloc(1, (*in_out_buf_size = u8len + 1))))
return 0;
- if (len + u8len >= *inOutBufSize) {
+ if (len + u8len >= *in_out_buf_size) {
void *tmp;
- if (!(tmp = realloc(*inOutString, (*inOutBufSize * 2)))) {
- if (!(tmp = malloc((*inOutBufSize * 2))))
+ if (!(tmp = realloc(*in_out_string, (*in_out_buf_size * 2)))) {
+ if (!(tmp = malloc((*in_out_buf_size * 2))))
return 0;
- memcpy(tmp, *inOutString, *inOutBufSize);
- free(*inOutString);
+ memcpy(tmp, *in_out_string, *in_out_buf_size);
+ free(*in_out_string);
}
- memset(tmp + *inOutBufSize, 0, *inOutBufSize);
- *inOutString = tmp;
- *inOutBufSize *= 2;
+ memset(tmp + *in_out_buf_size, 0, *in_out_buf_size);
+ *in_out_string = tmp;
+ *in_out_buf_size *= 2;
}
- char *str = *inOutString + start;
+ char *str = *in_out_string + start;
memmove(str + u8len, str, len - start);
memcpy(str, rune, u8len);
- (*inOutString)[len + u8len] = 0;
+ (*in_out_string)[len + u8len] = 0;
- if (outRuneWidth)
- *outRuneWidth = _bmUtf8RuneWidth(rune, u8len);
+ if (out_rune_width)
+ *out_rune_width = bm_utf8_rune_width(rune, u8len);
return u8len;
}
/**
* Insert unicode character to UTF8 buffer.
*
- * @param inOutString Reference to buffer.
- * @param inOutBufSize Reference to size of the buffer.
+ * @param in_out_string Reference to buffer.
+ * @param in_out_buf_size Reference to size of the buffer.
* @param start Start offset where to insert to. (cursor)
* @param unicode Unicode character to insert.
- * @param outRuneWidth Reference to size_t, return number of columns for inserted rune, or -1 on failure.
+ * @param out_rune_width Reference to size_t, return number of columns for inserted rune, or -1 on failure.
* @return Number of bytes inserted to buffer.
*/
-size_t _bmUnicodeInsert(char **inOutString, size_t *inOutBufSize, size_t start, unsigned int unicode, size_t *outRuneWidth)
+size_t
+bm_unicode_insert(char **in_out_string, size_t *in_out_buf_size, size_t start, uint32_t unicode, size_t *out_rune_width)
{
- assert(inOutString);
- assert(inOutBufSize);
+ assert(in_out_string && in_out_buf_size);
char u8len = ((unicode < 0x80) ? 1 : ((unicode < 0x800) ? 2 : ((unicode < 0x10000) ? 3 : 4)));
char mb[5] = { 0, 0, 0, 0 };
@@ -308,7 +317,7 @@ size_t _bmUnicodeInsert(char **inOutString, size_t *inOutBufSize, size_t start,
mb[0] |= (unicode >> (i * 6 - 6));
}
- return _bmUtf8RuneInsert(inOutString, inOutBufSize, start, mb, u8len, outRuneWidth);
+ return bm_utf8_rune_insert(in_out_string, in_out_buf_size, start, mb, u8len, out_rune_width);
}
/* vim: set ts=8 sw=4 tw=0 :*/
diff --git a/lib/version.h.in b/lib/version.h.in
index 6be8b5f..9d9b851 100644
--- a/lib/version.h.in
+++ b/lib/version.h.in
@@ -1,3 +1,4 @@
+#define INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@"
static const char *BM_VERSION = "@BEMENU_VERSION@";
/* vim: set ts=8 sw=4 tw=0 :*/