The only two things you know about "window management" by now are how to create a window (via createWindow
) and how to tell your program that you wish your window to be redisplayed (via postRedisplay
). As you may have guessed, there are a lot of other things that you can do with a window.
Before we start, it is important to keep two things in mind:
newtype Window = Window Int deriving (Eq,Ord)In other words, each window is associated to an identifier (
Int
). The range of allocated identifiers starts at one. The function createWindow
returns a IO Window
, so it is always possible to keep the identifier of a created window using:
w1 <- createWindow ...
keyboardFunc
, mouseFunc
, etc.) are associated to a specific window. These procedures are part of the window context (let's think of this as being the collection of all window properties). Each created window has a unique associated context. State changes to a window's associated context can be done immediately after the window is created.
For example, you must declare a keyboardFunc
twice if you pretend to read keyboard inputs in two different windows. Notice that the function declared can be the same for both windows. Watch carefully the following code:
main :: IO () main = do GLUT.init Nothing w1 <- createWindow "Hello World" (return ()) [ Single, GLUT.Rgb ] (Just (WindowPosition 100 100)) (Just (WindowSize 300 250)) keyboardFunc (Just keyboard) mouseFunc (Just mouse1) w2 <- createWindow "Hello World, again!" (return ()) [ Single, GLUT.Rgb ] (Just (WindowPosition 100 100)) (Just (WindowSize 300 250)) keyboardFunc (Just keyboard) mouseFunc (Just mouse2) myInit mainLoop
In this example, two windows were created. When a keyboard key is pressed and the first window (w1
) is active, the function keyboard
is going to deal with this input. The same happens when the active window is w2
. But when a mouse button is pressed, the function that is going to deal with this input will be mouse1
, if the active window is w1
, or mouse2
, if the active window is w2
. As you noticed, each window needs its own declaration of callback procedures, but the function indicated by them can be the same.
Once you understood this introduction, let's take a look on what you can do with windows:
Function:
createWindow :: String -> DisplayAction -> [DisplayMode] -> Maybe WindowPosition -> Maybe WindowSize -> IO Window
Usage and Comments: The current window is set to the newly created window. All you need to know about this function was already described in the Your First (and Simple) Program lesson. Check out it if you still have any doubts. Perhaps the only thing you don't know by now is the values of a DisplayMode
. They are:
- Rgb
- Rgba
- Index
- Single
- Double
- Accum
- Alpha
- Depth
- Stencil
- Multisample
- Stereo
- Luminance
Function: createSubWindow :: Window -> WindowPosition -> WindowSize -> IO Window
Usage: createSubWindow (parent window) (WindowPosition posX posY) (WindowSize width height)
Comments: All values of WindowPosition
and WindowSize
are related to pixels. The current window is set to the newly created subwindow. Subwindows can be nested arbitrarily deep.
Function: setWindow :: Window -> IO ()
Usage: setWindow (identifier of GLUT window to make the current window)
Comments: You can create a lot of windows first, then declare their callback procedures one by one, usging setWindow
to set the current window. Perhaps this will generate a "cleaner" code.
Function: getWindow :: IO Window
Usage: getWindow
Comments: If no windows exist or the previously current window was destroyed, getWindow
returns zero.
Function: destroyWindow :: Window -> IO ()
Usage: destroyWindow (identifier of GLUT window to destroy)
Comments: Any subwindows of destroyed windows are also destroyed. If the [identifier of GLUT window to destroy]
was the current window, the current window becomes invalid (getWindow
will return zero).
Function: postWindowRedisplay :: Window -> IO ()
Usage: postWindowRedisplay (identifier of GLUT window to redisplay)
Comments: The postRedisplay
function you already know forces the current window to be redisplayed.
Function: swapBuffers :: IO ()
Usage: swapBuffers
Comments: The contents of the back buffer of the layer in use of the current window to become the contents of the front buffer. The contents of the back buffer then become undefined. The update typically takes place during the vertical retrace of the monitor, rather than immediately after glutSwapBuffers is called. Subsequent HOpenGL commands can be issued immediately after calling swapBuffers
, but are not executed until the buffer exchange is completed. If the layer in use is not double buffered, swapBuffers
has no effect.
Function: positionWindow :: WindowPosition -> IO ()
Usage: positionWindow (WindowPosition posX posY)
Comments: For top-level windows, the posX
and posY
parameters are pixel offsets from the screen origin. For subwindows, the posX
and posY
parameters are pixel offsets from the window's parent window origin. This function disables the full screen status of a window if previously enabled.
Function: reshapeWindow :: WindowSize -> IO ()
Usage: reshapeWindow (WindowSize width height)
Comments: reshapeWindow
requests a change in the size of the current window. Whether a reshape actually takes effect and, if so, the reshaped dimensions are reported to the program by a reshape callback (reshapeFunc
). This function disables the full screen status of a window if previously enabled.
Function: fullScreen :: IO ()
Usage: fullScreen
Comments: fullScreen
requests that the current window be made full screen. The exact semantics of what full screen means may vary by window system. The intent is to make the window as large as possible and disable any window decorations or borders added the window system. The window width and height are not guaranteed to be the same as the screen width and height, but that is the intent of making a window full screen. Subsequent reshapeWindow
and positionWindow
requests on the window will disable the full screen status of the window. This funtion is defined to work only on top-level windows
Functions:
popWindow :: IO () pushWindow :: IO ()
Usage:
popWindow pushWindow
Comments: Both of these functions work on top-level windows and subwindows. The effect of pushing and popping windows does not take place immediately. Instead the push or pop is saved for execution upon return to the GLUT event loop. Subsequent push or pop requests on a window replace the previously saved request for that window. The effect of pushing and popping top-level windows is subject to the window system's policy for restacking windows.
Function: hideWindow :: IO ()
Usage: hideWindow
Comments: hideWindow
will hide the current window. The effect of showing, hiding, and iconifying windows does not take place immediately. Instead the requests are saved for execution upon return to the GLUT event loop. Subsequent show, hide, or iconification requests on a window replace the previously saved request for that window.
Function: iconifyWindow :: IO ()
Usage: iconifyWindow
Comments: iconifyWindow
will iconify a top-level window, but GLUT prohibits iconification of a subwindow. The effect of showing, hiding, and iconifying windows does not take place immediately. Instead the requests are saved for execution upon return to the GLUT event loop. Subsequent show, hide, or iconification requests on a window replace the previously saved request for that window.
Function: showWindow :: IO ()
Usage: showWindow
Comments: showWindow
will show the current window (though it may still not be visible if obscured by other shown windows). The effect of showing, hiding, and iconifying windows does not take place immediately. Instead the requests are saved for execution upon return to the GLUT event loop. Subsequent show, hide, or iconification requests on a window replace the previously saved request for that window.
Functions:
setWindowTitle :: String -> IO () setIconTitle :: String -> IO ()
Usage:
setWindowTitle (ASCII character string for the window name to be set for the window) setIconTitle (ASCII character string for the icon name to be set for the window)
Comments: These routines should be called only when the current window is a top-level window. Upon creation of a top-level window, the window and icon names are determined by the name parameter to createWindow
. Once created, setWindowTitle
and setIconTitle
can change the window and icon names respectively of top-level windows. Each call requests the window system change the title appropriately. Requests are not buffered or coalesced. The policy by which the window and icon name are displayed is window system dependent. Both function have the same effect under Windows 95/98/NT.
Function: setCursor :: Cursor -> IO ()
Usage: setCursor (name of cursor image to change to)
Comments: The options for the [name of cursor image to change to]
are:
CursorRightArrow
- arrow pointing up and to the right.
CursorLeftArrow
- arrow pointing up and to the left.
CursorInfo
- pointing hand.
CursorDestroy
- skull & cross bones.
CursorHelp
- question mark.
CursorCycle
- arrows rotating in a circle.
CursorSpray
- spray can.
CursorWait
- wrist watch.
CursorText
- insertion point cursor for text.
CursorCrosshair
- simple cross-hair.
CursorUpDown
- bi-directional pointing up & down.
CursorLeftRight
- bi-directional pointing left & right.
CursorTopSide
- arrow pointing to top side.
CursorBottomSide
- arrow pointing to bottom side.
CursorLeftSide
- arrow pointing to left side.
CursorRightSide
- arrow pointing to right side.
CursorTopLeftCorner
- arrow pointing to top-left corner.
CursorTopRightCorner
- arrow pointing to top-right corner.
CursorBottomRightCorner
- arrow pointing to bottom-left corner.
CursorBottomLeftCorner
- arrow pointing to bottom-right corner.
CursorInherit
- use parent's cursor.
CursorNone
- invisible cursor.
CursorFullCrosshair
- full-screen cross-hair cursor (if possible, otherwise CursorCrosshair
).
Comments (continuation): This function changes the cursor image of the current window. Each call requests the window system change the cursor appropriately. The cursor image when a window is created is CursorInherit
. The exact cursor images used are implementation dependent. The intent is for the image to convey the meaning of the cursor name. For a top-level window, CursorInherit
uses the default window system cursor.
Function: warpPointer :: WindowPosition -> IO ()
Usage: warpPointer (WindowPosition posX posY)
Comments: This function warps the window system's pointer to a new location relative to the origin of the current window. The new location will be offset posX
pixels on the X axis and posY
pixels on the Y axis. These parameters may be negative. The warp is done immediately. If the pointer would be warped outside the screen's frame buffer region, the location will be clamped to the nearest screen edge.
The function createWindow
is defined in module GLUT_Init. The other ones, in module GLUT_Window. Both of them are imported with you program already imports module GLUT.
I would like to thank The OpenGL Utility Toolkit (GLUT) Programming Interface API Version 3 Documentation, created by Mark J. Kilgard, Silicon Graphics, Inc. It was very important for the development of this lesson.