From b4a91efedcca0f337896e23702cad2cc24d3bfa1 Mon Sep 17 00:00:00 2001 From: Stu Black Date: Mon, 2 Mar 2026 13:50:30 -0500 Subject: [PATCH] Port WMColor to Rust. --- WINGs/Makefile.am | 1 - WINGs/WINGs/WINGs.h | 2 +- WINGs/WINGs/WINGsP.h.in | 27 +- WINGs/wcolorpanel.c | 8 +- WINGs/widgets.c | 10 +- WINGs/wings-rs-tests/Makefile.am | 2 +- WINGs/wings-rs-tests/build.rs | 3 + WINGs/wings-rs/Makefile.am | 11 +- WINGs/wings-rs/patch_WINGsP.sh | 2 +- WINGs/wings-rs/src/color.rs | 566 +++++++++++++++++++++++++++++++ WINGs/wings-rs/src/ffi.rs | 2 + WINGs/wings-rs/src/font.rs | 41 +-- WINGs/wings-rs/src/lib.rs | 2 + WINGs/wmisc.c | 2 +- WINGs/wtext.c | 4 +- WINGs/wview.c | 10 +- 16 files changed, 615 insertions(+), 78 deletions(-) create mode 100644 WINGs/wings-rs/src/color.rs create mode 100644 WINGs/wings-rs/src/ffi.rs diff --git a/WINGs/Makefile.am b/WINGs/Makefile.am index 3ada7950..08dd0050 100644 --- a/WINGs/Makefile.am +++ b/WINGs/Makefile.am @@ -32,7 +32,6 @@ libWINGs_la_SOURCES = \ wbox.c \ wbrowser.c \ wbutton.c \ - wcolor.c \ wcolorpanel.c \ wcolorwell.c \ wconfig.h \ diff --git a/WINGs/WINGs/WINGs.h b/WINGs/WINGs/WINGs.h index 1d1a2927..49df41da 100644 --- a/WINGs/WINGs/WINGs.h +++ b/WINGs/WINGs/WINGs.h @@ -852,7 +852,7 @@ Pixmap WMGetPixmapMaskXID(WMPixmap *pixmap); WMPixmap* WMGetSystemPixmap(WMScreen *scr, int image); -/* ---[ WINGs/wcolor.c ]-------------------------------------------------- */ +/* ---[ WINGs/wings-rs/src/color.rs ]------------------------------------- */ WMColor* WMDarkGrayColor(WMScreen *scr); diff --git a/WINGs/WINGs/WINGsP.h.in b/WINGs/WINGs/WINGsP.h.in index 0f0ca77e..a3d45dfa 100644 --- a/WINGs/WINGs/WINGsP.h.in +++ b/WINGs/WINGs/WINGsP.h.in @@ -67,8 +67,10 @@ typedef struct W_DraggingInfo { /* ---[ Structures from WINGs.h ]----------------------------------------- */ -/* Pre-definition of internal structs */ +/* Opaque primitive types defined in Rust. */ typedef struct W_Color W_Color; + +/* Pre-definition of internal structs */ typedef struct W_Pixmap W_Pixmap; typedef struct W_View W_View; @@ -130,10 +132,10 @@ typedef struct W_Screen { W_DraggingInfo dragInfo; /* colors */ - W_Color *white; - W_Color *black; - W_Color *gray; - W_Color *darkGray; + WMColor *white; + WMColor *black; + WMColor *gray; + WMColor *darkGray; GC stippleGC; @@ -413,21 +415,6 @@ void W_BalloonHandleEnterView(WMView *view); void W_BalloonHandleLeaveView(WMView *view); -/* ---[ wcolor.c ]-------------------------------------------------------- */ - -struct W_Color { - struct W_Screen *screen; - - XColor color; - unsigned short alpha; - short refCount; - GC gc; - struct { - unsigned int exact:1; - } flags; -}; - - /* ---[ wevent.c ]-------------------------------------------------------- */ typedef struct W_EventHandler { diff --git a/WINGs/wcolorpanel.c b/WINGs/wcolorpanel.c index 35443d81..5ae526f5 100644 --- a/WINGs/wcolorpanel.c +++ b/WINGs/wcolorpanel.c @@ -1292,7 +1292,7 @@ void WMSetColorPanelPickerMode(WMColorPanel * panel, WMColorPanelMode mode) panel->mode = mode; } -WMColor *WMGetColorPanelColor(WMColorPanel * panel) +WMColor* WMGetColorPanelColor(WMColorPanel * panel) { return WMGetColorWellColor(panel->colorWell); } @@ -1301,9 +1301,9 @@ void WMSetColorPanelColor(WMColorPanel * panel, WMColor * color) { WMSetColorWellColor(panel->colorWell, color); - panel->color.rgb.red = color->color.red >> 8; - panel->color.rgb.green = color->color.green >> 8; - panel->color.rgb.blue = color->color.blue >> 8; + panel->color.rgb.red = (WMRedComponentOfColor(color) >> 8); + panel->color.rgb.green = (WMGreenComponentOfColor(color) >> 8); + panel->color.rgb.blue = (WMBlueComponentOfColor(color) >> 8); panel->color.set = cpRGB; if (panel->mode == panel->lastChanged) diff --git a/WINGs/widgets.c b/WINGs/widgets.c index 12bfaa1f..d5135c5e 100644 --- a/WINGs/widgets.c +++ b/WINGs/widgets.c @@ -725,14 +725,14 @@ WMScreen *WMCreateScreenWithRContext(Display * display, int screen, RContext * c gcv.graphics_exposures = False; gcv.function = GXxor; - gcv.foreground = scrPtr->white->color.pixel; + gcv.foreground = WMColorPixel(scrPtr->white); if (gcv.foreground == 0) gcv.foreground = 1; scrPtr->xorGC = XCreateGC(display, W_DRAWABLE(scrPtr), GCFunction | GCGraphicsExposures | GCForeground, &gcv); gcv.function = GXxor; - gcv.foreground = scrPtr->gray->color.pixel; + gcv.foreground = WMColorPixel(scrPtr->gray); gcv.subwindow_mode = IncludeInferiors; scrPtr->ixorGC = XCreateGC(display, W_DRAWABLE(scrPtr), GCFunction | GCGraphicsExposures | GCForeground | GCSubwindowMode, &gcv); @@ -743,8 +743,8 @@ WMScreen *WMCreateScreenWithRContext(Display * display, int screen, RContext * c scrPtr->clipGC = XCreateGC(display, W_DRAWABLE(scrPtr), GCFunction | GCGraphicsExposures, &gcv); stipple = XCreateBitmapFromData(display, W_DRAWABLE(scrPtr), STIPPLE_BITS, STIPPLE_WIDTH, STIPPLE_HEIGHT); - gcv.foreground = scrPtr->darkGray->color.pixel; - gcv.background = scrPtr->gray->color.pixel; + gcv.foreground = WMColorPixel(scrPtr->darkGray); + gcv.background = WMColorPixel(scrPtr->gray); gcv.fill_style = FillStippled; gcv.stipple = stipple; scrPtr->stippleGC = XCreateGC(display, W_DRAWABLE(scrPtr), @@ -1000,7 +1000,7 @@ void WMSetWidgetBackgroundColor(WMWidget * w, WMColor * color) WMRedisplayWidget(w); } -WMColor *WMGetWidgetBackgroundColor(WMWidget * w) +WMColor * WMGetWidgetBackgroundColor(WMWidget * w) { return W_VIEW(w)->backColor; } diff --git a/WINGs/wings-rs-tests/Makefile.am b/WINGs/wings-rs-tests/Makefile.am index bf2b7d5a..ec75d8eb 100644 --- a/WINGs/wings-rs-tests/Makefile.am +++ b/WINGs/wings-rs-tests/Makefile.am @@ -40,4 +40,4 @@ all: rustlib # process, and WINGs currently assumes that it is running in a single-threaded # environment. test: rustlib - LD_LIBRARY_PATH=../.libs $(CARGO) nextest run + LD_LIBRARY_PATH=../.libs:../../wrlib/.libs $(CARGO) nextest run diff --git a/WINGs/wings-rs-tests/build.rs b/WINGs/wings-rs-tests/build.rs index 830385df..10aa504a 100644 --- a/WINGs/wings-rs-tests/build.rs +++ b/WINGs/wings-rs-tests/build.rs @@ -1,7 +1,9 @@ fn main() { println!("cargo::rustc-link-search=../.libs"); + println!("cargo::rustc-link-search=../../wrlib/.libs"); println!("cargo::rustc-link-arg=-lX11"); + println!("cargo::rustc-link-arg-tests=-lwraster"); println!("cargo::rustc-link-arg-tests=-lWUtil"); println!("cargo::rustc-link-arg-tests=-lWINGs"); println!("cargo::rustc-link-arg-tests=-lXft"); @@ -11,6 +13,7 @@ fn main() { println!("cargo::rustc-link-arg-examples=-lWUtil"); println!("cargo::rustc-link-arg-examples=-lWINGs"); + println!("cargo::rustc-link-arg-examples=-lwraster"); println!("cargo::rustc-link-arg-examples=-lX11"); println!("cargo::rustc-link-arg-examples=-lXft"); println!("cargo::rustc-link-arg-examples=-lpango-1.0"); diff --git a/WINGs/wings-rs/Makefile.am b/WINGs/wings-rs/Makefile.am index da3c4f26..9191d38a 100644 --- a/WINGs/wings-rs/Makefile.am +++ b/WINGs/wings-rs/Makefile.am @@ -1,9 +1,11 @@ AUTOMAKE_OPTIONS = -RUST_SOURCES = \ +RUST_SRC = \ src/WINGsP.rs \ src/button.rs \ + src/color.rs \ src/configuration.rs \ + src/ffi.rs \ src/font.rs \ src/font_panel.rs \ src/lib.rs \ @@ -19,7 +21,7 @@ RUST_EXTRA = \ src/WINGsP.rs: ../WINGs/WINGsP.h ../../wrlib/wraster.h ../WINGs/WINGs.h ../WINGs/WUtil.h Makefile patch_WINGsP.sh $(BINDGEN) ../WINGs/WINGsP.h \ --no-recursive-allowlist \ - --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" \ + --allowlist-type "^W_.+|^WM(View|Array|DragOperationType|Point|Data|OpenPanel|SavePanel|HashTable|DraggingInfo|SelectionProcs|Rect|EventProc|Widget|Size|Pixmap|FilePanel|List|ListItem)" \ --allowlist-type "^WM(FontPanel|Screen|Button)" \ --allowlist-function "^WMCreateScreen|^WM(Get|Show)FontPanel|^WMCreateCommandButton|^WM(Initialize|Release)Application|^WMScreenMainLoop|^WMHandleEvent" \ --allowlist-function "^WMWidgetScreen|^WM(Initialize|Release)Application|^WM(ScreenMainLoop|HandleEvent)|^WM(((Get|Set)TextFieldFont)|GetTextFieldText|SetTextFieldText|SelectTextFieldRange)" \ @@ -46,9 +48,6 @@ src/WINGsP.rs: ../WINGs/WINGsP.h ../../wrlib/wraster.h ../WINGs/WINGs.h ../WINGs --allowlist-function "^WM(CreateLabel|SetLabelText|SetLabelFont|SetLabelTextColor|SetLabelRelief|SetLabelTextAlignment)" \ --allowlist-type "^WM(Button|ButtonBehaviorMask)" \ --allowlist-function "^WM(CreateCustomButton|SetButtonText|SetButtonAction|SetButtonText)" \ - --allowlist-function "wmkrange" \ - --allowlist-type "^WM(View|Array|DragOperationType|Point|Data|OpenPanel|SavePanel|HashTable|DraggingInfo|SelectionProcs|Rect|EventProc|Widget|Size|Color|Pixmap|FilePanel|Screen|List|ListItem)" \ - --allowlist-type "^R(Context|ContextAttributes|Image|RenderingMode|ScalingFilter|StdColormapMode|ImageFormat|Color)" \ --allowlist-type "_WINGsConfiguration" \ --allowlist-item "^WMAlignment" \ --allowlist-item "^WMReliefType" \ @@ -60,7 +59,7 @@ src/WINGsP.rs: ../WINGs/WINGsP.h ../../wrlib/wraster.h ../WINGs/WINGs.h ../WINGs Cargo.lock: $(CARGO) build -target/debug/libwings_rs.so: $(RUST_SOURCES) $(RUST_EXTRA) +target/debug/libwings_rs.so: $(RUST_SRC) $(RUST_EXTRA) $(CARGO) build check-local: diff --git a/WINGs/wings-rs/patch_WINGsP.sh b/WINGs/wings-rs/patch_WINGsP.sh index 00854f66..966ed1ea 100755 --- a/WINGs/wings-rs/patch_WINGsP.sh +++ b/WINGs/wings-rs/patch_WINGsP.sh @@ -15,7 +15,7 @@ fi FILE="$1" exec sed -i -r \ - -e "1s/^/use wutil_rs::range::ffi::*;\nuse x11::xlib::*;\nuse crate::font::ffi::WMFont;\n\n/" \ + -e "1s/^/use wrlib_rs::ffi::*;\nuse wutil_rs::range::ffi::*;\nuse x11::xlib::*;\nuse crate::ffi::*;\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" \ diff --git a/WINGs/wings-rs/src/color.rs b/WINGs/wings-rs/src/color.rs new file mode 100644 index 00000000..6e586c62 --- /dev/null +++ b/WINGs/wings-rs/src/color.rs @@ -0,0 +1,566 @@ +use crate::WINGsP::WMScreen; +use std::cell::RefCell; +use std::ffi::c_ulong; +use std::ptr::{self, NonNull}; +use wrlib_rs::ffi::{RColor, RGetClosestXColor}; + +pub struct Color { + screen: NonNull, + color: x11::xlib::XColor, + alpha: RefCell, + gc: RefCell, +} + +#[derive(Clone, Copy, Debug)] +pub struct Rgb { + pub r: u16, + pub g: u16, + pub b: u16, +} + +impl Rgb { + pub fn with_alpha(self, alpha: u16) -> Rgba { + Rgba { + r: self.r, + g: self.g, + b: self.b, + a: alpha, + } + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ColorMatch { + Approximate, + Exact, +} + +#[derive(Clone, Copy, Debug)] +pub struct Rgba { + pub r: u16, + pub g: u16, + pub b: u16, + pub a: u16, +} + +impl Color { + const LIGHT_STIPPLE_WIDTH: u32 = 4; + const LIGHT_STIPPLE_HEIGHT: u32 = 4; + const LIGHT_STIPPLE_BITS: [u8; 4] = [0x05, 0x0a, 0x05, 0x0a]; + const DARK_STIPPLE_WIDTH: u32 = 4; + const DARK_STIPPLE_HEIGHT: u32 = 4; + const DARK_STIPPLE_BITS: [u8; 4] = [0x0a, 0x04, 0x0a, 0x01]; + + pub fn new_rgb(screen: NonNull, rgb: Rgb, mtch: ColorMatch) -> Option { + Self::new_rgba(screen, rgb.with_alpha(0xffff), mtch) + } + + pub fn new_rgba(screen: NonNull, rgba: Rgba, mtch: ColorMatch) -> Option { + match mtch { + ColorMatch::Approximate => find_close_rgba(screen, rgba), + ColorMatch::Exact => create_rgba(screen, rgba), + } + } + + pub fn red(&self) -> u16 { + self.color.red + } + + pub fn green(&self) -> u16 { + self.color.green + } + + pub fn blue(&self) -> u16 { + self.color.blue + } + + pub fn alpha(&self) -> u16 { + *self.alpha.borrow() + } + + pub fn pixel(&self) -> c_ulong { + self.color.pixel + } + + pub fn to_xft_color(&self) -> x11::xft::XftColor { + x11::xft::XftColor { + color: x11::xrender::XRenderColor { + red: self.red(), + green: self.green(), + blue: self.blue(), + alpha: self.alpha(), + }, + pixel: self.pixel(), + } + } + + pub fn to_rcolor(&self) -> RColor { + RColor { + red: (self.red() >> 8) as u8, + green: (self.green() >> 8) as u8, + blue: (self.blue() >> 8) as u8, + alpha: (self.alpha() >> 8) as u8, + } + } + + pub fn gc(&self) -> x11::xlib::GC { + let mut gc = self.gc.borrow_mut(); + if gc.is_null() { + let mut gcv = + unsafe { std::mem::MaybeUninit::::zeroed().assume_init() }; + gcv.foreground = self.pixel(); + gcv.graphics_exposures = 0; + + *gc = unsafe { + let screen = &mut *self.screen.as_ptr(); + x11::xlib::XCreateGC( + screen.display, + (*screen.rcontext).drawable, + (x11::xlib::GCForeground | x11::xlib::GCGraphicsExposures) as u64, + &mut gcv, + ) + }; + } + *gc + } + + pub fn hex_triplet(&self) -> String { + format!( + "#{:02x}{:02x}{:02x}", + self.red() >> 8, + self.green() >> 8, + self.blue() >> 8 + ) + } +} + +/* + * TODO: make the color creation code return the same WMColor for the + * same colors. + * make findCloseColor() find the closest color in the RContext pallette + * or in the other colors allocated by WINGs. + */ + +fn find_close_rgba(screen: NonNull, rgba: Rgba) -> Option { + let rcontext = unsafe { (*screen.as_ptr()).rcontext }; + let display = unsafe { (*screen.as_ptr()).display }; + let colormap = unsafe { (*screen.as_ptr()).colormap }; + + let mut xcolor = x11::xlib::XColor { + pixel: 0, + red: 0, + green: 0, + blue: 0, + flags: 0, + pad: 0, + }; + let mut rcolor = RColor { + red: (rgba.r >> 8) as u8, + green: (rgba.g >> 8) as u8, + blue: (rgba.b >> 8) as u8, + alpha: (rgba.a >> 8) as u8, + }; + if unsafe { RGetClosestXColor(rcontext, &mut rcolor, &mut xcolor) } == 0 { + return None; + } + if unsafe { x11::xlib::XAllocColor(display, colormap, &mut xcolor) } == 0 { + return None; + } + + Some(Color { + screen: screen, + color: xcolor, + alpha: RefCell::new(rgba.a), + gc: RefCell::new(ptr::null_mut()), + }) +} + +fn create_rgba(screen: NonNull, rgba: Rgba) -> Option { + let display = unsafe { (*screen.as_ptr()).display }; + let colormap = unsafe { (*screen.as_ptr()).colormap }; + let mut xcolor = x11::xlib::XColor { + red: rgba.r, + green: rgba.g, + blue: rgba.b, + flags: x11::xlib::DoRed | x11::xlib::DoGreen | x11::xlib::DoBlue, + pad: 0, + pixel: 0, + }; + if unsafe { x11::xlib::XAllocColor(display, colormap, &mut xcolor) } == 0 { + return None; + } + + Some(Color { + screen: screen, + color: xcolor, + alpha: RefCell::new(rgba.a), + gc: RefCell::new(ptr::null_mut()), + }) +} + +impl Drop for Color { + fn drop(&mut self) { + unsafe { + let display = (*self.screen.as_ptr()).display; + let colormap = (*self.screen.as_ptr()).colormap; + x11::xlib::XFreeColors(display, colormap, &mut self.color.pixel, 1, 0); + let gc = self.gc.borrow(); + if !gc.is_null() { + x11::xlib::XFreeGC(display, *gc); + } + } + } +} + +pub mod ffi { + use super::*; + use std::ffi::{c_char, c_int, c_uint, c_ulong, c_ushort, CString}; + use std::ptr::NonNull; + use std::rc::Rc; + use wrlib_rs::ffi::RColor; + + pub type WMColor = Rc; + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMCreateRGBColor( + screen: NonNull, + red: c_ushort, + green: c_ushort, + blue: c_ushort, + exact: c_int, + ) -> *mut WMColor { + Color::new_rgb( + screen, + Rgb { + r: red, + g: green, + b: blue, + }, + if exact == 0 { + ColorMatch::Approximate + } else { + ColorMatch::Exact + }, + ) + .map(|c| Box::leak(Box::new(Rc::new(c))) as *mut _) + .unwrap_or(unsafe { (*screen.as_ptr()).black }) + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMGetRColorFroMColor(color: NonNull) -> RColor { + unsafe { (*color.as_ptr()).to_rcolor() } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn pixel(c: &WMColor) -> c_ulong { + c.color.pixel + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMCreateRGBAColor( + screen: NonNull, + red: c_ushort, + green: c_ushort, + blue: c_ushort, + alpha: c_ushort, + exact: c_int, + ) -> *mut WMColor { + Color::new_rgba( + screen, + Rgba { + r: red, + g: green, + b: blue, + a: alpha, + }, + if exact == 0 { + ColorMatch::Approximate + } else { + ColorMatch::Exact + }, + ) + .map(|c| Box::leak(Box::new(Rc::new(c))) as *mut _) + .unwrap_or(unsafe { (*screen.as_ptr()).black }) + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMCreateNamedColor( + screen: NonNull, + name: *const c_char, + exact: c_int, + ) -> *mut WMColor { + let display = unsafe { (*screen.as_ptr()).display }; + let colormap = unsafe { (*screen.as_ptr()).colormap }; + let mut xcolor = x11::xlib::XColor { + red: 0, + green: 0, + blue: 0, + flags: 0, + pad: 0, + pixel: 0, + }; + if unsafe { x11::xlib::XParseColor(display, colormap, name, &mut xcolor) } == 0 { + return ptr::null_mut(); + } + let visual_class = unsafe { (*(*screen.as_ptr()).visual).class }; + let exact = visual_class == x11::xlib::TrueColor || exact != 0; + if exact { + if let Some(c) = Color::new_rgb( + screen, + Rgb { + r: xcolor.red, + g: xcolor.green, + b: xcolor.blue, + }, + ColorMatch::Exact, + ) { + return Box::leak(Box::new(Rc::new(c))) as *mut _; + } + } + match Color::new_rgb( + screen, + Rgb { + r: xcolor.red, + g: xcolor.green, + b: xcolor.blue, + }, + ColorMatch::Approximate, + ) { + Some(c) => Box::leak(Box::new(Rc::new(c))) as *mut _, + None => ptr::null_mut(), + } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMRetainColor(color: NonNull) -> *mut WMColor { + Box::leak(Box::new(unsafe { (*color.as_ptr()).clone() })) as *mut _ + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMReleaseColor(color: NonNull) { + unsafe { + let _ = Box::from_raw(color.as_ptr()); + } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMSetColorAlpha(color: NonNull, alpha: c_ushort) { + unsafe { + (&mut *color.as_ptr()).alpha.replace(alpha); + } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMPaintColorSwatch( + color: NonNull, + d: x11::xlib::Drawable, + x: c_int, + y: c_int, + width: c_uint, + height: c_uint, + ) { + unsafe { + let color = &mut *color.as_ptr(); + let display = (*color.screen.as_ptr()).display; + x11::xlib::XFillRectangle(display, d, color.gc(), x, y, width, height); + } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMColorPixel(color: NonNull) -> c_ulong { + unsafe { (*color.as_ptr()).pixel() } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMColorGC(color: NonNull) -> x11::xlib::GC { + unsafe { (&mut *color.as_ptr()).gc() } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMSetColorInGC(color: NonNull, gc: x11::xlib::GC) { + unsafe { + let color = &mut *color.as_ptr(); + let display = (*color.screen.as_ptr()).display; + x11::xlib::XSetForeground(display, gc, color.pixel()); + } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMWhiteColor(screen: NonNull) -> *mut WMColor { + unsafe { + let scr = &mut *screen.as_ptr(); + if scr.white.is_null() { + // TODO: warn if we couldn't allocate. + scr.white = WMCreateRGBColor(screen, 0xffff, 0xffff, 0xffff, 1); + } + + NonNull::new(scr.white) + .map(|c| WMRetainColor(c)) + .unwrap_or(ptr::null_mut()) + } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMBlackColor(screen: NonNull) -> *mut WMColor { + unsafe { + let scr = &mut *screen.as_ptr(); + if scr.black.is_null() { + // TODO: warn or bail out if we couldn't allocate. + scr.black = WMCreateRGBColor(screen, 0, 0, 0, 1); + } + + NonNull::new(scr.black) + .map(|c| WMRetainColor(c)) + .unwrap_or(ptr::null_mut()) + } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMGrayColor(screen: NonNull) -> *mut WMColor { + unsafe { + let scr = &mut *screen.as_ptr(); + if scr.gray.is_null() { + if scr.depth == 1 { + let white = WMWhiteColor(screen); + let black = WMBlackColor(screen); + let stipple = x11::xlib::XCreateBitmapFromData( + scr.display, + (*scr.rcontext).drawable, + Color::LIGHT_STIPPLE_BITS.as_ptr(), + Color::LIGHT_STIPPLE_WIDTH, + Color::LIGHT_STIPPLE_HEIGHT, + ); + let color = create_rgba( + screen, + Rgba { + r: 0, + g: 0, + b: 0, + a: 0xffff, + }, + ) + .expect("cannot create stipple color"); + let mut gcv = + std::mem::MaybeUninit::::zeroed().assume_init(); + gcv.foreground = (&mut *white).color.pixel; + gcv.background = (&mut *black).color.pixel; + gcv.fill_style = x11::xlib::FillStippled; + gcv.stipple = stipple; + *color.gc.borrow_mut() = x11::xlib::XCreateGC( + scr.display, + (*scr.rcontext).drawable, + (x11::xlib::GCForeground + | x11::xlib::GCBackground + | x11::xlib::GCStipple + | x11::xlib::GCFillStyle + | x11::xlib::GCGraphicsExposures) as u64, + &mut gcv, + ); + x11::xlib::XFreePixmap(scr.display, stipple); + if let Some(white) = NonNull::new(white) { + WMReleaseColor(white); + } + if let Some(black) = NonNull::new(black) { + WMReleaseColor(black); + } + } else { + scr.gray = WMCreateRGBColor(screen, 0xaeba, 0xaaaa, 0xaeba, 1); + // TODO: warn or bail if we couldn't allocate. + } + } + NonNull::new(scr.gray) + .map(|c| WMRetainColor(c)) + .unwrap_or(ptr::null_mut()) + } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMDarkGrayColor(screen: NonNull) -> *mut WMColor { + unsafe { + let scr = &mut *screen.as_ptr(); + if scr.darkGray.is_null() { + if scr.depth == 1 { + let white = WMWhiteColor(screen); + let black = WMBlackColor(screen); + let stipple = x11::xlib::XCreateBitmapFromData( + scr.display, + (*scr.rcontext).drawable, + Color::DARK_STIPPLE_BITS.as_ptr(), + Color::DARK_STIPPLE_WIDTH, + Color::DARK_STIPPLE_HEIGHT, + ); + let color = create_rgba( + screen, + Rgba { + r: 0, + g: 0, + b: 0, + a: 0xffff, + }, + ) + .expect("cannot create dark stipple color"); + let mut gcv = + std::mem::MaybeUninit::::zeroed().assume_init(); + gcv.foreground = (&mut *white).color.pixel; + gcv.background = (&mut *black).color.pixel; + gcv.fill_style = x11::xlib::FillStippled; + gcv.stipple = stipple; + *color.gc.borrow_mut() = x11::xlib::XCreateGC( + scr.display, + (*scr.rcontext).drawable, + (x11::xlib::GCForeground + | x11::xlib::GCBackground + | x11::xlib::GCStipple + | x11::xlib::GCFillStyle + | x11::xlib::GCGraphicsExposures) as u64, + &mut gcv, + ); + x11::xlib::XFreePixmap(scr.display, stipple); + if let Some(white) = NonNull::new(white) { + WMReleaseColor(white); + } + if let Some(black) = NonNull::new(black) { + WMReleaseColor(black); + } + } else { + scr.darkGray = WMCreateRGBColor(screen, 0x5144, 0x5555, 0x5144, 1); + // TODO: warn or bail if we couldn't allocate. + } + } + NonNull::new(scr.darkGray) + .map(|c| WMRetainColor(c)) + .unwrap_or(ptr::null_mut()) + } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMRedComponentOfColor(color: NonNull) -> c_ushort { + unsafe { (*color.as_ptr()).red() } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMGreenComponentOfColor(color: NonNull) -> c_ushort { + unsafe { (*color.as_ptr()).green() } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMBlueComponentOfColor(color: NonNull) -> c_ushort { + unsafe { (*color.as_ptr()).blue() } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMGetColorAlpha(color: NonNull) -> c_ushort { + unsafe { (*color.as_ptr()).alpha() } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn WMGetColorRGBDescription(color: NonNull) -> *const c_char { + unsafe { + wutil_rs::string::wstrdup( + CString::new((*color.as_ptr()).hex_triplet()) + .unwrap() + .as_ptr(), + ) + } + } +} diff --git a/WINGs/wings-rs/src/ffi.rs b/WINGs/wings-rs/src/ffi.rs new file mode 100644 index 00000000..3ef6248c --- /dev/null +++ b/WINGs/wings-rs/src/ffi.rs @@ -0,0 +1,2 @@ +pub use crate::color::ffi::*; +pub use crate::font::ffi::*; diff --git a/WINGs/wings-rs/src/font.rs b/WINGs/wings-rs/src/font.rs index 605aecc4..9992bb34 100644 --- a/WINGs/wings-rs/src/font.rs +++ b/WINGs/wings-rs/src/font.rs @@ -1,4 +1,7 @@ -use crate::pango_extras; +use crate::{ + color::ffi::WMColor, + pango_extras, +}; use std::{ ffi::{CStr, CString, c_double, c_int, c_uint, c_void}, @@ -452,7 +455,7 @@ pub mod ffi { pub unsafe extern "C" fn WMDrawString( screen: *mut WINGsP::W_Screen, d: x11::xlib::Drawable, - color: *mut WINGsP::W_Color, + color: *mut WMColor, font: *mut WMFont, x: c_int, y: c_int, @@ -466,15 +469,7 @@ pub mod ffi { 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 mut xftcolor = color.to_xft_color(); let previous_text = unsafe { pango_sys::pango_layout_get_text(layout) }; if previous_text.is_null() { @@ -507,8 +502,8 @@ pub mod ffi { 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, + color: *mut WMColor, + background: *mut WMColor, font: *mut WMFont, x: c_int, y: c_int, @@ -523,24 +518,8 @@ pub mod ffi { 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, - }; + let mut text_color = color.to_xft_color(); + let background = background.to_xft_color(); unsafe { let Ok(width) = u32::try_from(WMWidthOfString(font, text, length)) else { diff --git a/WINGs/wings-rs/src/lib.rs b/WINGs/wings-rs/src/lib.rs index 02464da9..4364ee1b 100644 --- a/WINGs/wings-rs/src/lib.rs +++ b/WINGs/wings-rs/src/lib.rs @@ -4,7 +4,9 @@ #[allow(non_upper_case_globals)] pub mod WINGsP; pub mod button; +pub mod color; pub mod configuration; +pub mod ffi; pub mod font; pub mod font_panel; pub mod list; diff --git a/WINGs/wmisc.c b/WINGs/wmisc.c index 584593e3..68b98e2b 100644 --- a/WINGs/wmisc.c +++ b/WINGs/wmisc.c @@ -165,7 +165,7 @@ int W_GetTextHeight(WMFont * font, const char *text, int width, int wrap) void W_PaintText(W_View * view, Drawable d, WMFont * font, int x, int y, - int width, WMAlignment alignment, WMColor * color, int wrap, + int width, WMAlignment alignment, WMColor *color, int wrap, const char *text, int length) { const char *ptr = text; diff --git a/WINGs/wtext.c b/WINGs/wtext.c index a1040e2e..2a9c3660 100644 --- a/WINGs/wtext.c +++ b/WINGs/wtext.c @@ -2989,8 +2989,8 @@ WMText *WMCreateTextForDocumentType(WMWidget * parent, WMAction * parser, WMActi W_SetViewBackgroundColor(tPtr->view, tPtr->bgColor); gcv.graphics_exposures = False; - gcv.foreground = scr->gray->color.pixel; - gcv.background = scr->darkGray->color.pixel; + gcv.foreground = WMColorPixel(scr->gray); + gcv.background = WMColorPixel(scr->darkGray); gcv.fill_style = FillStippled; /* why not use scr->stipple here? */ gcv.stipple = XCreateBitmapFromData(dpy, W_DRAWABLE(scr), STIPPLE_BITS, STIPPLE_WIDTH, STIPPLE_HEIGHT); diff --git a/WINGs/wview.c b/WINGs/wview.c index 2ab31f84..9a927fae 100644 --- a/WINGs/wview.c +++ b/WINGs/wview.c @@ -102,8 +102,8 @@ static W_View *createView(W_Screen * screen, W_View * parent) view->attribFlags |= CWBackPixel | CWColormap | CWBorderPixel | CWBackPixmap; view->attribs.background_pixmap = None; - view->attribs.background_pixel = screen->gray->color.pixel; - view->attribs.border_pixel = screen->black->color.pixel; + view->attribs.background_pixel = WMColorPixel(screen->gray); + view->attribs.border_pixel = WMColorPixel(screen->black); view->attribs.colormap = screen->colormap; view->backColor = WMRetainColor(screen->gray); @@ -483,7 +483,7 @@ void W_RedisplayView(W_View * view) WMHandleEvent(&ev); } -void W_SetViewBackgroundColor(W_View * view, WMColor * color) +void W_SetViewBackgroundColor(W_View * view, WMColor *color) { if (view->backColor) WMReleaseColor(view->backColor); @@ -491,9 +491,9 @@ void W_SetViewBackgroundColor(W_View * view, WMColor * color) view->attribFlags |= CWBackPixel; view->attribFlags &= ~CWBackPixmap; - view->attribs.background_pixel = color->color.pixel; + view->attribs.background_pixel = WMColorPixel(color); if (view->flags.realized) { - XSetWindowBackground(view->screen->display, view->window, color->color.pixel); + XSetWindowBackground(view->screen->display, view->window, WMColorPixel(color)); XClearWindow(view->screen->display, view->window); } } -- 2.39.5