Author Topic: Designing a new Finder  (Read 65404 times)

Offline OS923

  • Platinum Member
  • *****
  • Posts: 888
Re: Designing a new Finder
« Reply #120 on: January 21, 2021, 07:27:06 AM »
I found it. Problem solved.

Offline IIO

  • Platinum Member
  • *****
  • Posts: 4439
  • just a number
Re: Designing a new Finder
« Reply #121 on: January 21, 2021, 09:04:46 PM »
What do you think of this idea:

Hide the contents of the window of a folder that is being changed until there are x seconds of no change.

OSX does this when you perform a huge task such as copying 30,000 files at once. but it is not intented and in extreme cases it goes together with corrupt files or corrupt desktop entries.
insert arbitrary signature here

Offline IIO

  • Platinum Member
  • *****
  • Posts: 4439
  • just a number
Re: Designing a new Finder
« Reply #122 on: January 21, 2021, 09:07:10 PM »
The colors are wrong. Red and blue are too light and green is much too dark. If I make a screenshot and I watch it on a Windows computer then the colors are correct. How is that possible?

i had exactly the same issue 20 minutes ago in a forum. i think it is releated to the png format. i cropped and saved-in in OS9, then copied across the clipboard in firefox in win10 -> and light green ended up as dark green.
insert arbitrary signature here

Offline IIO

  • Platinum Member
  • *****
  • Posts: 4439
  • just a number
Re: Designing a new Finder
« Reply #123 on: January 21, 2021, 09:09:40 PM »
haha, is that window drawn onscreen? do you know that "rounded WDEF SDK" where you can have platinum styled oval windows?
insert arbitrary signature here

Offline OS923

  • Platinum Member
  • *****
  • Posts: 888
Re: Designing a new Finder
« Reply #124 on: January 22, 2021, 01:35:23 PM »
It’s not a window. It’s drawn directly on screen, like the desktop picture and the icons.

Offline gsteemso

  • Newcomer
  • Posts: 4
Re: Designing a new Finder
« Reply #125 on: May 30, 2021, 04:13:42 PM »
It's been probably 15 years or more since I was able to devote much time to "just what, exactly, IS wrong with Apple's Finder?", so I am probably going to miss several important points here. That said, in no particular order:

- A lot of the stock Finder's most annoying usability shortcomings were addressed by the commercial (or was it shareware?) replacement, "Pathfinder". I couldn't afford it when it was current and I lost track of it thereafter, but who knows; it could be a good source of behavioural examples, if nothing else.

- I believe that the stock Finder's "you might tell it to quit, but you can't totally stop it from returning" thing is due in no small part to it being identified during boot as the first program the system is to run. As I recall, the boot process involves five pieces of stored information, processed sequentially: (1) The boot device/partition, (2) the "blessed" folder in the (usually HFS+) volume (filesystem) on that partition, and the names of (3) the System file, of (4) the default application to execute after booting (normally the Finder, but sometimes the Installer or something more exotic), and of (5) the debugger (if any; usually Macsbug, if it is) within that folder.

The name of the OS routine for ending a program, "ExitToShell", hints at the intended use of that program singled out for execution immediately after booting: it's the "outer shell" within which everything else is done, which is why it automatically resurrects whenever nothing else is running. The same thing happens on single-volume installation media for some versions of the system software, when the thing is configured to boot directly into the Installer instead of the Finder (though I only definitively recall experiencing that with OS X install media, so it may not be directly relevant).

- Even though fairly decent OS-level support is present for foreign file systems, Apple's Finder has usually reacted ungracefully to anything that doesn't match its preconceptions. For example (but first, some background):

The old "Macintosh File System" from 1984, which gave an illusion of directories by storing every file name as a full pathname and then illusorily acting like the file really was stored within all of the directories so named, allowed individual pieces of those pathnames to be up to 63 characters long. (In that era, pretty much all system software was written in Pascal on an Apple Lisa; character strings compatible with that system are of fixed length, and begin with a one-byte datum indicating how many of the bytes in it actually contain text. Such a Pascal string sized to hold a 63-byte datum would occupy a conveniently power-of-2 64-byte block.)

When the MFS' replacement, the Heirarchical File System, was being designed only a couple of years later, there was a great need to make each file's metainformation (stored in the volume's "where everything actually _is_" catalogue) as compact as possible so that more than one catalogue entry could be squeezed into a single 512-byte disk block. Reserving a 64-byte Pascal string for the filename would eat a full eighth of a disk block all by itself, and how many people really used names that long? (I can tell you that I rarely even came close, back before I had access to interesting downloadables online; of course, after that particular paradigmatic peregrination, I've used a lot more information in my filenames to clearly identify things.) In any case, halving the space reserved for filenames to 32 bytes (allowing names up to 31 bytes long) seemed a reasonable tradeoff at the time.

Fast forward several Finder iterations, and as of System 7, MFS volumes were sufficiently uncommon that some coder within Apple was unaware of the possibility of a filename ever exceeding the 31-byte HFS maximum; from that point forward -- right up until MFS support was removed entirely! -- if you tried to access an MFS volume containing a filename segment longer than 31 bytes, the Finder would immediately, violently, and messily crash.

