diff --git a/.gitignore b/.gitignore index a3f07ae9..3de3fa75 100644 --- a/.gitignore +++ b/.gitignore @@ -142,4 +142,5 @@ WPrefs.app/WPrefs.desktop .pc # Rust stuff. -/*/target/** +/**/target/** +WINGs/wings-rs/src/WINGsP.rs diff --git a/Makefile.am b/Makefile.am index 10837d32..0a50bf18 100644 --- a/Makefile.am +++ b/Makefile.am @@ -39,7 +39,7 @@ ACLOCAL_AMFLAGS = -I m4 AM_DISTCHECK_CONFIGURE_FLAGS = --enable-silent-rules LINGUAS='*' -SUBDIRS = wrlib wutil-rs wings-rs WINGs wmaker-rs src util po WindowMaker wmlib WPrefs.app doc +SUBDIRS = wrlib wutil-rs WINGs wmaker-rs src util po WindowMaker wmlib WPrefs.app doc DIST_SUBDIRS = $(SUBDIRS) test EXTRA_DIST = TODO BUGS BUGFORM FAQ INSTALL \ diff --git a/WINGs/Makefile.am b/WINGs/Makefile.am index 8a1a839e..6b086343 100644 --- a/WINGs/Makefile.am +++ b/WINGs/Makefile.am @@ -2,7 +2,7 @@ AUTOMAKE_OPTIONS = -SUBDIRS = WINGs . po Documentation Resources +SUBDIRS = WINGs wings-rs . po Documentation Resources DIST_SUBDIRS = $(SUBDIRS) Tests Examples Extras libWINGs_la_LDFLAGS = -version-info @WINGS_VERSION@ @@ -41,7 +41,6 @@ libWINGs_la_SOURCES = \ wevent.c \ wfilepanel.c \ wframe.c \ - wfont.c \ wfontpanel.c \ widgets.c \ winputmethod.c \ diff --git a/WINGs/WINGs/WINGs.h b/WINGs/WINGs/WINGs.h index 2d2b3a8e..c6f638ff 100644 --- a/WINGs/WINGs/WINGs.h +++ b/WINGs/WINGs/WINGs.h @@ -778,12 +778,8 @@ void WMSetViewDragDestinationProcs(WMView *view, WMDragDestinationProcs *procs); /* ---[ WINGs/wfont.c ]--------------------------------------------------- */ -Bool WMIsAntialiasingEnabled(WMScreen *scrPtr); - WMFont* WMCreateFont(WMScreen *scrPtr, const char *fontName); -WMFont* WMCopyFontWithStyle(WMScreen *scrPtr, WMFont *font, WMFontStyle style); - WMFont* WMRetainFont(WMFont *font); void WMReleaseFont(WMFont *font); @@ -792,12 +788,10 @@ char* WMGetFontName(WMFont *font); unsigned int WMFontHeight(WMFont *font); +unsigned int WMFontAscent(WMFont *font); + void WMGetScaleBaseFromSystemFont(WMScreen *scrPtr, int *alphabetWidth, int *fontHeight); -void WMSetWidgetDefaultFont(WMScreen *scr, WMFont *font); - -void WMSetWidgetDefaultBoldFont(WMScreen *scr, WMFont *font); - WMFont* WMDefaultSystemFont(WMScreen *scrPtr); WMFont* WMDefaultBoldSystemFont(WMScreen *scrPtr); @@ -815,6 +809,8 @@ void WMDrawImageString(WMScreen *scr, Drawable d, WMColor *color, int WMWidthOfString(WMFont *font, const char *text, int length); +struct _XftFont *WMFontXftFont(WMFont *font); + /* ---[ WINGs/wpixmap.c ]------------------------------------------------- */ WMPixmap* WMRetainPixmap(WMPixmap *pixmap); diff --git a/WINGs/WINGs/WINGsP.h.in b/WINGs/WINGs/WINGsP.h.in index a0020989..031d9ef3 100644 --- a/WINGs/WINGs/WINGsP.h.in +++ b/WINGs/WINGs/WINGsP.h.in @@ -152,11 +152,11 @@ typedef struct W_Screen { GC drawImStringGC; /* for WMDrawImageString() */ - struct W_Font *normalFont; + WMFont *normalFont; - struct W_Font *boldFont; + WMFont *boldFont; - WMHashTable *fontCache; + void *fontCache; /* owned/maintainted by wings-rs/src/screen.rs */ Bool antialiasedText; @@ -441,24 +441,6 @@ typedef struct W_EventHandler { void W_CallDestroyHandlers(W_View *view); -/* ---[ wfont.c ]--------------------------------------------------------- */ - -typedef struct W_Font { - struct W_Screen *screen; - - struct _XftFont *font; - - short height; - short y; - short refCount; - char *name; - -@USE_PANGO@ PangoLayout *layout; -} W_Font; - -#define W_FONTID(f) (f)->font->fid - - /* ---[ widgets.c ]------------------------------------------------------- */ #define WC_UserWidget 128 @@ -504,7 +486,7 @@ void W_DrawReliefWithGC(W_Screen *scr, Drawable d, int x, int y, GC black, GC dark, GC light, GC white); void W_PaintTextAndImage(W_View *view, int wrap, WMColor *textColor, - W_Font *font, WMReliefType relief, const char *text, + WMFont *font, WMReliefType relief, const char *text, WMAlignment alignment, W_Pixmap *image, WMImagePosition position, WMColor *backColor, int ofs); diff --git a/WINGs/wfont.c b/WINGs/wfont.c deleted file mode 100644 index 52af4bfc..00000000 --- a/WINGs/wfont.c +++ /dev/null @@ -1,433 +0,0 @@ - -#include - -#include "wconfig.h" - -#include "WINGsP.h" - -#include -#include -#include - -#include -#include - -#ifdef USE_PANGO -#include -#include -#include -#endif - -#define DEFAULT_FONT "sans serif:pixelsize=12" - -#define DEFAULT_SIZE WINGsConfiguration.defaultFontSize - -static FcPattern *xlfdToFcPattern(const char *xlfd) -{ - FcPattern *pattern; - char *fname, *ptr; - - /* Just skip old font names that contain %d in them. - * We don't support that anymore. */ - if (strchr(xlfd, '%') != NULL) - return FcNameParse((FcChar8 *) DEFAULT_FONT); - - fname = wstrdup(xlfd); - if ((ptr = strchr(fname, ','))) { - *ptr = 0; - } - pattern = XftXlfdParse(fname, False, False); - wfree(fname); - - if (!pattern) { - wwarning(_("invalid font: %s. Trying '%s'"), xlfd, DEFAULT_FONT); - pattern = FcNameParse((FcChar8 *) DEFAULT_FONT); - } - - return pattern; -} - -static char *xlfdToFcName(const char *xlfd) -{ - FcPattern *pattern; - char *fname; - char *result; - - pattern = xlfdToFcPattern(xlfd); - fname = (char *)FcNameUnparse(pattern); - result = wstrdup(fname); - free(fname); - FcPatternDestroy(pattern); - - return result; -} - -static Bool hasProperty(FcPattern * pattern, const char *property) -{ - FcValue val; - - if (FcPatternGet(pattern, property, 0, &val) == FcResultMatch) { - return True; - } - - return False; -} - -static Bool hasPropertyWithStringValue(FcPattern * pattern, const char *object, const char *value) -{ - FcChar8 *str; - int id; - - if (!value || value[0] == 0) - return True; - - id = 0; - while (FcPatternGetString(pattern, object, id, &str) == FcResultMatch) { - if (strcasecmp(value, (char *)str) == 0) { - return True; - } - id++; - } - - return False; -} - -static char *makeFontOfSize(const char *font, int size, const char *fallback) -{ - FcPattern *pattern; - char *name; - char *result; - - if (font[0] == '-') { - pattern = xlfdToFcPattern(font); - } else { - pattern = FcNameParse((const FcChar8 *) font); - } - - /*FcPatternPrint(pattern); */ - - if (size > 0) { - FcPatternDel(pattern, FC_PIXEL_SIZE); - FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)size); - } else if (size == 0 && !hasProperty(pattern, "size") && !hasProperty(pattern, FC_PIXEL_SIZE)) { - FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)DEFAULT_SIZE); - } - - if (fallback && !hasPropertyWithStringValue(pattern, FC_FAMILY, fallback)) { - FcPatternAddString(pattern, FC_FAMILY, (const FcChar8 *) fallback); - } - - /*FcPatternPrint(pattern); */ - - name = (char *)FcNameUnparse(pattern); - result = wstrdup(name); - free(name); - FcPatternDestroy(pattern); - - return result; -} - -WMFont *WMCreateFont(WMScreen * scrPtr, const char *fontName) -{ - Display *display = scrPtr->display; - WMFont *font; - char *fname; -#ifdef USE_PANGO - PangoFontMap *fontmap; - PangoContext *context; - PangoLayout *layout; - FcPattern *pattern; - PangoFontDescription *description; - double size; -#endif - - if (fontName[0] == '-') { - fname = xlfdToFcName(fontName); - } else { - fname = wstrdup(fontName); - } - - if (!WINGsConfiguration.antialiasedText && !strstr(fname, ":antialias=")) { - fname = wstrappend(fname, ":antialias=false"); - } - - font = WMHashGet(scrPtr->fontCache, fname); - if (font) { - WMRetainFont(font); - wfree(fname); - return font; - } - - font = wmalloc(sizeof(WMFont)); - - font->screen = scrPtr; - - font->font = XftFontOpenName(display, scrPtr->screen, fname); - if (!font->font) { - wfree(font); - wfree(fname); - return NULL; - } - - font->height = font->font->ascent + font->font->descent; - font->y = font->font->ascent; - - font->refCount = 1; - - font->name = fname; - -#ifdef USE_PANGO - fontmap = pango_xft_get_font_map(scrPtr->display, scrPtr->screen); - context = pango_font_map_create_context(fontmap); - layout = pango_layout_new(context); - - pattern = FcNameParse((FcChar8 *) font->name); - description = pango_fc_font_description_from_pattern(pattern, FALSE); - - /* Pango examines FC_SIZE but not FC_PIXEL_SIZE of the patten, but - * font-name has only "pixelsize", so set the size manually here. - */ - if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &size) == FcResultMatch) - pango_font_description_set_absolute_size(description, size * PANGO_SCALE); - - pango_layout_set_font_description(layout, description); - - font->layout = layout; -#endif - - assert(WMHashInsert(scrPtr->fontCache, font->name, font) == NULL); - - return font; -} - -WMFont *WMRetainFont(WMFont * font) -{ - wassertrv(font != NULL, NULL); - - font->refCount++; - - return font; -} - -void WMReleaseFont(WMFont * font) -{ - wassertr(font != NULL); - - font->refCount--; - if (font->refCount < 1) { - XftFontClose(font->screen->display, font->font); - if (font->name) { - WMHashRemove(font->screen->fontCache, font->name); - wfree(font->name); - } - wfree(font); - } -} - -Bool WMIsAntialiasingEnabled(WMScreen * scrPtr) -{ - return scrPtr->antialiasedText; -} - -unsigned int WMFontHeight(WMFont * font) -{ - wassertrv(font != NULL, 0); - - return font->height; -} - -char *WMGetFontName(WMFont * font) -{ - wassertrv(font != NULL, NULL); - - return font->name; -} - -void WMGetScaleBaseFromSystemFont(WMScreen *scrPtr, int *alphabetWidth, int *fontHeight) -{ - WMFont *font; - - font = WMDefaultSystemFont(scrPtr); - *alphabetWidth = WMWidthOfString(font, "abcdefghijklmnopqrstuvwxyz", 26); - *fontHeight = WMFontHeight(font); - WMReleaseFont(font); -} - -WMFont *WMDefaultSystemFont(WMScreen * scrPtr) -{ - return WMRetainFont(scrPtr->normalFont); -} - -WMFont *WMDefaultBoldSystemFont(WMScreen * scrPtr) -{ - return WMRetainFont(scrPtr->boldFont); -} - -WMFont *WMSystemFontOfSize(WMScreen * scrPtr, int size) -{ - WMFont *font; - char *fontSpec; - - fontSpec = makeFontOfSize(WINGsConfiguration.systemFont, size, NULL); - - font = WMCreateFont(scrPtr, fontSpec); - - if (!font) { - wwarning(_("could not load font: %s."), fontSpec); - } - - wfree(fontSpec); - - return font; -} - -WMFont *WMBoldSystemFontOfSize(WMScreen * scrPtr, int size) -{ - WMFont *font; - char *fontSpec; - - fontSpec = makeFontOfSize(WINGsConfiguration.boldSystemFont, size, NULL); - - font = WMCreateFont(scrPtr, fontSpec); - - if (!font) { - wwarning(_("could not load font: %s."), fontSpec); - } - - wfree(fontSpec); - - return font; -} - -int WMWidthOfString(WMFont * font, const char *text, int length) -{ -#ifdef USE_PANGO - const char *previous_text; - int width; -#else - XGlyphInfo extents; -#endif - - wassertrv(font != NULL && text != NULL, 0); -#ifdef USE_PANGO - previous_text = pango_layout_get_text(font->layout); - if ((previous_text == NULL) || (strncmp(text, previous_text, length) != 0) || previous_text[length] != '\0') - pango_layout_set_text(font->layout, text, length); - pango_layout_get_pixel_size(font->layout, &width, NULL); - - return width; -#else - XftTextExtentsUtf8(font->screen->display, font->font, (XftChar8 *) text, length, &extents); - - return extents.xOff; /* don't ask :P */ -#endif -} - -void WMDrawString(WMScreen * scr, Drawable d, WMColor * color, WMFont * font, int x, int y, const char *text, int length) -{ - XftColor xftcolor; -#ifdef USE_PANGO - const char *previous_text; -#endif - - wassertr(font != NULL); - - xftcolor.color.red = color->color.red; - xftcolor.color.green = color->color.green; - xftcolor.color.blue = color->color.blue; - xftcolor.color.alpha = color->alpha;; - xftcolor.pixel = W_PIXEL(color); - - XftDrawChange(scr->xftdraw, d); - -#ifdef USE_PANGO - previous_text = pango_layout_get_text(font->layout); - if ((previous_text == NULL) || (strcmp(text, previous_text) != 0)) - pango_layout_set_text(font->layout, text, length); - pango_xft_render_layout(scr->xftdraw, &xftcolor, font->layout, x * PANGO_SCALE, y * PANGO_SCALE); -#else - XftDrawStringUtf8(scr->xftdraw, &xftcolor, font->font, x, y + font->y, (XftChar8 *) text, length); -#endif -} - -void -WMDrawImageString(WMScreen * scr, Drawable d, WMColor * color, WMColor * background, - WMFont * font, int x, int y, const char *text, int length) -{ - XftColor textColor; - XftColor bgColor; -#ifdef USE_PANGO - const char *previous_text; -#endif - - wassertr(font != NULL); - - textColor.color.red = color->color.red; - textColor.color.green = color->color.green; - textColor.color.blue = color->color.blue; - textColor.color.alpha = color->alpha;; - textColor.pixel = W_PIXEL(color); - - bgColor.color.red = background->color.red; - bgColor.color.green = background->color.green; - bgColor.color.blue = background->color.blue; - bgColor.color.alpha = background->alpha;; - bgColor.pixel = W_PIXEL(background); - - XftDrawChange(scr->xftdraw, d); - - XftDrawRect(scr->xftdraw, &bgColor, x, y, WMWidthOfString(font, text, length), font->height); - -#ifdef USE_PANGO - previous_text = pango_layout_get_text(font->layout); - if ((previous_text == NULL) || (strcmp(text, previous_text) != 0)) - pango_layout_set_text(font->layout, text, length); - pango_xft_render_layout(scr->xftdraw, &textColor, font->layout, x * PANGO_SCALE, y * PANGO_SCALE); -#else - XftDrawStringUtf8(scr->xftdraw, &textColor, font->font, x, y + font->y, (XftChar8 *) text, length); -#endif -} - -WMFont *WMCopyFontWithStyle(WMScreen * scrPtr, WMFont * font, WMFontStyle style) -{ - FcPattern *pattern; - WMFont *copy; - char *name; - - if (!font) - return NULL; - - /* It's enough to add italic to slant, even if the font has no italic - * variant, but only oblique. This is because fontconfig will actually - * return the closest match font to what we requested which is the - * oblique font. Same goes for using bold for weight. - */ - pattern = FcNameParse((FcChar8 *) WMGetFontName(font)); - switch (style) { - case WFSNormal: - FcPatternDel(pattern, FC_WEIGHT); - FcPatternDel(pattern, FC_SLANT); - break; - case WFSBold: - FcPatternDel(pattern, FC_WEIGHT); - FcPatternAddString(pattern, FC_WEIGHT, (FcChar8 *) "bold"); - break; - case WFSItalic: - FcPatternDel(pattern, FC_SLANT); - FcPatternAddString(pattern, FC_SLANT, (FcChar8 *) "italic"); - break; - case WFSBoldItalic: - FcPatternDel(pattern, FC_WEIGHT); - FcPatternDel(pattern, FC_SLANT); - FcPatternAddString(pattern, FC_WEIGHT, (FcChar8 *) "bold"); - FcPatternAddString(pattern, FC_SLANT, (FcChar8 *) "italic"); - break; - } - - name = (char *)FcNameUnparse(pattern); - copy = WMCreateFont(scrPtr, name); - FcPatternDestroy(pattern); - free(name); - - return copy; -} diff --git a/WINGs/widgets.c b/WINGs/widgets.c index e0434f5f..35cafa85 100644 --- a/WINGs/widgets.c +++ b/WINGs/widgets.c @@ -629,7 +629,8 @@ WMScreen *WMCreateScreenWithRContext(Display * display, int screen, RContext * c scrPtr->rootWin = RootWindow(display, screen); - scrPtr->fontCache = WMCreateStringHashTable(); + // Will be initialized lazily in wings-rs/src/screen.rs. + scrPtr->fontCache = NULL; scrPtr->xftdraw = XftDrawCreate(scrPtr->display, W_DRAWABLE(scrPtr), scrPtr->visual, scrPtr->colormap); @@ -909,18 +910,6 @@ WMScreen *WMCreateScreenWithRContext(Display * display, int screen, RContext * c return scrPtr; } -void WMSetWidgetDefaultFont(WMScreen * scr, WMFont * font) -{ - WMReleaseFont(scr->normalFont); - scr->normalFont = WMRetainFont(font); -} - -void WMSetWidgetDefaultBoldFont(WMScreen * scr, WMFont * font) -{ - WMReleaseFont(scr->boldFont); - scr->boldFont = WMRetainFont(font); -} - void WMHangData(WMWidget * widget, void *data) { W_VIEW(widget)->hangedData = data; diff --git a/WINGs/wings-rs/Cargo.toml b/WINGs/wings-rs/Cargo.toml new file mode 100644 index 00000000..689a9201 --- /dev/null +++ b/WINGs/wings-rs/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "wings-rs" +version = "0.1.0" +edition = "2024" + +[lib] +crate-type = ["staticlib"] + +[dependencies] +libc = "0.2.177" +pango-sys = "0.21.2" +wutil-rs = { path = "../../wutil-rs" } +x11 = "2.21.0" +yeslogic-fontconfig-sys = "6.0" diff --git a/WINGs/wings-rs/Makefile.am b/WINGs/wings-rs/Makefile.am new file mode 100644 index 00000000..73afa18a --- /dev/null +++ b/WINGs/wings-rs/Makefile.am @@ -0,0 +1,28 @@ +AUTOMAKE_OPTIONS = + +RUST_SOURCES = \ + src/WINGsP.rs \ + src/configuration.rs \ + src/font.rs \ + src/lib.rs \ + src/pango_extras.rs \ + src/screen.rs + +RUST_EXTRA = \ + Cargo.lock \ + Cargo.toml + +src/WINGsP.rs: ../WINGs/WINGsP.h ../../wrlib/wraster.h ../WINGs/WINGs.h ../WINGs/WUtil.h Makefile patch_WINGsP.sh + $(BINDGEN) ../WINGs/WINGsP.h --ignore-functions --allowlist-type "^W_.+|^WM(View|Array|DragOperationType|Point|Data|OpenPanel|SavePanel|HashTable|DraggingInfo|SelectionProcs|Rect|EventProc|Widget|Size|Color|Pixmap|FilePanel)|R(Context|ContextAttributes|Image|RenderingMode|ScalingFilter|StdColormapMode|ImageFormat|Color)|_WINGsConfiguration" --no-recursive-allowlist -o src/WINGsP.rs -- @PANGO_CFLAGS@ -I../../wrlib -I.. && ./patch_WINGsP.sh src/WINGsP.rs + +target/debug/libwings_rs.a: $(RUST_SOURCES) $(RUST_EXTRA) + $(CARGO) build + +check-local: + $(CARGO) test + +clean-local: + $(CARGO) clean + rm -f src/WINGsP.rs + +all: target/debug/libwings_rs.a diff --git a/WINGs/wings-rs/patch_WINGsP.sh b/WINGs/wings-rs/patch_WINGsP.sh new file mode 100755 index 00000000..5475b133 --- /dev/null +++ b/WINGs/wings-rs/patch_WINGsP.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +# This file provides ad-hoc fixups to the WINGsP provided by bindgen: +# - Import Xlib symbols so that everything compiles. +# - The opaque type names _XftDraw and _XftFont are replaced with void*. +# - Pango bindings aren't yet pulled into our Rust code, so PangoLayout is also demoted to void*. + +set -e + +if [ "x$1" = "x" ]; then + echo "Usage: $(basename $0) " + exit 1 +fi + +FILE="$1" + +exec sed -i -r \ + -e "1s/^/use x11::xlib::*;\nuse crate::font::ffi::WMFont;\n\n/" \ + -e "s/_XftDraw/::std::ffi::c_void/g" \ + -e "s/_XftFont/::std::ffi::c_void/g" \ + -e "s/PangoLayout/::std::ffi::c_void/g" \ + "$1" diff --git a/WINGs/wings-rs/src/configuration.rs b/WINGs/wings-rs/src/configuration.rs new file mode 100644 index 00000000..4a70bb55 --- /dev/null +++ b/WINGs/wings-rs/src/configuration.rs @@ -0,0 +1,66 @@ +//! Global WINGs configuration. +//! +//! Use [`Configuration::global`] to get a snapshot of current configuration +//! settings. +//! +//! ## Rust rewrite notes +//! +//! This accesses a global that is defined in C code. Once more of WINGs is +//! migrated to Rust, we should use a different approach that is more +//! Rust-friendly. Threading a configuration object down the stack is a likely +//! way to go. + +use crate::WINGsP::_WINGsConfiguration; + +use std::{ffi::CStr, ptr::NonNull}; + +unsafe extern "C" { + static WINGsConfiguration: _WINGsConfiguration; +} + +#[derive(Clone, Copy, Debug)] +pub struct Configuration { + pub system_font: &'static CStr, + pub bold_system_font: &'static CStr, + pub default_font_size: u16, + pub antialiased_text: bool, + pub floppy_path: &'static CStr, + pub double_click_delay: u32, + pub mouse_wheel_up: u32, + pub mouse_wheel_down: u32, +} + +impl Configuration { + /// Returns the current WINGs configuration. Returns `None` if the + /// configuration appears not to have been loaded. + /// + /// This should only be called after `W_ReadConfigurations` is called + /// (presumably when initializing WINGs in C code), but it should be safe to + /// call it at any time. (It may just contain nonsense values.) + /// + /// ## Rust rewrite notes + /// + /// We should migrate away from a static global and thread a configuration + /// object in some other way. + pub fn global() -> Option { + let c = unsafe { &WINGsConfiguration }; + let system_font = unsafe { CStr::from_ptr(NonNull::new(c.systemFont)?.as_ptr()) }; + let bold_system_font = unsafe { CStr::from_ptr(NonNull::new(c.boldSystemFont)?.as_ptr()) }; + let default_font_size = u16::try_from(c.defaultFontSize).ok()?; + let antialiased_text = c.antialiasedText != 0; + let floppy_path = unsafe { CStr::from_ptr(NonNull::new(c.floppyPath)?.as_ptr()) }; + let double_click_delay = u32::try_from(c.doubleClickDelay).ok()?; + let mouse_wheel_up = u32::try_from(c.mouseWheelUp).ok()?; + let mouse_wheel_down = u32::try_from(c.mouseWheelDown).ok()?; + Some(Configuration { + system_font, + bold_system_font, + default_font_size, + antialiased_text, + floppy_path, + double_click_delay, + mouse_wheel_up, + mouse_wheel_down, + }) + } +} diff --git a/WINGs/wings-rs/src/font.rs b/WINGs/wings-rs/src/font.rs new file mode 100644 index 00000000..605aecc4 --- /dev/null +++ b/WINGs/wings-rs/src/font.rs @@ -0,0 +1,586 @@ +use crate::pango_extras; + +use std::{ + ffi::{CStr, CString, c_double, c_int, c_uint, c_void}, + ptr::NonNull, + rc::Rc, +}; + +use crate::configuration::Configuration; + +pub const DEFAULT_FONT: &'static str = "sans serif:pixelsize=12"; +pub const DEFAULT_FONT_CSTR: &'static CStr = c"sans serif:pixelsize=12"; + +/// A loaded font, with support for basic drawing operations. +/// +/// This owns Pango rendering state, and draw operations may mutate it. As a +/// result, this is not at all thread-safe. +/// +/// ## Rust rewrite notes +/// +/// Unlike the original C API, font caching is handled by methods on +/// [`W_Screen`]. +pub struct Font { + name: FontName, + font: NonNull, + height: c_uint, + ascent: c_uint, + layout: NonNull, +} + +/// Attempts to convert `xlfd` to a Fontconfig pattern. Returns `None` if this +/// cannot be accomplished (e.g., `xlfd` could not be parsed). +fn xlfd_to_fc_pattern(xlfd: &str) -> Option> { + if xlfd.contains('%') { + return NonNull::new(unsafe { + fontconfig_sys::FcNameParse(DEFAULT_FONT_CSTR.as_ptr()).cast::() + }); + } + + let name = xlfd.split(',').next().unwrap(); + let ignore_scalable = 0; + let complete = 0; + NonNull::new(unsafe { + x11::xft::XftXlfdParse( + name.as_ptr(), + ignore_scalable, + complete, + ) + }) + .or_else(|| { + // TODO: warn. + NonNull::new(unsafe { + x11::xft::XftXlfdParse( + DEFAULT_FONT_CSTR.as_ptr(), + ignore_scalable, + complete, + ) + }) + }) +} + +/// A font name, with support for X logical font descriptions (like +/// `-bitstream-charter-medium-r-normal--12-120-75-75-p-68-iso8859-1`, including +/// `*`-style wildcards but not old-style `%d` tokens) and Fontconfig +/// descriptions (like `sans serif:pixelsize=12`). +/// +/// Data is held in a [`std::rc::Rc`], so copies are lightweight, and ownership +/// may be shared between multiple objects (e.g., keying a hashtable and +/// referenced by hashtable values). +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub struct FontName(Rc); + +impl FontName { + /// Tries to interpret `name` as an XLFD or Fontconfig name. Returns an + /// instantiated `FontName` if this succeeds, or `None`. + pub fn new(name: &str) -> Option { + let name = if name.starts_with('-') { + let pattern = xlfd_to_fc_pattern(name)?; + let name = unsafe { fontconfig_sys::FcNameUnparse(pattern.as_ptr().cast::()) }; + let name = NonNull::new(name)?; + let result = unsafe { CStr::from_ptr(name.as_ptr()) }.to_str().ok()?; + unsafe { + libc::free(name.as_ptr().cast::()); + fontconfig_sys::FcPatternDestroy(pattern.as_ptr().cast::()); + } + result + } else { + name + }; + if !Configuration::global() + .map(|c| c.antialiased_text) + .unwrap_or(false) + && !name.contains(":antialias=") + { + let mut name = String::from(name); + name += ":antialias=false"; + Some(FontName(Rc::from(CString::new(name).ok()?))) + } else { + Some(FontName(Rc::from(CString::new(name).ok()?))) + } + } + + /// Returns a C-style string owned by this object that names the font in a + /// way that is suitable for `x11::xft::XftFontOpenName` and other Xft + /// functions. + pub fn as_xft_name(&self) -> *const u8 { + self.0.as_ptr() + } + + /// Converts `self` into a shareable name. + pub fn into_name(self) -> Rc { + self.0.into() + } +} + +impl Font { + /// Tries to load the named font for `screen` on `display`. Returns `None` + /// if `name` can't be handled or font cannot be loaded. + pub fn load(display: &mut x11::xlib::Display, screen: c_int, name: &FontName) -> Option { + let font = NonNull::new(unsafe { + x11::xft::XftFontOpenName(display, screen, name.as_xft_name()) + })?; + let f = unsafe { font.as_ref() }; + let height = u32::try_from(f.ascent + f.descent).ok()?; + let fontmap = unsafe { pango_extras::pango_xft_get_font_map(display, screen) }; + let context = unsafe { pango_sys::pango_font_map_create_context(fontmap) }; + let layout = NonNull::new(unsafe { pango_sys::pango_layout_new(context) })?; + let pattern = unsafe { fontconfig_sys::FcNameParse(name.as_xft_name()) }; + let description = + unsafe { pango_extras::pango_fc_font_description_from_pattern(pattern.cast(), 0) }; + + // Pango examines FC_SIZE but not FC_PIXEL_SIZE of the pattern, but + // font-name has only "pixelsize", so set the size manually here. + let mut size: c_double = 0.0; + unsafe { + if fontconfig_sys::FcPatternGetDouble( + pattern, + fontconfig_sys::constants::FC_PIXEL_SIZE.as_ptr(), + 0, + &mut size, + ) == fontconfig_sys::FcResultMatch + { + pango_sys::pango_font_description_set_absolute_size( + description, + size * (pango_sys::PANGO_SCALE as c_double), + ); + } + + pango_sys::pango_layout_set_font_description(layout.as_ptr(), description); + pango_sys::pango_font_description_free(description); + } + + Some(Font { + font, + height, + ascent: u32::try_from(f.ascent).ok()?, + name: name.clone(), + layout, + }) + } + + /// Loads the font `name` at the size `size` (in pixels). + pub fn load_at_size( + display: &mut x11::xlib::Display, + screen: c_int, + name: &FontName, + size: u32, + ) -> Option { + let pattern = unsafe { fontconfig_sys::FcNameParse(name.as_xft_name()) }; + unsafe { + fontconfig_sys::FcPatternDel( + pattern, + fontconfig_sys::constants::FC_PIXEL_SIZE.as_ptr(), + ); + fontconfig_sys::FcPatternAddDouble( + pattern, + fontconfig_sys::constants::FC_PIXEL_SIZE.as_ptr(), + size as f64, + ); + } + + let name = unsafe { fontconfig_sys::FcNameUnparse(pattern) }; + unsafe { + fontconfig_sys::FcPatternDestroy(pattern); + } + let name = NonNull::new(name)?; + let font_name = FontName(Rc::from(unsafe { CStr::from_ptr(name.as_ptr()) })); + unsafe { + libc::free(name.as_ptr().cast::()); + } + + Font::load(display, screen, &font_name) + } + + pub fn name(&self) -> &FontName { + &self.name + } +} + +impl Drop for Font { + fn drop(&mut self) { + unsafe { + libc::free(self.font.as_ptr().cast::()); + } + } +} + +pub mod ffi { + use super::{Font, FontName}; + + use std::ffi::CStr; + + use crate::{WINGsP, configuration::Configuration, pango_extras}; + + use std::{ + ffi::{c_char, c_int, c_uint}, + ptr, + rc::Rc, + }; + + pub type WMFont = Rc; + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMCreateFont( + screen: *mut WINGsP::W_Screen, + font_name: *const c_char, + ) -> *mut WMFont { + if screen.is_null() || font_name.is_null() { + return ptr::null_mut(); + } + + let screen = unsafe { &mut *screen }; + + if screen.display.is_null() { + return ptr::null_mut(); + } + + let font_name = unsafe { CStr::from_ptr(font_name) }; + let Ok(font_name) = font_name.to_str() else { + return ptr::null_mut(); + }; + let Some(font_name) = FontName::new(font_name) else { + return ptr::null_mut(); + }; + + let display = unsafe { &mut *screen.display }; + let screen_n = screen.screen; + screen + .font_cache_get_or_else(font_name, |font_name| { + Font::load(display, screen_n, font_name) + }) + .map(|font| Box::leak(Box::new(font)) as *mut WMFont) + .unwrap_or(ptr::null_mut()) + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMRetainFont(font: *mut WMFont) -> *mut WMFont { + if font.is_null() { + return ptr::null_mut(); + } + let font = unsafe { (*font).clone() }; + Box::leak(Box::new(font)) + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMReleaseFont(font: *mut WMFont) { + if font.is_null() { + return; + } + let _ = unsafe { Box::from_raw(font) }; + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMGetFontName(font: *const WMFont) -> *const c_char { + if font.is_null() { + return ptr::null_mut(); + } + unsafe { (**font).name.as_xft_name() } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMFontAscent(font: *mut WMFont) -> c_uint { + if font.is_null() { + return 0; + } + return unsafe { (**font).ascent }; + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMFontXftFont(font: *mut WMFont) -> *mut x11::xft::XftFont { + if font.is_null() { + return ptr::null_mut(); + } + return unsafe { (**font).font.as_ptr() }; + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMFontHeight(font: *const WMFont) -> c_uint { + if font.is_null() { + return 0; + } + unsafe { (**font).height } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMGetScaleBaseFromSystemFont( + screen: *mut WINGsP::W_Screen, + alphabet_width: *mut c_int, + font_height: *mut c_int, + ) { + let font = unsafe { WMDefaultSystemFont(screen) }; + unsafe { + *alphabet_width = WMWidthOfString(font, c"abcdefghijklmnopqrstuvwxyz".as_ptr(), 26); + } + if let Ok(x) = unsafe { (**font).height.try_into() } { + unsafe { + *font_height = x; + } + } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMDefaultSystemFont(screen: *mut WINGsP::W_Screen) -> *mut WMFont { + if screen.is_null() { + return ptr::null_mut(); + } + + unsafe { WMRetainFont((*screen).normalFont) } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMDefaultBoldSystemFont(screen: *mut WINGsP::W_Screen) -> *mut WMFont { + if screen.is_null() { + return ptr::null_mut(); + } + + unsafe { WMRetainFont((*screen).boldFont) } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMSystemFontOfSize( + screen: *mut WINGsP::W_Screen, + size: c_int, + ) -> *mut WMFont { + if screen.is_null() { + return ptr::null_mut(); + } + let screen = unsafe { &*screen }; + if screen.display.is_null() { + return ptr::null_mut(); + } + if screen.display.is_null() { + return ptr::null_mut(); + } + let display = unsafe { &mut *screen.display }; + let size = if size > 0 { + size as u32 + } else { + match Configuration::global().map(|c| c.default_font_size as u32) { + Some(x) => x, + None => return ptr::null_mut(), + } + }; + let Some(font_name) = Configuration::global() + .and_then(|c| c.system_font.to_str().ok()) + .and_then(|name| FontName::new(name)) + else { + return ptr::null_mut(); + }; + if let Some(font) = Font::load_at_size(display, screen.screen, &font_name, size) { + Box::leak(Box::new(Rc::new(font))) + } else { + // TODO: warn. + ptr::null_mut() + } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMBoldSystemFontOfSize( + screen: *mut WINGsP::W_Screen, + size: c_int, + ) -> *mut WMFont { + if screen.is_null() { + return ptr::null_mut(); + } + let screen = unsafe { &*screen }; + if screen.display.is_null() { + return ptr::null_mut(); + } + if screen.display.is_null() { + return ptr::null_mut(); + } + let display = unsafe { &mut *screen.display }; + let size = if size > 0 { + size as u32 + } else { + match Configuration::global().map(|c| c.default_font_size as u32) { + Some(x) => x, + None => return ptr::null_mut(), + } + }; + let Some(font_name) = Configuration::global() + .and_then(|c| c.bold_system_font.to_str().ok()) + .and_then(|name| FontName::new(name)) + else { + return ptr::null_mut(); + }; + if let Some(font) = Font::load_at_size(display, screen.screen, &font_name, size) { + Box::leak(Box::new(Rc::new(font))) + } else { + // TODO: warn. + ptr::null_mut() + } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMWidthOfString( + font: *mut WMFont, + text: *const c_char, + length: c_int, + ) -> c_int { + if font.is_null() || text.is_null() || length <= 0 { + return 0; + } + let font = unsafe { &*font }; + let layout = font.layout.as_ptr(); + let previous_text = unsafe { pango_sys::pango_layout_get_text(layout) }; + + if previous_text.is_null() { + unsafe { + pango_sys::pango_layout_set_text(layout, text, length); + } + } else { + let length = length as usize; + let previous_text = unsafe { CStr::from_ptr(previous_text).to_bytes() }; + let text = unsafe { std::slice::from_raw_parts(text, length) }; + if previous_text.len() < length || previous_text[0..length] != text[0..length] { + unsafe { + pango_sys::pango_layout_set_text(layout, text.as_ptr(), length as i32); + } + } + } + + let mut width = 0; + unsafe { + pango_sys::pango_layout_get_pixel_size(layout, &mut width, ptr::null_mut()); + } + width + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMDrawString( + screen: *mut WINGsP::W_Screen, + d: x11::xlib::Drawable, + color: *mut WINGsP::W_Color, + font: *mut WMFont, + x: c_int, + y: c_int, + text: *const c_char, + length: c_int, + ) { + if screen.is_null() || color.is_null() || font.is_null() || text.is_null() { + return; + } + + let screen = unsafe { &*screen }; + let color = unsafe { &*color }; + let layout = unsafe { &mut *(**font).layout.as_ptr() }; + let mut xftcolor = x11::xft::XftColor { + color: x11::xrender::XRenderColor { + red: color.color.red, + green: color.color.green, + blue: color.color.blue, + alpha: color.alpha, + }, + pixel: color.color.pixel, + }; + + let previous_text = unsafe { pango_sys::pango_layout_get_text(layout) }; + if previous_text.is_null() { + unsafe { + pango_sys::pango_layout_set_text(layout, text, length); + } + } else { + let text = unsafe { CStr::from_ptr(text) }; + let previous_text = unsafe { CStr::from_ptr(previous_text) }; + if previous_text != text { + unsafe { + pango_sys::pango_layout_set_text(layout, text.as_ptr(), length); + } + } + } + + unsafe { + x11::xft::XftDrawChange(screen.xftdraw.cast(), d); + pango_extras::pango_xft_render_layout( + screen.xftdraw.cast(), + &mut xftcolor, + layout, + x * pango_sys::PANGO_SCALE, + y * pango_sys::PANGO_SCALE, + ); + } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMDrawImageString( + screen: *mut WINGsP::W_Screen, + d: x11::xlib::Drawable, + color: *mut WINGsP::W_Color, + background: *mut WINGsP::W_Color, + font: *mut WMFont, + x: c_int, + y: c_int, + text: *const c_char, + length: c_int, + ) { + if screen.is_null() || color.is_null() || font.is_null() || text.is_null() { + return; + } + + let screen = unsafe { &*screen }; + let color = unsafe { &*color }; + let background = unsafe { &*background }; + let layout = unsafe { &mut *(**font).layout.as_ptr() }; + let mut text_color = x11::xft::XftColor { + color: x11::xrender::XRenderColor { + red: color.color.red, + green: color.color.green, + blue: color.color.blue, + alpha: color.alpha, + }, + pixel: color.color.pixel, + }; + let background = x11::xft::XftColor { + color: x11::xrender::XRenderColor { + red: background.color.red, + green: background.color.green, + blue: background.color.blue, + alpha: background.alpha, + }, + pixel: color.color.pixel, + }; + + unsafe { + let Ok(width) = u32::try_from(WMWidthOfString(font, text, length)) else { + // TODO: complain. + return; + }; + x11::xft::XftDrawChange(screen.xftdraw.cast(), d); + x11::xft::XftDrawRect( + screen.xftdraw.cast(), + &background, + x, + y, + width, + (**font).height, + ); + } + + let previous_text = unsafe { pango_sys::pango_layout_get_text(layout) }; + if previous_text.is_null() { + unsafe { + pango_sys::pango_layout_set_text(layout, text, length); + } + } else { + let text = unsafe { CStr::from_ptr(text) }; + let previous_text = unsafe { CStr::from_ptr(previous_text) }; + if text != previous_text { + unsafe { + pango_sys::pango_layout_set_text(layout, text.as_ptr(), length); + } + } + } + + unsafe { + pango_extras::pango_xft_render_layout( + screen.xftdraw.cast(), + &mut text_color, + layout, + x * pango_sys::PANGO_SCALE, + y * pango_sys::PANGO_SCALE, + ); + } + } +} diff --git a/WINGs/wings-rs/src/lib.rs b/WINGs/wings-rs/src/lib.rs new file mode 100644 index 00000000..db2efa54 --- /dev/null +++ b/WINGs/wings-rs/src/lib.rs @@ -0,0 +1,8 @@ +#[allow(non_camel_case_types)] +#[allow(non_snake_case)] +#[allow(non_upper_case_globals)] +pub mod WINGsP; +pub mod configuration; +pub mod font; +pub(crate) mod pango_extras; +pub mod screen; diff --git a/WINGs/wings-rs/src/pango_extras.rs b/WINGs/wings-rs/src/pango_extras.rs new file mode 100644 index 00000000..60672553 --- /dev/null +++ b/WINGs/wings-rs/src/pango_extras.rs @@ -0,0 +1,21 @@ +use std::ffi::c_int; + +unsafe extern "C" { + pub fn pango_xft_get_font_map( + display: *mut x11::xlib::Display, + screen: c_int, + ) -> *mut pango_sys::PangoFontMap; + + pub fn pango_fc_font_description_from_pattern( + pattern: *mut x11::xft::FcPattern, + include_size: c_int, + ) -> *mut pango_sys::PangoFontDescription; + + pub fn pango_xft_render_layout( + draw: *mut x11::xft::XftDraw, + color: *mut x11::xft::XftColor, + layout: *mut pango_sys::PangoLayout, + x: c_int, + y: c_int, + ); +} diff --git a/WINGs/wings-rs/src/screen.rs b/WINGs/wings-rs/src/screen.rs new file mode 100644 index 00000000..8d5170e9 --- /dev/null +++ b/WINGs/wings-rs/src/screen.rs @@ -0,0 +1,63 @@ +use crate::{ + WINGsP::W_Screen, + font::{Font, FontName}, +}; + +use std::{ + collections::{HashMap, hash_map::Entry}, + ffi::c_void, + rc::Rc, +}; + +impl W_Screen { + fn font_cache_mut(&mut self) -> &mut HashMap> { + if self.fontCache.is_null() { + self.fontCache = (Box::leak(Box::new(HashMap::>::new())) + as *mut HashMap<_, _>) + .cast::(); + } + unsafe { &mut *self.fontCache.cast::>>() } + } + + pub fn font_cache_get_or_else( + &mut self, + name: FontName, + f: impl FnOnce(&FontName) -> Option, + ) -> Option> { + match self.font_cache_mut().entry(name) { + Entry::Occupied(o) => Some(o.get().clone()), + Entry::Vacant(v) => { + if let Some(font) = f(v.key()) { + let font = Rc::new(font); + v.insert(font.clone()); + Some(font) + } else { + None + } + } + } + } + + /// Removes `font` from the font cache if it is not in use anywhere else + /// (i.e., the only live references are `font` and an entry in the cache). + pub fn font_cache_flush(&mut self, font: &Rc) { + if Rc::strong_count(font) > 2 { + return; + } + self.font_cache_mut().remove(&font.name()); + } +} + +#[cfg(test)] +mod test { + use crate::WINGsP::W_Screen; + + use std::mem::MaybeUninit; + + #[test] + fn font_cache_init() { + let mut screen: W_Screen = unsafe { MaybeUninit::zeroed().assume_init() }; + let cache = screen.font_cache_mut(); + assert!(cache.is_empty()); + } +} diff --git a/WINGs/winputmethod.c b/WINGs/winputmethod.c index eff25b4f..0194697a 100644 --- a/WINGs/winputmethod.c +++ b/WINGs/winputmethod.c @@ -109,7 +109,7 @@ void W_CreateIC(WMView * view) // this really needs to be changed, but I don't know how yet -Dan // it used to be like this with fontsets, but no longer applies to xft preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, - XNArea, &rect, XNFontInfo, scr->normalFont->font, NULL); + XNArea, &rect, XNFontInfo, WMFontXftFont(scr->normalFont), NULL); } view->xic = XCreateIC(scr->imctx->xim, XNInputStyle, scr->imctx->ximstyle, diff --git a/WINGs/wmisc.c b/WINGs/wmisc.c index ba4c8a6a..584593e3 100644 --- a/WINGs/wmisc.c +++ b/WINGs/wmisc.c @@ -201,7 +201,7 @@ W_PaintText(W_View * view, Drawable d, WMFont * font, int x, int y, } void -W_PaintTextAndImage(W_View * view, int wrap, WMColor * textColor, W_Font * font, +W_PaintTextAndImage(W_View * view, int wrap, WMColor * textColor, WMFont * font, WMReliefType relief, const char *text, WMAlignment alignment, W_Pixmap * image, WMImagePosition position, WMColor * backColor, int ofs) diff --git a/WINGs/wtext.c b/WINGs/wtext.c index c16773ff..994fa3d5 100644 --- a/WINGs/wtext.c +++ b/WINGs/wtext.c @@ -718,8 +718,8 @@ static void paintText(Text * tPtr) if (!tPtr->flags.monoFont && tb->underlined) { XDrawLine(dpy, tPtr->db, WMColorGC(color), tb->sections[s].x - tPtr->hpos, - y + font->y + 1, - tb->sections[s].x + tb->sections[s].w - tPtr->hpos, y + font->y + 1); + y + WMFontAscent(font) + 1, + tb->sections[s].x + tb->sections[s].w - tPtr->hpos, y + WMFontAscent(font) + 1); } } tb = (!done ? tb->next : NULL); @@ -897,7 +897,7 @@ static void updateCursorPosition(Text * tPtr) if (!(tb = tPtr->firstTextBlock)) { WMFont *font = tPtr->dFont; tPtr->tpos = 0; - tPtr->cursor.h = font->height + abs(font->height - font->y); + tPtr->cursor.h = WMFontHeight(font) + abs(WMFontHeight(font) - WMFontAscent(font)); tPtr->cursor.y = 2; tPtr->cursor.x = 2; @@ -979,7 +979,7 @@ static void cursorToTextPosition(Text * tPtr, int x, int y) if (!(tb = tPtr->firstTextBlock)) { WMFont *font = tPtr->dFont; tPtr->tpos = 0; - tPtr->cursor.h = font->height + abs(font->height - font->y); + tPtr->cursor.h = WMFontHeight(font) + abs(WMFontHeight(font) - WMFontAscent(font)); tPtr->cursor.y = 2; tPtr->cursor.x = 2; return; @@ -1378,9 +1378,9 @@ static int layOutLine(Text * tPtr, myLineItems * items, int nitems, int x, int y } else { font = (tPtr->flags.monoFont) ? tPtr->dFont : tb->d.font; - /*max_d = WMAX(max_d, abs(font->height-font->y)); */ + /*max_d = WMAX(max_d, abs(WMFontHeight(font)-WMFontAscent(font))); */ max_d = 2; - line_height = WMAX(line_height, font->height + max_d); + line_height = WMAX(line_height, WMFontHeight(font) + max_d); text = &(tb->text[items[i].begin]); len = items[i].end - items[i].begin; if (tPtr->flags.alignment != WALeft) @@ -1430,7 +1430,7 @@ static int layOutLine(Text * tPtr, myLineItems * items, int nitems, int x, int y len = items[i].end - items[i].begin; text = &(tb->text[items[i].begin]); - tb->sections[n].y = y + line_height - font->y; + tb->sections[n].y = y + line_height - WMFontAscent(font); tb->sections[n].w = WMWidthOfString(font, &(tb->text[tb->sections[n].begin]), diff --git a/WPrefs.app/Makefile.am b/WPrefs.app/Makefile.am index 50c258eb..13621007 100644 --- a/WPrefs.app/Makefile.am +++ b/WPrefs.app/Makefile.am @@ -68,8 +68,10 @@ WPrefs_DEPENDENCIES = $(top_builddir)/WINGs/libWINGs.la WPrefs_LDADD = \ $(top_builddir)/wutil-rs/target/debug/libwutil_rs.a\ $(top_builddir)/WINGs/libWINGs.la\ + $(top_builddir)/WINGs/wings-rs/target/debug/libwings_rs.a\ $(top_builddir)/WINGs/libWUtil.la\ $(top_builddir)/wrlib/libwraster.la \ + @PANGO_LIBS@ \ @XLFLAGS@ @XLIBS@ \ @LIBM@ \ @FCLIBS@ \ diff --git a/WPrefs.app/double.c b/WPrefs.app/double.c index 26269001..075454ad 100644 --- a/WPrefs.app/double.c +++ b/WPrefs.app/double.c @@ -94,7 +94,7 @@ static void paintDoubleTest(_DoubleTest * dPtr) if (dPtr->text) { int y; - y = (dPtr->view->size.height - scr->normalFont->height) / 2; + y = (dPtr->view->size.height - WMFontHeight(scr->normalFont)) / 2; W_PaintText(dPtr->view, dPtr->view->window, scr->normalFont, dPtr->on, dPtr->on + y, dPtr->view->size.width, WACenter, scr->black, False, dPtr->text, strlen(dPtr->text)); diff --git a/configure.ac b/configure.ac index 6bec12dd..61761963 100644 --- a/configure.ac +++ b/configure.ac @@ -60,6 +60,11 @@ AS_IF(test x$RUSTC = xno, AC_MSG_ERROR([rustc is required. Please set the RUSTC environment variable or install the Rust toolchain from https://www.rust-lang.org/]) ) AC_SUBST(RUSTC, [rustc]) +AC_CHECK_PROG(BINDGEN, [bindgen], [yes], [no]) +AS_IF(test x$BINDGEN = xno, + AC_MSG_ERROR([bindgen is required. Please set the BINDGEN environment variable or install bindgen (maybe with `cargo install bindgen-cli`)]) +) +AC_SUBST(BINDGEN, [bindgen]) dnl libtool library versioning dnl ========================== @@ -924,12 +929,11 @@ AC_CONFIG_FILES( wrlib/Makefile wrlib/po/Makefile wrlib/tests/Makefile - dnl Rust implementation of WINGs libraries + dnl Rust implementation of WINGs utilities wutil-rs/Makefile - wings-rs/Makefile dnl WINGs toolkit - WINGs/Makefile WINGs/WINGs/Makefile WINGs/po/Makefile + WINGs/Makefile WINGs/wings-rs/Makefile WINGs/WINGs/Makefile WINGs/po/Makefile WINGs/Documentation/Makefile WINGs/Resources/Makefile WINGs/Extras/Makefile WINGs/Examples/Makefile WINGs/Tests/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index 8ba6f2af..b967829b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -161,7 +161,10 @@ wmaker_LDADD = \ $(top_builddir)/WINGs/libWUtil.la\ $(top_builddir)/wrlib/libwraster.la\ $(top_builddir)/wutil-rs/target/debug/libwutil_rs.a\ + $(top_builddir)/WINGs/wings-rs/target/debug/libwings_rs.a\ $(top_builddir)/wmaker-rs/target/debug/libwmaker_rs.a\ + @PANGO_LIBS@ \ + @FCLIBS@ \ @XLFLAGS@ \ @LIBXRANDR@ \ @LIBXINERAMA@ \ diff --git a/util/Makefile.am b/util/Makefile.am index 3fdd6d67..c4d6bec6 100644 --- a/util/Makefile.am +++ b/util/Makefile.am @@ -67,15 +67,17 @@ geticonset_LDADD= \ wmagnify_LDADD = \ $(top_builddir)/WINGs/libWINGs.la \ $(top_builddir)/WINGs/libWUtil.la \ + $(top_builddir)/WINGs/wings-rs/target/debug/libwings_rs.a \ $(top_builddir)/wrlib/libwraster.la \ - @XLFLAGS@ @XLIBS@ @INTLIBS@ + @XLFLAGS@ @XLIBS@ @INTLIBS@ @FCLIBS@ @PANGO_LIBS@ wmsetbg_LDADD = \ $(top_builddir)/WINGs/libWINGs.la \ $(top_builddir)/wutil-rs/target/debug/libwutil_rs.a \ + $(top_builddir)/WINGs/wings-rs/target/debug/libwings_rs.a \ $(top_builddir)/WINGs/libWUtil.la \ $(top_builddir)/wrlib/libwraster.la \ - @XLFLAGS@ @LIBXINERAMA@ @XLIBS@ @INTLIBS@ + @XLFLAGS@ @LIBXINERAMA@ @XLIBS@ @INTLIBS@ @FCLIBS@ @PANGO_LIBS@ wmgenmenu_LDADD = \ $(top_builddir)/WINGs/libWUtil.la \ @@ -100,6 +102,7 @@ wmiv_LDADD = \ $(top_builddir)/WINGs/libWINGs.la \ $(top_builddir)/WINGs/libWUtil.la \ $(top_builddir)/wutil-rs/target/debug/libwutil_rs.a \ + $(top_builddir)/WINGs/wings-rs/target/debug/libwings_rs.a \ @XLFLAGS@ @XLIBS@ @GFXLIBS@ \ @PANGO_LIBS@ @PTHREAD_LIBS@ @LIBEXIF@ diff --git a/wings-rs/Cargo.toml b/wings-rs/Cargo.toml deleted file mode 100644 index 2a743277..00000000 --- a/wings-rs/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "wings-rs" -version = "0.1.0" -edition = "2024" - -[dependencies] -wutil-rs = { path = "../wutil-rs" } diff --git a/wings-rs/Makefile.am b/wings-rs/Makefile.am deleted file mode 100644 index 2aa61a59..00000000 --- a/wings-rs/Makefile.am +++ /dev/null @@ -1,19 +0,0 @@ -AUTOMAKE_OPTIONS = - -RUST_SOURCES = \ - src/lib.rs - -RUST_EXTRA = \ - Cargo.lock \ - Cargo.toml - -target/debug/libwings_rs.a: $(RUST_SOURCES) $(RUST_EXTRA) - $(CARGO) build - -check-local: - $(CARGO) test - -clean-local: - $(CARGO) clean - -all: target/debug/libwings_rs.a diff --git a/wings-rs/src/lib.rs b/wings-rs/src/lib.rs deleted file mode 100644 index b93cf3ff..00000000 --- a/wings-rs/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub fn add(left: u64, right: u64) -> u64 { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -}