packages feed

threadscope-0.1: ThreadScope.hs

{-# LANGUAGE CPP #-}
-- ThreadScope: a graphical viewer for Haskell event log information.
-- Maintainer: satnams@microsoft.com, s.singh@ieee.org

module Main where

-- Imports for GTK/Glade
import Graphics.UI.Gtk
import Graphics.UI.Gtk.Glade
import Graphics.Rendering.Cairo 
import qualified Graphics.Rendering.Cairo as C
import Graphics.UI.Gtk.ModelView as New

-- Imports from Haskell library
import System.Environment
import Control.Monad
import Data.IORef
import Data.Maybe
import qualified Data.Function
import Data.List
#ifndef mingw32_HOST_OS
import System.Posix
#endif
import Control.Concurrent
import Control.Exception

import Paths_threadscope

-- Imports for ThreadScope
import State
import About
import FileDialog
import Options
import ReadEvents
import EventsWindow
import Timeline
import SaveAsPDF
import SaveAsPNG
import Sidebar
import Traces

-------------------------------------------------------------------------------

main :: IO ()
main 
  = do -- Deal with command line argument processing.
       -- This application accepts one optional argument specifying 
       -- the event log.
       args <- getArgs
       let options = parseOptions args

       unsafeInitGUIForThreadedRTS
       state <- buildInitialState options

       startup options state

startup :: [Option] -> ViewerState -> IO ()
startup options state@ViewerState{..} 
  = do
       let
           filenames = [filename | Filename filename <- options]
           tracenames = [name | TestTrace name <- options]
       when (length filenames > 1)
         (putStrLn "usage: threadscope [eventlog_filename]")
       let filename = if filenames == [] then
                       ""
                      else
                        head filenames
           traceName = if tracenames == [] then
                         ""
                       else
                         head tracenames

       writeIORef filenameIORef (if filename == "" then
                                   Nothing
                                 else
                                   Just filename)
        
       widgetSetAppPaintable mainWindow True
       logoPath <- getDataFileName "threadscope.png"
       windowSetIconFromFile mainWindow logoPath

       ------------------------------------------------------------------------
       -- Status bar functionality
       ctx <- statusbarGetContextId statusBar "state"
       statusbarPush statusBar ctx "No eventlog loaded."

       ------------------------------------------------------------------------
       --- Get the label for the name of the event log

       -- B&W toggle button
       bwToggle `onToggle` timelineParamsChanged state

       -- No Labels toggle button
       showLabelsToggle `onToolButtonToggled` timelineParamsChanged state

       -- When a filename for an event log is specified open and
       -- parse the event log file and update the IORefs for 
       -- the capabilities and event array.
       when (filename /= "") $ registerEventsFromFile filename state

       -- Likewise for test traces
       when (traceName /= "") $ registerEventsFromTrace traceName state

       -- B&W toggle button
                      
       -- The File:Open menu option can be used to specify an
       -- eventlog file.
       openMenuItem `onActivateLeaf` do
         filename <- openFileDialog mainWindow
         when (isJust filename) $
           registerEventsFromFile (fromJust filename) state
                                     
       ------------------------------------------------------------------------
       -- Save as PDF functionality
       saveAsPDFMenuItem `onActivateLeaf` saveAsPDF state 

       ------------------------------------------------------------------------
       -- Save as PNG functionality
       saveAsPNGMenuItem `onActivateLeaf` saveAsPNG state 

       ------------------------------------------------------------------------
       -- Reload functionality
       onActivateLeaf reloadMenuItem $
          do mb_filename <- readIORef filenameIORef
             case mb_filename of
               Nothing -> return ()
               Just filename -> registerEventsFromFile filename state

       ------------------------------------------------------------------------
       -- CPUs view

       setupTimelineView state

       ------------------------------------------------------------------------
       -- Event view

       setupEventsWindow state

       ------------------------------------------------------------------------
       -- Sidebar

       setupSideBar state

       ------------------------------------------------------------------------
       -- Quit
       quitMenuItem `onActivateLeaf` mainQuit

       ------------------------------------------------------------------------
       -- About dialog
       aboutMenuItem `onActivateLeaf` showAboutDialog mainWindow

       ------------------------------------------------------------------------
       -- Quit behaviour
       onDestroy mainWindow mainQuit

       ------------------------------------------------------------------------
       -- Show all windows
       widgetShowAll mainWindow

#ifndef mingw32_HOST_OS
       main <- myThreadId
       installHandler sigINT (Catch (postGUIAsync (throw UserInterrupt))) Nothing
#endif

       ------------------------------------------------------------------------
       -- Enter main event loop for GUI.
       mainGUI

-------------------------------------------------------------------------------

buildInitialState :: [Option] -> IO ViewerState
buildInitialState options = do

       gladePath <- getDataFileName "threadscope.glade"
       Just xml <- xmlNew gladePath
       
       let debug = Debug `elem` options


       filenameIORef <- newIORef Nothing

       -- IORefs are used to communicate informaiton about the eventlog
       -- to the callback functions for windows, buttons etc.
       capabilitiesIORef <- newIORef Nothing
       hecsIORef         <- newIORef Nothing
       lastTxIORef       <- newIORef 0
       eventArrayIORef   <- newIORef (error "eventArrayIORef")
       scaleIORef        <- newIORef defaultScaleValue
       cursorIORef       <- newIORef 0

       mainWindow         <- xmlGetWidget xml castToWindow "main_window"
       statusBar          <- xmlGetWidget xml castToStatusbar "statusbar"
       hpaned             <- xmlGetWidget xml castToHPaned "hpaned"

       bwToggle           <- xmlGetWidget xml castToCheckMenuItem "black_and_white"
       sidebarToggle      <- xmlGetWidget xml castToCheckMenuItem "view_sidebar"
       openMenuItem       <- xmlGetWidget xml castToMenuItem "openMenuItem"
       saveAsPDFMenuItem  <- xmlGetWidget xml castToMenuItem "saveAsPDFMenuItem"
       saveAsPNGMenuItem     <- xmlGetWidget xml castToMenuItem "saveAsPNGMenuItem"
       reloadMenuItem     <- xmlGetWidget xml castToMenuItem "view_reload"
       quitMenuItem       <- xmlGetWidget xml castToMenuItem "quitMenuItem"
       aboutMenuItem      <- xmlGetWidget xml castToMenuItem "aboutMenuItem"

       timelineDrawingArea      <- xmlGetWidget xml castToDrawingArea
                                        "timeline_drawingarea"
       timelineLabelDrawingArea <- xmlGetWidget xml castToDrawingArea
                                        "timeline_labels_drawingarea"
       timelineKeyDrawingArea   <- xmlGetWidget xml castToDrawingArea
                                        "timeline_key_drawingarea"
       timelineHScrollbar       <- xmlGetWidget xml castToHScrollbar
                                        "timeline_hscroll"
       timelineVScrollbar       <- xmlGetWidget xml castToVScrollbar
                                        "timeline_vscroll"
       timelineAdj         <- rangeGetAdjustment timelineHScrollbar
       timelineVAdj        <- rangeGetAdjustment timelineVScrollbar

       timelineTraces     <- newIORef []
       timelinePrevView   <- newIORef Nothing

       zoomInButton       <- xmlGetWidget xml castToToolButton "cpus_zoomin"
       zoomOutButton      <- xmlGetWidget xml castToToolButton "cpus_zoomout"
       zoomFitButton      <- xmlGetWidget xml castToToolButton "cpus_zoomfit"

       showLabelsToggle   <- xmlGetWidget xml castToToggleToolButton "cpus_showlabels"
       firstButton        <- xmlGetWidget xml castToToolButton "cpus_first"
       lastButton         <- xmlGetWidget xml castToToolButton "cpus_last"
       centreButton       <- xmlGetWidget xml castToToolButton "cpus_centre"

       eventsFontExtents  <- newIORef (error "eventsFontExtents")
       eventsCursorIORef  <- newIORef Nothing
       eventsVScrollbar   <- xmlGetWidget xml castToVScrollbar "eventsVScroll"
       eventsAdj          <- rangeGetAdjustment eventsVScrollbar
       eventsDrawingArea  <- xmlGetWidget xml castToDrawingArea "eventsDrawingArea"
       eventsTextEntry    <- xmlGetWidget xml castToEntry "events_entry"
       eventsFindButton   <- xmlGetWidget xml castToToolButton "events_find"
       eventsFirstButton  <- xmlGetWidget xml castToToolButton "events_first"
       eventsHomeButton   <- xmlGetWidget xml castToToolButton "events_home"
       eventsLastButton   <- xmlGetWidget xml castToToolButton "events_last"

       sidebarVBox        <- xmlGetWidget xml castToVBox "sidebar_vbox"
       sidebarHBox        <- xmlGetWidget xml castToHBox "sidebar_hbox"
       sidebarCombo       <- xmlGetWidget xml castToComboBox "sidebar_combobox"
       sidebarComboState  <- newIORef sidebarBookmarks
       sidebarCloseButton <- xmlGetWidget xml castToButton "sidebar_close_button"
       bookmarkVBox       <- xmlGetWidget xml castToVBox "bookmarks_vbox"
       bookmarkTreeView   <- xmlGetWidget xml castToTreeView "bookmark_list"

       -- Bookmarks
       addBookmarkButton  <- xmlGetWidget xml castToToolButton "add_bookmark_button"
       deleteBookmarkButton <- xmlGetWidget xml castToToolButton "delete_bookmark" 
       gotoBookmarkButton  <- xmlGetWidget xml castToToolButton "goto_bookmark_button"
       bookmarkStore <- New.listStoreNew []
       New.treeViewSetModel bookmarkTreeView bookmarkStore  
       New.treeViewSetHeadersVisible bookmarkTreeView True
       bookmarkColumn <- New.treeViewColumnNew
       New.treeViewColumnSetTitle bookmarkColumn "Time"    
       cell <- New.cellRendererTextNew
       New.treeViewColumnPackStart bookmarkColumn cell True
       New.cellLayoutSetAttributes bookmarkColumn cell bookmarkStore  
          (\record -> [New.cellText := show record ++ " ns"])
       New.treeViewAppendColumn bookmarkTreeView bookmarkColumn

       -- Trace view
       tracesVBox <- vBoxNew False 0
       tracesTreeView <- treeViewNew
       tracesStore <- treeStoreNew []
       treeViewSetModel tracesTreeView tracesStore
       boxPackEnd tracesVBox tracesTreeView PackGrow 0

       return ViewerState { .. }