/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "applib/ui/property_animation.h"
#include "applib/ui/window.h"
//! @file kernel/services/compositor.h
//! This file manages what's currently shown on the screen of your Pebble!
//! There are two main things that are managed by the compositor...
//!
//!
The App Framebuffer
//! This is the framebuffer the app is currently drawing into. The compositor
//! handles animating between app framebuffers when the app changes and window
//! animations requested by the window stack. The compositor will also draw in
//! the status bar when the app is in fullscreen, and the app will adjust its
//! framebuffer's destination frame vertically. The framebuffer is simply
//! bitblt'ed into the appropriate position whenever compositor_flush is called.
//!
//! @see \ref compositor_get_child_entity
//! @see \ref compositor_set_entity_framebuffer
//! @see \ref compositor_transition
//! @see \ref window_stack_animation_schedule
//! @see \ref app_emit_render_ready_event
//!
//! Modal Window
//! A modal window is a Window that can be rendered on top of an app without
//! interrupting it. The modal window can only be supplied by the kernel, so
//! we can trust its contents. The modal window is animated up and down the
//! screen when its pushed and popped. Since the window doesn't have a framebuffer
//! of its own, we render it to the main framebuffer on top of everything else
//! whenever compositor_flush is called.
//!
//! Transition direction, from the current position to the next.
//! For example, Up is a transition to some item that is upwards of the current screen.
typedef enum {
CompositorTransitionDirectionUp,
CompositorTransitionDirectionDown,
CompositorTransitionDirectionLeft,
CompositorTransitionDirectionRight,
CompositorTransitionDirectionNone,
} CompositorTransitionDirection;
typedef void (*CompositorTransitionInitFunc)(Animation *animation);
// TODO: PBL-31460 Change compositor transitions to use AnimationProgress
// This would enable time-based bounce back transitions
typedef void (*CompositorTransitionUpdateFunc)(GContext *ctx, Animation *animation,
uint32_t distance_normalized);
typedef void (*CompositorTransitionTeardownFunc)(Animation *animation);
typedef struct CompositorTransition {
CompositorTransitionInitFunc init; //!< Mandatory initialization function
CompositorTransitionUpdateFunc update; //!< Mandatory update function
CompositorTransitionTeardownFunc teardown; //!< Optional teardown function
//! If false, modals are rendered after the update function, otherwise they are skipped
bool skip_modal_render_after_update;
} CompositorTransition;
typedef struct FrameBuffer FrameBuffer;
void compositor_init(void);
//! Kick off a transition using the given CompositorTransition implementation. If a transition is
//! already underway the transition will be immediately cancelled and this one will be scheduled
//! in its place.
//!
//! For modal windows the new app we're animating to should already be on top of the modal window
//! stack. For apps the new app we're animating to should always be running. For apps, the
//! animation won't begin until the app has already started rendering itself.
void compositor_transition(const CompositorTransition *impl);
//! Perform the compositor transition rendering steps for a given update function.
//! Normally you will not call this, as the assigned transition animation automatically runs this.
//! However, if an animation needs to be scheduled inside of the compositor transition animation,
//! the new animation will need to call this in order to properly render.
//! A good use-case for this is when the transition needs to use an animation_sequence.
//!
//! For an example of this being used, check out compositor_shutter_transitions.c
void compositor_transition_render(CompositorTransitionUpdateFunc func, Animation *animation,
const AnimationProgress distance_normalized);
//! Writes the app framebuffer to either the system framebuffer or display directly.
//! Calls compositor_render_modal if all modals are transparent as well.
void compositor_render_app(void);
//! Renders modals using the kernel graphics context
void compositor_render_modal(void);
//! The modal needs to redraw its buffer to the display.
void compositor_modal_render_ready(void);
//! The app needs to copy its framebuffer to the display.
void compositor_app_render_ready(void);
FrameBuffer* compositor_get_framebuffer(void);
GBitmap compositor_get_framebuffer_as_bitmap(void);
//! Gets the app framebuffer as a bitmap. The bounds of the bitmap will be set based on
//! app_manager_get_framebuffer_size() rather than the app's framebuffer size to protect against
//! malicious apps changing it.
GBitmap compositor_get_app_framebuffer_as_bitmap(void);
//! @return True if we're currently mid-animation between apps or modal windows
bool compositor_is_animating(void);
//! Sets the modal draw offset for transitions that redraw the modal
void compositor_set_modal_transition_offset(GPoint modal_offset);
//! Stops an existing transition in its tracks.
void compositor_transition_cancel(void);
//! Don't allow new frames to be pushed to the compositor from either the app or the modal.
void compositor_freeze(void);
//! Resuming allowing new frames to be pushed to the compositor, undoes the effects of
//! compositor_freeze.
void compositor_unfreeze(void);