present_screen.c revision eee80088
135c4bbdfSmrg/*
235c4bbdfSmrg * Copyright © 2013 Keith Packard
335c4bbdfSmrg *
435c4bbdfSmrg * Permission to use, copy, modify, distribute, and sell this software and its
535c4bbdfSmrg * documentation for any purpose is hereby granted without fee, provided that
635c4bbdfSmrg * the above copyright notice appear in all copies and that both that copyright
735c4bbdfSmrg * notice and this permission notice appear in supporting documentation, and
835c4bbdfSmrg * that the name of the copyright holders not be used in advertising or
935c4bbdfSmrg * publicity pertaining to distribution of the software without specific,
1035c4bbdfSmrg * written prior permission.  The copyright holders make no representations
1135c4bbdfSmrg * about the suitability of this software for any purpose.  It is provided "as
1235c4bbdfSmrg * is" without express or implied warranty.
1335c4bbdfSmrg *
1435c4bbdfSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1535c4bbdfSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1635c4bbdfSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1735c4bbdfSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1835c4bbdfSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1935c4bbdfSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
2035c4bbdfSmrg * OF THIS SOFTWARE.
2135c4bbdfSmrg */
2235c4bbdfSmrg
2335c4bbdfSmrg#include "present_priv.h"
2435c4bbdfSmrg
2535c4bbdfSmrgint present_request;
2635c4bbdfSmrgDevPrivateKeyRec present_screen_private_key;
2735c4bbdfSmrgDevPrivateKeyRec present_window_private_key;
2835c4bbdfSmrg
2935c4bbdfSmrg/*
3035c4bbdfSmrg * Get a pointer to a present window private, creating if necessary
3135c4bbdfSmrg */
3235c4bbdfSmrgpresent_window_priv_ptr
3335c4bbdfSmrgpresent_get_window_priv(WindowPtr window, Bool create)
3435c4bbdfSmrg{
3535c4bbdfSmrg    present_window_priv_ptr window_priv = present_window_priv(window);
3635c4bbdfSmrg
3735c4bbdfSmrg    if (!create || window_priv != NULL)
3835c4bbdfSmrg        return window_priv;
3935c4bbdfSmrg    window_priv = calloc (1, sizeof (present_window_priv_rec));
4035c4bbdfSmrg    if (!window_priv)
4135c4bbdfSmrg        return NULL;
4235c4bbdfSmrg    xorg_list_init(&window_priv->vblank);
4335c4bbdfSmrg    xorg_list_init(&window_priv->notifies);
441b5d61b8Smrg
451b5d61b8Smrg    window_priv->window = window;
4635c4bbdfSmrg    window_priv->crtc = PresentCrtcNeverSet;
4735c4bbdfSmrg    dixSetPrivate(&window->devPrivates, &present_window_private_key, window_priv);
4835c4bbdfSmrg    return window_priv;
4935c4bbdfSmrg}
5035c4bbdfSmrg
5135c4bbdfSmrg/*
5235c4bbdfSmrg * Hook the close screen function to clean up our screen private
5335c4bbdfSmrg */
5435c4bbdfSmrgstatic Bool
5535c4bbdfSmrgpresent_close_screen(ScreenPtr screen)
5635c4bbdfSmrg{
5735c4bbdfSmrg    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
5835c4bbdfSmrg
59ed6184dfSmrg    if (screen_priv->flip_destroy)
60ed6184dfSmrg        screen_priv->flip_destroy(screen);
6135c4bbdfSmrg
6235c4bbdfSmrg    unwrap(screen_priv, screen, CloseScreen);
6335c4bbdfSmrg    (*screen->CloseScreen) (screen);
6435c4bbdfSmrg    free(screen_priv);
6535c4bbdfSmrg    return TRUE;
6635c4bbdfSmrg}
6735c4bbdfSmrg
6835c4bbdfSmrg/*
6935c4bbdfSmrg * Free any queued presentations for this window
7035c4bbdfSmrg */
7135c4bbdfSmrgstatic void
7235c4bbdfSmrgpresent_free_window_vblank(WindowPtr window)
7335c4bbdfSmrg{
741b5d61b8Smrg    ScreenPtr                   screen = window->drawable.pScreen;
751b5d61b8Smrg    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
7635c4bbdfSmrg    present_window_priv_ptr     window_priv = present_window_priv(window);
7735c4bbdfSmrg    present_vblank_ptr          vblank, tmp;
7835c4bbdfSmrg
7935c4bbdfSmrg    xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->vblank, window_list) {
801b5d61b8Smrg        screen_priv->abort_vblank(window->drawable.pScreen, window, vblank->crtc, vblank->event_id, vblank->target_msc);
8135c4bbdfSmrg        present_vblank_destroy(vblank);
8235c4bbdfSmrg    }
8335c4bbdfSmrg}
8435c4bbdfSmrg
8535c4bbdfSmrg/*
8635c4bbdfSmrg * Hook the close window function to clean up our window private
8735c4bbdfSmrg */
8835c4bbdfSmrgstatic Bool
8935c4bbdfSmrgpresent_destroy_window(WindowPtr window)
9035c4bbdfSmrg{
9135c4bbdfSmrg    Bool ret;
9235c4bbdfSmrg    ScreenPtr screen = window->drawable.pScreen;
9335c4bbdfSmrg    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
9435c4bbdfSmrg    present_window_priv_ptr window_priv = present_window_priv(window);
9535c4bbdfSmrg
96eee80088Smrg    present_send_config_notify(window,
97eee80088Smrg                               window->drawable.x,
98eee80088Smrg                               window->drawable.y,
99eee80088Smrg                               window->drawable.width,
100eee80088Smrg                               window->drawable.height,
101eee80088Smrg                               window->borderWidth,
102eee80088Smrg                               window->nextSib,
103eee80088Smrg                               PresentWindowDestroyed);
104eee80088Smrg
10535c4bbdfSmrg    if (window_priv) {
10635c4bbdfSmrg        present_clear_window_notifies(window);
10735c4bbdfSmrg        present_free_events(window);
10835c4bbdfSmrg        present_free_window_vblank(window);
1091b5d61b8Smrg
110ed6184dfSmrg        screen_priv->clear_window_flip(window);
1111b5d61b8Smrg
11235c4bbdfSmrg        free(window_priv);
11335c4bbdfSmrg    }
11435c4bbdfSmrg    unwrap(screen_priv, screen, DestroyWindow);
11535c4bbdfSmrg    if (screen->DestroyWindow)
11635c4bbdfSmrg        ret = screen->DestroyWindow (window);
11735c4bbdfSmrg    else
11835c4bbdfSmrg        ret = TRUE;
11935c4bbdfSmrg    wrap(screen_priv, screen, DestroyWindow, present_destroy_window);
12035c4bbdfSmrg    return ret;
12135c4bbdfSmrg}
12235c4bbdfSmrg
12335c4bbdfSmrg/*
12435c4bbdfSmrg * Hook the config notify screen function to deliver present config notify events
12535c4bbdfSmrg */
12635c4bbdfSmrgstatic int
12735c4bbdfSmrgpresent_config_notify(WindowPtr window,
12835c4bbdfSmrg                   int x, int y, int w, int h, int bw,
12935c4bbdfSmrg                   WindowPtr sibling)
13035c4bbdfSmrg{
13135c4bbdfSmrg    int ret;
13235c4bbdfSmrg    ScreenPtr screen = window->drawable.pScreen;
13335c4bbdfSmrg    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
13435c4bbdfSmrg
135eee80088Smrg    present_send_config_notify(window, x, y, w, h, bw, sibling, 0);
13635c4bbdfSmrg
13735c4bbdfSmrg    unwrap(screen_priv, screen, ConfigNotify);
13835c4bbdfSmrg    if (screen->ConfigNotify)
13935c4bbdfSmrg        ret = screen->ConfigNotify (window, x, y, w, h, bw, sibling);
14035c4bbdfSmrg    else
14135c4bbdfSmrg        ret = 0;
14235c4bbdfSmrg    wrap(screen_priv, screen, ConfigNotify, present_config_notify);
14335c4bbdfSmrg    return ret;
14435c4bbdfSmrg}
14535c4bbdfSmrg
14635c4bbdfSmrg/*
14735c4bbdfSmrg * Hook the clip notify screen function to un-flip as necessary
14835c4bbdfSmrg */
14935c4bbdfSmrg
15035c4bbdfSmrgstatic void
15135c4bbdfSmrgpresent_clip_notify(WindowPtr window, int dx, int dy)
15235c4bbdfSmrg{
15335c4bbdfSmrg    ScreenPtr screen = window->drawable.pScreen;
15435c4bbdfSmrg    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
15535c4bbdfSmrg
1561b5d61b8Smrg    screen_priv->check_flip_window(window);
15735c4bbdfSmrg    unwrap(screen_priv, screen, ClipNotify)
15835c4bbdfSmrg    if (screen->ClipNotify)
15935c4bbdfSmrg        screen->ClipNotify (window, dx, dy);
16035c4bbdfSmrg    wrap(screen_priv, screen, ClipNotify, present_clip_notify);
16135c4bbdfSmrg}
16235c4bbdfSmrg
163ed6184dfSmrgBool
1641b5d61b8Smrgpresent_screen_register_priv_keys(void)
16535c4bbdfSmrg{
16635c4bbdfSmrg    if (!dixRegisterPrivateKey(&present_screen_private_key, PRIVATE_SCREEN, 0))
16735c4bbdfSmrg        return FALSE;
16835c4bbdfSmrg
16935c4bbdfSmrg    if (!dixRegisterPrivateKey(&present_window_private_key, PRIVATE_WINDOW, 0))
17035c4bbdfSmrg        return FALSE;
17135c4bbdfSmrg
1721b5d61b8Smrg    return TRUE;
1731b5d61b8Smrg}
1741b5d61b8Smrg
175ed6184dfSmrgpresent_screen_priv_ptr
1761b5d61b8Smrgpresent_screen_priv_init(ScreenPtr screen)
1771b5d61b8Smrg{
1781b5d61b8Smrg    present_screen_priv_ptr screen_priv;
1791b5d61b8Smrg
1801b5d61b8Smrg    screen_priv = calloc(1, sizeof (present_screen_priv_rec));
1811b5d61b8Smrg    if (!screen_priv)
1821b5d61b8Smrg        return NULL;
1831b5d61b8Smrg
1841b5d61b8Smrg    wrap(screen_priv, screen, CloseScreen, present_close_screen);
1851b5d61b8Smrg    wrap(screen_priv, screen, DestroyWindow, present_destroy_window);
1861b5d61b8Smrg    wrap(screen_priv, screen, ConfigNotify, present_config_notify);
1871b5d61b8Smrg    wrap(screen_priv, screen, ClipNotify, present_clip_notify);
1881b5d61b8Smrg
1891b5d61b8Smrg    dixSetPrivate(&screen->devPrivates, &present_screen_private_key, screen_priv);
1901b5d61b8Smrg
1911b5d61b8Smrg    return screen_priv;
1921b5d61b8Smrg}
1931b5d61b8Smrg
1941b5d61b8Smrg/*
1951b5d61b8Smrg * Initialize a screen for use with present in default screen flip mode (scmd)
1961b5d61b8Smrg */
1971b5d61b8Smrgint
1981b5d61b8Smrgpresent_screen_init(ScreenPtr screen, present_screen_info_ptr info)
1991b5d61b8Smrg{
2001b5d61b8Smrg    if (!present_screen_register_priv_keys())
2011b5d61b8Smrg        return FALSE;
2021b5d61b8Smrg
2031b5d61b8Smrg    if (!present_screen_priv(screen)) {
2041b5d61b8Smrg        present_screen_priv_ptr screen_priv = present_screen_priv_init(screen);
2051b5d61b8Smrg        if (!screen_priv)
2061b5d61b8Smrg            return FALSE;
2071b5d61b8Smrg
2081b5d61b8Smrg        screen_priv->info = info;
2091b5d61b8Smrg        present_scmd_init_mode_hooks(screen_priv);
21035c4bbdfSmrg
21135c4bbdfSmrg        present_fake_screen_init(screen);
21235c4bbdfSmrg    }
21335c4bbdfSmrg
21435c4bbdfSmrg    return TRUE;
21535c4bbdfSmrg}
21635c4bbdfSmrg
21735c4bbdfSmrg/*
21835c4bbdfSmrg * Initialize the present extension
21935c4bbdfSmrg */
22035c4bbdfSmrgvoid
22135c4bbdfSmrgpresent_extension_init(void)
22235c4bbdfSmrg{
22335c4bbdfSmrg    ExtensionEntry *extension;
22435c4bbdfSmrg    int i;
22535c4bbdfSmrg
22635c4bbdfSmrg#ifdef PANORAMIX
22735c4bbdfSmrg    if (!noPanoramiXExtension)
22835c4bbdfSmrg        return;
22935c4bbdfSmrg#endif
23035c4bbdfSmrg
23135c4bbdfSmrg    extension = AddExtension(PRESENT_NAME, PresentNumberEvents, PresentNumberErrors,
23235c4bbdfSmrg                             proc_present_dispatch, sproc_present_dispatch,
23335c4bbdfSmrg                             NULL, StandardMinorOpcode);
23435c4bbdfSmrg    if (!extension)
23535c4bbdfSmrg        goto bail;
23635c4bbdfSmrg
23735c4bbdfSmrg    present_request = extension->base;
23835c4bbdfSmrg
23935c4bbdfSmrg    if (!present_init())
24035c4bbdfSmrg        goto bail;
24135c4bbdfSmrg
24235c4bbdfSmrg    if (!present_event_init())
24335c4bbdfSmrg        goto bail;
24435c4bbdfSmrg
24535c4bbdfSmrg    for (i = 0; i < screenInfo.numScreens; i++) {
24635c4bbdfSmrg        if (!present_screen_init(screenInfo.screens[i], NULL))
24735c4bbdfSmrg            goto bail;
24835c4bbdfSmrg    }
24935c4bbdfSmrg    return;
25035c4bbdfSmrg
25135c4bbdfSmrgbail:
25235c4bbdfSmrg    FatalError("Cannot initialize Present extension");
25335c4bbdfSmrg}
254