#lang scheme/gui (require setup/getinfo mrlib/bitmap-label "show-help.ss") (define-struct game (file name set icon)) (define gamedir (collection-path "games")) (define (get-game game) (let* ([game (path-element->string game)] [info (with-handlers ([exn:fail? (lambda (x) #f)]) (get-info (list "games" game)))] [main (and info (info 'game (lambda () #f)))] [gamefile (lambda (f) (build-path gamedir game f))]) (and main (make-game (gamefile main) (info 'name (lambda () (string-titlecase (regexp-replace* #rx"-" game " ")))) (info 'game-set (lambda () "Other Games")) (info 'game-icon (lambda () (gamefile (format "~a.png" game)))))))) (define (run-game game) (define c (make-custodian)) (define run (dynamic-wind begin-busy-cursor (lambda () (with-handlers ([exn? (lambda (e) (lambda () (raise e)))]) (let ([u (dynamic-require (game-file game) 'game@)]) (lambda () (invoke-unit u))))) end-busy-cursor)) (parameterize* ([current-custodian c] [current-namespace (make-gui-empty-namespace)] [current-eventspace (make-eventspace)]) (queue-callback (lambda () (exit-handler (lambda (v) (custodian-shutdown-all c))) (with-handlers ([exn? (lambda (e) (message-box (format "Error in \"~a\"" (game-name game)) (let ([ep (open-output-string)]) (parameterize ([current-error-port ep]) ((error-display-handler) (exn-message e) e)) (get-output-string ep)) f '(ok)))]) (run)))))) (define games (filter values (map get-game (directory-list gamedir)))) (define game-sets (let ([ht (make-hash)]) (for ([g games]) (let ([set (game-set g)]) (hash-set! ht set (cons g (hash-ref ht set '()))))) (sort (hash-map ht cons) (lambda (x y) (let ([xlen (length x)] [ylen (length y)]) (cond [(> xlen ylen) #t] [(< xlen ylen) #f] [else (string