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 |  | ||||||
| 				k.code.codepoint = cp + 96; |  | ||||||
| 			app_process_termo_event (&k); |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  | 	else | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	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