Skip to content
Commits on Source (16)
......@@ -313,8 +313,11 @@ xwl_output_remove_emulated_mode_for_client(struct xwl_output *xwl_output,
struct xwl_emulated_mode *emulated_mode;
emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, client);
if (emulated_mode)
if (emulated_mode) {
DebugF("XWAYLAND: xwl_output_remove_emulated_mode: %dx%d\n",
emulated_mode->width, emulated_mode->height);
memset(emulated_mode, 0, sizeof(*emulated_mode));
}
}
/* From hw/xfree86/common/xf86DefModeSet.c with some obscure modes dropped */
......@@ -469,9 +472,6 @@ static void
xwl_output_set_randr_emu_prop(WindowPtr window,
struct xwl_output_randr_emu_prop *prop)
{
if (!xwl_window_is_toplevel(window))
return;
if (prop->rect_count) {
dixChangeWindowProperty(serverClient, window, prop->atom,
XA_CARDINAL, 32, PropModeReplace,
......@@ -484,7 +484,8 @@ xwl_output_set_randr_emu_prop(WindowPtr window,
static void
xwl_output_set_randr_emu_prop_callback(void *resource, XID id, void *user_data)
{
xwl_output_set_randr_emu_prop(resource, user_data);
if (xwl_window_is_toplevel(resource))
xwl_output_set_randr_emu_prop(resource, user_data);
}
static void
......@@ -515,7 +516,8 @@ xwl_output_set_emulated_mode(struct xwl_output *xwl_output, ClientPtr client,
from_vidmode ? "vidmode" : "randr",
mode->mode.width, mode->mode.height);
if (mode->mode.width == xwl_output->width && mode->mode.height == xwl_output->height)
/* modes[0] is the actual (not-emulated) output mode */
if (mode == xwl_output->randr_output->modes[0])
xwl_output_remove_emulated_mode_for_client(xwl_output, client);
else
xwl_output_add_emulated_mode_for_client(xwl_output, client, mode, from_vidmode);
......
......@@ -638,9 +638,15 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
xwl_screen->CloseScreen = pScreen->CloseScreen;
pScreen->CloseScreen = xwl_close_screen;
xwl_screen->ChangeWindowAttributes = pScreen->ChangeWindowAttributes;
pScreen->ChangeWindowAttributes = xwl_change_window_attributes;
xwl_screen->ResizeWindow = pScreen->ResizeWindow;
pScreen->ResizeWindow = xwl_resize_window;
xwl_screen->MoveWindow = pScreen->MoveWindow;
pScreen->MoveWindow = xwl_move_window;
if (xwl_screen->rootless) {
xwl_screen->SetWindowPixmap = pScreen->SetWindowPixmap;
pScreen->SetWindowPixmap = xwl_window_set_window_pixmap;
......
......@@ -48,6 +48,7 @@ struct xwl_screen {
int height;
int depth;
ScreenPtr screen;
int wm_client_id;
int expecting_event;
enum RootClipMode root_clip_mode;
......@@ -62,7 +63,9 @@ struct xwl_screen {
DestroyWindowProcPtr DestroyWindow;
XYToWindowProcPtr XYToWindow;
SetWindowPixmapProcPtr SetWindowPixmap;
ChangeWindowAttributesProcPtr ChangeWindowAttributes;
ResizeWindowProcPtr ResizeWindow;
MoveWindowProcPtr MoveWindow;
struct xorg_list output_list;
struct xorg_list seat_list;
......
......@@ -217,17 +217,13 @@ xwl_window_enable_viewport(struct xwl_window *xwl_window,
struct xwl_output *xwl_output,
struct xwl_emulated_mode *emulated_mode)
{
/* If necessary disable old viewport to apply new settings */
if (xwl_window_has_viewport_enabled(xwl_window))
xwl_window_disable_viewport(xwl_window);
DebugF("XWAYLAND: enabling viewport %dx%d -> %dx%d\n",
emulated_mode->width, emulated_mode->height,
xwl_output->width, xwl_output->height);
xwl_window->viewport =
wp_viewporter_get_viewport(xwl_window->xwl_screen->viewporter,
xwl_window->surface);
if (!xwl_window_has_viewport_enabled(xwl_window)) {
DebugF("XWAYLAND: enabling viewport %dx%d -> %dx%d\n",
emulated_mode->width, emulated_mode->height,
xwl_output->width, xwl_output->height);
xwl_window->viewport = wp_viewporter_get_viewport(xwl_window->xwl_screen->viewporter,
xwl_window->surface);
}
wp_viewport_set_source(xwl_window->viewport,
wl_fixed_from_int(0),
......@@ -243,41 +239,31 @@ xwl_window_enable_viewport(struct xwl_window *xwl_window,
}
static Bool
xwl_screen_client_is_window_manager(struct xwl_screen *xwl_screen,
ClientPtr client)
window_is_wm_window(WindowPtr window)
{
WindowPtr root = xwl_screen->screen->root;
OtherClients *others;
for (others = wOtherClients(root); others; others = others->next) {
if (SameClient(others, client)) {
if (others->mask & (SubstructureRedirectMask | ResizeRedirectMask))
return TRUE;
}
}
struct xwl_screen *xwl_screen = xwl_screen_get(window->drawable.pScreen);
return FALSE;
return CLIENT_ID(window->drawable.id) == xwl_screen->wm_client_id;
}
static ClientPtr
xwl_window_get_owner(struct xwl_window *xwl_window)
static WindowPtr
window_get_client_toplevel(WindowPtr window)
{
WindowPtr window = xwl_window->window;
ClientPtr client = wClient(window);
assert(window);
/* If the toplevel window is owned by the window-manager, then the
* actual client toplevel window has been reparented to a window-manager
* decoration window. In that case return the client of the
* first *and only* child of the toplevel (decoration) window.
* actual client toplevel window has been reparented to some window-manager
* decoration/wrapper windows. In that case recurse by checking the client
* of the first *and only* child of the decoration/wrapper window.
*/
if (xwl_screen_client_is_window_manager(xwl_window->xwl_screen, client)) {
if (window_is_wm_window(window)) {
if (window->firstChild && window->firstChild == window->lastChild)
return wClient(window->firstChild);
return window_get_client_toplevel(window->firstChild);
else
return NULL; /* Should never happen, skip resolution emulation */
}
return client;
return window;
}
static Bool
......@@ -289,14 +275,19 @@ xwl_window_should_enable_viewport(struct xwl_window *xwl_window,
struct xwl_emulated_mode *emulated_mode;
struct xwl_output *xwl_output;
ClientPtr owner;
WindowPtr window;
DrawablePtr drawable;
if (!xwl_screen_has_resolution_change_emulation(xwl_screen))
return FALSE;
owner = xwl_window_get_owner(xwl_window);
if (!owner)
window = window_get_client_toplevel(xwl_window->window);
if (!window)
return FALSE;
owner = wClient(window);
drawable = &window->drawable;
/* 1. Test if the window matches the emulated mode on one of the outputs
* This path gets hit by most games / libs (e.g. SDL, SFML, OGRE)
*/
......@@ -305,10 +296,10 @@ xwl_window_should_enable_viewport(struct xwl_window *xwl_window,
if (!emulated_mode)
continue;
if (xwl_window->x == xwl_output->x &&
xwl_window->y == xwl_output->y &&
xwl_window->width == emulated_mode->width &&
xwl_window->height == emulated_mode->height) {
if (drawable->x == xwl_output->x &&
drawable->y == xwl_output->y &&
drawable->width == emulated_mode->width &&
drawable->height == emulated_mode->height) {
*emulated_mode_ret = emulated_mode;
*xwl_output_ret = xwl_output;
......@@ -324,9 +315,9 @@ xwl_window_should_enable_viewport(struct xwl_window *xwl_window,
emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, owner);
if (xwl_output && xwl_window->window->overrideRedirect &&
emulated_mode && emulated_mode->from_vidmode &&
xwl_window->x == 0 && xwl_window->y == 0 &&
xwl_window->width == xwl_screen->width &&
xwl_window->height == xwl_screen->height) {
drawable->x == 0 && drawable->y == 0 &&
drawable->width == xwl_screen->width &&
drawable->height == xwl_screen->height) {
*emulated_mode_ret = emulated_mode;
*xwl_output_ret = xwl_output;
......@@ -356,17 +347,15 @@ xwl_window_check_resolution_change_emulation(struct xwl_window *xwl_window)
Bool
xwl_window_is_toplevel(WindowPtr window)
{
struct xwl_screen *xwl_screen = xwl_screen_get(window->drawable.pScreen);
if (xwl_screen_client_is_window_manager(xwl_screen, wClient(window)))
if (window_is_wm_window(window))
return FALSE;
/* CSD and override-redirect toplevel windows */
if (window_get_damage(window))
return TRUE;
/* Normal toplevel client windows, reparented to decoration window */
return (window->parent && window_get_damage(window->parent));
/* Normal toplevel client windows, reparented to a window-manager window */
return window->parent && window_is_wm_window(window->parent);
}
static void
......@@ -443,6 +432,7 @@ ensure_surface_for_window(WindowPtr window)
struct xwl_screen *xwl_screen;
struct xwl_window *xwl_window;
struct wl_region *region;
WindowPtr toplevel;
if (xwl_window_get(window))
return TRUE;
......@@ -464,8 +454,6 @@ ensure_surface_for_window(WindowPtr window)
xwl_window->xwl_screen = xwl_screen;
xwl_window->window = window;
xwl_window->width = window->drawable.width;
xwl_window->height = window->drawable.height;
xwl_window->surface = wl_compositor_create_surface(xwl_screen->compositor);
if (xwl_window->surface == NULL) {
ErrorF("wl_display_create_surface failed\n");
......@@ -517,6 +505,18 @@ ensure_surface_for_window(WindowPtr window)
xwl_window_init_allow_commits(xwl_window);
/* When a new window-manager window is realized, then the randr emulation
* props may have not been set on the managed client window yet.
*/
if (window_is_wm_window(window)) {
toplevel = window_get_client_toplevel(window);
if (toplevel)
xwl_output_set_window_randr_emu_props(xwl_screen, toplevel);
} else {
/* CSD or O-R toplevel window, check viewport on creation */
xwl_window_check_resolution_change_emulation(xwl_window);
}
return TRUE;
err_surf:
......@@ -561,8 +561,6 @@ xwl_realize_window(WindowPtr window)
return FALSE;
}
xwl_output_set_window_randr_emu_props(xwl_screen, window);
return ensure_surface_for_window(window);
}
......@@ -660,6 +658,30 @@ xwl_window_set_window_pixmap(WindowPtr window,
xwl_window_buffers_recycle(xwl_window);
}
Bool
xwl_change_window_attributes(WindowPtr window, unsigned long mask)
{
ScreenPtr screen = window->drawable.pScreen;
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
OtherClients *others;
Bool ret;
screen->ChangeWindowAttributes = xwl_screen->ChangeWindowAttributes;
ret = (*screen->ChangeWindowAttributes) (window, mask);
xwl_screen->ChangeWindowAttributes = screen->ChangeWindowAttributes;
screen->ChangeWindowAttributes = xwl_change_window_attributes;
if (window != screen->root || !(mask & CWEventMask))
return ret;
for (others = wOtherClients(window); others; others = others->next) {
if (others->mask & (SubstructureRedirectMask | ResizeRedirectMask))
xwl_screen->wm_client_id = CLIENT_ID(others->resource);
}
return ret;
}
void
xwl_resize_window(WindowPtr window,
int x, int y,
......@@ -671,20 +693,37 @@ xwl_resize_window(WindowPtr window,
struct xwl_window *xwl_window;
xwl_screen = xwl_screen_get(screen);
xwl_window = xwl_window_get(window);
xwl_window = xwl_window_from_window(window);
screen->ResizeWindow = xwl_screen->ResizeWindow;
(*screen->ResizeWindow) (window, x, y, width, height, sib);
xwl_screen->ResizeWindow = screen->ResizeWindow;
screen->ResizeWindow = xwl_resize_window;
if (xwl_window) {
xwl_window->x = x;
xwl_window->y = y;
xwl_window->width = width;
xwl_window->height = height;
if (xwl_window && (xwl_window_get(window) || xwl_window_is_toplevel(window)))
xwl_window_check_resolution_change_emulation(xwl_window);
}
void
xwl_move_window(WindowPtr window,
int x, int y,
WindowPtr next_sib,
VTKind kind)
{
ScreenPtr screen = window->drawable.pScreen;
struct xwl_screen *xwl_screen;
struct xwl_window *xwl_window;
xwl_screen = xwl_screen_get(screen);
xwl_window = xwl_window_from_window(window);
screen->MoveWindow = xwl_screen->MoveWindow;
(*screen->MoveWindow) (window, x, y, next_sib, kind);
xwl_screen->MoveWindow = screen->MoveWindow;
screen->MoveWindow = xwl_move_window;
if (xwl_window && (xwl_window_get(window) || xwl_window_is_toplevel(window)))
xwl_window_check_resolution_change_emulation(xwl_window);
}
}
static void
......
......@@ -33,6 +33,7 @@
#include <X11/X.h>
#include <dix.h>
#include <propertyst.h>
#include <validate.h>
#include "xwayland-types.h"
......@@ -40,7 +41,6 @@ struct xwl_window {
struct xwl_screen *xwl_screen;
struct wl_surface *surface;
struct wp_viewport *viewport;
int32_t x, y, width, height;
float scale_x, scale_y;
struct wl_shell_surface *shell_surface;
WindowPtr window;
......@@ -69,10 +69,15 @@ void xwl_window_check_resolution_change_emulation(struct xwl_window *xwl_window)
void xwl_window_set_window_pixmap(WindowPtr window, PixmapPtr pixmap);
Bool xwl_realize_window(WindowPtr window);
Bool xwl_unrealize_window(WindowPtr window);
Bool xwl_change_window_attributes(WindowPtr window, unsigned long mask);
void xwl_resize_window(WindowPtr window,
int x, int y,
unsigned int width, unsigned int height,
WindowPtr sib);
void xwl_move_window(WindowPtr window,
int x, int y,
WindowPtr next_sib,
VTKind kind);
Bool xwl_destroy_window(WindowPtr window);
void xwl_window_post_damage(struct xwl_window *xwl_window);
void xwl_window_create_frame_callback(struct xwl_window *xwl_window);
......
......@@ -27,17 +27,6 @@
#include "present_priv.h"
#include <gcstruct.h>
/*
* Returns:
* TRUE if the first MSC value is equal to or after the second one
* FALSE if the first MSC value is before the second one
*/
static Bool
msc_is_equal_or_after(uint64_t test, uint64_t reference)
{
return (int64_t)(test - reference) >= 0;
}
uint32_t
present_query_capabilities(RRCrtcPtr crtc)
{
......@@ -157,31 +146,73 @@ present_can_window_flip(WindowPtr window)
return screen_priv->can_window_flip(window);
}
void
present_adjust_timings(uint32_t options,
uint64_t *crtc_msc,
uint64_t *target_msc,
uint64_t
present_get_target_msc(uint64_t target_msc_arg,
uint64_t crtc_msc,
uint64_t divisor,
uint64_t remainder)
uint64_t remainder,
uint32_t options)
{
/* Adjust target_msc to match modulus
const Bool synced_flip = !(options & PresentOptionAsync);
uint64_t target_msc;
/* If the specified target-msc lies in the future, then this
* defines the target-msc according to Present protocol.
*/
if (msc_is_equal_or_after(*crtc_msc, *target_msc)) {
if (divisor != 0) {
*target_msc = *crtc_msc - (*crtc_msc % divisor) + remainder;
if (options & PresentOptionAsync) {
if (msc_is_after(*crtc_msc, *target_msc))
*target_msc += divisor;
} else {
if (msc_is_equal_or_after(*crtc_msc, *target_msc))
*target_msc += divisor;
}
} else {
*target_msc = *crtc_msc;
if (!(options & PresentOptionAsync))
(*target_msc)++;
}
if (msc_is_after(target_msc_arg, crtc_msc))
return target_msc_arg;
/* If no divisor is specified, the modulo is undefined
* and we do present instead asap.
*/
if (divisor == 0) {
target_msc = crtc_msc;
/* When no async presentation is forced, by default we sync the
* presentation with vblank. But in this case we can't target
* the current crtc-msc, which already has begun, but must aim
* for the upcoming one.
*/
if (synced_flip)
target_msc++;
return target_msc;
}
/* Calculate target-msc by the specified modulo parameters. According
* to Present protocol this is after the next field with:
*
* field-msc % divisor == remainder.
*
* The following formula calculates a target_msc solving above equation
* and with |target_msc - crtc_msc| < divisor.
*
* Example with crtc_msc = 10, divisor = 4 and remainder = 3, 2, 1, 0:
* 11 = 10 - 2 + 3 = 10 - (10 % 4) + 3,
* 10 = 10 - 2 + 2 = 10 - (10 % 4) + 2,
* 9 = 10 - 2 + 1 = 10 - (10 % 4) + 1,
* 8 = 10 - 2 + 0 = 10 - (10 % 4) + 0.
*/
target_msc = crtc_msc - (crtc_msc % divisor) + remainder;
/* Here we already found the correct field-msc. */
if (msc_is_after(target_msc, crtc_msc))
return target_msc;
/*
* Here either:
* a) target_msc == crtc_msc, i.e. crtc_msc actually solved
* above equation with crtc_msc % divisor == remainder.
*
* => This means we want to present at target_msc + divisor for a synced
* flip or directly now for an async flip.
*
* b) target_msc < crtc_msc with target_msc + divisor > crtc_msc.
*
* => This means in any case we want to present at target_msc + divisor.
*/
if (synced_flip || msc_is_after(crtc_msc, target_msc))
target_msc += divisor;
return target_msc;
}
int
......
......@@ -279,12 +279,12 @@ present_set_tree_pixmap(WindowPtr window,
PixmapPtr expected,
PixmapPtr pixmap);
void
present_adjust_timings(uint32_t options,
uint64_t *crtc_msc,
uint64_t *target_msc,
uint64_t
present_get_target_msc(uint64_t target_msc_arg,
uint64_t crtc_msc,
uint64_t divisor,
uint64_t remainder);
uint64_t remainder,
uint32_t options);
int
present_pixmap(WindowPtr window,
......
......@@ -222,32 +222,6 @@ present_queue_vblank(ScreenPtr screen,
return ret;
}
static uint64_t
present_window_to_crtc_msc(WindowPtr window, RRCrtcPtr crtc, uint64_t window_msc, uint64_t new_msc)
{
present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE);
if (crtc != window_priv->crtc) {
uint64_t old_ust, old_msc;
if (window_priv->crtc == PresentCrtcNeverSet) {
window_priv->msc_offset = 0;
} else {
/* The old CRTC may have been turned off, in which case
* we'll just use whatever previous MSC we'd seen from this CRTC
*/
if (present_get_ust_msc(window->drawable.pScreen, window_priv->crtc, &old_ust, &old_msc) != Success)
old_msc = window_priv->msc;
window_priv->msc_offset += new_msc - old_msc;
}
window_priv->crtc = crtc;
}
return window_msc + window_priv->msc_offset;
}
/*
* When the wait fence or previous flip is completed, it's time
* to re-try the request
......@@ -638,6 +612,30 @@ present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
present_execute_post(vblank, ust, crtc_msc);
}
static void
present_scmd_update_window_crtc(WindowPtr window, RRCrtcPtr crtc, uint64_t new_msc)
{
present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE);
uint64_t old_ust, old_msc;
/* Crtc unchanged, no offset. */
if (crtc == window_priv->crtc)
return;
/* No crtc earlier to offset against, just set the crtc. */
if (window_priv->crtc == PresentCrtcNeverSet) {
window_priv->crtc = crtc;
return;
}
/* Crtc may have been turned off, just use whatever previous MSC we'd seen from this CRTC. */
if (present_get_ust_msc(window->drawable.pScreen, window_priv->crtc, &old_ust, &old_msc) != Success)
old_msc = window_priv->msc;
window_priv->msc_offset += new_msc - old_msc;
window_priv->crtc = crtc;
}
static int
present_scmd_pixmap(WindowPtr window,
PixmapPtr pixmap,
......@@ -650,7 +648,7 @@ present_scmd_pixmap(WindowPtr window,
SyncFence *wait_fence,
SyncFence *idle_fence,
uint32_t options,
uint64_t window_msc,
uint64_t target_window_msc,
uint64_t divisor,
uint64_t remainder,
present_notify_ptr notifies,
......@@ -682,7 +680,7 @@ present_scmd_pixmap(WindowPtr window,
ret = present_get_ust_msc(screen, target_crtc, &ust, &crtc_msc);
target_msc = present_window_to_crtc_msc(window, target_crtc, window_msc, crtc_msc);
present_scmd_update_window_crtc(window, target_crtc, crtc_msc);
if (ret == Success) {
/* Stash the current MSC away in case we need it later
......@@ -690,11 +688,11 @@ present_scmd_pixmap(WindowPtr window,
window_priv->msc = crtc_msc;
}
present_adjust_timings(options,
&crtc_msc,
&target_msc,
divisor,
remainder);
target_msc = present_get_target_msc(target_window_msc + window_priv->msc_offset,
crtc_msc,
divisor,
remainder,
options);
/*
* Look for a matching presentation already on the list and
......
......@@ -519,25 +519,28 @@ present_wnmd_queue_vblank(ScreenPtr screen,
return (*screen_priv->wnmd_info->queue_vblank) (window, crtc, event_id, msc);
}
static uint64_t
present_wnmd_window_to_crtc_msc(WindowPtr window, RRCrtcPtr crtc, uint64_t window_msc, uint64_t new_msc)
static void
present_wnmd_update_window_crtc(WindowPtr window, RRCrtcPtr crtc, uint64_t new_msc)
{
present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE);
if (crtc != window_priv->crtc) {
if (window_priv->crtc == PresentCrtcNeverSet) {
window_priv->msc_offset = 0;
} else {
/* The old CRTC may have been turned off, in which case
* we'll just use whatever previous MSC we'd seen from this CRTC
*/
/* Crtc unchanged, no offset. */
if (crtc == window_priv->crtc)
return;
window_priv->msc_offset += new_msc - window_priv->msc;
}
/* No crtc earlier to offset against, just set the crtc. */
if (window_priv->crtc == PresentCrtcNeverSet) {
window_priv->msc_offset = 0;
window_priv->crtc = crtc;
return;
}
return window_msc + window_priv->msc_offset;
/* In window-mode the last correct msc-offset is always kept
* in window-priv struct because msc is saved per window and
* not per crtc as in screen-mode.
*/
window_priv->msc_offset += new_msc - window_priv->msc;
window_priv->crtc = crtc;
}
static int
......@@ -552,7 +555,7 @@ present_wnmd_pixmap(WindowPtr window,
SyncFence *wait_fence,
SyncFence *idle_fence,
uint32_t options,
uint64_t window_msc,
uint64_t target_window_msc,
uint64_t divisor,
uint64_t remainder,
present_notify_ptr notifies,
......@@ -574,7 +577,7 @@ present_wnmd_pixmap(WindowPtr window,
ret = present_wnmd_get_ust_msc(screen, window, &ust, &crtc_msc);
target_msc = present_wnmd_window_to_crtc_msc(window, target_crtc, window_msc, crtc_msc);
present_wnmd_update_window_crtc(window, target_crtc, crtc_msc);
if (ret == Success) {
/* Stash the current MSC away in case we need it later
......@@ -582,11 +585,11 @@ present_wnmd_pixmap(WindowPtr window,
window_priv->msc = crtc_msc;
}
present_adjust_timings(options,
&crtc_msc,
&target_msc,
divisor,
remainder);
target_msc = present_get_target_msc(target_window_msc + window_priv->msc_offset,
crtc_msc,
divisor,
remainder,
options);
/*
* Look for a matching presentation already on the list...
......