packages feed

apelsin-1.1: src/Apelsin.hs

import Graphics.UI.Gtk
import System.Glib.GError

import Control.Applicative
import Control.Monad.IO.Class
import Control.Exception
import Control.Monad
import Data.Char (toLower)
import qualified Data.Set as S
import Network.Socket
import Network.Tremulous.Protocol
import System.FilePath (joinPath)

import Types
import Constants
import GtkUtils
import ServerInfo
import ServerBrowser
import FindPlayers
import Clanlist
import ClanFetcher
import Preferences
import Config
import Toolbar

main :: IO ()
main = withSocketsDo $ do
	unsafeInitGUIForThreadedRTS
	win		<- windowNew
	config		<- configFromFile
	cacheclans	<- clanListFromCache
	bundle	<-	(do
			mpolled		<- atomically $ newTMVar (PollResult [] 0 0 S.empty)
			mconfig		<- atomically $ newTMVar config
			mclans		<- atomically $ newTMVar cacheclans
			browserStore	<- listStoreNew []
			return Bundle {parent = win, ..}
			)
	mupdate <- atomically newEmptyTMVar
	(currentInfo, currentUpdate, currentSet)<- newServerInfo bundle mupdate
	(browser, browserUpdate, ent0)		<- newServerBrowser bundle currentSet
	(findPlayers, findUpdate, ent1)		<- newFindPlayers bundle currentSet
	(clanlist, clanlistUpdate, ent3)	<- newClanList bundle cacheclans currentSet
	(onlineclans, onlineclansUpdate)	<- newOnlineClans bundle currentSet

	preferences				<- newPreferences bundle
	atomically $ putTMVar mupdate (findUpdate, onlineclansUpdate)

	toolbar <- newToolbar bundle
		[]
		[browserUpdate, findUpdate, currentUpdate]
		[onlineclansUpdate, clanlistUpdate]

	-- /// Layout ////////////////////////////////////////////////////////////////////////////

	book <- notebookNew
	notebookAppendPage book browser		"Browser"
	notebookAppendPage book findPlayers	"Find players"
	notebookAppendPage book onlineclans	"Online clans"
	notebookAppendPage book clanlist	"Clan list"
	notebookAppendPage book preferences	"Preferences"
	leftView <- vBoxNew False 0
	boxPackStart leftView toolbar PackNatural 0
	boxPackStart leftView book PackGrow 0
	

	pane <- hPanedNew
	panedPack1 pane leftView True False
	panedPack2 pane currentInfo  False True


	-- save the current window size and pane positon on exit
	on win deleteEvent $ tryEvent $ liftIO $ do
		Config {autoGeometry} <- atomically $ readTMVar (mconfig bundle)
		when autoGeometry $ do
			file		<- inCacheDir "windowsize"
			(winw, winh)	<- windowGetSize win
			ppos		<- panedGetPosition pane
			writeFile file $ show (winw, winh, ppos)
		mainQuit

	ddir <- getDataDir
	handleGError (const $ trace $ "Window icon not found in: " ++ ddir) $ do
		let list = map
			(\x -> joinPath [ddir, "icons", "hicolor", x ++ "x" ++ x, "apps", "apelsin.png"])
			["16", "32", "48", "64"]
		icons <- mapM pixbufNewFromFile list
		set win [ windowIconList := icons]
	
	-- Without allowshrink the window may change size back and forth when selecting new servers
	set win [ containerChild	:= pane
		, windowTitle		:= fullProgramName
		, windowAllowShrink	:= True
		]

	--Showing it to get size requests
	widgetShowAll leftView

	-- Restore the window size and pane position
	when (autoGeometry config) $ handle ignoreIOException $ do
		file	<- inCacheDir "windowsize"
		fx	<- readFile file
		whenJust (mread fx) $ \(winw::Int, winh, ppos::Int) -> do
			Requisition  _ minh	<- widgetSizeRequest leftView
			Requisition minw _	<- widgetSizeRequest leftView
			let panebuf = 15 -- size we assume the panehandle is at most
			panedSetPosition pane (if minw+panebuf > winw then ppos+panebuf else ppos)
			set win [ widgetHeightRequest	:= max minh winh
				, widgetWidthRequest	:= max (minw+panebuf) winw ]
	widgetShowAll win

	on win keyPressEvent $  do
		kmod	<- eventModifier
		k	<- map toLower <$> eventKeyName
		case kmod of
			[Alt]	| Just page <- mread k
				, page >= 1
				, page <= 5
				-> do	liftIO (set book [ notebookPage := page - 1])
					return True
			[Control]
				| k == "l" || k == "f"
				-> do	page <- liftIO (get book notebookPage)
					case page of
						0 -> liftIO $ widgetGrabFocus ent0
						1 -> liftIO $ widgetGrabFocus ent1
						3 -> liftIO $ widgetGrabFocus ent3
						_ -> return ()
					return True
			_ -> return False
			
	widgetGrabFocus ent0
	mainGUI


ignoreIOException :: IOException -> IO ()
ignoreIOException _ = return ()