2016-11-18 9 views
3

Я хотел бы сделать в statusicon моей заявки.Как сделать в gtk3 statusicon с помощью cairo в приложении haskell?

Я знаю, что могу сделать statusicon дисплеем pixbuf, установив statusIconPixbuf.

И я могу создать пустой pixbuf через pixbufNew и делать такие вещи, как заполнение его одним цветом.

Но как сделать визуализацию в этом pixbuf с помощью cairo?

Или это pixbuf не правильная вещь для использования? Есть ли лучший способ визуализации в statusicon?

ответ

0

Использование Pixbuf Мне нужен способ визуализации в него.

следующее решение принимает каирский Rendering render :: Render a и желаемый X и Y размерности (квадрат) Pixbuf (Вы можете изменить это, если вам нужно создать неквадратные Pixbufs.)

import qualified Foreign.Ptr as Pointer 
import qualified ByteString as B 

renderPixbuf :: Int -> Render a -> IO Pixbuf 
renderPixbuf size render = withImageSurface FormatARGB32 size size $ \surface -> do 
    renderWith surface render 
    stride <- imageSurfaceGetStride surface 
    surfaceData <- swapRB stride <$> imageSurfaceGetData surface 
    B.useAsCStringLen surfaceData $ \(pointer, _) -> do 
     let pointer' = Pointer.castPtr pointer 
     pixbufNewFromData pointer' ColorspaceRgb True 8 size size stride 

Это использует функцию withImageSurface для создания поверхности для каира, которую нужно визуализировать, а затем вызывает renderWith для выполнения фактического рендеринга, указанного в render.

Следующие две строки извлекают шаг изображения, то есть количество байтов в строке и фактические данные изображения как ByteString.

swapRB - это функция, которая преобразует байтовую строку, потому что как-то красный и синий каналы находятся в неправильном порядке. Ниже описано, как это делается.

В B.useAsCStringLen он получает низкий уровень: It TAKS в байтовой строке, возвращаемой imageSurfaceGetData и преобразует его в Ptr CUChar создать новую Pixbuf с помощью pixbufNewFromData.

Все.

swapRB определяется следующим образом:

import Data.Word (Word8) 
import Data.List (unfoldr) 

splitAtIfNotNull :: Int -> B.ByteString -> Maybe (B.ByteString,B.ByteString) 
splitAtIfNotNull i string 
    | B.null string = Nothing 
    | otherwise = Just $ B.splitAt i string 

mapChunks :: (B.ByteString -> B.ByteString) -> Int -> B.ByteString -> B.ByteString 
mapChunks mapper chunkSize = B.concat . map mapper . unfoldr (splitAtIfNotNull chunkSize) 

swapRB :: Int -> B.ByteString -> B.ByteString 
swapRB = mapChunks swapRBforLine 
    where swapRBforLine :: B.ByteString -> B.ByteString 
     swapRBforLine = mapChunks (B.pack . swapRBforPixel . B.unpack) 4 
     swapRBforPixel :: [Word8] -> [Word8] 
     swapRBforPixel [b,g,r,a] = [r,g,b,a] 
     swapRBforPixel other = other 

Это разбивает байтовой строки из pixeldata в линии, а затем разбивает строки в пикселях каждый из которых состоит из 4-х байтов: один байт для каждого из каналов красного, зеленого, синего, альфа. Innermost является фактическим обменом:

swapRBforPixel [b,g,r,a] = [r,g,b,a]