zu www.bildungsgueter.de next page Table of Section Contents previous page

Asking Permission Before a Window is Closed


Occasionally it is useful not to close a window immediately but to ask the user to confirm the close request. To do that, you have to provide a handler for the deleteEvent of your window. That handler is required to have the type

Window ->  IO Bool

or

Window ->  EventM EAny Bool

The return value of that handler indicates whether or not the user allows to close the window.

The handler itself opens a dialog window to obtain a decision.

Archive file with this example: Example003.tar.gz. Be sure to read the file README.txt for further instructions.

import "gtk3" Graphics.UI.Gtk
import "gtk3" Graphics.UI.Gtk.Gdk.Events
import Control.Monad.IO.Class      -- for liftIO

--  This function handles the delete event. The delete event is
--  vetoable; the event handler is required to return a logical
--  value to indicate whether the event handling should be continued
--  or aborted.
--  Possible result values of this funtion:
--    True  :  do not continue event handling. This will keep
--             the window.
--    False :  continue event handling. This will close and
--             destroy the window.
--  This handler displays a confirmer to decide how to proceed.
--
deleteEventHandler :: Window ->  IO Bool
deleteEventHandler transientParentWindow =
    do
    dialog <- messageDialogNew (Just transientParentWindow)
                      [DialogDestroyWithParent] 
                      MessageQuestion 
                      ButtonsYesNo 
                      "Do you want to close this window ?"
    set dialog [windowTitle := "About to close"]
    result <- dialogRun dialog
    widgetDestroy dialog
    if result == ResponseYes
       then return False
       else return True

--  This function is to be called when the window is destroyed.
--  The function has the responsibility to terminate the program
--  in an orderly way. It does so in exiting the event loop.
destroyEventHandler :: IO ()
destroyEventHandler =
  do mainQuit

-- main program: create and display the window
main :: IO ()
main = do
    initGUI
    --  all needed widgets are created
    window <- windowNew
    --  the properties of the main window are set
    set window [windowDefaultWidth   := 250,    --  initial window size
                windowDefaultHeight  := 280,
                widgetWidthRequest   := 100,    --  minimal window size
                widgetHeightRequest  := 80,
                windowWindowPosition := WinPosCenter,
                windowTitle := "Example 3"]
    --  all needed callback functions are provided
    on window deleteEvent $ liftIO (deleteEventHandler window)
    on window objectDestroy destroyEventHandler
    --  all widgets are made visible
    widgetShow window
    --  the event processing is started
    mainGUI

It is possible to write the event handler for the deleteEvent in a slightly different manner:

deleteEventHandler :: Window ->  IO Bool
deleteEventHandler transientParentWindow =
    do
    dialog <- messageDialogNew (Just transientParentWindow)
                      [DialogDestroyWithParent] 
                      MessageQuestion 
                      ButtonsYesNo 
                      "Do you want to close this window ?"
    set dialog [windowTitle := "About to close"]
    result <- dialogRun dialog
    widgetDestroy dialog
    let answer = result == ResponseNo
    return answer

Second Solution

import "gtk3" Graphics.UI.Gtk
import "gtk3" Graphics.UI.Gtk.Gdk.Events
import Control.Monad.IO.Class      -- for liftIO


--  This function handles the delete event. The delete event is
--  vetoable; the event handler is required to return a logical
--  value to indicate whether the event handling should be continued
--  or aborted.
--  Possible result values of this funtion:
--    True  :  do not continue event handling. This will keep
--             the window.
--    False :  continue event handling. This will close and
--             destroy the window.
--  This handler displays a confirmer to decide how to proceed.
--
deleteEventHandler :: Window ->  EventM EAny Bool
deleteEventHandler transientParentWindow =
  liftIO $
    do
    dialog <- messageDialogNew (Just transientParentWindow)
                      [DialogDestroyWithParent] 
                      MessageQuestion
                      ButtonsYesNo 
                      "Do you want to close this window ?"
    set dialog [windowTitle := "About to close"]
    result <- dialogRun dialog
    widgetDestroy dialog
    if result == ResponseYes
       then return False --  continue event handling, close and destroy the window
       else return True  --  event handling is now complete, do not continue


--  This function is to be called when the window is destroyed.
--  The function has the responsibility to terminate the program
--  in an orderly way. It does so in exiting the event loop.
destroyEventHandler :: IO ()
destroyEventHandler =
  do mainQuit

-- main program: create and display the window
main :: IO ()
main = do
    initGUI
    --  all needed widgets are created
    window <- windowNew
    --  the properties of the main window are set
    set window [windowDefaultWidth   := 250,
                windowDefaultHeight  := 280,
                widgetWidthRequest   := 100,
                widgetHeightRequest  := 80,
                windowWindowPosition := WinPosCenterAlways,
                windowTitle := "Example 3"]
    --  all needed callback functions are provided
    on window deleteEvent (deleteEventHandler window)
    on window objectDestroy  destroyEventHandler
    --  all widgets are made visible
    widgetShow window
    --  the event processing is started
    mainGUI

previous page Table of Section Contents next page