Long story short... A hypothetically better Finder's design _must_ allow for arbitrary data it gets from elsewhere to suddenly turn out to be larger in future. As ever, reserving unnecessarily large buffers _now_ would be wasteful and foolish; but planning for some sort of graceful "it might look wrong but it still _works_" near-success mode instead of failing to plan at all and getting a catastrophic failure mode, as Apple once did with the size of filenames, sounds like a smart move to me.

Offline IIO

  • Platinum Member
  • *****
  • Posts: 4439
  • just a number
Re: Designing a new Finder
« Reply #126 on: May 31, 2021, 12:04:35 AM »
A lot of the stock Finder's most annoying usability shortcomings

get some more concrete maybe? :)

Quote
the stock Finder's "you might tell it to quit, but you can't totally stop it from returning" thing is due in no small part to it being identified during boot as the first program the system is to run.

it is a special type of program, not having the usual APPL signature.

there are patches for finder to be able to quit it permanently, but i think you can also quit it using a third party extensions.

Quote
which is why it automatically resurrects whenever nothing else is running.

hmmm. why would one want it not to restart when no other app is open? what can you do with an OS while no application is running?

Quote
Reserving a 64-byte Pascal string for the filename would eat a full eighth of a disk block all by itself, and how many people really used names that long?

i mostly like the finder´s strict character limit a lot. for multimedia work it is great. it forces you to find short and descriptive names, and you end up with a browser with not so wide windows in list view.

however, it begins to suck when you are looking a longer files which originated elsewhere.

a scene release of the type "Grmblfx-GmbH.GermanSuperSoftware.AllInOnePackage.Insert_a_Long_Application_Name_Here.including_cheese_crackers.
mustdownloadnow.Date.Time.Releasegroup.Platform.Version.Build.7z"
will show up as "Grmblfx-GmbH.GermanSuperSof#12345" and then you can not distinguish it from 50 other files and need to use another Browser to be able to read the long name.

but seriously, this is kind of unfixable. while we have beeen discussing to include long names in a new finder, i dont think it is a good idea to let people also write long names in a mac os classic.

dont forget that those long names will only be readable on OS9 machines which also have that new finder, and that many OS9 based file transfer programs will also not be able to transfer those long names.


Quote
the 31-byte HFS maximum

you probably know that but: no! it is only a finder limit. HFS+ allows 255 characters.


Quote
Long story short... A hypothetically better Finder's design _must_ allow for arbitrary data it gets from elsewhere to suddenly turn out to be larger in future.

see above, the transfer protocol must also allow it in order to work.

i believe "show long names" belonged best into the individual view options for the finder windows. :)

insert arbitrary signature here

Offline OS923

  • Platinum Member
  • *****
  • Posts: 888
Re: Designing a new Finder
« Reply #127 on: May 31, 2021, 08:43:50 AM »
That’s right. There should be a feature that you can enable to display long Unicode filenames to give you the chance to replace them with short filenames that don’t cause trouble with other programs. There should be no feature that inserts new long Unicode filenames that no one can handle.

As far as I know, long Unicode filenames are supported by only Finder and StuffIt, and even they can’t display them.

Worst of all is that if you have a long Unicode filename, then it is shortened with a hexadecimal number at the end which changes if you move the file to another folder.

Offline Mat

  • Platinum Member
  • *****
  • Posts: 644
Re: Designing a new Finder
« Reply #128 on: May 31, 2021, 10:43:22 AM »
dont forget that those long names will only be readable on OS9 machines which also have that new finder,
And as so often I do not get why we are discussing things that can be done/used since the 90ies. You know about "Joliet Volume Access" and "Kilometre Browser" ( https://www.faustic.com/km/old.html )?

I for myselve think that 31 characters are fine. Everything more than 64 characters is for sure not useful for a name (!) that should identyfy a file inside a GUI. Even modern Linux-Desktops are restricting visible characters to 50 per file. So longer filenames are an explenation and would belong to comments, or a readmefile or be presented by a folder structure, but not by extending a name! That ugly behaviour to make huge file names at other operating systems is a workaround for what filenames never have been intended!  Mac OS 9 is clear, straight and consistent regarding this field, and I still love it for being so.

Offline IIO

  • Platinum Member
  • *****
  • Posts: 4439
  • just a number
Re: Designing a new Finder
« Reply #129 on: May 31, 2021, 01:35:41 PM »
it has not been useful in the past to call your audiofiles
SoundOfAPianoFallingDownTheStairsVersion3Revision2StereoMastered.aif
and then tell your friends or customers "if you want to see the name, please use a third party browser" - and it wont be very useful in 2021 either.

to be exact, even in operating systems like 10.14 or windows 10 where you can have thousands of characters, i much appreciate short names. :)
insert arbitrary signature here

Offline Mat

  • Platinum Member
  • *****
  • Posts: 644
Re: Designing a new Finder
« Reply #130 on: May 31, 2021, 03:06:29 PM »
Exactly!
And what I wanted to say with my posting above is that it doesn't matter if it is a tool that we have for 25 years, or a system extention that makes long filenames available.

Offline IIO

  • Platinum Member
  • *****
  • Posts: 4439
  • just a number
Re: Designing a new Finder
« Reply #131 on: May 31, 2021, 03:58:56 PM »
that is the point where we disagree.

while both is a third party tool which you only need to read long names, it would be really nice to have it integrated into the / a finder.

