packages feed

hs-wayland-scanner-0.1.0: examples/hello-world/Buffer.hs

{-# LANGUAGE ForeignFunctionInterface #-}
module Buffer where

import Foreign
import Foreign.C.Types
import Control.Monad
import System.Posix.Types (Fd(..), COff(..))
import System.Posix.IO (closeFd)
import System.Posix.Files (setFdSize, stdFileMode)
import System.Posix.SharedMem

-- Using the mmap package would be nice but there are some portabilty
-- issues (see below), so we will use mmap from the standard C library.
-- import System.IO.MMap

import Graphics.Wayland.Protocol.Wayland
import Graphics.Wayland.Client.Protocol.Wayland

-- Use mmap from the Standard C library.
foreign import ccall "sys/mman.h mmap"
  c_mmap :: Ptr () -> CSize -> CInt -> CInt -> CInt -> COff -> IO (Ptr ())

-- Helper to get the CInt out of Fd
unFd :: Fd -> CInt
unFd (Fd n) = n

-- Create a buffer and  fill it with green pixels.
createBuffer :: Ptr WlShm -> Int -> Int -> IO (Ptr WlBuffer)
createBuffer shm width height = do
  let stride = width * 4
      size   = fromIntegral $ stride * height
      -- A unique name for the shared memory segment.
      shmName = "/hs-wayland-example-" ++ show width ++ "x" ++ show height

  -- Create a shared memory object, with shmReadWrite and shmCreate.
  fd <- shmOpen shmName (ShmOpenFlags True True False False) stdFileMode

  -- Resize the memory segment to the correct size.
  setFdSize fd size

  -- Map the memory into our process.
  -- mmapFilePtr from the mmap package requires the full path which
  -- may be different in different POSIX systems.
  -- (ptr, _, _, _) <- mmapFilePtr ("/dev/shm" ++ shmName) ReadWrite (Just (0, fromIntegral size))
  ptr <- c_mmap nullPtr (fromIntegral size) (1 .|. 2) 1 (unFd fd) 0

  -- Fill with blue with 50% transparency (0x800000FF)
  let pixels = castPtr ptr :: Ptr Word32
  forM_ [0 .. width * height - 1] $ \i ->
    pokeElemOff pixels i 0x800000ff

  -- Create Wayland objects.
  pool   <- wl_shm_create_pool shm (unFd fd) (fromIntegral size)
  buffer <- wl_shm_pool_create_buffer pool
                0
                (fromIntegral width)
                (fromIntegral height)
                (fromIntegral stride)
                WL_SHM_FORMAT_ARGB8888 -- 32-bit ARGB format

  -- Cleanup.
  shmUnlink shmName
  closeFd fd

  return buffer