-- -*-haskell-*- -- Clutter Stage -- -- Author : Matthew Arsenault -- -- Created: 11 Sep 2009 -- -- Copyright (C) 2009 Matthew Arsenault -- -- 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 3 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. -- {-# LANGUAGE ForeignFunctionInterface #-} #include #include {# context lib="clutter" prefix="clutter" #} --FIXME: remove reference to freeing stuff -- | 'Stage' — Top level visual element to which actors are placed. module Graphics.UI.Clutter.Stage ( -- * Detail -- | ClutterStage is a top level 'window' on which child actors are placed and manipulated. -- -- Clutter creates a default stage upon initialization, which can be -- retrieved using 'stageGetDefault'. Clutter always -- provides the default stage, unless the backend is unable to create -- one. The stage returned by 'stageGetDefault' is -- guaranteed to always be the same. -- -- Backends might provide support for multiple stages. The support for -- this feature can be checked at run-time using the -- 'clutterFeatureAvailable' function and the -- CLUTTER_FEATURE_STAGE_MULTIPLE flag. If the backend used supports -- multiple stages, new 'Stage' instances can be created using -- 'stageNew'. These stages must be managed by the developer -- using 'actorDestroy', which will take care of destroying -- all the actors contained inside them. -- -- 'Stage' is a proxy actor, wrapping the backend-specific -- implementation of the windowing system. It is possible to subclass -- 'Stage', as long as every overridden virtual function chains up -- to the parent class corresponding function. -- * Class Hierarchy -- | -- @ -- | 'GObject' -- | +----'Actor' -- | +----'Group' -- | +----'Stage' -- @ -- * Types Stage, StageClass, Perspective(..), Fog(..), PickMode(..), -- * Constructors stageGetDefault, stageNew, -- * Methods, stageIsDefault, stageSetColor, stageGetColor, stageSetFullscreen, stageGetFullscreen, stageShowCursor, stageHideCursor, stageGetActorAtPos, stageEnsureCurrent, stageEnsureViewport, stageEnsureRedraw, stageQueueRedraw, --stageEvent, stageSetKeyFocus, stageGetKeyFocus, --stageKeyFocus, --stageReadPixels, stageSetThrottleMotionEvents, stageGetThrottleMotionEvents, stageSetPerspective, stageGetPerspective, stageSetTitle, stageGetTitle, stageSetUserResizable, stageGetUserResizable, stageSetUseFog, stageGetUseFog, stageSetFog, stageGetFog, -- * Attributes stageColor, stageCursorVisible, stageFog, stageFullscreenSet, stageOffscreen, stagePerspective, stageTitle, stageUseFog, stageUserResizable, -- * Signals --FIXME: Export conflicts with Text's signals and probably other signals onActivate, afterActivate, activate, onDeactivate, afterDeactivate, deactivate, onFullscreen, afterFullscreen, fullscreen, onUnfullscreen, afterUnfullscreen, unfullscreen ) where {# import Graphics.UI.Clutter.Types #} {# import Graphics.UI.Clutter.Actor #} {# import Graphics.UI.Clutter.Signals #} {# import Graphics.UI.Clutter.Utility #} import C2HS import Control.Monad (liftM) import System.Glib.Attributes import System.Glib.Properties import System.Glib.FFI (maybeNull) -- | Returns the main stage. The default 'Stage' is a singleton, so -- the stage will be created the first time this function is called -- (typically, inside 'clutterInit'); all the subsequent calls to -- 'stageGetDefault' will return the same instance. -- Clutter guarantess the existence of the default stage. {# fun unsafe stage_get_default as ^ { } -> `Stage' newStage* #} -- | Creates a new, non-default stage. A non-default stage is a new -- top-level actor which can be used as another container. It works -- exactly like the default stage, but while 'stageGetDefault' will -- always return the same instance, you will have to keep any -- 'Stage' returned by 'stageNew'. -- -- The ability to support multiple stages depends on the current -- backend. Use 'clutterFeatureAvailable' and -- CLUTTER_FEATURE_STAGE_MULTIPLE to check at runtime whether a -- backend supports multiple stages. -- -- [@Returns@] @Just@ a new stage, or @Nothing@ if the default -- backend does not support multiple stages. Use 'actorDestroy' to -- programmatically close the returned stage. -- {# fun unsafe stage_new as ^ { } -> `Maybe Stage' maybeNewStage* #} -- | Checks if stage is the default stage, or an instance created using -- 'stageNew' but internally using the same implementation. -- {# fun unsafe stage_is_default as ^ `(StageClass stage)' => { withStageClass* `stage' } -> `Bool' #} -- | Sets the stage color. {# fun unsafe stage_set_color as ^ `(StageClass stage)' => { withStageClass* `stage', withColor* `Color' } -> `()' #} -- | Retrieves the stage color. {# fun unsafe stage_get_color as ^ `(StageClass stage)' => { withStageClass* `stage', alloca- `Color' peek*} -> `()' #} -- | Asks to place the stage window in the fullscreen or unfullscreen -- states. -- -- ( Note that you shouldn't assume the window is definitely full screen -- afterward, because other entities (e.g. the user or window manager) -- could unfullscreen it again, and not all window managers honor -- requests to fullscreen windows. -- -- If you want to receive notification of the fullscreen state you should -- either use the "fullscreen" and "unfullscreen" signals, or use the -- notify signal for the "fullscreen-set" property {# fun unsafe stage_set_fullscreen as ^ `(StageClass stage)' => { withStageClass* `stage', `Bool'} -> `()' #} -- | Retrieves whether the stage is full screen or not {# fun unsafe stage_get_fullscreen as ^ `(StageClass stage)' => { withStageClass* `stage' } -> `Bool' #} -- | Shows the cursor on the stage window {# fun unsafe stage_show_cursor as ^ `(StageClass stage)' => { withStageClass* `stage' } -> `()' #} -- | Makes the cursor invisible on the stage window {# fun unsafe stage_hide_cursor as ^ `(StageClass stage)' => { withStageClass* `stage' } -> `()' #} --CHECKME: Should I even include non-application functions? -- | Checks the scene at the coordinates x and y and returns a pointer to the 'Actor' at those coordinates. -- -- By using pick_mode it is possible to control which actors will be painted and thus available. {# fun unsafe stage_get_actor_at_pos as ^ `(StageClass stage)' => { withStageClass* `stage', cFromEnum `PickMode', `Int', `Int'} -> `Actor' newActor* #} -- | This function essentially makes sure the right GL context is -- current for the passed stage. It is not intended to be used by -- applications. {# fun unsafe stage_ensure_current as ^ `(StageClass stage)' => { withStageClass* `stage' } -> `()' #} -- | Ensures that the GL viewport is updated with the current stage -- window size. -- -- This function will queue a redraw of stage. -- -- This function should not be called by applications; it is used when -- embedding a ClutterStage into a toolkit with another windowing -- system, like GTK+. {# fun unsafe stage_ensure_viewport as ^ `(StageClass stage)' => { withStageClass* `stage' } -> `()' #} -- | Ensures that stage is redrawn -- -- This function should not be called by applications: it is used when -- embedding a 'Stage' into a toolkit with another windowing -- system, like GTK+. {# fun unsafe stage_ensure_redraw as ^ `(StageClass stage)' => { withStageClass* `stage' } -> `()' #} -- | Queues a redraw for the passed stage. -- -- Note -- -- Applications should call 'actorQueueRedraw' and not this function. -- Note -- -- This function is just a wrapper for 'actorQueueRedraw' and should probably go away. {# fun unsafe stage_queue_redraw as ^ `(StageClass stage)' => { withStageClass* `stage' } -> `()' #} --CHECKME this might fall under the category of low level event stuff we're not dealing with --{# fun unsafe stage_event as ^ `(StageClass stage)' => { withStageClass* `stage', withEvent* `Event' } -> `Bool' #} -- | Sets the key focus on actor. An actor with key focus will receive -- all the key events. If actor is @Nothing@, the stage will receive -- focus. -- -- [@stage@] the 'Stage' -- -- [@actor@] @Just@ the actor to set key focus to, or @Nothing@ -- -- * Since 0.6 -- {# fun unsafe stage_set_key_focus as ^ `(StageClass stage, ActorClass actor)' => { withStageClass* `stage', withMaybeActorClass* `Maybe actor' } -> `()' #} -- | Retrieves the actor that is currently under key focus. -- -- [@stage@] the 'Stage' -- -- [@Returns@] the actor with key focus, or the stage. transfer none. -- -- * Since 0.6 -- {# fun unsafe stage_get_key_focus as ^ `(StageClass stage)' => { withStageClass* `stage' } -> `Actor' newActor* #} --TODO: Same problem as other places, setting and getting ActorClass is unhappy --stageKeyFocus :: (StageClass stage, ActorClass actor) => Attr stage actor --stageKeyFocus = newAttr stageGetKeyFocus stageSetKeyFocus --TODO: all those types, namely guchar* out = what? --Returns some kind of image buffer, what do I do with it? --{# fun unsafe stage_read_pixels as ^ `(StageClass stage)' => { withStageClass* `stage', `Int', `Int', `Int', `Int' } -> `Ptr ()' #} --Why is this scattered around in many places in gtk2hs? foreign import ccall unsafe "&g_free" finalizerGFree :: FinalizerPtr a stageReadPixels :: (StageClass stage) => stage -> Int -> Int -> Int -> Int -> IO (Maybe (RGBData Int Word8)) stageReadPixels stage x y w h = let cx = cIntConv x cy = cIntConv y cw = cIntConv w ch = cIntConv h in withStageClass stage $ \stgPtr -> do sizeW <- if w == -1 then liftM floor (actorGetWidth stage) else return w sizeH <- if h == -1 then liftM floor (actorGetHeight stage) else return h let size = sizeW * sizeH * 4 ptr <- {# call unsafe stage_read_pixels #} stgPtr cx cy cw ch if ptr == nullPtr then return Prelude.Nothing else newForeignPtr finalizerGFree ptr >>= \fptr -> return $ Just (mkRGBData (castForeignPtr fptr) True size) -- | Sets whether motion events received between redraws should be -- throttled or not. If motion events are throttled, those events -- received by the windowing system between redraws will be compressed -- so that only the last event will be propagated to the stage and its -- actors. This function should only be used if you want to have all -- the motion events delivered to your application code. {# fun unsafe stage_set_throttle_motion_events as ^ `(StageClass stage)' => { withStageClass* `stage', `Bool' } -> `()' #} -- | Retrieves the value set with 'stageSetThrottleMotionEvents' {# fun unsafe stage_get_throttle_motion_events as ^ `(StageClass stage)' => { withStageClass* `stage' } -> `Bool' #} -- | Retrieves the stage perspective. {# fun unsafe stage_get_perspective as ^ `(StageClass stage)' => { withStageClass* `stage', alloca- `Perspective' peek* } -> `()' #} -- | Sets the stage perspective. {# fun unsafe stage_set_perspective as ^ `(StageClass stage)' => { withStageClass* `stage', withPerspective* `Perspective'} -> `()' #} --TODO: Unicode??? -- | Sets the stage title. {# fun unsafe stage_set_title as ^ `(StageClass stage)' => { withStageClass* `stage', withMaybeString* `Maybe String' } -> `()' #} -- | Gets the stage title. {# fun unsafe stage_get_title as ^ `(StageClass stage)' => { withStageClass* `stage' } -> `Maybe String' maybeString* #} -- | Sets if the stage is resizable by user interaction (e.g. via window manager controls) {# fun unsafe stage_set_user_resizable as ^ `(StageClass stage)' => { withStageClass* `stage', `Bool' } -> `()' #} -- | Retrieves the value set with 'stageSetUserResizable'. {# fun unsafe stage_get_user_resizable as ^ `(StageClass stage)' => { withStageClass* `stage' } -> `Bool' #} -- | Sets whether the depth cueing effect on the stage should be enabled or not. -- -- Depth cueing is a 3D effect that makes actors farther away from -- the viewing point less opaque, by fading them with the stage -- color. -- -- The parameters of the GL fog used can be changed using the 'stageSetFog' function. {# fun unsafe stage_set_use_fog as ^ `(StageClass stage)' => { withStageClass* `stage', `Bool' } -> `()' #} -- | Gets whether the depth cueing effect is enabled on stage. {# fun unsafe stage_get_use_fog as ^ `(StageClass stage)' => { withStageClass* `stage' } -> `Bool' #} -- | Sets the fog (also known as "depth cueing") settings for the stage. -- -- A 'Stage' will only use a linear fog progression, which depends -- solely on the distance from the viewer. The cogl_set_fog() function in -- COGL exposes more of the underlying implementation, and allows -- changing the for progression function. It can be directly used by -- disabling the "use-fog" property and connecting a signal handler to -- the "paint" signal on the stage, like: -- TODO: The equivalent example -- -- Note: The fogging functions only work correctly when the visible -- actors use unmultiplied alpha colors. By default Cogl will premultiply -- textures and cogl_set_source_color will premultiply colors, so unless -- you explicitly load your textures requesting an unmultiplied -- internal_format and use cogl_material_set_color you can only use -- fogging with fully opaque actors. -- -- We can look to improve this in the future when we can depend on -- fragment shaders. {# fun unsafe stage_set_fog as ^ `(StageClass stage)' => { withStageClass* `stage', withFog* `Fog' } -> `()' #} -- | Retrieves the current depth cueing settings from the stage. {# fun unsafe stage_get_fog as ^ `(StageClass stage)' => { withStageClass* `stage', alloca- `Fog' peek* } -> `()' #} -- Attributes -- | The color of the main stage. stageColor :: (StageClass stage) => Attr stage Color stageColor = newNamedAttr "color" stageGetColor stageSetColor -- | Whether the mouse pointer should be visible -- -- Default value: @True@ -- stageCursorVisible :: (StageClass stage) => Attr stage Bool stageCursorVisible = newAttrFromBoolProperty "cursor-visible" -- | Whether the main stage is fullscreen. -- -- Default value: @False@ -- stageFullscreenSet :: (StageClass stage) => ReadAttr stage Bool stageFullscreenSet = readAttrFromBoolProperty "fullscreen-set" -- | Whether the stage should be rendered in an offscreen buffer. -- -- * Warning -- -- Not every backend supports redirecting the stage to an offscreen -- buffer. This property might not work and it might be deprecated at -- any later date. -- -- Default value: @False@ -- stageOffscreen :: (StageClass stage) => Attr stage Bool stageOffscreen = newAttrFromBoolProperty "offscreen" -- | The parameters used for the perspective projection from 3D -- coordinates to 2D -- -- * Since 0.8.2 -- stagePerspective :: (StageClass stage) => Attr stage Perspective stagePerspective = newNamedAttr "perspective" stageGetPerspective stageSetPerspective -- | The stage's title - usually displayed in stage windows title -- decorations. -- -- Default value: @Nothing@ -- -- * Since 0.4 -- stageTitle :: (StageClass stage) => Attr stage (Maybe String) stageTitle = newNamedAttr "title" stageGetTitle stageSetTitle -- | Whether the stage is resizable via user interaction. -- -- Default value: @False@ -- -- * Since 0.4 -- stageUserResizable :: (StageClass stage) => Attr stage Bool stageUserResizable = newNamedAttr "user-resizable" stageGetUserResizable stageSetUserResizable -- | Whether the stage should use a linear GL "fog" in creating the -- depth-cueing effect, to enhance the perception of depth by fading -- actors farther from the viewpoint. -- -- Default value: @False@ -- -- * Since 0.6 -- stageUseFog :: (StageClass stage) => Attr stage Bool stageUseFog = newNamedAttr "use-fog" stageGetUseFog stageSetUseFog -- | The settings for the GL "fog", used only if "use-fog" is set to -- @True@ -- -- * Since 1.0 -- stageFog :: (StageClass stage) => Attr stage Fog stageFog = newNamedAttr "fog" stageGetFog stageSetFog -- Signals --See note in Types of Activatable -- | The 'activate' signal is emitted when the stage receives key focus from the underlying window system. instance Activatable Stage where onActivate = connect_NONE__NONE "activate" False afterActivate = connect_NONE__NONE "activate" True activate = Signal (connect_NONE__NONE "activate") onDeactivate, afterDeactivate :: (StageClass stage) => stage -> IO () -> IO (ConnectId stage) onDeactivate = connect_NONE__NONE "deactivate" False afterDeactivate = connect_NONE__NONE "deactivate" True -- | The 'deactivate' signal is emitted when the stage loses key focus -- from the underlying window system. deactivate :: (StageClass stage) => Signal stage (IO ()) deactivate = Signal (connect_NONE__NONE "deactivate") onFullscreen, afterFullscreen :: (StageClass stage) => stage -> IO () -> IO (ConnectId stage) onFullscreen = connect_NONE__NONE "fullscreen" False afterFullscreen = connect_NONE__NONE "fullscreen" True -- | The 'fullscreen' signal is emitted when the stage is made fullscreen. fullscreen :: (StageClass stage) => Signal stage (IO ()) fullscreen = Signal (connect_NONE__NONE "fullscreen") onUnfullscreen, afterUnfullscreen :: (StageClass stage) => stage -> IO () -> IO (ConnectId stage) onUnfullscreen = connect_NONE__NONE "unfullscreen" False afterUnfullscreen = connect_NONE__NONE "unfullscreen" True -- | The 'unfullscreen' signal is emitted when the stage leaves a fullscreen state. unfullscreen :: (StageClass stage) => Signal stage (IO ()) unfullscreen = Signal (connect_NONE__NONE "unfullscreen")