coela, kilometre and the long info CMM are not ideal to use.
« Last Edit: May 31, 2021, 04:23:24 PM by IIO »
insert arbitrary signature here

Offline OS923

  • Platinum Member
  • *****
  • Posts: 888
Re: Designing a new Finder
« Reply #132 on: June 05, 2021, 06:42:20 AM »
I looked into those softwares with The Fragmalyzer. They don’t use Textension. They can’t edit Unicode.

Then I looked into CW Pro 8 how much trouble it would be to edit Unicode. I found it easy. The clipboard works with Unicode.

I think about a program that opens a window for every dropped item. It shows the long Unicode name in the text and the normal name in the title. You can change the name and then Save and this updates the name. Just a small program that does one thing. This would be only a few lines of code and I make it open source. Then you can adapt it to your own taste.

Offline IIO

  • Platinum Member
  • *****
  • Posts: 4439
  • just a number
Re: Designing a new Finder
« Reply #133 on: June 05, 2021, 08:49:58 AM »
this is how "long info" looks.

it only processes single files and wont even open when you select two items.

insert arbitrary signature here

Offline OS923

  • Platinum Member
  • *****
  • Posts: 888
Re: Designing a new Finder
« Reply #134 on: June 08, 2021, 10:54:22 AM »
I adapted CW Pro 8.3’s LMLTEPane to make it work with CW Pro 6.3. I can now edit long filenames. Drag items to the program and it opens a window for every item. If you change something in Finder then the window is updated.

Unicode doesn’t work yet. It was more complicated than I anticipated.

These are the available text encodings:
Code: [Select]
Text encoding 0: base=0 variant=1 format=0
Text encoding 1: base=0 variant=2 format=0
Text encoding 2: base=1 variant=0 format=0
Text encoding 3: base=1 variant=1 format=0
Text encoding 4: base=1 variant=2 format=0
Text encoding 5: base=1 variant=3 format=0
Text encoding 6: base=1 variant=4 format=0
Text encoding 7: base=1 variant=5 format=0
Text encoding 8: base=2 variant=0 format=0
Text encoding 9: base=3 variant=0 format=0
Text encoding 10: base=4 variant=0 format=0
Text encoding 11: base=4 variant=1 format=0
Text encoding 12: base=4 variant=2 format=0
Text encoding 13: base=4 variant=3 format=0
Text encoding 14: base=5 variant=0 format=0
Text encoding 15: base=5 variant=1 format=0
Text encoding 16: base=6 variant=0 format=0
Text encoding 17: base=7 variant=1 format=0
Text encoding 18: base=7 variant=2 format=0
Text encoding 19: base=7 variant=3 format=0
Text encoding 20: base=9 variant=0 format=0
Text encoding 21: base=10 variant=0 format=0
Text encoding 22: base=11 variant=0 format=0
Text encoding 23: base=21 variant=0 format=0
Text encoding 24: base=25 variant=0 format=0
Text encoding 25: base=26 variant=0 format=0
Text encoding 26: base=29 variant=0 format=0
Text encoding 27: base=33 variant=0 format=0
Text encoding 28: base=34 variant=0 format=0
Text encoding 29: base=35 variant=0 format=0
Text encoding 30: base=36 variant=1 format=0
Text encoding 31: base=36 variant=2 format=0
Text encoding 32: base=37 variant=2 format=0
Text encoding 33: base=37 variant=3 format=0
Text encoding 34: base=37 variant=4 format=0
Text encoding 35: base=37 variant=5 format=0
Text encoding 36: base=38 variant=1 format=0
Text encoding 37: base=38 variant=2 format=0
Text encoding 38: base=41 variant=0 format=0
Text encoding 39: base=140 variant=0 format=0
Text encoding 40: base=140 variant=1 format=0
Text encoding 41: base=252 variant=1 format=0
Text encoding 42: base=252 variant=2 format=0
Text encoding 43: base=257 variant=0 format=0
Text encoding 44: base=257 variant=0 format=1
Text encoding 45: base=257 variant=0 format=2
Text encoding 46: base=259 variant=0 format=0
Text encoding 47: base=259 variant=0 format=1
Text encoding 48: base=259 variant=0 format=2
Text encoding 49: base=259 variant=2 format=0
Text encoding 50: base=260 variant=0 format=0
Text encoding 51: base=260 variant=0 format=1
Text encoding 52: base=260 variant=0 format=2
Text encoding 53: base=260 variant=2 format=0
Text encoding 54: base=513 variant=0 format=0
Text encoding 55: base=514 variant=0 format=0
Text encoding 56: base=515 variant=0 format=0
Text encoding 57: base=516 variant=0 format=0
Text encoding 58: base=517 variant=0 format=0
Text encoding 59: base=518 variant=0 format=0
Text encoding 60: base=519 variant=0 format=0
Text encoding 61: base=520 variant=0 format=0
Text encoding 62: base=521 variant=0 format=0
Text encoding 63: base=527 variant=0 format=0
Text encoding 64: base=1024 variant=0 format=0
Text encoding 65: base=1040 variant=0 format=0
Text encoding 66: base=1049 variant=0 format=0
Text encoding 67: base=1053 variant=0 format=0
Text encoding 68: base=1056 variant=0 format=0
Text encoding 69: base=1057 variant=0 format=0
Text encoding 70: base=1059 variant=0 format=0
Text encoding 71: base=1280 variant=0 format=0
Text encoding 72: base=1281 variant=0 format=0
Text encoding 73: base=1282 variant=0 format=0
Text encoding 74: base=1283 variant=0 format=0
Text encoding 75: base=1284 variant=0 format=0
Text encoding 76: base=1285 variant=0 format=0
Text encoding 77: base=1286 variant=0 format=0
Text encoding 78: base=1287 variant=0 format=0
Text encoding 79: base=1288 variant=0 format=0
Text encoding 80: base=1536 variant=0 format=0
Text encoding 81: base=1570 variant=0 format=0
Text encoding 82: base=1584 variant=0 format=0
Text encoding 83: base=1585 variant=0 format=0
Text encoding 84: base=1600 variant=0 format=0
Text encoding 85: base=2080 variant=0 format=0
Text encoding 86: base=2096 variant=0 format=0
Text encoding 87: base=2112 variant=0 format=0
Text encoding 88: base=2336 variant=0 format=0
Text encoding 89: base=2352 variant=0 format=0
Text encoding 90: base=2353 variant=0 format=0
Text encoding 91: base=2368 variant=0 format=0
Text encoding 92: base=2561 variant=0 format=0
Text encoding 93: base=2562 variant=0 format=0
Text encoding 94: base=2563 variant=0 format=0
Text encoding 95: base=2564 variant=2 format=0
Text encoding 96: base=2564 variant=6 format=0
Text encoding 97: base=2564 variant=11 format=0
Text encoding 98: base=2564 variant=14 format=0
Text encoding 99: base=2565 variant=0 format=0
Text encoding 100: base=2817 variant=0 format=0
Text encoding 101: base=3074 variant=0 format=0
Text encoding 102: base=4095 variant=0 format=0

