Remove unused article-content-wide classes

This commit is contained in:
Shadowfacts 2025-02-12 10:55:31 -05:00
parent 86bd8a39ee
commit 3c76daed1e
6 changed files with 16 additions and 26 deletions

View File

@ -189,10 +189,6 @@ header {
text-wrap: pretty;
}
.read-more {
font-style: italic;
}
.header-anchor {
text-decoration: none;
font-size: 1rem;

View File

@ -42,7 +42,7 @@
{% if latest_post.excerpt %}
{{ latest_post.excerpt }}
<p>
<a href="{{ latest_post_permalink }}" class="read-more">Read more…</a>
<a href="{{ latest_post_permalink }}" class="italic">Read more…</a>
</p>
{% else %}
{{ latest_post_content }}

View File

@ -130,13 +130,13 @@ I knew the name of the notification I needed to fire, but not what to do with it
Looking at the disassembly, we can see exactly what it's doing:
<div class="article-content-wide"><img src="/2021/scrollswitcher/awakefromnib.png" alt="Hopper showing the disassembly for -[MouseController awakeFromNib]"></div>
<img src="/2021/scrollswitcher/awakefromnib.png" alt="Hopper showing the disassembly for -[MouseController awakeFromNib]">
It's adding an observer to `NSDistributedNotificationCenter`'s `defaultCenter` for the `SwipeScrollDirectionDidChangeNotification`—the notification name I saw earlier in the Console. The other place it's referenced from (`[MTMouseScrollGesture initWithDictionary:andReadPreferences:]`) is doing the same thing: adding an observer. So, it looks like this notification isn't what triggers the actual change to the actual scroll input handling deep in the guts of the system. If that were the case, I'd expect to see the preference pane _send_ the notification, not just receive it.
But, it still may be useful. Looking at the implementation of the `_swipeScrollDirectionDidChangeNotification:` method it's setting as the callback for the action, we can see that it's probably updating the checkbox value. That `setState:` call sure seems like it's on the `NSButton` used for the natural scrolling checkbox.
<div class="article-content-wide"><img src="/2021/scrollswitcher/notificationhandler.png" alt="Hopper showing the disassembly for -[MouseController _swipeScrollDirectionDidChangeNotification:]"></div>
<img src="/2021/scrollswitcher/notificationhandler.png" alt="Hopper showing the disassembly for -[MouseController _swipeScrollDirectionDidChangeNotification:]">
[`NSDistributedNotificationCenter`](https://developer.apple.com/documentation/foundation/nsdistributednotificationcenter) is described as being like the regular notification center but for inter-process communication, which sounds like what we want. It has pretty much the same API as the regular one, so we can just send that notification when we change the scroll mode.
@ -166,7 +166,7 @@ With that in place, clicking the menu bar item both sets the default and causes
That's all well and good, but clicking the menu item still doesn't actually change what happens when you move two fingers on the trackpad. It clearly works when clicking the checkbox in System Preferences, so there must be something else it's doing that we're not. Internally, this feature seems to be consistently referred to as the "swipe scroll direction" (even though it affects non-swipe scrolling), so, back in Hopper, we can search for procedures named like that. There's one that immediately looks promising `setSwipeScrollDirection`, that just delegates to an externally implemented `_setSwipeScrollDirection`.
<div class="article-content-wide"><img src="/2021/scrollswitcher/setswipescrolldirection.png" alt="Hopper showing the assembly for setSwipeScrollDirection"></div>
<img src="/2021/scrollswitcher/setswipescrolldirection.png" alt="Hopper showing the assembly for setSwipeScrollDirection">
Looking at the references to the function, I saw it was called by the `-[MouseController scrollingBehavior:]` setter. That seems like the function that I wanted, but since it was implemented elsewhere, I had no idea what parameters it took. So, where's it implemented?
@ -187,7 +187,7 @@ $ dyld_shared_cache_util -extract ~/Desktop/Libraries/ /System/Library/dyld/dyld
It took a couple guesses, but I found that the `_setSwipeScrollingDirection` function is defined in `PreferencePanesSupport.framework`.
<div class="article-content-wide"><img src="/2021/scrollswitcher/preferencepanessupport.png" alt="Hopper showing the disassembly for _setSwipeScrollDirection in PreferencePanesSupport"></div>
<img src="/2021/scrollswitcher/preferencepanessupport.png" alt="Hopper showing the disassembly for _setSwipeScrollDirection in PreferencePanesSupport">
Hopper thinks it takes an int, but we can clearly see the parameter's being used as a bool. `rcx` is initialized to `kCFBooleanFalse` and set to `kCFBooleanTrue` if the parameter is true, and that's the value being passed to `CFPreferencesSetValue`. Perfect.
@ -218,4 +218,3 @@ I can't really take a screen recording of that, so you'll have to take my word t
If you're interested in the complete code, it can be found [here](https://git.shadowfacts.net/shadowfacts/ScrollSwitcher). It's not currently packaged for distribution, but you can build and run it yourself. Because it needs the sandbox disabled, it won't ever been in the App Store, but at some point I might slap an app icon on it and published a notarized, built version. So, if anyone's interested, let me know.
As it currently exists, the app—which I'm calling ScrollSwitcher—covers 90% of my needs. I don't generally dock/undock more than a one or twice a day, so just being able to click a menu bar item is plenty fast. That said, I may still extend it for "fun". One obvious improvement would be automatically changing the state when an external mouse is connected/disconnected. That shouldn't be too hard, right? Right?

View File

@ -35,9 +35,8 @@ Since the [last time](/2021/scrollswitcher/) I wrote about this, a couple things
With the shared cache extracted, I could load the AppKit binary into Hopper (I had to disable the Objective-C analysis, otherwise the app crashed when trying to load the binary) and start poking around. I searched for the `NSPageLayout` class that I'm interested in, and looked at the `runModalWithPrintInfo:` method, since that sounded like a good candidate for something that would lead to the bulk of the implementation. And, indeed, it was. The method appears to be a fairly simple wrapper around the `PMPrepare...` function that sounds like it lives in a separate private framework.
<div class="article-content-wide">
<img src="/2022/clarus/appkit.png" alt="Hopper window with AppKit showing the runModalWithPrintInfo: method">
</div>
<img src="/2022/clarus/appkit.png" alt="Hopper window with AppKit showing the runModalWithPrintInfo: method">
<aside class="inline">
@ -47,9 +46,8 @@ Curious about what those `_objc_msgSend$...` calls are? I would be to, if I hadd
The next step was figuring out where that prepare function is actually implemented. Running `otool -L` on the AppKit binary doesn't reveal anything obviously useful, but in the PrivateFrameworks directory extracted from the dyld shared cache, there's something called `PrintingPrivate.framework`, which sounds promising. Opening it up in Hopper, I saw that this is indeed the framework I was looking for.
<div class="article-content-wide">
<img src="/2022/clarus/printingprivate.png" alt="PrintingPrivate in Hopper showing the _PMPrepareAppKitPageSetupDialogWithPrintInfoPrivate function">
</div>
<img src="/2022/clarus/printingprivate.png" alt="PrintingPrivate in Hopper showing the _PMPrepareAppKitPageSetupDialogWithPrintInfoPrivate function">
Looking at the implementation of the prepare function, what immediately jumps out is the call to `_LoadAndGetPrintingUIBundle`. This seems to be yet another layer of indirection with the actual thing implemented in a different bundle. There's also a call in the else branch to the similarly-named `_LoadAndGetPrintCocoaUIBundle`, but let's start with the first one in hopes that it's more common.
@ -59,9 +57,8 @@ If you look for the function PrintingPrivate calls, it turns out it winds up in
What's this? A method called `updateClarus`? Could it be? Have we finally reached it?
<div class="article-content-wide">
<img src="/2022/clarus/printingui.png" alt="The PrintingUI binary in Hopper with the search panel showing a bunch of methods with 'clarus' in the name">
</div>
<img src="/2022/clarus/printingui.png" alt="The PrintingUI binary in Hopper with the search panel showing a bunch of methods with 'clarus' in the name">
Yes! Clarus, I'm coming! One method that sounds particularly encouraging is `-[PMPageSetupController setClarusImageView:]`. If I can find out what's setting the image view, maybe that'll lead to where it's being configured with the image.
@ -118,4 +115,3 @@ let image = bundle.image(forResource: "Clarus")
I'm not sure if the Mac App Store would consider that using private SPI, so use it at your own risk.
It would be very cool to see Clarus return as an SF Symbol some day. If hundreds of icons for various Apple products can go in, so too can everyone's favorite dogcow.

View File

@ -34,9 +34,8 @@ While the app was in the foreground, ActivityKit would log a message whenever I
I scratched my head at the issue of background updates for a while, and tried a couple things to no avail, until I attached Console.app to my phone and filtered for "activity". At which point, I saw a bunch of messages like these from `sessionkitd` (which is the system daemon that manages live activities):
<div class="article-content-wide">
<img src="/2022/live-activities/console.png" alt="com.apple.activitykit sessionkitd xpc Process is playing background media and forbidden to update activity: 984">
</div>
<img src="/2022/live-activities/console.png" alt="com.apple.activitykit sessionkitd xpc Process is playing background media and forbidden to update activity: 984">
Apps playing background audio seem to be completely forbidden from updating Live Activities. The only possible reason for this I can imagine is to prevent apps from making their own now playing activities, rather than relying on the system one. I don't know why this is the case, but whatever, back to trying to find workarounds.

View File

@ -194,7 +194,7 @@ So, when put all together, there will be three layers which are (back to front):
30%, 50% { width: 100%; height: 100px; top: 50px; left: 0; }
}
</style>
<div id="layer-diagram" class="article-content-wide" aria-labelled="Diagram of the animation's layer structure. The presenter layer at the back is always visible. The presented layer in the middle fades in and out. The matched layer at the front changes shape between a small square while the presented layer is hidden and a larger rectangle when the presented layer is visible.">
<div id="layer-diagram" aria-label="Diagram of the animation's layer structure. The presenter layer at the back is always visible. The presented layer in the middle fades in and out. The matched layer at the front changes shape between a small square while the presented layer is hidden and a larger rectangle when the presented layer is visible.">
<div id="layer-container">
<div id="red"><p>Presenter</p></div>
<div id="green"><div id="background"></div><p>Presented</p></div>