<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule"
>

<channel>
	<title>Stephan Sokolow&#039;s Blog</title>
	<atom:link href="http://blog.ssokolow.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.ssokolow.com</link>
	<description>Programming, Linux, Web, and Fiction Reviews</description>
	<lastBuildDate>Sun, 08 Mar 2026 09:08:27 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://blog.ssokolow.com/wp-content/uploads/2015/08/cropped-favicon-32x32.png</url>
	<title>Stephan Sokolow&#039;s Blog</title>
	<link>https://blog.ssokolow.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<creativeCommons:license>https://creativecommons.org/licenses/by-sa/4.0/</creativeCommons:license>
	<item>
		<title>Tips Roll-up 2023-2024</title>
		<link>https://blog.ssokolow.com/archives/2025/02/12/tips-roll-up-2023-2024/</link>
					<comments>https://blog.ssokolow.com/archives/2025/02/12/tips-roll-up-2023-2024/#respond</comments>
		
		<dc:creator><![CDATA[Stephan Sokolow]]></dc:creator>
		<pubDate>Wed, 12 Feb 2025 05:09:30 +0000</pubDate>
				<category><![CDATA[Geek Stuff]]></category>
		<guid isPermaLink="false">https://blog.ssokolow.com/?p=6981</guid>

					<description><![CDATA[Here are a few things that I posted on Mastodon because they were too short for a blog post, but which I think should be cross-posted anyway for archival:]]></description>
										<content:encoded><![CDATA[
<p>Here are a few things that I posted on Mastodon because they were too short for a blog post, but which I think should be cross-posted anyway for archival:</p>



<ul class="wp-block-list">
<li><strong>KVM &#8220;not compatible with&#8221; Linux or Mac OS:</strong> If you have a DVI KVM switch that says its &#8220;double-tap scroll lock to switch inputs&#8221; feature is only compatible with Windows, what they probably mean is &#8220;we listen for the scroll lock LED to blink and Windows is the only OS that maps the Scroll Lock keycode to a modifier in this day and age&#8221;. Here&#8217;s a <a href="https://gist.github.com/ssokolow/01e8b9b6029f1a4c73b53b48aa5c770a">script</a> I wrote to trigger the switch on X11 and then made a taskbar icon for.</li>



<li><strong>Two-page CBZ to HTML conversion:</strong> If you&#8217;re stubborn like me and have a CBZ file containing a bunch of two-page spreads that Calibre splits and orders incorrectly when making an EPUB file, you too can work around the iOS Files app&#8217;s refusal to load subresources and turn it into a quick-and-dirty CBZ reader by embedding your pages into an HTML file using data URIs using <a href="https://gist.github.com/ssokolow/482f9277251c7fdbd907c2711109f050">this script I wrote</a>&#8230; it actually performs quite well in my testing. (&lt;2s load time for a 40MiB CBZ file)</li>



<li><strong>Sandboxing libusb:</strong> If you&#8217;re setting up systemd sandboxing for a libusb-based daemon, you&#8217;ll need to allow <code>AF_NETLINK</code> sockets (eg. <code>RestrictAddressFamilies=AF_NETLINK</code>) if you want it to work… I&#8217;m still trying to figure out a working <code>DeviceAllow</code> string for my CM19A so I can go back to the <code>DevicePolicy=closed</code> and <code>PrivateDevices=yes</code> I was using with my CM17A. You can poke at the full systemd unit file at <a href="https://github.com/ssokolow/fan_remote/">ssokolow/fan_remote</a> on GitHub.</li>



<li><strong>TekSavvy DSL, IPv6, and OPNSense:</strong> If you&#8217;re on TekSavvy DSL, following <a href="https://docs.opnsense.org/manual/how-tos/ipv6_dsl.html" target="_blank" rel="noreferrer noopener">the &#8220;IPv6 for generic DSL dialup</a>&#8220;<a href="https://docs.opnsense.org/manual/how-tos/ipv6_dsl.html" target="_blank" rel="noreferrer noopener"> guide</a> then restarting your router and disconnect/reconnect cycling LAN devices will WORK to get you IPv6 (you may need to toggle Firefox&#8217;s DoH to get fallback working on <a href="https://ipv6-test.com/" target="_blank" rel="noreferrer noopener">https://ipv6-test.com/</a> )&#8230; but it won&#8217;t get you ICMPv6. Follow <a href="https://homenetworkguy.com/how-to/configure-ipv6-opnsense-with-isp-such-as-comcast-xfinity/" target="_blank" rel="noreferrer noopener">this &#8220;How to Configure IPv6 in Your Home Network with ISP such as Comcast Xfinity&#8221; guide</a> for that but set &#8220;any&#8221; as the destination address instead of &#8220;WAN address&#8221; or it won&#8217;t work.</li>



<li><strong>86Box and Flatpak:</strong> If you&#8217;re getting strange read/write errors or &#8220;sharing violation&#8221;s when running &#8220;make boot disk&#8221; tools/batch files in 86Box and you&#8217;re using the Flatpak version, create your floppy disk images inside <code>~/.var/app/net._86box._86Box/</code> or grant a manifest permission. Apparently there&#8217;s a bug or incompleteness in the Flatpak documents portal FUSE filesystem.</li>



<li><strong>Missing CD Audio in Games:</strong> If you get an <code>MMSYSTEM262</code> error from The Incredible Toon Machine and no CD music (or just no CD music from Age of Empires in general) on Windows 9x and you have more than one CD drive (eg. physical and DAEMON Tools or Alcohol 52% Retro Edition), the fix is probably to go into <code>Control Panel → Multimedia → Devices → Media Control Devices → CD Audio Device (Media Control) → Properties → Settings</code> … and change &#8220;Default CD-ROM drive for playing CD music&#8221;.<br />I&#8217;m not sure how to do this on Windows XP since the equivalent to that last <code>Settings</code> button does nothing when clicked, so the workaround for newer Windows versions is just to go into the system management console and swap the drive letters of your optical drives. (Though that may make some badly-designed games require a reinstall to get them to look at the new drive letter.)</li>



<li><strong>Flaky iPhone:</strong> If you&#8217;ve got a hand-me-down iPhone where the flashlight or rotation lock occasional toggle without being asked, the touch sensor on the back may be too sensitive. Try turning off the &#8220;tap on the back of the phone to&#8230;&#8221; feature and see if that fixes it. (For me, it had become so sensitive it was activating <em>through</em> the Otter Box belt clip I&#8217;m using as a lens cap and the air gap below it.)</li>



<li><strong>YD-RP2040:</strong> The YD-RP2040 isn&#8217;t 100% compatible with name-brand Raspberry Pi Pico boards. If you need to build something that has it acting as a USB host, prepare for the slightly fiddly job of tacking a piece of resistor leg between the two legs of a BAT54C barrier diode facing the USB C connector to allow current from <code>Vin</code> to flow to the USB connector (I&#8217;ve contributed an annotated photo in the ps2x2pico <a href="https://github.com/No0ne/ps2x2pico/?tab=readme-ov-file#troubleshooting">README</a> &#8230; also, the <code>(VBUS)</code> and <code>(VSYS)</code> silkscreens on the bottom are wrong. <code>Vout</code> is <strong>not</strong> <code>VBUS</code>. Follow <a href="https://github.com/initdc/YD-RP2040/blob/master/YD-2040-2022-V1.1-SCH.pdf">this schematic</a>.</li>



<li><strong>Display Alignment in KDE:</strong> If snap-to-edge behaviour in KDE Display Settings is preventing you from getting the monitor alignment you want (eg. top-aligned 1280&#215;1024,1920&#215;1080,1280&#215;1024), try changing (but not applying) resolutions, then snapping, then changing them back.</li>



<li><strong>No route to host:</strong> If your client says &#8220;No route to host&#8221; on some ports but not others, double-check your server&#8217;s firewall configuration… for example, if you&#8217;re trying to use UFW and something also installed firewalld behind your back, you&#8217;re going to get very confusing symptoms that won&#8217;t be fixed by asking UFW to flush your iptables and re-create them.</li>



<li><strong>annoyingasians.mpg:</strong> If you ever wondered what the music was from an old ebaumsworld video named <code>annoyingasians.mpg</code> with no other context&#8230; searching the filename on YouTube allows Content ID to find the answer. It&#8217;s called<a href="https://www.youtube.com/watch?v=2TqoacPsq_8"> 중화반점.</a></li>



<li><strong>Firefox Smooth Scrolling:</strong> If you&#8217;re getting smooth scrolling from your scroll wheel in Firefox despite the checkbox still being unchecked and you don&#8217;t like your scrolling being slow/laggy, try going into <code>about:config</code> and toggling the <code>general.smoothScroll.mouseWheel</code> pref to also be false.</li>



<li><strong>WinSCP:</strong> If you&#8217;re using WinSCP&#8217;s <code>synchronize</code> command in a script but you don&#8217;t edit your script very often and your new exclusion pattern seems to be getting ignored, check if you&#8217;re trying to name a directory without including the trailing slash.</li>



<li><strong>Occam&#8217;s Razor:</strong> Put a pin in this for future sharing → <a href="https://www.youtube.com/watch?v=mO46CNftRDs" target="_blank" rel="noreferrer noopener">https://www.youtube.com/watch?v=mO46CNftRDs</a><br />&#8220;Actually, it&#8217;s not asteroid bacteria&#8230; we discovered that bacteria managed to evolve to eat the cleaning products we use to sterilize clean rooms&#8221; is one of the most intuitive examples I&#8217;ve seen for why people shouldn&#8217;t leap to assuming fantastic answers like UFOs or cryptids.</li>



<li><strong>Python enums:</strong> Because of how Python&#8217;s <code>enum.Enum</code> implements nominal typing and how Python imports work, it risks seemingly mundane refactorings causing <code>var == FooEnum.Bar</code> comparisons to start to mysteriously fail when PyQt and Qt Designer&#8217;s &#8220;Promote…&#8221; feature are involved. If you don&#8217;t need such strict nominal typing, using <code>enum.IntEnum</code> to relax the equality comparison will avoid that source of footguns.</li>
</ul>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.ssokolow.com/archives/2025/02/12/tips-roll-up-2023-2024/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
				<creativeCommons:license>https://creativecommons.org/licenses/by-sa/4.0/</creativeCommons:license>
	</item>
		<item>
		<title>Fixing Hotplug for the ATI Remote Wonder II on X11</title>
		<link>https://blog.ssokolow.com/archives/2024/01/21/fixing-hotplug-for-the-ati-remote-wonder-ii-on-x11/</link>
					<comments>https://blog.ssokolow.com/archives/2024/01/21/fixing-hotplug-for-the-ati-remote-wonder-ii-on-x11/#respond</comments>
		
		<dc:creator><![CDATA[Stephan Sokolow]]></dc:creator>
		<pubDate>Mon, 22 Jan 2024 02:03:43 +0000</pubDate>
				<category><![CDATA[Lair Improvement]]></category>
		<guid isPermaLink="false">http://blog.ssokolow.com/?p=6963</guid>

					<description><![CDATA[EDIT: It turns out hotplug wasn&#8217;t the problem. Something else is resetting the X11 keymap without it involving the device getting reset&#8230; I&#8217;m done with this nonsense. I&#8217;ll temporarily set a user cronjob to force it back to what it&#8217;s &#8230; <a href="https://blog.ssokolow.com/archives/2024/01/21/fixing-hotplug-for-the-ati-remote-wonder-ii-on-x11/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p><strong>EDIT:</strong> It turns out hotplug wasn&#8217;t the problem. Something else is resetting the X11 keymap without it involving the device getting reset&#8230; I&#8217;m done with this nonsense. I&#8217;ll temporarily set a user cronjob to force it back to what it&#8217;s supposed to be and then, when I have a moment, replace <code>xbindkeys</code> with a udev rule to loosen the security on the ATi Remote Wonder&#8217;s <code>evdev</code> node (it&#8217;s not as if I&#8217;ll ever be entering sensitive data using it) and a custom quick-and-dirty runs-in-my-X11-session daemon to listen to the raw evdev input events and react to them. (Sort of a knock-off <a href="https://lirc.org/">LIRC</a> for something the kernel driver exposes as a keyboard and mouse.)</p>



<p><strong>EDIT (The following day):</strong> Instead of going through all this mess, just bypass the nonsense. Install <a href="https://github.com/k0kubun/xremap">xremap</a>, set a udev rule like <code>SUBSYSTEMS=="usb", ATTRS{idVendor}=="0471", ATTRS{idProduct}=="0602", MODE="0664"</code>, create your mappings somewhere like <code>~/.config/xremap.yml</code>, and then add an autostart entry for your desktop that says <code>sh -c "exec xremap ~/.config/xremap.yml --watch=device --device 'ATI Remote Wonder II'"</code>. That way, you&#8217;re binding directly against the evdev symbols <em>and</em> you have the ability to keybind to things like &#8220;A, but only from the remote, not the keyboard&#8221;, which is a big hassle otherwise. Its support for application-specific keybinds even has support for Wayland if you&#8217;re using either GNOME Shell, KWin, or something wlroots-based as your compositor.</p>



<p>If you&#8217;ve got an ATi Remote Wonder II and you&#8217;re using an X11-based desktop, you might have noticed that it&#8217;s a bit of a hassle to get the mappings to stick for the buttons with keycodes outside the 0-255 range that X11 supports.</p>



<p>First, you need to remap them into the range the X11 core protocol supports, which isn&#8217;t <em>that</em> difficult if you&#8217;re familiar with <a href="https://wiki.archlinux.org/title/udev#About_udev_rules">writing udev rules</a>&#8230;</p>



<pre class="wp-block-code"><code># /etc/udev/rules.d/99-ati-remote-wonder-ii.rules
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0471", ATTRS{idProduct}=="0602", RUN+="/usr/bin/setkeycodes 0x005C 28 0x015C 28 0x025C 28 0x035C 28 0x045C 28 0x0020 192 0x0120 192 0x0220 192 0x0320 192 0x0420 192 0x0021 19
3 0x0121 193 0x0221 193 0x0321 193 0x0421 193"</code></pre>



<p>&#8230;but the range from 0-255 makes it kind of difficult to find keys that both <em>have</em> a default X11 keysym mapping and don&#8217;t have some kind of predefined behaviour attached to them, such as altering the volume.</p>



<p>With Kubuntu Linux 20.04 LTS, the above line was enough but, when I upgraded to 22.04 LTS, something broke my mapping for a &#8220;trigger the talking clock from bed and log the time I asked&#8221; button.</p>



<p>KDE lacks the ability to do what I want through the GUI, custom keymaps are practically undocumented and apparently require editing stuff under <code>/usr</code> to boot, and I couldn&#8217;t just run <code>xmodmap</code> once a minute on a cronjob, since that exacerbated a reset bug that shows up with X11+my USB-PS2 adapter+my pre-2013-layout Unicomp keyboard, so that left me with only one option: Figuring out the &#8220;in an X11 session&#8221; equivalent to <code>udev</code>&#8216;s <code>RUN+=</code> construct.</p>



<p>Enter <code><a href="https://github.com/andrewshadura/inputplug">inputplug</a></code>. It&#8217;s included in the Ubuntu repos and it&#8217;s a daemon which will run a script every time the XInput hierarchy changes.</p>



<p>Here&#8217;s the little script I wrote (based on the usual boilerplate template I start all my Python scripts from), to fire off an <code>xmodmap</code> every time some kind of USB hiccup resets the ATi Remote Wonder II&#8217;s key mapping:</p>



<pre class="wp-block-code"><code>#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Helper to apply xmodmap settings every time USB connectivity for the
ATi Remote Wonder II hiccups and resets them.
"""

__author__ = "Stephan Sokolow (deitarion/SSokolow)"
__appname__ = "inputplug command for ATi Remote Wonder II"
__version__ = "0.1"
__license__ = "MIT"

import logging, os, subprocess, time
log = logging.getLogger(__name__)


def main():
    """The main entry point, compatible with setuptools entry points."""
    from argparse import ArgumentParser, RawDescriptionHelpFormatter
    parser = ArgumentParser(formatter_class=RawDescriptionHelpFormatter,
      description=__doc__.replace('\r\n', '\n').split('\n--snip--\n')&#91;0])
    parser.add_argument('-V', '--version', action='version',
      version="%%(prog)s v%s" % __version__)
    parser.add_argument('-v', '--verbose', action="count",
      default=2, help="Increase the verbosity. Use twice for extra effect.")
    parser.add_argument('-q', '--quiet', action="count",
      default=0, help="Decrease the verbosity. Use twice for extra effect.")
    parser.add_argument('event_type', action="store")
    parser.add_argument('device_id', action="store")
    parser.add_argument('device_type', action="store")
    parser.add_argument('device_name', action="store")

    args = parser.parse_args()

    # Set up clean logging to stderr
    log_levels = &#91;logging.CRITICAL, logging.ERROR, logging.WARNING,
                  logging.INFO, logging.DEBUG]
    args.verbose = min(args.verbose - args.quiet, len(log_levels) - 1)
    args.verbose = max(args.verbose, 0)
    logging.basicConfig(level=logging.DEBUG,
                format='%(levelname)s: %(message)s')

    if args.device_type != 'XISlaveKeyboard':
        log.debug("Skipped event from device (type != XISlaveKeyboard): %s",
            args.device_name)
        return
    if args.device_name != 'ATI Remote Wonder II':
        log.debug("Skipped event from device (name != ATI Remote Wonder II):"
            " %s", args.device_name)
        return
    log.info("Calling xmodmap after 1-second delay")
    time.sleep(1)
    subprocess.check_call(&#91;'xmodmap', os.path.expanduser('~/.xmodmaprc')])


if __name__ == '__main__':  # pragma: nocover
    main()

# vim: set sw=4 sts=4 expandtab :</code></pre>



<p>Yes, the <code>time.sleep(1)</code> is a hack, but I just don&#8217;t have time to be <em>that</em> correct about it. You run it by putting it at <code>~/bin/set_xmodmap_for_remote.py</code>, <code>chmod</code>-ing it executable, and launching <code>inputplug -0 -c ~/bin/set_xmodmap_for_remote.py</code>.</p>



<p>(The <code>-0</code> makes <code>inputplug</code> act as if all input devices were hot-plugged <em>after</em> it launched, so you don&#8217;t need to pull and plug the remote&#8217;s receiver on boot to get the initial <code>xmodmap</code>.)</p>



<p>Just run that on login through whatever approach your desktop prefers and you should be good.</p>



<p>I&#8217;m partial to putting this into <code>~/.config/autostart/inputplug.desktop</code> rather than puttering around with the GUIs:</p>



<pre class="wp-block-code"><code>&#91;Desktop Entry]
Version=1.0
Type=Application
Name=inputplug
GenericName=XInput Hierarchy Change Handler
Comment=Restore xmodmap changes after ATi Remote Wonder hotplug
Exec=sh -c "exec inputplug -0 -c ~/bin/set_xmodmap_for_remote.py"
StartupNotify=true
Terminal=false</code></pre>



<p>(The <code>sh -c "exec ..."</code> hack is needed because <code>.desktop</code> files don&#8217;t support <code>~</code> or <code>$HOME</code> otherwise and I don&#8217;t want to hard-code the path to my home dir.)</p>



<p>I have noticed a weird thing in testing where the first input event from the remote after a hotplug isn&#8217;t subject to the changed settings, no matter how long I wait before trying, but I&#8217;m not sure how to diagnose it so we&#8217;ll just stop here for now.)</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.ssokolow.com/archives/2024/01/21/fixing-hotplug-for-the-ati-remote-wonder-ii-on-x11/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
				<creativeCommons:license>https://creativecommons.org/licenses/by-sa/4.0/</creativeCommons:license>
	</item>
		<item>
		<title>Fanfiction &#8211; Taylor Varga</title>
		<link>https://blog.ssokolow.com/archives/2023/11/24/fanfiction-taylor-varga/</link>
					<comments>https://blog.ssokolow.com/archives/2023/11/24/fanfiction-taylor-varga/#comments</comments>
		
		<dc:creator><![CDATA[Stephan Sokolow]]></dc:creator>
		<pubDate>Fri, 24 Nov 2023 08:45:14 +0000</pubDate>
				<category><![CDATA[Fanfiction]]></category>
		<guid isPermaLink="false">http://blog.ssokolow.com/?p=6948</guid>

					<description><![CDATA[Taylor Varga by mp3.1415player Length: 2,058,592 wordsStatus: OngoingCrossover: Worm + Luna Varga (but with the assumption nobody but the author has seen Luna Varga) Today&#8217;s fic is a doozy and not just for its eye-opening length. Like the stories by &#8230; <a href="https://blog.ssokolow.com/archives/2023/11/24/fanfiction-taylor-varga/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p><a href="https://www.fanfiction.net/s/12404721/1/Taylor-Varga">Taylor Varga</a> by mp3.1415player</p>



<p><strong>Length:</strong> 2,058,592 words<br /><strong>Status:</strong> Ongoing<br /><strong>Crossover:</strong> Worm + <a href="https://www.anime-planet.com/anime/luna-varga">Luna Varga</a> (but with the assumption nobody but the author has seen Luna Varga)</p>



<p>Today&#8217;s fic is a doozy and not just for its eye-opening length. Like the stories by mp3.1415player on my <a href="https://blog.ssokolow.com/fanfiction-review-todo-list/">review TODO list</a>, it&#8217;s excellent on its own merits. (Among other things, it feels as if at least 95% of all memorable moments in the Worm fanfiction I&#8217;ve read come from this story.)</p>



<p>Being so long, it&#8217;s one of those stories where more than just the plot evolves over time&#8230; so I&#8217;ll discuss it in segments. There will be things that are <em>technically</em> spoilers but, because this fic is so much about the journey, I don&#8217;t think knowing the high-level details ruin anything.</p>



<p>When things start out, it&#8217;s Yet Another Alternative Trigger Fic (Buffy the Vampire Slayer fandom has YAHF (Yet Another Halloween Fic), so I think I can make a mild commentary on the prevalence of alternative triggers). Being a Luna Varga crossover, as you might expect, Taylor winds up stuck with a tail and body-sharing with/changing into a Godzilla knock-off.</p>



<p>However, that&#8217;s where things diverge. If there&#8217;s one summary that <em>would</em> fit the entire story, it&#8217;s &#8220;What would happen if you dropped an <a href="https://tvtropes.org/pmwiki/pmwiki.php/Main/OutsideContextProblem">Outside Context Problem</a> into the Worm setting on the side of good?&#8221; &#8230;very much so. Taylor Varga is essentially a fix-fic that doesn&#8217;t feel like a fix-fic. It&#8217;s a story that could be summed up as &#8220;destiny trolls the Worm setting&#8221;. It&#8217;s a light, character-centric story that&#8217;s a lot of fun.</p>



<p>Just look at what Director Piggot has to say about informing the Chief Director:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>&#8220;I was really hoping to have more to tell her than &#8216;<em>I don&#8217;t know what the fuck is going on but it&#8217;s scaly and snickers a lot</em>&#8216; though. Never mind this entire damn Coil problem.&#8221;</p>
<cite>Taylor Varga, Chapter 98</cite></blockquote>



<p>&#8230;and yes, them thinking that Coil is a problem is a result of Coil&#8217;s problem status being neutralized. More specifically, because Taylor is now bonded to a magic alien dinosaur demon, she doesn&#8217;t quite follow the same laws of physics anymore, which causes a <em>ton</em> of problems for any thinker abilities that would otherwise make it difficult to write a fix-fic which runs off the canon rails as gleefully as this one does over its couple-million-word run. In Coil&#8217;s case, he spends the first half of the fic hiding in his bunker, bothering nobody, as he desperately tries to figure ouy why timelines where he meddles keep ending in black voids.</p>



<p>Of course, it it were <em>just</em> a Luna Varga crossover, that&#8217;d be too simple. Whatever &#8220;Greater Power&#8221; decided to hijack Taylor&#8217;s trigger event also unshackled Varga&#8217;s abilities&#8230; watch out Brockton Bay, Taylor Hebert is now an infinitely variable dinosaur (her words, not mine) with a human-form tail hidden under a magical <a href="https://hitchhikers.fandom.com/wiki/Somebody_Else%27s_Problem_Field">Somebody Else&#8217;s Problem Field</a> and a permanent new best friend with a questionable sense of appropriate humor.</p>



<p>So, yes. Stage one in the story is Taylor Hebert or, more correctly, &#8220;Saurial&#8221; the anthropomorphic velociraptor girl, wandering around Brockton Bay and stopping crime she bumps into while she gets used to her changed situation&#8230; and then starting to experiment with other forms. Enter PHO. Playing into people&#8217;s preconceptions because it&#8217;s fun and/or helps keep a secret identity will be a recurring theme.</p>



<p>Combine that with yet another twist on &#8220;The locker incident leads to Taylor and Danny manoeuvring Blackwell into a corner&#8221; and Taylor winds up at Arcadia where a chance encounter (Amy Dallon trips over Taylor&#8217;s invisible tail and then Taylor unknowingly gives her a glimpse at her biology when offering her a hand up) and Taylor&#8217;s ambient Outside Context Problem-ness (which will be lampshaded later) lead to a new friendship for Taylor and Panacea finally accepting the idea that she needs some &#8220;me time&#8221;.</p>



<p>Throw in an incident with Taylor saving the Undersiders from Lung, and the stage is set for phase 2.</p>



<p>In Phase 2, Amy Dallon gets talked into actually using her abilities and, before you know it, Ianthe (Amy) and Metis (Lisa), the reptilian exo-suits made from repurposed onion biomass, are wandering around and PHO is inadvertently helping them to build a backstory about The Family, a species of reptilian aliens from deep time who H.P. Lovecraft might have taken inspiration from.</p>



<p>Phase 2 also involves a lot of &#8220;Let&#8217;s use fix-fic as a vehicle to troll the setting by way of varga magic&#8221; humour, including a supermaterial Varga can conjure up that he only knows as &#8220;the good stuff&#8221;. </p>



<p>This is also a fic where Taylor is so good at math that she arrives at Vista&#8217;s powers from another direction, and then makes a &#8220;desktop R&#8217;lyeh&#8221; as a gag gift for Danny which inspires Vista to unintentionally traumatize her classmates and teammates by discovering how to create Lovecraftian &#8220;monstrous geometry&#8221; using only a pencil and paper&#8230; and one where Taylor helps Amy realize that, if she creates a bioconstruct to do it for her, she can enhance herself, including her brain, and do so without the risk of wrecking something. (Something which, combined with Taylor bringing novelty wherever she goes, makes the shards of all Taylor&#8217;s growing circle of cape friends very happy&#8230; though Lisa isn&#8217;t particularly pleased with how much she&#8217;s inadvertently taught hers to feel smug when they start to sense their presence.)</p>



<p>Basically, once the story really gets going, it&#8217;s a fun character piece about three smart, wildly OP young women with offbeat senses of humour (one of whom is still clinging to the idea of being &#8220;the normal one&#8221;) slowly fixing the Worm setting with the power of trolling, confusion, unknowingly having moments of comically good luck, being genuinely good people, and being so visibly OP in their alternative identities that it completely stymies people who would plot against them.. (Gotta love stories where people are unarguably OP but it doesn&#8217;t hurt the story because &#8220;not even Superman can punch clinical depression&#8221;.)</p>



<p>If you&#8217;re thinking this sounds vaguely reminiscent of stories like Make A Wish by Rorschach&#8217;s Blot which rely heavily on &#8220;humour based around a gigantic misconception and that misconception slowly becoming reality by default&#8221;, you&#8217;d be right and this <em>also</em> inspired a slew of third-party contributions. In later chapters, look forward to omakes like &#8220;Saurial is not pleased that Odin from the Marvel Cinematic Universe is claiming her old hammer (Mjolnir) to be his own work&#8221; and spin-offs like <a href="https://www.fanfiction.net/s/12959550/1/The-Long-Slow-Lizarding-of-Hermione-Granger">The Long Slow Lizarding of Hermione Granger</a>.</p>



<p>So, what would I rate it? Well, it gets a bit slow around the bit when they finally go in to dig out Coil, and I do think the omakes got a bit too numerous at points, but, overall, it&#8217;s still good enough that I&#8217;d probably give it a 4.9 out of 5. Definitely would recommend.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.ssokolow.com/archives/2023/11/24/fanfiction-taylor-varga/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
				<creativeCommons:license>https://creativecommons.org/licenses/by-sa/4.0/</creativeCommons:license>
	</item>
		<item>
		<title>Vorke V1 Plus Thermal/Fan Fix for Linux</title>
		<link>https://blog.ssokolow.com/archives/2023/11/17/vorke-v1-plus-thermal-fan-fix-for-linux/</link>
					<comments>https://blog.ssokolow.com/archives/2023/11/17/vorke-v1-plus-thermal-fan-fix-for-linux/#respond</comments>
		
		<dc:creator><![CDATA[Stephan Sokolow]]></dc:creator>
		<pubDate>Fri, 17 Nov 2023 06:05:56 +0000</pubDate>
				<category><![CDATA[Geek Stuff]]></category>
		<guid isPermaLink="false">http://blog.ssokolow.com/?p=6939</guid>

					<description><![CDATA[If you have a Vorke V1 Plus that doesn&#8217;t want to drive its fan under Linux, or which doesn&#8217;t want to shut off the fan after the UEFI turns it on at boot, here&#8217;s what worked for me: As for &#8230; <a href="https://blog.ssokolow.com/archives/2023/11/17/vorke-v1-plus-thermal-fan-fix-for-linux/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p>If you have a Vorke V1 Plus that doesn&#8217;t want to drive its fan under Linux, or which doesn&#8217;t want to shut off the fan after the UEFI turns it on at boot, here&#8217;s what worked for me:</p>



<ol class="wp-block-list">
<li>Make sure you&#8217;ve got a kernel version that allows you to manually control the fan via one of the <code>/sys/class/thermal/cooling_deviceX/cur_state</code> nodes. Debian bookworm&#8217;s default <code>6.1.0-13</code> kernel had problems with that while my Ubuntu 22.04 LTS flash drive&#8217;s <code>6.2.0-16</code> didn&#8217;t, so I wound up pulling one of the 6.5.0 kernels from Debian <a href="https://wiki.debian.org/Backports">backports</a>.)</li>



<li>Make sure <code>thermald</code> is installed. My experience is that, without it, the Vorke V1 Plus will just leave its fan on whatever the UEFI set it to, no matter how high or low the CPU temperature goes.</li>



<li>Write this configuration into <code>/etc/thermald/thermal-conf.xml</code>:<pre>&lt;?xml version="1.0"?><br />&lt;ThermalConfiguration><br />  &lt;Platform><br />    &lt;Name>Prefer fan over thermal throttling&lt;/Name><br />    &lt;ProductName>*&lt;/ProductName><br />    &lt;Preference>PERFORMANCE&lt;/Preference><br />  &lt;/Platform><br />&lt;/ThermalConfiguration></pre>As far as I can tell, <code>thermald</code> on Debian bookworm defaults to <code>&lt;Preference>QUIET&lt;/Preference></code>, which means &#8220;Thermal throttle as much as you need to in order to avoid spinning up the fan&#8221;.<br /><br />(Which <em>is</em> a neat option for things with shrill fans like the Vorke V1 Plus if I can figure out an easy way to toggle it… maybe reassign the power button from &#8220;request a clean shutdown&#8221; to &#8220;toggle cooling between performance and quiet&#8221;.)<br /><br />There&#8217;s probably some other way you&#8217;re meant to do this, and I welcome comments from people who actually know how this is supposed to work, because I found thermald to be frustratingly under-documented.</li>



<li>Run <code>systemctl edit thermald.service</code> and paste in these lines:<pre>[Service]<br />ExecStart=<br />ExecStart=/usr/sbin/thermald --no-daemon --dbus-enable --exclusive-control --config-file=/etc/thermald/thermal-conf.xml</pre>Without <code>--exclusive-control</code>, I found thermald still allowing temperatures to shoot up without enabling the fan.</li>
</ol>



<p>As for <code>--config-file</code>, the manpage says <code>/etc/thermald/thermal-conf.xml</code> should be in the default search path, but, without specifying it explicitly, I was still getting no effect, despite neither of the higher-priority paths existing.</p>



<ol class="wp-block-list" start="4">
<li>Reboot (instead of just restarting thermald) to make sure all changes will persist as intended and stress-test the CPU with something like <code>stress --cpu 4</code>.</li>
</ol>



<p>If you still have trouble, try toggling DPTF enable/disable in the UEFI settings. (hold Delete while powering on, and then go into <code>Advanced > Thermal</code>.)</p>



<p>I don&#8217;t know if playing around with DPTF is necessary with the Vorke V1 Plus, but I also have a Vorke V1 and I needed to toggle it on that one so I could memtest86 the RAM upgrade I put in without the thing slowly overheating.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.ssokolow.com/archives/2023/11/17/vorke-v1-plus-thermal-fan-fix-for-linux/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
				<creativeCommons:license>https://creativecommons.org/licenses/by-sa/4.0/</creativeCommons:license>
	</item>
		<item>
		<title>How to remove pcANYWHERE32 v8.0 from Windows XP</title>
		<link>https://blog.ssokolow.com/archives/2023/09/06/how-to-remove-pcanywhere32-v8-0-from-windows-xp/</link>
					<comments>https://blog.ssokolow.com/archives/2023/09/06/how-to-remove-pcanywhere32-v8-0-from-windows-xp/#respond</comments>
		
		<dc:creator><![CDATA[Stephan Sokolow]]></dc:creator>
		<pubDate>Wed, 06 Sep 2023 23:30:25 +0000</pubDate>
				<category><![CDATA[Retrocomputing]]></category>
		<guid isPermaLink="false">http://blog.ssokolow.com/?p=6863</guid>

					<description><![CDATA[…so you naively thought that continuing past the Windows XP compatibility warning and installing pcANYWHERE 8.0 would give you a working pcANYWHERE client but no server? …and you now have a machine that just boots into a black 640&#215;480 screen &#8230; <a href="https://blog.ssokolow.com/archives/2023/09/06/how-to-remove-pcanywhere32-v8-0-from-windows-xp/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p>…so you naively thought that continuing past the Windows XP compatibility warning and installing pcANYWHERE 8.0 would give you a working pcANYWHERE client but no server?</p>



<p>…and you now have a machine that just boots into a black 640&#215;480 screen which ignores Ctrl+Alt+Delete but does let you move the mouse?</p>



<p>…even if you choose to boot into Safe Mode?</p>



<p>Here&#8217;s how I recovered my Windows XP retro-machine without undue pain:</p>



<ol class="wp-block-list">
<li>Pull up the &#8220;Windows Advanced Options Menu&#8221; (Hit F8 after your BIOS hands off to Windows but before the boot logo appears… I just tap it repeatedly.)</li>



<li>Choose &#8220;Last Know Good Configuration (your most recent settings that worked)&#8221;</li>



<li>You&#8217;ll probably get a working boot with auto-login temporarily disabled. I just hit Enter with the username it pre-filled and no password.</li>



<li>Use Add/Remove Programs to uninstall pcANYWHERE.</li>



<li>To be sure you&#8217;ve gotten rid of it, go into System Restore (Start &gt; Applications &gt; Accessories &gt; System Tools &gt; System Restore) and roll your system configuration back to the most recent System Restore point.</li>
</ol>



<p>That should do it.</p>



<p><strong>TIP:</strong> If you can&#8217;t get F8 to work, make sure you&#8217;re using a PS/2 keyboard, not a USB one.</p>



<p>(If your BIOS doesn&#8217;t have working USB→PS/2 keyboard emulation, the Windows boot menu won&#8217;t see your input either because it happens before Windows&#8217;s own USB HID drivers get loaded. This confused me for a moment, before I realized I&#8217;d never needed to go into the BIOS setup or boot menu, or access the Windows boot options since I switched to a USB+VGA KVM switch to let it share the desk with my Power Mac G4.)</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.ssokolow.com/archives/2023/09/06/how-to-remove-pcanywhere32-v8-0-from-windows-xp/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
				<creativeCommons:license>https://creativecommons.org/licenses/by-sa/4.0/</creativeCommons:license>
	</item>
		<item>
		<title>Fanfiction &#8211; That Sounds Like Work</title>
		<link>https://blog.ssokolow.com/archives/2023/09/03/fanfiction-that-sounds-like-work/</link>
					<comments>https://blog.ssokolow.com/archives/2023/09/03/fanfiction-that-sounds-like-work/#respond</comments>
		
		<dc:creator><![CDATA[Stephan Sokolow]]></dc:creator>
		<pubDate>Sun, 03 Sep 2023 20:11:27 +0000</pubDate>
				<category><![CDATA[Fanfiction]]></category>
		<guid isPermaLink="false">http://blog.ssokolow.com/?p=6859</guid>

					<description><![CDATA[How does a completed Worm crackfic based around Taylor Hebert triggering with superpowered laziness sound? What about a fic with bits like this? &#8220;You let my brother hijack your body… so you don&#8217;t have to walk?&#8221; said Cherie with an &#8230; <a href="https://blog.ssokolow.com/archives/2023/09/03/fanfiction-that-sounds-like-work/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p>How does a completed Worm crackfic based around Taylor Hebert triggering with superpowered laziness sound?</p>



<p>What about a fic with bits like this?</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>&#8220;You let my brother hijack your body… so you don&#8217;t have to walk?&#8221; said Cherie with an incredulous tone.</p>



<p>&#8220;Of course! Have you tried walking? You have to pick up your leg off the ground and everything! The worst bit is that you have to do that over and over again if you want to get anywhere. The mere fact that walking exists proves that there is no such thing as an all-loving God! Man invented the wheel thousands of years ago just so we wouldn&#8217;t have to do the devil&#8217;s work anymore!&#8221; she ranted. This girl was a nut bag. Where did Jean-Paul even find her?</p>
</blockquote>



<p>If it sounds good, it&#8217;s <a href="https://forums.spacebattles.com/threads/that-sounds-like-work-au-crack-complete.641911/reader/">That Sounds Like Work</a> by Flabbyknight.</p>



<p>…spoiler alert: It starts with her beating Emma by being too super-apathetic (i.e. too lazy to care), driving Emma into such fits of frustration that the Winslow staff can&#8217;t help but respond.</p>



<p>In the spirit of the story&#8217;s premise, I won&#8217;t go on in more detail as I usually would (though I will say that the first chapter, as entertaining as it is, isn&#8217;t representative of the heights of crackfic-ness that it grows into) and I won&#8217;t take the time to figure out where above 4.5 it belongs on my rating scale.</p>



<p>…but I will say that I loved it and It also won second place in the Crack/Humor category in /r/WormFanfic&#8217;s <a href="https://www.reddit.com/r/WormFanfic/wiki/bestof2019">Best of 2019</a> list.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.ssokolow.com/archives/2023/09/03/fanfiction-that-sounds-like-work/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
				<creativeCommons:license>https://creativecommons.org/licenses/by-sa/4.0/</creativeCommons:license>
	</item>
		<item>
		<title>Quick tip for RetroArch&#8217;s DOSBox-Pure core</title>
		<link>https://blog.ssokolow.com/archives/2023/08/24/quick-tip-for-retroarchs-dosbox-pure-core/</link>
					<comments>https://blog.ssokolow.com/archives/2023/08/24/quick-tip-for-retroarchs-dosbox-pure-core/#respond</comments>
		
		<dc:creator><![CDATA[Stephan Sokolow]]></dc:creator>
		<pubDate>Fri, 25 Aug 2023 02:06:40 +0000</pubDate>
				<category><![CDATA[Retrocomputing]]></category>
		<guid isPermaLink="false">http://blog.ssokolow.com/?p=6853</guid>

					<description><![CDATA[If you&#8217;re trying to set up DOS games like Jetpack in something like RetroPie or Batocera, you might run into a problem where pressing the S key (&#8220;start new game&#8221; in Jetpack) doesn&#8217;t do anything, whether through a physical keyboard &#8230; <a href="https://blog.ssokolow.com/archives/2023/08/24/quick-tip-for-retroarchs-dosbox-pure-core/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p>If you&#8217;re trying to set up DOS games like <a href="https://www.adeptsoftware.com/jetpack/">Jetpack</a> in something like <a href="https://retropie.org.uk/">RetroPie</a> or <a href="https://batocera.org/">Batocera</a>, you might run into a problem where pressing the S key (&#8220;start new game&#8221; in Jetpack) doesn&#8217;t do anything, whether through a physical keyboard or through padtokey mappings.</p>



<p>This is most likely because RetroArch&#8217;s <a href="https://docs.libretro.com/guides/input-and-controls/">default hotkeys</a> map S to one of the buttons on the virtual gamepad. (A decision which makes sense for consoles, where you need a gamepad and a keyboard is optional at best, but makes no sense for retro computers, where a keyboard is standard or even built-in, and a joystick is optional)</p>



<p>While I don&#8217;t know about RetroPie, under Batocera, the simplest solution is to add the following lines to your <code>/userdata/system/batocera.conf</code> to disable those mappings:</p>



<pre class="wp-block-code"><code>dos.retroarch.input_player1_a=nul
dos.retroarch.input_player1_b=nul
dos.retroarch.input_player1_x=nul
dos.retroarch.input_player1_y=nul</code></pre>



<p>Then, if you do need mappings for DOS games, they probably go the other way (making the gamepad fake keypresses) and can be handled via padtokey mappings.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.ssokolow.com/archives/2023/08/24/quick-tip-for-retroarchs-dosbox-pure-core/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
				<creativeCommons:license>https://creativecommons.org/licenses/by-sa/4.0/</creativeCommons:license>
	</item>
		<item>
		<title>Fixing Applications Which Resist Feeling Platform-Native</title>
		<link>https://blog.ssokolow.com/archives/2023/06/17/fixing-applications-which-resist-feeling-platform-native/</link>
					<comments>https://blog.ssokolow.com/archives/2023/06/17/fixing-applications-which-resist-feeling-platform-native/#respond</comments>
		
		<dc:creator><![CDATA[Stephan Sokolow]]></dc:creator>
		<pubDate>Sun, 18 Jun 2023 03:36:43 +0000</pubDate>
				<category><![CDATA[Geek Stuff]]></category>
		<guid isPermaLink="false">http://blog.ssokolow.com/?p=6808</guid>

					<description><![CDATA[NOTE: I will update this post as I run into more application frameworks which need a little encouragement to feel native on my KDE desktop. While a lot of the technologies covered are strongly associated with Linux, they do still &#8230; <a href="https://blog.ssokolow.com/archives/2023/06/17/fixing-applications-which-resist-feeling-platform-native/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p><strong>NOTE:</strong> I will update this post as I run into more application frameworks which need a little encouragement to feel native on my KDE desktop. While a lot of the technologies covered <em>are</em> strongly associated with Linux, they do still tend to be portable, so this information isn&#8217;t <em>exclusively</em> for Linux.</p>



<p>It seems like, these days, the rise of Electron and other web-based application toolkits has emboldened every two-bit UI designer to forget that the point of a user interface is to fade into the background and let the content gain full focus. (And that means consistency is paramount.)</p>



<p>I won&#8217;t go into detail on that, given that others have already done that:</p>



<ul class="wp-block-list">
<li><a href="https://datagubbe.se/decusab/">The Decline of Usability</a></li>



<li><a href="https://medium.com/@probonopd/make-it-simple-linux-desktop-usability-part-1-5fa0fb369b42">Make. It. Simple. Linux Desktop Usability — Part 1</a></li>



<li><a href="https://pointieststick.com/2018/12/18/on-headerbars/">On Headerbars</a></li>



<li><a href="https://blog.brixit.nl/the-end-of-the-nice-gtk-button/">The end of the nice GTK button</a></li>



<li><a href="https://tonsky.me/blog/checkbox/">In Loving Memory of Square Checkbox</a></li>
</ul>



<p>It doesn&#8217;t help that everyone (<a href="https://web.archive.org/web/20230103193104/https://twitter.com/nikitonsky/status/1557357661171204098">including Apple</a>) seems to have forgotten Joel Spolsky&#8217;s <a href="https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/">Things You Should Never Do, Part I</a> and that the computing world in general has been sliding in this direction <a href="https://www.wired.com/2002/10/the-mac-os-that-cant-be-tweaked/">since 2002</a>.</p>



<p>&#8230;but it is still my computer, and I still have to live with it&#8230; so here&#8217;s a reference for how to apply UI customizations to various applications and UI toolkits as an end-user.</p>



<h2 class="wp-block-heading">Firefox</h2>



<p>Call me crazy, but I have to wonder what&#8217;s going on at Mozilla headquarters that nobody seems to have asked &#8220;Is it possible that making our UI chrome feel less similar to platform-native UI than Google Chrome&#8217;s, and grabbing user attention with whizbang elements of dubious value&#8230; is hurting our user appeal, not helping it?&#8221;</p>



<p>Anyway, here&#8217;s a summary of the <a href="https://www.reddit.com/r/FirefoxCSS/comments/73dvty/tutorial_how_to_create_and_livedebug_userchromecss/">relevant guides</a> on /r/FirefoxCSS (See also <a href="https://www.userchrome.org/adding-style-recipes-userchrome-css.html">userChrome.org</a>):</p>



<ol class="wp-block-list">
<li>Enable <code>userChrome.css</code>:
<ul class="wp-block-list">
<li>Open up <code>about:config</code> and set <code>toolkit.legacyUserProfileCustomizations.stylesheets</code> to <code>true</code></li>



<li>Create <code>chrome/userChrome.css</code> inside your profile folder (There&#8217;s a button to open a file browser window for your profile inside <code>about:support</code> but I somehow broke it while locking down my Flatpak install of Firefox further.)</li>
</ul>
</li>



<li>Enable the browser inspector:
<ul class="wp-block-list">
<li>Open the developer tools (<code>Ctrl + Shift + I</code> on Linux or Windows), open Settings (the cog which may be inside the overflow/… menu), and enable &#8220;Enable browser chrome and add-on debugging toolboxes&#8221; and &#8220;Enable remote debugging&#8221;.</li>



<li>Restart Firefox</li>
</ul>
</li>



<li>Write your CSS tweak:
<ul class="wp-block-list">
<li>Press <code>Ctrl + Alt + Shift + I</code> and choose OK in the &#8220;Incoming Connection&#8221; dialog (It will probably have appeared behind the unnamed, empty window which will become the browser inspector)</li>



<li>You will now have something that looks like the browser&#8217;s developer tools but lets you inspect and manipulate the browser&#8217;s UI instead. It&#8217;ll initially be an ugly vertical split with a log on the left but that will eventually go away. (I don&#8217;t know how to make it go away faster)</li>



<li>Use the &#8220;Inspector&#8221; tab to identify what to change</li>



<li>To actually make changes, select &#8220;Style Editor&#8221; and use the &#8220;Filter style sheets&#8221; field to find <code>userChrome.css.</code> This way, if you like the changes, all it takes to persist them is to click &#8220;Save&#8221; in the userChrome.css entry in the vertical tabs down the left side.</li>
</ul>
</li>
</ol>



<p>Here are a few examples of tweaks you can create:</p>



<pre class="wp-block-code"><code>/* Remove pointless thumbnail in the Bookmark popup
   (Why?! You can always see the full version while bookmarking anyway.) */
#editBookmarkPanelImage,
#editBookmarkPanelFaviconContainer {
  display: none !important;
}

/* Hide "Saved to Library!" bookmark confirmation popup
   (The star in the address bar having stayed filled already says that.) */
#confirmation-hint {
  display: none !important;
}

/* Compact sidebar header to match my compact toolbars
 * BUG: https://bugzilla.mozilla.org/show_bug.cgi?id=1435184 */
#sidebar-header {
  height: 32px !important;
  padding: 0 !important;
  font-size: 12px !important;
}</code></pre>



<h2 class="wp-block-heading">Thunderbird</h2>



<p>All the same steps as with Firefox apply (including the caution that the &#8220;Incoming Connection&#8221; dialog will probably fail to put itself at the top of the window stack), but the means to enable things are in slightly different places. (Thanks to <a href="https://superuser.com/questions/1660637/how-to-adjust-the-font-size-of-the-message-list-and-of-the-folder-list-in-thunde">this Superuser Q&amp;A</a> and <a href="https://www.reddit.com/r/Thunderbird/comments/jm5muz/dom_inspector_reference/">this /r/Thunderbird thread</a> for helping me piece things together)</p>



<ul class="wp-block-list">
<li>To access <code>about:config</code> so you can enable <code>toolkit.legacyUserProfileCustomizations.stylesheets</code>, go into the &#8220;General&#8221; page of settings, scroll down to the bottom, and click the &#8220;Config Editor&#8230;&#8221; button.</li>



<li>Instead of typing <code>about:support</code> into the address bar, you can find the button to open your user profile to add <code>chrome/userChrome.css</code> under <code>Help &gt; More Troubleshooting Information</code>.</li>



<li>The option to open the developer tools is at <code>Tools &gt; Developer Tools &gt; Developer Toolbox</code></li>
</ul>



<p>An example customization you can create would be this:</p>



<pre class="wp-block-code"><code>/* Override the horrendous UI font that Thunderbird suddenly started choosing
   (i.e. Match Qt, GTK+ 2.x, and GTK 3 apps)  */
* {
   font-family: "Noto Sans", "Nimbus Sans L", "Droid Sans", sans-serif !important;
}</code></pre>



<p><strong>NOTE:</strong> As of at least Thunderbird version 115, you&#8217;ll want to <em>remove</em> the <code>@namespace</code> line from any suggested <code>userChrome.css</code> content or you&#8217;ll be fighting an <a href="https://www.reddit.com/r/Thunderbird/comments/15xxjwh/userchromecss_only_selectively_applying_in_tb_115/">uphill battle</a> to apply changes to the increasing number of elements of Thunderbird&#8217;s UI that are HTML instead of XUL.</p>



<h2 class="wp-block-heading">GTK 3+</h2>



<p>Starting with GTK 3, the GNOME people and I have&#8230; <a href="https://stopthemingmy.app/">differences of opinion</a>&#8230; made worse by how the links I started with find more fodder in GTK 3 than any other system. While I&#8217;ve managed to replace most GTK applications on my desktop with Qt equivalents by now, there still exist a few of them (eg. Inkscape) with no viable replacements.</p>



<p>While such apps are, thankfully, not trying to embrace GNOME-isms that run counter to hard-won design principles from HCI research, they&#8217;re still being dragged along for the ride by the GNOME-isms creeping into GTK components outside <code>libadwaita</code>.</p>



<ul class="wp-block-list">
<li><strong>Archlinux Users:</strong> If your intent is to make your GTK 3 stuff feel more native on a non-GNOME desktop, start by installing the <a href="https://github.com/lah7/gtk3-classic/">gtk3-classic</a> package from AUR. It contains a GTK 3.x patched to revert some of the hard-coded GNOME-isms.</li>



<li><strong>Other Distros:</strong> If your goals include disabling some visual inconsistency caused by GNOME applying client-side window decorations (eg. drop shadows on context menus), <a href="https://github.com/PCMan/gtk3-nocsd">gtk3-nocsd</a> will resolve that&#8230; but it is an <code>LD_PRELOAD</code> hack, and getting it to work reliably when Flatpak isn&#8217;t designed to allow <code>LD_PRELOAD</code> hacks is iffy, so I&#8217;d suggest using it as a last resort.</li>
</ul>



<h3 class="wp-block-heading">Settings</h3>



<p>No matter how much user-hostility we may feel is present in the GNOME developers&#8217; behaviour these days, they <em>do</em> still allow <em>some</em> customization, so always check that before getting hacky.</p>



<p>For GTK 3, settings are customized by putting lines like <code>gtk-dialogs-use-header=0</code> into <code>~/.config/gtk-3.0/settings.ini</code>.  For GTK 4, it&#8217;s <code>~/.config/gtk-4.0/settings.ini</code>.</p>



<p>Valid <code>settings.ini</code> keys are documented as properties under the relevant GTK version&#8217;s <code>GtkSettings</code> API documentation. (eg <a href="https://docs.gtk.org/gtk3/class.Settings.html#properties">GtkSettings for GTK 3</a>)</p>



<p>Here are some suggested changes mentioned on <a href="https://wiki.archlinux.org/title/GTK">Archwiki</a>:</p>



<ul class="wp-block-list">
<li><code>gtk-can-change-accels = 1</code> is a deprecated GTK 3 option that lets you hover your mouse over a menu item and then press a hotkey to assign to it.</li>



<li><code>gtk-toolbar-style=GTK_TOOLBAR_ICONS</code>  is another deprecated GTK 3 option that will give you icon-only toolbar buttons without needing to reach for the CSS overrides (That&#8217;s what tooltips are for, don&#8217;t you think?)</li>



<li><code>gtk-overlay-scrolling = false</code> is listed as API-unstable, but should replace those touchscreen-style overlay scrollbars with ones where you don&#8217;t need to wiggle the mouse to see what your current scroll position is.</li>
</ul>



<p>There&#8217;s also the <code>gsettings set org.gtk.Settings.FileChooser startup-mode cwd</code> command (which you may need to run inside your Flatpaks) to restore the &#8220;old-fashioned&#8221; behaviour of having GTK file chooser dialogs start in the current directory rather than the recent files list.</p>



<h3 class="wp-block-heading">Themes</h3>



<p>Flatpak should automatically install the Flatpak version of whatever GTK theme you&#8217;re using but, if it doesn&#8217;t the first two things to try are:</p>



<ul class="wp-block-list">
<li>Make sure whatever settings daemon your desktop uses is installed and running. If the active theme isn&#8217;t being announced, then <code>flatpak upgrade</code> can&#8217;t install it.</li>



<li>It&#8217;s possible your theme hasn&#8217;t been packaged for Flatpak. The <a href="https://github.com/refi64/stylepak">Stylepak</a> tool will grab whatever GTK theme is active on the host and construct a Flatpak package from it.</li>



<li>There&#8217;s currently a <a href="https://bugs.kde.org/show_bug.cgi?id=426788">bug</a> that can cause Flatpak&#8217;d GTK applications to revert from Breeze to Adwaita on KDE desktops. To work around it, just go into the <code>Application Style</code> system settings module, click the <code>Configure GNOME/GTK Application Style...</code> button, fiddle around with one of the drop-downs to enable the Apply button, put the themes back to what you want, and click Apply. (I haven&#8217;t yet investigated a permanent fix.)</li>



<li>According to <a href="https://discourse.flathub.org/t/for-kde-users-script-to-apply-your-custom-breeze-colorscheme-to-all-your-gtk3-flatpak-apps/1319">this thread</a>, there are situations where a customized Breeze color scheme (I just use the default) won&#8217;t get applied to GTK 3 apps, and the workaround is a global filesystem override (either via Flatseal or manually editing <code>~/.local/share/flatpak/overrides/global</code>) to grant access to <code>filesystems=~/.local/share/icons:ro;~/.themes:ro;~/.icons:ro;xdg-config/gtk-3.0:ro;</code></li>



<li><code>libadwaita</code>-based apps aren&#8217;t meant to be themed beyond the light/dark switch and the recolouring API they eventually want to add, but, if the theme was designed to support it, you can force the issue by setting the <code>GTK_THEME</code> environment variable. I recommend doing it on a per-application basis rather than globally.<br /></li>
</ul>



<h3 class="wp-block-heading">Open/Save Dialogs</h3>



<p>This is one area where things are actually getting <em>better</em> for desktop consistency and user customization instead of worse. If your goal is to get all apps using the same desktop-provided Open/Save dialogs, the GNOME people are on board with that. Thanks to the XDG Portal system, anything that uses <code>GtkFileChooserNative</code> (GTK 3) or <code>GtkFileDialog</code> (GTK 4) instead of <code>GtkFileChooser</code> (holdover from GTK+ 2) is capable of delegating to a common dialog service provided by your desktop.</p>



<ul class="wp-block-list">
<li>Where possible, install applications through Flatpak or Snap. You&#8217;ll get the maximum amount of XDG Portal support by default, you won&#8217;t have to upgrade your whole distro to get access to new versions which add more portal support, and any testing the package maintainer does will be done with them enabled.</li>



<li>Anything using <code>GtkFileDialog</code> will use portals by default where available.</li>



<li><code>GtkFileChooserNative</code> only uses portals when running under Flatpak/Snap by default, because of buggy behaviour in certain GNOME apps. However, if you&#8217;re not using those GNOME apps, you can set an environment variable named  <code>GDK_DEBUG=portals</code> (formerly <code>GTK_USE_PORTAL=1</code>) to forcibly enable them.</li>



<li><strong>Firefox/Thunderbird:</strong> If not using the official Flatpak or Snap packages, open up <code>about:config</code> and set <code>widget.use-xdg-desktop-portal.file-picker</code> to <code>1</code></li>
</ul>



<h3 class="wp-block-heading">Widgets and/or libadwaita</h3>



<p>While I still think the <em>need</em> for it in this situation is a giant regression, I have to applaud the GTK developers for once again demonstrating that, regardless of my disagreements with them on what constitutes good UI design goals, their underlying infrastructure since the beginning of the GTK 3 era (GIR, gtk-rs, etc.) has been admirable.</p>



<p>As of GTK 3.14, they now have an equivalent to the Firefox Browser Toolbox that I pointed you at further up. It&#8217;s called <a href="https://wiki.gnome.org/Projects/GTK/Inspector">GtkInspector</a>, and it&#8217;s now a standard part of all GTK installs that just needs to be enabled through one of these means:</p>



<ul class="wp-block-list">
<li>Run <code>gsettings set org.gtk.Settings.Debug enable-inspector-keybinding true</code>. Any GTK application started after you did that will open GtkInspector when you press <code>Ctrl+Shift+D</code>.<br /><br />(If it&#8217;s a Flatpak, you may need to use <code>flatpak run --command='sh' &lt;AppID&gt;</code> or <code>flatpak enter &lt;AppID&gt;</code> and run the <code>gsettings</code> command inside the Flatpak.)</li>



<li>Run the application with the <code>GTK_DEBUG=interactive</code> environment variable set. The inspector will open automatically.</li>
</ul>



<p>Here are some tips:</p>



<ul class="wp-block-list">
<li>GTK extends CSS with a <code>@define-color name #c01040</code>; construct, and those defined colours are referenced by using <code>@name</code> where you might otherwise use something like <code>#f0f0f0</code> or <code>white</code>.</li>



<li>If your Flatpak app isn&#8217;t obeying the colours you expect and the widgets used by the application are very similar in Adwaita and your chosen theme, check the Visual tab in the inspector to see if it&#8217;s just falling back to Adwaita. There&#8217;s an a workaround on <a href="https://bugs.kde.org/show_bug.cgi?id=426788">this open KDE bug</a>.</li>



<li>Look at the class name (eg. <code>GtkPaned</code>) in the Object tab&#8217;s header (to the right of the drop-down button) and search for it in the online GTK API documentation for whichever version of GTK you&#8217;re dealing with. Each entry has a &#8220;CSS nodes&#8221; section (intended to allow application developers to customize their UI) which will help you craft your overrides. (eg. <a href="https://docs.gtk.org/gtk4/class.Paned.html#css-nodes">GtkPaned under GTK 4</a>)</li>



<li>Don&#8217;t get demoralized if your changes don&#8217;t seem to be doing anything. It <em>is</em> more finicky than tweaking Firefox&#8217;s UI using the Browser Toolbox.</li>
</ul>



<p>To make changes to GTK 3 apps global and persistent, put the CSS you figure out into <code>~/config/.gtk-3.0/gtk.css</code>. Here&#8217;s a fix I&#8217;m currently using:</p>



<pre class="wp-block-code"><code>/* Workaround for &#91;Breeze] &#91;Bug 414763] */
scrollbar trough { min-width: 6px; }
scrollbar:hover trough { min-width: 6px; }
scrollbar.horizontal trough { min-height: 6px; }
scrollbar.horizontal:hover.horizontal trough { min-height: 6px; }
scrollbar slider { min-width: 6px; }
scrollbar slider:hover { min-width: 6px; }
scrollbar.horizontal slider { min-height: 6px; }
scrollbar.horizontal slider { min-height: 6px; }</code></pre>



<p>&#8230;and here&#8217;s all the stuff I had to pile up to get things like Inkscape context menus feeling reasonably native to a KDE desktop again:</p>



<pre class="wp-block-code"><code>/* Un-round GtkPopover corners and remove drop shadow */
.menu, .menu * {
    box-shadow: none;
    border-radius: 0 0 0 0;
}

/* https://wiki.archlinux.org/title/GTK#Client-side_decorations */

.window-frame, .window-frame:backdrop {
 box-shadow: 0 0 0 black;
 border-style: none;
 margin: 0;
 border-radius: 0;
}

.titlebar {
 border-radius: 0;
}

.window-frame.csd.popup {
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.13);
}

.header-bar {
  background-image: none;
  background-color: #ededed;
  box-shadow: none;
}
/* You may want to use this if you do not like the double title.
GtkLabel.title {
    opacity: 0;
}*/

/* https://github.com/numixproject/numix-gtk-theme/issues/206#issuecomment-817660426 */

decoration {
  box-shadow: none;
  border-style: hidden;
  margin: 0;
  border-radius: 0;
}

/* https://github.com/numixproject/numix-gtk-theme/issues/206#issuecomment-1232256979 */

popover * {
  box-shadow: none;
  border-style: hidden;
  margin: 0px;
  border-radius: 0px;
}

.window-frame {
    box-shadow: none;
    margin: 1px;
}</code></pre>



<h3 class="wp-block-heading">Fonts</h3>



<p>As of GTK 4, lots of people without HiDPI displays have been complaining about <a href="https://gitlab.gnome.org/GNOME/gtk/-/issues/3787">blurry text</a>. (i.e. the forcing of the &#8220;accurate glyph positioning is more important than crisp glyph edges&#8221; approach to low-resolution font rendering that Apple has been using since they stopped using bitmap fonts, long before high-DPI displays as opposed to the approach Microsoft has historically taken of using &#8220;font hinting&#8221; to find the least bad way to nudge lines to line up with pixel boundaries.)</p>



<p>None of the remaining GTK apps on my desktop have upgraded off GTK 3 yet (in fact, the Geeqie Flatpak finally considered their GTK 3 port debugged enough to migrate off GTK+ 2.x today) but I&#8217;ve read that making sure you&#8217;re on GTK 4.6 or newer and adding <code>gtk-hint-font-metrics=1</code> to <code>~/.config/gtk-4.0/settings.ini</code> will help.</p>



<p>See also the <a href="https://wiki.archlinux.org/title/GTK">GTK</a> page on Archwiki and, if you&#8217;re trying to harmonize GTK and Qt, the <a href="https://wiki.archlinux.org/title/Uniform_look_for_Qt_and_GTK_applications">Uniform look for Qt and GTK applications</a> too.</p>



<h2 class="wp-block-heading">Ttk (Themed Tk)</h2>



<p>Here&#8217;s a <a href="https://rdbende.github.io/tkinter-docs/resources/list-of-ttk-themes.html">list of Ttk themes</a> you can browse through to find something as close as possible to the rest of your desktop.</p>



<p>If their <a href="https://ttkthemes.readthedocs.io/en/latest/installation.html">Installation</a> guide isn&#8217;t enough, I wrote about how to to it <a href="https://blog.ssokolow.com/archives/2011/10/01/installing-a-new-ttktile-theme/">more manually</a> years ago.</p>



<h2 class="wp-block-heading">Wine</h2>



<p>Last time I tried using Wine&#8217;s <code>.msstyles</code> support (over a decade ago), it made the UI sluggish to respond, so I just found a .reg patch to apply the default Breeze colour scheme to regular Windows 9x-style Win32 widgets instead.</p>



<p>From what I remember, applications have to opt into themed widgets on Windows, while basic colour schemes go back at least as far as Windows 3.1, so you&#8217;d probably benefit from one of these even if you <em>do</em> enable a <code>.msstyles</code> theme&#8230; though the comments on the Breeze Dark colour scheme do point out that Wine 7.4 gained an on-by-default msstyle named &#8220;Light&#8221; that you may need to switch back to &#8220;(No style)&#8221; in <code>winecfg</code>.</p>



<p>Here&#8217;s what I used, plus a dark variant of it:</p>



<ul class="wp-block-list">
<li><a href="https://store.kde.org/p/1259774/">Breeze color scheme for WINE</a> (To quote RogueScholar&#8217;s review, &#8220;What is this wizardry?Suddenly all my WINE apps are beautiful&#8221;)</li>



<li><a href="https://gist.github.com/Zeinok/ceaf6ff204792dde0ae31e0199d89398">Breeze Dark theme for Wine</a></li>
</ul>



<p>Since I did that, an <a href="https://store.kde.org/p/2318557">improved fork</a> has been created which also offers <code>.reg</code> files to adjust the window metrics and font smoothing and to do font substitution to make Windows apps fit in even more.</p>



<p>Alternatively, if you <em>do</em> want to use an <code>.msstyles</code> theme, <a href="https://github.com/listumps/wine_themes">this GitHub repository</a> has a bunch of them that are tested to work well with Wine.</p>



<h2 class="wp-block-heading">Web Apps</h2>



<p>Tons of people have written about restyling things with CSS userstyles, so I&#8217;ll just give a few tips:</p>



<ul class="wp-block-list">
<li>You can access Firefox&#8217;s normal context menu with <code>Shift+RightClick</code> if it&#8217;s been overridden.</li>



<li>You can access things like Page Info without knowing their keyboard shortcuts by tapping <code>Alt</code> to reveal the traditional menu bar.</li>



<li>I recommend <a href="https://github.com/openstyles/stylus">Stylus</a> as a userstyle host for Firefox and Ungoogled Chromium.</li>



<li>Here&#8217;s an example where I worked around Discord&#8217;s lack of easy-to-match CSS classes to turn off the distracting visual cacophony of customized username colours:</li>
</ul>



<pre class="wp-block-code"><code>/* I don't want my chat client to look like a Hawaiian shirt, thanks. */
span&#91;class^=roleColor-], span&#91;class*=' roleColor-'] {
    color: #72767d !important;
}
span&#91;class^=username-], span&#91;class*=' username-'] {
    color: #23262a !important;
}</code></pre>



<p>For the record, the ability to do this is one of the reasons I prefer in-browser versions of unavoidable web-tech to Electron versions. (The other major reason is that they&#8217;ll accept tighter sandboxing.)</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.ssokolow.com/archives/2023/06/17/fixing-applications-which-resist-feeling-platform-native/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
				<creativeCommons:license>https://creativecommons.org/licenses/by-sa/4.0/</creativeCommons:license>
	</item>
		<item>
		<title>Learning Materials for getting into Windows 3.1 programming</title>
		<link>https://blog.ssokolow.com/archives/2023/04/04/learning-materials-for-getting-into-windows-3-1-programming/</link>
					<comments>https://blog.ssokolow.com/archives/2023/04/04/learning-materials-for-getting-into-windows-3-1-programming/#comments</comments>
		
		<dc:creator><![CDATA[Stephan Sokolow]]></dc:creator>
		<pubDate>Tue, 04 Apr 2023 05:15:11 +0000</pubDate>
				<category><![CDATA[Retrocomputing]]></category>
		<guid isPermaLink="false">http://blog.ssokolow.com/?p=6783</guid>

					<description><![CDATA[As with my other recent post (Learning Materials for getting into C programming for MS-DOS/PC-DOS/DR-DOS/FreeDOS), I&#8217;m also gearing up to do the Windows 3.1 hobby programming I wanted to do as a kid but couldn&#8217;t, and that means collecting learning &#8230; <a href="https://blog.ssokolow.com/archives/2023/04/04/learning-materials-for-getting-into-windows-3-1-programming/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p>As with my other recent post (<a href="/archives/2023/02/27/learning-materials-for-getting-into-c-programming-for-ms-dos-pc-dos-dr-dos-freedos/">Learning Materials for getting into C programming for MS-DOS/PC-DOS/DR-DOS/FreeDOS</a>), I&#8217;m also gearing up to do the Windows 3.1 hobby programming I wanted to do as a kid but couldn&#8217;t, and that means collecting learning resources for that too.</p>



<p><strong>NOTE:</strong> I haven&#8217;t managed to research the intermediate and advanced materials as thoroughly as for DOS yet, so suggestions are welcome.</p>


<dl>
<dt>C Programming itself</dt>
<dd>As with DOS programming, I don&#8217;t want to recommend the books I just <em>happened</em> to use. Any book should do.</dd>
<dt>Segmented memory models in C, linked lists, hash tables, and the trade-offs therein</dt>
<dd>Win16 adds more to memory management on top of what&#8217;s available in DOS, but it&#8217;s fundamentally still just real-mode C or C++ programming, so start by learning the same things.</dd>
<dd>Borrow <a href="https://archive.org/details/microsoftcsecret0000jams/">Microsoft C: Secrets, Shortcuts, and Solutions</a> by Kris Jamsa from the Internet Archive&#8217;s book library and read chapters 25 (Dynamic Memory Allocation) and 28 (Understanding Memory Models) and borrow <a href="https://archive.org/details/advancedturboc00schi/">Advanced Turbo C</a> by Herbert Schildt and read Chapter 3 (Dynamic Allocation) and Appendix A (Turbo C Memory Models).  (I didn&#8217;t find either to communicate the relevant ideas ideally, but seeing the same thing explained by two different people really helps.)
<p>Alternatively, Schildt&#8217;s <a href="https://archive.org/details/advancedc0000schi/page/n3/mode/2up">Advanced C, Second Edition</a> from the following year appears to have all the same content in the relevant sections as Advanced Turbo C does. (The <a href="https://archive.org/details/advancedc00schi/mode/2up">first edition</a> spends less time on those topics and I didn&#8217;t see a section on memory models in it, so I advise only consulting it if you want a dead-tree edition and can&#8217;t find any of the other suggestions from Schildt cheaply.)</p>
</dd>
<dd></dd>
<dd>See also the <a href="https://open-watcom.github.io/open-watcom-v2-wikidocs/clr.html#Special_Pointer_Types_for_Open_Watcom_CD16">Special Pointer Types for Open Watcom C/16</a> section of the Open Watcom 2.0 C Language Reference once you&#8217;ve had things start to click.</dd>
<dd>If you want to buy just one book, buy one of the books by Schildt. Jamsa&#8217;s phrasing on memory models was a bit more illuminating for me, but Schildt&#8217;s no slouch there and he goes into much more detail on data structures, including implementing and comparing the strengths and weaknesses of three different ways to implement sparse arrays.</dd>
<dt>Windows 3.1 Application Quick Start</dt>
<dd>Read <a href="https://www.transmissionzero.co.uk/computing/win16-apps-in-c/">Building Win16 GUI Applications in C</a> by Transmission Zero. It&#8217;s a quick online article/post that goes through how to produce the working skeleton of a Windows 3.1 application using a 16-bit Microsoft C Compiler but explicitly points out <a href="https://github.com/open-watcom/open-watcom-v2/">Open Watcom C/C++</a> as one of example of the any other compilers with the &#8220;necessary headers and libraries for Win16 development&#8221; that should work too.</dd>
<dt>Beginner Windows 3.1 Programming</dt>
<dd><a href="https://archive.org/details/programmingwindo0000petz_o9r4">Programming Windows 3.1</a> by Charles Petzold is apparently considered the gold standard for an introduction to Windows 3.1 programming. Thankfully, it&#8217;s available in the Internet Archive&#8217;s lending library and, thankfully, Mr. Petzold still offers a <a href="http://www.charlespetzold.com/src/ProgWin31.zip">download</a> of the companion floppy <a href="http://www.charlespetzold.com/books.html">on the old version of his website</a>.</dd>
<dd>In the event that you can&#8217;t use that for some reason, another one which the Watcom manuals suggest is Windows Programming Primer Plus by Jim Conger from Waite Group Press. It&#8217;s not in the Internet Archive&#8217;s collection as far as I can tell, so you&#8217;d have to turn to <a href="https://worldcat.org/title/26361938">WorldCat</a> or <a href="https://www.abebooks.com/products/isbn/9781878739216/30919058063">AbeBooks</a> for that one.</dd>
<dt>Windows 3.1 API Reference</dt>
<dd>If you&#8217;re using Open Watcom C/C++, then you won&#8217;t have the advantage of Microsoft&#8217;s Windows API documentation.</dd>
<dd>Their manuals recommend buying the <a href="https://archive.org/details/waitegroupswindo00cong">Windows API Bible</a> (Windows 3.0 APIs) and the <a href="https://archive.org/details/windowsapinewtes0000cong">Windows API New Testament</a> (Windows 3.1 API additions) by James L. Conger from Waite Group Press&#8230; both of which are also in the Internet Archive&#8217;s lending library.</dd>
<dt>Class Library</dt>
<dd>If you&#8217;re using Open Watcom C/C++, you won&#8217;t have access to MFC (Visual C++) or OWL (Borland C++). <a href="https://archive.org/details/windowswritingre00dila">Windows++: Writing Reusable Windows Code in C++</a> by Paul DiLascia walks you through building your own class library.</dd>
<dt>Intermediate Skills</dt>
<dd>This is where things get hazy. Historically, people tended to learn about this sort of thing through journals like <a href="https://archive.org/search?query=Dr.+Dobb's+Journal">Dr. Dobb&#8217;s Journal</a>, <a href="https://archive.org/search?query=Windows+Programmer%27s+Journal&amp;and%5B%5D=subject%3A%22Programming+and+Development%22&amp;and%5B%5D=mediatype%3A%22software%22&amp;and%5B%5D=year%3A%5B1992+TO+1993%5D">The Windows Programmer&#8217;s Journal</a>, and so on. There are also some journal issues included on the MSDN Library Archive CD that you could get as an option from Microsoft back in the Windows 9x era and install using the CD key from the corresponding release of the regular MSDN library disc. However, those don&#8217;t turn up very often on eBay.</dd>
<dd>That said, for a less involved way to start moving beyond beginner materials, my searches turned up a book named <a href="https://archive.org/details/windowsprogrammi0000crou">The Windows Programming Puzzle Book</a> by Kim Crouse&#8230; and, yes, that <em>is</em> another link to the Internet Archive&#8217;s lending library. To put it simply, the first third of it is a set of questions, programming challenges, and buggy programs to be fixed, and the latter two thirds are answers, including explanations for why they&#8217;re the answer.</dd>
<dd>As for DDE references, I ran across a piece of advice in Dino Esposito&#8217;s Visual C++ Windows Shell Programming which recommends the documentation included with the Microsoft Internet Client SDKs as the best place for information on DDE&#8230; which I believe are the files archived <a href="https://browsers.evolt.org/browsers/archive/ie/win32/SDKs/">here</a>.</dd>
<dt>Advanced Stuff</dt>
<dd>Funny enough, the advanced stuff was easier for me to find, because there are good resources in the same series as Undocumented DOS and The Undocumented PC, which I already had. Specifically, <a href="https://archive.org/details/undocumentedwind00schu">Undocumented Windows</a> by Andrew Schulman, David Maxey, and Matt Pietrek and <a href="https://archive.org/details/windowsinternals00piet">Windows Internals</a> by Matt Pietrek, both available in the Internet Archive&#8217;s lending library.</dd>
</dl>


<p><strong>See Also:</strong> <a href="https://blog.ssokolow.com/archives/2017/10/19/useful-info-on-win16-targeting-compilers-and-a-list-of-resources/">Useful Info On Win16-Targeting Compilers… And a List of DOS/Win16 Resources</a></p>



<h2 class="wp-block-heading">A Note on Convenience Over Openness</h2>



<p>If you find writing a Windows 3.1 application in C or C++ too daunting and your primary goal is solving your own problems conveniently with no concern for making available open-source code for anyone to contribute to, there <em>are</em> options which are generally much easier than C or C++, but require buying proprietary software.</p>



<h3 class="wp-block-heading">Suggestion 1: Borland Delphi 1.x</h3>



<p>My first recommendation would be to search eBay for a copy of Borland Delphi 1.x on CD (either on its own or included on the CDs for Delphi 2.x through 4.x to support 16-bit development.).</p>



<p>It produces fast, self-contained EXEs and, for the kinds of tasks taught by Petzold in Programming Windows 3.1, it&#8217;s stupid simple.</p>



<p>(Having never used it before, I was able to create a &#8220;mirror a text field&#8217;s contents in a label&#8221; application in five minutes, just by dragging a couple of controls into the dialog builder that it opens into, double-clicking the text field to open up the <code>Edit1Change</code> handler, tentatively typing <code>Label1.Text = Edit1.Value</code> into it, pressing F9 (Run) to get an error message telling me my guess was wrong, and then selecting identifiers and pressing F1 or choosing &#8220;Topic Search&#8221; from the context menu to discover that it should be <code>Label1.Caption := Edit1.Text</code>.)</p>



<p>Seriously. Delphi is a <em>ridiculously</em> polished way to quickly whip up a GUI application, even for 2023, let alone for 1993.</p>



<h3 class="wp-block-heading">Suggestion 2: Visual Basic 4 or lower</h3>



<p>My second choice would be Microsoft Visual Basic 1, 2, 3, or 4.</p>



<p>It&#8217;ll be harder to find copies on eBay, they&#8217;ll probably cost more, the resulting binaries won&#8217;t run as fast, it doesn&#8217;t produce self-contained single-file executables, the IDE-Help integration can&#8217;t automatically resolve an identifier&#8217;s name to the corresponding widget&#8217;s documentation, CD-ROM versions of anything older than Visual Basic 4 are practically unobtanium, and Visual Basic 4 splits binaries across many more files than Visual Basic 3… but its ease of use is comparable to Delphi and I was still able to make the same test app in under 5 minutes when I haven&#8217;t touched BASIC of any kind in over 20 years.</p>



<p>Visual Basic 3 is generally agreed to be the best version for Windows 3.1 development.</p>



<h3 class="wp-block-heading">Suggestion 3: WinBatch</h3>



<p>If something more like <a href="https://www.autohotkey.com/">AutoHotKey</a>  for Windows 3.1 would meet your needs, go grab a copy of the trial version of <a href="https://archive.org/details/WB40L_ZIP">WinBatch 4.0L</a> from the Internet Archive and see if it does what you want. </p>



<p>If so, go to <a href="https://www.winbatch.com/">the WinBatch website</a> and buy a copy. They explicitly say &#8220;Support for Windows XP, Vista, 7, 8, 8.1, 10, 11, 2003, 2008, 2012, 2016, 2019, and 2022. Older versions are available for 95, 98, ME, NT, 2000, and even Windows 3.1&#8221;.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.ssokolow.com/archives/2023/04/04/learning-materials-for-getting-into-windows-3-1-programming/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
				<creativeCommons:license>https://creativecommons.org/licenses/by-sa/4.0/</creativeCommons:license>
	</item>
		<item>
		<title>Learning Materials for getting into C programming for MS-DOS/PC-DOS/DR-DOS/FreeDOS</title>
		<link>https://blog.ssokolow.com/archives/2023/02/27/learning-materials-for-getting-into-c-programming-for-ms-dos-pc-dos-dr-dos-freedos/</link>
					<comments>https://blog.ssokolow.com/archives/2023/02/27/learning-materials-for-getting-into-c-programming-for-ms-dos-pc-dos-dr-dos-freedos/#comments</comments>
		
		<dc:creator><![CDATA[Stephan Sokolow]]></dc:creator>
		<pubDate>Mon, 27 Feb 2023 12:56:37 +0000</pubDate>
				<category><![CDATA[Retrocomputing]]></category>
		<guid isPermaLink="false">http://blog.ssokolow.com/?p=6767</guid>

					<description><![CDATA[Last Updated: 2025-08-06 (Added &#8220;Performance Optimization&#8221; section) For a while now, I&#8217;ve been wanting to get into some DOS hobby programming using Open Watcom C/C++ (or maybe gcc-ia16), but, given that DOS programming was on the wane before the Internet &#8230; <a href="https://blog.ssokolow.com/archives/2023/02/27/learning-materials-for-getting-into-c-programming-for-ms-dos-pc-dos-dr-dos-freedos/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p><strong>Last Updated: 2025-08-06</strong> (Added &#8220;Performance Optimization&#8221; section)</p>



<p>For a while now, I&#8217;ve been wanting to get into some DOS hobby programming using <a href="https://github.com/open-watcom/open-watcom-v2/">Open Watcom C/C++</a> (or maybe <a href="https://github.com/tkchia/gcc-ia16">gcc-ia16</a>), but, given that DOS programming was on the wane before the Internet came around, and my childhood programming stuff is either for BASIC or a copy of Microsoft C/C++ 7.0 with reference manuals but no tutorials, that was proving kind of difficult.</p>



<p>However, recently, I was clued into the fact that there are actually some pretty good books I could borrow for free on the Internet Archive as a way to either determine that I wanted to buy them, or just read those crucial few pages that would make other resources make sense in the mind of a more modern programmer… so here&#8217;s what I&#8217;ve found so far:</p>


<dl>
<dt>C Programming itself</dt>
<dd>Literally any decent learning materials will do, so I don&#8217;t want to recommend the books I just <em>happened</em> to use.</dd>
<dt>Segmented memory models in C, linked lists, hash tables, and the trade-offs therein</dt>
<dd>Borrow <a href="https://archive.org/details/microsoftcsecret0000jams/">Microsoft C: Secrets, Shortcuts, and Solutions</a> by Kris Jamsa from the Internet Archive&#8217;s book library and read chapters 25 (Dynamic Memory Allocation) and 28 (Understanding Memory Models) and borrow <a href="https://archive.org/details/advancedturboc00schi/">Advanced Turbo C</a> by Herbert Schildt and read Chapter 3 (Dynamic Allocation) and Appendix A (Turbo C Memory Models).  (I didn&#8217;t find either to communicate the relevant ideas ideally, but seeing the same thing explained by two different people really helps.)
<p>Alternatively, Schildt&#8217;s <a href="https://archive.org/details/advancedc0000schi/page/n3/mode/2up">Advanced C, Second Edition</a> from the following year appears to have all the same content in the relevant sections as Advanced Turbo C does. (The <a href="https://archive.org/details/advancedc00schi/mode/2up">first edition</a> spends less time on those topics and I didn&#8217;t see a section on memory models in it, so I advise only consulting it if you want a dead-tree edition and can&#8217;t find any of the other suggestions from Schildt cheaply.)</p>
</dd>
<dd>See also the <a href="https://open-watcom.github.io/open-watcom-v2-wikidocs/clr.html#Special_Pointer_Types_for_Open_Watcom_CD16">Special Pointer Types for Open Watcom C/16</a> section of the Open Watcom 2.0 C Language Reference once you&#8217;ve had things start to click.</dd>
<dd>If you want to buy just one book, buy one of the books by Schildt. Jamsa&#8217;s phrasing on memory models was a bit more illuminating for me, but Schildt&#8217;s no slouch there and he goes into much more detail on data structures, including implementing and comparing the strengths and weaknesses of three different ways to implement sparse arrays.</dd>
<dt>Using VGA&#8217;s 640x480x16color planar graphics mode</dt>
<dd>Borrow or buy Richard F. Ferraro&#8217;s Programmer&#8217;s Guide to the EGA and VGA Cards, <a href="https://archive.org/details/programmersguide02edferr/mode/2up">Second Edition</a> or <a href="https://archive.org/details/programmersguidetotheegavgaandsupervgacardsbyrichardf.ferraro19943rdedition/mode/2up">Third Edition</a> (Internet Archive links) or, if you want nicer illustrations and only need a brief introduction to EGA/VGA planar video rather than an entire book about DOS graphics, borrow <a href="https://archive.org/details/waitegroupsmicro0000lafo">The Waite Group&#8217;s Microsoft C programming For The PC, Second Edition</a> by Robert Lafore and read chapter 11 (Direct-Access Graphics).</dd>
<dd>If you want to buy something, go for the second edition of Ferraro&#8217;s book. It&#8217;ll get you 500 pages on EGA and VGA and 500 pages on SVGA, including VESA and model-specific extensions offered by cards like the ATi VGA Wonder and the Tseng ET4000. The third edition is rarer and more expensive, has cover art that, in my opinion, has aged much more poorly, and what you&#8217;re paying for is having twice as many vendors covered in the part of the book about how to use model-specific SVGA stuff not covered by VESA&#8230; but, if you&#8217;ve got the cash and you&#8217;re going to be writing enough demoscene code for things like the XGA, the 8514/A, or S3 SVGA cards, the third edition may be worth buying.</dd>
<dd>See also chapter 2 (Icon-Based Interfaces) of <a href="https://archive.org/details/craftofc00herb">The Craft of C</a> by Herbert Schildt.</dd>
<dt>Using 256-color linear graphics modes on VGA and reading the mouse</dt>
<dd>Read David Brackeen&#8217;s <a href="http://www.brackeen.com/vga/index.html">256-Color VGA Programming in C</a>. (It&#8217;s a free series of online tutorials with source downloads for <a href="http://delorie.com/djgpp/">DJGPP</a> and &#8220;Borland C, Turbo C, etc.&#8221;)</dd>
<dd>If that&#8217;s not enough, borrow Richard F. Ferraro&#8217;s Programmer&#8217;s Guide to the EGA and VGA Cards, <a href="https://archive.org/details/programmersguide02edferr/mode/2up">Second Edition</a> or <a href="https://archive.org/details/programmersguidetotheegavgaandsupervgacardsbyrichardf.ferraro19943rdedition/mode/2up">Third Edition</a> from the Internet Archive for the video and read Chapter 9, &#8220;Interfacing to the Mouse&#8221; of Herbert Schildt&#8217;s <a href="https://archive.org/details/cpowerusersguide00schi/mode/2up">C Power User&#8217;s Guide</a> (<a href="https://archive.org/details/cpowerusersguide00schi_0/mode/2up">alt</a>) (apparently also sold as &#8220;The Art of C: Elegant Programming Solutions&#8221;). (Schildt also covers using the PC speaker.)</dd>
<dt>Playing music on an Adlib-compatible sound card</dt>
<dd>Download <a href="https://archive.org/details/adlf_zip">Programming the AdLib/Sound Blaster v2.0</a> (A.K.A. <code>adlf.zip</code>) from the Internet Archive. (<a href="/wp-content/adlf.zip">local copy</a>)</dd>
<dt>Playing digital audio on a SoundBlaster-compatible sound card</dt>
<dd>Download <a href="https://archive.org/details/sblast09_zip">SoundBlaster Programming Information v0.90</a> (<a href="/wp-content/sblast09.zip">local copy</a>), <a href="https://archive.org/details/sbprog10_zip">Soundblaster programming routines (C++ src)</a> (utility code under MIT-like license terms) (<a href="/wp-content/sbprog10.zip">local copy</a>), and <a href="https://archive.org/details/sb16doc_zip">Programming the SoundBlaster 16 DSP</a> (<a href="/wp-content/sb16doc.zip">local copy</a>).</dd>
<dd>I&#8217;m not recommending a print book because, as far as I can tell, reverse-engineered free eBooks by hardware hackers are the only place to find info that doesn&#8217;t assume you bought the SDK from Creative Labs.</dd>
<dt>Reading from the PC Gameport</dt>
<dd>Read <a href="https://www.epanorama.net/documents/joystick/pc_joystick.html">ePanorama.net &#8211; PC analogue joystick interface</a>.</dd>
<dt>DOS/BIOS interrupt API reference</dt>
<dd>See <a href="http://www.ctyme.com/rbrown.htm">Ralf Brown&#8217;s Interrupt List</a> (<a href="https://fd.lod.bz/rbil/">alt</a>, <a href="https://www.cs.cmu.edu/~ralf/files.html">download</a>).</dd>
<dt>Turbo Vision API documentation</dt>
<dd>When Borland released the source code for the C++ version of their Turbo Vision TUI library and the Free Pascal people ported it back to Pascal as Free Vision, neither released API documentation.</dd>
<dd>The recommended Borland <a href="https://archive.org/details/bitsavers_borlandTurrogrammingGuide1992_25707423">Turbo Vision Version 2.0 Programming Guide</a> from Turbo Pascal 7.0 is in the Internet Archive&#8217;s collection. However, the <a href="https://archive.org/details/bitsavers_borlandturVersion6.0TurboVision1990_16007263">Turbo Vision Programming Guide</a> from Turbo Pascal 6.0 is a decent runner-up if you can&#8217;t use it for some reason.</dd>
<dt>Assembly Language</dt>
<dd>I&#8217;m still working on this, but John Socha and Peter Noton&#8217;s <a href="https://archive.org/details/assemblylanguage00soch/mode/2up">Assembly Language for the PC, Third Edition</a> looks like a good candidate.</dd>
<dt>Performance Optimization</dt>
<dd>If you want to push the hardware you&#8217;re targeting, <a href="https://www.agner.org/optimize/">Agner Fog</a>&#8216;s got you covered with everything from C++ and assembly-language optimization guides to CPU instruction timing tables&#8230; though the tables only go back to the original Pentium so, for earlier x86 CPUs, see the Quantasm list (<a href="https://web.archive.org/web/20020219153200/http://www.quantasm.com/opcode_i.html">Wayback</a>, <a href="http://aturing.umcs.maine.edu/~meadow/courses/cos335/80x86-Integer-Instruction-Set-Clocks.pdf">PDF</a>).</dd>
<dd>See also Michael Abrash&#8217;s Graphics Programming Black Book (<a href="https://www.phatcode.net/res/224/files/html/index.html">HTML</a>, <a href="https://github.com/jeffpar/abrash-black-book">Markdown sources for making ePub/Mobi files</a>).</dd>
<dt>Everything else I&#8217;ve been interested in about DOS programming so far</dt>
<dd>Start by borrowing <a href="https://archive.org/details/craftofc00herb">The Craft of C</a> by Herbert Schildt and <a href="https://archive.org/details/ctoolboxreadytor0000hunt">The C Toolbox, Second Edition</a> by William James Hunt from the Internet Archive&#8217;s library. (Among other things, the former covers TSRs in C, writing a rudimentary C interpreter, basic EGA graphics, interacting with the DOS mouse drivers, implementing a screen editor, and building an icon-based interface and icon and bitmap font editors while the latter covers other useful things like TUI popup windows and using the serial port.)</dd>
<dd>If you want another book that I found useful, Herbert Schildt&#8217;s <a href="https://archive.org/details/cpowerusersguide00schi/mode/2up">C Power User&#8217;s Guide</a> (<a href="https://archive.org/details/cpowerusersguide00schi_0/mode/2up">alt</a>) (apparently also sold as &#8220;The Art of C: Elegant Programming Solutions&#8221;) has a fair bit of useful non-overlap. Its chapters cover TUI pop-up and pull-down menus and pop-up windows, writing TSRs in C, Mode 4 (CGA) graphics including 2D rotation, basic DOS game development, using the serial port, writing a rudimentary BASIC interpreter, miscellaneous text-mode stuff like using color and changing the text cursor size, controlling the PC speaker, interacting with DOS mouse drivers, and drawing bar graphs.</dd>
</dl>


<p>Beyond that, you&#8217;re into more advanced stuff:</p>



<ul class="wp-block-list">
<li><a href="https://archive.org/details/Undocumented_DOS">Undocumented DOS</a> (<a href="https://archive.org/details/undocdos2ed">2nd ed.</a>)</li>



<li><a href="https://archive.org/details/undocumentedpc0000vang">The Undocumented PC</a> (<a href="https://archive.org/details/undocumentedpcpr0000vang">2nd ed.</a>)</li>



<li>References for things like VESA and software 3D scattered around places like the Wayback Machine archive of <a href="https://web.archive.org/web/20010412112113/http://www.geocities.com/siliconvalley/park/9784/tut.html">STEEL&#8217;s Programming Resources</a>.</li>
</ul>



<p>I hope this helps you and you may also want to check out my <a href="https://blog.ssokolow.com/archives/2017/10/19/useful-info-on-win16-targeting-compilers-and-a-list-of-resources/">Useful Info On Win16-Targeting Compilers… And a List of DOS/Win16 Resources</a> post and my similar <a href="https://blog.ssokolow.com/archives/2023/04/04/learning-materials-for-getting-into-windows-3-1-programming/">list of learning materials for Windows 3.1</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.ssokolow.com/archives/2023/02/27/learning-materials-for-getting-into-c-programming-for-ms-dos-pc-dos-dr-dos-freedos/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
				<creativeCommons:license>https://creativecommons.org/licenses/by-sa/4.0/</creativeCommons:license>
	</item>
	</channel>
</rss>