These are the available Unicode conversions:
Code: [Select]
Text encoding 43 -> 44
Text encoding 44 -> 43
Text encoding 43 -> 45
Text encoding 45 -> 43
Text encoding 46 -> 47
Text encoding 47 -> 46
Text encoding 46 -> 48
Text encoding 48 -> 46
Text encoding 46 -> 49
Text encoding 48 -> 49

HFS+ filenames are Unicode 2.0 canonical decomp variant (I call this HFS). Classic Mac OS can convert Unicode 2.0 16-bit (46) and Unicode 2.0 UTF8 (48) to HFS (49) but not the other way. Once it's converted to HFS it can't be converted to anything. Linking to Carbon didn't make a difference. Note also that it can't convert between Unicode 1.1 (257) and Unicode 2.0 (259). Thus I have to write my own conversion.

A table-based solution would take 595*65536*sizeof(Element) of memory. That may be the reason why Apple didn’t include this in the MacOS. Thus I'll use a tree-based solution.

I tried this first in Scheme and it works.
Code: [Select]
(require-library "compat.ss")

(load "Data1.ss")
(load "Data2.ss")
(load "Data3.ss")
(load "Data4.ss")

(define conversie
  (class object% ()
    (private
      [boom '()]
      [unicode #f])
    (public
      [voegtoe (lambda (x lijst)
                 (if (null? lijst)
                     (set! unicode x)
                     (letrec ((eerste (car lijst))
                              (rest (cdr lijst))
                              (gevonden (assoc eerste boom)))
                       (if gevonden
                           (send (cadr gevonden) voegtoe x rest)
                           (let ((nieuw (make-object conversie)))
                             (begin
                               (set! boom (cons (list eerste nieuw) boom))
                               (send nieuw voegtoe x rest)))))))]
      [zoek (lambda (lijst)
              (if (null? lijst)
                  unicode
                  (letrec ((eerste (car lijst))
                           (rest (cdr lijst))
                           (gevonden (assoc eerste boom)))
                    (if gevonden
                        (send (cadr gevonden) zoek rest)
                        #f))))]
      [tel (lambda ()
             (define (som boom)
               (if (null? boom)
                   0
                   (let ((eerste (car boom))
                         (rest (cdr boom)))
                     (+ (send (cadr eerste) tel)
                        (som rest)))))
             (if (null? boom)
                 0
                 (+ 1 (som boom))))]
      [sorteer (lambda ()
                 (define (kleinerdan? x y)
                   (< (car x) (car y)))
                 (if (null? boom)
                     'ok
                     (set! boom (sort kleinerdan? boom))))]
      [schrijf (lambda ()
                 (define (vertaal paar)
                   (list (car paar) (send (cadr paar) schrijf)))
                 (if (null? boom)
                     (number->string unicode)
                     (map vertaal boom)))])
    (sequence
      (super-init))))

(define c (make-object conversie))
(define (voegtoe x lijst) (send c voegtoe x lijst))
(define (zoek lijst) (send c zoek lijst))
(define (tel) (send c tel))
(define (sorteer) (send c sorteer))
(define (schrijf) (send c schrijf))

(define (voegdatatoe data)
  (define (voeg-x-en-lijst-toe r)
    (voegtoe (car r) (cdr r)))
  (for-each voeg-x-en-lijst-toe data))

(voegdatatoe data1)
(voegdatatoe data2)
(voegdatatoe data3)
(voegdatatoe data4)

(zoek '(180)) ; -> 8189
(zoek '(105 769)) ; -> 146
(zoek '(4362 4468 4532)) ; -> 50457
(zoek '(919 837 788 769)) ; -> 8093

(tel) ; -> 595

(sorteer)

(schrijf)

Now I have to write the C++ version. Then I can EDIT Unicode filenames.

Offline OS923

  • Platinum Member
  • *****
  • Posts: 888
Re: Designing a new Finder
« Reply #135 on: June 13, 2021, 09:40:07 AM »
Almost right. Not bad for a first try.

First you need to make a text encoding converter.
Code: [Select]
Bool BOOL_MakeTables()
{
    TextEncoding const plainTextEncoding=
        ::CreateTextEncoding(kTextEncodingUnicodeV2_0,
                             kUnicodeNoSubset,
                             kUnicode16BitFormat);
    if (!plainTextEncoding)
        {
        ReturnFalse("\pCreateTextEncoding fails");
        }

    TextEncoding const hfsTextEncoding=
        ::CreateTextEncoding(kTextEncodingUnicodeV2_0,
                             kUnicodeCanonicalDecompVariant,
                             kUnicode16BitFormat);
    if (!hfsTextEncoding)
        {
        ReturnFalse("\pCreateTextEncoding fails");
        }

    TECObjectRef plainToHFS;
    OSStatus status=::TECCreateConverter(&plainToHFS,
                                         plainTextEncoding,
                                         hfsTextEncoding);
    if (status)
        {
        ReturnFalse_status("\pTECCreateConverter fails",status);
        }

    const Bool ok=BOOL_MakeTables(plainToHFS);

    status=::TECDisposeConverter(plainToHFS);
    if (status)
        {
        ReturnFalse("\pTECDisposeConverter fails");
        }

    if (!ok)
        {
        ReturnFalse("\pMakeTables fails");
        }

    return True;
}

Then you need to make 4 tables.
Code: [Select]
#include "Make4Tables.h"

#include "PStr.cp.h"

//----------------------------------------
// Implementation details.
//----------------------------------------

Bool BOOL_MakeTable(TECObjectRef plainToHFS,
                    SInt32 length);

Bool BOOL_MakeTable(TECObjectRef plainToHFS,
                    SInt32 length,
                    BigTextFileWriter &cpp);

Bool BOOL_MakeTable(TECObjectRef plainToHFS,
                    SInt32 length,
                    BigTextFileWriter &cpp,
                    BigTextFileWriter &scheme);

Bool BOOL_ShowCpp(UniChar plain,
                  const HFSUniStr255 &u,
                  BigTextFileWriter &cpp);

Bool BOOL_ShowScheme(UniChar plain,
                     const HFSUniStr255 &u,
                     BigTextFileWriter &scheme);

//----------------------------------------

Bool BOOL_Make4Tables(TECObjectRef const plainToHFS)
{
    for (SInt32 length=1;length<=4;length++)
        {
        if (!BOOL_MakeTable(plainToHFS,
                            length))
            {
            ReturnFalse("\pMakeTable fails");
            }
        }
    return True;
}

//----------------------------------------
// Implementation details.
//----------------------------------------

Bool BOOL_MakeTable(TECObjectRef const plainToHFS,
                    const SInt32 length)
{
    PStr<31> path;
    SpellReadable(path,"\p:Output:Data");
    SpellNumber(path,length);
    SpellReadable(path,"\p.cp");

    FSSpec spec;
    OSErr err=::FSMakeFSSpec(0,
                             0,
                             path,
                             &spec);
    if (err)
        {
        if (err!=fnfErr)
            {
            ReturnFalse_err("\pFSpCreate fails",err);
            }
        err=::FSpCreate(&spec,
                        'R*ch',
                        'TEXT',
                        smSystemScript);
        if (err)
            {
            ReturnFalse_err("\pFSpCreate fails",err);
            }
        }

    BigMacFileWriter cpp;
    if (!cpp.BOOL_Open(spec))
        {
        ReturnFalse("\pOpen fails");
        }

    const Bool ok=BOOL_MakeTable(plainToHFS,
                                 length,
                                 cpp);

    if (!cpp.BOOL_Close())
        {
        ReturnFalse("\pClose fails");
        }

    if (!ok)
        {
        ReturnFalse("\pMakeTable fails");
        }

    return True;
}

Bool BOOL_MakeTable(TECObjectRef const plainToHFS,
                    const SInt32 length,
                    BigTextFileWriter &cpp)
{
    PStr<31> path;
    SpellReadable(path,"\p:Output:Data");
    SpellNumber(path,length);
    SpellReadable(path,"\p.ss");

    FSSpec spec;
    OSErr err=::FSMakeFSSpec(0,
                             0,
                             path,
                             &spec);
    if (err)
        {
        if (err!=fnfErr)
            {
            ReturnFalse_err("\pFSpCreate fails",err);
            }
        err=::FSpCreate(&spec,
                        'R*ch',
                        'TEXT',
                        smSystemScript);
        if (err)
            {
            ReturnFalse_err("\pFSpCreate fails",err);
            }
        }

    BigMacFileWriter scheme;
    if (!scheme.BOOL_Open(spec))
        {
        ReturnFalse("\pOpen fails");
        }

    const Bool ok=BOOL_MakeTable(plainToHFS,
                                 length,
                                 cpp,
                                 scheme);

    if (!scheme.BOOL_Close())
        {
        ReturnFalse("\pClose fails");
        }

    if (!ok)
        {
        ReturnFalse("\pMakeTable fails");
        }

    return True;
}

Bool BOOL_MakeTable(TECObjectRef const plainToHFS,
                    const SInt32 length,
                    BigTextFileWriter &cpp,
                    BigTextFileWriter &scheme)
{
    SInt32 count=0;
    for (SInt32 i=0;i<65536;i++)
        {
        const UniChar plain=static_cast<UniChar>(i);
        HFSUniStr255 hfs;
        ByteCount actualInputLength;
        ByteCount actualOutputLength;
        const OSStatus status=::TECConvertText(plainToHFS,
                                               reinterpret_cast<ConstTextPtr>(&plain),
                                               2,
                                               &actualInputLength,
                                               reinterpret_cast<TextPtr>(hfs.unicode),
                                               510,
                                               &actualOutputLength);
        if (status)
            {
            ReturnFalse_status("\pTECConvertText fails",status);
            }

        hfs.length=static_cast<UInt16>(actualOutputLength>>1);

        if (hfs.length==length)
            {
            if (not ((length==1) and (*hfs.unicode==plain)))
                {
                count++;
                if (!BOOL_ShowCpp(plain,
                                  hfs,
                                  cpp))
                    {
                    ReturnFalse("\pShowCpp fails");
                    }
                if (!BOOL_ShowScheme(plain,
                                     hfs,
                                     scheme))
                    {
                    ReturnFalse("\pShowScheme fails");
                    }
                }
            }
        }

    cout << "Count for length ";
    cout << length;
    cout << " is ";
    cout << count;
    cout << ".";
    cout << endl;

    return True;
}

Bool BOOL_ShowCpp(const UniChar plain,
                  const HFSUniStr255 &hfs,
                  BigTextFileWriter &cpp)
{
    SpellReadable(cpp,"\p{");
    SpellNumber(cpp,plain);
    for (SInt32 i=0;i<hfs.length;i++)
        {
        SpellReadable(cpp,"\p,");
        SpellNumber(cpp,hfs.unicode[i]);
        }
    SpellReadable(cpp,"\p},");
    StartANewLine(cpp);
    return True;
}

Bool BOOL_ShowScheme(const UniChar plain,
                     const HFSUniStr255 &hfs,
                     BigTextFileWriter &scheme)
{
    SpellReadable(scheme,"\p(");
    SpellNumber(scheme,plain);
    for (SInt32 i=0;i<hfs.length;i++)
        {
        SpellReadable(scheme,"\p ");
        SpellNumber(scheme,hfs.unicode[i]);
        }
    SpellReadable(scheme,"\p)");
    StartANewLine(scheme);
    return True;
}

You can use this to write your own Unicode to HFS conversion.

Then you can use these tables to build a tree. Thanks to the Scheme language we can do this in a few words.
Code: [Select]
(require-library "compat.ss")

(define conversion
  (class object% ()
    (private
      [tree '()]
      [unicode #f])
    (public
      [add (lambda (plain hfs)
             (if (null? hfs)
                 (set! unicode plain)
                 (letrec ((first (car hfs))
                          (rest (cdr hfs))
                          (found (assv first tree)))
                   (if found
                       (send (cadr found) add plain rest)
                       (let ((new (make-object conversion)))
                         (begin
                           (set! tree (cons (list first new) tree))
                           (send new add plain rest)))))))]
      [search (lambda (hfs)
                (if (null? hfs)
                    unicode
                    (letrec ((first (car hfs))
                             (rest (cdr hfs))
                             (found (assoc first tree)))
                      (if found
                          (send (cadr found) search rest)
                          #f))))]
      [count (lambda ()
               (define (sum tree)
                 (if (null? tree)
                     0
                     (let ((first (car tree))
                           (rest (cdr tree)))
                       (+ (send (cadr first) count)
                          (sum rest)))))
               (if (null? tree)
                   0
                   (+ 1 (sum tree))))]
      [merge-sort (lambda ()
                    (define (merge-sort-tree tree)
                      (define (merge-sort-sub x)
                        (send (cadr x) merge-sort))
                      (define (lt? x y)
                        (< (car x) (car y)))
                      (begin
                        (for-each merge-sort-sub tree)
                        (sort lt? tree)))
                    (if (null? tree)
                        'ok
                        (set! tree (merge-sort-tree tree))))]
      [get-tree (lambda ()
                  (define (translate pair)
                    (list (car pair) (send (cadr pair) get-tree)))
                  (if (null? tree)
                      (number->string unicode)
                      (let ((translated (map translate tree)))
                        (if unicode
                            (cons (number->string unicode) translated)
                            translated))))]
      [display-tree-lengths (lambda ()
                              (define (translate pair)
                                (send (cadr pair) display-tree-lengths))
                              (if (not (null? tree))
                                  (begin
                                    (display (length tree))
                                    (newline)
                                    (for-each translate tree))))])
    (sequence
      (super-init))))

(define c (make-object conversion))
(define (add plain hfs) (send c add plain hfs))
(define (search hfs) (send c search hfs))
(define (count) (send c count))
(define (merge-sort) (send c merge-sort))
(define (get-tree) (send c get-tree))
(define (display-tree-lengths) (send c display-tree-lengths))

(define (add-data data)
  (define (add-plain-and-hfs r)
    (add (car r) (cdr r)))
  (for-each add-plain-and-hfs data))

(define (write-binary vpad b)
  (define dest-port
    (open-output-file vpad 'truncate/replace))
  (define (write-n1 n)
    (write-char (integer->char n) dest-port))
  (define (write-n2 n)
    (define hi (quotient n 256))
    (define lo (remainder n 256))
    (write-n1 hi)
    (write-n1 lo))
  (define (write-elements t)
    (begin
      (write-n2 (length t))
      (for-each write-conversion t)))
  (define (write-table t)
    (define first (car t))
    (define rest (cdr t))
    (if (string? first)
        (begin
          (write-n1 0)
          (write-n2 (string->number first))
          (write-elements rest))
        (begin
          (write-n1 1)
          (write-elements t))))
  (define (write-conversion c)
    (define hfs (car c))
    (define x (cadr c))
    (begin
      (write-n2 hfs)
      (if (string? x)
          (begin
            (write-n1 0)
            (write-n2 (string->number x)))
          (begin
            (write-n1 1)
            (write-table x)))))
  (begin
    (for-each write-conversion b)
    (close-output-port dest-port)))

(define (write-scheme vpad x)
  (define dest-port
    (open-output-file vpad 'truncate/replace))
  (begin
    (write x dest-port)
    (close-output-port dest-port)))

(load "Data1.ss")
(load "Data2.ss")
(load "Data3.ss")
(load "Data4.ss")

(add-data data1)
(add-data data2)
(add-data data3)
(add-data data4)

(search '(180)) ; => 8189
(search '(105 769)) ; => 146
(search '(4362 4468 4532)) ; => 50457
(search '(919 837 788 769)) ; => 8093

(count) ; => 595

(merge-sort)

(define b (get-tree))

(write-binary "Tree.dat" b)

(write-scheme "Tree.ss" b)

(display-tree-lengths)
; =>
; root has length 76
; 51 times length 1
; 24 times length 2
; 42 times length 3
; 15 times length 4
; 6 times length 5
; 4 times length 7
; 4 times length 9
; 19 times length 21
; 399 times length 27

The result is saved to a binary file that we copy into 'HFS+' resource 129.

Then you also make a table that tells you wether a character translates into itself:
Code: [Select]
#include "MakeIdentityTable.h"

//----------------------------------------
// Implementation details.
//----------------------------------------

Bool BOOL_MakeIdentityTable(TECObjectRef plainToHFS,
                            BigBinaryFileWriter &output);

//----------------------------------------

Bool BOOL_MakeIdentityTable(TECObjectRef const plainToHFS)
{
    FSSpec spec;
    OSErr err=::FSMakeFSSpec(0,
                             0,
                             "\p:Output:Identity.dat",
                             &spec);
    if (err)
        {
        if (err!=fnfErr)
            {
            ReturnFalse_err("\pFSpCreate fails",err);
            }
        err=::FSpCreate(&spec,
                        'hDmp',
                        'BINA',
                        smSystemScript);
        if (err)
            {
            ReturnFalse_err("\pFSpCreate fails",err);
            }
        }

    BigBinaryFileWriter output;
    if (!output.BOOL_Open(spec))
        {
        ReturnFalse("\pOpen fails");
        }

    const Bool ok=BOOL_MakeIdentityTable(plainToHFS,
                                         output);

    if (!output.BOOL_Close())
        {
        ReturnFalse("\pClose fails");
        }

    if (!ok)
        {
        ReturnFalse("\pMakeIdentityTable fails");
        }

    return True;
}

//----------------------------------------
// Implementation details.
//----------------------------------------

Bool BOOL_MakeIdentityTable(TECObjectRef const plainToHFS,
                            BigBinaryFileWriter &output)
{
    for (SInt32 i=0;i<65536;i++)
        {
        const UniChar plain=static_cast<UniChar>(i);
        HFSUniStr255 hfs;
        ByteCount actualInputLength;
        ByteCount actualOutputLength;
        const OSStatus status=::TECConvertText(plainToHFS,
                                               reinterpret_cast<ConstTextPtr>(&plain),
                                               2,
                                               &actualInputLength,
                                               reinterpret_cast<TextPtr>(hfs.unicode),
                                               510,
                                               &actualOutputLength);
        if (status)
            {
            ReturnFalse_status("\pTECConvertText fails",status);
            }

        hfs.length=static_cast<UInt16>(actualOutputLength>>1);

        const bool identity=(hfs.length==1) and (*hfs.unicode==plain);
        WriteBinary(output,identity);
        }
    return True;
}

The result is saved to a binary file that we copy into 'HFS+' resource 128.

'HFS+' resource 128 is used by the conversions in either direction.
'HFS+' resource 129 is used only by the HFS to Unicode conversion.
The 4 tables are used only by the Unicode to HFS conversion.

Then we notice that there are a few characters which are converted to the same character. If you convert them back then you may not get the original. For example 63, 65534 and 65535 are converted to 63.

Then you may end up with these conversions:
Code: [Select]
59 => 59 => 894
63 => 63 => 65535
96 => 96 => 8175
180 => 180 => 8189
183 => 183 => 903
198 => 198 => 1236
230 => 230 => 1237
399 => 399 => 1240
415 => 415 => 1256
439 => 439 => 1248
601 => 601 => 1241
629 => 629 => 1257
658 => 658 => 1249
697 => 697 => 884
768 => 768 => 832
769 => 769 => 833
787 => 787 => 835
953 => 953 => 8126
65534 => 63 => 65535

We avoid this by storing only the smallest number if there's more than one possibility. Then you get these conversions:
Code: [Select]
832 => 768 => 768
833 => 769 => 769
835 => 787 => 787
884 => 697 => 697
894 => 59 => 59
903 => 183 => 183
1236 => 198 => 198
1237 => 230 => 230
1240 => 399 => 399
1241 => 601 => 601
1248 => 439 => 439
1249 => 658 => 658
1256 => 415 => 415
1257 => 629 => 629
8126 => 953 => 953
8175 => 96 => 96
8189 => 180 => 180
65534 => 63 => 63
65535 => 63 => 63

This was found with this program:
Code: [Select]
Bool BOOL_Test_Unicode_HFS()
{
    for (z4 i=0;i<65536;i++)
        {
        c_n2 unicode1=static_cast<n2>(i);
        z4 hfs_length;
        n2 hfs[4];
        UnicodeToHFS::Convert(unicode1,
                              hfs_length,
                              hfs);
        z4 hfs_used;
        n2 unicode2;
        if (!HFSToUnicode::CanConvert(hfs_length,
                                      hfs,
                                      hfs_used,
                                      unicode2))
            {
            SpellReadable(cout,"\pThere's no conversion for ");
            SpellNumber(cout,unicode1);
            StartANewLine(cout);
            }
        if (hfs_used!=hfs_length)
            {
            ReturnFalse("\pUnused characters");
            }
        if (unicode2!=unicode1)
            {
            SpellNumber(cout,unicode1);
            SpellReadable(cout,"\p => ");
            for (z4 j=0;j<hfs_length;j++)
                {
                SpellNumber(cout,hfs[j]);
                SpellReadable(cout,"\p ");
                }
            SpellReadable(cout,"\p=> ");
            SpellNumber(cout,unicode2);
            StartANewLine(cout);
            }
        }
    return True;
}

My converter reads these resources and recreates the tables and the tree, then disposes the resources.

The memory use is fair:
- around 93 K shared.
- around 640 K for Unicode to HFS only.
- around 527 K for HFS to Unicode only.

Now the bad news: 18134 Unicode characters are not accepted by FSRenameUnicode. That's 28%.
Code: [Select]
Bool BOOL_TryEveryHFSFilenameWithLength1()
{
    FSSpec spec;
    OSErr err=::FSMakeFSSpec(0,
                             0,
                             "\pTest:0",
                             &spec);
    if (err)
        {
        ReturnFalse_err("\pFSMakeFSSpec fails",err);
        }

    FSRef ref;
    err=::FSpMakeFSRef(&spec,
                       &ref);
    if (err)
        {
        ReturnFalse_err("\pFSpMakeFSRef fails",err);
        }

    for (SInt32 i=0;i<65536;i++)
        {
        UniChar unicode[1];
        *unicode=static_cast<UniChar>(i);
        HFSUniStr255 hfs;
        UnicodeToHFS::Convert(1,
                              unicode,
                              hfs);
        err=::FSRenameUnicode(&ref,
                              hfs.length,
                              hfs.unicode,
                              kTextEncodingDefaultFormat,
                              nil);
        if (err)
            {
            cout << "Rename as ";
            cout << i;
            cout << " returns ";
            cout << err;
            cout << '.';
            cout << endl;
            }
        }

    return True;
}

In UnicodeTable.sitx you can see which characters you can use.

That's how far I've got.

See the demo program in the attachment.

Offline OS923

  • Platinum Member
  • *****
  • Posts: 888
Re: Designing a new Finder
« Reply #136 on: July 13, 2021, 07:23:08 AM »
 UnicodeNameEditor is discontinued because I don’t use PowerPlant anymore.

Offline OS923

  • Platinum Member
  • *****
  • Posts: 888
Re: Designing a new Finder
« Reply #137 on: August 09, 2021, 10:26:16 AM »
I wrote a WDEF which can draw Unicode text in the title bar.
It's just a working WDEF, no bling bling.
Here's a preview with a demo program:
http://os923.gangstalkingwiki.com/DesignNewFinder.htm
There’s no need to rewrite the entire WDEF because Appearance allows you to patch the function that draws the title. I tried this today and it works, it draws the title in Geneva 12. This works only with Appearance 1.1. Instead of trying this in a WDEF you can try this in a normal program by drawing a window frame in a window using DrawThemeWindowFrame.

Offline OS923

  • Platinum Member
  • *****
  • Posts: 888
Re: Designing a new Finder
« Reply #138 on: August 23, 2021, 08:33:11 AM »
I found the solution for the Unicode window titles.

Offline OS923

  • Platinum Member
  • *****
  • Posts: 888
Re: Designing a new Finder
« Reply #139 on: August 31, 2021, 08:17:06 AM »
I found the solution for color windows. This requires ColorSync. It's not flawless. There's a small chance for a glitch in drawing the grow box. I could understand that it's always wrong or usually wrong but not that it's rarely wrong. It’s impossible to debug.