Compare commits
No commits in common. "2803a8153b27d1d0096207573a70d0d5e6877156" and "830a744a11a5ebdf57beedfa1bee7fcafb0cc267" have entirely different histories.
2803a8153b
...
830a744a11
@ -58,7 +58,7 @@ if (WITH_PULSE)
|
|||||||
list (APPEND extra_libraries ${libpulse_LIBRARIES})
|
list (APPEND extra_libraries ${libpulse_LIBRARIES})
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
pkg_check_modules (x11 x11 xrender xft fontconfig)
|
pkg_check_modules (x11 x11 xkbcommon xrender xft fontconfig)
|
||||||
option (WITH_X11 "Use FFTW to enable spectrum visualisation" ${x11_FOUND})
|
option (WITH_X11 "Use FFTW to enable spectrum visualisation" ${x11_FOUND})
|
||||||
if (WITH_X11)
|
if (WITH_X11)
|
||||||
if (NOT x11_FOUND)
|
if (NOT x11_FOUND)
|
||||||
|
@ -40,8 +40,8 @@ Building
|
|||||||
Build dependencies: CMake, pkg-config, asciidoctor,
|
Build dependencies: CMake, pkg-config, asciidoctor,
|
||||||
liberty (included), termo (included) +
|
liberty (included), termo (included) +
|
||||||
Runtime dependencies: ncursesw, libunistring, cURL,
|
Runtime dependencies: ncursesw, libunistring, cURL,
|
||||||
fftw3 (optional), libpulse (optional) +
|
fftw3 (optional), libpulse (optional)
|
||||||
Optional X11 dependencies: x11, xft
|
Optional X11 dependencies: x11, xkbcommon, xft
|
||||||
|
|
||||||
$ git clone --recursive https://git.janouch.name/p/nncmpp.git
|
$ git clone --recursive https://git.janouch.name/p/nncmpp.git
|
||||||
$ mkdir nncmpp/build
|
$ mkdir nncmpp/build
|
||||||
|
98
nncmpp.c
98
nncmpp.c
@ -113,6 +113,7 @@ enum
|
|||||||
#include <X11/keysym.h>
|
#include <X11/keysym.h>
|
||||||
#include <X11/XKBlib.h>
|
#include <X11/XKBlib.h>
|
||||||
#include <X11/Xft/Xft.h>
|
#include <X11/Xft/Xft.h>
|
||||||
|
#include <xkbcommon/xkbcommon.h>
|
||||||
#endif // WITH_X11
|
#endif // WITH_X11
|
||||||
|
|
||||||
#define APP_TITLE PROGRAM_NAME ///< Left top corner
|
#define APP_TITLE PROGRAM_NAME ///< Left top corner
|
||||||
@ -861,10 +862,6 @@ spectrum_free (struct spectrum *s)
|
|||||||
fftw_free (s->windowed);
|
fftw_free (s->windowed);
|
||||||
free (s->data);
|
free (s->data);
|
||||||
free (s->window);
|
free (s->window);
|
||||||
#if 0
|
|
||||||
// We don't particularly want to discard wisdom.
|
|
||||||
fftwf_cleanup ();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
free (s->rendered);
|
free (s->rendered);
|
||||||
free (s->spectrum);
|
free (s->spectrum);
|
||||||
@ -1348,8 +1345,6 @@ static struct app_context
|
|||||||
bool pulse_control_requested; ///< PulseAudio control desired by user
|
bool pulse_control_requested; ///< PulseAudio control desired by user
|
||||||
|
|
||||||
#ifdef WITH_X11
|
#ifdef WITH_X11
|
||||||
XIM x11_im; ///< Input method
|
|
||||||
XIC x11_ic; ///< Input method context
|
|
||||||
Display *dpy; ///< X display handle
|
Display *dpy; ///< X display handle
|
||||||
struct poller_fd x11_event; ///< X11 events on wire
|
struct poller_fd x11_event; ///< X11 events on wire
|
||||||
struct poller_idle xpending_event; ///< X11 events possibly in I/O queues
|
struct poller_idle xpending_event; ///< X11 events possibly in I/O queues
|
||||||
@ -5744,8 +5739,6 @@ x11_flip (void)
|
|||||||
static void
|
static void
|
||||||
x11_destroy (void)
|
x11_destroy (void)
|
||||||
{
|
{
|
||||||
XDestroyIC (g.x11_ic);
|
|
||||||
XCloseIM (g.x11_im);
|
|
||||||
XDestroyWindow (g.dpy, g.x11_window);
|
XDestroyWindow (g.dpy, g.x11_window);
|
||||||
XRenderFreePicture (g.dpy, g.x11_pixmap_picture);
|
XRenderFreePicture (g.dpy, g.x11_pixmap_picture);
|
||||||
XFreePixmap (g.dpy, g.x11_pixmap);
|
XFreePixmap (g.dpy, g.x11_pixmap);
|
||||||
@ -5755,9 +5748,6 @@ x11_destroy (void)
|
|||||||
|
|
||||||
poller_fd_reset (&g.x11_event);
|
poller_fd_reset (&g.x11_event);
|
||||||
XCloseDisplay (g.dpy);
|
XCloseDisplay (g.dpy);
|
||||||
|
|
||||||
// Xft hooks called in XCloseDisplay() don't clean up everything.
|
|
||||||
FcFini ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ui x11_ui =
|
static struct ui x11_ui =
|
||||||
@ -5853,15 +5843,12 @@ x11_convert_keysym (KeySym keysym)
|
|||||||
static void
|
static void
|
||||||
on_x11_keypress (XEvent *e)
|
on_x11_keypress (XEvent *e)
|
||||||
{
|
{
|
||||||
// A kibibyte long buffer will have to suffice for anyone.
|
|
||||||
XKeyEvent *ev = &e->xkey;
|
XKeyEvent *ev = &e->xkey;
|
||||||
char buf[1 << 10] = {}, *p = buf;
|
unsigned unconsumed_mods = 0;
|
||||||
KeySym keysym = None;
|
KeySym keysym = None;
|
||||||
Status status = 0;
|
if (!XkbLookupKeySym (g.dpy,
|
||||||
int len = Xutf8LookupString
|
(KeyCode) ev->keycode, ev->state, &unconsumed_mods, &keysym))
|
||||||
(g.x11_ic, ev, buf, sizeof buf, &keysym, &status);
|
return;
|
||||||
if (status == XBufferOverflow)
|
|
||||||
print_warning ("input method overflow");
|
|
||||||
|
|
||||||
termo_key_t key = {};
|
termo_key_t key = {};
|
||||||
if (ev->state & ShiftMask)
|
if (ev->state & ShiftMask)
|
||||||
@ -5875,37 +5862,19 @@ on_x11_keypress (XEvent *e)
|
|||||||
{
|
{
|
||||||
key.type = TERMO_TYPE_FUNCTION;
|
key.type = TERMO_TYPE_FUNCTION;
|
||||||
key.code.number = 1 + keysym - XK_F1;
|
key.code.number = 1 + keysym - XK_F1;
|
||||||
app_process_termo_event (&key);
|
|
||||||
}
|
}
|
||||||
else if ((key.code.sym = x11_convert_keysym (keysym)) != TERMO_SYM_UNKNOWN)
|
else if ((key.code.sym = x11_convert_keysym (keysym)) != TERMO_SYM_UNKNOWN)
|
||||||
{
|
|
||||||
key.type = TERMO_TYPE_KEYSYM;
|
key.type = TERMO_TYPE_KEYSYM;
|
||||||
app_process_termo_event (&key);
|
else if ((key.code.codepoint = xkb_keysym_to_utf32 (keysym)))
|
||||||
}
|
|
||||||
else if (len)
|
|
||||||
{
|
{
|
||||||
|
// Not filling in UTF-8, but xkb_keysym_to_utf8() exists.
|
||||||
key.type = TERMO_TYPE_KEY;
|
key.type = TERMO_TYPE_KEY;
|
||||||
key.modifiers &= ~TERMO_KEYMOD_SHIFT;
|
key.modifiers &= ~TERMO_KEYMOD_SHIFT;
|
||||||
|
}
|
||||||
int32_t cp = 0;
|
|
||||||
struct utf8_iter iter = { .s = buf, .len = len };
|
|
||||||
size_t cp_len = 0;
|
|
||||||
while ((cp = utf8_iter_next (&iter, &cp_len)) >= 0)
|
|
||||||
{
|
|
||||||
termo_key_t k = key;
|
|
||||||
memcpy (k.multibyte, p, MIN (cp_len, sizeof k.multibyte - 1));
|
|
||||||
p += cp_len;
|
|
||||||
|
|
||||||
// This is unfortunate, but probably in the right place.
|
|
||||||
if (cp >= 32)
|
|
||||||
k.code.codepoint = cp;
|
|
||||||
else if (ev->state & ShiftMask)
|
|
||||||
k.code.codepoint = cp + 64;
|
|
||||||
else
|
else
|
||||||
k.code.codepoint = cp + 96;
|
return;
|
||||||
app_process_termo_event (&k);
|
|
||||||
}
|
app_process_termo_event (&key);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -6006,9 +5975,6 @@ on_x11_pending (void *user_data)
|
|||||||
{
|
{
|
||||||
if (XNextEvent (g.dpy, &ev.core))
|
if (XNextEvent (g.dpy, &ev.core))
|
||||||
exit_fatal ("XNextEvent returned non-zero");
|
exit_fatal ("XNextEvent returned non-zero");
|
||||||
if (XFilterEvent (&ev.core, None))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
on_x11_event (&ev.core);
|
on_x11_event (&ev.core);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6127,18 +6093,11 @@ x11_init_fonts (void)
|
|||||||
static void
|
static void
|
||||||
x11_init (void)
|
x11_init (void)
|
||||||
{
|
{
|
||||||
// https://tedyin.com/posts/a-brief-intro-to-linux-input-method-framework/
|
|
||||||
if (!XSupportsLocale ())
|
|
||||||
print_warning ("locale not supported by Xlib");
|
|
||||||
XSetLocaleModifiers ("");
|
|
||||||
|
|
||||||
if (!(g.dpy = XkbOpenDisplay
|
if (!(g.dpy = XkbOpenDisplay
|
||||||
(NULL, &g.xkb_base_event_code, NULL, NULL, NULL, NULL)))
|
(NULL, &g.xkb_base_event_code, NULL, NULL, NULL, NULL)))
|
||||||
exit_fatal ("cannot open display");
|
exit_fatal ("cannot open display");
|
||||||
if (!XftDefaultHasRender (g.dpy))
|
if (!XftDefaultHasRender (g.dpy))
|
||||||
exit_fatal ("XRender is not supported");
|
exit_fatal ("XRender is not supported");
|
||||||
if (!(g.x11_im = XOpenIM (g.dpy, NULL, NULL, NULL)))
|
|
||||||
exit_fatal ("failed to open an input method");
|
|
||||||
|
|
||||||
x11_default_error_handler = XSetErrorHandler (on_x11_error);
|
x11_default_error_handler = XSetErrorHandler (on_x11_error);
|
||||||
|
|
||||||
@ -6184,14 +6143,16 @@ x11_init (void)
|
|||||||
g.ui_height = 24 * g.ui_vunit;
|
g.ui_height = 24 * g.ui_vunit;
|
||||||
g.ui_width = g.ui_height * 4 / 3;
|
g.ui_width = g.ui_height * 4 / 3;
|
||||||
|
|
||||||
long im_event_mask = 0;
|
|
||||||
if (!XGetIMValues (g.x11_im, XNFilterEvents, &im_event_mask, NULL))
|
|
||||||
attrs.event_mask |= im_event_mask;
|
|
||||||
|
|
||||||
Visual *visual = DefaultVisual (g.dpy, screen);
|
Visual *visual = DefaultVisual (g.dpy, screen);
|
||||||
g.x11_window = XCreateWindow (g.dpy, RootWindow (g.dpy, screen), 100, 100,
|
g.x11_window = XCreateWindow (g.dpy, RootWindow (g.dpy, screen), 100, 100,
|
||||||
g.ui_width, g.ui_height, 0, CopyFromParent, InputOutput, visual,
|
g.ui_width, g.ui_height, 0, CopyFromParent, InputOutput, visual,
|
||||||
CWEventMask | CWBackPixel | CWBitGravity, &attrs);
|
CWEventMask | CWBackPixel | CWBitGravity, &attrs);
|
||||||
|
g.x11_pixmap = XCreatePixmap (g.dpy, g.x11_window, g.ui_width, g.ui_height,
|
||||||
|
DefaultDepth (g.dpy, screen));
|
||||||
|
|
||||||
|
x11_init_pixmap ();
|
||||||
|
g.xft_draw = XftDrawCreate (g.dpy, g.x11_pixmap, visual, cmap);
|
||||||
|
g.ui = &x11_ui;
|
||||||
|
|
||||||
XTextProperty prop = {};
|
XTextProperty prop = {};
|
||||||
char *name = PROGRAM_NAME;
|
char *name = PROGRAM_NAME;
|
||||||
@ -6199,31 +6160,6 @@ x11_init (void)
|
|||||||
XSetWMName (g.dpy, g.x11_window, &prop);
|
XSetWMName (g.dpy, g.x11_window, &prop);
|
||||||
XFree (prop.value);
|
XFree (prop.value);
|
||||||
|
|
||||||
// TODO: It is possible to do, e.g., on-the-spot.
|
|
||||||
XIMStyle im_style = XIMPreeditNothing | XIMStatusNothing;
|
|
||||||
XIMStyles *im_styles = NULL;
|
|
||||||
bool im_style_found = false;
|
|
||||||
if (!XGetIMValues (g.x11_im, XNQueryInputStyle, &im_styles, NULL)
|
|
||||||
&& im_styles)
|
|
||||||
{
|
|
||||||
for (unsigned i = 0; i < im_styles->count_styles; i++)
|
|
||||||
im_style_found |= im_styles->supported_styles[i] == im_style;
|
|
||||||
XFree (im_styles);
|
|
||||||
}
|
|
||||||
if (!im_style_found)
|
|
||||||
print_warning ("failed to find the desired input method style");
|
|
||||||
if (!(g.x11_ic = XCreateIC (g.x11_im,
|
|
||||||
XNInputStyle, im_style,
|
|
||||||
XNClientWindow, g.x11_window,
|
|
||||||
NULL)))
|
|
||||||
exit_fatal ("failed to open an input context");
|
|
||||||
|
|
||||||
XSetICFocus (g.x11_ic);
|
|
||||||
|
|
||||||
x11_init_pixmap ();
|
|
||||||
g.xft_draw = XftDrawCreate (g.dpy, g.x11_pixmap, visual, cmap);
|
|
||||||
g.ui = &x11_ui;
|
|
||||||
|
|
||||||
XMapWindow (g.dpy, g.x11_window);
|
XMapWindow (g.dpy, g.x11_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user