Apresentando no HN: Libmui, uma biblioteca de widgets clássicos do macOS para Linux
(github.com/buserror)- Libmui é uma biblioteca de UI que replica boa parte da API “Toolbox” do Macintosh Classic; não é uma implementação completa, mas oferece os recursos necessários para o emulador MII Apple //e e para aplicativos simples
- Começou como uma biblioteca de UI para o MII e busca uma UI posicionada manualmente, sem muitas dependências e sem menus com estilo de jogo baseados em “Arrow Keys + Return + Escape”
- A renderização funciona desenhando em um buffer ARGB e depois copiando para uma textura OpenGL ou para um shared pixmap do X11/XCB, acompanhando regiões inválidas para redesenhar apenas o necessário
- Diferentemente da Toolbox original do Macintosh, a API funciona de forma assíncrona e baseada em callbacks; ao mudar o estado, a UI se redesenha quando necessário, e os eventos são entregues por callback em vez de polling
- Inclui recursos de Window, Menu, Control, List, Alert e Standard File, mas não oferece zooming, resizing, diálogo de Save, dark mode, themes, Wayland, GTK/QT/SDL nem bindings para Rust/Go/Python
O que a Libmui oferece
- Libmui é uma biblioteca que replica grande parte da API “Toolbox” do Macintosh Classic
- Não é uma implementação completa, mas inclui as partes necessárias para alguns aplicativos simples e para o emulador MII Apple //e
- Ela surgiu da necessidade de uma biblioteca de UI para o MII, com poucas dependências e sem foco em uma navegação de menu com cara de jogo
- Primeiro foi testada uma UI immediate mode com Nuklear, mas o visual não agradou, a personalização era limitada e o mecanismo de layout colocava elementos em posições diferentes das desejadas
- Também pesou a experiência de que UIs immediate mode mantêm estado interno baseado em hash, e colisões de hash podem gerar problemas reais de depuração
- O objetivo é chegar mais perto de uma UI refinada manualmente do que de uma UI decidida automaticamente por um mecanismo de layout
Modelo de renderização e funcionamento
- A Libmui desenha a UI em uma “screen” formada por um buffer ARGB
- No MII, esse buffer é sobreposto como uma textura OpenGL
- A demo playground na pasta example copia o resultado para uma janela X11 usando XCB shared pixmap, e também funciona em X11 remoto
- Como em sistemas antigos, ela acompanha a invalid region e redesenha só as partes necessárias
- Não redesenha tudo a cada vez, então o overdraw é muito baixo
- Para desenhar em um framebuffer de 16 bits, por exemplo, é preciso converter diretamente a partir da saída ARGB
- Como só a dirty region precisa ser convertida, o custo não é alto
- A renderização poderia ser vetorizada em algo como vertex buffers, mas a avaliação é que o método atual já é rápido o suficiente e não precisa voltar ao comportamento de redesenhar tudo, como em UIs immediate mode
Diferenças em relação à Toolbox original do Macintosh
- O visual começou inspirado no MacOS 8/9, mas com os elementos em escala de cinza removidos; a avaliação foi que o estilo mais flat do System 7 envelheceu melhor, então esse caminho foi escolhido
- O popup menu é mais próximo do OS8, e a scrollbar se aproxima mais do GS/OS
- A grande diferença da API é o funcionamento totalmente assíncrono
- Não dá para desenhar em uma window ou GrafPort com spinloop a qualquer momento como no original
- Ao mudar o estado da UI, ela se redesenha sozinha quando necessário
- O processamento de eventos é baseado em callbacks
- Não há polling para descobrir o que aconteceu na UI
- Quando um item de menu é clicado ou um atalho de teclado é acionado, o callback de ação é chamado
- A estrutura conceitual é mais simples que a original
- Tudo é
mui_windowoumui_control - windows, menubars e menus são
mui_window - títulos de menu, itens de menu, todos os elementos dentro da window e linhas separadoras são
mui_control
- Tudo é
Managers e controles disponíveis
-
Window Manager
- Suporta criação de janelas e desenho dentro delas
- Oferece até 15 camadas, clipping, comportamento BringToFront e arraste de janelas
- O sistema de coordenadas, como no original, fica limitado a dois tipos: screen coordinates e window content coordinates
- Mantém uma lista de invalid rectangles para evitar redesenhar a janela inteira toda vez
- zooming e resizing estão em TODO
- transparent windows não são suportadas de propósito
- Isso acontece porque as janelas são desenhadas de cima para baixo para otimizar o clipping
- Para lidar com transparência seria preciso desenhar de baixo para cima, o que forçaria o redesenho de mais conteúdo
- Ainda assim, é possível aplicar alpha blend da screen inteira da UI no local desejado
-
Menu Manager
- Suporta menubar, menus, checkmarks e atalhos de teclado
- Foi feito para parecer com o System 7/8 ou com o GS/OS
- Há hierarchical menus, mas eles ainda não são idênticos ao original e precisam de melhorias
- Exibição e rolagem de popups muito grandes estão em TODO
- O suporte a sticky menus está meio implementado, mas foi desativado porque ainda não está correto
-
Control Manager
- Suporta buttons, checkboxes, radio buttons, scrollbars verticais e textboxes com quebra de linha
- O Edit Field ainda está em desenvolvimento, e o Slider está ausente
- O protótipo do controle de edição de texto funciona bem para entrada de uma linha, mas ainda não se encaixa em caixas de texto com múltiplas linhas
-
List Manager
- No momento, está quase hardcoded para mostrar nomes de arquivos
- Lida com arrow keys, page up/down e scroll wheel
- Como no MacOS original, é possível localizar o item desejado com typeahead
- O uso de compressão de fonte ou abreviação com ellipsis quando o texto do item é longo demais está em TODO
-
Alerts e Standard File
- O Alert oferece a caixa de diálogo comum de Cancel + OK
- Mais tipos de alert estão em TODO
- O Standard File oferece o clássico diálogo de Open file
- Esse recurso foi um dos principais objetivos iniciais da biblioteca
- O diálogo de Save está em TODO
- Há um popup extra que mostra diretórios usados recentemente
- Suporta arrow keys, page up/down e busca de arquivos por typeahead
-
Resource Manager
- Não há Resource Manager
- A avaliação é que seria necessária uma ferramenta como o ResEdit, então isso ficou fora do escopo atual
- Existe uma ideia de formato MessagePack para recursos, mas isso foi deixado para depois
Dependências e build
- A única dependência externa é libpixman
- libpixman é uma biblioteca para processamento de pixels e fornece recursos de region úteis para clipping
- Não é tão boa quanto as regions do QuickDraw, mas é considerada suficiente
- Também há componentes incluídos no código-fonte
- libcg: um pequeno renderizador antialiasing parecido com o cairo, composto por 2 arquivos
- stb_truetype.h: usado para carregar fontes TrueType
stb_ttc.h: uma extensão destb_truetype.hque organiza dicionário de fontes/glyphs, hash table, textura de fonte etc.- O código de geometria 2D tem mais de 25 anos e também foi incluído em libc3
- O build usa um Makefile simples, executando
makeno diretório raiz - Para compilar tests, demos e samples, são necessários
xcb,xcb-shm,xcb-randrexkbcommon-x11 - Se estiver usando o driver binário da Nvidia, para o
mui_shellfuncionar é preciso adicionarOption "AllowSHMPixmaps" "1"emDeviceno/etc/X11/xorg.conf
Forma de uso e fluxo de desenvolvimento
- Como ponto de partida, recomenda-se modificar
mui_shell.cemui_widgets_demo.c ui_mui_shellcarregamui_widgets_demo.socomo plugin e o recarrega automaticamente quando detecta mudanças- Ao modificar
mui_widgets_demo.c, ele é executado novamente após o recarregamento, permitindo criar novos dialogs rapidamente - Executar
make watchno diretóriolibmuirecompila automaticamente a biblioteca e omui_shellsempre que houver mudanças - Com o auto save do editor, isso permite um fluxo de trabalho de editar, compilar e executar continuamente
O que explicitamente não é oferecido
- sem dark mode
- sem suporte a themes
- sem transparent windows e sem cube effect
- sticky menus não estão ativados no momento
- não usa
cmake,meson,ninjanem autotools - sem bindings para linguagens como Rust, Go e Python
- não usa frameworks como GTK e QT
- não usa SDL
- sem suporte a Wayland
1 comentários
Comentários do Hacker News
A propósito, existe uma fonte TrueType em domínio público que reproduz muito bem a fonte de sistema Chicago original: https://fontlibrary.org/en/font/chicagoflf
A Charcoal, usada depois do System 8.x, é bem menos conhecida e, pessoalmente, acho uma melhoria considerável
Ainda assim, mudar para Chicago na biblioteca é na verdade bem fácil. Além da reprodução mencionada, também existe por aí uma versão TTF “plain” da Chicago original
Depois é só converter o TTF para OTF com a ferramenta de linha de comando do FontForge: https://www.macintoshrepository.org/1682-mac-os-7-6-x
fontforge -script -c 'Open($1); Generate($2);' input_font.ttf output_font.otfMuito legal. O Michel fez isso para o emulador Apple II dele, e eu estou usando meio que de brincadeira para substituir o frontend de um emulador Archimedes
Ainda está no começo, mas se eu consigo entender a API, então com certeza é uma boa API :)
Mesmo assim, tenho carinho pela interface clássica do Mac
Gostei do rasterizador gráfico 2D com abordagem de cabeçalho duplo que este projeto usa: https://github.com/xboot/libcg
Sempre impressiona ver como dá para criar software poderoso com dependências tão mínimas
Será que é tão difícil fazer uma biblioteca de UI limpa e poderosa que possa servir como alternativa ao Electron?
Incrível. Em C e sob licença MIT! Se alguém adicionar um shim para a API do AppKit, talvez até possa competir com o GNUstep
Ficou bonito. Queria poder mudar toda a minha interface do macOS para algo assim
Bom projeto. Eu gostava muito da antiga interface clássica do Mac
Todos os exemplos parecem ótimos, e pelo código de demonstração dos widgets também parece fácil de usar
Muito legal. Fico me perguntando quanto trabalho daria ler arquivos de recursos (.rsrc) do resource fork para montar a UI
Se isso fosse possível, daria para usar o ResEdit :-)