gi-gtk-hs 0.3.5.0 → 0.3.6.1
raw patch · 2 files changed
+144/−4 lines, 2 filesdep ~basedep ~base-compatnew-uploader
Dependency ranges changed: base, base-compat
Files
- gi-gtk-hs.cabal +5/−4
- src/Data/GI/Gtk/Threading.hs +139/−0
gi-gtk-hs.cabal view
@@ -1,5 +1,5 @@ name: gi-gtk-hs-version: 0.3.5.0+version: 0.3.6.1 synopsis: A wrapper for gi-gtk, adding a few more idiomatic API parts on top description: A wrapper for gi-gtk, adding a few more idiomatic API parts on top homepage: https://github.com/haskell-gi/gi-gtk-hs@@ -18,6 +18,7 @@ library exposed-modules: Data.GI.Gtk, Data.GI.Gtk.BuildFn+ Data.GI.Gtk.Threading Data.GI.Gtk.ModelView.Types Data.GI.Gtk.ModelView.CellLayout Data.GI.Gtk.ModelView.CustomStore@@ -26,13 +27,13 @@ Data.GI.Gtk.ModelView.TreeModel Data.GI.Gtk.ComboBox - build-depends: base >=4.7 && <4.11,- base-compat >=0.9.0 && <0.10,+ build-depends: base >=4.7 && <5,+ base-compat >=0.9.0 && <0.11, mtl >=2.1 && <2.3, transformers >=0.3.0.0 && <0.6, containers >=0.5.5.1 && <0.6, text >=1.2 && <1.3,- haskell-gi-base >=0.20 && <0.21,+ haskell-gi-base >=0.20 && <0.22, gi-glib >=2.0.6 && <2.1, gi-gobject >=2.0.6 && <2.1, gi-gdk >=3.0.6 && <3.1,
+ src/Data/GI/Gtk/Threading.hs view
@@ -0,0 +1,139 @@+-- -*-haskell-*-+--+-- Author : Brandon Sloane+--+-- Created: 16 August 2017+--+-- Copyright (C) 2017 Brandon Sloane+--+-- This library is free software; you can redistribute it and/or+-- modify it under the terms of the GNU Lesser General Public+-- License as published by the Free Software Foundation; either+-- version 2.1 of the License, or (at your option) any later version.+--+-- This library is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU+-- Lesser General Public License for more details.+--+-- |+-- Stability : provisional+-- Portability : portable (depends on GHC)+--+-- Utility functions for threading+--+module Data.GI.Gtk.Threading+ (+-- | Utility functions to run IO actions on the GUI thread. You must call+-- 'Data.GI.Gtk.Threading.setGUIThread' or 'Data.GI.Gtk.Threading.setCurrentThreadAsGUIThread'+-- before using the synchronous options, or you risk deadlocking.+--+-- Note that the notion of "Thread" used by this module corresponds to operating system threads, not Haskell threads.+-- A single operating system thread may run multiple Haskell threads, and a Haskell thread may migrate between operating system threads.+-- In order for this nothing of "Thread" to make sense to a Haskell program, we must be working in a bound Haskell thread, which is tied to a single operating system thread.+-- Haskell's main function is automatically bound, and the postGUI functions will create a new bound thread if nessasary.+ setGUIThread+ , getGUIThread+ , setCurrentThreadAsGUIThread+ , postGUISyncWithPriority+ , postGUISync+ , postGUIASyncWithPriority+ , postGUIASync+ , compareThreads+ , isGUIThread+ , module GI.GLib --threadSelf and Thread+ ) where++import Control.Concurrent+import Control.Concurrent.MVar+import Data.Int (Int32)+import System.IO.Unsafe (unsafePerformIO)+import System.IO (stderr, hPutStrLn)+import GI.Gdk (threadsAddIdle)+import GI.GLib.Constants+import GI.GLib (threadSelf, Thread(..))+import Data.GI.Base.ManagedPtr+++guiThread :: MVar (Maybe Thread)+{-# NOINLINE guiThread #-}+guiThread = unsafePerformIO $ newMVar Nothing++-- | Inform gi-gtk-hs what thread is running the gtk main loop.+setGUIThread :: Thread -> IO ()+setGUIThread t = swapMVar guiThread (Just t) >> return ()++-- | Inform gi-gtk-hs that the current thread is, or will be, running the gtk main loop.+--+-- Equivalent to @'GI.GLib.threadSelf' >>= 'Data.GI.Gtk.Threading.setGUIThread'@+setCurrentThreadAsGUIThread :: IO ()+setCurrentThreadAsGUIThread = threadSelf >>= setGUIThread++-- | Get the Thread that is running the Gtk main loop, if it has been set.+getGUIThread :: IO (Maybe Thread)+getGUIThread = readMVar guiThread++-- | Queue an action to be run in the GTK event loop.+-- If called from the same process as the event loop, this runs the action directly.+-- Otherwise, this queues it in GTK's event loop and blocks until the action is complete+--+-- You must call 'Data.GI.Gtk.Threading.setGUIThread' or 'Data.GI.Gtk.Threading.setCurrentThreadAsGUIThread' before this.+--+-- Priority is typically between 'GI.GLib.Constants.PRIORITY_HIGH_IDLE' (100) and 'GI.GLib.Constants.PRIORITY_DEFAULT_IDLE' (200)+postGUISyncWithPriority :: Int32 -> IO a -> IO a+postGUISyncWithPriority priority action = runInBoundThread $ do+ b <- isGUIThread+ if b then+ action+ else+ run+ where+ run = do+ ans <- newEmptyMVar+ threadsAddIdle priority $ action >>= putMVar ans >> return False+ takeMVar ans++-- | Queue an action to be run in the GTK event loop.+-- If called from the same process as the event loop, this runs the action directly.+-- Otherwise, this queues it in GTK's event loop and blocks until the action is complete+--+-- You must call 'Data.GI.Gtk.Threading.setGUIThread' or 'Data.GI.Gtk.Threading.setCurrentThreadAsGUIThread' before this.+--+-- Equivalent to @'Data.GI.Gtk.Threading.postGUISyncWithPriority' 'GI.GLib.Constants.PRIORITY_DEFAULT_IDLE'@+postGUISync :: IO a -> IO a+postGUISync = postGUISyncWithPriority PRIORITY_DEFAULT_IDLE++-- | Queue an action to be run in the GTK event loop.+-- This function queues the event regardless of what process it is called from, and returns immidietly.+--+-- Priority is typically between 'GI.GLib.Constants.PRIORITY_HIGH_IDLE' (100) and 'GI.GLib.Constants.PRIORITY_DEFAULT_IDLE' (200)+postGUIASyncWithPriority :: Int32 -> IO () -> IO ()+postGUIASyncWithPriority priority action = threadsAddIdle priority (action >> return False) >> return ()++-- | Queue an action to be run in the GTK event loop.+-- This function queues the event regardless of what process it is called from, and returns immidietly.+--+-- Equivalent to @'Data.GI.Gtk.Threading.postGUIASyncWithPriority' 'GI.GLib.Constants.PRIORITY_DEFAULT_IDLE'@+postGUIASync :: IO () -> IO ()+postGUIASync = postGUIASyncWithPriority PRIORITY_DEFAULT_IDLE++-- | Test if two 'GI.GLib.Structs.Thread.Thread's refer to the same OS thread.+-- A 'GI.GLib.Structs.Thread.Thread' can be gotten from 'GI.GLib.Structs.Thread.threadSelf'.+-- Note that 'GI.GLib.Structs.Thread.threadSelf' only makes sense from a bound thread.+compareThreads :: Thread -> Thread -> IO Bool+compareThreads (Thread mptr1) (Thread mptr2) =+ withManagedPtr mptr1 $ \ptr1 ->+ withManagedPtr mptr2 $ \ptr2 ->+ return $ ptr1 == ptr2++-- | Check if the current thread is the Gtk gui thread.+--+-- You must call 'Data.GI.Gtk.Threading.setGUIThread' or 'Data.GI.Gtk.Threading.setCurrentThreadAsGUIThread' before this.+-- This only makes sense when called from a bound thread.+isGUIThread :: IO Bool+isGUIThread = do+ guiThread <- getGUIThread+ case guiThread of+ Nothing -> hPutStrLn stderr "WARNING Data.GI.Gtk.Threading Calling isGUIThread before setGUIThread" >> return False+ Just t1 -> threadSelf >>= compareThreads t1+