forked from 12to11/12to11
Check in C and XML files for tests
* 12to11-test.xml: * buffer_release.c: * test.c: New files.
This commit is contained in:
parent
0a68122e52
commit
4e9a442856
3 changed files with 774 additions and 0 deletions
94
12to11-test.xml
Normal file
94
12to11-test.xml
Normal file
|
@ -0,0 +1,94 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="test">
|
||||
<copyright>
|
||||
Copyright (C) 2022 various contributors.
|
||||
|
||||
This file is part of 12to11.
|
||||
|
||||
12to11 is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation, either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
12to11 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 General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with 12to11. If not, see https://www.gnu.org/licenses/.
|
||||
</copyright>
|
||||
|
||||
<interface name="test_manager" version="1">
|
||||
<description summary="test interface">
|
||||
This protocol is used by the 12to11 protocol translator to
|
||||
support various tests. The test_manager global allows creating
|
||||
a surface whose bounds and contents can be inspected, and
|
||||
connecting to the X server used by the compositor.
|
||||
|
||||
Upon binding to the test_manager, a display_string event is sent
|
||||
containing the name of the X display.
|
||||
</description>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="role_present" value="1"
|
||||
summary="given wl_surface has/had another role"/>
|
||||
</enum>
|
||||
|
||||
<request name="get_test_surface">
|
||||
<description summary="obtain test surface role">
|
||||
Get a test_surface object for a particular surface. If a role
|
||||
was already attached to this surface, or a role of a different
|
||||
type was previously attached, a role_present error is issued.
|
||||
|
||||
The window is created immediately after get_test_surface is
|
||||
called. It is mapped once a commit request with a non-nil
|
||||
buffer is made.
|
||||
|
||||
Once the window associated with the test_surface object is
|
||||
mapped, a mapped event is sent.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="test_surface"/>
|
||||
<arg name="surface" type="object" interface="wl_surface"/>
|
||||
</request>
|
||||
|
||||
<event name="display_string">
|
||||
<description summary="X server name">
|
||||
The display_string event sends the name of the X display to
|
||||
clients. It is sent immediately after binding to the
|
||||
test_manager object.
|
||||
</description>
|
||||
<arg name="name" type="string"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="test_surface" version="1">
|
||||
<description summary="test surface">
|
||||
This role provides a test surface. Various buffers and
|
||||
subsurfaces can be attached, and the resulting display contents
|
||||
validated.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy role">
|
||||
This request destroys the test_surface role. Subsequently,
|
||||
get_test_surface can be called again with its surface.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<event name="mapped">
|
||||
<description summary="role initialized">
|
||||
The map event is sent once the window is mapped and its
|
||||
contents can be retrieved. The two arguments are the XID of
|
||||
the window and the name of the display it is on.
|
||||
|
||||
If the surface is mapped, then unmapped (by having a nil
|
||||
buffer attached) and then mapped again, without waiting for
|
||||
the first mapped event, the delivery of subsequent mapped
|
||||
events becomes undefined.
|
||||
</description>
|
||||
<arg name="xid" type="uint"/>
|
||||
<arg name="display_string" type="string"/>
|
||||
</event>
|
||||
</interface>
|
||||
</protocol>
|
146
buffer_release.c
Normal file
146
buffer_release.c
Normal file
|
@ -0,0 +1,146 @@
|
|||
/* Wayland compositor running on top of an X server.
|
||||
|
||||
Copyright (C) 2022 to various contributors.
|
||||
|
||||
This file is part of 12to11.
|
||||
|
||||
12to11 is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation, either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
12to11 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 General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "compositor.h"
|
||||
|
||||
/* Simple helper code for managing buffer release in surfaces. */
|
||||
|
||||
typedef struct _ReleaseLaterRecord ReleaseLaterRecord;
|
||||
|
||||
struct _ReleaseLaterRecord
|
||||
{
|
||||
/* A monotonically (overflow aside) increasing identifier. */
|
||||
uint64_t id;
|
||||
|
||||
/* The buffer that should be released upon receiving this
|
||||
message. */
|
||||
ExtBuffer *buffer;
|
||||
|
||||
/* The idle callback, if any. */
|
||||
IdleCallbackKey key;
|
||||
|
||||
/* The buffer release helper. */
|
||||
BufferReleaseHelper *helper;
|
||||
|
||||
/* The next and last records. */
|
||||
ReleaseLaterRecord *next, *last;
|
||||
};
|
||||
|
||||
struct _BufferReleaseHelper
|
||||
{
|
||||
/* Queue of buffers pending release. */
|
||||
ReleaseLaterRecord records;
|
||||
|
||||
/* Callback run upon all buffers being released. */
|
||||
AllReleasedCallback callback;
|
||||
|
||||
/* Data for that callback. */
|
||||
void *callback_data;
|
||||
};
|
||||
|
||||
BufferReleaseHelper *
|
||||
MakeBufferReleaseHelper (AllReleasedCallback callback,
|
||||
void *callback_data)
|
||||
{
|
||||
BufferReleaseHelper *helper;
|
||||
|
||||
helper = XLCalloc (1, sizeof *helper);
|
||||
helper->records.next = &helper->records;
|
||||
helper->records.last = &helper->records;
|
||||
helper->callback = callback;
|
||||
helper->callback_data = callback_data;
|
||||
|
||||
return helper;
|
||||
}
|
||||
|
||||
void
|
||||
FreeBufferReleaseHelper (BufferReleaseHelper *helper)
|
||||
{
|
||||
ReleaseLaterRecord *next, *last;
|
||||
|
||||
/* Do an XSync, and then release all the records. */
|
||||
XSync (compositor.display, False);
|
||||
|
||||
next = helper->records.next;
|
||||
while (next != &helper->records)
|
||||
{
|
||||
last = next;
|
||||
next = next->next;
|
||||
|
||||
/* Cancel the idle callback if it already exists. */
|
||||
if (last->key)
|
||||
RenderCancelIdleCallback (last->key);
|
||||
|
||||
/* Release the buffer now. */
|
||||
XLReleaseBuffer (last->buffer);
|
||||
|
||||
/* Before freeing the record itself. */
|
||||
XLFree (last);
|
||||
}
|
||||
|
||||
/* Free the helper. */
|
||||
XLFree (helper);
|
||||
}
|
||||
|
||||
static void
|
||||
BufferIdleCallback (RenderBuffer buffer, void *data)
|
||||
{
|
||||
ReleaseLaterRecord *record;
|
||||
BufferReleaseHelper *helper;
|
||||
|
||||
record = data;
|
||||
helper = record->helper;
|
||||
|
||||
/* Release the buffer. */
|
||||
XLReleaseBuffer (record->buffer);
|
||||
|
||||
/* Unlink and free the record. */
|
||||
record->next->last = record->last;
|
||||
record->last->next = record->next;
|
||||
XLFree (record);
|
||||
|
||||
/* If there are no more records in the helper, run its
|
||||
all-released-callback. */
|
||||
if (helper->records.next == &helper->records)
|
||||
helper->callback (helper->callback_data);
|
||||
}
|
||||
|
||||
void
|
||||
ReleaseBufferWithHelper (BufferReleaseHelper *helper, ExtBuffer *buffer,
|
||||
RenderTarget target)
|
||||
{
|
||||
ReleaseLaterRecord *record;
|
||||
RenderBuffer render_buffer;
|
||||
|
||||
render_buffer = XLRenderBufferFromBuffer (buffer);
|
||||
|
||||
record = XLCalloc (1, sizeof *record);
|
||||
record->next = helper->records.next;
|
||||
record->last = &helper->records;
|
||||
helper->records.next->last = record;
|
||||
helper->records.next = record;
|
||||
|
||||
/* Now, the record is linked into the list. Record the buffer and
|
||||
add an idle callback. */
|
||||
record->buffer = buffer;
|
||||
record->key = RenderAddIdleCallback (render_buffer, target,
|
||||
BufferIdleCallback,
|
||||
record);
|
||||
record->helper = helper;
|
||||
}
|
534
test.c
Normal file
534
test.c
Normal file
|
@ -0,0 +1,534 @@
|
|||
/* Wayland compositor running on top of an X server.
|
||||
|
||||
Copyright (C) 2022 to various contributors.
|
||||
|
||||
This file is part of 12to11.
|
||||
|
||||
12to11 is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation, either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
12to11 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 General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "compositor.h"
|
||||
#include "12to11-test.h"
|
||||
|
||||
#define TestSurfaceFromRole(role) ((TestSurface *) (role))
|
||||
|
||||
#define DefaultEventMask \
|
||||
(ExposureMask | StructureNotifyMask | PropertyChangeMask)
|
||||
|
||||
enum
|
||||
{
|
||||
IsSurfaceMapped = 1,
|
||||
PendingBufferRelease = 1 << 1,
|
||||
PendingFrameCallback = 1 << 2,
|
||||
};
|
||||
|
||||
typedef struct _TestSurface TestSurface;
|
||||
|
||||
struct _TestSurface
|
||||
{
|
||||
/* The associated role. */
|
||||
Role role;
|
||||
|
||||
/* The associated subcompositor. */
|
||||
Subcompositor *subcompositor;
|
||||
|
||||
/* The associated buffer release helper. */
|
||||
BufferReleaseHelper *release_helper;
|
||||
|
||||
/* The associated window. */
|
||||
Window window;
|
||||
|
||||
/* The associated rendering target. */
|
||||
RenderTarget target;
|
||||
|
||||
/* The number of references to this test surface, and flags. */
|
||||
int refcount, flags;
|
||||
|
||||
/* The last known width and height. */
|
||||
int bounds_width, bounds_height;
|
||||
};
|
||||
|
||||
/* The test surface manager global. */
|
||||
static struct wl_global *test_manager_global;
|
||||
|
||||
/* Hash table of all surfaces. */
|
||||
static XLAssocTable *surfaces;
|
||||
|
||||
static void
|
||||
DestroyBacking (TestSurface *test)
|
||||
{
|
||||
if (--test->refcount)
|
||||
return;
|
||||
|
||||
/* Release all allocated resources. */
|
||||
RenderDestroyRenderTarget (test->target);
|
||||
XDestroyWindow (compositor.display, test->window);
|
||||
|
||||
/* And the buffer release helper. */
|
||||
FreeBufferReleaseHelper (test->release_helper);
|
||||
|
||||
/* Delete the association. */
|
||||
XLDeleteAssoc (surfaces, test->window);
|
||||
|
||||
/* Free the subcompositor. */
|
||||
SubcompositorFree (test->subcompositor);
|
||||
|
||||
/* And since there are no C level references to the role anymore, it
|
||||
can be freed. */
|
||||
XLFree (test);
|
||||
}
|
||||
|
||||
static void
|
||||
RunFrameCallbacks (TestSurface *test)
|
||||
{
|
||||
struct timespec time;
|
||||
|
||||
clock_gettime (CLOCK_MONOTONIC, &time);
|
||||
XLSurfaceRunFrameCallbacks (test->role.surface, time);
|
||||
|
||||
test->flags &= ~PendingFrameCallback;
|
||||
}
|
||||
|
||||
static void
|
||||
RunFrameCallbacksConditionally (TestSurface *test)
|
||||
{
|
||||
if (!test->role.surface)
|
||||
return;
|
||||
|
||||
if (test->flags & PendingBufferRelease)
|
||||
/* Wait for all buffers to be released first. */
|
||||
test->flags |= PendingFrameCallback;
|
||||
else
|
||||
RunFrameCallbacks (test);
|
||||
}
|
||||
|
||||
static void
|
||||
AllBuffersReleased (void *data)
|
||||
{
|
||||
TestSurface *test;
|
||||
|
||||
test = data;
|
||||
|
||||
if (!test->role.surface)
|
||||
return;
|
||||
|
||||
test->flags &= ~PendingBufferRelease;
|
||||
|
||||
/* Run pending frame callbacks. */
|
||||
if (test->flags & PendingFrameCallback)
|
||||
RunFrameCallbacks (test);
|
||||
}
|
||||
|
||||
static void
|
||||
NoteBounds (void *data, int min_x, int min_y, int max_x, int max_y)
|
||||
{
|
||||
TestSurface *test;
|
||||
int bounds_width, bounds_height;
|
||||
|
||||
test = data;
|
||||
|
||||
/* Avoid resizing the window should its actual size not have
|
||||
changed. */
|
||||
|
||||
bounds_width = max_x - min_x + 1;
|
||||
bounds_height = max_y - min_y + 1;
|
||||
|
||||
if (test->bounds_width != bounds_width
|
||||
|| test->bounds_height != bounds_height)
|
||||
{
|
||||
/* Resize the window to fit. */
|
||||
XResizeWindow (compositor.display, test->window,
|
||||
bounds_width, bounds_height);
|
||||
test->bounds_width = bounds_width;
|
||||
test->bounds_height = bounds_height;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
NoteFrame (FrameMode mode, uint64_t id, void *data)
|
||||
{
|
||||
if (mode != ModeComplete && mode != ModePresented)
|
||||
return;
|
||||
|
||||
/* Run the frame callbacks. With the test surface, this also serves
|
||||
to mean that painting has completed. */
|
||||
RunFrameCallbacksConditionally (data);
|
||||
}
|
||||
|
||||
static void
|
||||
MapTestSurface (TestSurface *test)
|
||||
{
|
||||
/* Set the bounds width and height. */
|
||||
test->bounds_width = SubcompositorWidth (test->subcompositor);
|
||||
test->bounds_height = SubcompositorHeight (test->subcompositor);
|
||||
|
||||
/* First, resize the window to the current bounds. */
|
||||
XResizeWindow (compositor.display, test->window,
|
||||
test->bounds_width, test->bounds_height);
|
||||
|
||||
/* Next, map the window and raise it. Wait for a subsequent
|
||||
MapNotify before sending the map event. */
|
||||
XMapRaised (compositor.display, test->window);
|
||||
|
||||
/* And say that the window is now mapped. */
|
||||
test->flags |= IsSurfaceMapped;
|
||||
}
|
||||
|
||||
static void
|
||||
UnmapTestSurface (TestSurface *test)
|
||||
{
|
||||
if (test->flags & IsSurfaceMapped)
|
||||
/* Unmap the surface. */
|
||||
XUnmapWindow (compositor.display, test->window);
|
||||
}
|
||||
|
||||
static void
|
||||
Commit (Surface *surface, Role *role)
|
||||
{
|
||||
TestSurface *test;
|
||||
|
||||
test = TestSurfaceFromRole (role);
|
||||
|
||||
if (surface->current_state.buffer
|
||||
&& !(test->flags & IsSurfaceMapped))
|
||||
/* Map the surface now. */
|
||||
MapTestSurface (test);
|
||||
else if (!surface->current_state.buffer)
|
||||
/* Unmap the surface now. */
|
||||
UnmapTestSurface (test);
|
||||
|
||||
/* Finally, do a subcompositor update if the surface is now
|
||||
mapped. */
|
||||
if (test->flags & IsSurfaceMapped)
|
||||
SubcompositorUpdate (test->subcompositor);
|
||||
}
|
||||
|
||||
static Bool
|
||||
Setup (Surface *surface, Role *role)
|
||||
{
|
||||
TestSurface *test;
|
||||
|
||||
test = TestSurfaceFromRole (role);
|
||||
|
||||
/* Set role->surface here, since this is where the refcounting is
|
||||
done as well. */
|
||||
role->surface = surface;
|
||||
|
||||
/* Prevent the surface from ever holding another kind of role. */
|
||||
surface->role_type = TestSurfaceType;
|
||||
|
||||
/* Attach the views to the subcompositor. */
|
||||
ViewSetSubcompositor (surface->view, test->subcompositor);
|
||||
ViewSetSubcompositor (surface->under, test->subcompositor);
|
||||
|
||||
/* Make sure the under view ends up beneath surface->view. */
|
||||
SubcompositorInsert (test->subcompositor, surface->under);
|
||||
SubcompositorInsert (test->subcompositor, surface->view);
|
||||
|
||||
/* Retain the backing data. */
|
||||
test->refcount++;
|
||||
return True;
|
||||
}
|
||||
|
||||
static void
|
||||
Teardown (Surface *surface, Role *role)
|
||||
{
|
||||
TestSurface *test;
|
||||
|
||||
/* Clear role->surface here, since this is where the refcounting is
|
||||
done as well. */
|
||||
role->surface = NULL;
|
||||
|
||||
test = TestSurfaceFromRole (role);
|
||||
|
||||
/* Unparent the surface's views as well. */
|
||||
ViewUnparent (surface->view);
|
||||
ViewUnparent (surface->under);
|
||||
|
||||
/* Detach the surface's views from the subcompositor. */
|
||||
ViewSetSubcompositor (surface->view, NULL);
|
||||
ViewSetSubcompositor (surface->under, NULL);
|
||||
|
||||
/* Release the backing data. */
|
||||
DestroyBacking (test);
|
||||
}
|
||||
|
||||
static void
|
||||
Destroy (struct wl_client *client, struct wl_resource *resource)
|
||||
{
|
||||
TestSurface *test;
|
||||
|
||||
test = wl_resource_get_user_data (resource);
|
||||
|
||||
/* Now detach the role from its surface, which can be reused in the
|
||||
future. */
|
||||
if (test->role.surface)
|
||||
XLSurfaceReleaseRole (test->role.surface, &test->role);
|
||||
|
||||
/* And destroy the resource. */
|
||||
wl_resource_destroy (resource);
|
||||
}
|
||||
|
||||
static void
|
||||
ReleaseBuffer (Surface *surface, Role *role, ExtBuffer *buffer)
|
||||
{
|
||||
TestSurface *test;
|
||||
RenderBuffer render_buffer;
|
||||
|
||||
test = TestSurfaceFromRole (role);
|
||||
render_buffer = XLRenderBufferFromBuffer (buffer);
|
||||
|
||||
if (RenderIsBufferIdle (render_buffer, test->target))
|
||||
/* Release the buffer now -- it is already idle. */
|
||||
XLReleaseBuffer (buffer);
|
||||
else
|
||||
{
|
||||
/* Release the buffer once it becomes idle, or is destroyed. */
|
||||
ReleaseBufferWithHelper (test->release_helper, buffer,
|
||||
test->target);
|
||||
|
||||
/* Mark the surface as pending buffer release, so frame
|
||||
callbacks can be deferred until all buffers are released. */
|
||||
test->flags |= PendingBufferRelease;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
SubsurfaceUpdate (Surface *surface, Role *role)
|
||||
{
|
||||
TestSurface *test;
|
||||
|
||||
test = TestSurfaceFromRole (role);
|
||||
SubcompositorUpdate (test->subcompositor);
|
||||
}
|
||||
|
||||
static Window
|
||||
GetWindow (Surface *surface, Role *role)
|
||||
{
|
||||
TestSurface *test;
|
||||
|
||||
test = TestSurfaceFromRole (role);
|
||||
return test->window;
|
||||
}
|
||||
|
||||
static const struct test_surface_interface test_surface_impl =
|
||||
{
|
||||
.destroy = Destroy,
|
||||
};
|
||||
|
||||
static void
|
||||
HandleResourceDestroy (struct wl_resource *resource)
|
||||
{
|
||||
TestSurface *test;
|
||||
|
||||
test = wl_resource_get_user_data (resource);
|
||||
test->role.resource = NULL;
|
||||
|
||||
/* Dereference the backing data. */
|
||||
DestroyBacking (test);
|
||||
}
|
||||
|
||||
static void
|
||||
GetTestSurface (struct wl_client *client, struct wl_resource *resource,
|
||||
uint32_t id, struct wl_resource *surface_resource)
|
||||
{
|
||||
Surface *surface;
|
||||
TestSurface *test;
|
||||
XSetWindowAttributes attrs;
|
||||
unsigned long flags;
|
||||
|
||||
surface = wl_resource_get_user_data (surface_resource);
|
||||
|
||||
if (surface->role_type != AnythingType
|
||||
&& surface->role_type != TestSurfaceType)
|
||||
{
|
||||
/* The client is trying to create a test surface for a surface
|
||||
that has or had some other role. */
|
||||
wl_resource_post_error (resource, TEST_MANAGER_ERROR_ROLE_PRESENT,
|
||||
"a role is/was already present on the given surface");
|
||||
return;
|
||||
}
|
||||
|
||||
test = XLSafeMalloc (sizeof *test);
|
||||
|
||||
if (!test)
|
||||
{
|
||||
wl_resource_post_no_memory (resource);
|
||||
return;
|
||||
}
|
||||
|
||||
memset (test, 0, sizeof *test);
|
||||
|
||||
/* Now create the associated resource. */
|
||||
test->role.resource
|
||||
= wl_resource_create (client, &test_surface_interface,
|
||||
wl_resource_get_version (resource),
|
||||
id);
|
||||
if (!test->role.resource)
|
||||
{
|
||||
wl_resource_post_no_memory (resource);
|
||||
XLFree (test);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create the window. */
|
||||
attrs.colormap = compositor.colormap;
|
||||
attrs.border_pixel = border_pixel;
|
||||
attrs.event_mask = DefaultEventMask;
|
||||
attrs.cursor = InitDefaultCursor ();
|
||||
flags = CWColormap | CWBorderPixel | CWEventMask | CWCursor;
|
||||
|
||||
test->window = XCreateWindow (compositor.display,
|
||||
DefaultRootWindow (compositor.display),
|
||||
0, 0, 20, 20, 0, compositor.n_planes,
|
||||
InputOutput, compositor.visual, flags,
|
||||
&attrs);
|
||||
|
||||
/* And the subcompositor and rendering target. */
|
||||
test->subcompositor = MakeSubcompositor ();
|
||||
test->target = RenderTargetFromWindow (test->window, DefaultEventMask);
|
||||
|
||||
/* And a buffer release helper. */
|
||||
test->release_helper = MakeBufferReleaseHelper (AllBuffersReleased,
|
||||
test);
|
||||
|
||||
/* Set the subcompositor target. */
|
||||
SubcompositorSetTarget (test->subcompositor, &test->target);
|
||||
|
||||
/* Set some callbacks. The note frame callback is not useful as
|
||||
test surfaces have no frame clock. */
|
||||
SubcompositorSetBoundsCallback (test->subcompositor, NoteBounds, test);
|
||||
SubcompositorSetNoteFrameCallback (test->subcompositor, NoteFrame,
|
||||
test);
|
||||
|
||||
/* Create the hash table used to look up test surfaces if
|
||||
necessary. */
|
||||
|
||||
if (!surfaces)
|
||||
surfaces = XLCreateAssocTable (16);
|
||||
|
||||
/* Associate the window with the role. */
|
||||
XLMakeAssoc (surfaces, test->window, test);
|
||||
|
||||
/* Set the role implementation. */
|
||||
test->role.funcs.commit = Commit;
|
||||
test->role.funcs.teardown = Teardown;
|
||||
test->role.funcs.setup = Setup;
|
||||
test->role.funcs.release_buffer = ReleaseBuffer;
|
||||
test->role.funcs.subsurface_update = SubsurfaceUpdate;
|
||||
test->role.funcs.get_window = GetWindow;
|
||||
|
||||
/* Add the resource implementation. */
|
||||
wl_resource_set_implementation (test->role.resource, &test_surface_impl,
|
||||
test, HandleResourceDestroy);
|
||||
test->refcount++;
|
||||
|
||||
/* Attach the role. */
|
||||
if (!XLSurfaceAttachRole (surface, &test->role))
|
||||
abort ();
|
||||
}
|
||||
|
||||
static const struct test_manager_interface test_manager_impl =
|
||||
{
|
||||
.get_test_surface = GetTestSurface,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void
|
||||
HandleBind (struct wl_client *client, void *data, uint32_t version,
|
||||
uint32_t id)
|
||||
{
|
||||
struct wl_resource *resource;
|
||||
char *name;
|
||||
|
||||
resource = wl_resource_create (client, &test_manager_interface,
|
||||
version, id);
|
||||
|
||||
if (!resource)
|
||||
{
|
||||
wl_client_post_no_memory (client);
|
||||
return;
|
||||
}
|
||||
|
||||
wl_resource_set_implementation (resource, &test_manager_impl,
|
||||
NULL, NULL);
|
||||
|
||||
/* Send the display name to the client. */
|
||||
name = DisplayString (compositor.display);
|
||||
test_manager_send_display_string (resource, name);
|
||||
}
|
||||
|
||||
void
|
||||
XLInitTest (void)
|
||||
{
|
||||
test_manager_global
|
||||
= wl_global_create (compositor.wl_display, &test_manager_interface,
|
||||
1, NULL, HandleBind);
|
||||
}
|
||||
|
||||
static Bool
|
||||
DispatchMapNotify (XEvent *event)
|
||||
{
|
||||
TestSurface *test;
|
||||
|
||||
/* Try to look up the surface. */
|
||||
test = XLLookUpAssoc (surfaces, event->xmap.window);
|
||||
|
||||
if (!test)
|
||||
return False;
|
||||
|
||||
/* The surface is now mapped. Dispatch the mapped event. */
|
||||
if (test->flags & IsSurfaceMapped && test->role.resource)
|
||||
test_surface_send_mapped (test->role.resource, test->window,
|
||||
DisplayString (compositor.display));
|
||||
return True;
|
||||
}
|
||||
|
||||
static Bool
|
||||
DispatchExpose (XEvent *event)
|
||||
{
|
||||
TestSurface *test;
|
||||
|
||||
/* Try to look up the surface. */
|
||||
test = XLLookUpAssoc (surfaces, event->xexpose.window);
|
||||
|
||||
if (!test)
|
||||
return False;
|
||||
|
||||
/* Expose the subcompositor. */
|
||||
SubcompositorExpose (test->subcompositor, event);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
Bool
|
||||
XLHandleOneXEventForTest (XEvent *event)
|
||||
{
|
||||
if (!surfaces)
|
||||
return False;
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case MapNotify:
|
||||
return DispatchMapNotify (event);
|
||||
|
||||
case Expose:
|
||||
return DispatchExpose (event);
|
||||
}
|
||||
|
||||
return False;
|
||||
}
|
Loading…
Add table
Reference in a new issue