Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for setting window icon and title on MacOS #6

Open
georgefst opened this issue Dec 21, 2021 · 1 comment
Open

Add support for setting window icon and title on MacOS #6

georgefst opened this issue Dec 21, 2021 · 1 comment

Comments

@georgefst
Copy link
Owner

We need a Mac version of Util.Window (introduced in georgefst/lifx-manager#8)

XQuartz

(I abandoned this as it's all clunkier than expected, even once set up properly. And, crucially, I couldn't get openDisplay to return anything other than null for a Gloss window, probably because Gloss is using an OpenGL that targets Quartz, rather than X11.)

None/little of the below should be necessary:

nix-shell -p xorg.libX11 -p xorg.libXext -p xorg.libXrender -p xorg.libXrandr -p xorg.libXScrnSaver

#TODO this errors out for some (error: path '/nix/store/m76c8x2qxc42vc9g9gmbi5vh3kqq2lj1-libX11-1.7.0-man' is not valid)
    # so we've hardcoded Church paths below (12/12/21), rather than using e.g. `$X11`
#TODO also for some of these, there are multiple paths
X11=$(nix path-info $(nix-instantiate '<nixpkgs>' -A xorg.libX11))
Xrandr=$(nix path-info $(nix-instantiate '<nixpkgs>' -A xorg.libXrandr))
# ...

rm cabal.project.local
echo '
package X11
    extra-lib-dirs:
        /nix/store/gfipvaizlslshnphk65582pcv2mqqj2v-libX11-1.7.0/lib
        /nix/store/lh8s4vv95dirn11fj89ax2x6w9sqk9d5-libXrandr-1.5.2/lib
        /nix/store/pl0f3wanll5phixlxm011ql1rrzdj2xk-libXScrnSaver-1.2.3/lib
        /nix/store/bpvrd298qm3dvvzclav8hb39394i4c0x-libXext-1.3.4/lib
' > cabal.project.local
CPPFLAGS=" \
    -I/nix/store/kp8lx4z07lhwffr6dr0gz6x7v3cdbi7i-xorgproto-2020.1/include \
    -I/nix/store/5czbg1s55qy00ia03xpjgx2r3h88z21x-libX11-1.7.0-dev/include \
    -I/nix/store/731lhdqg9vs44ikzhl3kwg44zz808pdd-libXrandr-1.5.2-dev/include \
    -I/nix/store/gq4v0d7wvbzqxm28zjf8ci26m463x1lm-libXrender-0.9.10-dev/include \
    -I/nix/store/pl0f3wanll5phixlxm011ql1rrzdj2xk-libXScrnSaver-1.2.3/include \
    " \
LDFLAGS=" \
    -L/nix/store/gfipvaizlslshnphk65582pcv2mqqj2v-libX11-1.7.0/lib \
    -L/nix/store/lh8s4vv95dirn11fj89ax2x6w9sqk9d5-libXrandr-1.5.2/lib \
    -L/nix/store/pl0f3wanll5phixlxm011ql1rrzdj2xk-libXScrnSaver-1.2.3/lib \
    -L/nix/store/bpvrd298qm3dvvzclav8hb39394i4c0x-libXext-1.3.4/lib \
    " \
cabb

Quartz API via macos-corelibs ^>= 0.0.1.0

This library is unmaintained and the API messy (plus no Hackage docs), but it actually seems pretty solid. I sense the author really knows what they're doing, and has thought through a lot of the hard problems involved in building a Haskell wrapper for Quartz. Unfortunately, it seems that Quartz doesn't allow for arbitrarily setting window title and icon like X11 and Win32 do. Very possibly for security reasons (it actually surprises me a little that the other two are so cavalier). I only realised this restriction after spending a few hours fiddling, and writing the exploratory code below.

{-# OPTIONS_GHC -Wno-unused-top-binds #-}

module Util.Window.Quartz (
    Window,
    findByName,
    setTitle,
    setIcon,
) where

import Data.ByteString (ByteString)
import Data.Text (Text)

import MacSdk

test = do
    Just widsArray <- windowListCopyWindowInfo [] Nothing
    wids <- arrayValues $ getDictionary <$> widsArray
    traverse mkWID wids

data WID = WID
    { kCGWindowNumber :: Int
    , kCGWindowStoreType :: Int
    , kCGWindowLayer :: Int
    -- , kCGWindowBounds :: Dictionary
    , kCGWindowSharingState :: Int
    -- , kCGWindowAlpha :: Float
    , kCGWindowOwnerPID :: Int
    , kCGWindowMemoryUsage :: Int
    , kCGWindowOwnerName :: Maybe String
    , kCGWindowName :: Maybe String
    , kCGWindowIsOnscreen :: Maybe Bool
    , kCGWindowBackingLocationVideoMemory :: Maybe Bool
    }
    deriving (Show)

-- mkWID :: WindowInfoDictionary -> IO WID
-- mkWID (getDictionary -> wid) = do
mkWID :: Dictionary -> IO WID
mkWID wid = do
    kCGWindowNumber <- int =<< dictLookup "kCGWindowNumber"
    kCGWindowStoreType <- int =<< dictLookup "kCGWindowStoreType"
    kCGWindowLayer <- int =<< dictLookup "kCGWindowLayer"
    -- kCGWindowBounds <- fromString CFStringEncodingUTF8 "kCGWindowBounds"
    kCGWindowSharingState <- int =<< dictLookup "kCGWindowSharingState"
    -- kCGWindowAlpha <- float =<< dictLookup "kCGWindowAlpha"
    kCGWindowOwnerPID <- int =<< dictLookup "kCGWindowOwnerPID"
    kCGWindowMemoryUsage <- int =<< dictLookup "kCGWindowMemoryUsage"
    kCGWindowOwnerName <- traverse string =<< dictLookup' "kCGWindowOwnerName"
    kCGWindowName <- traverse string =<< dictLookup' "kCGWindowName"
    kCGWindowIsOnscreen <- traverse bool =<< dictLookup' "kCGWindowIsOnscreen"
    kCGWindowBackingLocationVideoMemory <- traverse bool =<< dictLookup' "kCGWindowBackingLocationVideoMemory"
    pure $ WID{..}
  where
    dictLookup s = getDictValue wid =<< fromString CFStringEncodingUTF8 s
    dictLookup' s = do
        s' <- fromString CFStringEncodingUTF8 s
        withCFPtr s' $ getDictValueSafe wid
    int x = do
        Just n <- numberGetValue x NumberIntType
        pure $ fromIntegral n
    string s = do
        Just r <- toString CFStringEncodingUTF8 s
        pure r
    bool x = withCFPtr x refToBool

data Window = Window
    deriving (Eq, Ord)

findByName ::
    -- | substring which must appear in the window title
    Text ->
    IO Window
findByName name = do
    undefined

setTitle :: Window -> Text -> IO ()
setTitle (Window) t = do
    undefined

setIcon ::
    Window ->
    -- | PNG image
    ByteString ->
    IO ()
setIcon (Window) img = do
    undefined

AppKit?

I don't know much about it, but it looks like this may be the way.

@georgefst georgefst transferred this issue from georgefst/lifx-manager Dec 22, 2023
@georgefst
Copy link
Owner Author

The complexity of this is another reason why I don't really like this library, and feel it may be better to just use proper packaging where possible. See #2 (comment).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant