Compare commits

...

65 Commits

Author SHA1 Message Date
Michel Dänzer 1dbb96ae48 Bump version for the Xwayland 21.1.2 release 2021-07-09 12:14:50 +02:00
Michel Dänzer b42c33b6ef xwayland: Call RRTellChanged if the RandR configuration may have changed
This makes sure RandR events are sent to interested clients as needed.
This was happening implicitly in some cases, but not in others, e.g. if
the root window size didn't change.

If this were to call RRTellChanged more often than necessary in some
cases, that should be harmless, as it only sends events if something
has actually changed since last time.

Should fix https://bugzilla.redhat.com/show_bug.cgi?id=1979892 .

v2:
* Call RRTellChanged at the very end of update_screen_size, just in
  case.

Reviewed-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 204f10c29e)
2021-07-09 12:10:54 +02:00
Michel Dänzer 96829a7b19 randr: Bail from RRTellChanged if there's no root window yet
This can happen if RRTellChanged is called during initialization.

Continuing in that case makes no sense conceptually:

* Any event sent over the wire requires a corresponding window.
* No root window probably means there can't be any clients which could
  receive the events.

In practice, it would result in a crash down the road due to
dereferencing the NULL ScreenRec::root pointer.

Reviewed-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit a6d178b6af)
2021-07-09 12:10:27 +02:00
Michel Dänzer bfd7e302fc Bump version to 21.1.1.901
Xwayland 21.1.2 release candidate 1.
2021-06-30 16:43:31 +02:00
Olivier Fourdan d9005a02e9 xwayland/eglstream: Remove stream validity
To avoid an EGL stream in the wrong state, if the window pixmap changed
before the stream was connected, we would still keep the pending stream
but mark it as invalid. Once the callback is received, the pending would
be simply discarded.

But all of this is actually to avoid a bug in egl-wayland, there should
not be any problem with Xwayland destroying an EGL stream while the
compositor is still using it.

With that bug now fixed in egl-wayland 1.1.7, we can safely drop all
that logic from Xwayland EGLstream backend.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1189
(cherry picked from commit 7d509b6f34)
2021-06-30 09:25:19 +02:00
Olivier Fourdan 8c74023712 xwayland/eglstream: Keep pending stream if the pixmap didn't change
If the pixmap does not actually change in set_window_pixmap(), there is
no need to invalidate the pending stream, if there's one.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Suggested-by: Michel Dänzer <mdaenzer@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
(cherry picked from commit 2be9f795bc)
2021-06-30 09:25:15 +02:00
Olivier Fourdan 763f4fb278 glx: Set ContextTag for all contexts
Currently, xorgGlxMakeCurrent() would set the context tag only for
indirect GLX contexts.

However, several other places expect to find a context for the tag or
they would raise a GLXBadContextTag error, such as WaitGL() or WaitX().

Set the context tag for direct contexts as well, to avoid raising an
error and possibly killing the client and set currentClient.

Thanks to Erik Kurzinger <ekurzinger@nvidia.com> for spotting the issue.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
(cherry picked from commit c468d34c72)
(cherry picked from commit aad61e8e03)
2021-06-21 11:16:58 +02:00
Erik Kurzinger e754b473d1 glx: don't create implicit GLXWindow if one already exists
If a GLXMakeCurrent request specifies an X window as its drawable,
__glXGetDrawable will implicitly create a GLXWindow for it. However,
the client may have already explicitly created a GLXWindow for that X
window. If that happens, two __glXDrawableRes resources will be added
to the window.

If the explicitly-created GLXWindow is later destroyed by the client,
DrawableGone will call FreeResourceByType on the X window, but this
will actually free the resource for the implicitly-created GLXWindow,
since that one would be at the head of the list.

Then if the X window is destroyed after that, the resource for the
explicitly-created GLXWindow will be freed. But that GLXWindow was
already destroyed above. This crashes the server when it tries to call
the destroyed GLXWindow's destructor. It also means the
implicitly-created GLXWindow would have been leaked since the
FreeResourceByType call mentioned above skips calling the destructor.

To fix this, if __glXGetDrawable is given an X window, it should check
if there is already a GLXWindow associated with it, and only create an
implicit one if there is not.

Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
(cherry picked from commit b7a85e44da)
2021-06-21 11:16:58 +02:00
Olivier Fourdan 831426afd1 xwayland/eglstream: Log when GL_OES_EGL_image is missing
That will dramatically affect performance, might as well log when we
cannot use GL_OES_EGL_image with the NVIDIA closed-source driver.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
(cherry picked from commit 34a58d7714)
2021-06-21 11:16:58 +02:00
Olivier Fourdan 2e1bb50644 xwayland/eglstream: Use "nvidia" for GLVND
If the EGLStream backend is able to use hardware acceleration with the
NVIDIA closed source driver, we should use the "nvidia" GLX
implementation instead of the one from Mesa to take advantage of the
NVIDIA hardware accelerated rendering.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
(cherry picked from commit fae58e9b03)
2021-06-21 11:16:58 +02:00
Olivier Fourdan 8744ab1b41 xwayland: Add preferred GLVND vendor to xwl_screen
If Xwayland's EGLstream backend supports hardware acceleration with the
NVIDIA closed-source driver, the GLX library also needs to be one
shipped by NVIDIA, that's what GLVND is for.

Add a new member to the xwl_screen that the backend can optionally set
to the preferred GLVND vendor to use.

If not set, "mesa" is assumed.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
(cherry picked from commit 24fc8aea1e)
2021-06-21 11:16:58 +02:00
Erik Kurzinger f4720f1c42 xwayland/eglstream: flush stream after eglSwapBuffers
When eglSwapBuffers inserts a new frame into a window's stream, there may be a
delay before the state of the consumer end of the stream is updated to reflect
this. If the subsequent wl_surface_attach, wl_surface_damage, wl_surface_commit
calls are received by the compositor before then, it will (typically) re-use
the previous frame acquired from the stream instead of the latest one.

This can leave the window displaying out-of-date contents, which might never be
updated thereafter.

To fix this, after calling eglSwapBuffers, xwl_glamor_eglstream_post_damage
should call eglStreamFlushNV. This call will block until it can be guaranteed
that the state of the consumer end of the stream has been updated to reflect
that a new frame is available.

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1171

Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com>
(cherry picked from commit 7515c23a41)
2021-06-21 11:16:58 +02:00
Erik Kurzinger b2963fccc1 xwayland/eglstream: allow commits to dma-buf backed pixmaps
As of commit 098e0f52 xwl_glamor_eglstream_allow_commits will not allow commits
if the xwl_pixmap does not have an EGLSurface. This is valid for pixmaps backed
by an EGLStream, however pixmaps backed by a dma-buf for OpenGL or Vulkan
rendering will never have an EGLSurface.  Unlike EGLStream backed pixmaps,
though, glamor will render directly to the buffer that Xwayland passes to the
compositor. Hence, they don't require the intermediate copy in
xwl_glamor_eglstream_post_damage that EGLStream backed pixmaps do, so there is
no need for an EGLSurface.

Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com>
Acked-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
(cherry picked from commit 3d33d885fc)
2021-06-21 11:16:58 +02:00
Olivier Fourdan bdb4712da3 xwayland/eglstream: Set ALU to GXCopy for blitting
The EGLstream backend's post damage function uses a shader and
glDrawArrays() to copy the data from the glamor's pixmap texture prior
to do the eglSwapBuffers().

However, glDrawArrays() can be affected by the GL state, and therefore
not reliably produce the expected copy, causing the content of the
buffer to be corrupted.

Make sure to set the ALU to GXCopy prior to call glDrawArrays() to get
the expected result.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Suggested-by: Michel Dänzer <mdaenzer@redhat.com>
(cherry picked from commit 012350e3db)
2021-06-21 11:16:58 +02:00
Olivier Fourdan 96febe8ba4 xwayland/eglstream: Do not always increment pixmap refcnt on commit
Currently, the EGLstream backend would increment the pixmap refcount for
each commit, and decrease that refcount on the wl_buffer release
callback.

But that's relying on the compositor sending us a release callback for
each commit, otherwise the pixmap refcount will keep increasing and the
pixmap will be leaked.

So instead, increment the refcount on the pixmap only when we have not
received a release notification for the wl_buffer, to avoid increasing
the pixmap refcount more than once without a corresponding release
event.

This way, if the pixmap is still in use when released on the X11 side,
the EGL stream will be kept until the compositor releases it.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Suggested-by: Michel Dänzer <mdaenzer@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
(cherry picked from commit d85bfa6ab7)
2021-06-21 11:16:58 +02:00
Olivier Fourdan 7d839b3ed3 xwayland/eglstream: Check eglSwapBuffers()
EGLstream's post_damage() would unconditionally return success
regardless of the actual status of the eglSwapBuffers().

Yet, if eglSwapBuffers() fails, we should not post the corresponding
damage as they wouldn't match the actual content of the buffer.

Use the eglSwapBuffers() return value as the return value for
post_damage() and do not take a refrence on the pixmap if it fails.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
(cherry picked from commit b583395cd3)
2021-06-21 11:16:58 +02:00
Olivier Fourdan 8b8a9bf6c7 xwayland/eglstream: Fix calloc/malloc
Use calloc() instead of malloc() like the rest of the code.

Also fix the arguments of calloc() calls to match the definition which
is calloc(size_t nmemb, size_t size).

This is a cleanup patch, no functional change.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
(cherry picked from commit a457999710)
2021-06-21 11:16:58 +02:00
Olivier Fourdan 15e550cc9a xwayland/eglstream: Do not commit without surface
The EGL surface for the xwl_pixmap is created once the stream is ready
and valid.

If the pixmap's EGL surface fails, for whatever reason, the xwl_pixmap
will be unusable and will end up as an invalid wl_buffer.

Make sure we do not allow commits in that case and recreate the
xwl_pixmap/stream.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
(cherry picked from commit 098e0f52c0)
2021-06-21 11:16:58 +02:00
Olivier Fourdan 01319a9006 xwayland/eglstream: Drop the list of pending streams
Now that the pending stream is associated with the xwl_pixmap for
EGLStream and the xwl_pixmap itself is associated to the pixmap, we have
a reliable way to get to those data from any pending stream.

As a result, the list of pending streams that we keep in the EGLStream
global structure becomes useless.

So we can drop the pending stream's xwl_pixmap and also the list of
pending streams altogether, and save us a walk though that list for each
callback.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Suggested-by: Michel Dänzer <mdaenzer@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
(cherry picked from commit bee2ebb29f)
2021-06-21 11:16:58 +02:00
Olivier Fourdan 77617490fc xwayland/eglstream: Keep a reference to the pixmap
Commit affc47452 - "xwayland: Drop the separate refcount for the
xwl_pixmap" removed the separate reference counter for the xwl_pixmap
which holds the EGLStream.

While that works fine for the common case, if the window's pixmap is
changed before the stream is ready, the older pixmap will be destroyed
and the xwl_pixmap along with it, even if the compositor is still using
the stream.

The code that was removed with commit affc47452 was taking care of that
by increasing the separate reference counter for the xwl_pixmap, but it
no longer the case.

As a result, we may end up with the EGL stream in the wrong state when
trying to use it, which will cascade down into all sort of issues.

To avoid the problem, increase the reference count on the pixmap when it
is marked as invalid in EGLStream's SetWindowPixmap().

This way, the xwl_pixmap and the EGLStream are kept until released by
the compositor, even when the pixmap changes before stream is ready.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
Fixes: affc47452 xwayland: Drop the separate refcount for the xwl_pixmap
https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
(cherry picked from commit e19bf86c17)
2021-06-21 11:16:58 +02:00
Olivier Fourdan b05b19df01 xwayland/eglstream: Dissociate pending stream from window
Previously, we would have pending streams associated with top level X11
windows, keeping temporary accounting for the pending streams before
they get fully initialized for the xwl_pixmap which would be associated
with X11 pixmaps.

If the window content changes before the stream is ready, the
corresponding pending stream would be marked as invalid and the pending
stream would be eventually removed once the stream becomes ready.

Since commit affc47452 - "xwayland: Drop the separate refcount for the
xwl_pixmap", we no longer keep a separate reference counter for the
xwl_pixmap, but rather tie it to the X11 pixmap lifespan. Yet, the
pending stream would still be associated with the X11 toplevel window.

Dissociate the pending streams from the X11 toplevel window, to keep it
tied only to the xwl_pixmap so that we can have:

 - pixmap <-> xwl_pixmap
 - xwl_pixmap <-> pending stream

Of course, the pending streams remain temporary and get removed as soon
as the ready callback is triggered, but the pending streams are not
linked to the X11 window anymore which can change their content, and
therefore their X11 pixmap at any time.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
(cherry picked from commit cb61ecc729)
2021-06-21 11:16:58 +02:00
Olivier Fourdan 1cce4bfd68 xwayland/eglstream: Add more error checking
eglCreateStreamKHR() can fail and return EGL_NO_STREAM_KHR, in which
case there is no point in trying to create a buffer from it.

Similarly, eglCreateStreamProducerSurfaceKHR() also fail and return
EGL_NO_SURFACE, which in turn will be used in eglMakeCurrent() as
draw/read surface, and therefore would mean no draw/read buffer.

In those cases, log the error, and bail out early. That won't solve the
issue but will help with investigating the root cause of issues with
EGLStream backend.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
(cherry picked from commit cc596bcfb2)
2021-06-21 11:16:58 +02:00
Olivier Fourdan 526cb24826 xwayland/eglstream: Small refactoring
Some functions are called "callback" whereas they are not longer
callback functions or "unref" while they no longer deal with a reference
counter anymore, which is quite confusing. Rename those functions to be
more explicit.

Also, the pending streams can be destroyed in different places, move the
common code to separate function to avoid duplicating code and help with
readability of the code.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Acked-by: Michel Dänzer <mdaenzer@redhat.com>
(cherry picked from commit 823f3254fa)
2021-06-21 11:16:58 +02:00
Olivier Fourdan 72790f7446 xwayland/eglstream: Check framebuffer status
The EGLStream backend would sometime generate GL errors trying to draw
to the framebuffer, which gives an invalid buffer, which in turn would
generate a Wayland error from the compositor which is fatal to the
client.

Check the framebuffer status and bail out early if it's not complete,
to avoid getting into trouble later.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
(cherry picked from commit 85244d2a20)
2021-06-21 11:16:58 +02:00
Olivier Fourdan 46dc7e8ee3 xwayland/glamor: Add return status to post_damage
If the glamor backend failed to post damage, the caller should do the
same to avoid a failure to attach the buffer to the Wayland surface.

Change the API of Xwayland's glamor backend post_damage() to return a
status so that xwl_window_post_damage() can tell whether the callee
failed.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
(cherry picked from commit 252cbad316)
2021-06-21 11:16:58 +02:00
Olivier Fourdan 673676e759 glamor: Dump backtrace on GL error
Currrently, when a GL error is triggered, glamor would log the error
which may not be sufficient to trace it back to the cause of the error.

Also dump the backtrace which may give more information as to where the
error comes from.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Martin Peres <martin.peres@mupuf.org>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
(cherry picked from commit 3b265c59a6)
2021-06-21 11:16:58 +02:00
Olivier Fourdan 740f00d44f xwayland: Check buffer prior to attaching it
If the buffer is NULL, do not even try to attach it, and risk a Wayland
protocol error which would be fatal to us.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Martin Peres <martin.peres@mupuf.org>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
(cherry picked from commit 25d2f4948f)
2021-06-21 11:16:58 +02:00
Olivier Fourdan 8499fc0671 xwayland/eglstream: Check buffer creation
EGLStream wl_eglstream_display_create_stream() may fail, yet Xwayland
would try to attach the buffer which may cause a fatal Wayland protocol
error raised by the compositor.

Check if the buffer creation worked, and fail gracefully otherwise (like
wayland-eglsurface does).

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Martin Peres <martin.peres@mupuf.org>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
(cherry picked from commit 4f0889e983)
2021-06-21 11:16:58 +02:00
Erik Kurzinger d60acf6f0b xwayland-eglstream: fix X11 rendering to flipping GL / VK window
If a window is being used for direct rendering with OpenGL or Vulkan, and is
using the flipping path for presentation, it's pixmap will be set to a dma-buf
backed pixmap created by the client-side GL driver. However, this means that
xwl_glamor_eglstream_post_damage won't work since it requires that the pixmap
has an EGLSurface that it can render to, which dma-buf backed pixmaps do not.

In this case, though, xwl_glamor_eglstream_post_damage is not necessary since
glamor will have rendered directly to the pixmap, so we can simply pass it
directly to the compositor. There's no need for the intermediate copy we
normally do in that function.

Therefore, this change adds an early-return case to post_damage for dma-buf
backed pixmaps, and removes the corresponding asserts from that function and
allow_commits.

Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com>
Acked-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
(cherry picked from commit 4f6fbd5009)
2021-06-21 11:16:58 +02:00
Erik Kurzinger 3d10978cb6 xwayland: implement pixmap_from_buffers for the eglstream backend
Provides an implementation for the pixmap_from_buffers DRI3 function for
xwayland's eglstream backend. This will be used by the NVIDIA GLX driver
to pass buffers from client applications to the server. These can then
be presented using the PRESENT extension.

To hopefully make this less error-prone, we also introduce a "type"
field for this struct to distinguish between xwl_pixmaps for the new
DRI3-created pixmaps and those for the existing glamor-created pixmaps.

Additionally, the patch enables wnmd present mode with the eglstream backend.
This involves creating a wl_buffer for the provided dma-buf before importing it
into EGL and passing this to the compositor so it can be scanned out directly
if possible.

Since both backends now support this present mode, the HAS_PRESENT_FLIP flag is
no longer needed, so it can be removed.

Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
Acked-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com>
(cherry picked from commit 38e875904b)
2021-06-21 11:16:58 +02:00
Erik Kurzinger f44b22b0c6 xwayland: Add check_flip() glamor backend function
This is preliminary work for hardware accelerated rendering with the
NVIDIA driver.

This exposes a new glamor backend function, check_flip, which can be
used to control whether flipping is supported for the given pixmap.

Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
Acked-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com>
(cherry picked from commit bc99dd2127)
2021-06-21 11:16:58 +02:00
Erik Kurzinger 15d3756814 xwayland: move formats and modifiers functions to common glamor code
This is preliminary work for hardware accelerated rendering with the
NVIDIA driver.

This moves the modifiers and formats functions previously only available
to the GBM backend to the common glamor code so that it can be used by
both the GBM and EGLStream backends.

Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
Acked-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com>
(cherry picked from commit 400d4d0fdd)
2021-06-21 11:16:58 +02:00
Olivier Fourdan 1f65893873 xwayland: Move dmabuf interface to common glamor code
This is preliminary work for hardware accelerated rendering with the
NVIDIA driver.

The EGLStream backend can possibly also use the dmabuf interface, so
move the relevant code from the GBM specific source to the common bits.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit ae225417c0)
2021-06-21 11:16:58 +02:00
Michel Dänzer d4cc2e2db9 Bump version for Xwayland 21.1.1 release 2021-04-13 16:29:16 +02:00
Matthieu Herrb 1e4bf85df1 Fix XChangeFeedbackControl() request underflow
CVE-2021-3472 / ZDI-CAN-1259

This vulnerability was discovered by:
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative

Signed-off-by: Matthieu Herrb <matthieu@herrb.eu>
(cherry picked from commit 7aaf54a188)
2021-04-13 15:55:41 +02:00
Michel Dänzer 2a327e5860 Bump version for final Xwayland 21.1.0 release 2021-03-17 17:45:01 +01:00
Michel Dänzer aa06f8bdec meson: Make sure XKM_OUTPUT_DIR has a trailing slash
RunXkbComp passes an invalid file path to xkbcomp if there's no
trailing slash.

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1146
Suggested-by: Dylan Baker <dylan.c.baker@intel.com>
(cherry picked from commit 6c51818a0f)
2021-03-15 17:30:24 +01:00
Olivier Fourdan a8581795ed xwayland: Fix LeaveNotify for relative pointer
Since commit 20c78f38, we use the relative pointer for enter/leave
events.

However, sprite_check_lost_focus() which verifies whether the pointer has
left an Xwayland surface still explicitly check for the absolute
pointer.

As a result, no LeaveNotify event is emitted anymore now when the
pointer crosses from an Xwayland surface to a Wayland native one.

Make sure to check the last slave device against get_pointer_event() as
well, not just the absolute pointer.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Acked-by: Martin Peres <martin.peres@mupuf.org>
Acked-by: Roman Gilg <subdiff@gmail.com>
Tested-by: Roman Gilg <subdiff@gmail.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Fixes: 20c78f38 - xwayland: use get_pointer_device() for enter/leave
                  handling too
(cherry picked from commit d7391f383d)
2021-03-05 09:25:24 +01:00
Michel Dänzer f20dc97947 Bump version to 21.0.99.902
Xwayland 21.1.0 release candidate 2.
2021-03-03 18:03:00 +01:00
Olivier Fourdan 15f8b78904 xwayland: Delay cursor visibility update
Xwayland won't emulate XWarpPointer requests if the cursor is visible,
this is to avoid having the cursor jumping on screen and preventing
random X11 clients from controlling the pointer in Wayland, while
allowing games which use that mechanism with a hidden cursor to work in
Xwayland.

There are, however, games which tend to do it in the wrong order, i.e.
show the cursor before moving the pointer, and because Xwayland will not
allow an X11 client to move the pointer while the cursor is visible, the
requests will fail.

Add a workaround for such X11 clients, when the cursor is being shown,
keep it invisible until the cursor is actually moved. This way, X11
clients which show their cursor just before moving it would still have a
chance to succeed.

v2: Add a timeout to show the cursor for well behaved clients.
v3: Some cleanup (Michel)
v4: Do not cancel cursor delay when updating the cursor to avoid
    delaying cursor visibility indefinitely if the client keeps
    settings different cursors (Michel)

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Tested-by: Jaap Buurman jaapbuurman@gmail.com
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/734
(cherry picked from commit 97ed0048e4)
2021-03-03 17:56:55 +01:00
Adam Jackson efd546cd1e meson.build: Keep the protocol version looking like xserver 1.20.x did
This effectively changes the versioning to be as if xserver 21.0 was
xserver 1.21.0. This should keep any client-side version checks that
know about the Xorg 7.0 -> xserver 1.0 epoch from getting confused.

Fixes: 1e72c3ce84 "Bump version to 21.0.99.1"
2021-03-02 11:40:14 +01:00
Michel Dänzer 280aac5a0e Bump version to 21.0.99.901
Xwayland 21.1.0 release candidate 1.
2021-02-17 16:17:08 +01:00
Michel Dänzer fdc61c5a3c meson: Simplify build_glamor logic
Don't need the separate glamor_option variable anymore.

Fixes: 274d54d1c3 "meson: Build Xwayland unconditionally"
2021-02-17 11:55:19 +00:00
Olivier Fourdan 22a3dedac3 dix: Guard against non-existing PtrFeedbackPtr
Trying to change the pointer control settings on a device without
PtrFeedbackPtr would be a bug and a crash in the Xserver.

Guard against that case by returning early with a BadImplementation
error, that might kill the X11 client but the Xserver would survive.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Related: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1137
(imported from commit dee2bb033e)
2021-02-17 11:55:19 +00:00
Olivier Fourdan b16dbd878d xwayland: Add PtrFeedback to the touch device
Trying to change the acceleration/threshold on Xwayland cannot work, and
the corresponding handler xwl_pointer_control() is a no-op.

Yet, an X11 client trying to change those on the touch device may
possibly cause a crash because the touch device in Xwayland doesn't set
that.

Initialize the touch device's PtrFeedback to make sure that just cannot
happen.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1137
(cherry picked from commit ab76272a7d)
2021-02-17 11:55:19 +00:00
Olivier Fourdan 4d2128fd1d xwayland: Use relative device for buttons/axis/enter/leave
We are using the relative pointer for motion events, but buttons and
axis events still go through the absolute pointer device.

That means additional DeviceChanged events that could be avoided if the
buttons and axis events were coming from the same device as motion
events.

However, routing just the buttons and axis events is not sufficient. In
Weston, clicking the window decoration of an Xwayland client gives us a
wl_pointer.button event immediately followed by a wl_pointer.leave event.
The leave event does not contain any button state information, so the button
remains logically down in the DIX.

Once the pointer button is released, a wl_pointer.enter event is sent with
the current button state (zero). This needs to trigger a ButtonRelease event
but for that we need to ensure that the device is the same as the one we send
ButtonPress events through.

Route those events along with enter/leave events to the relative pointer
if available so that motion, buttons and axis events come from the same
device (most of the time).

Suggested-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Olivier Fourdan <ofourdan@redhat.com>
Related: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1130
(cherry picked from commit a4095162ca)
(cherry picked from commit 20c78f38a0)
2021-02-17 10:16:43 +01:00
Olivier Fourdan 49c479a7c3 xwayland: Add wheel axis to relative pointer
The relative pointer only has 2 axis, if we want to route the mouse
wheel events to that device, we need to add the axis definition, similar
to what is done for the absolute pointer.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Related: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1130
(cherry picked from commit 1abab61dc2)
2021-02-17 10:16:43 +01:00
Olivier Fourdan c3f86d2868 xwayland: Split dispatch_pointer_motion_event
This is a cleanup patch, no functional change.

Split the function dispatch_pointer_motion_event() into three separate
simpler functions, relative motion with a warp emulator, relative motion
and absolute motion.

This makes the code a lot easier to read for me, rather than having
everything in a single function with nested if/else conditions.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit 7181792824)
2021-02-17 10:16:43 +01:00
Olivier Fourdan 2e212551d6 xwayland: Use relative values for raw events
Xwayland supports relative motion events from the Wayland compositor via
the relative-pointer protocol, and converts those to the absolute range
in device units for raw events.

Some X11 clients however wrongly assume relative values in the axis
values even for devices explicitly labeled as absolute. While this is a
bug in the client, such applications would work fine in plain Xorg but
not with Xwayland.

To avoid that issue, use the relative values for raw events without
conversion, so that such application continue to work in Xwayland.

Thanks Peter for figuring out the root cause.

v2: Don't duplicate relative and absolute events (Peter)
v3: Use POINTER_RAWONLY (Peter)

Suggested-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1130
(cherry picked from commit c5c5322ad6)
2021-02-17 10:16:43 +01:00
Olivier Fourdan 7531d71663 xwayland: Use a resolution of 0 for relative motion
That's what evdev/libinput drivers do.

Suggested-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Related: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1130
(cherry picked from commit ebdb2e2646)
2021-02-17 10:16:43 +01:00
Olivier Fourdan 0663a245ad dix: Add POINTER_RAWONLY flag
This add a new flag POINTER_RAWONLY for GetPointerEvents() which does
pretty much the opposite of POINTER_NORAW.

Basically, this tells GetPointerEvents() that we only want the
DeviceChanged events and any raw events for this motion but no actual
motion events.

This is preliminary work for Xwayland to be able to use relative motion
events for raw events. Xwayland would use absolute events for raw
events, but some X11 clients (wrongly) assume raw events to be always
relative.

To allow such clients to work with Xwayland, it needs to switch to
relative raw events (if those are available from the Wayland
compositor).

However, Xwayland cannot use relative motion events for actual pointer
location because that would cause a drift over time, the pointer being
actually controlled by the Wayland compositor.

So Xwayland needs to be able to send only relative raw events, hence
this API.

Bump the ABI_XINPUT_VERSION minor version to reflect that API addition.

v2: Actually avoid sending motion events (Peter)
v3: Keep sending raw emulated events with RAWONLY (Peter)

Suggested-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Related: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1130
(cherry picked from commit b5e1f13681)
2021-02-17 10:16:43 +01:00
Michel Dänzer 1e72c3ce84 Bump version to 21.0.99.1
Preparation for a 21.1 release.
2021-02-03 18:26:42 +01:00
Michel Dänzer 001f0c8938 meson: Change project name to xwayland 2021-02-03 18:26:20 +01:00
Michel Dänzer 0408fcb329 Don't install Xvfb
We're keeping it for unit tests, but we don't want to ship it from this
branch.

Also disable Xvfb in CI for ninja test. It's still built and used for
unit tests as part of ninja dist, but we don't want to run XTS on Xvfb.
2021-02-03 18:22:18 +01:00
Michel Dänzer 274d54d1c3 meson: Build Xwayland unconditionally 2021-02-03 18:21:08 +01:00
Michel Dänzer be7257c5d1 Drop miext/shadow directory
Not used on this branch.
2021-02-03 18:17:09 +01:00
Michel Dänzer aa49cd5ab7 Drop EXA code
Not used on this branch.
2021-02-03 18:16:34 +01:00
Michel Dänzer 23296633bb Drop config directory
Not used anymore on this branch.
2021-02-03 18:15:10 +01:00
Michel Dänzer 9335ee7994 Drop Xephyr / kdrive DDX 2021-02-03 18:13:15 +01:00
Michel Dänzer 4f4b8e00fc Drop Xorg DDX 2021-02-03 18:10:48 +01:00
Michel Dänzer 8f480147f6 Drop Xwin DDX 2021-02-03 18:08:58 +01:00
Michel Dänzer 69cc6a6caa Drop Xnest DDX 2021-02-03 18:01:50 +01:00
Michel Dänzer 6cae4b397d Drop Xquartz DDX 2021-02-03 18:00:43 +01:00
Michel Dänzer f8a6a7b265 Drop DMX DDX 2021-02-03 18:00:04 +01:00
Michel Dänzer 9de9c31273 Drop autotools build system
Only meson is supported for Xwayland-only releases.
2021-02-03 17:59:31 +01:00
1100 changed files with 969 additions and 408915 deletions

View File

@ -29,7 +29,6 @@ pkg-config,\
python3,\
windowsdriproto,\
xorgproto,\
libdmx-devel,\
libepoxy-devel,\
libfontenc-devel,\
libfreetype-devel,\
@ -73,7 +72,7 @@ cache:
- '%CYGWIN_ROOT%\home\%USERNAME%\.ccache'
build_script:
- SET PATH=%CYGWIN_ROOT%/bin
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; meson setup --prefix=/usr -Dxv=false -Dxf86bigfont=true -Ddmx=true -Dxephyr=true -Dxnest=true -Dxvfb=true -Dxwin=true -Dxorg=true -Dhal=false -Dudev=false -Dpciaccess=false -Dint10=false build"'
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; meson setup --prefix=/usr -Dxv=false -Dxf86bigfont=true -Dxvfb=true build"'
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; meson configure build"'
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; ninja -C build"'
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; ccache -s"'

View File

@ -59,21 +59,10 @@ debian-buster:
after_script:
- ccache --show-stats
autotools:
extends: .common-build-and-test
script:
- mkdir build/
- cd build/
- ../autogen.sh --prefix=/usr CFLAGS="-fno-common"
- make -j${FDO_CI_CONCURRENT:-4} distcheck
- PIGLIT_DIR=/root/piglit XTEST_DIR=/root/xts make -j${FDO_CI_CONCURRENT:-4} check
- cd ..
- .gitlab-ci/manpages-check
meson:
extends: .common-build-and-test
script:
- meson -Dc_args="-fno-common" -Dprefix=/usr -Dxephyr=true -Dwerror=true $MESON_EXTRA_OPTIONS build/
- meson -Dc_args="-fno-common" -Dprefix=/usr -Dxvfb=false -Dwerror=true $MESON_EXTRA_OPTIONS build/
- ninja -j${FDO_CI_CONCURRENT:-4} -C build/ dist
- PIGLIT_DIR=/root/piglit XTEST_DIR=/root/xts ninja -j${FDO_CI_CONCURRENT:-4} -C build/ test
- .gitlab-ci/manpages-check

View File

@ -1,27 +0,0 @@
language: c
cache:
ccache: true
directories:
- $HOME/Library/Caches/Homebrew
branches:
except:
- /appveyor.*/
os: osx
osx_image: xcode9.2
matrix:
include:
- env: TOOL=meson
- env: TOOL=autotools
install:
- brew update
- HOMEBREW_NO_AUTO_UPDATE=1 brew install ccache meson
script:
- ./test/scripts/build-travis-osx.sh $TOOL
- ccache -s
before_cache:
- brew cleanup

View File

@ -1,215 +0,0 @@
AUTOMAKE_OPTIONS=nostdinc
# Required for automake < 1.14
ACLOCAL_AMFLAGS = -I m4
if COMPOSITE
COMPOSITE_DIR=composite
endif
if GLX
GLX_DIR=glx
endif
if DBE
DBE_DIR=dbe
endif
if RECORD
RECORD_DIR=record
endif
if DRI3
DRI3_DIR=dri3
endif
if PRESENT
PRESENT_DIR=present
endif
if PSEUDORAMIX
PSEUDORAMIX_DIR=pseudoramiX
endif
if GLAMOR
GLAMOR_DIR=glamor
endif
SUBDIRS = \
doc \
man \
include \
dix \
fb \
mi \
Xext \
miext \
os \
randr \
render \
Xi \
xkb \
$(PSEUDORAMIX_DIR) \
$(DBE_DIR) \
$(RECORD_DIR) \
xfixes \
damageext \
$(COMPOSITE_DIR) \
$(GLX_DIR) \
$(PRESENT_DIR) \
$(DRI3_DIR) \
exa \
$(GLAMOR_DIR) \
config \
hw \
test
if XORG
aclocaldir = $(datadir)/aclocal
aclocal_DATA = xorg-server.m4
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = xorg-server.pc
endif
EXTRA_DIST = xorg-server.pc.in xorg-server.m4 autogen.sh README.md
DISTCHECK_CONFIGURE_FLAGS=\
--with-xkb-path=$(XKB_BASE_DIRECTORY) \
--with-xkb-bin-directory=$(XKB_BIN_DIRECTORY) \
--with-xkb-output='$${datadir}/X11/xkb/compiled'
.PHONY: ChangeLog INSTALL
INSTALL:
$(INSTALL_CMD)
ChangeLog:
$(CHANGELOG_CMD)
dist-hook: ChangeLog INSTALL
DIST_SUBDIRS = \
doc \
man \
include \
dix \
fb \
mi \
Xext \
miext \
os \
pseudoramiX \
randr \
render \
Xi \
xkb \
dbe \
record \
xfixes \
damageext \
composite \
glx \
exa \
glamor \
config \
dri3 \
present \
hw \
test
# gross hack
relink: all
$(AM_V_at)$(MAKE) -C hw relink
install-headers: Makefile
+find . -name Makefile | while read m; do \
if grep -q install-sdkHEADERS $$m; then \
(cd `dirname "$$m"` && make install-sdkHEADERS) \
fi \
done
distcheck-hook:
cd $(srcdir) && \
meson setup _distcheck_build && \
meson configure _distcheck_build && \
ninja -C _distcheck_build && \
rm -rf _distcheck_build && \
cd -
EXTRA_DIST += \
meson_options.txt \
include/xorg-config.h.meson.in \
include/xwin-config.h.meson.in \
hw/xfree86/loader/symbol-test.c \
composite/meson.build \
config/meson.build \
damageext/meson.build \
dbe/meson.build \
dix/meson.build \
dri3/meson.build \
exa/meson.build \
fb/meson.build \
glamor/meson.build \
glx/meson.build \
hw/dmx/config/meson.build \
hw/dmx/examples/meson.build \
hw/dmx/glxProxy/meson.build \
hw/dmx/input/meson.build \
hw/dmx/meson.build \
hw/kdrive/ephyr/meson.build \
hw/kdrive/meson.build \
hw/kdrive/src/meson.build \
hw/meson.build \
hw/vfb/meson.build \
hw/xfree86/common/meson.build \
hw/xfree86/ddc/meson.build \
hw/xfree86/dixmods/meson.build \
hw/xfree86/dri2/meson.build \
hw/xfree86/dri/meson.build \
hw/xfree86/drivers/modesetting/meson.build \
hw/xfree86/exa/meson.build \
hw/xfree86/fbdevhw/meson.build \
hw/xfree86/glamor_egl/meson.build \
hw/xfree86/i2c/meson.build \
hw/xfree86/int10/meson.build \
hw/xfree86/loader/meson.build \
hw/xfree86/meson.build \
hw/xfree86/modes/meson.build \
hw/xfree86/os-support/meson.build \
hw/xfree86/parser/meson.build \
hw/xfree86/ramdac/meson.build \
hw/xfree86/shadowfb/meson.build \
hw/xfree86/vgahw/meson.build \
hw/xfree86/x86emu/meson.build \
hw/xfree86/xkb/meson.build \
hw/xnest/meson.build \
hw/xquartz/meson.build \
hw/xwayland/meson.build \
hw/xwin/dri/meson.build \
hw/xwin/glx/meson.build \
hw/xwin/meson.build \
hw/xwin/winclipboard/meson.build \
include/meson.build \
meson.build \
miext/damage/meson.build \
miext/shadow/meson.build \
miext/sync/meson.build \
mi/meson.build \
os/meson.build \
present/meson.build \
pseudoramiX/meson.build \
randr/meson.build \
record/meson.build \
render/meson.build \
test/bigreq/meson.build \
test/bigreq/request-length.c \
test/meson.build \
test/sync/meson.build \
test/sync/sync.c \
Xext/meson.build \
xfixes/meson.build \
Xi/meson.build \
xkb/meson.build
DISTCLEANFILES = buildDateTime.h

View File

@ -1,120 +0,0 @@
noinst_LTLIBRARIES = libXext.la libXvidmode.la libhashtable.la
AM_CFLAGS = $(DIX_CFLAGS)
if XORG
sdk_HEADERS = xvdix.h xvmcext.h geext.h geint.h shmint.h syncsdk.h
endif
# Sources always included in libXextbuiltin.la, libXext.la
BUILTIN_SRCS = \
bigreq.c \
geext.c \
shape.c \
sleepuntil.c \
sleepuntil.h \
sync.c \
syncsdk.h \
syncsrv.h \
xcmisc.c \
xtest.c
BUILTIN_LIBS =
# Optional sources included if extension enabled by configure.ac rules
# MIT Shared Memory extension
MITSHM_SRCS = shm.c shmint.h
if MITSHM
BUILTIN_SRCS += $(MITSHM_SRCS)
endif
# XVideo extension
XV_SRCS = xvmain.c xvdisp.c xvmc.c xvdix.h xvmcext.h xvdisp.h
if XV
BUILTIN_SRCS += $(XV_SRCS)
endif
# XResource extension: lets clients get data about per-client resource usage
RES_SRCS = xres.c
if RES
BUILTIN_SRCS += $(RES_SRCS)
endif
# MIT ScreenSaver extension
SCREENSAVER_SRCS = saver.c
if SCREENSAVER
BUILTIN_SRCS += $(SCREENSAVER_SRCS)
endif
# Xinerama extension: making multiple video devices act as one virtual screen
XINERAMA_SRCS = panoramiX.c panoramiX.h panoramiXh.h panoramiXsrv.h panoramiXprocs.c panoramiXSwap.c
if XINERAMA
BUILTIN_SRCS += $(XINERAMA_SRCS)
if XORG
sdk_HEADERS += panoramiXsrv.h panoramiX.h
endif
endif
# X-ACE extension: provides hooks for building security policy extensions
# like XC-Security, X-SELinux & XTSol
XACE_SRCS = xace.c xace.h xacestr.h
if XACE
BUILTIN_SRCS += $(XACE_SRCS)
if XORG
sdk_HEADERS += xace.h xacestr.h
endif
endif
# SELinux extension: provides SELinux policy support for X objects
# requires X-ACE extension
XSELINUX_SRCS = xselinux_ext.c xselinux_hooks.c xselinux_label.c xselinux.h xselinuxint.h
if XSELINUX
BUILTIN_SRCS += $(XSELINUX_SRCS)
BUILTIN_LIBS += $(SELINUX_LIBS)
endif
# Security extension: multi-level security to protect clients from each other
XCSECURITY_SRCS = security.c securitysrv.h
if XCSECURITY
BUILTIN_SRCS += $(XCSECURITY_SRCS)
endif
# XF86 Big Font extension
BIGFONT_SRCS = xf86bigfont.c xf86bigfontsrv.h
if XF86BIGFONT
BUILTIN_SRCS += $(BIGFONT_SRCS)
endif
# DPMS extension
DPMS_SRCS = dpms.c dpmsproc.h
if DPMSExtension
BUILTIN_SRCS += $(DPMS_SRCS)
endif
# Now take all of the above, mix well, bake for 10 minutes and get libXext*.la
libXext_la_SOURCES = $(BUILTIN_SRCS)
libXext_la_LIBADD = $(BUILTIN_LIBS)
if RES
libXext_la_LIBADD += libhashtable.la
endif
# XVidMode extension
libXvidmode_la_SOURCES = vidmode.c
#Hashtable
libhashtable_la_SOURCES = hashtable.c hashtable.h
EXTRA_DIST = \
$(MITSHM_SRCS) \
$(XV_SRCS) \
$(RES_SRCS) \
$(SCREENSAVER_SRCS) \
$(XACE_SRCS) \
$(XCSECURITY_SRCS) \
$(XSELINUX_SRCS) \
$(XINERAMA_SRCS) \
$(BIGFONT_SRCS) \
$(DPMS_SRCS) \
$(GE_SRCS)

View File

@ -73,5 +73,3 @@ libxserver_xext_vidmode = static_library('libxserver_xext_vidmode',
include_directories: inc,
dependencies: common_dep,
)
install_data(hdrs_xext, install_dir: xorgsdkdir)

View File

@ -1,111 +0,0 @@
noinst_LTLIBRARIES = libXi.la libXistubs.la
AM_CFLAGS = $(DIX_CFLAGS)
libXi_la_SOURCES = \
allowev.c \
allowev.h \
chgdctl.c \
chgdctl.h \
chgfctl.c \
chgfctl.h \
chgkbd.c \
chgkbd.h \
chgkmap.c \
chgkmap.h \
chgprop.c \
chgprop.h \
chgptr.c \
chgptr.h \
closedev.c \
closedev.h \
devbell.c \
devbell.h \
exevents.c \
exglobals.h \
extinit.c \
getbmap.c \
getbmap.h \
getdctl.c \
getdctl.h \
getfctl.c \
getfctl.h \
getfocus.c \
getfocus.h \
getkmap.c \
getkmap.h \
getmmap.c \
getmmap.h \
getprop.c \
getprop.h \
getselev.c \
getselev.h \
getvers.c \
getvers.h \
grabdev.c \
grabdev.h \
grabdevb.c \
grabdevb.h \
grabdevk.c \
grabdevk.h \
gtmotion.c \
gtmotion.h \
listdev.c \
listdev.h \
opendev.c \
opendev.h \
queryst.c \
queryst.h \
selectev.c \
selectev.h \
sendexev.c \
sendexev.h \
setbmap.c \
setbmap.h \
setdval.c \
setdval.h \
setfocus.c \
setfocus.h \
setmmap.c \
setmmap.h \
setmode.c \
setmode.h \
ungrdev.c \
ungrdev.h \
ungrdevb.c \
ungrdevb.h \
ungrdevk.c \
ungrdevk.h \
xiallowev.c \
xiallowev.h \
xibarriers.c \
xibarriers.h \
xichangecursor.c \
xichangecursor.h \
xichangehierarchy.c \
xichangehierarchy.h \
xigetclientpointer.c \
xigetclientpointer.h \
xigrabdev.c \
xigrabdev.h \
xipassivegrab.h \
xipassivegrab.c \
xiproperty.c \
xiproperty.h \
xiquerydevice.c \
xiquerydevice.h \
xiquerypointer.c \
xiquerypointer.h \
xiqueryversion.c \
xiqueryversion.h \
xiselectev.c \
xiselectev.h \
xisetclientpointer.c \
xisetclientpointer.h \
xisetdevfocus.c \
xisetdevfocus.h \
xiwarppointer.c \
xiwarppointer.h
libXistubs_la_SOURCES = \
stubs.c

View File

@ -464,8 +464,11 @@ ProcXChangeFeedbackControl(ClientPtr client)
break;
case StringFeedbackClass:
{
xStringFeedbackCtl *f = ((xStringFeedbackCtl *) &stuff[1]);
xStringFeedbackCtl *f;
REQUEST_AT_LEAST_EXTRA_SIZE(xChangeFeedbackControlReq,
sizeof(xStringFeedbackCtl));
f = ((xStringFeedbackCtl *) &stuff[1]);
if (client->swapped) {
if (len < bytes_to_int32(sizeof(xStringFeedbackCtl)))
return BadLength;

View File

@ -1,17 +0,0 @@
#! /bin/sh
srcdir=`dirname "$0"`
test -z "$srcdir" && srcdir=.
ORIGDIR=`pwd`
cd "$srcdir"
autoreconf --force -v --install || exit 1
cd "$ORIGDIR" || exit $?
git config --local --get format.subjectPrefix ||
git config --local format.subjectPrefix "PATCH xserver"
if test -z "$NOCONFIGURE"; then
exec "$srcdir"/configure "$@"
fi

View File

@ -1,15 +0,0 @@
noinst_LTLIBRARIES = libcomposite.la
AM_CFLAGS = $(DIX_CFLAGS)
if XORG
sdk_HEADERS = compositeext.h
endif
libcomposite_la_SOURCES = \
compalloc.c \
compext.c \
compint.h \
compinit.c \
compoverlay.c \
compwindow.c

View File

@ -15,5 +15,3 @@ libxserver_composite = static_library('libxserver_composite',
include_directories: inc,
dependencies: common_dep,
)
install_data(hdrs_composite, install_dir: xorgsdkdir)

View File

@ -1,38 +0,0 @@
# Collection of quirks and blacklist/whitelists for specific devices.
# Accelerometer device, posts data through ABS_X/ABS_Y, making X unusable
# http://bugs.freedesktop.org/show_bug.cgi?id=22442
Section "InputClass"
Identifier "ThinkPad HDAPS accelerometer blacklist"
MatchProduct "ThinkPad HDAPS accelerometer data"
Option "Ignore" "on"
EndSection
# https://bugzilla.redhat.com/show_bug.cgi?id=523914
# Mouse does not move in PV Xen guest
# Explicitly tell evdev to not ignore the absolute axes.
Section "InputClass"
Identifier "Xen Virtual Pointer axis blacklist"
MatchProduct "Xen Virtual Pointer"
Option "IgnoreAbsoluteAxes" "off"
Option "IgnoreRelativeAxes" "off"
EndSection
# https://bugs.freedesktop.org/show_bug.cgi?id=55867
# Bug 55867 - Doesn't know how to tag XI_TRACKBALL
Section "InputClass"
Identifier "Tag trackballs as XI_TRACKBALL"
MatchProduct "trackball"
MatchDriver "evdev"
Option "TypeName" "TRACKBALL"
EndSection
# https://bugs.freedesktop.org/show_bug.cgi?id=62831
# Bug 62831 - Mionix Naos 5000 mouse detected incorrectly
Section "InputClass"
Identifier "Tag Mionix Naos 5000 mouse XI_MOUSE"
MatchProduct "La-VIEW Technology Naos 5000 Mouse"
MatchDriver "evdev"
Option "TypeName" "MOUSE"
EndSection

View File

@ -1,41 +0,0 @@
AM_CFLAGS = $(DIX_CFLAGS)
noinst_LTLIBRARIES = libconfig.la
libconfig_la_SOURCES = config.c config-backends.h
libconfig_la_LIBADD =
if NEED_DBUS
AM_CFLAGS += $(DBUS_CFLAGS)
libconfig_la_SOURCES += dbus-core.c
libconfig_la_LIBADD += $(DBUS_LIBS)
endif
if CONFIG_UDEV
AM_CFLAGS += $(UDEV_CFLAGS)
libconfig_la_SOURCES += udev.c
libconfig_la_LIBADD += $(UDEV_LIBS)
if XORG
xorgconfddir = $(datadir)/X11/$(XF86CONFIGDIR)
xorgconfd_DATA = 10-quirks.conf
endif
else
if CONFIG_HAL
AM_CFLAGS += $(HAL_CFLAGS)
libconfig_la_SOURCES += hal.c
libconfig_la_LIBADD += $(HAL_LIBS)
else
if CONFIG_WSCONS
libconfig_la_SOURCES += wscons.c
endif # CONFIG_WSCONS
endif # !CONFIG_HAL
endif # !CONFIG_UDEV
EXTRA_DIST = x11-input.fdi fdi2iclass.py 10-quirks.conf

View File

@ -1,46 +0,0 @@
/*
* Copyright © 2006-2007 Daniel Stone
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Author: Daniel Stone <daniel@fooishbar.org>
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "input.h"
#include "list.h"
void remove_devices(const char *backend, const char *config_info);
BOOL device_is_duplicate(const char *config_info);
#ifdef CONFIG_UDEV
int config_udev_pre_init(void);
int config_udev_init(void);
void config_udev_fini(void);
void config_udev_odev_probe(config_odev_probe_proc_ptr probe_callback);
#elif defined(CONFIG_HAL)
int config_hal_init(void);
void config_hal_fini(void);
#elif defined(CONFIG_WSCONS)
int config_wscons_init(void);
void config_wscons_fini(void);
#endif

View File

@ -1,151 +0,0 @@
/*
* Copyright © 2006-2007 Daniel Stone
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Author: Daniel Stone <daniel@fooishbar.org>
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <unistd.h>
#include "os.h"
#include "inputstr.h"
#include "hotplug.h"
#include "config-backends.h"
#include "systemd-logind.h"
void
config_pre_init(void)
{
#ifdef CONFIG_UDEV
if (!config_udev_pre_init())
ErrorF("[config] failed to pre-init udev\n");
#endif
}
void
config_init(void)
{
#ifdef CONFIG_UDEV
if (!config_udev_init())
ErrorF("[config] failed to initialise udev\n");
#elif defined(CONFIG_HAL)
if (!config_hal_init())
ErrorF("[config] failed to initialise HAL\n");
#elif defined(CONFIG_WSCONS)
if (!config_wscons_init())
ErrorF("[config] failed to initialise wscons\n");
#endif
}
void
config_fini(void)
{
#if defined(CONFIG_UDEV)
config_udev_fini();
#elif defined(CONFIG_HAL)
config_hal_fini();
#elif defined(CONFIG_WSCONS)
config_wscons_fini();
#endif
}
void
config_odev_probe(config_odev_probe_proc_ptr probe_callback)
{
#if defined(CONFIG_UDEV_KMS)
config_udev_odev_probe(probe_callback);
#endif
}
static void
remove_device(const char *backend, DeviceIntPtr dev)
{
/* this only gets called for devices that have already been added */
LogMessage(X_INFO, "config/%s: removing device %s\n", backend, dev->name);
/* Call PIE here so we don't try to dereference a device that's
* already been removed. */
input_lock();
ProcessInputEvents();
DeleteInputDeviceRequest(dev);
input_unlock();
}
void
remove_devices(const char *backend, const char *config_info)
{
DeviceIntPtr dev, next;
for (dev = inputInfo.devices; dev; dev = next) {
next = dev->next;
if (dev->config_info && strcmp(dev->config_info, config_info) == 0)
remove_device(backend, dev);
}
for (dev = inputInfo.off_devices; dev; dev = next) {
next = dev->next;
if (dev->config_info && strcmp(dev->config_info, config_info) == 0)
remove_device(backend, dev);
}
RemoveInputDeviceTraces(config_info);
}
BOOL
device_is_duplicate(const char *config_info)
{
DeviceIntPtr dev;
for (dev = inputInfo.devices; dev; dev = dev->next) {
if (dev->config_info && (strcmp(dev->config_info, config_info) == 0))
return TRUE;
}
for (dev = inputInfo.off_devices; dev; dev = dev->next) {
if (dev->config_info && (strcmp(dev->config_info, config_info) == 0))
return TRUE;
}
return FALSE;
}
struct OdevAttributes *
config_odev_allocate_attributes(void)
{
struct OdevAttributes *attribs =
xnfcalloc(1, sizeof (struct OdevAttributes));
attribs->fd = -1;
return attribs;
}
void
config_odev_free_attributes(struct OdevAttributes *attribs)
{
if (attribs->fd != -1)
systemd_logind_release_fd(attribs->major, attribs->minor, attribs->fd);
free(attribs->path);
free(attribs->syspath);
free(attribs->busid);
free(attribs->driver);
free(attribs);
}

View File

@ -1,40 +0,0 @@
D-BUS Configuration API v2
----------------------------
The X server will register the bus name org.x.config.displayN, and the
object /org/x/config/N, where N is the display number.
Currently only hotplugging of input devices is supported.
org.x.config.input:
org.x.config.input.version:
Returns one unsigned int32, which is the API version.
org.x.config.input.add:
Takes an argument of key/value option pairs in arrays, e.g.:
[ss][ss][ss][ss]
is the signature for four options. These options will be passed
to the input driver as with any others.
Option names beginning with _ are not allowed; they are reserved
for internal use.
Returns a number of signed int32s. Positive integers are the
device IDs of new devices; negative numbers are X error codes,
as defined in X.h. BadMatch will be returned if the options
given do not match any device. BadValue is returned for a malformed
message. (Example: 8 is new device ID 8; -8 is BadMatch.)
Notably, BadAlloc is never returned: the server internally signals
to D-BUS that the attempt failed for lack of memory.
org.x.config.input.remove:
Takes one uint32 argument, which is the device ID to remove, i.e.:
u
is the signature.
Returns one signed int32 which represents an X status as defined in
X.h. See org.x.config.input.add. Error codes are negative numbers.
org.x.config.input.listDevices:
Lists the currently active devices. No argument.
Return value is sequence of [<id> <name>] [<id> <name>] ..., i.e. [us].

View File

@ -1,238 +0,0 @@
/*
* Copyright © 2006-2007 Daniel Stone
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Author: Daniel Stone <daniel@fooishbar.org>
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <dbus/dbus.h>
#include <sys/select.h>
#include "dix.h"
#include "os.h"
#include "dbus-core.h"
/* How often to attempt reconnecting when we get booted off the bus. */
#define RECONNECT_DELAY (10 * 1000) /* in ms */
struct dbus_core_info {
int fd;
DBusConnection *connection;
OsTimerPtr timer;
struct dbus_core_hook *hooks;
};
static struct dbus_core_info bus_info = { .fd = -1 };
static CARD32 reconnect_timer(OsTimerPtr timer, CARD32 time, void *arg);
static void
socket_handler(int fd, int ready, void *data)
{
struct dbus_core_info *info = data;
if (info->connection) {
do {
dbus_connection_read_write_dispatch(info->connection, 0);
} while (info->connection &&
dbus_connection_get_is_connected(info->connection) &&
dbus_connection_get_dispatch_status(info->connection) ==
DBUS_DISPATCH_DATA_REMAINS);
}
}
/**
* Disconnect (if we haven't already been forcefully disconnected), clean up
* after ourselves, and call all registered disconnect hooks.
*/
static void
teardown(void)
{
struct dbus_core_hook *hook;
if (bus_info.timer) {
TimerFree(bus_info.timer);
bus_info.timer = NULL;
}
/* We should really have pre-disconnect hooks and run them here, for
* completeness. But then it gets awkward, given that you can't
* guarantee that they'll be called ... */
if (bus_info.connection)
dbus_connection_unref(bus_info.connection);
if (bus_info.fd != -1)
RemoveNotifyFd(bus_info.fd);
bus_info.fd = -1;
bus_info.connection = NULL;
for (hook = bus_info.hooks; hook; hook = hook->next) {
if (hook->disconnect)
hook->disconnect(hook->data);
}
}
/**
* This is a filter, which only handles the disconnected signal, which
* doesn't go to the normal message handling function. This takes
* precedence over the message handling function, so have have to be
* careful to ignore anything we don't want to deal with here.
*/
static DBusHandlerResult
message_filter(DBusConnection * connection, DBusMessage * message, void *data)
{
/* If we get disconnected, then take everything down, and attempt to
* reconnect immediately (assuming it's just a restart). The
* connection isn't valid at this point, so throw it out immediately. */
if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
DebugF("[dbus-core] disconnected from bus\n");
bus_info.connection = NULL;
teardown();
if (bus_info.timer)
TimerFree(bus_info.timer);
bus_info.timer = TimerSet(NULL, 0, 1, reconnect_timer, NULL);
return DBUS_HANDLER_RESULT_HANDLED;
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
/**
* Attempt to connect to the system bus, and set a filter to deal with
* disconnection (see message_filter above).
*
* @return 1 on success, 0 on failure.
*/
static int
connect_to_bus(void)
{
DBusError error;
struct dbus_core_hook *hook;
dbus_error_init(&error);
bus_info.connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
if (!bus_info.connection || dbus_error_is_set(&error)) {
LogMessage(X_ERROR, "dbus-core: error connecting to system bus: %s (%s)\n",
error.name, error.message);
goto err_begin;
}
/* Thankyou. Really, thankyou. */
dbus_connection_set_exit_on_disconnect(bus_info.connection, FALSE);
if (!dbus_connection_get_unix_fd(bus_info.connection, &bus_info.fd)) {
ErrorF("[dbus-core] couldn't get fd for system bus\n");
goto err_unref;
}
if (!dbus_connection_add_filter(bus_info.connection, message_filter,
&bus_info, NULL)) {
ErrorF("[dbus-core] couldn't add filter: %s (%s)\n", error.name,
error.message);
goto err_fd;
}
dbus_error_free(&error);
SetNotifyFd(bus_info.fd, socket_handler, X_NOTIFY_READ, &bus_info);
for (hook = bus_info.hooks; hook; hook = hook->next) {
if (hook->connect)
hook->connect(bus_info.connection, hook->data);
}
return 1;
err_fd:
bus_info.fd = -1;
err_unref:
dbus_connection_unref(bus_info.connection);
bus_info.connection = NULL;
err_begin:
dbus_error_free(&error);
return 0;
}
static CARD32
reconnect_timer(OsTimerPtr timer, CARD32 time, void *arg)
{
if (connect_to_bus()) {
TimerFree(bus_info.timer);
bus_info.timer = NULL;
return 0;
}
else {
return RECONNECT_DELAY;
}
}
int
dbus_core_add_hook(struct dbus_core_hook *hook)
{
struct dbus_core_hook **prev;
for (prev = &bus_info.hooks; *prev; prev = &(*prev)->next);
hook->next = NULL;
*prev = hook;
/* If we're already connected, call the connect hook. */
if (bus_info.connection)
hook->connect(bus_info.connection, hook->data);
return 1;
}
void
dbus_core_remove_hook(struct dbus_core_hook *hook)
{
struct dbus_core_hook **prev;
for (prev = &bus_info.hooks; *prev; prev = &(*prev)->next) {
if (*prev == hook) {
*prev = hook->next;
break;
}
}
}
int
dbus_core_init(void)
{
memset(&bus_info, 0, sizeof(bus_info));
bus_info.fd = -1;
bus_info.hooks = NULL;
if (!connect_to_bus())
bus_info.timer = TimerSet(NULL, 0, 1, reconnect_timer, NULL);
return 1;
}
void
dbus_core_fini(void)
{
teardown();
}

View File

@ -1,202 +0,0 @@
#!/usr/bin/python
#
# Convert xorg keys from hal FDIs files to xorg.conf InputClass sections.
# Modified from Martin Pitt's original fdi2mpi.py script:
# http://cgit.freedesktop.org/media-player-info/tree/tools/fdi2mpi.py
#
# (C) 2010 Dan Nicholson
# (C) 2009 Canonical Ltd.
# Author: Dan Nicholson <dbn.lists@gmail.com>
# Author: Martin Pitt <martin.pitt@ubuntu.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# fur- nished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FIT- NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
# NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import sys, xml.dom.minidom
# dict converting <match> tags to Match* entries
match_table = {
'info.product': 'MatchProduct',
'input.product': 'MatchProduct',
'info.vendor': 'MatchVendor',
'input.vendor': 'MatchVendor',
'info.device': 'MatchDevicePath',
'linux.device_file': 'MatchDevicePath',
'/org/freedesktop/Hal/devices/computer:system.kernel.name': 'MatchOS',
'@info.parent:pnp.id': 'MatchPnPID',
}
# dict converting info.capabilities list to Match* entries
cap_match_table = {
'input.keys': 'MatchIsKeyboard',
'input.keyboard': 'MatchIsKeyboard',
'input.keypad': 'MatchIsKeyboard',
'input.mouse': 'MatchIsPointer',
'input.joystick': 'MatchIsJoystick',
'input.tablet': 'MatchIsTablet',
'input.touchpad': 'MatchIsTouchpad',
'input.touchscreen': 'MatchIsTouchscreen',
}
def device_glob(path):
'''Convert a contains device path to a glob entry'''
if path[0] != '/':
path = '*' + path
return path + '*'
def parse_match(node):
'''Parse a <match> tag to a tuple with InputClass values'''
match = None
value = None
booltype = False
# see what type of key we have
if node.attributes.has_key('key'):
key = node.attributes['key'].nodeValue
if key in match_table:
match = match_table[key]
elif key == 'info.capabilities':
booltype = True
# bail out now if it's unrecognized
if not match and not booltype:
return (match, value)
if node.attributes.has_key('string'):
value = node.attributes['string'].nodeValue
elif node.attributes.has_key('contains'):
value = node.attributes['contains'].nodeValue
if match == 'MatchDevicePath':
value = device_glob(value)
elif booltype and value in cap_match_table:
match = cap_match_table[value]
value = 'yes'
elif node.attributes.has_key('string_outof'):
value = node.attributes['string_outof'].nodeValue.replace(';','|')
elif node.attributes.has_key('contains_outof'):
all_values = node.attributes['contains_outof'].nodeValue.split(';')
for v in all_values:
if match == 'MatchDevicePath':
v = device_glob(v)
elif match == 'MatchPnPID' and len(v) < 7:
v += '*'
if value:
value += '|' + v
else:
value = v
return (match, value)
def parse_options(node):
'''Parse the x11_* options and return InputClass entries'''
driver = ''
ignore = False
options = []
for n in node.childNodes:
if n.nodeType != xml.dom.minidom.Node.ELEMENT_NODE:
continue
tag = n.tagName
key = n.attributes['key'].nodeValue
value = ''
if n.hasChildNodes():
content_node = n.childNodes[0]
assert content_node.nodeType == xml.dom.Node.TEXT_NODE
value = content_node.nodeValue
if tag == 'match':
continue
assert tag in ('addset', 'merge', 'append', 'remove')
if tag == 'remove' and key == 'input.x11_driver':
ignore = True
elif key == 'input.x11_driver':
driver = value
elif key.startswith('input.x11_options.'):
option = key.split('.', 2)[2]
options.append((option, value))
return (driver, ignore, options)
def is_match_node(node):
'''Check if a node is a <match> element'''
return node.nodeType == xml.dom.minidom.Node.ELEMENT_NODE and \
node.tagName == 'match'
def parse_all_matches(node):
'''Parse a x11 match tag and any parents that don't supply their
own options'''
matches = []
while True:
(key, value) = parse_match(node)
if key and value:
matches.append((key, value))
# walk up to a parent match node
node = node.parentNode
if node == None or not is_match_node(node):
break
# leave if there other options at this level
children = set([n.tagName for n in node.childNodes
if n.nodeType == xml.dom.minidom.Node.ELEMENT_NODE])
if children & set(['addset', 'merge', 'append']):
break
return matches
# stupid counter to give "unique" rule names
num_sections = 1
def print_section(matches, driver, ignore, options):
'''Print a valid InputClass section to stdout'''
global num_sections
print 'Section "InputClass"'
print '\tIdentifier "Converted Class %d"' % num_sections
num_sections += 1
for m, v in matches:
print '\t%s "%s"' % (m, v)
if driver:
print '\tDriver "%s"' % driver
if ignore:
print '\tOption "Ignore" "yes"'
for o, v in options:
print '\tOption "%s" "%s"' % (o, v)
print 'EndSection'
def parse_fdi(fdi):
'''Parse x11 matches from fdi'''
# find all <match> leaf nodes
num = 0
for match_node in fdi.getElementsByTagName('match'):
children = set([n.tagName for n in match_node.childNodes
if n.nodeType == xml.dom.minidom.Node.ELEMENT_NODE])
# see if there are any options at this level
(driver, ignore, options) = parse_options(match_node)
if not driver and not ignore and not options:
continue
matches = parse_all_matches(match_node)
if num > 0:
print
print_section(matches, driver, ignore, options)
num += 1
for f in sys.argv[1:]:
parse_fdi(xml.dom.minidom.parse(f))

View File

@ -1,675 +0,0 @@
/*
* Copyright © 2007 Daniel Stone
* Copyright © 2007 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Author: Daniel Stone <daniel@fooishbar.org>
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <dbus/dbus.h>
#include <hal/libhal.h>
#include <string.h>
#include <sys/select.h>
#include "dbus-core.h"
#include "input.h"
#include "inputstr.h"
#include "hotplug.h"
#include "config-backends.h"
#include "os.h"
#define LIBHAL_PROP_KEY "input.x11_options."
#define LIBHAL_XKB_PROP_KEY "input.xkb."
struct config_hal_info {
DBusConnection *system_bus;
LibHalContext *hal_ctx;
};
/* Used for special handling of xkb options. */
struct xkb_options {
char *layout;
char *model;
char *rules;
char *variant;
char *options;
};
static void
device_removed(LibHalContext * ctx, const char *udi)
{
char *value;
if (asprintf(&value, "hal:%s", udi) == -1)
return;
remove_devices("hal", value);
free(value);
}
static char *
get_prop_string(LibHalContext * hal_ctx, const char *udi, const char *name)
{
char *prop, *ret;
prop = libhal_device_get_property_string(hal_ctx, udi, name, NULL);
LogMessageVerb(X_INFO, 10, "config/hal: getting %s on %s returned %s\n",
name, udi, prop ? prop : "(null)");
if (prop) {
ret = strdup(prop);
libhal_free_string(prop);
}
else {
return NULL;
}
return ret;
}
static char *
get_prop_string_array(LibHalContext * hal_ctx, const char *udi,
const char *prop)
{
char **props, *ret, *str;
int i, len = 0;
props = libhal_device_get_property_strlist(hal_ctx, udi, prop, NULL);
if (props) {
for (i = 0; props[i]; i++)
len += strlen(props[i]);
ret = calloc(sizeof(char), len + i); /* i - 1 commas, 1 NULL */
if (!ret) {
libhal_free_string_array(props);
return NULL;
}
str = ret;
for (i = 0; props[i]; i++) {
strcpy(str, props[i]);
str += strlen(props[i]);
*str++ = ',';
}
*(str - 1) = '\0';
libhal_free_string_array(props);
}
else {
return NULL;
}
return ret;
}
static void
device_added(LibHalContext * hal_ctx, const char *udi)
{
char *path = NULL, *driver = NULL, *name = NULL, *config_info = NULL;
char *hal_tags, *parent;
InputOption *input_options = NULL;
InputAttributes attrs = { 0 };
DeviceIntPtr dev = NULL;
DBusError error;
struct xkb_options xkb_opts = { 0 };
int rc;
LibHalPropertySet *set = NULL;
LibHalPropertySetIterator set_iter;
char *psi_key = NULL, *tmp_val;
dbus_error_init(&error);
driver = get_prop_string(hal_ctx, udi, "input.x11_driver");
if (!driver) {
/* verbose, don't tell the user unless they _want_ to see it */
LogMessageVerb(X_INFO, 7,
"config/hal: no driver specified for device %s\n", udi);
goto unwind;
}
path = get_prop_string(hal_ctx, udi, "input.device");
if (!path) {
LogMessage(X_WARNING,
"config/hal: no driver or path specified for %s\n", udi);
goto unwind;
}
attrs.device = strdup(path);
name = get_prop_string(hal_ctx, udi, "info.product");
if (!name)
name = strdup("(unnamed)");
else
attrs.product = strdup(name);
attrs.vendor = get_prop_string(hal_ctx, udi, "info.vendor");
hal_tags = get_prop_string(hal_ctx, udi, "input.tags");
attrs.tags = xstrtokenize(hal_tags, ",");
free(hal_tags);
if (libhal_device_query_capability(hal_ctx, udi, "input.keys", NULL))
attrs.flags |= ATTR_KEY | ATTR_KEYBOARD;
if (libhal_device_query_capability(hal_ctx, udi, "input.mouse", NULL))
attrs.flags |= ATTR_POINTER;
if (libhal_device_query_capability(hal_ctx, udi, "input.joystick", NULL))
attrs.flags |= ATTR_JOYSTICK;
if (libhal_device_query_capability(hal_ctx, udi, "input.tablet", NULL))
attrs.flags |= ATTR_TABLET;
if (libhal_device_query_capability(hal_ctx, udi, "input.tablet_pad", NULL))
attrs.flags |= ATTR_TABLET_PAD;
if (libhal_device_query_capability(hal_ctx, udi, "input.touchpad", NULL))
attrs.flags |= ATTR_TOUCHPAD;
if (libhal_device_query_capability(hal_ctx, udi, "input.touchscreen", NULL))
attrs.flags |= ATTR_TOUCHSCREEN;
parent = get_prop_string(hal_ctx, udi, "info.parent");
if (parent) {
int usb_vendor, usb_product;
char *old_parent;
/* construct USB ID in lowercase - "0000:ffff" */
usb_vendor = libhal_device_get_property_int(hal_ctx, parent,
"usb.vendor_id", NULL);
LogMessageVerb(X_INFO, 10,
"config/hal: getting usb.vendor_id on %s "
"returned %04x\n", parent, usb_vendor);
usb_product = libhal_device_get_property_int(hal_ctx, parent,
"usb.product_id", NULL);
LogMessageVerb(X_INFO, 10,
"config/hal: getting usb.product_id on %s "
"returned %04x\n", parent, usb_product);
if (usb_vendor && usb_product)
if (asprintf(&attrs.usb_id, "%04x:%04x", usb_vendor, usb_product)
== -1)
attrs.usb_id = NULL;
attrs.pnp_id = get_prop_string(hal_ctx, parent, "pnp.id");
old_parent = parent;
while (!attrs.pnp_id &&
(parent = get_prop_string(hal_ctx, parent, "info.parent"))) {
attrs.pnp_id = get_prop_string(hal_ctx, parent, "pnp.id");
free(old_parent);
old_parent = parent;
}
free(old_parent);
}
input_options = input_option_new(NULL, "_source", "server/hal");
if (!input_options) {
LogMessage(X_ERROR,
"config/hal: couldn't allocate first key/value pair\n");
goto unwind;
}
/* most drivers use device.. not path. evdev uses both however, but the
* path version isn't documented apparently. support both for now. */
input_options = input_option_new(input_options, "path", path);
input_options = input_option_new(input_options, "device", path);
input_options = input_option_new(input_options, "driver", driver);
input_options = input_option_new(input_options, "name", name);
if (asprintf(&config_info, "hal:%s", udi) == -1) {
config_info = NULL;
LogMessage(X_ERROR, "config/hal: couldn't allocate name\n");
goto unwind;
}
/* Check for duplicate devices */
if (device_is_duplicate(config_info)) {
LogMessage(X_WARNING,
"config/hal: device %s already added. Ignoring.\n", name);
goto unwind;
}
/* ok, grab options from hal.. iterate through all properties
* and lets see if any of them are options that we can add */
set = libhal_device_get_all_properties(hal_ctx, udi, &error);
if (!set) {
LogMessage(X_ERROR,
"config/hal: couldn't get property list for %s: %s (%s)\n",
udi, error.name, error.message);
goto unwind;
}
libhal_psi_init(&set_iter, set);
while (libhal_psi_has_more(&set_iter)) {
/* we are looking for supported keys.. extract and add to options */
psi_key = libhal_psi_get_key(&set_iter);
if (psi_key) {
/* normal options first (input.x11_options.<propname>) */
if (!strncasecmp
(psi_key, LIBHAL_PROP_KEY, sizeof(LIBHAL_PROP_KEY) - 1)) {
char *tmp;
/* only support strings for all values */
tmp_val = get_prop_string(hal_ctx, udi, psi_key);
if (tmp_val) {
/* xkb needs special handling. HAL specs include
* input.xkb.xyz options, but the x11-input.fdi specifies
* input.x11_options.Xkbxyz options. By default, we use
* the former, unless the specific X11 ones are specified.
* Since we can't predict the order in which the keys
* arrive, we need to store them.
*/
if ((tmp = strcasestr(psi_key, "xkb")) && strlen(tmp) >= 4) {
if (!strcasecmp(&tmp[3], "layout")) {
free(xkb_opts.layout);
xkb_opts.layout = strdup(tmp_val);
}
else if (!strcasecmp(&tmp[3], "model")) {
free(xkb_opts.model);
xkb_opts.model = strdup(tmp_val);
}
else if (!strcasecmp(&tmp[3], "rules")) {
free(xkb_opts.rules);
xkb_opts.rules = strdup(tmp_val);
}
else if (!strcasecmp(&tmp[3], "variant")) {
free(xkb_opts.variant);
xkb_opts.variant = strdup(tmp_val);
}
else if (!strcasecmp(&tmp[3], "options")) {
free(xkb_opts.options);
xkb_opts.options = strdup(tmp_val);
}
}
else {
/* all others */
input_options =
input_option_new(input_options,
psi_key + sizeof(LIBHAL_PROP_KEY) -
1, tmp_val);
free(tmp_val);
}
}
else {
/* server 1.4 had xkb_options as strlist. */
if ((tmp = strcasestr(psi_key, "xkb")) &&
(strlen(tmp) >= 4) &&
(!strcasecmp(&tmp[3], "options")) &&
(tmp_val =
get_prop_string_array(hal_ctx, udi, psi_key))) {
free(xkb_opts.options);
xkb_opts.options = strdup(tmp_val);
}
}
}
else if (!strncasecmp
(psi_key, LIBHAL_XKB_PROP_KEY,
sizeof(LIBHAL_XKB_PROP_KEY) - 1)) {
char *tmp;
/* only support strings for all values */
tmp_val = get_prop_string(hal_ctx, udi, psi_key);
if (tmp_val && strlen(psi_key) >= sizeof(LIBHAL_XKB_PROP_KEY)) {
tmp = &psi_key[sizeof(LIBHAL_XKB_PROP_KEY) - 1];
if (!strcasecmp(tmp, "layout")) {
if (!xkb_opts.layout)
xkb_opts.layout = strdup(tmp_val);
}
else if (!strcasecmp(tmp, "rules")) {
if (!xkb_opts.rules)
xkb_opts.rules = strdup(tmp_val);
}
else if (!strcasecmp(tmp, "variant")) {
if (!xkb_opts.variant)
xkb_opts.variant = strdup(tmp_val);
}
else if (!strcasecmp(tmp, "model")) {
if (!xkb_opts.model)
xkb_opts.model = strdup(tmp_val);
}
else if (!strcasecmp(tmp, "options")) {
if (!xkb_opts.options)
xkb_opts.options = strdup(tmp_val);
}
free(tmp_val);
}
else {
/* server 1.4 had xkb options as strlist */
tmp_val = get_prop_string_array(hal_ctx, udi, psi_key);
if (tmp_val &&
strlen(psi_key) >= sizeof(LIBHAL_XKB_PROP_KEY)) {
tmp = &psi_key[sizeof(LIBHAL_XKB_PROP_KEY) - 1];
if (!strcasecmp(tmp, ".options") && (!xkb_opts.options))
xkb_opts.options = strdup(tmp_val);
}
free(tmp_val);
}
}
}
/* psi_key doesn't need to be freed */
libhal_psi_next(&set_iter);
}
/* Now add xkb options */
if (xkb_opts.layout)
input_options =
input_option_new(input_options, "xkb_layout", xkb_opts.layout);
if (xkb_opts.rules)
input_options =
input_option_new(input_options, "xkb_rules", xkb_opts.rules);
if (xkb_opts.variant)
input_options =
input_option_new(input_options, "xkb_variant", xkb_opts.variant);
if (xkb_opts.model)
input_options =
input_option_new(input_options, "xkb_model", xkb_opts.model);
if (xkb_opts.options)
input_options =
input_option_new(input_options, "xkb_options", xkb_opts.options);
input_options = input_option_new(input_options, "config_info", config_info);
/* this isn't an error, but how else do you output something that the user can see? */
LogMessage(X_INFO, "config/hal: Adding input device %s\n", name);
if ((rc = NewInputDeviceRequest(input_options, &attrs, &dev)) != Success) {
LogMessage(X_ERROR, "config/hal: NewInputDeviceRequest failed (%d)\n",
rc);
dev = NULL;
goto unwind;
}
unwind:
if (set)
libhal_free_property_set(set);
free(path);
free(driver);
free(name);
free(config_info);
input_option_free_list(&input_options);
free(attrs.product);
free(attrs.vendor);
free(attrs.device);
free(attrs.pnp_id);
free(attrs.usb_id);
if (attrs.tags) {
char **tag = attrs.tags;
while (*tag) {
free(*tag);
tag++;
}
free(attrs.tags);
}
free(xkb_opts.layout);
free(xkb_opts.rules);
free(xkb_opts.model);
free(xkb_opts.variant);
free(xkb_opts.options);
dbus_error_free(&error);
return;
}
static void
disconnect_hook(void *data)
{
DBusError error;
struct config_hal_info *info = data;
if (info->hal_ctx) {
if (dbus_connection_get_is_connected(info->system_bus)) {
dbus_error_init(&error);
if (!libhal_ctx_shutdown(info->hal_ctx, &error))
LogMessage(X_WARNING,
"config/hal: disconnect_hook couldn't shut down context: %s (%s)\n",
error.name, error.message);
dbus_error_free(&error);
}
libhal_ctx_free(info->hal_ctx);
}
info->hal_ctx = NULL;
info->system_bus = NULL;
}
static BOOL
connect_and_register(DBusConnection * connection, struct config_hal_info *info)
{
DBusError error;
char **devices;
int num_devices, i;
if (info->hal_ctx)
return TRUE; /* already registered, pretend we did something */
info->system_bus = connection;
dbus_error_init(&error);
info->hal_ctx = libhal_ctx_new();
if (!info->hal_ctx) {
LogMessage(X_ERROR, "config/hal: couldn't create HAL context\n");
goto out_err;
}
if (!libhal_ctx_set_dbus_connection(info->hal_ctx, info->system_bus)) {
LogMessage(X_ERROR,
"config/hal: couldn't associate HAL context with bus\n");
goto out_err;
}
if (!libhal_ctx_init(info->hal_ctx, &error)) {
LogMessage(X_ERROR,
"config/hal: couldn't initialise context: %s (%s)\n",
error.name ? error.name : "unknown error",
error.message ? error.message : "null");
goto out_err;
}
if (!libhal_device_property_watch_all(info->hal_ctx, &error)) {
LogMessage(X_ERROR,
"config/hal: couldn't watch all properties: %s (%s)\n",
error.name ? error.name : "unknown error",
error.message ? error.message : "null");
goto out_ctx;
}
libhal_ctx_set_device_added(info->hal_ctx, device_added);
libhal_ctx_set_device_removed(info->hal_ctx, device_removed);
devices = libhal_find_device_by_capability(info->hal_ctx, "input",
&num_devices, &error);
/* FIXME: Get default devices if error is set. */
if (dbus_error_is_set(&error)) {
LogMessage(X_ERROR, "config/hal: couldn't find input device: %s (%s)\n",
error.name ? error.name : "unknown error",
error.message ? error.message : "null");
goto out_ctx;
}
for (i = 0; i < num_devices; i++)
device_added(info->hal_ctx, devices[i]);
libhal_free_string_array(devices);
dbus_error_free(&error);
return TRUE;
out_ctx:
dbus_error_free(&error);
if (!libhal_ctx_shutdown(info->hal_ctx, &error)) {
LogMessage(X_WARNING,
"config/hal: couldn't shut down context: %s (%s)\n",
error.name ? error.name : "unknown error",
error.message ? error.message : "null");
dbus_error_free(&error);
}
out_err:
dbus_error_free(&error);
if (info->hal_ctx) {
libhal_ctx_free(info->hal_ctx);
}
info->hal_ctx = NULL;
info->system_bus = NULL;
return FALSE;
}
/**
* Handle NewOwnerChanged signals to deal with HAL startup at X server runtime.
*
* NewOwnerChanged is send once when HAL shuts down, and once again when it
* comes back up. Message has three arguments, first is the name
* (org.freedesktop.Hal), the second one is the old owner, third one is new
* owner.
*/
static DBusHandlerResult
ownerchanged_handler(DBusConnection * connection, DBusMessage * message,
void *data)
{
int ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
if (dbus_message_is_signal(message,
"org.freedesktop.DBus", "NameOwnerChanged")) {
DBusError error;
char *name, *old_owner, *new_owner;
dbus_error_init(&error);
dbus_message_get_args(message, &error,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_STRING, &old_owner,
DBUS_TYPE_STRING, &new_owner, DBUS_TYPE_INVALID);
if (dbus_error_is_set(&error)) {
ErrorF
("[config/hal] failed to get NameOwnerChanged args: %s (%s)\n",
error.name, error.message);
}
else if (name && strcmp(name, "org.freedesktop.Hal") == 0) {
if (!old_owner || !strlen(old_owner)) {
DebugF("[config/hal] HAL startup detected.\n");
if (connect_and_register
(connection, (struct config_hal_info *) data))
dbus_connection_unregister_object_path(connection,
"/org/freedesktop/DBus");
else
ErrorF("[config/hal] Failed to connect to HAL bus.\n");
}
ret = DBUS_HANDLER_RESULT_HANDLED;
}
dbus_error_free(&error);
}
return ret;
}
/**
* Register a handler for the NameOwnerChanged signal.
*/
static BOOL
listen_for_startup(DBusConnection * connection, void *data)
{
DBusObjectPathVTable vtable = {.message_function = ownerchanged_handler, };
DBusError error;
const char MATCH_RULE[] = "sender='org.freedesktop.DBus',"
"interface='org.freedesktop.DBus',"
"type='signal',"
"path='/org/freedesktop/DBus'," "member='NameOwnerChanged'";
int rc = FALSE;
dbus_error_init(&error);
dbus_bus_add_match(connection, MATCH_RULE, &error);
if (!dbus_error_is_set(&error)) {
if (dbus_connection_register_object_path(connection,
"/org/freedesktop/DBus",
&vtable, data))
rc = TRUE;
else
ErrorF("[config/hal] cannot register object path.\n");
}
else {
ErrorF("[config/hal] couldn't add match rule: %s (%s)\n", error.name,
error.message);
ErrorF("[config/hal] cannot detect a HAL startup.\n");
}
dbus_error_free(&error);
return rc;
}
static void
connect_hook(DBusConnection * connection, void *data)
{
struct config_hal_info *info = data;
if (listen_for_startup(connection, data) &&
connect_and_register(connection, info))
dbus_connection_unregister_object_path(connection,
"/org/freedesktop/DBus");
return;
}
static struct config_hal_info hal_info;
static struct dbus_core_hook hook = {
.connect = connect_hook,
.disconnect = disconnect_hook,
.data = &hal_info,
};
int
config_hal_init(void)
{
memset(&hal_info, 0, sizeof(hal_info));
hal_info.system_bus = NULL;
hal_info.hal_ctx = NULL;
if (!dbus_core_add_hook(&hook)) {
LogMessage(X_ERROR, "config/hal: failed to add D-Bus hook\n");
return 0;
}
/* verbose message */
LogMessageVerb(X_INFO, 7, "config/hal: initialized\n");
return 1;
}
void
config_hal_fini(void)
{
dbus_core_remove_hook(&hook);
}

View File

@ -1,35 +0,0 @@
srcs_config = [
'config.c',
]
config_dep = [common_dep]
if build_dbus
srcs_config += 'dbus-core.c'
config_dep += dbus_dep
endif
if build_hal
srcs_config += 'hal.c'
config_dep += hal_dep
endif
if build_udev
srcs_config += 'udev.c'
config_dep += udev_dep
endif
if host_machine.system() == 'openbsd'
srcs_config += 'wscons.c'
endif
if build_xorg
install_data('10-quirks.conf',
install_dir: join_paths(get_option('datadir'), 'X11/xorg.conf.d'))
endif
libxserver_config = static_library('libxserver_config',
srcs_config,
include_directories: inc,
dependencies: config_dep,
)

View File

@ -1,579 +0,0 @@
/*
* Copyright © 2009 Julien Cristau
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Author: Julien Cristau <jcristau@debian.org>
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <libudev.h>
#include <ctype.h>
#include <unistd.h>
#include "input.h"
#include "inputstr.h"
#include "hotplug.h"
#include "config-backends.h"
#include "os.h"
#include "globals.h"
#include "systemd-logind.h"
#ifdef HAVE_SYS_SYSMACROS_H
#include <sys/sysmacros.h>
#endif
#define UDEV_XKB_PROP_KEY "xkb"
#define LOG_PROPERTY(path, prop, val) \
LogMessageVerb(X_INFO, 10, \
"config/udev: getting property %s on %s " \
"returned \"%s\"\n", \
(prop), (path), (val) ? (val) : "(null)")
#define LOG_SYSATTR(path, attr, val) \
LogMessageVerb(X_INFO, 10, \
"config/udev: getting attribute %s on %s " \
"returned \"%s\"\n", \
(attr), (path), (val) ? (val) : "(null)")
static struct udev_monitor *udev_monitor;
#ifdef CONFIG_UDEV_KMS
static void
config_udev_odev_setup_attribs(struct udev_device *udev_device, const char *path, const char *syspath,
int major, int minor,
config_odev_probe_proc_ptr probe_callback);
#endif
static char itoa_buf[16];
static const char *itoa(int i)
{
snprintf(itoa_buf, sizeof(itoa_buf), "%d", i);
return itoa_buf;
}
static Bool
check_seat(struct udev_device *udev_device)
{
const char *dev_seat;
dev_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
if (!dev_seat)
dev_seat = "seat0";
if (SeatId && strcmp(dev_seat, SeatId))
return FALSE;
if (!SeatId && strcmp(dev_seat, "seat0"))
return FALSE;
return TRUE;
}
static void
device_added(struct udev_device *udev_device)
{
const char *path, *name = NULL;
char *config_info = NULL;
const char *syspath;
const char *tags_prop;
const char *key, *value, *tmp;
#ifdef CONFIG_UDEV_KMS
const char *subsys = NULL;
#endif
InputOption *input_options;
InputAttributes attrs = { };
DeviceIntPtr dev = NULL;
struct udev_list_entry *set, *entry;
struct udev_device *parent;
int rc;
dev_t devnum;
path = udev_device_get_devnode(udev_device);
syspath = udev_device_get_syspath(udev_device);
if (!path || !syspath)
return;
if (!check_seat(udev_device))
return;
devnum = udev_device_get_devnum(udev_device);
#ifdef CONFIG_UDEV_KMS
subsys = udev_device_get_subsystem(udev_device);
if (subsys && !strcmp(subsys, "drm")) {
const char *sysname = udev_device_get_sysname(udev_device);
if (strncmp(sysname, "card", 4) != 0)
return;
/* Check for devices already added through xf86platformProbe() */
if (xf86_find_platform_device_by_devnum(major(devnum), minor(devnum)))
return;
LogMessage(X_INFO, "config/udev: Adding drm device (%s)\n", path);
config_udev_odev_setup_attribs(udev_device, path, syspath, major(devnum),
minor(devnum), NewGPUDeviceRequest);
return;
}
#endif
value = udev_device_get_property_value(udev_device, "ID_INPUT");
if (!value || !strcmp(value, "0")) {
LogMessageVerb(X_INFO, 10,
"config/udev: ignoring device %s without "
"property ID_INPUT set\n", path);
return;
}
input_options = input_option_new(NULL, "_source", "server/udev");
if (!input_options)
return;
parent = udev_device_get_parent(udev_device);
if (parent) {
const char *ppath = udev_device_get_devnode(parent);
const char *product = udev_device_get_property_value(parent, "PRODUCT");
const char *pnp_id = udev_device_get_sysattr_value(parent, "id");
unsigned int usb_vendor, usb_model;
name = udev_device_get_sysattr_value(parent, "name");
LOG_SYSATTR(ppath, "name", name);
if (!name) {
name = udev_device_get_property_value(parent, "NAME");
LOG_PROPERTY(ppath, "NAME", name);
}
/* construct USB ID in lowercase hex - "0000:ffff" */
if (product &&
sscanf(product, "%*x/%4x/%4x/%*x", &usb_vendor, &usb_model) == 2) {
char *usb_id;
if (asprintf(&usb_id, "%04x:%04x", usb_vendor, usb_model)
== -1)
usb_id = NULL;
else
LOG_PROPERTY(ppath, "PRODUCT", product);
attrs.usb_id = usb_id;
}
while (!pnp_id && (parent = udev_device_get_parent(parent))) {
pnp_id = udev_device_get_sysattr_value(parent, "id");
if (!pnp_id)
continue;
attrs.pnp_id = strdup(pnp_id);
ppath = udev_device_get_devnode(parent);
LOG_SYSATTR(ppath, "id", pnp_id);
}
}
if (!name)
name = "(unnamed)";
else
attrs.product = strdup(name);
input_options = input_option_new(input_options, "name", name);
input_options = input_option_new(input_options, "path", path);
input_options = input_option_new(input_options, "device", path);
input_options = input_option_new(input_options, "major", itoa(major(devnum)));
input_options = input_option_new(input_options, "minor", itoa(minor(devnum)));
if (path)
attrs.device = strdup(path);
tags_prop = udev_device_get_property_value(udev_device, "ID_INPUT.tags");
LOG_PROPERTY(path, "ID_INPUT.tags", tags_prop);
attrs.tags = xstrtokenize(tags_prop, ",");
if (asprintf(&config_info, "udev:%s", syspath) == -1) {
config_info = NULL;
goto unwind;
}
if (device_is_duplicate(config_info)) {
LogMessage(X_WARNING, "config/udev: device %s already added. "
"Ignoring.\n", name);
goto unwind;
}
set = udev_device_get_properties_list_entry(udev_device);
udev_list_entry_foreach(entry, set) {
key = udev_list_entry_get_name(entry);
if (!key)
continue;
value = udev_list_entry_get_value(entry);
if (!strncasecmp(key, UDEV_XKB_PROP_KEY, sizeof(UDEV_XKB_PROP_KEY) - 1)) {
LOG_PROPERTY(path, key, value);
tmp = key + sizeof(UDEV_XKB_PROP_KEY) - 1;
if (!strcasecmp(tmp, "rules"))
input_options =
input_option_new(input_options, "xkb_rules", value);
else if (!strcasecmp(tmp, "layout"))
input_options =
input_option_new(input_options, "xkb_layout", value);
else if (!strcasecmp(tmp, "variant"))
input_options =
input_option_new(input_options, "xkb_variant", value);
else if (!strcasecmp(tmp, "model"))
input_options =
input_option_new(input_options, "xkb_model", value);
else if (!strcasecmp(tmp, "options"))
input_options =
input_option_new(input_options, "xkb_options", value);
}
else if (!strcmp(key, "ID_VENDOR")) {
LOG_PROPERTY(path, key, value);
attrs.vendor = strdup(value);
} else if (!strncmp(key, "ID_INPUT_", 9)) {
const struct pfmap {
const char *property;
unsigned int flag;
} map[] = {
{ "ID_INPUT_KEY", ATTR_KEY },
{ "ID_INPUT_KEYBOARD", ATTR_KEYBOARD },
{ "ID_INPUT_MOUSE", ATTR_POINTER },
{ "ID_INPUT_JOYSTICK", ATTR_JOYSTICK },
{ "ID_INPUT_TABLET", ATTR_TABLET },
{ "ID_INPUT_TABLET_PAD", ATTR_TABLET_PAD },
{ "ID_INPUT_TOUCHPAD", ATTR_TOUCHPAD },
{ "ID_INPUT_TOUCHSCREEN", ATTR_TOUCHSCREEN },
{ NULL, 0 },
};
/* Anything but the literal string "0" is considered a
* boolean true. The empty string isn't a thing with udev
* properties anyway */
if (value && strcmp(value, "0")) {
const struct pfmap *m = map;
while (m->property != NULL) {
if (!strcmp(m->property, key)) {
LOG_PROPERTY(path, key, value);
attrs.flags |= m->flag;
}
m++;
}
}
}
}
input_options = input_option_new(input_options, "config_info", config_info);
/* Default setting needed for non-seat0 seats */
if (ServerIsNotSeat0())
input_options = input_option_new(input_options, "GrabDevice", "on");
LogMessage(X_INFO, "config/udev: Adding input device %s (%s)\n",
name, path);
rc = NewInputDeviceRequest(input_options, &attrs, &dev);
if (rc != Success)
goto unwind;
unwind:
free(config_info);
input_option_free_list(&input_options);
free(attrs.usb_id);
free(attrs.pnp_id);
free(attrs.product);
free(attrs.device);
free(attrs.vendor);
if (attrs.tags) {
char **tag = attrs.tags;
while (*tag) {
free(*tag);
tag++;
}
free(attrs.tags);
}
return;
}
static void
device_removed(struct udev_device *device)
{
char *value;
const char *syspath = udev_device_get_syspath(device);
#ifdef CONFIG_UDEV_KMS
const char *subsys = udev_device_get_subsystem(device);
if (subsys && !strcmp(subsys, "drm")) {
const char *sysname = udev_device_get_sysname(device);
const char *path = udev_device_get_devnode(device);
dev_t devnum = udev_device_get_devnum(device);
if ((strncmp(sysname,"card", 4) != 0) || (path == NULL))
return;
LogMessage(X_INFO, "config/udev: removing GPU device %s %s\n",
syspath, path);
config_udev_odev_setup_attribs(device, path, syspath, major(devnum),
minor(devnum), DeleteGPUDeviceRequest);
/* Retry vtenter after a drm node removal */
systemd_logind_vtenter();
return;
}
#endif
if (asprintf(&value, "udev:%s", syspath) == -1)
return;
remove_devices("udev", value);
free(value);
}
static void
socket_handler(int fd, int ready, void *data)
{
struct udev_device *udev_device;
const char *action;
input_lock();
udev_device = udev_monitor_receive_device(udev_monitor);
if (!udev_device) {
input_unlock();
return;
}
action = udev_device_get_action(udev_device);
if (action) {
if (!strcmp(action, "add")) {
device_removed(udev_device);
device_added(udev_device);
} else if (!strcmp(action, "change")) {
/* ignore change for the drm devices */
const char *subsys = udev_device_get_subsystem(udev_device);
if (subsys && strcmp(subsys, "drm")) {
device_removed(udev_device);
device_added(udev_device);
}
}
else if (!strcmp(action, "remove"))
device_removed(udev_device);
}
udev_device_unref(udev_device);
input_unlock();
}
int
config_udev_pre_init(void)
{
struct udev *udev;
udev = udev_new();
if (!udev)
return 0;
udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
if (!udev_monitor)
return 0;
udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "input",
NULL);
/* For Wacom serial devices */
udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL);
#ifdef CONFIG_UDEV_KMS
/* For output GPU devices */
udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "drm", NULL);
#endif
#ifdef HAVE_UDEV_MONITOR_FILTER_ADD_MATCH_TAG
if (ServerIsNotSeat0())
udev_monitor_filter_add_match_tag(udev_monitor, SeatId);
#endif
if (udev_monitor_enable_receiving(udev_monitor)) {
ErrorF("config/udev: failed to bind the udev monitor\n");
return 0;
}
return 1;
}
int
config_udev_init(void)
{
struct udev *udev;
struct udev_enumerate *enumerate;
struct udev_list_entry *devices, *device;
udev = udev_monitor_get_udev(udev_monitor);
enumerate = udev_enumerate_new(udev);
if (!enumerate)
return 0;
udev_enumerate_add_match_subsystem(enumerate, "input");
udev_enumerate_add_match_subsystem(enumerate, "tty");
#ifdef CONFIG_UDEV_KMS
udev_enumerate_add_match_subsystem(enumerate, "drm");
#endif
#ifdef HAVE_UDEV_ENUMERATE_ADD_MATCH_TAG
if (ServerIsNotSeat0())
udev_enumerate_add_match_tag(enumerate, SeatId);
#endif
udev_enumerate_scan_devices(enumerate);
devices = udev_enumerate_get_list_entry(enumerate);
udev_list_entry_foreach(device, devices) {
const char *syspath = udev_list_entry_get_name(device);
struct udev_device *udev_device =
udev_device_new_from_syspath(udev, syspath);
/* Device might be gone by the time we try to open it */
if (!udev_device)
continue;
device_added(udev_device);
udev_device_unref(udev_device);
}
udev_enumerate_unref(enumerate);
SetNotifyFd(udev_monitor_get_fd(udev_monitor), socket_handler, X_NOTIFY_READ, NULL);
return 1;
}
void
config_udev_fini(void)
{
struct udev *udev;
if (!udev_monitor)
return;
udev = udev_monitor_get_udev(udev_monitor);
RemoveNotifyFd(udev_monitor_get_fd(udev_monitor));
udev_monitor_unref(udev_monitor);
udev_monitor = NULL;
udev_unref(udev);
}
#ifdef CONFIG_UDEV_KMS
/* Find the last occurrence of the needle in haystack */
static char *strrstr(const char *haystack, const char *needle)
{
char *prev, *last, *tmp;
prev = strstr(haystack, needle);
if (!prev)
return NULL;
last = prev;
tmp = prev + 1;
while (tmp) {
last = strstr(tmp, needle);
if (!last)
return prev;
else {
prev = last;
tmp = prev + 1;
}
}
return last;
}
static void
config_udev_odev_setup_attribs(struct udev_device *udev_device, const char *path, const char *syspath,
int major, int minor,
config_odev_probe_proc_ptr probe_callback)
{
struct OdevAttributes *attribs = config_odev_allocate_attributes();
const char *value, *str;
attribs->path = XNFstrdup(path);
attribs->syspath = XNFstrdup(syspath);
attribs->major = major;
attribs->minor = minor;
value = udev_device_get_property_value(udev_device, "ID_PATH");
if (value && (str = strrstr(value, "pci-"))) {
value = str;
if ((str = strstr(value, "usb-")))
value = str;
attribs->busid = XNFstrdup(value);
attribs->busid[3] = ':';
}
/* ownership of attribs is passed to probe layer */
probe_callback(attribs);
}
void
config_udev_odev_probe(config_odev_probe_proc_ptr probe_callback)
{
struct udev *udev;
struct udev_enumerate *enumerate;
struct udev_list_entry *devices, *device;
udev = udev_monitor_get_udev(udev_monitor);
enumerate = udev_enumerate_new(udev);
if (!enumerate)
return;
udev_enumerate_add_match_subsystem(enumerate, "drm");
udev_enumerate_add_match_sysname(enumerate, "card[0-9]*");
#ifdef HAVE_UDEV_ENUMERATE_ADD_MATCH_TAG
if (ServerIsNotSeat0())
udev_enumerate_add_match_tag(enumerate, SeatId);
#endif
udev_enumerate_scan_devices(enumerate);
devices = udev_enumerate_get_list_entry(enumerate);
udev_list_entry_foreach(device, devices) {
const char *syspath = udev_list_entry_get_name(device);
struct udev_device *udev_device = udev_device_new_from_syspath(udev, syspath);
const char *path = udev_device_get_devnode(udev_device);
const char *sysname = udev_device_get_sysname(udev_device);
dev_t devnum = udev_device_get_devnum(udev_device);
const char *subsys = udev_device_get_subsystem(udev_device);
if (!path || !syspath || !subsys)
goto no_probe;
else if (strcmp(subsys, "drm") != 0)
goto no_probe;
else if (strncmp(sysname, "card", 4) != 0)
goto no_probe;
else if (!check_seat(udev_device))
goto no_probe;
config_udev_odev_setup_attribs(udev_device, path, syspath, major(devnum),
minor(devnum), probe_callback);
no_probe:
udev_device_unref(udev_device);
}
udev_enumerate_unref(enumerate);
return;
}
#endif

View File

@ -1,262 +0,0 @@
/*
* Copyright (c) 2011 Matthieu Herrb
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsksymdef.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "input.h"
#include "inputstr.h"
#include "os.h"
#include "config-backends.h"
#define WSCONS_KBD_DEVICE "/dev/wskbd"
#define WSCONS_MOUSE_PREFIX "/dev/wsmouse"
#define KB_OVRENC \
{ KB_UK, "gb" }, \
{ KB_SV, "se" }, \
{ KB_SG, "ch" }, \
{ KB_SF, "ch" }, \
{ KB_LA, "latam" }, \
{ KB_CF, "ca" }
struct nameint {
int val;
char *name;
} kbdenc[] = {
KB_OVRENC,
KB_ENCTAB,
{0}
};
struct nameint kbdvar[] = {
{KB_NODEAD | KB_SG, "de_nodeadkeys"},
{KB_NODEAD | KB_SF, "fr_nodeadkeys"},
{KB_SF, "fr"},
{KB_DVORAK | KB_CF, "fr-dvorak"},
{KB_DVORAK | KB_FR, "bepo"},
{KB_DVORAK, "dvorak"},
{KB_CF, "fr-legacy"},
{KB_NODEAD, "nodeadkeys"},
{0}
};
struct nameint kbdopt[] = {
{KB_SWAPCTRLCAPS, "ctrl:swapcaps"},
{0}
};
struct nameint kbdmodel[] = {
{WSKBD_TYPE_ZAURUS, "zaurus"},
{0}
};
static void
wscons_add_keyboard(void)
{
InputAttributes attrs = { };
DeviceIntPtr dev = NULL;
InputOption *input_options = NULL;
char *config_info = NULL;
int fd, i, rc;
unsigned int type;
kbd_t wsenc = 0;
/* Find keyboard configuration */
fd = open(WSCONS_KBD_DEVICE, O_RDWR | O_NONBLOCK | O_EXCL);
if (fd == -1) {
LogMessage(X_ERROR, "wskbd: open %s: %s\n",
WSCONS_KBD_DEVICE, strerror(errno));
return;
}
if (ioctl(fd, WSKBDIO_GETENCODING, &wsenc) == -1) {
LogMessage(X_WARNING, "wskbd: ioctl(WSKBDIO_GETENCODING) "
"failed: %s\n", strerror(errno));
close(fd);
return;
}
if (ioctl(fd, WSKBDIO_GTYPE, &type) == -1) {
LogMessage(X_WARNING, "wskbd: ioctl(WSKBDIO_GTYPE) "
"failed: %s\n", strerror(errno));
close(fd);
return;
}
close(fd);
input_options = input_option_new(input_options, "_source", "server/wscons");
if (input_options == NULL)
return;
LogMessage(X_INFO, "config/wscons: checking input device %s\n",
WSCONS_KBD_DEVICE);
input_options = input_option_new(input_options, "name", WSCONS_KBD_DEVICE);
input_options = input_option_new(input_options, "driver", "kbd");
config_info = Xprintf("wscons:%s", WSCONS_KBD_DEVICE);
if (!config_info)
goto unwind;
if (KB_ENCODING(wsenc) == KB_USER) {
/* Ignore wscons "user" layout */
LogMessageVerb(X_INFO, 3, "wskbd: ignoring \"user\" layout\n");
goto kbd_config_done;
}
for (i = 0; kbdenc[i].val; i++)
if (KB_ENCODING(wsenc) == kbdenc[i].val) {
LogMessageVerb(X_INFO, 3, "wskbd: using layout %s\n",
kbdenc[i].name);
input_options = input_option_new(input_options,
"xkb_layout", kbdenc[i].name);
break;
}
for (i = 0; kbdvar[i].val; i++)
if (wsenc == kbdvar[i].val || KB_VARIANT(wsenc) == kbdvar[i].val) {
LogMessageVerb(X_INFO, 3, "wskbd: using variant %s\n",
kbdvar[i].name);
input_options = input_option_new(input_options,
"xkb_variant", kbdvar[i].name);
break;
}
for (i = 0; kbdopt[i].val; i++)
if (KB_VARIANT(wsenc) == kbdopt[i].val) {
LogMessageVerb(X_INFO, 3, "wskbd: using option %s\n",
kbdopt[i].name);
input_options = input_option_new(input_options,
"xkb_options", kbdopt[i].name);
break;
}
for (i = 0; kbdmodel[i].val; i++)
if (type == kbdmodel[i].val) {
LogMessageVerb(X_INFO, 3, "wskbd: using model %s\n",
kbdmodel[i].name);
input_options = input_option_new(input_options,
"xkb_model", kbdmodel[i].name);
break;
}
kbd_config_done:
attrs.flags |= ATTR_KEY | ATTR_KEYBOARD;
rc = NewInputDeviceRequest(input_options, &attrs, &dev);
if (rc != Success)
goto unwind;
for (; dev; dev = dev->next) {
free(dev->config_info);
dev->config_info = strdup(config_info);
}
unwind:
input_option_free_list(&input_options);
}
static void
wscons_add_pointer(const char *path, const char *driver, int flags)
{
InputAttributes attrs = { };
DeviceIntPtr dev = NULL;
InputOption *input_options = NULL;
char *config_info = NULL;
int rc;
config_info = Xprintf("wscons:%s", path);
if (!config_info)
return;
input_options = input_option_new(input_options, "_source", "server/wscons");
if (input_options == NULL)
return;
input_options = input_option_new(input_options, "name", strdup(path));
input_options = input_option_new(input_options, "driver", strdup(driver));
input_options = input_option_new(input_options, "device", strdup(path));
LogMessage(X_INFO, "config/wscons: checking input device %s\n", path);
attrs.flags |= flags;
rc = NewInputDeviceRequest(input_options, &attrs, &dev);
if (rc != Success)
goto unwind;
for (; dev; dev = dev->next) {
free(dev->config_info);
dev->config_info = strdup(config_info);
}
unwind:
input_option_free_list(&input_options);
}
static void
wscons_add_pointers(void)
{
char devname[256];
int fd, i, wsmouse_type;
/* Check pointing devices */
for (i = 0; i < 4; i++) {
snprintf(devname, sizeof(devname), "%s%d", WSCONS_MOUSE_PREFIX, i);
LogMessageVerb(X_INFO, 10, "wsmouse: checking %s\n", devname);
fd = open_device(devnamem O_RDWR | O_NONBLOCK | O_EXCL);
if (fd == -1) {
LogMessageVerb(X_WARNING, 10, "%s: %s\n", devname, strerror(errno));
continue;
}
if (ioctl(fd, WSMOUSEIO_GTYPE, &wsmouse_type) != 0) {
LogMessageVerb(X_WARNING, 10,
"%s: WSMOUSEIO_GTYPE failed\n", devname);
close(fd);
continue;
}
close(fd);
switch (wsmouse_type) {
case WSMOUSE_TYPE_SYNAPTICS:
wscons_add_pointer(devname, "synaptics", ATTR_TOUCHPAD);
break;
case WSMOUSE_TYPE_TPANEL:
wscons_add_pointer(devname, "ws", ATTR_TOUCHSCREEN);
break;
default:
break;
}
}
/* Add a default entry catching all other mux elements as "mouse" */
wscons_add_pointer(WSCONS_MOUSE_PREFIX, "mouse", ATTR_POINTER);
}
int
config_wscons_init(void)
{
wscons_add_keyboard();
wscons_add_pointers();
return 1;
}
void
config_wscons_fini(void)
{
/* Not much to do ? */
}

View File

@ -1,93 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<deviceinfo version="0.2">
<device>
<!-- The way this works:
Match against some input device (see the HAL specification for more
information), and then merge in keys, which you can use to specify
the configuration similar to the way you would in xorg.conf. You will
need to restart HAL after making changes. If you are having issues,
starting X with the -logverbose 7 flag may yield useful information.
Keys Supported:
Key "input.x11_driver" (string)
This specifies the driver to use. You MUST specify this option,
or a driver will not be loaded and the rest will be ignored by
Xorg
Key "input.x11_options.<option name>" (string)
This allows you to specify arbitrary options to pass to the driver.
Anything you would normally specify in xorg.conf goes here. So, for
option "Mode" in xorg.conf, you would specify the key name of
"input.x11_options.Mode".
Do not specify "input.x11_options.Device" since "input.device"
will be used automatically.
You MUST specify all options as strings, otherwise the server will
ignore them.
Legacy Keys
"input.xkb.rules"
"input.xkb.model"
"input.xkb.layout"
"input.xkb.variant"
"input.xkb.options"
These keys are deprecated. Use these instead:
"input.x11_options.XkbRules"
"input.x11_options.XkbModel"
"input.x11_options.XkbLayout"
"input.x11_options.XkbVariant"
"input.x11_options.XkbOptions"
See the evdev documentation for more information.
FIXME: Support tablets too.
TODO: I think its fixed, can't test
-->
<match key="info.capabilities" contains="input.mouse">
<merge key="input.x11_driver" type="string">mouse</merge>
<match key="/org/freedesktop/Hal/devices/computer:system.kernel.name"
string="Linux">
<merge key="input.x11_driver" type="string">evdev</merge>
</match>
<match key="/org/freedesktop/Hal/devices/computer:system.kernel.name"
string="SunOS">
<match key="input.device" contains="usb">
<merge key="input.x11_options.StreamsModule" type="string">usbms</merge>
<merge key="input.x11_options.Protocol" type="string">VUID</merge>
</match>
</match>
</match>
<match key="info.capabilities" contains="input.keys">
<merge key="input.x11_options.XkbRules" type="string">base</merge>
<!-- If we're using Linux, we use evdev by default (falling back to
kbd otherwise). -->
<merge key="input.x11_driver" type="string">kbd</merge>
<merge key="input.x11_options.XkbModel" type="string">pc105</merge>
<match key="/org/freedesktop/Hal/devices/computer:system.kernel.name"
string="Linux">
<merge key="input.x11_driver" type="string">evdev</merge>
<merge key="input.x11_options.XkbModel" type="string">evdev</merge>
</match>
<match key="/org/freedesktop/Hal/devices/computer:system.kernel.name"
string="SunOS">
<match key="input.device" contains="usb">
<merge key="input.x11_options.StreamsModule" type="string">usbkbm</merge>
<merge key="input.x11_options.Protocol" type="string">VUID</merge>
</match>
</match>
<merge key="input.x11_options.XkbLayout" type="string">us</merge>
<merge key="input.x11_options.XkbVariant" type="string" />
</match>
</device>
</deviceinfo>

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +0,0 @@
noinst_LTLIBRARIES = libdamageext.la
AM_CFLAGS = $(DIX_CFLAGS)
libdamageext_la_SOURCES = \
damageext.c \
damageextint.h

View File

@ -1,12 +0,0 @@
noinst_LTLIBRARIES = libdbe.la
AM_CFLAGS = $(DIX_CFLAGS)
if XORG
sdk_HEADERS = dbestruct.h
endif
libdbe_la_SOURCES = \
dbe.c \
midbe.c \
midbe.h

View File

@ -12,5 +12,3 @@ libxserver_dbe = static_library('libxserver_dbe',
include_directories: inc,
dependencies: common_dep,
)
install_data(hdrs_dbe, install_dir: xorgsdkdir)

View File

@ -1,61 +0,0 @@
noinst_LTLIBRARIES = libdix.la libmain.la
AM_CPPFLAGS = -I$(top_srcdir)/include
AM_CFLAGS = $(DIX_CFLAGS)
libmain_la_SOURCES = \
stubmain.c
libdix_la_SOURCES = \
atom.c \
colormap.c \
cursor.c \
devices.c \
dispatch.c \
dispatch.h \
dixfonts.c \
main.c \
dixutils.c \
enterleave.c \
enterleave.h \
events.c \
eventconvert.c \
extension.c \
gc.c \
getevents.c \
globals.c \
glyphcurs.c \
grabs.c \
initatoms.c \
inpututils.c \
pixmap.c \
privates.c \
property.c \
ptrveloc.c \
region.c \
registry.c \
resource.c \
selection.c \
swaprep.c \
swapreq.c \
tables.c \
touch.c \
window.c
EXTRA_DIST = buildatoms BuiltInAtoms
# Install list of protocol names
miscconfigdir = $(SERVER_MISC_CONFIG_PATH)
dist_miscconfig_DATA = protocol.txt
if SPECIAL_DTRACE_OBJECTS
# Generate dtrace object code for probes in libdix
dtrace-dix.o: $(top_srcdir)/include/Xserver.d libdix.la
$(AM_V_GEN)$(DTRACE) -G -C -o $@ -s $(top_srcdir)/include/Xserver.d $(am_libdix_la_OBJECTS:%.lo=.libs/%.o)
noinst_PROGRAMS = dix.O
dix_O_SOURCES =
dix.O: dtrace-dix.o libdix.la
$(AM_V_GEN)ld -r -o $@ $(am_libdix_la_OBJECTS:%.lo=.libs/%.o)
endif

View File

@ -2257,6 +2257,9 @@ ProcChangePointerControl(ClientPtr client)
REQUEST(xChangePointerControlReq);
REQUEST_SIZE_MATCH(xChangePointerControlReq);
/* If the device has no PtrFeedbackPtr, the xserver has a bug */
BUG_RETURN_VAL (!mouse->ptrfeed, BadImplementation);
ctrl = mouse->ptrfeed->ctrl;
if ((stuff->doAccel != xTrue) && (stuff->doAccel != xFalse)) {
client->errorValue = stuff->doAccel;

View File

@ -1343,7 +1343,7 @@ fill_pointer_events(InternalEvent *events, DeviceIntPtr pDev, int type,
int buttons, CARD32 ms, int flags,
const ValuatorMask *mask_in)
{
int num_events = 1;
int num_events = 0;
DeviceEvent *event;
RawDeviceEvent *raw = NULL;
double screenx = 0.0, screeny = 0.0; /* desktop coordinate system */
@ -1386,6 +1386,10 @@ fill_pointer_events(InternalEvent *events, DeviceIntPtr pDev, int type,
num_events++;
init_raw(pDev, raw, ms, type, buttons);
if (flags & POINTER_EMULATED)
raw->flags = XIPointerEmulated;
set_raw_valuators(raw, &mask, TRUE, raw->valuators.data_raw);
}
@ -1454,36 +1458,37 @@ fill_pointer_events(InternalEvent *events, DeviceIntPtr pDev, int type,
master->last.valuators[1] = screeny;
}
event = &events->device_event;
init_device_event(event, pDev, ms, EVENT_SOURCE_NORMAL);
if ((flags & POINTER_RAWONLY) == 0) {
num_events++;
if (type == MotionNotify) {
event->type = ET_Motion;
event->detail.button = 0;
}
else {
if (type == ButtonPress) {
event->type = ET_ButtonPress;
set_button_down(pDev, buttons, BUTTON_POSTED);
event = &events->device_event;
init_device_event(event, pDev, ms, EVENT_SOURCE_NORMAL);
if (type == MotionNotify) {
event->type = ET_Motion;
event->detail.button = 0;
}
else if (type == ButtonRelease) {
event->type = ET_ButtonRelease;
set_button_up(pDev, buttons, BUTTON_POSTED);
else {
if (type == ButtonPress) {
event->type = ET_ButtonPress;
set_button_down(pDev, buttons, BUTTON_POSTED);
}
else if (type == ButtonRelease) {
event->type = ET_ButtonRelease;
set_button_up(pDev, buttons, BUTTON_POSTED);
}
event->detail.button = buttons;
}
event->detail.button = buttons;
/* root_x and root_y must be in per-screen coordinates */
event_set_root_coordinates(event, screenx - scr->x, screeny - scr->y);
if (flags & POINTER_EMULATED)
event->flags = XIPointerEmulated;
set_valuators(pDev, event, &mask);
}
/* root_x and root_y must be in per-screen coordinates */
event_set_root_coordinates(event, screenx - scr->x, screeny - scr->y);
if (flags & POINTER_EMULATED) {
if (raw)
raw->flags = XIPointerEmulated;
event->flags = XIPointerEmulated;
}
set_valuators(pDev, event, &mask);
return num_events;
}

View File

@ -99,7 +99,6 @@ Equipment Corporation.
#include <X11/fonts/libxfont2.h>
#include "opaque.h"
#include "servermd.h"
#include "hotplug.h"
#include "dixfont.h"
#include "extnsionst.h"
#include "privates.h"

View File

@ -1,15 +0,0 @@
SUBDIRS = dtrace
if ENABLE_DEVEL_DOCS
if HAVE_XMLTO
# Main DocBook/XML files (DOCTYPE book)
docbook = Xserver-spec.xml Xinput.xml
# Generate DocBook/XML output formats with or without stylesheets
include $(top_srcdir)/devbook.am
endif HAVE_XMLTO
endif ENABLE_DEVEL_DOCS
EXTRA_DIST = smartsched filter-xmlto.sh

View File

@ -1,15 +0,0 @@
if ENABLE_DOCS
if XSERVER_DTRACE
# Main DocBook/XML files (DOCTYPE book)
docbook = Xserver-DTrace.xml
# The location where the DocBook/XML files and their generated formats are installed
shelfdir = $(docdir)
# Generate DocBook/XML output formats with or without stylesheets
include $(top_srcdir)/docbook.am
endif XSERVER_DTRACE
endif ENABLE_DOCS

View File

@ -1,13 +0,0 @@
noinst_LTLIBRARIES = libdri3.la
AM_CFLAGS = \
@DIX_CFLAGS@ \
@LIBDRM_CFLAGS@
libdri3_la_SOURCES = \
dri3.h \
dri3_priv.h \
dri3.c \
dri3_request.c \
dri3_screen.c
sdk_HEADERS = dri3.h

View File

@ -16,5 +16,3 @@ if build_dri3
dependencies: [ common_dep, libdrm_dep ],
)
endif
install_data(hdrs_dri3, install_dir: xorgsdkdir)

View File

@ -1,24 +0,0 @@
noinst_LTLIBRARIES = libexa.la
if XORG
sdk_HEADERS = exa.h
endif
AM_CPPFLAGS = $(XORG_INCS)
AM_CFLAGS = $(XORG_CFLAGS) $(DIX_CFLAGS)
libexa_la_SOURCES = \
exa.c \
exa.h \
exa_classic.c \
exa_migration_classic.c \
exa_driver.c \
exa_mixed.c \
exa_migration_mixed.c \
exa_accel.c \
exa_glyphs.c \
exa_offscreen.c \
exa_render.c \
exa_priv.h \
exa_unaccel.c

1144
exa/exa.c

File diff suppressed because it is too large Load Diff

820
exa/exa.h
View File

@ -1,820 +0,0 @@
/*
*
* Copyright (C) 2000 Keith Packard
* 2004 Eric Anholt
* 2005 Zack Rusin
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of copyright holders not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Copyright holders make no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
/** @file
* This is the header containing the public API of EXA for exa drivers.
*/
#ifndef EXA_H
#define EXA_H
#include "scrnintstr.h"
#include "pixmapstr.h"
#include "windowstr.h"
#include "gcstruct.h"
#include "picturestr.h"
#include "fb.h"
#define EXA_VERSION_MAJOR 2
#define EXA_VERSION_MINOR 6
#define EXA_VERSION_RELEASE 0
typedef struct _ExaOffscreenArea ExaOffscreenArea;
typedef void (*ExaOffscreenSaveProc) (ScreenPtr pScreen,
ExaOffscreenArea * area);
typedef enum _ExaOffscreenState {
ExaOffscreenAvail,
ExaOffscreenRemovable,
ExaOffscreenLocked
} ExaOffscreenState;
struct _ExaOffscreenArea {
int base_offset; /* allocation base */
int offset; /* aligned offset */
int size; /* total allocation size */
unsigned last_use;
void *privData;
ExaOffscreenSaveProc save;
ExaOffscreenState state;
ExaOffscreenArea *next;
unsigned eviction_cost;
ExaOffscreenArea *prev; /* Double-linked list for defragmentation */
int align; /* required alignment */
};
/**
* The ExaDriver structure is allocated through exaDriverAlloc(), and then
* fllled in by drivers.
*/
typedef struct _ExaDriver {
/**
* exa_major and exa_minor should be set by the driver to the version of
* EXA which the driver was compiled for (or configures itself at runtime
* to support). This allows EXA to extend the structure for new features
* without breaking ABI for drivers compiled against older versions.
*/
int exa_major, exa_minor;
/**
* memoryBase is the address of the beginning of framebuffer memory.
* The visible screen should be within memoryBase to memoryBase +
* memorySize.
*/
CARD8 *memoryBase;
/**
* offScreenBase is the offset from memoryBase of the beginning of the area
* to be managed by EXA's linear offscreen memory manager.
*
* In XFree86 DDX drivers, this is probably:
* (pScrn->displayWidth * cpp * pScrn->virtualY)
*/
unsigned long offScreenBase;
/**
* memorySize is the length (in bytes) of framebuffer memory beginning
* from memoryBase.
*
* The offscreen memory manager will manage the area beginning at
* (memoryBase + offScreenBase), with a length of (memorySize -
* offScreenBase)
*
* In XFree86 DDX drivers, this is probably (pScrn->videoRam * 1024)
*/
unsigned long memorySize;
/**
* pixmapOffsetAlign is the byte alignment necessary for pixmap offsets
* within framebuffer.
*
* Hardware typically has a required alignment of offsets, which may or may
* not be a power of two. EXA will ensure that pixmaps managed by the
* offscreen memory manager meet this alignment requirement.
*/
int pixmapOffsetAlign;
/**
* pixmapPitchAlign is the byte alignment necessary for pixmap pitches
* within the framebuffer.
*
* Hardware typically has a required alignment of pitches for acceleration.
* For 3D hardware, Composite acceleration often requires that source and
* mask pixmaps (textures) have a power-of-two pitch, which can be demanded
* using EXA_OFFSCREEN_ALIGN_POT. These pitch requirements only apply to
* pixmaps managed by the offscreen memory manager. Thus, it is up to the
* driver to ensure that the visible screen has an appropriate pitch for
* acceleration.
*/
int pixmapPitchAlign;
/**
* The flags field is bitfield of boolean values controlling EXA's behavior.
*
* The flags include EXA_OFFSCREEN_PIXMAPS, EXA_OFFSCREEN_ALIGN_POT, and
* EXA_TWO_BITBLT_DIRECTIONS.
*/
int flags;
/** @{ */
/**
* maxX controls the X coordinate limitation for rendering from the card.
* The driver should never receive a request for rendering beyond maxX
* in the X direction from the origin of a pixmap.
*/
int maxX;
/**
* maxY controls the Y coordinate limitation for rendering from the card.
* The driver should never receive a request for rendering beyond maxY
* in the Y direction from the origin of a pixmap.
*/
int maxY;
/** @} */
/* private */
ExaOffscreenArea *offScreenAreas;
Bool needsSync;
int lastMarker;
/** @name Solid
* @{
*/
/**
* PrepareSolid() sets up the driver for doing a solid fill.
* @param pPixmap Destination pixmap
* @param alu raster operation
* @param planemask write mask for the fill
* @param fg "foreground" color for the fill
*
* This call should set up the driver for doing a series of solid fills
* through the Solid() call. The alu raster op is one of the GX*
* graphics functions listed in X.h, and typically maps to a similar
* single-byte "ROP" setting in all hardware. The planemask controls
* which bits of the destination should be affected, and will only represent
* the bits up to the depth of pPixmap. The fg is the pixel value of the
* foreground color referred to in ROP descriptions.
*
* Note that many drivers will need to store some of the data in the driver
* private record, for sending to the hardware with each drawing command.
*
* The PrepareSolid() call is required of all drivers, but it may fail for any
* reason. Failure results in a fallback to software rendering.
*/
Bool (*PrepareSolid) (PixmapPtr pPixmap,
int alu, Pixel planemask, Pixel fg);
/**
* Solid() performs a solid fill set up in the last PrepareSolid() call.
*
* @param pPixmap destination pixmap
* @param x1 left coordinate
* @param y1 top coordinate
* @param x2 right coordinate
* @param y2 bottom coordinate
*
* Performs the fill set up by the last PrepareSolid() call, covering the
* area from (x1,y1) to (x2,y2) in pPixmap. Note that the coordinates are
* in the coordinate space of the destination pixmap, so the driver will
* need to set up the hardware's offset and pitch for the destination
* coordinates according to the pixmap's offset and pitch within
* framebuffer. This likely means using exaGetPixmapOffset() and
* exaGetPixmapPitch().
*
* This call is required if PrepareSolid() ever succeeds.
*/
void (*Solid) (PixmapPtr pPixmap, int x1, int y1, int x2, int y2);
/**
* DoneSolid() finishes a set of solid fills.
*
* @param pPixmap destination pixmap.
*
* The DoneSolid() call is called at the end of a series of consecutive
* Solid() calls following a successful PrepareSolid(). This allows drivers
* to finish up emitting drawing commands that were buffered, or clean up
* state from PrepareSolid().
*
* This call is required if PrepareSolid() ever succeeds.
*/
void (*DoneSolid) (PixmapPtr pPixmap);
/** @} */
/** @name Copy
* @{
*/
/**
* PrepareCopy() sets up the driver for doing a copy within video
* memory.
*
* @param pSrcPixmap source pixmap
* @param pDstPixmap destination pixmap
* @param dx X copy direction
* @param dy Y copy direction
* @param alu raster operation
* @param planemask write mask for the fill
*
* This call should set up the driver for doing a series of copies from the
* the pSrcPixmap to the pDstPixmap. The dx flag will be positive if the
* hardware should do the copy from the left to the right, and dy will be
* positive if the copy should be done from the top to the bottom. This
* is to deal with self-overlapping copies when pSrcPixmap == pDstPixmap.
* If your hardware can only support blits that are (left to right, top to
* bottom) or (right to left, bottom to top), then you should set
* #EXA_TWO_BITBLT_DIRECTIONS, and EXA will break down Copy operations to
* ones that meet those requirements. The alu raster op is one of the GX*
* graphics functions listed in X.h, and typically maps to a similar
* single-byte "ROP" setting in all hardware. The planemask controls which
* bits of the destination should be affected, and will only represent the
* bits up to the depth of pPixmap.
*
* Note that many drivers will need to store some of the data in the driver
* private record, for sending to the hardware with each drawing command.
*
* The PrepareCopy() call is required of all drivers, but it may fail for any
* reason. Failure results in a fallback to software rendering.
*/
Bool (*PrepareCopy) (PixmapPtr pSrcPixmap,
PixmapPtr pDstPixmap,
int dx, int dy, int alu, Pixel planemask);
/**
* Copy() performs a copy set up in the last PrepareCopy call.
*
* @param pDstPixmap destination pixmap
* @param srcX source X coordinate
* @param srcY source Y coordinate
* @param dstX destination X coordinate
* @param dstY destination Y coordinate
* @param width width of the rectangle to be copied
* @param height height of the rectangle to be copied.
*
* Performs the copy set up by the last PrepareCopy() call, copying the
* rectangle from (srcX, srcY) to (srcX + width, srcY + width) in the source
* pixmap to the same-sized rectangle at (dstX, dstY) in the destination
* pixmap. Those rectangles may overlap in memory, if
* pSrcPixmap == pDstPixmap. Note that this call does not receive the
* pSrcPixmap as an argument -- if it's needed in this function, it should
* be stored in the driver private during PrepareCopy(). As with Solid(),
* the coordinates are in the coordinate space of each pixmap, so the driver
* will need to set up source and destination pitches and offsets from those
* pixmaps, probably using exaGetPixmapOffset() and exaGetPixmapPitch().
*
* This call is required if PrepareCopy ever succeeds.
*/
void (*Copy) (PixmapPtr pDstPixmap,
int srcX,
int srcY, int dstX, int dstY, int width, int height);
/**
* DoneCopy() finishes a set of copies.
*
* @param pPixmap destination pixmap.
*
* The DoneCopy() call is called at the end of a series of consecutive
* Copy() calls following a successful PrepareCopy(). This allows drivers
* to finish up emitting drawing commands that were buffered, or clean up
* state from PrepareCopy().
*
* This call is required if PrepareCopy() ever succeeds.
*/
void (*DoneCopy) (PixmapPtr pDstPixmap);
/** @} */
/** @name Composite
* @{
*/
/**
* CheckComposite() checks to see if a composite operation could be
* accelerated.
*
* @param op Render operation
* @param pSrcPicture source Picture
* @param pMaskPicture mask picture
* @param pDstPicture destination Picture
*
* The CheckComposite() call checks if the driver could handle acceleration
* of op with the given source, mask, and destination pictures. This allows
* drivers to check source and destination formats, supported operations,
* transformations, and component alpha state, and send operations it can't
* support to software rendering early on. This avoids costly pixmap
* migration to the wrong places when the driver can't accelerate
* operations. Note that because migration hasn't happened, the driver
* can't know during CheckComposite() what the offsets and pitches of the
* pixmaps are going to be.
*
* See PrepareComposite() for more details on likely issues that drivers
* will have in accelerating Composite operations.
*
* The CheckComposite() call is recommended if PrepareComposite() is
* implemented, but is not required.
*/
Bool (*CheckComposite) (int op,
PicturePtr pSrcPicture,
PicturePtr pMaskPicture, PicturePtr pDstPicture);
/**
* PrepareComposite() sets up the driver for doing a Composite operation
* described in the Render extension protocol spec.
*
* @param op Render operation
* @param pSrcPicture source Picture
* @param pMaskPicture mask picture
* @param pDstPicture destination Picture
* @param pSrc source pixmap
* @param pMask mask pixmap
* @param pDst destination pixmap
*
* This call should set up the driver for doing a series of Composite
* operations, as described in the Render protocol spec, with the given
* pSrcPicture, pMaskPicture, and pDstPicture. The pSrc, pMask, and
* pDst are the pixmaps containing the pixel data, and should be used for
* setting the offset and pitch used for the coordinate spaces for each of
* the Pictures.
*
* Notes on interpreting Picture structures:
* - The Picture structures will always have a valid pDrawable.
* - The Picture structures will never have alphaMap set.
* - The mask Picture (and therefore pMask) may be NULL, in which case the
* operation is simply src OP dst instead of src IN mask OP dst, and
* mask coordinates should be ignored.
* - pMarkPicture may have componentAlpha set, which greatly changes
* the behavior of the Composite operation. componentAlpha has no effect
* when set on pSrcPicture or pDstPicture.
* - The source and mask Pictures may have a transformation set
* (Picture->transform != NULL), which means that the source coordinates
* should be transformed by that transformation, resulting in scaling,
* rotation, etc. The PictureTransformPoint() call can transform
* coordinates for you. Transforms have no effect on Pictures when used
* as a destination.
* - The source and mask pictures may have a filter set. PictFilterNearest
* and PictFilterBilinear are defined in the Render protocol, but others
* may be encountered, and must be handled correctly (usually by
* PrepareComposite failing, and falling back to software). Filters have
* no effect on Pictures when used as a destination.
* - The source and mask Pictures may have repeating set, which must be
* respected. Many chipsets will be unable to support repeating on
* pixmaps that have a width or height that is not a power of two.
*
* If your hardware can't support source pictures (textures) with
* non-power-of-two pitches, you should set #EXA_OFFSCREEN_ALIGN_POT.
*
* Note that many drivers will need to store some of the data in the driver
* private record, for sending to the hardware with each drawing command.
*
* The PrepareComposite() call is not required. However, it is highly
* recommended for performance of antialiased font rendering and performance
* of cairo applications. Failure results in a fallback to software
* rendering.
*/
Bool (*PrepareComposite) (int op,
PicturePtr pSrcPicture,
PicturePtr pMaskPicture,
PicturePtr pDstPicture,
PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst);
/**
* Composite() performs a Composite operation set up in the last
* PrepareComposite() call.
*
* @param pDstPixmap destination pixmap
* @param srcX source X coordinate
* @param srcY source Y coordinate
* @param maskX source X coordinate
* @param maskY source Y coordinate
* @param dstX destination X coordinate
* @param dstY destination Y coordinate
* @param width destination rectangle width
* @param height destination rectangle height
*
* Performs the Composite operation set up by the last PrepareComposite()
* call, to the rectangle from (dstX, dstY) to (dstX + width, dstY + height)
* in the destination Pixmap. Note that if a transformation was set on
* the source or mask Pictures, the source rectangles may not be the same
* size as the destination rectangles and filtering. Getting the coordinate
* transformation right at the subpixel level can be tricky, and rendercheck
* can test this for you.
*
* This call is required if PrepareComposite() ever succeeds.
*/
void (*Composite) (PixmapPtr pDst,
int srcX,
int srcY,
int maskX,
int maskY, int dstX, int dstY, int width, int height);
/**
* DoneComposite() finishes a set of Composite operations.
*
* @param pPixmap destination pixmap.
*
* The DoneComposite() call is called at the end of a series of consecutive
* Composite() calls following a successful PrepareComposite(). This allows
* drivers to finish up emitting drawing commands that were buffered, or
* clean up state from PrepareComposite().
*
* This call is required if PrepareComposite() ever succeeds.
*/
void (*DoneComposite) (PixmapPtr pDst);
/** @} */
/**
* UploadToScreen() loads a rectangle of data from src into pDst.
*
* @param pDst destination pixmap
* @param x destination X coordinate.
* @param y destination Y coordinate
* @param width width of the rectangle to be copied
* @param height height of the rectangle to be copied
* @param src pointer to the beginning of the source data
* @param src_pitch pitch (in bytes) of the lines of source data.
*
* UploadToScreen() copies data in system memory beginning at src (with
* pitch src_pitch) into the destination pixmap from (x, y) to
* (x + width, y + height). This is typically done with hostdata uploads,
* where the CPU sets up a blit command on the hardware with instructions
* that the blit data will be fed through some sort of aperture on the card.
*
* If UploadToScreen() is performed asynchronously, it is up to the driver
* to call exaMarkSync(). This is in contrast to most other acceleration
* calls in EXA.
*
* UploadToScreen() can aid in pixmap migration, but is most important for
* the performance of exaGlyphs() (antialiased font drawing) by allowing
* pipelining of data uploads, avoiding a sync of the card after each glyph.
*
* @return TRUE if the driver successfully uploaded the data. FALSE
* indicates that EXA should fall back to doing the upload in software.
*
* UploadToScreen() is not required, but is recommended if Composite
* acceleration is supported.
*/
Bool (*UploadToScreen) (PixmapPtr pDst,
int x,
int y, int w, int h, char *src, int src_pitch);
/**
* UploadToScratch() is no longer used and will be removed next time the EXA
* major version needs to be bumped.
*/
Bool (*UploadToScratch) (PixmapPtr pSrc, PixmapPtr pDst);
/**
* DownloadFromScreen() loads a rectangle of data from pSrc into dst
*
* @param pSrc source pixmap
* @param x source X coordinate.
* @param y source Y coordinate
* @param width width of the rectangle to be copied
* @param height height of the rectangle to be copied
* @param dst pointer to the beginning of the destination data
* @param dst_pitch pitch (in bytes) of the lines of destination data.
*
* DownloadFromScreen() copies data from offscreen memory in pSrc from
* (x, y) to (x + width, y + height), to system memory starting at
* dst (with pitch dst_pitch). This would usually be done
* using scatter-gather DMA, supported by a DRM call, or by blitting to AGP
* and then synchronously reading from AGP. Because the implementation
* might be synchronous, EXA leaves it up to the driver to call
* exaMarkSync() if DownloadFromScreen() was asynchronous. This is in
* contrast to most other acceleration calls in EXA.
*
* DownloadFromScreen() can aid in the largest bottleneck in pixmap
* migration, which is the read from framebuffer when evicting pixmaps from
* framebuffer memory. Thus, it is highly recommended, even though
* implementations are typically complicated.
*
* @return TRUE if the driver successfully downloaded the data. FALSE
* indicates that EXA should fall back to doing the download in software.
*
* DownloadFromScreen() is not required, but is highly recommended.
*/
Bool (*DownloadFromScreen) (PixmapPtr pSrc,
int x, int y,
int w, int h, char *dst, int dst_pitch);
/**
* MarkSync() requests that the driver mark a synchronization point,
* returning an driver-defined integer marker which could be requested for
* synchronization to later in WaitMarker(). This might be used in the
* future to avoid waiting for full hardware stalls before accessing pixmap
* data with the CPU, but is not important in the current incarnation of
* EXA.
*
* Note that drivers should call exaMarkSync() when they have done some
* acceleration, rather than their own MarkSync() handler, as otherwise EXA
* will be unaware of the driver's acceleration and not sync to it during
* fallbacks.
*
* MarkSync() is optional.
*/
int (*MarkSync) (ScreenPtr pScreen);
/**
* WaitMarker() waits for all rendering before the given marker to have
* completed. If the driver does not implement MarkSync(), marker is
* meaningless, and all rendering by the hardware should be completed before
* WaitMarker() returns.
*
* Note that drivers should call exaWaitSync() to wait for all acceleration
* to finish, as otherwise EXA will be unaware of the driver having
* synchronized, resulting in excessive WaitMarker() calls.
*
* WaitMarker() is required of all drivers.
*/
void (*WaitMarker) (ScreenPtr pScreen, int marker);
/** @{ */
/**
* PrepareAccess() is called before CPU access to an offscreen pixmap.
*
* @param pPix the pixmap being accessed
* @param index the index of the pixmap being accessed.
*
* PrepareAccess() will be called before CPU access to an offscreen pixmap.
* This can be used to set up hardware surfaces for byteswapping or
* untiling, or to adjust the pixmap's devPrivate.ptr for the purpose of
* making CPU access use a different aperture.
*
* The index is one of #EXA_PREPARE_DEST, #EXA_PREPARE_SRC,
* #EXA_PREPARE_MASK, #EXA_PREPARE_AUX_DEST, #EXA_PREPARE_AUX_SRC, or
* #EXA_PREPARE_AUX_MASK. Since only up to #EXA_NUM_PREPARE_INDICES pixmaps
* will have PrepareAccess() called on them per operation, drivers can have
* a small, statically-allocated space to maintain state for PrepareAccess()
* and FinishAccess() in. Note that PrepareAccess() is only called once per
* pixmap and operation, regardless of whether the pixmap is used as a
* destination and/or source, and the index may not reflect the usage.
*
* PrepareAccess() may fail. An example might be the case of hardware that
* can set up 1 or 2 surfaces for CPU access, but not 3. If PrepareAccess()
* fails, EXA will migrate the pixmap to system memory.
* DownloadFromScreen() must be implemented and must not fail if a driver
* wishes to fail in PrepareAccess(). PrepareAccess() must not fail when
* pPix is the visible screen, because the visible screen can not be
* migrated.
*
* @return TRUE if PrepareAccess() successfully prepared the pixmap for CPU
* drawing.
* @return FALSE if PrepareAccess() is unsuccessful and EXA should use
* DownloadFromScreen() to migate the pixmap out.
*/
Bool (*PrepareAccess) (PixmapPtr pPix, int index);
/**
* FinishAccess() is called after CPU access to an offscreen pixmap.
*
* @param pPix the pixmap being accessed
* @param index the index of the pixmap being accessed.
*
* FinishAccess() will be called after finishing CPU access of an offscreen
* pixmap set up by PrepareAccess(). Note that the FinishAccess() will not be
* called if PrepareAccess() failed and the pixmap was migrated out.
*/
void (*FinishAccess) (PixmapPtr pPix, int index);
/**
* PixmapIsOffscreen() is an optional driver replacement to
* exaPixmapHasGpuCopy(). Set to NULL if you want the standard behaviour
* of exaPixmapHasGpuCopy().
*
* @param pPix the pixmap
* @return TRUE if the given drawable is in framebuffer memory.
*
* exaPixmapHasGpuCopy() is used to determine if a pixmap is in offscreen
* memory, meaning that acceleration could probably be done to it, and that it
* will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it
* with the CPU.
*
*
*/
Bool (*PixmapIsOffscreen) (PixmapPtr pPix);
/** @name PrepareAccess() and FinishAccess() indices
* @{
*/
/**
* EXA_PREPARE_DEST is the index for a pixmap that may be drawn to or
* read from.
*/
#define EXA_PREPARE_DEST 0
/**
* EXA_PREPARE_SRC is the index for a pixmap that may be read from
*/
#define EXA_PREPARE_SRC 1
/**
* EXA_PREPARE_SRC is the index for a second pixmap that may be read
* from.
*/
#define EXA_PREPARE_MASK 2
/**
* EXA_PREPARE_AUX* are additional indices for other purposes, e.g.
* separate alpha maps with Composite operations.
*/
#define EXA_PREPARE_AUX_DEST 3
#define EXA_PREPARE_AUX_SRC 4
#define EXA_PREPARE_AUX_MASK 5
#define EXA_NUM_PREPARE_INDICES 6
/** @} */
/**
* maxPitchPixels controls the pitch limitation for rendering from
* the card.
* The driver should never receive a request for rendering a pixmap
* that has a pitch (in pixels) beyond maxPitchPixels.
*
* Setting this field is optional -- if your hardware doesn't have
* a pitch limitation in pixels, don't set this. If neither this value
* nor maxPitchBytes is set, then maxPitchPixels is set to maxX.
* If set, it must not be smaller than maxX.
*
* @sa maxPitchBytes
*/
int maxPitchPixels;
/**
* maxPitchBytes controls the pitch limitation for rendering from
* the card.
* The driver should never receive a request for rendering a pixmap
* that has a pitch (in bytes) beyond maxPitchBytes.
*
* Setting this field is optional -- if your hardware doesn't have
* a pitch limitation in bytes, don't set this.
* If set, it must not be smaller than maxX * 4.
* There's no default value for maxPitchBytes.
*
* @sa maxPitchPixels
*/
int maxPitchBytes;
/* Hooks to allow driver to its own pixmap memory management */
void *(*CreatePixmap) (ScreenPtr pScreen, int size, int align);
void (*DestroyPixmap) (ScreenPtr pScreen, void *driverPriv);
/**
* Returning a pixmap with non-NULL devPrivate.ptr implies a pixmap which is
* not offscreen, which will never be accelerated and Prepare/FinishAccess won't
* be called.
*/
Bool (*ModifyPixmapHeader) (PixmapPtr pPixmap, int width, int height,
int depth, int bitsPerPixel, int devKind,
void *pPixData);
/* hooks for drivers with tiling support:
* driver MUST fill out new_fb_pitch with valid pitch of pixmap
*/
void *(*CreatePixmap2) (ScreenPtr pScreen, int width, int height,
int depth, int usage_hint, int bitsPerPixel,
int *new_fb_pitch);
/** @} */
Bool (*SharePixmapBacking)(PixmapPtr pPixmap, ScreenPtr secondary, void **handle_p);
Bool (*SetSharedPixmapBacking)(PixmapPtr pPixmap, void *handle);
} ExaDriverRec, *ExaDriverPtr;
/** @name EXA driver flags
* @{
*/
/**
* EXA_OFFSCREEN_PIXMAPS indicates to EXA that the driver can support
* offscreen pixmaps.
*/
#define EXA_OFFSCREEN_PIXMAPS (1 << 0)
/**
* EXA_OFFSCREEN_ALIGN_POT indicates to EXA that the driver needs pixmaps
* to have a power-of-two pitch.
*/
#define EXA_OFFSCREEN_ALIGN_POT (1 << 1)
/**
* EXA_TWO_BITBLT_DIRECTIONS indicates to EXA that the driver can only
* support copies that are (left-to-right, top-to-bottom) or
* (right-to-left, bottom-to-top).
*/
#define EXA_TWO_BITBLT_DIRECTIONS (1 << 2)
/**
* EXA_HANDLES_PIXMAPS indicates to EXA that the driver can handle
* all pixmap addressing and migration.
*/
#define EXA_HANDLES_PIXMAPS (1 << 3)
/**
* EXA_SUPPORTS_PREPARE_AUX indicates to EXA that the driver can handle the
* EXA_PREPARE_AUX* indices in the Prepare/FinishAccess hooks. If there are no
* such hooks, this flag has no effect.
*/
#define EXA_SUPPORTS_PREPARE_AUX (1 << 4)
/**
* EXA_SUPPORTS_OFFSCREEN_OVERLAPS indicates to EXA that the driver Copy hooks
* can handle the source and destination occupying overlapping offscreen memory
* areas. This allows the offscreen memory defragmentation code to defragment
* areas where the defragmented position overlaps the fragmented position.
*
* Typically this is supported by traditional 2D engines but not by 3D engines.
*/
#define EXA_SUPPORTS_OFFSCREEN_OVERLAPS (1 << 5)
/**
* EXA_MIXED_PIXMAPS will hide unacceleratable pixmaps from drivers and manage the
* problem known software fallbacks like trapezoids. This only migrates pixmaps one way
* into a driver pixmap and then pins it.
*/
#define EXA_MIXED_PIXMAPS (1 << 6)
/** @} */
/* in exa.c */
extern _X_EXPORT ExaDriverPtr exaDriverAlloc(void);
extern _X_EXPORT Bool
exaDriverInit(ScreenPtr pScreen, ExaDriverPtr pScreenInfo);
extern _X_EXPORT void
exaDriverFini(ScreenPtr pScreen);
extern _X_EXPORT void
exaMarkSync(ScreenPtr pScreen);
extern _X_EXPORT void
exaWaitSync(ScreenPtr pScreen);
extern _X_EXPORT unsigned long
exaGetPixmapOffset(PixmapPtr pPix);
extern _X_EXPORT unsigned long
exaGetPixmapPitch(PixmapPtr pPix);
extern _X_EXPORT unsigned long
exaGetPixmapSize(PixmapPtr pPix);
extern _X_EXPORT void *exaGetPixmapDriverPrivate(PixmapPtr p);
/* in exa_offscreen.c */
extern _X_EXPORT ExaOffscreenArea *exaOffscreenAlloc(ScreenPtr pScreen,
int size, int align,
Bool locked,
ExaOffscreenSaveProc save,
void *privData);
extern _X_EXPORT ExaOffscreenArea *exaOffscreenFree(ScreenPtr pScreen,
ExaOffscreenArea * area);
extern _X_EXPORT void
ExaOffscreenMarkUsed(PixmapPtr pPixmap);
extern _X_EXPORT void
exaEnableDisableFBAccess(ScreenPtr pScreen, Bool enable);
extern _X_EXPORT Bool
exaDrawableIsOffscreen(DrawablePtr pDrawable);
/* in exa.c */
extern _X_EXPORT void
exaMoveInPixmap(PixmapPtr pPixmap);
extern _X_EXPORT void
exaMoveOutPixmap(PixmapPtr pPixmap);
/* in exa_unaccel.c */
extern _X_EXPORT CARD32
exaGetPixmapFirstPixel(PixmapPtr pPixmap);
/**
* Returns TRUE if the given planemask covers all the significant bits in the
* pixel values for pDrawable.
*/
#define EXA_PM_IS_SOLID(_pDrawable, _pm) \
(((_pm) & FbFullMask((_pDrawable)->depth)) == \
FbFullMask((_pDrawable)->depth))
#endif /* EXA_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,265 +0,0 @@
/*
* Copyright © 2009 Maarten Maathuis
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <string.h>
#include "exa_priv.h"
#include "exa.h"
/* This file holds the classic exa specific implementation. */
static _X_INLINE void *
ExaGetPixmapAddress(PixmapPtr p)
{
ExaPixmapPriv(p);
if (pExaPixmap->use_gpu_copy && pExaPixmap->fb_ptr)
return pExaPixmap->fb_ptr;
else
return pExaPixmap->sys_ptr;
}
/**
* exaCreatePixmap() creates a new pixmap.
*
* If width and height are 0, this won't be a full-fledged pixmap and it will
* get ModifyPixmapHeader() called on it later. So, we mark it as pinned, because
* ModifyPixmapHeader() would break migration. These types of pixmaps are used
* for scratch pixmaps, or to represent the visible screen.
*/
PixmapPtr
exaCreatePixmap_classic(ScreenPtr pScreen, int w, int h, int depth,
unsigned usage_hint)
{
PixmapPtr pPixmap;
ExaPixmapPrivPtr pExaPixmap;
BoxRec box;
int bpp;
ExaScreenPriv(pScreen);
if (w > 32767 || h > 32767)
return NullPixmap;
swap(pExaScr, pScreen, CreatePixmap);
pPixmap = pScreen->CreatePixmap(pScreen, w, h, depth, usage_hint);
swap(pExaScr, pScreen, CreatePixmap);
if (!pPixmap)
return NULL;
pExaPixmap = ExaGetPixmapPriv(pPixmap);
pExaPixmap->driverPriv = NULL;
bpp = pPixmap->drawable.bitsPerPixel;
pExaPixmap->driverPriv = NULL;
/* Scratch pixmaps may have w/h equal to zero, and may not be
* migrated.
*/
if (!w || !h)
pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
else
pExaPixmap->score = EXA_PIXMAP_SCORE_INIT;
pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
pExaPixmap->sys_pitch = pPixmap->devKind;
pPixmap->devPrivate.ptr = NULL;
pExaPixmap->use_gpu_copy = FALSE;
pExaPixmap->fb_ptr = NULL;
exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
pExaPixmap->fb_size = pExaPixmap->fb_pitch * h;
if (pExaPixmap->fb_pitch > 131071) {
swap(pExaScr, pScreen, DestroyPixmap);
pScreen->DestroyPixmap(pPixmap);
swap(pExaScr, pScreen, DestroyPixmap);
return NULL;
}
/* Set up damage tracking */
pExaPixmap->pDamage = DamageCreate(NULL, NULL,
DamageReportNone, TRUE,
pScreen, pPixmap);
if (pExaPixmap->pDamage == NULL) {
swap(pExaScr, pScreen, DestroyPixmap);
pScreen->DestroyPixmap(pPixmap);
swap(pExaScr, pScreen, DestroyPixmap);
return NULL;
}
DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage);
/* This ensures that pending damage reflects the current operation. */
/* This is used by exa to optimize migration. */
DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE);
pExaPixmap->area = NULL;
/* We set the initial pixmap as completely valid for a simple reason.
* Imagine a 1000x1000 pixmap, it has 1 million pixels, 250000 of which
* could form single pixel rects as part of a region. Setting the complete region
* as valid is a natural defragmentation of the region.
*/
box.x1 = 0;
box.y1 = 0;
box.x2 = w;
box.y2 = h;
RegionInit(&pExaPixmap->validSys, &box, 0);
RegionInit(&pExaPixmap->validFB, &box, 0);
exaSetAccelBlock(pExaScr, pExaPixmap, w, h, bpp);
/* During a fallback we must prepare access. */
if (pExaScr->fallback_counter)
exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
return pPixmap;
}
Bool
exaModifyPixmapHeader_classic(PixmapPtr pPixmap, int width, int height,
int depth, int bitsPerPixel, int devKind,
void *pPixData)
{
ScreenPtr pScreen;
ExaScreenPrivPtr pExaScr;
ExaPixmapPrivPtr pExaPixmap;
Bool ret;
if (!pPixmap)
return FALSE;
pScreen = pPixmap->drawable.pScreen;
pExaScr = ExaGetScreenPriv(pScreen);
pExaPixmap = ExaGetPixmapPriv(pPixmap);
if (pExaPixmap) {
if (pPixData)
pExaPixmap->sys_ptr = pPixData;
if (devKind > 0)
pExaPixmap->sys_pitch = devKind;
/* Classic EXA:
* - Framebuffer.
* - Scratch pixmap with gpu memory.
*/
if (pExaScr->info->memoryBase && pPixData) {
if ((CARD8 *) pPixData >= pExaScr->info->memoryBase &&
((CARD8 *) pPixData - pExaScr->info->memoryBase) <
pExaScr->info->memorySize) {
pExaPixmap->fb_ptr = pPixData;
pExaPixmap->fb_pitch = devKind;
pExaPixmap->use_gpu_copy = TRUE;
}
}
if (width > 0 && height > 0 && bitsPerPixel > 0) {
exaSetFbPitch(pExaScr, pExaPixmap, width, height, bitsPerPixel);
exaSetAccelBlock(pExaScr, pExaPixmap, width, height, bitsPerPixel);
}
/* Pixmaps subject to ModifyPixmapHeader will be pinned to system or
* gpu memory, so there's no need to track damage.
*/
if (pExaPixmap->pDamage) {
DamageDestroy(pExaPixmap->pDamage);
pExaPixmap->pDamage = NULL;
}
}
swap(pExaScr, pScreen, ModifyPixmapHeader);
ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
bitsPerPixel, devKind, pPixData);
swap(pExaScr, pScreen, ModifyPixmapHeader);
/* Always NULL this, we don't want lingering pointers. */
pPixmap->devPrivate.ptr = NULL;
return ret;
}
Bool
exaDestroyPixmap_classic(PixmapPtr pPixmap)
{
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv(pScreen);
Bool ret;
if (pPixmap->refcnt == 1) {
ExaPixmapPriv(pPixmap);
exaDestroyPixmap(pPixmap);
if (pExaPixmap->area) {
DBG_PIXMAP(("-- 0x%p (0x%x) (%dx%d)\n",
(void *) pPixmap->drawable.id,
ExaGetPixmapPriv(pPixmap)->area->offset,
pPixmap->drawable.width, pPixmap->drawable.height));
/* Free the offscreen area */
exaOffscreenFree(pPixmap->drawable.pScreen, pExaPixmap->area);
pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
pPixmap->devKind = pExaPixmap->sys_pitch;
}
RegionUninit(&pExaPixmap->validSys);
RegionUninit(&pExaPixmap->validFB);
}
swap(pExaScr, pScreen, DestroyPixmap);
ret = pScreen->DestroyPixmap(pPixmap);
swap(pExaScr, pScreen, DestroyPixmap);
return ret;
}
Bool
exaPixmapHasGpuCopy_classic(PixmapPtr pPixmap)
{
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv(pScreen);
ExaPixmapPriv(pPixmap);
Bool ret;
if (pExaScr->info->PixmapIsOffscreen) {
void *old_ptr = pPixmap->devPrivate.ptr;
pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
pPixmap->devPrivate.ptr = old_ptr;
}
else
ret = (pExaPixmap->use_gpu_copy && pExaPixmap->fb_ptr);
return ret;
}

View File

@ -1,230 +0,0 @@
/*
* Copyright © 2009 Maarten Maathuis
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <string.h>
#include "exa_priv.h"
#include "exa.h"
/* This file holds the driver allocated pixmaps specific implementation. */
static _X_INLINE void *
ExaGetPixmapAddress(PixmapPtr p)
{
ExaPixmapPriv(p);
return pExaPixmap->sys_ptr;
}
/**
* exaCreatePixmap() creates a new pixmap.
*
* Pixmaps are always marked as pinned, because exa has no control over them.
*/
PixmapPtr
exaCreatePixmap_driver(ScreenPtr pScreen, int w, int h, int depth,
unsigned usage_hint)
{
PixmapPtr pPixmap;
ExaPixmapPrivPtr pExaPixmap;
int bpp;
size_t paddedWidth, datasize;
ExaScreenPriv(pScreen);
if (w > 32767 || h > 32767)
return NullPixmap;
swap(pExaScr, pScreen, CreatePixmap);
pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint);
swap(pExaScr, pScreen, CreatePixmap);
if (!pPixmap)
return NULL;
pExaPixmap = ExaGetPixmapPriv(pPixmap);
pExaPixmap->driverPriv = NULL;
bpp = pPixmap->drawable.bitsPerPixel;
/* Set this before driver hooks, to allow for driver pixmaps without gpu
* memory to back it. These pixmaps have a valid pointer at all times.
*/
pPixmap->devPrivate.ptr = NULL;
if (pExaScr->info->CreatePixmap2) {
int new_pitch = 0;
pExaPixmap->driverPriv =
pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp,
&new_pitch);
paddedWidth = pExaPixmap->fb_pitch = new_pitch;
}
else {
paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
if (paddedWidth / 4 > 32767 || h > 32767)
return NullPixmap;
exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
if (paddedWidth < pExaPixmap->fb_pitch)
paddedWidth = pExaPixmap->fb_pitch;
datasize = h * paddedWidth;
pExaPixmap->driverPriv =
pExaScr->info->CreatePixmap(pScreen, datasize, 0);
}
if (!pExaPixmap->driverPriv) {
swap(pExaScr, pScreen, DestroyPixmap);
pScreen->DestroyPixmap(pPixmap);
swap(pExaScr, pScreen, DestroyPixmap);
return NULL;
}
/* Allow ModifyPixmapHeader to set sys_ptr appropriately. */
pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
pExaPixmap->fb_ptr = NULL;
pExaPixmap->pDamage = NULL;
pExaPixmap->sys_ptr = NULL;
(*pScreen->ModifyPixmapHeader) (pPixmap, w, h, 0, 0, paddedWidth, NULL);
pExaPixmap->area = NULL;
exaSetAccelBlock(pExaScr, pExaPixmap, w, h, bpp);
pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
/* During a fallback we must prepare access. */
if (pExaScr->fallback_counter)
exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
return pPixmap;
}
Bool
exaModifyPixmapHeader_driver(PixmapPtr pPixmap, int width, int height,
int depth, int bitsPerPixel, int devKind,
void *pPixData)
{
ScreenPtr pScreen;
ExaScreenPrivPtr pExaScr;
ExaPixmapPrivPtr pExaPixmap;
Bool ret;
if (!pPixmap)
return FALSE;
pScreen = pPixmap->drawable.pScreen;
pExaScr = ExaGetScreenPriv(pScreen);
pExaPixmap = ExaGetPixmapPriv(pPixmap);
if (pExaPixmap) {
if (pPixData)
pExaPixmap->sys_ptr = pPixData;
if (devKind > 0)
pExaPixmap->sys_pitch = devKind;
if (width > 0 && height > 0 && bitsPerPixel > 0) {
exaSetFbPitch(pExaScr, pExaPixmap, width, height, bitsPerPixel);
exaSetAccelBlock(pExaScr, pExaPixmap, width, height, bitsPerPixel);
}
}
if (pExaScr->info->ModifyPixmapHeader) {
ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth,
bitsPerPixel, devKind,
pPixData);
/* For EXA_HANDLES_PIXMAPS, we set pPixData to NULL.
* If pPixmap->devPrivate.ptr is non-NULL, then we've got a
* !has_gpu_copy pixmap. We need to store the pointer,
* because PrepareAccess won't be called.
*/
if (!pPixData && pPixmap->devPrivate.ptr && pPixmap->devKind) {
pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
pExaPixmap->sys_pitch = pPixmap->devKind;
}
if (ret == TRUE)
goto out;
}
swap(pExaScr, pScreen, ModifyPixmapHeader);
ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
bitsPerPixel, devKind, pPixData);
swap(pExaScr, pScreen, ModifyPixmapHeader);
out:
/* Always NULL this, we don't want lingering pointers. */
pPixmap->devPrivate.ptr = NULL;
return ret;
}
Bool
exaDestroyPixmap_driver(PixmapPtr pPixmap)
{
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv(pScreen);
Bool ret;
if (pPixmap->refcnt == 1) {
ExaPixmapPriv(pPixmap);
exaDestroyPixmap(pPixmap);
if (pExaPixmap->driverPriv)
pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
pExaPixmap->driverPriv = NULL;
}
swap(pExaScr, pScreen, DestroyPixmap);
ret = pScreen->DestroyPixmap(pPixmap);
swap(pExaScr, pScreen, DestroyPixmap);
return ret;
}
Bool
exaPixmapHasGpuCopy_driver(PixmapPtr pPixmap)
{
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv(pScreen);
void *saved_ptr;
Bool ret;
saved_ptr = pPixmap->devPrivate.ptr;
pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
pPixmap->devPrivate.ptr = saved_ptr;
return ret;
}

View File

@ -1,839 +0,0 @@
/*
* Copyright © 2008 Red Hat, Inc.
* Partly based on code Copyright © 2000 SuSE, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Red Hat not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. Red Hat makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: Owen Taylor <otaylor@fishsoup.net>
* Based on code by: Keith Packard
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <stdlib.h>
#include "exa_priv.h"
#include "mipict.h"
#if DEBUG_GLYPH_CACHE
#define DBG_GLYPH_CACHE(a) ErrorF a
#else
#define DBG_GLYPH_CACHE(a)
#endif
/* Width of the pixmaps we use for the caches; this should be less than
* max texture size of the driver; this may need to actually come from
* the driver.
*/
#define CACHE_PICTURE_WIDTH 1024
/* Maximum number of glyphs we buffer on the stack before flushing
* rendering to the mask or destination surface.
*/
#define GLYPH_BUFFER_SIZE 256
typedef struct {
PicturePtr mask;
ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE];
int count;
} ExaGlyphBuffer, *ExaGlyphBufferPtr;
typedef enum {
ExaGlyphSuccess, /* Glyph added to render buffer */
ExaGlyphFail, /* out of memory, etc */
ExaGlyphNeedFlush, /* would evict a glyph already in the buffer */
} ExaGlyphCacheResult;
void
exaGlyphsInit(ScreenPtr pScreen)
{
ExaScreenPriv(pScreen);
int i = 0;
memset(pExaScr->glyphCaches, 0, sizeof(pExaScr->glyphCaches));
pExaScr->glyphCaches[i].format = PICT_a8;
pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight =
16;
i++;
pExaScr->glyphCaches[i].format = PICT_a8;
pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight =
32;
i++;
pExaScr->glyphCaches[i].format = PICT_a8r8g8b8;
pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight =
16;
i++;
pExaScr->glyphCaches[i].format = PICT_a8r8g8b8;
pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight =
32;
i++;
assert(i == EXA_NUM_GLYPH_CACHES);
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
pExaScr->glyphCaches[i].columns =
CACHE_PICTURE_WIDTH / pExaScr->glyphCaches[i].glyphWidth;
pExaScr->glyphCaches[i].size = 256;
pExaScr->glyphCaches[i].hashSize = 557;
}
}
static void
exaUnrealizeGlyphCaches(ScreenPtr pScreen, unsigned int format)
{
ExaScreenPriv(pScreen);
int i;
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
if (cache->format != format)
continue;
if (cache->picture) {
FreePicture((void *) cache->picture, (XID) 0);
cache->picture = NULL;
}
free(cache->hashEntries);
cache->hashEntries = NULL;
free(cache->glyphs);
cache->glyphs = NULL;
cache->glyphCount = 0;
}
}
#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
/* All caches for a single format share a single pixmap for glyph storage,
* allowing mixing glyphs of different sizes without paying a penalty
* for switching between mask pixmaps. (Note that for a size of font
* right at the border between two sizes, we might be switching for almost
* every glyph.)
*
* This function allocates the storage pixmap, and then fills in the
* rest of the allocated structures for all caches with the given format.
*/
static Bool
exaRealizeGlyphCaches(ScreenPtr pScreen, unsigned int format)
{
ExaScreenPriv(pScreen);
int depth = PIXMAN_FORMAT_DEPTH(format);
PictFormatPtr pPictFormat;
PixmapPtr pPixmap;
PicturePtr pPicture;
CARD32 component_alpha;
int height;
int i;
int error;
pPictFormat = PictureMatchFormat(pScreen, depth, format);
if (!pPictFormat)
return FALSE;
/* Compute the total vertical size needed for the format */
height = 0;
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
int rows;
if (cache->format != format)
continue;
cache->yOffset = height;
rows = (cache->size + cache->columns - 1) / cache->columns;
height += rows * cache->glyphHeight;
}
/* Now allocate the pixmap and picture */
pPixmap = (*pScreen->CreatePixmap) (pScreen,
CACHE_PICTURE_WIDTH, height, depth, 0);
if (!pPixmap)
return FALSE;
component_alpha = NeedsComponent(pPictFormat->format);
pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat,
CPComponentAlpha, &component_alpha, serverClient,
&error);
(*pScreen->DestroyPixmap) (pPixmap); /* picture holds a refcount */
if (!pPicture)
return FALSE;
/* And store the picture in all the caches for the format */
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
int j;
if (cache->format != format)
continue;
cache->picture = pPicture;
cache->picture->refcnt++;
cache->hashEntries = xallocarray(cache->hashSize, sizeof(int));
cache->glyphs = xallocarray(cache->size, sizeof(ExaCachedGlyphRec));
cache->glyphCount = 0;
if (!cache->hashEntries || !cache->glyphs)
goto bail;
for (j = 0; j < cache->hashSize; j++)
cache->hashEntries[j] = -1;
cache->evictionPosition = rand() % cache->size;
}
/* Each cache references the picture individually */
FreePicture((void *) pPicture, (XID) 0);
return TRUE;
bail:
exaUnrealizeGlyphCaches(pScreen, format);
return FALSE;
}
void
exaGlyphsFini(ScreenPtr pScreen)
{
ExaScreenPriv(pScreen);
int i;
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
if (cache->picture)
exaUnrealizeGlyphCaches(pScreen, cache->format);
}
}
static int
exaGlyphCacheHashLookup(ExaGlyphCachePtr cache, GlyphPtr pGlyph)
{
int slot;
slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize;
while (TRUE) { /* hash table can never be full */
int entryPos = cache->hashEntries[slot];
if (entryPos == -1)
return -1;
if (memcmp
(pGlyph->sha1, cache->glyphs[entryPos].sha1,
sizeof(pGlyph->sha1)) == 0) {
return entryPos;
}
slot--;
if (slot < 0)
slot = cache->hashSize - 1;
}
}
static void
exaGlyphCacheHashInsert(ExaGlyphCachePtr cache, GlyphPtr pGlyph, int pos)
{
int slot;
memcpy(cache->glyphs[pos].sha1, pGlyph->sha1, sizeof(pGlyph->sha1));
slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize;
while (TRUE) { /* hash table can never be full */
if (cache->hashEntries[slot] == -1) {
cache->hashEntries[slot] = pos;
return;
}
slot--;
if (slot < 0)
slot = cache->hashSize - 1;
}
}
static void
exaGlyphCacheHashRemove(ExaGlyphCachePtr cache, int pos)
{
int slot;
int emptiedSlot = -1;
slot = (*(CARD32 *) cache->glyphs[pos].sha1) % cache->hashSize;
while (TRUE) { /* hash table can never be full */
int entryPos = cache->hashEntries[slot];
if (entryPos == -1)
return;
if (entryPos == pos) {
cache->hashEntries[slot] = -1;
emptiedSlot = slot;
}
else if (emptiedSlot != -1) {
/* See if we can move this entry into the emptied slot, we can't
* do that if if entry would have hashed between the current position
* and the emptied slot. (taking wrapping into account). Bad positions
* are:
*
* | XXXXXXXXXX |
* i j
*
* |XXX XXXX|
* j i
*
* i - slot, j - emptiedSlot
*
* (Knuth 6.4R)
*/
int entrySlot =
(*(CARD32 *) cache->glyphs[entryPos].sha1) % cache->hashSize;
if (!((entrySlot >= slot && entrySlot < emptiedSlot) ||
(emptiedSlot < slot &&
(entrySlot < emptiedSlot || entrySlot >= slot)))) {
cache->hashEntries[emptiedSlot] = entryPos;
cache->hashEntries[slot] = -1;
emptiedSlot = slot;
}
}
slot--;
if (slot < 0)
slot = cache->hashSize - 1;
}
}
#define CACHE_X(pos) (((pos) % cache->columns) * cache->glyphWidth)
#define CACHE_Y(pos) (cache->yOffset + ((pos) / cache->columns) * cache->glyphHeight)
/* The most efficient thing to way to upload the glyph to the screen
* is to use the UploadToScreen() driver hook; this allows us to
* pipeline glyph uploads and to avoid creating gpu backed pixmaps for
* glyphs that we'll never use again.
*
* If we can't do it with UploadToScreen (because the glyph has a gpu copy,
* etc), we fall back to CompositePicture.
*
* We need to damage the cache pixmap manually in either case because the damage
* layer unwrapped the picture screen before calling exaGlyphs.
*/
static void
exaGlyphCacheUploadGlyph(ScreenPtr pScreen,
ExaGlyphCachePtr cache, int x, int y, GlyphPtr pGlyph)
{
ExaScreenPriv(pScreen);
PicturePtr pGlyphPicture = GetGlyphPicture(pGlyph, pScreen);
PixmapPtr pGlyphPixmap = (PixmapPtr) pGlyphPicture->pDrawable;
ExaPixmapPriv(pGlyphPixmap);
PixmapPtr pCachePixmap = (PixmapPtr) cache->picture->pDrawable;
if (!pExaScr->info->UploadToScreen || pExaScr->swappedOut ||
pExaPixmap->accel_blocked)
goto composite;
/* If the glyph pixmap is already uploaded, no point in doing
* things this way */
if (exaPixmapHasGpuCopy(pGlyphPixmap))
goto composite;
/* UploadToScreen only works if bpp match */
if (pGlyphPixmap->drawable.bitsPerPixel !=
pCachePixmap->drawable.bitsPerPixel)
goto composite;
if (pExaScr->do_migration) {
ExaMigrationRec pixmaps[1];
/* cache pixmap must have a gpu copy. */
pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = FALSE;
pixmaps[0].pPix = pCachePixmap;
pixmaps[0].pReg = NULL;
exaDoMigration(pixmaps, 1, TRUE);
}
if (!exaPixmapHasGpuCopy(pCachePixmap))
goto composite;
/* x,y are in pixmap coordinates, no need for cache{X,Y}off */
if (pExaScr->info->UploadToScreen(pCachePixmap,
x,
y,
pGlyph->info.width,
pGlyph->info.height,
(char *) pExaPixmap->sys_ptr,
pExaPixmap->sys_pitch))
goto damage;
composite:
CompositePicture(PictOpSrc,
pGlyphPicture,
None,
cache->picture,
0, 0, 0, 0, x, y, pGlyph->info.width, pGlyph->info.height);
damage:
/* The cache pixmap isn't a window, so no need to offset coordinates. */
exaPixmapDirty(pCachePixmap,
x, y, x + cache->glyphWidth, y + cache->glyphHeight);
}
static ExaGlyphCacheResult
exaGlyphCacheBufferGlyph(ScreenPtr pScreen,
ExaGlyphCachePtr cache,
ExaGlyphBufferPtr buffer,
GlyphPtr pGlyph,
PicturePtr pSrc,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst)
{
ExaCompositeRectPtr rect;
int pos;
int x, y;
if (buffer->mask && buffer->mask != cache->picture)
return ExaGlyphNeedFlush;
if (!cache->picture) {
if (!exaRealizeGlyphCaches(pScreen, cache->format))
return ExaGlyphFail;
}
DBG_GLYPH_CACHE(("(%d,%d,%s): buffering glyph %lx\n",
cache->glyphWidth, cache->glyphHeight,
cache->format == PICT_a8 ? "A" : "ARGB",
(long) *(CARD32 *) pGlyph->sha1));
pos = exaGlyphCacheHashLookup(cache, pGlyph);
if (pos != -1) {
DBG_GLYPH_CACHE((" found existing glyph at %d\n", pos));
x = CACHE_X(pos);
y = CACHE_Y(pos);
}
else {
if (cache->glyphCount < cache->size) {
/* Space remaining; we fill from the start */
pos = cache->glyphCount;
x = CACHE_X(pos);
y = CACHE_Y(pos);
cache->glyphCount++;
DBG_GLYPH_CACHE((" storing glyph in free space at %d\n", pos));
exaGlyphCacheHashInsert(cache, pGlyph, pos);
}
else {
/* Need to evict an entry. We have to see if any glyphs
* already in the output buffer were at this position in
* the cache
*/
pos = cache->evictionPosition;
x = CACHE_X(pos);
y = CACHE_Y(pos);
DBG_GLYPH_CACHE((" evicting glyph at %d\n", pos));
if (buffer->count) {
int i;
for (i = 0; i < buffer->count; i++) {
if (pSrc ?
(buffer->rects[i].xMask == x &&
buffer->rects[i].yMask ==
y) : (buffer->rects[i].xSrc == x &&
buffer->rects[i].ySrc == y)) {
DBG_GLYPH_CACHE((" must flush buffer\n"));
return ExaGlyphNeedFlush;
}
}
}
/* OK, we're all set, swap in the new glyph */
exaGlyphCacheHashRemove(cache, pos);
exaGlyphCacheHashInsert(cache, pGlyph, pos);
/* And pick a new eviction position */
cache->evictionPosition = rand() % cache->size;
}
exaGlyphCacheUploadGlyph(pScreen, cache, x, y, pGlyph);
}
buffer->mask = cache->picture;
rect = &buffer->rects[buffer->count];
if (pSrc) {
rect->xSrc = xSrc;
rect->ySrc = ySrc;
rect->xMask = x;
rect->yMask = y;
}
else {
rect->xSrc = x;
rect->ySrc = y;
rect->xMask = 0;
rect->yMask = 0;
}
rect->pDst = pDst;
rect->xDst = xDst;
rect->yDst = yDst;
rect->width = pGlyph->info.width;
rect->height = pGlyph->info.height;
buffer->count++;
return ExaGlyphSuccess;
}
#undef CACHE_X
#undef CACHE_Y
static ExaGlyphCacheResult
exaBufferGlyph(ScreenPtr pScreen,
ExaGlyphBufferPtr buffer,
GlyphPtr pGlyph,
PicturePtr pSrc,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst)
{
ExaScreenPriv(pScreen);
unsigned int format = (GetGlyphPicture(pGlyph, pScreen))->format;
int width = pGlyph->info.width;
int height = pGlyph->info.height;
ExaCompositeRectPtr rect;
PicturePtr mask;
int i;
if (buffer->count == GLYPH_BUFFER_SIZE)
return ExaGlyphNeedFlush;
if (PICT_FORMAT_BPP(format) == 1)
format = PICT_a8;
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
if (format == cache->format &&
width <= cache->glyphWidth && height <= cache->glyphHeight) {
ExaGlyphCacheResult result = exaGlyphCacheBufferGlyph(pScreen,
&pExaScr->
glyphCaches
[i],
buffer,
pGlyph,
pSrc,
pDst,
xSrc, ySrc,
xMask, yMask,
xDst, yDst);
switch (result) {
case ExaGlyphFail:
break;
case ExaGlyphSuccess:
case ExaGlyphNeedFlush:
return result;
}
}
}
/* Couldn't find the glyph in the cache, use the glyph picture directly */
mask = GetGlyphPicture(pGlyph, pScreen);
if (buffer->mask && buffer->mask != mask)
return ExaGlyphNeedFlush;
buffer->mask = mask;
rect = &buffer->rects[buffer->count];
rect->xSrc = xSrc;
rect->ySrc = ySrc;
rect->xMask = xMask;
rect->yMask = yMask;
rect->xDst = xDst;
rect->yDst = yDst;
rect->width = width;
rect->height = height;
buffer->count++;
return ExaGlyphSuccess;
}
static void
exaGlyphsToMask(PicturePtr pMask, ExaGlyphBufferPtr buffer)
{
exaCompositeRects(PictOpAdd, buffer->mask, NULL, pMask,
buffer->count, buffer->rects);
buffer->count = 0;
buffer->mask = NULL;
}
static void
exaGlyphsToDst(CARD8 op, PicturePtr pSrc, PicturePtr pDst, ExaGlyphBufferPtr buffer)
{
exaCompositeRects(op, pSrc, buffer->mask, pDst, buffer->count,
buffer->rects);
buffer->count = 0;
buffer->mask = NULL;
}
/* Cut and paste from render/glyph.c - probably should export it instead */
static void
GlyphExtents(int nlist, GlyphListPtr list, GlyphPtr * glyphs, BoxPtr extents)
{
int x1, x2, y1, y2;
int n;
GlyphPtr glyph;
int x, y;
x = 0;
y = 0;
extents->x1 = MAXSHORT;
extents->x2 = MINSHORT;
extents->y1 = MAXSHORT;
extents->y2 = MINSHORT;
while (nlist--) {
x += list->xOff;
y += list->yOff;
n = list->len;
list++;
while (n--) {
glyph = *glyphs++;
x1 = x - glyph->info.x;
if (x1 < MINSHORT)
x1 = MINSHORT;
y1 = y - glyph->info.y;
if (y1 < MINSHORT)
y1 = MINSHORT;
x2 = x1 + glyph->info.width;
if (x2 > MAXSHORT)
x2 = MAXSHORT;
y2 = y1 + glyph->info.height;
if (y2 > MAXSHORT)
y2 = MAXSHORT;
if (x1 < extents->x1)
extents->x1 = x1;
if (x2 > extents->x2)
extents->x2 = x2;
if (y1 < extents->y1)
extents->y1 = y1;
if (y2 > extents->y2)
extents->y2 = y2;
x += glyph->info.xOff;
y += glyph->info.yOff;
}
}
}
void
exaGlyphs(CARD8 op,
PicturePtr pSrc,
PicturePtr pDst,
PictFormatPtr maskFormat,
INT16 xSrc,
INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs)
{
PixmapPtr pMaskPixmap = 0;
PicturePtr pMask = NULL;
ScreenPtr pScreen = pDst->pDrawable->pScreen;
int width = 0, height = 0;
int x, y;
int first_xOff = list->xOff, first_yOff = list->yOff;
int n;
GlyphPtr glyph;
int error;
BoxRec extents = { 0, 0, 0, 0 };
CARD32 component_alpha;
ExaGlyphBuffer buffer;
if (maskFormat) {
ExaScreenPriv(pScreen);
GCPtr pGC;
xRectangle rect;
GlyphExtents(nlist, list, glyphs, &extents);
if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
return;
width = extents.x2 - extents.x1;
height = extents.y2 - extents.y1;
if (maskFormat->depth == 1) {
PictFormatPtr a8Format = PictureMatchFormat(pScreen, 8, PICT_a8);
if (a8Format)
maskFormat = a8Format;
}
pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
maskFormat->depth,
CREATE_PIXMAP_USAGE_SCRATCH);
if (!pMaskPixmap)
return;
component_alpha = NeedsComponent(maskFormat->format);
pMask = CreatePicture(0, &pMaskPixmap->drawable,
maskFormat, CPComponentAlpha, &component_alpha,
serverClient, &error);
if (!pMask ||
(!component_alpha && pExaScr->info->CheckComposite &&
!(*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, NULL, pMask)))
{
PictFormatPtr argbFormat;
(*pScreen->DestroyPixmap) (pMaskPixmap);
if (!pMask)
return;
/* The driver can't seem to composite to a8, let's try argb (but
* without component-alpha) */
FreePicture((void *) pMask, (XID) 0);
argbFormat = PictureMatchFormat(pScreen, 32, PICT_a8r8g8b8);
if (argbFormat)
maskFormat = argbFormat;
pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
maskFormat->depth,
CREATE_PIXMAP_USAGE_SCRATCH);
if (!pMaskPixmap)
return;
pMask = CreatePicture(0, &pMaskPixmap->drawable, maskFormat, 0, 0,
serverClient, &error);
if (!pMask) {
(*pScreen->DestroyPixmap) (pMaskPixmap);
return;
}
}
pGC = GetScratchGC(pMaskPixmap->drawable.depth, pScreen);
ValidateGC(&pMaskPixmap->drawable, pGC);
rect.x = 0;
rect.y = 0;
rect.width = width;
rect.height = height;
(*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect);
FreeScratchGC(pGC);
x = -extents.x1;
y = -extents.y1;
}
else {
x = 0;
y = 0;
}
buffer.count = 0;
buffer.mask = NULL;
while (nlist--) {
x += list->xOff;
y += list->yOff;
n = list->len;
while (n--) {
glyph = *glyphs++;
if (glyph->info.width > 0 && glyph->info.height > 0) {
/* pGlyph->info.{x,y} compensate for empty space in the glyph. */
if (maskFormat) {
if (exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask,
0, 0, 0, 0, x - glyph->info.x,
y - glyph->info.y) ==
ExaGlyphNeedFlush) {
exaGlyphsToMask(pMask, &buffer);
exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask,
0, 0, 0, 0, x - glyph->info.x,
y - glyph->info.y);
}
}
else {
if (exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst,
xSrc + (x - glyph->info.x) - first_xOff,
ySrc + (y - glyph->info.y) - first_yOff,
0, 0, x - glyph->info.x,
y - glyph->info.y)
== ExaGlyphNeedFlush) {
exaGlyphsToDst(op, pSrc, pDst, &buffer);
exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst,
xSrc + (x - glyph->info.x) - first_xOff,
ySrc + (y - glyph->info.y) - first_yOff,
0, 0, x - glyph->info.x,
y - glyph->info.y);
}
}
}
x += glyph->info.xOff;
y += glyph->info.yOff;
}
list++;
}
if (buffer.count) {
if (maskFormat)
exaGlyphsToMask(pMask, &buffer);
else
exaGlyphsToDst(op, pSrc, pDst, &buffer);
}
if (maskFormat) {
x = extents.x1;
y = extents.y1;
CompositePicture(op,
pSrc,
pMask,
pDst,
xSrc + x - first_xOff,
ySrc + y - first_yOff, 0, 0, x, y, width, height);
FreePicture((void *) pMask, (XID) 0);
(*pScreen->DestroyPixmap) (pMaskPixmap);
}
}

View File

@ -1,761 +0,0 @@
/*
* Copyright © 2006 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Authors:
* Eric Anholt <eric@anholt.net>
* Michel Dänzer <michel@tungstengraphics.com>
*
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <string.h>
#include "exa_priv.h"
#include "exa.h"
#if DEBUG_MIGRATE
#define DBG_MIGRATE(a) ErrorF a
#else
#define DBG_MIGRATE(a)
#endif
/**
* The fallback path for UTS/DFS failing is to just memcpy. exaCopyDirtyToSys
* and exaCopyDirtyToFb both needed to do this loop.
*/
static void
exaMemcpyBox(PixmapPtr pPixmap, BoxPtr pbox, CARD8 *src, int src_pitch,
CARD8 *dst, int dst_pitch)
{
int i, cpp = pPixmap->drawable.bitsPerPixel / 8;
int bytes = (pbox->x2 - pbox->x1) * cpp;
src += pbox->y1 * src_pitch + pbox->x1 * cpp;
dst += pbox->y1 * dst_pitch + pbox->x1 * cpp;
for (i = pbox->y2 - pbox->y1; i; i--) {
memcpy(dst, src, bytes);
src += src_pitch;
dst += dst_pitch;
}
}
/**
* Returns TRUE if the pixmap is dirty (has been modified in its current
* location compared to the other), or lacks a private for tracking
* dirtiness.
*/
static Bool
exaPixmapIsDirty(PixmapPtr pPix)
{
ExaPixmapPriv(pPix);
if (pExaPixmap == NULL)
EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsDirty was called on a non-exa pixmap.\n"), TRUE);
if (!pExaPixmap->pDamage)
return FALSE;
return RegionNotEmpty(DamageRegion(pExaPixmap->pDamage)) ||
!RegionEqual(&pExaPixmap->validSys, &pExaPixmap->validFB);
}
/**
* Returns TRUE if the pixmap is either pinned in FB, or has a sufficient score
* to be considered "should be in framebuffer". That's just anything that has
* had more acceleration than fallbacks, or has no score yet.
*
* Only valid if using a migration scheme that tracks score.
*/
static Bool
exaPixmapShouldBeInFB(PixmapPtr pPix)
{
ExaPixmapPriv(pPix);
if (exaPixmapIsPinned(pPix))
return TRUE;
return pExaPixmap->score >= 0;
}
/**
* If the pixmap is currently dirty, this copies at least the dirty area from
* FB to system or vice versa. Both areas must be allocated.
*/
static void
exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc,
Bool (*transfer) (PixmapPtr pPix, int x, int y, int w, int h,
char *sys, int sys_pitch), int fallback_index,
void (*sync) (ScreenPtr pScreen))
{
PixmapPtr pPixmap = migrate->pPix;
ExaPixmapPriv(pPixmap);
RegionPtr damage = DamageRegion(pExaPixmap->pDamage);
RegionRec CopyReg;
Bool save_use_gpu_copy;
int save_pitch;
BoxPtr pBox;
int nbox;
Bool access_prepared = FALSE;
Bool need_sync = FALSE;
/* Damaged bits are valid in current copy but invalid in other one */
if (pExaPixmap->use_gpu_copy) {
RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB, damage);
RegionSubtract(&pExaPixmap->validSys, &pExaPixmap->validSys, damage);
}
else {
RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys, damage);
RegionSubtract(&pExaPixmap->validFB, &pExaPixmap->validFB, damage);
}
RegionEmpty(damage);
/* Copy bits valid in source but not in destination */
RegionNull(&CopyReg);
RegionSubtract(&CopyReg, pValidSrc, pValidDst);
if (migrate->as_dst) {
ExaScreenPriv(pPixmap->drawable.pScreen);
/* XXX: The pending damage region will be marked as damaged after the
* operation, so it should serve as an upper bound for the region that
* needs to be synchronized for the operation. Unfortunately, this
* causes corruption in some cases, e.g. when starting compiz. See
* https://bugs.freedesktop.org/show_bug.cgi?id=12916 .
*/
if (pExaScr->optimize_migration) {
RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
#if DEBUG_MIGRATE
if (RegionNil(pending_damage)) {
static Bool firsttime = TRUE;
if (firsttime) {
ErrorF("%s: Pending damage region empty!\n", __func__);
firsttime = FALSE;
}
}
#endif
/* Try to prevent destination valid region from growing too many
* rects by filling it up to the extents of the union of the
* destination valid region and the pending damage region.
*/
if (RegionNumRects(pValidDst) > 10) {
BoxRec box;
BoxPtr pValidExt, pDamageExt;
RegionRec closure;
pValidExt = RegionExtents(pValidDst);
pDamageExt = RegionExtents(pending_damage);
box.x1 = min(pValidExt->x1, pDamageExt->x1);
box.y1 = min(pValidExt->y1, pDamageExt->y1);
box.x2 = max(pValidExt->x2, pDamageExt->x2);
box.y2 = max(pValidExt->y2, pDamageExt->y2);
RegionInit(&closure, &box, 0);
RegionIntersect(&CopyReg, &CopyReg, &closure);
}
else
RegionIntersect(&CopyReg, &CopyReg, pending_damage);
}
/* The caller may provide a region to be subtracted from the calculated
* dirty region. This is to avoid migration of bits that don't
* contribute to the result of the operation.
*/
if (migrate->pReg)
RegionSubtract(&CopyReg, &CopyReg, migrate->pReg);
}
else {
/* The caller may restrict the region to be migrated for source pixmaps
* to what's relevant for the operation.
*/
if (migrate->pReg)
RegionIntersect(&CopyReg, &CopyReg, migrate->pReg);
}
pBox = RegionRects(&CopyReg);
nbox = RegionNumRects(&CopyReg);
save_use_gpu_copy = pExaPixmap->use_gpu_copy;
save_pitch = pPixmap->devKind;
pExaPixmap->use_gpu_copy = TRUE;
pPixmap->devKind = pExaPixmap->fb_pitch;
while (nbox--) {
pBox->x1 = max(pBox->x1, 0);
pBox->y1 = max(pBox->y1, 0);
pBox->x2 = min(pBox->x2, pPixmap->drawable.width);
pBox->y2 = min(pBox->y2, pPixmap->drawable.height);
if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2)
continue;
if (!transfer || !transfer(pPixmap,
pBox->x1, pBox->y1,
pBox->x2 - pBox->x1,
pBox->y2 - pBox->y1,
(char *) (pExaPixmap->sys_ptr
+ pBox->y1 * pExaPixmap->sys_pitch
+
pBox->x1 *
pPixmap->drawable.bitsPerPixel /
8), pExaPixmap->sys_pitch)) {
if (!access_prepared) {
ExaDoPrepareAccess(pPixmap, fallback_index);
access_prepared = TRUE;
}
if (fallback_index == EXA_PREPARE_DEST) {
exaMemcpyBox(pPixmap, pBox,
pExaPixmap->sys_ptr, pExaPixmap->sys_pitch,
pPixmap->devPrivate.ptr, pPixmap->devKind);
}
else {
exaMemcpyBox(pPixmap, pBox,
pPixmap->devPrivate.ptr, pPixmap->devKind,
pExaPixmap->sys_ptr, pExaPixmap->sys_pitch);
}
}
else
need_sync = TRUE;
pBox++;
}
pExaPixmap->use_gpu_copy = save_use_gpu_copy;
pPixmap->devKind = save_pitch;
/* Try to prevent source valid region from growing too many rects by
* removing parts of it which are also in the destination valid region.
* Removing anything beyond that would lead to data loss.
*/
if (RegionNumRects(pValidSrc) > 20)
RegionSubtract(pValidSrc, pValidSrc, pValidDst);
/* The copied bits are now valid in destination */
RegionUnion(pValidDst, pValidDst, &CopyReg);
RegionUninit(&CopyReg);
if (access_prepared)
exaFinishAccess(&pPixmap->drawable, fallback_index);
else if (need_sync && sync)
sync(pPixmap->drawable.pScreen);
}
/**
* If the pixmap is currently dirty, this copies at least the dirty area from
* the framebuffer memory copy to the system memory copy. Both areas must be
* allocated.
*/
void
exaCopyDirtyToSys(ExaMigrationPtr migrate)
{
PixmapPtr pPixmap = migrate->pPix;
ExaScreenPriv(pPixmap->drawable.pScreen);
ExaPixmapPriv(pPixmap);
exaCopyDirty(migrate, &pExaPixmap->validSys, &pExaPixmap->validFB,
pExaScr->info->DownloadFromScreen, EXA_PREPARE_SRC,
exaWaitSync);
}
/**
* If the pixmap is currently dirty, this copies at least the dirty area from
* the system memory copy to the framebuffer memory copy. Both areas must be
* allocated.
*/
void
exaCopyDirtyToFb(ExaMigrationPtr migrate)
{
PixmapPtr pPixmap = migrate->pPix;
ExaScreenPriv(pPixmap->drawable.pScreen);
ExaPixmapPriv(pPixmap);
exaCopyDirty(migrate, &pExaPixmap->validFB, &pExaPixmap->validSys,
pExaScr->info->UploadToScreen, EXA_PREPARE_DEST, NULL);
}
/**
* Allocates a framebuffer copy of the pixmap if necessary, and then copies
* any necessary pixmap data into the framebuffer copy and points the pixmap at
* it.
*
* Note that when first allocated, a pixmap will have FALSE dirty flag.
* This is intentional because pixmap data starts out undefined. So if we move
* it in due to the first operation against it being accelerated, it will have
* undefined framebuffer contents that we didn't have to upload. If we do
* moveouts (and moveins) after the first movein, then we will only have to copy
* back and forth if the pixmap was written to after the last synchronization of
* the two copies. Then, at exaPixmapSave (when the framebuffer copy goes away)
* we mark the pixmap dirty, so that the next exaMoveInPixmap will actually move
* all the data, since it's almost surely all valid now.
*/
static void
exaDoMoveInPixmap(ExaMigrationPtr migrate)
{
PixmapPtr pPixmap = migrate->pPix;
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv(pScreen);
ExaPixmapPriv(pPixmap);
/* If we're VT-switched away, no touching card memory allowed. */
if (pExaScr->swappedOut)
return;
/* If we're not allowed to move, then fail. */
if (exaPixmapIsPinned(pPixmap))
return;
/* Don't migrate in pixmaps which are less than 8bpp. This avoids a lot of
* fragility in EXA, and <8bpp is probably not used enough any more to care
* (at least, not in acceleratd paths).
*/
if (pPixmap->drawable.bitsPerPixel < 8)
return;
if (pExaPixmap->accel_blocked)
return;
if (pExaPixmap->area == NULL) {
pExaPixmap->area =
exaOffscreenAlloc(pScreen, pExaPixmap->fb_size,
pExaScr->info->pixmapOffsetAlign, FALSE,
exaPixmapSave, (void *) pPixmap);
if (pExaPixmap->area == NULL)
return;
pExaPixmap->fb_ptr = (CARD8 *) pExaScr->info->memoryBase +
pExaPixmap->area->offset;
}
exaCopyDirtyToFb(migrate);
if (exaPixmapHasGpuCopy(pPixmap))
return;
DBG_MIGRATE(("-> %p (0x%x) (%dx%d) (%c)\n", pPixmap,
(ExaGetPixmapPriv(pPixmap)->area ?
ExaGetPixmapPriv(pPixmap)->area->offset : 0),
pPixmap->drawable.width,
pPixmap->drawable.height,
exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
pExaPixmap->use_gpu_copy = TRUE;
pPixmap->devKind = pExaPixmap->fb_pitch;
pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
}
void
exaMoveInPixmap_classic(PixmapPtr pPixmap)
{
static ExaMigrationRec migrate = {.as_dst = FALSE,.as_src = TRUE,
.pReg = NULL
};
migrate.pPix = pPixmap;
exaDoMoveInPixmap(&migrate);
}
/**
* Switches the current active location of the pixmap to system memory, copying
* updated data out if necessary.
*/
static void
exaDoMoveOutPixmap(ExaMigrationPtr migrate)
{
PixmapPtr pPixmap = migrate->pPix;
ExaPixmapPriv(pPixmap);
if (!pExaPixmap->area || exaPixmapIsPinned(pPixmap))
return;
exaCopyDirtyToSys(migrate);
if (exaPixmapHasGpuCopy(pPixmap)) {
DBG_MIGRATE(("<- %p (%p) (%dx%d) (%c)\n", pPixmap,
(void *) (ExaGetPixmapPriv(pPixmap)->area ?
ExaGetPixmapPriv(pPixmap)->area->offset : 0),
pPixmap->drawable.width,
pPixmap->drawable.height,
exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
pExaPixmap->use_gpu_copy = FALSE;
pPixmap->devKind = pExaPixmap->sys_pitch;
pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
}
}
void
exaMoveOutPixmap_classic(PixmapPtr pPixmap)
{
static ExaMigrationRec migrate = {.as_dst = FALSE,.as_src = TRUE,
.pReg = NULL
};
migrate.pPix = pPixmap;
exaDoMoveOutPixmap(&migrate);
}
/**
* Copies out important pixmap data and removes references to framebuffer area.
* Called when the memory manager decides it's time to kick the pixmap out of
* framebuffer entirely.
*/
void
exaPixmapSave(ScreenPtr pScreen, ExaOffscreenArea * area)
{
PixmapPtr pPixmap = area->privData;
ExaPixmapPriv(pPixmap);
exaMoveOutPixmap(pPixmap);
pExaPixmap->fb_ptr = NULL;
pExaPixmap->area = NULL;
/* Mark all FB bits as invalid, so all valid system bits get copied to FB
* next time */
RegionEmpty(&pExaPixmap->validFB);
}
/**
* For the "greedy" migration scheme, pushes the pixmap toward being located in
* framebuffer memory.
*/
static void
exaMigrateTowardFb(ExaMigrationPtr migrate)
{
PixmapPtr pPixmap = migrate->pPix;
ExaPixmapPriv(pPixmap);
if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) {
DBG_MIGRATE(("UseScreen: not migrating pinned pixmap %p\n",
(void *) pPixmap));
return;
}
DBG_MIGRATE(("UseScreen %p score %d\n",
(void *) pPixmap, pExaPixmap->score));
if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) {
exaDoMoveInPixmap(migrate);
pExaPixmap->score = 0;
}
if (pExaPixmap->score < EXA_PIXMAP_SCORE_MAX)
pExaPixmap->score++;
if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN &&
!exaPixmapHasGpuCopy(pPixmap)) {
exaDoMoveInPixmap(migrate);
}
if (exaPixmapHasGpuCopy(pPixmap)) {
exaCopyDirtyToFb(migrate);
ExaOffscreenMarkUsed(pPixmap);
}
else
exaCopyDirtyToSys(migrate);
}
/**
* For the "greedy" migration scheme, pushes the pixmap toward being located in
* system memory.
*/
static void
exaMigrateTowardSys(ExaMigrationPtr migrate)
{
PixmapPtr pPixmap = migrate->pPix;
ExaPixmapPriv(pPixmap);
DBG_MIGRATE(("UseMem: %p score %d\n", (void *) pPixmap,
pExaPixmap->score));
if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED)
return;
if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT)
pExaPixmap->score = 0;
if (pExaPixmap->score > EXA_PIXMAP_SCORE_MIN)
pExaPixmap->score--;
if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area)
exaDoMoveOutPixmap(migrate);
if (exaPixmapHasGpuCopy(pPixmap)) {
exaCopyDirtyToFb(migrate);
ExaOffscreenMarkUsed(pPixmap);
}
else
exaCopyDirtyToSys(migrate);
}
/**
* If the pixmap has both a framebuffer and system memory copy, this function
* asserts that both of them are the same.
*/
static Bool
exaAssertNotDirty(PixmapPtr pPixmap)
{
ExaPixmapPriv(pPixmap);
CARD8 *dst, *src;
RegionRec ValidReg;
int dst_pitch, src_pitch, cpp, y, nbox, save_pitch;
BoxPtr pBox;
Bool ret = TRUE, save_use_gpu_copy;
if (exaPixmapIsPinned(pPixmap) || pExaPixmap->area == NULL)
return ret;
RegionNull(&ValidReg);
RegionIntersect(&ValidReg, &pExaPixmap->validFB, &pExaPixmap->validSys);
nbox = RegionNumRects(&ValidReg);
if (!nbox)
goto out;
pBox = RegionRects(&ValidReg);
dst_pitch = pExaPixmap->sys_pitch;
src_pitch = pExaPixmap->fb_pitch;
cpp = pPixmap->drawable.bitsPerPixel / 8;
save_use_gpu_copy = pExaPixmap->use_gpu_copy;
save_pitch = pPixmap->devKind;
pExaPixmap->use_gpu_copy = TRUE;
pPixmap->devKind = pExaPixmap->fb_pitch;
if (!ExaDoPrepareAccess(pPixmap, EXA_PREPARE_SRC))
goto skip;
while (nbox--) {
int rowbytes;
pBox->x1 = max(pBox->x1, 0);
pBox->y1 = max(pBox->y1, 0);
pBox->x2 = min(pBox->x2, pPixmap->drawable.width);
pBox->y2 = min(pBox->y2, pPixmap->drawable.height);
if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2)
continue;
rowbytes = (pBox->x2 - pBox->x1) * cpp;
src =
(CARD8 *) pPixmap->devPrivate.ptr + pBox->y1 * src_pitch +
pBox->x1 * cpp;
dst = pExaPixmap->sys_ptr + pBox->y1 * dst_pitch + pBox->x1 * cpp;
for (y = pBox->y1; y < pBox->y2;
y++, src += src_pitch, dst += dst_pitch) {
if (memcmp(dst, src, rowbytes) != 0) {
ret = FALSE;
exaPixmapDirty(pPixmap, pBox->x1, pBox->y1, pBox->x2, pBox->y2);
break;
}
}
}
skip:
exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
pExaPixmap->use_gpu_copy = save_use_gpu_copy;
pPixmap->devKind = save_pitch;
out:
RegionUninit(&ValidReg);
return ret;
}
/**
* Performs migration of the pixmaps according to the operation information
* provided in pixmaps and can_accel and the migration scheme chosen in the
* config file.
*/
void
exaDoMigration_classic(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
{
ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen;
ExaScreenPriv(pScreen);
int i, j;
/* If this debugging flag is set, check each pixmap for whether it is marked
* as clean, and if so, actually check if that's the case. This should help
* catch issues with failing to mark a drawable as dirty. While it will
* catch them late (after the operation happened), it at least explains what
* went wrong, and instrumenting the code to find what operation happened
* to the pixmap last shouldn't be hard.
*/
if (pExaScr->checkDirtyCorrectness) {
for (i = 0; i < npixmaps; i++) {
if (!exaPixmapIsDirty(pixmaps[i].pPix) &&
!exaAssertNotDirty(pixmaps[i].pPix))
ErrorF("%s: Pixmap %d dirty but not marked as such!\n",
__func__, i);
}
}
/* If anything is pinned in system memory, we won't be able to
* accelerate.
*/
for (i = 0; i < npixmaps; i++) {
if (exaPixmapIsPinned(pixmaps[i].pPix) &&
!exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
EXA_FALLBACK(("Pixmap %p (%dx%d) pinned in sys\n", pixmaps[i].pPix,
pixmaps[i].pPix->drawable.width,
pixmaps[i].pPix->drawable.height));
can_accel = FALSE;
break;
}
}
if (pExaScr->migration == ExaMigrationSmart) {
/* If we've got something as a destination that we shouldn't cause to
* become newly dirtied, take the unaccelerated route.
*/
for (i = 0; i < npixmaps; i++) {
if (pixmaps[i].as_dst && !exaPixmapShouldBeInFB(pixmaps[i].pPix) &&
!exaPixmapIsDirty(pixmaps[i].pPix)) {
for (i = 0; i < npixmaps; i++) {
if (!exaPixmapIsDirty(pixmaps[i].pPix))
exaDoMoveOutPixmap(pixmaps + i);
}
return;
}
}
/* If we aren't going to accelerate, then we migrate everybody toward
* system memory, and kick out if it's free.
*/
if (!can_accel) {
for (i = 0; i < npixmaps; i++) {
exaMigrateTowardSys(pixmaps + i);
if (!exaPixmapIsDirty(pixmaps[i].pPix))
exaDoMoveOutPixmap(pixmaps + i);
}
return;
}
/* Finally, the acceleration path. Move them all in. */
for (i = 0; i < npixmaps; i++) {
exaMigrateTowardFb(pixmaps + i);
exaDoMoveInPixmap(pixmaps + i);
}
}
else if (pExaScr->migration == ExaMigrationGreedy) {
/* If we can't accelerate, either because the driver can't or because one of
* the pixmaps is pinned in system memory, then we migrate everybody toward
* system memory.
*
* We also migrate toward system if all pixmaps involved are currently in
* system memory -- this can mitigate thrashing when there are significantly
* more pixmaps active than would fit in memory.
*
* If not, then we migrate toward FB so that hopefully acceleration can
* happen.
*/
if (!can_accel) {
for (i = 0; i < npixmaps; i++)
exaMigrateTowardSys(pixmaps + i);
return;
}
for (i = 0; i < npixmaps; i++) {
if (exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
/* Found one in FB, so move all to FB. */
for (j = 0; j < npixmaps; j++)
exaMigrateTowardFb(pixmaps + i);
return;
}
}
/* Nobody's in FB, so move all away from FB. */
for (i = 0; i < npixmaps; i++)
exaMigrateTowardSys(pixmaps + i);
}
else if (pExaScr->migration == ExaMigrationAlways) {
/* Always move the pixmaps out if we can't accelerate. If we can
* accelerate, try to move them all in. If that fails, then move them
* back out.
*/
if (!can_accel) {
for (i = 0; i < npixmaps; i++)
exaDoMoveOutPixmap(pixmaps + i);
return;
}
/* Now, try to move them all into FB */
for (i = 0; i < npixmaps; i++) {
exaDoMoveInPixmap(pixmaps + i);
}
/* If we couldn't fit everything in, abort */
for (i = 0; i < npixmaps; i++) {
if (!exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
return;
}
}
/* Yay, everything has a gpu copy, mark memory as used */
for (i = 0; i < npixmaps; i++) {
ExaOffscreenMarkUsed(pixmaps[i].pPix);
}
}
}
void
exaPrepareAccessReg_classic(PixmapPtr pPixmap, int index, RegionPtr pReg)
{
ExaMigrationRec pixmaps[1];
if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) {
pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = FALSE;
}
else {
pixmaps[0].as_dst = FALSE;
pixmaps[0].as_src = TRUE;
}
pixmaps[0].pPix = pPixmap;
pixmaps[0].pReg = pReg;
exaDoMigration(pixmaps, 1, FALSE);
(void) ExaDoPrepareAccess(pPixmap, index);
}

View File

@ -1,270 +0,0 @@
/*
* Copyright © 2009 Maarten Maathuis
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <string.h>
#include "exa_priv.h"
#include "exa.h"
void
exaCreateDriverPixmap_mixed(PixmapPtr pPixmap)
{
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv(pScreen);
ExaPixmapPriv(pPixmap);
int w = pPixmap->drawable.width, h = pPixmap->drawable.height;
int depth = pPixmap->drawable.depth, bpp = pPixmap->drawable.bitsPerPixel;
int usage_hint = pPixmap->usage_hint;
int paddedWidth = pExaPixmap->sys_pitch;
/* Already done. */
if (pExaPixmap->driverPriv)
return;
if (exaPixmapIsPinned(pPixmap))
return;
/* Can't accel 1/4 bpp. */
if (pExaPixmap->accel_blocked || bpp < 8)
return;
if (pExaScr->info->CreatePixmap2) {
int new_pitch = 0;
pExaPixmap->driverPriv =
pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp,
&new_pitch);
paddedWidth = pExaPixmap->fb_pitch = new_pitch;
}
else {
if (paddedWidth < pExaPixmap->fb_pitch)
paddedWidth = pExaPixmap->fb_pitch;
pExaPixmap->driverPriv =
pExaScr->info->CreatePixmap(pScreen, paddedWidth * h, 0);
}
if (!pExaPixmap->driverPriv)
return;
(*pScreen->ModifyPixmapHeader) (pPixmap, w, h, 0, 0, paddedWidth, NULL);
}
void
exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
{
int i;
/* If anything is pinned in system memory, we won't be able to
* accelerate.
*/
for (i = 0; i < npixmaps; i++) {
if (exaPixmapIsPinned(pixmaps[i].pPix) &&
!exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
can_accel = FALSE;
break;
}
}
/* We can do nothing. */
if (!can_accel)
return;
for (i = 0; i < npixmaps; i++) {
PixmapPtr pPixmap = pixmaps[i].pPix;
ExaPixmapPriv(pPixmap);
if (!pExaPixmap->driverPriv)
exaCreateDriverPixmap_mixed(pPixmap);
if (pExaPixmap->pDamage && exaPixmapHasGpuCopy(pPixmap)) {
ExaScreenPriv(pPixmap->drawable.pScreen);
/* This pitch is needed for proper acceleration. For some reason
* there are pixmaps without pDamage and a bad fb_pitch value.
* So setting devKind when only exaPixmapHasGpuCopy() is true
* causes corruption. Pixmaps without pDamage are not migrated
* and should have a valid devKind at all times, so that's why this
* isn't causing problems. Pixmaps have their gpu pitch set the
* first time in the MPH call from exaCreateDriverPixmap_mixed().
*/
pPixmap->devKind = pExaPixmap->fb_pitch;
exaCopyDirtyToFb(pixmaps + i);
if (pExaScr->deferred_mixed_pixmap == pPixmap &&
!pixmaps[i].as_dst && !pixmaps[i].pReg)
pExaScr->deferred_mixed_pixmap = NULL;
}
pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
}
}
void
exaMoveInPixmap_mixed(PixmapPtr pPixmap)
{
ExaMigrationRec pixmaps[1];
pixmaps[0].as_dst = FALSE;
pixmaps[0].as_src = TRUE;
pixmaps[0].pPix = pPixmap;
pixmaps[0].pReg = NULL;
exaDoMigration(pixmaps, 1, TRUE);
}
void
exaDamageReport_mixed(DamagePtr pDamage, RegionPtr pRegion, void *closure)
{
PixmapPtr pPixmap = closure;
ExaPixmapPriv(pPixmap);
/* Move back results of software rendering on system memory copy of mixed driver
* pixmap (see exaPrepareAccessReg_mixed).
*
* Defer moving the destination back into the driver pixmap, to try and save
* overhead on multiple subsequent software fallbacks.
*/
if (!pExaPixmap->use_gpu_copy && exaPixmapHasGpuCopy(pPixmap)) {
ExaScreenPriv(pPixmap->drawable.pScreen);
if (pExaScr->deferred_mixed_pixmap &&
pExaScr->deferred_mixed_pixmap != pPixmap)
exaMoveInPixmap_mixed(pExaScr->deferred_mixed_pixmap);
pExaScr->deferred_mixed_pixmap = pPixmap;
}
}
/* With mixed pixmaps, if we fail to get direct access to the driver pixmap, we
* use the DownloadFromScreen hook to retrieve contents to a copy in system
* memory, perform software rendering on that and move back the results with the
* UploadToScreen hook (see exaDamageReport_mixed).
*/
void
exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg)
{
ExaPixmapPriv(pPixmap);
Bool has_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
Bool success;
success = ExaDoPrepareAccess(pPixmap, index);
if (success && has_gpu_copy && pExaPixmap->pDamage) {
/* You cannot do accelerated operations while a buffer is mapped. */
exaFinishAccess(&pPixmap->drawable, index);
/* Update the gpu view of both deferred destination pixmaps and of
* source pixmaps that were migrated with a bounding region.
*/
exaMoveInPixmap_mixed(pPixmap);
success = ExaDoPrepareAccess(pPixmap, index);
if (success) {
/* We have a gpu pixmap that can be accessed, we don't need the cpu
* copy anymore. Drivers that prefer DFS, should fail prepare
* access.
*/
DamageDestroy(pExaPixmap->pDamage);
pExaPixmap->pDamage = NULL;
free(pExaPixmap->sys_ptr);
pExaPixmap->sys_ptr = NULL;
return;
}
}
if (!success) {
ExaMigrationRec pixmaps[1];
/* Do we need to allocate our system buffer? */
if (!pExaPixmap->sys_ptr) {
pExaPixmap->sys_ptr = xallocarray(pExaPixmap->sys_pitch,
pPixmap->drawable.height);
if (!pExaPixmap->sys_ptr)
FatalError("EXA: malloc failed for size %d bytes\n",
pExaPixmap->sys_pitch * pPixmap->drawable.height);
}
if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) {
pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = FALSE;
}
else {
pixmaps[0].as_dst = FALSE;
pixmaps[0].as_src = TRUE;
}
pixmaps[0].pPix = pPixmap;
pixmaps[0].pReg = pReg;
if (!pExaPixmap->pDamage &&
(has_gpu_copy || !exaPixmapIsPinned(pPixmap))) {
Bool as_dst = pixmaps[0].as_dst;
/* Set up damage tracking */
pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL,
DamageReportNonEmpty, TRUE,
pPixmap->drawable.pScreen,
pPixmap);
if (pExaPixmap->pDamage) {
DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage);
/* This ensures that pending damage reflects the current
* operation. This is used by exa to optimize migration.
*/
DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE);
}
if (has_gpu_copy) {
exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width,
pPixmap->drawable.height);
/* We don't know which region of the destination will be damaged,
* have to assume all of it
*/
if (as_dst) {
pixmaps[0].as_dst = FALSE;
pixmaps[0].as_src = TRUE;
pixmaps[0].pReg = NULL;
}
exaCopyDirtyToSys(pixmaps);
}
if (as_dst)
exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width,
pPixmap->drawable.height);
}
else if (has_gpu_copy)
exaCopyDirtyToSys(pixmaps);
pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
pPixmap->devKind = pExaPixmap->sys_pitch;
pExaPixmap->use_gpu_copy = FALSE;
}
}

View File

@ -1,330 +0,0 @@
/*
* Copyright © 2009 Maarten Maathuis
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <string.h>
#include "exa_priv.h"
#include "exa.h"
/* This file holds the driver allocated pixmaps + better initial placement code.
*/
static _X_INLINE void *
ExaGetPixmapAddress(PixmapPtr p)
{
ExaPixmapPriv(p);
return pExaPixmap->sys_ptr;
}
/**
* exaCreatePixmap() creates a new pixmap.
*/
PixmapPtr
exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth,
unsigned usage_hint)
{
PixmapPtr pPixmap;
ExaPixmapPrivPtr pExaPixmap;
int bpp;
size_t paddedWidth;
ExaScreenPriv(pScreen);
if (w > 32767 || h > 32767)
return NullPixmap;
swap(pExaScr, pScreen, CreatePixmap);
pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint);
swap(pExaScr, pScreen, CreatePixmap);
if (!pPixmap)
return NULL;
pExaPixmap = ExaGetPixmapPriv(pPixmap);
pExaPixmap->driverPriv = NULL;
bpp = pPixmap->drawable.bitsPerPixel;
paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
if (paddedWidth / 4 > 32767 || h > 32767)
return NullPixmap;
/* We will allocate the system pixmap later if needed. */
pPixmap->devPrivate.ptr = NULL;
pExaPixmap->sys_ptr = NULL;
pExaPixmap->sys_pitch = paddedWidth;
pExaPixmap->area = NULL;
pExaPixmap->fb_ptr = NULL;
pExaPixmap->pDamage = NULL;
exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
exaSetAccelBlock(pExaScr, pExaPixmap, w, h, bpp);
(*pScreen->ModifyPixmapHeader) (pPixmap, w, h, 0, 0, paddedWidth, NULL);
/* A scratch pixmap will become a driver pixmap right away. */
if (!w || !h) {
exaCreateDriverPixmap_mixed(pPixmap);
pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
}
else {
pExaPixmap->use_gpu_copy = FALSE;
if (w == 1 && h == 1) {
pExaPixmap->sys_ptr = malloc(paddedWidth);
/* Set up damage tracking */
pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL,
DamageReportNonEmpty, TRUE,
pPixmap->drawable.pScreen,
pPixmap);
if (pExaPixmap->pDamage) {
DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage);
/* This ensures that pending damage reflects the current
* operation. This is used by exa to optimize migration.
*/
DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE);
}
}
}
/* During a fallback we must prepare access. */
if (pExaScr->fallback_counter)
exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
return pPixmap;
}
Bool
exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
int bitsPerPixel, int devKind, void *pPixData)
{
ScreenPtr pScreen;
ExaScreenPrivPtr pExaScr;
ExaPixmapPrivPtr pExaPixmap;
Bool ret, has_gpu_copy;
if (!pPixmap)
return FALSE;
pScreen = pPixmap->drawable.pScreen;
pExaScr = ExaGetScreenPriv(pScreen);
pExaPixmap = ExaGetPixmapPriv(pPixmap);
if (pPixData) {
if (pExaPixmap->driverPriv) {
if (pExaPixmap->pDamage) {
DamageDestroy(pExaPixmap->pDamage);
pExaPixmap->pDamage = NULL;
}
pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
pExaPixmap->driverPriv = NULL;
}
pExaPixmap->use_gpu_copy = FALSE;
pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
}
has_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
if (width <= 0)
width = pPixmap->drawable.width;
if (height <= 0)
height = pPixmap->drawable.height;
if (bitsPerPixel <= 0) {
if (depth <= 0)
bitsPerPixel = pPixmap->drawable.bitsPerPixel;
else
bitsPerPixel = BitsPerPixel(depth);
}
if (depth <= 0)
depth = pPixmap->drawable.depth;
if (width != pPixmap->drawable.width ||
height != pPixmap->drawable.height ||
depth != pPixmap->drawable.depth ||
bitsPerPixel != pPixmap->drawable.bitsPerPixel) {
if (pExaPixmap->driverPriv) {
if (devKind > 0)
pExaPixmap->fb_pitch = devKind;
else
exaSetFbPitch(pExaScr, pExaPixmap, width, height, bitsPerPixel);
exaSetAccelBlock(pExaScr, pExaPixmap, width, height, bitsPerPixel);
RegionEmpty(&pExaPixmap->validFB);
}
/* Need to re-create system copy if there's also a GPU copy */
if (has_gpu_copy) {
if (pExaPixmap->sys_ptr) {
free(pExaPixmap->sys_ptr);
pExaPixmap->sys_ptr = NULL;
DamageDestroy(pExaPixmap->pDamage);
pExaPixmap->pDamage = NULL;
RegionEmpty(&pExaPixmap->validSys);
if (pExaScr->deferred_mixed_pixmap == pPixmap)
pExaScr->deferred_mixed_pixmap = NULL;
}
pExaPixmap->sys_pitch = PixmapBytePad(width, depth);
}
}
if (has_gpu_copy) {
pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
pPixmap->devKind = pExaPixmap->fb_pitch;
}
else {
pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
pPixmap->devKind = pExaPixmap->sys_pitch;
}
/* Only pass driver pixmaps to the driver. */
if (pExaScr->info->ModifyPixmapHeader && pExaPixmap->driverPriv) {
ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth,
bitsPerPixel, devKind,
pPixData);
if (ret == TRUE)
goto out;
}
swap(pExaScr, pScreen, ModifyPixmapHeader);
ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
bitsPerPixel, devKind, pPixData);
swap(pExaScr, pScreen, ModifyPixmapHeader);
out:
if (has_gpu_copy) {
pExaPixmap->fb_ptr = pPixmap->devPrivate.ptr;
pExaPixmap->fb_pitch = pPixmap->devKind;
}
else {
pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
pExaPixmap->sys_pitch = pPixmap->devKind;
}
/* Always NULL this, we don't want lingering pointers. */
pPixmap->devPrivate.ptr = NULL;
return ret;
}
Bool
exaDestroyPixmap_mixed(PixmapPtr pPixmap)
{
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv(pScreen);
Bool ret;
if (pPixmap->refcnt == 1) {
ExaPixmapPriv(pPixmap);
exaDestroyPixmap(pPixmap);
if (pExaScr->deferred_mixed_pixmap == pPixmap)
pExaScr->deferred_mixed_pixmap = NULL;
if (pExaPixmap->driverPriv)
pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
pExaPixmap->driverPriv = NULL;
if (pExaPixmap->pDamage) {
free(pExaPixmap->sys_ptr);
pExaPixmap->sys_ptr = NULL;
pExaPixmap->pDamage = NULL;
}
}
swap(pExaScr, pScreen, DestroyPixmap);
ret = pScreen->DestroyPixmap(pPixmap);
swap(pExaScr, pScreen, DestroyPixmap);
return ret;
}
Bool
exaPixmapHasGpuCopy_mixed(PixmapPtr pPixmap)
{
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv(pScreen);
ExaPixmapPriv(pPixmap);
void *saved_ptr;
Bool ret;
if (!pExaPixmap->driverPriv)
return FALSE;
saved_ptr = pPixmap->devPrivate.ptr;
pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
pPixmap->devPrivate.ptr = saved_ptr;
return ret;
}
Bool
exaSharePixmapBacking_mixed(PixmapPtr pPixmap, ScreenPtr secondary, void **handle_p)
{
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv(pScreen);
Bool ret = FALSE;
exaMoveInPixmap(pPixmap);
/* get the driver to give us a handle */
if (pExaScr->info->SharePixmapBacking)
ret = pExaScr->info->SharePixmapBacking(pPixmap, secondary, handle_p);
return ret;
}
Bool
exaSetSharedPixmapBacking_mixed(PixmapPtr pPixmap, void *handle)
{
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv(pScreen);
Bool ret = FALSE;
if (pExaScr->info->SetSharedPixmapBacking)
ret = pExaScr->info->SetSharedPixmapBacking(pPixmap, handle);
if (ret == TRUE)
exaMoveInPixmap(pPixmap);
return ret;
}

View File

@ -1,677 +0,0 @@
/*
* Copyright © 2003 Anders Carlsson
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Anders Carlsson not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Anders Carlsson makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* ANDERS CARLSSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL ANDERS CARLSSON BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/** @file
* This allocator allocates blocks of memory by maintaining a list of areas.
* When allocating, the contiguous block of areas with the minimum eviction
* cost is found and evicted in order to make room for the new allocation.
*/
#include "exa_priv.h"
#include <limits.h>
#include <assert.h>
#include <stdlib.h>
#if DEBUG_OFFSCREEN
#define DBG_OFFSCREEN(a) ErrorF a
#else
#define DBG_OFFSCREEN(a)
#endif
#if DEBUG_OFFSCREEN
static void
ExaOffscreenValidate(ScreenPtr pScreen)
{
ExaScreenPriv(pScreen);
ExaOffscreenArea *prev = 0, *area;
assert(pExaScr->info->offScreenAreas->base_offset ==
pExaScr->info->offScreenBase);
for (area = pExaScr->info->offScreenAreas; area; area = area->next) {
assert(area->offset >= area->base_offset);
assert(area->offset < (area->base_offset + area->size));
if (prev)
assert(prev->base_offset + prev->size == area->base_offset);
prev = area;
}
assert(prev->base_offset + prev->size == pExaScr->info->memorySize);
}
#else
#define ExaOffscreenValidate(s)
#endif
static ExaOffscreenArea *
ExaOffscreenKickOut(ScreenPtr pScreen, ExaOffscreenArea * area)
{
if (area->save)
(*area->save) (pScreen, area);
return exaOffscreenFree(pScreen, area);
}
static void
exaUpdateEvictionCost(ExaOffscreenArea * area, unsigned offScreenCounter)
{
unsigned age;
if (area->state == ExaOffscreenAvail)
return;
age = offScreenCounter - area->last_use;
/* This is unlikely to happen, but could result in a division by zero... */
if (age > (UINT_MAX / 2)) {
age = UINT_MAX / 2;
area->last_use = offScreenCounter - age;
}
area->eviction_cost = area->size / age;
}
static ExaOffscreenArea *
exaFindAreaToEvict(ExaScreenPrivPtr pExaScr, int size, int align)
{
ExaOffscreenArea *begin, *end, *best;
unsigned cost, best_cost;
int avail, real_size;
best_cost = UINT_MAX;
begin = end = pExaScr->info->offScreenAreas;
avail = 0;
cost = 0;
best = 0;
while (end != NULL) {
restart:
while (begin != NULL && begin->state == ExaOffscreenLocked)
begin = end = begin->next;
if (begin == NULL)
break;
/* adjust size needed to account for alignment loss for this area */
real_size = size + (begin->base_offset + begin->size - size) % align;
while (avail < real_size && end != NULL) {
if (end->state == ExaOffscreenLocked) {
/* Can't more room here, restart after this locked area */
avail = 0;
cost = 0;
begin = end;
goto restart;
}
avail += end->size;
exaUpdateEvictionCost(end, pExaScr->offScreenCounter);
cost += end->eviction_cost;
end = end->next;
}
/* Check the cost, update best */
if (avail >= real_size && cost < best_cost) {
best = begin;
best_cost = cost;
}
avail -= begin->size;
cost -= begin->eviction_cost;
begin = begin->next;
}
return best;
}
/**
* exaOffscreenAlloc allocates offscreen memory
*
* @param pScreen current screen
* @param size size in bytes of the allocation
* @param align byte alignment requirement for the offset of the allocated area
* @param locked whether the allocated area is locked and can't be kicked out
* @param save callback for when the area is evicted from memory
* @param privdata private data for the save callback.
*
* Allocates offscreen memory from the device associated with pScreen. size
* and align determine where and how large the allocated area is, and locked
* will mark whether it should be held in card memory. privdata may be any
* pointer for the save callback when the area is removed.
*
* Note that locked areas do get evicted on VT switch unless the driver
* requested version 2.1 or newer behavior. In that case, the save callback is
* still called.
*/
ExaOffscreenArea *
exaOffscreenAlloc(ScreenPtr pScreen, int size, int align,
Bool locked, ExaOffscreenSaveProc save, void *privData)
{
ExaOffscreenArea *area;
ExaScreenPriv(pScreen);
int real_size = 0, largest_avail = 0;
#if DEBUG_OFFSCREEN
static int number = 0;
ErrorF("================= ============ allocating a new pixmap %d\n",
++number);
#endif
ExaOffscreenValidate(pScreen);
if (!align)
align = 1;
if (!size) {
DBG_OFFSCREEN(("Alloc 0x%x -> EMPTY\n", size));
return NULL;
}
/* throw out requests that cannot fit */
if (size > (pExaScr->info->memorySize - pExaScr->info->offScreenBase)) {
DBG_OFFSCREEN(("Alloc 0x%x vs (0x%lx) -> TOBIG\n", size,
pExaScr->info->memorySize -
pExaScr->info->offScreenBase));
return NULL;
}
/* Try to find a free space that'll fit. */
for (area = pExaScr->info->offScreenAreas; area; area = area->next) {
/* skip allocated areas */
if (area->state != ExaOffscreenAvail)
continue;
/* adjust size to match alignment requirement */
real_size = size + (area->base_offset + area->size - size) % align;
/* does it fit? */
if (real_size <= area->size)
break;
if (area->size > largest_avail)
largest_avail = area->size;
}
if (!area) {
area = exaFindAreaToEvict(pExaScr, size, align);
if (!area) {
DBG_OFFSCREEN(("Alloc 0x%x -> NOSPACE\n", size));
/* Could not allocate memory */
ExaOffscreenValidate(pScreen);
return NULL;
}
/* adjust size needed to account for alignment loss for this area */
real_size = size + (area->base_offset + area->size - size) % align;
/*
* Kick out first area if in use
*/
if (area->state != ExaOffscreenAvail)
area = ExaOffscreenKickOut(pScreen, area);
/*
* Now get the system to merge the other needed areas together
*/
while (area->size < real_size) {
assert(area->next);
assert(area->next->state == ExaOffscreenRemovable);
(void) ExaOffscreenKickOut(pScreen, area->next);
}
}
/* save extra space in new area */
if (real_size < area->size) {
ExaOffscreenArea *new_area = malloc(sizeof(ExaOffscreenArea));
if (!new_area)
return NULL;
new_area->base_offset = area->base_offset;
new_area->offset = new_area->base_offset;
new_area->align = 0;
new_area->size = area->size - real_size;
new_area->state = ExaOffscreenAvail;
new_area->save = NULL;
new_area->last_use = 0;
new_area->eviction_cost = 0;
new_area->next = area;
new_area->prev = area->prev;
if (area->prev->next)
area->prev->next = new_area;
else
pExaScr->info->offScreenAreas = new_area;
area->prev = new_area;
area->base_offset = new_area->base_offset + new_area->size;
area->size = real_size;
}
else
pExaScr->numOffscreenAvailable--;
/*
* Mark this area as in use
*/
if (locked)
area->state = ExaOffscreenLocked;
else
area->state = ExaOffscreenRemovable;
area->privData = privData;
area->save = save;
area->last_use = pExaScr->offScreenCounter++;
area->offset = (area->base_offset + align - 1);
area->offset -= area->offset % align;
area->align = align;
ExaOffscreenValidate(pScreen);
DBG_OFFSCREEN(("Alloc 0x%x -> 0x%x (0x%x)\n", size,
area->base_offset, area->offset));
return area;
}
/**
* Ejects all offscreen areas, and uninitializes the offscreen memory manager.
*/
void
ExaOffscreenSwapOut(ScreenPtr pScreen)
{
ExaScreenPriv(pScreen);
ExaOffscreenValidate(pScreen);
/* loop until a single free area spans the space */
for (;;) {
ExaOffscreenArea *area = pExaScr->info->offScreenAreas;
if (!area)
break;
if (area->state == ExaOffscreenAvail) {
area = area->next;
if (!area)
break;
}
assert(area->state != ExaOffscreenAvail);
(void) ExaOffscreenKickOut(pScreen, area);
ExaOffscreenValidate(pScreen);
}
ExaOffscreenValidate(pScreen);
ExaOffscreenFini(pScreen);
}
/** Ejects all pixmaps managed by EXA. */
static void
ExaOffscreenEjectPixmaps(ScreenPtr pScreen)
{
ExaScreenPriv(pScreen);
ExaOffscreenValidate(pScreen);
/* loop until a single free area spans the space */
for (;;) {
ExaOffscreenArea *area;
for (area = pExaScr->info->offScreenAreas; area != NULL;
area = area->next) {
if (area->state == ExaOffscreenRemovable &&
area->save == exaPixmapSave) {
(void) ExaOffscreenKickOut(pScreen, area);
ExaOffscreenValidate(pScreen);
break;
}
}
if (area == NULL)
break;
}
ExaOffscreenValidate(pScreen);
}
void
ExaOffscreenSwapIn(ScreenPtr pScreen)
{
exaOffscreenInit(pScreen);
}
/**
* Prepares EXA for disabling of FB access, or restoring it.
*
* In version 2.1, the disabling results in pixmaps being ejected, while other
* allocations remain. With this plus the prevention of migration while
* swappedOut is set, EXA by itself should not cause any access of the
* framebuffer to occur while swapped out. Any remaining issues are the
* responsibility of the driver.
*
* Prior to version 2.1, all allocations, including locked ones, are ejected
* when access is disabled, and the allocator is torn down while swappedOut
* is set. This is more drastic, and caused implementation difficulties for
* many drivers that could otherwise handle the lack of FB access while
* swapped out.
*/
void
exaEnableDisableFBAccess(ScreenPtr pScreen, Bool enable)
{
ExaScreenPriv(pScreen);
if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS)
return;
if (!enable && pExaScr->disableFbCount++ == 0) {
if (pExaScr->info->exa_minor < 1)
ExaOffscreenSwapOut(pScreen);
else
ExaOffscreenEjectPixmaps(pScreen);
pExaScr->swappedOut = TRUE;
}
if (enable && --pExaScr->disableFbCount == 0) {
if (pExaScr->info->exa_minor < 1)
ExaOffscreenSwapIn(pScreen);
pExaScr->swappedOut = FALSE;
}
}
/* merge the next free area into this one */
static void
ExaOffscreenMerge(ExaScreenPrivPtr pExaScr, ExaOffscreenArea * area)
{
ExaOffscreenArea *next = area->next;
/* account for space */
area->size += next->size;
/* frob pointer */
area->next = next->next;
if (area->next)
area->next->prev = area;
else
pExaScr->info->offScreenAreas->prev = area;
free(next);
pExaScr->numOffscreenAvailable--;
}
/**
* exaOffscreenFree frees an allocation.
*
* @param pScreen current screen
* @param area offscreen area to free
*
* exaOffscreenFree frees an allocation created by exaOffscreenAlloc. Note that
* the save callback of the area is not called, and it is up to the driver to
* do any cleanup necessary as a result.
*
* @return pointer to the newly freed area. This behavior should not be relied
* on.
*/
ExaOffscreenArea *
exaOffscreenFree(ScreenPtr pScreen, ExaOffscreenArea * area)
{
ExaScreenPriv(pScreen);
ExaOffscreenArea *next = area->next;
ExaOffscreenArea *prev;
DBG_OFFSCREEN(("Free 0x%x -> 0x%x (0x%x)\n", area->size,
area->base_offset, area->offset));
ExaOffscreenValidate(pScreen);
area->state = ExaOffscreenAvail;
area->save = NULL;
area->last_use = 0;
area->eviction_cost = 0;
/*
* Find previous area
*/
if (area == pExaScr->info->offScreenAreas)
prev = NULL;
else
prev = area->prev;
pExaScr->numOffscreenAvailable++;
/* link with next area if free */
if (next && next->state == ExaOffscreenAvail)
ExaOffscreenMerge(pExaScr, area);
/* link with prev area if free */
if (prev && prev->state == ExaOffscreenAvail) {
area = prev;
ExaOffscreenMerge(pExaScr, area);
}
ExaOffscreenValidate(pScreen);
DBG_OFFSCREEN(("\tdone freeing\n"));
return area;
}
void
ExaOffscreenMarkUsed(PixmapPtr pPixmap)
{
ExaPixmapPriv(pPixmap);
ExaScreenPriv(pPixmap->drawable.pScreen);
if (!pExaPixmap || !pExaPixmap->area)
return;
pExaPixmap->area->last_use = pExaScr->offScreenCounter++;
}
/**
* Defragment offscreen memory by compacting allocated areas at the end of it,
* leaving the total amount of memory available as a single area at the
* beginning (when there are no pinned allocations).
*/
_X_HIDDEN ExaOffscreenArea *
ExaOffscreenDefragment(ScreenPtr pScreen)
{
ExaScreenPriv(pScreen);
ExaOffscreenArea *area, *largest_available = NULL;
int largest_size = 0;
PixmapPtr pDstPix;
ExaPixmapPrivPtr pExaDstPix;
pDstPix = (*pScreen->CreatePixmap) (pScreen, 0, 0, 0, 0);
if (!pDstPix)
return NULL;
pExaDstPix = ExaGetPixmapPriv(pDstPix);
pExaDstPix->use_gpu_copy = TRUE;
for (area = pExaScr->info->offScreenAreas->prev;
area != pExaScr->info->offScreenAreas;) {
ExaOffscreenArea *prev = area->prev;
PixmapPtr pSrcPix;
ExaPixmapPrivPtr pExaSrcPix;
Bool save_use_gpu_copy;
int save_pitch;
if (area->state != ExaOffscreenAvail ||
prev->state == ExaOffscreenLocked ||
(prev->state == ExaOffscreenRemovable &&
prev->save != exaPixmapSave)) {
area = prev;
continue;
}
if (prev->state == ExaOffscreenAvail) {
if (area == largest_available) {
largest_available = prev;
largest_size += prev->size;
}
area = prev;
ExaOffscreenMerge(pExaScr, area);
continue;
}
if (area->size > largest_size) {
largest_available = area;
largest_size = area->size;
}
pSrcPix = prev->privData;
pExaSrcPix = ExaGetPixmapPriv(pSrcPix);
pExaDstPix->fb_ptr = pExaScr->info->memoryBase +
area->base_offset + area->size - prev->size + prev->base_offset -
prev->offset;
pExaDstPix->fb_ptr -= (unsigned long) pExaDstPix->fb_ptr % prev->align;
if (pExaDstPix->fb_ptr <= pExaSrcPix->fb_ptr) {
area = prev;
continue;
}
if (!(pExaScr->info->flags & EXA_SUPPORTS_OFFSCREEN_OVERLAPS) &&
(pExaSrcPix->fb_ptr + prev->size) > pExaDstPix->fb_ptr) {
area = prev;
continue;
}
save_use_gpu_copy = pExaSrcPix->use_gpu_copy;
save_pitch = pSrcPix->devKind;
pExaSrcPix->use_gpu_copy = TRUE;
pSrcPix->devKind = pExaSrcPix->fb_pitch;
pDstPix->drawable.width = pSrcPix->drawable.width;
pDstPix->devKind = pSrcPix->devKind;
pDstPix->drawable.height = pSrcPix->drawable.height;
pDstPix->drawable.depth = pSrcPix->drawable.depth;
pDstPix->drawable.bitsPerPixel = pSrcPix->drawable.bitsPerPixel;
if (!pExaScr->info->PrepareCopy(pSrcPix, pDstPix, -1, -1, GXcopy, ~0)) {
pExaSrcPix->use_gpu_copy = save_use_gpu_copy;
pSrcPix->devKind = save_pitch;
area = prev;
continue;
}
pExaScr->info->Copy(pDstPix, 0, 0, 0, 0, pDstPix->drawable.width,
pDstPix->drawable.height);
pExaScr->info->DoneCopy(pDstPix);
exaMarkSync(pScreen);
DBG_OFFSCREEN(("Before swap: prev=0x%08x-0x%08x-0x%08x area=0x%08x-0x%08x-0x%08x\n", prev->base_offset, prev->offset, prev->base_offset + prev->size, area->base_offset, area->offset, area->base_offset + area->size));
/* Calculate swapped area offsets and sizes */
area->base_offset = prev->base_offset;
area->offset = area->base_offset;
prev->offset += pExaDstPix->fb_ptr - pExaSrcPix->fb_ptr;
assert(prev->offset >= pExaScr->info->offScreenBase);
assert(prev->offset < pExaScr->info->memorySize);
prev->base_offset = prev->offset;
if (area->next)
prev->size = area->next->base_offset - prev->base_offset;
else
prev->size = pExaScr->info->memorySize - prev->base_offset;
area->size = prev->base_offset - area->base_offset;
DBG_OFFSCREEN(("After swap: area=0x%08x-0x%08x-0x%08x prev=0x%08x-0x%08x-0x%08x\n", area->base_offset, area->offset, area->base_offset + area->size, prev->base_offset, prev->offset, prev->base_offset + prev->size));
/* Swap areas in list */
if (area->next)
area->next->prev = prev;
else
pExaScr->info->offScreenAreas->prev = prev;
if (prev->prev->next)
prev->prev->next = area;
else
pExaScr->info->offScreenAreas = area;
prev->next = area->next;
area->next = prev;
area->prev = prev->prev;
prev->prev = area;
if (!area->prev->next)
pExaScr->info->offScreenAreas = area;
#if DEBUG_OFFSCREEN
if (prev->prev == prev || prev->next == prev)
ErrorF("Whoops, prev points to itself!\n");
if (area->prev == area || area->next == area)
ErrorF("Whoops, area points to itself!\n");
#endif
pExaSrcPix->fb_ptr = pExaDstPix->fb_ptr;
pExaSrcPix->use_gpu_copy = save_use_gpu_copy;
pSrcPix->devKind = save_pitch;
}
pDstPix->drawable.width = 0;
pDstPix->drawable.height = 0;
pDstPix->drawable.depth = 0;
pDstPix->drawable.bitsPerPixel = 0;
(*pScreen->DestroyPixmap) (pDstPix);
if (area->state == ExaOffscreenAvail && area->size > largest_size)
return area;
return largest_available;
}
/**
* exaOffscreenInit initializes the offscreen memory manager.
*
* @param pScreen current screen
*
* exaOffscreenInit is called by exaDriverInit to set up the memory manager for
* the screen, if any offscreen memory is available.
*/
Bool
exaOffscreenInit(ScreenPtr pScreen)
{
ExaScreenPriv(pScreen);
ExaOffscreenArea *area;
/* Allocate a big free area */
area = malloc(sizeof(ExaOffscreenArea));
if (!area)
return FALSE;
area->state = ExaOffscreenAvail;
area->base_offset = pExaScr->info->offScreenBase;
area->offset = area->base_offset;
area->align = 0;
area->size = pExaScr->info->memorySize - area->base_offset;
area->save = NULL;
area->next = NULL;
area->prev = area;
area->last_use = 0;
area->eviction_cost = 0;
/* Add it to the free areas */
pExaScr->info->offScreenAreas = area;
pExaScr->offScreenCounter = 1;
pExaScr->numOffscreenAvailable = 1;
ExaOffscreenValidate(pScreen);
return TRUE;
}
void
ExaOffscreenFini(ScreenPtr pScreen)
{
ExaScreenPriv(pScreen);
ExaOffscreenArea *area;
/* just free all of the area records */
while ((area = pExaScr->info->offScreenAreas)) {
pExaScr->info->offScreenAreas = area->next;
free(area);
}
}

View File

@ -1,735 +0,0 @@
/*
*
* Copyright (C) 2000 Keith Packard, member of The XFree86 Project, Inc.
* 2005 Zack Rusin, Trolltech
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
#ifndef EXAPRIV_H
#define EXAPRIV_H
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "exa.h"
#include <X11/X.h>
#include <X11/Xproto.h>
#ifdef MITSHM
#include "shmint.h"
#endif
#include "scrnintstr.h"
#include "pixmapstr.h"
#include "windowstr.h"
#include "servermd.h"
#include "colormapst.h"
#include "gcstruct.h"
#include "input.h"
#include "mipointer.h"
#include "mi.h"
#include "dix.h"
#include "fb.h"
#include "fboverlay.h"
#include "fbpict.h"
#include "glyphstr.h"
#include "damage.h"
#define DEBUG_TRACE_FALL 0
#define DEBUG_MIGRATE 0
#define DEBUG_PIXMAP 0
#define DEBUG_OFFSCREEN 0
#define DEBUG_GLYPH_CACHE 0
#if DEBUG_TRACE_FALL
#define EXA_FALLBACK(x) \
do { \
ErrorF("EXA fallback at %s: ", __FUNCTION__); \
ErrorF x; \
} while (0)
char
exaDrawableLocation(DrawablePtr pDrawable);
#else
#define EXA_FALLBACK(x)
#endif
#if DEBUG_PIXMAP
#define DBG_PIXMAP(a) ErrorF a
#else
#define DBG_PIXMAP(a)
#endif
#ifndef EXA_MAX_FB
#define EXA_MAX_FB FB_OVERLAY_MAX
#endif
#ifdef DEBUG
#define EXA_FatalErrorDebug(x) FatalError x
#define EXA_FatalErrorDebugWithRet(x, ret) FatalError x
#else
#define EXA_FatalErrorDebug(x) ErrorF x
#define EXA_FatalErrorDebugWithRet(x, ret) \
do { \
ErrorF x; \
return ret; \
} while (0)
#endif
/**
* This is the list of migration heuristics supported by EXA. See
* exaDoMigration() for what their implementations do.
*/
enum ExaMigrationHeuristic {
ExaMigrationGreedy,
ExaMigrationAlways,
ExaMigrationSmart
};
typedef struct {
unsigned char sha1[20];
} ExaCachedGlyphRec, *ExaCachedGlyphPtr;
typedef struct {
/* The identity of the cache, statically configured at initialization */
unsigned int format;
int glyphWidth;
int glyphHeight;
int size; /* Size of cache; eventually this should be dynamically determined */
/* Hash table mapping from glyph sha1 to position in the glyph; we use
* open addressing with a hash table size determined based on size and large
* enough so that we always have a good amount of free space, so we can
* use linear probing. (Linear probing is preferable to double hashing
* here because it allows us to easily remove entries.)
*/
int *hashEntries;
int hashSize;
ExaCachedGlyphPtr glyphs;
int glyphCount; /* Current number of glyphs */
PicturePtr picture; /* Where the glyphs of the cache are stored */
int yOffset; /* y location within the picture where the cache starts */
int columns; /* Number of columns the glyphs are laid out in */
int evictionPosition; /* Next random position to evict a glyph */
} ExaGlyphCacheRec, *ExaGlyphCachePtr;
#define EXA_NUM_GLYPH_CACHES 4
#define EXA_FALLBACK_COPYWINDOW (1 << 0)
#define EXA_ACCEL_COPYWINDOW (1 << 1)
typedef struct _ExaMigrationRec {
Bool as_dst;
Bool as_src;
PixmapPtr pPix;
RegionPtr pReg;
} ExaMigrationRec, *ExaMigrationPtr;
typedef void (*EnableDisableFBAccessProcPtr) (ScreenPtr, Bool);
typedef struct {
ExaDriverPtr info;
ScreenBlockHandlerProcPtr SavedBlockHandler;
ScreenWakeupHandlerProcPtr SavedWakeupHandler;
CreateGCProcPtr SavedCreateGC;
CloseScreenProcPtr SavedCloseScreen;
GetImageProcPtr SavedGetImage;
GetSpansProcPtr SavedGetSpans;
CreatePixmapProcPtr SavedCreatePixmap;
DestroyPixmapProcPtr SavedDestroyPixmap;
CopyWindowProcPtr SavedCopyWindow;
ChangeWindowAttributesProcPtr SavedChangeWindowAttributes;
BitmapToRegionProcPtr SavedBitmapToRegion;
CreateScreenResourcesProcPtr SavedCreateScreenResources;
ModifyPixmapHeaderProcPtr SavedModifyPixmapHeader;
SharePixmapBackingProcPtr SavedSharePixmapBacking;
SetSharedPixmapBackingProcPtr SavedSetSharedPixmapBacking;
SourceValidateProcPtr SavedSourceValidate;
CompositeProcPtr SavedComposite;
TrianglesProcPtr SavedTriangles;
GlyphsProcPtr SavedGlyphs;
TrapezoidsProcPtr SavedTrapezoids;
AddTrapsProcPtr SavedAddTraps;
void (*do_migration) (ExaMigrationPtr pixmaps, int npixmaps,
Bool can_accel);
Bool (*pixmap_has_gpu_copy) (PixmapPtr pPixmap);
void (*do_move_in_pixmap) (PixmapPtr pPixmap);
void (*do_move_out_pixmap) (PixmapPtr pPixmap);
void (*prepare_access_reg) (PixmapPtr pPixmap, int index, RegionPtr pReg);
Bool swappedOut;
enum ExaMigrationHeuristic migration;
Bool checkDirtyCorrectness;
unsigned disableFbCount;
Bool optimize_migration;
unsigned offScreenCounter;
unsigned numOffscreenAvailable;
CARD32 lastDefragment;
CARD32 nextDefragment;
PixmapPtr deferred_mixed_pixmap;
/* Reference counting for accessed pixmaps */
struct {
PixmapPtr pixmap;
int count;
Bool retval;
} access[EXA_NUM_PREPARE_INDICES];
/* Holds information on fallbacks that cannot be relayed otherwise. */
unsigned int fallback_flags;
unsigned int fallback_counter;
ExaGlyphCacheRec glyphCaches[EXA_NUM_GLYPH_CACHES];
/**
* Regions affected by fallback composite source / mask operations.
*/
RegionRec srcReg;
RegionRec maskReg;
PixmapPtr srcPix;
PixmapPtr maskPix;
DevPrivateKeyRec pixmapPrivateKeyRec;
DevPrivateKeyRec gcPrivateKeyRec;
} ExaScreenPrivRec, *ExaScreenPrivPtr;
extern DevPrivateKeyRec exaScreenPrivateKeyRec;
#define exaScreenPrivateKey (&exaScreenPrivateKeyRec)
#define ExaGetScreenPriv(s) ((ExaScreenPrivPtr)dixGetPrivate(&(s)->devPrivates, exaScreenPrivateKey))
#define ExaScreenPriv(s) ExaScreenPrivPtr pExaScr = ExaGetScreenPriv(s)
#define ExaGetGCPriv(gc) ((ExaGCPrivPtr)dixGetPrivateAddr(&(gc)->devPrivates, &ExaGetScreenPriv(gc->pScreen)->gcPrivateKeyRec))
#define ExaGCPriv(gc) ExaGCPrivPtr pExaGC = ExaGetGCPriv(gc)
/*
* Some macros to deal with function wrapping.
*/
#define wrap(priv, real, mem, func) {\
priv->Saved##mem = real->mem; \
real->mem = func; \
}
#define unwrap(priv, real, mem) {\
real->mem = priv->Saved##mem; \
}
#ifdef HAVE_TYPEOF
#define swap(priv, real, mem) {\
typeof(real->mem) tmp = priv->Saved##mem; \
priv->Saved##mem = real->mem; \
real->mem = tmp; \
}
#else
#define swap(priv, real, mem) {\
const void *tmp = priv->Saved##mem; \
priv->Saved##mem = real->mem; \
real->mem = tmp; \
}
#endif
#define EXA_PRE_FALLBACK(_screen_) \
ExaScreenPriv(_screen_); \
pExaScr->fallback_counter++;
#define EXA_POST_FALLBACK(_screen_) \
pExaScr->fallback_counter--;
#define EXA_PRE_FALLBACK_GC(_gc_) \
ExaScreenPriv(_gc_->pScreen); \
ExaGCPriv(_gc_); \
pExaScr->fallback_counter++; \
swap(pExaGC, _gc_, ops);
#define EXA_POST_FALLBACK_GC(_gc_) \
pExaScr->fallback_counter--; \
swap(pExaGC, _gc_, ops);
/** Align an offset to an arbitrary alignment */
#define EXA_ALIGN(offset, align) (((offset) + (align) - 1) - \
(((offset) + (align) - 1) % (align)))
/** Align an offset to a power-of-two alignment */
#define EXA_ALIGN2(offset, align) (((offset) + (align) - 1) & ~((align) - 1))
#define EXA_PIXMAP_SCORE_MOVE_IN 10
#define EXA_PIXMAP_SCORE_MAX 20
#define EXA_PIXMAP_SCORE_MOVE_OUT -10
#define EXA_PIXMAP_SCORE_MIN -20
#define EXA_PIXMAP_SCORE_PINNED 1000
#define EXA_PIXMAP_SCORE_INIT 1001
#define ExaGetPixmapPriv(p) ((ExaPixmapPrivPtr)dixGetPrivateAddr(&(p)->devPrivates, &ExaGetScreenPriv((p)->drawable.pScreen)->pixmapPrivateKeyRec))
#define ExaPixmapPriv(p) ExaPixmapPrivPtr pExaPixmap = ExaGetPixmapPriv(p)
#define EXA_RANGE_PITCH (1 << 0)
#define EXA_RANGE_WIDTH (1 << 1)
#define EXA_RANGE_HEIGHT (1 << 2)
typedef struct {
ExaOffscreenArea *area;
int score; /**< score for the move-in vs move-out heuristic */
Bool use_gpu_copy;
CARD8 *sys_ptr; /**< pointer to pixmap data in system memory */
int sys_pitch; /**< pitch of pixmap in system memory */
CARD8 *fb_ptr; /**< pointer to pixmap data in framebuffer memory */
int fb_pitch; /**< pitch of pixmap in framebuffer memory */
unsigned int fb_size; /**< size of pixmap in framebuffer memory */
/**
* Holds information about whether this pixmap can be used for
* acceleration (== 0) or not (> 0).
*
* Contains a OR'ed combination of the following values:
* EXA_RANGE_PITCH - set if the pixmap's pitch is out of range
* EXA_RANGE_WIDTH - set if the pixmap's width is out of range
* EXA_RANGE_HEIGHT - set if the pixmap's height is out of range
*/
unsigned int accel_blocked;
/**
* The damage record contains the areas of the pixmap's current location
* (framebuffer or system) that have been damaged compared to the other
* location.
*/
DamagePtr pDamage;
/**
* The valid regions mark the valid bits (at least, as they're derived from
* damage, which may be overreported) of a pixmap's system and FB copies.
*/
RegionRec validSys, validFB;
/**
* Driver private storage per EXA pixmap
*/
void *driverPriv;
} ExaPixmapPrivRec, *ExaPixmapPrivPtr;
typedef struct {
/* GC values from the layer below. */
const GCOps *Savedops;
const GCFuncs *Savedfuncs;
} ExaGCPrivRec, *ExaGCPrivPtr;
typedef struct {
PicturePtr pDst;
INT16 xSrc;
INT16 ySrc;
INT16 xMask;
INT16 yMask;
INT16 xDst;
INT16 yDst;
INT16 width;
INT16 height;
} ExaCompositeRectRec, *ExaCompositeRectPtr;
/**
* exaDDXDriverInit must be implemented by the DDX using EXA, and is the place
* to set EXA options or hook in screen functions to handle using EXA as the AA.
*/
void exaDDXDriverInit(ScreenPtr pScreen);
/* exa_unaccel.c */
void
exaPrepareAccessGC(GCPtr pGC);
void
exaFinishAccessGC(GCPtr pGC);
void
ExaCheckFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nspans,
DDXPointPtr ppt, int *pwidth, int fSorted);
void
ExaCheckSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
DDXPointPtr ppt, int *pwidth, int nspans, int fSorted);
void
ExaCheckPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
int x, int y, int w, int h, int leftPad, int format,
char *bits);
void
ExaCheckCopyNtoN(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
BoxPtr pbox, int nbox, int dx, int dy, Bool reverse,
Bool upsidedown, Pixel bitplane, void *closure);
RegionPtr
ExaCheckCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
int srcx, int srcy, int w, int h, int dstx, int dsty);
RegionPtr
ExaCheckCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
int srcx, int srcy, int w, int h, int dstx, int dsty,
unsigned long bitPlane);
void
ExaCheckPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
DDXPointPtr pptInit);
void
ExaCheckPolylines(DrawablePtr pDrawable, GCPtr pGC,
int mode, int npt, DDXPointPtr ppt);
void
ExaCheckPolySegment(DrawablePtr pDrawable, GCPtr pGC,
int nsegInit, xSegment * pSegInit);
void
ExaCheckPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc * pArcs);
void
ExaCheckPolyFillRect(DrawablePtr pDrawable, GCPtr pGC,
int nrect, xRectangle *prect);
void
ExaCheckImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
int x, int y, unsigned int nglyph,
CharInfoPtr * ppci, void *pglyphBase);
void
ExaCheckPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
int x, int y, unsigned int nglyph,
CharInfoPtr * ppci, void *pglyphBase);
void
ExaCheckPushPixels(GCPtr pGC, PixmapPtr pBitmap,
DrawablePtr pDrawable, int w, int h, int x, int y);
void
ExaCheckCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc);
void
ExaCheckGetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
unsigned int format, unsigned long planeMask, char *d);
void
ExaCheckGetSpans(DrawablePtr pDrawable,
int wMax,
DDXPointPtr ppt, int *pwidth, int nspans, char *pdstStart);
void
ExaCheckAddTraps(PicturePtr pPicture,
INT16 x_off, INT16 y_off, int ntrap, xTrap * traps);
/* exa_accel.c */
static _X_INLINE Bool
exaGCReadsDestination(DrawablePtr pDrawable, unsigned long planemask,
unsigned int fillStyle, unsigned char alu,
Bool clientClip)
{
return ((alu != GXcopy && alu != GXclear && alu != GXset &&
alu != GXcopyInverted) || fillStyle == FillStippled ||
clientClip != FALSE || !EXA_PM_IS_SOLID(pDrawable, planemask));
}
void
exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc);
Bool
exaFillRegionTiled(DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile,
DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu,
Bool clientClip);
void
exaGetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
unsigned int format, unsigned long planeMask, char *d);
RegionPtr
exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
int srcx, int srcy, int width, int height, int dstx, int dsty);
Bool
exaHWCopyNtoN(DrawablePtr pSrcDrawable,
DrawablePtr pDstDrawable,
GCPtr pGC,
BoxPtr pbox,
int nbox, int dx, int dy, Bool reverse, Bool upsidedown);
void
exaCopyNtoN(DrawablePtr pSrcDrawable,
DrawablePtr pDstDrawable,
GCPtr pGC,
BoxPtr pbox,
int nbox,
int dx,
int dy,
Bool reverse, Bool upsidedown, Pixel bitplane, void *closure);
extern const GCOps exaOps;
void
ExaCheckComposite(CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask,
INT16 yMask,
INT16 xDst, INT16 yDst, CARD16 width, CARD16 height);
void
ExaCheckGlyphs(CARD8 op,
PicturePtr pSrc,
PicturePtr pDst,
PictFormatPtr maskFormat,
INT16 xSrc,
INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs);
/* exa_offscreen.c */
void
ExaOffscreenSwapOut(ScreenPtr pScreen);
void
ExaOffscreenSwapIn(ScreenPtr pScreen);
ExaOffscreenArea *ExaOffscreenDefragment(ScreenPtr pScreen);
Bool
exaOffscreenInit(ScreenPtr pScreen);
void
ExaOffscreenFini(ScreenPtr pScreen);
/* exa.c */
Bool
ExaDoPrepareAccess(PixmapPtr pPixmap, int index);
void
exaPrepareAccess(DrawablePtr pDrawable, int index);
void
exaFinishAccess(DrawablePtr pDrawable, int index);
void
exaDestroyPixmap(PixmapPtr pPixmap);
void
exaPixmapDirty(PixmapPtr pPix, int x1, int y1, int x2, int y2);
void
exaGetDrawableDeltas(DrawablePtr pDrawable, PixmapPtr pPixmap,
int *xp, int *yp);
Bool
exaPixmapHasGpuCopy(PixmapPtr p);
PixmapPtr
exaGetOffscreenPixmap(DrawablePtr pDrawable, int *xp, int *yp);
PixmapPtr
exaGetDrawablePixmap(DrawablePtr pDrawable);
void
exaSetFbPitch(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
int w, int h, int bpp);
void
exaSetAccelBlock(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
int w, int h, int bpp);
void
exaDoMigration(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
Bool
exaPixmapIsPinned(PixmapPtr pPix);
extern const GCFuncs exaGCFuncs;
/* exa_classic.c */
PixmapPtr
exaCreatePixmap_classic(ScreenPtr pScreen, int w, int h, int depth,
unsigned usage_hint);
Bool
exaModifyPixmapHeader_classic(PixmapPtr pPixmap, int width, int height,
int depth, int bitsPerPixel, int devKind,
void *pPixData);
Bool
exaDestroyPixmap_classic(PixmapPtr pPixmap);
Bool
exaPixmapHasGpuCopy_classic(PixmapPtr pPixmap);
/* exa_driver.c */
PixmapPtr
exaCreatePixmap_driver(ScreenPtr pScreen, int w, int h, int depth,
unsigned usage_hint);
Bool
exaModifyPixmapHeader_driver(PixmapPtr pPixmap, int width, int height,
int depth, int bitsPerPixel, int devKind,
void *pPixData);
Bool
exaDestroyPixmap_driver(PixmapPtr pPixmap);
Bool
exaPixmapHasGpuCopy_driver(PixmapPtr pPixmap);
/* exa_mixed.c */
PixmapPtr
exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth,
unsigned usage_hint);
Bool
exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
int bitsPerPixel, int devKind, void *pPixData);
Bool
exaDestroyPixmap_mixed(PixmapPtr pPixmap);
Bool
exaPixmapHasGpuCopy_mixed(PixmapPtr pPixmap);
/* exa_migration_mixed.c */
void
exaCreateDriverPixmap_mixed(PixmapPtr pPixmap);
void
exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
void
exaMoveInPixmap_mixed(PixmapPtr pPixmap);
void
exaDamageReport_mixed(DamagePtr pDamage, RegionPtr pRegion, void *closure);
void
exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg);
Bool
exaSetSharedPixmapBacking_mixed(PixmapPtr pPixmap, void *handle);
Bool
exaSharePixmapBacking_mixed(PixmapPtr pPixmap, ScreenPtr secondary, void **handle_p);
/* exa_render.c */
Bool
exaOpReadsDestination(CARD8 op);
void
exaComposite(CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask,
INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height);
void
exaCompositeRects(CARD8 op,
PicturePtr Src,
PicturePtr pMask,
PicturePtr pDst, int nrect, ExaCompositeRectPtr rects);
void
exaTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
int ntrap, xTrapezoid * traps);
void
exaTriangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
int ntri, xTriangle * tris);
/* exa_glyph.c */
void
exaGlyphsInit(ScreenPtr pScreen);
void
exaGlyphsFini(ScreenPtr pScreen);
void
exaGlyphs(CARD8 op,
PicturePtr pSrc,
PicturePtr pDst,
PictFormatPtr maskFormat,
INT16 xSrc,
INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs);
/* exa_migration_classic.c */
void
exaCopyDirtyToSys(ExaMigrationPtr migrate);
void
exaCopyDirtyToFb(ExaMigrationPtr migrate);
void
exaDoMigration_classic(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
void
exaPixmapSave(ScreenPtr pScreen, ExaOffscreenArea * area);
void
exaMoveOutPixmap_classic(PixmapPtr pPixmap);
void
exaMoveInPixmap_classic(PixmapPtr pPixmap);
void
exaPrepareAccessReg_classic(PixmapPtr pPixmap, int index, RegionPtr pReg);
#endif /* EXAPRIV_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,733 +0,0 @@
/*
*
* Copyright © 1999 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "exa_priv.h"
#include "mipict.h"
/*
* These functions wrap the low-level fb rendering functions and
* synchronize framebuffer/accelerated drawing by stalling until
* the accelerator is idle
*/
/**
* Calls exaPrepareAccess with EXA_PREPARE_SRC for the tile, if that is the
* current fill style.
*
* Solid doesn't use an extra pixmap source, and Stippled/OpaqueStippled are
* 1bpp and never in fb, so we don't worry about them.
* We should worry about them for completeness sake and going forward.
*/
void
exaPrepareAccessGC(GCPtr pGC)
{
if (pGC->stipple)
exaPrepareAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK);
if (pGC->fillStyle == FillTiled)
exaPrepareAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC);
}
/**
* Finishes access to the tile in the GC, if used.
*/
void
exaFinishAccessGC(GCPtr pGC)
{
if (pGC->fillStyle == FillTiled)
exaFinishAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC);
if (pGC->stipple)
exaFinishAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK);
}
#if DEBUG_TRACE_FALL
char
exaDrawableLocation(DrawablePtr pDrawable)
{
return exaDrawableIsOffscreen(pDrawable) ? 's' : 'm';
}
#endif /* DEBUG_TRACE_FALL */
void
ExaCheckFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nspans,
DDXPointPtr ppt, int *pwidth, int fSorted)
{
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
exaPrepareAccessGC(pGC);
pGC->ops->FillSpans(pDrawable, pGC, nspans, ppt, pwidth, fSorted);
exaFinishAccessGC(pGC);
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
void
ExaCheckSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
DDXPointPtr ppt, int *pwidth, int nspans, int fSorted)
{
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
pGC->ops->SetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
void
ExaCheckPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
int x, int y, int w, int h, int leftPad, int format,
char *bits)
{
PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
ExaPixmapPriv(pPixmap);
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
if (!pExaScr->prepare_access_reg || !pExaPixmap->pDamage ||
exaGCReadsDestination(pDrawable, pGC->planemask, pGC->fillStyle,
pGC->alu, pGC->clientClip != NULL))
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
else
pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_DEST,
DamagePendingRegion(pExaPixmap->pDamage));
pGC->ops->PutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
bits);
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
void
ExaCheckCopyNtoN(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
BoxPtr pbox, int nbox, int dx, int dy, Bool reverse,
Bool upsidedown, Pixel bitplane, void *closure)
{
RegionRec reg;
int xoff, yoff;
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
exaDrawableLocation(pSrc), exaDrawableLocation(pDst)));
if (pExaScr->prepare_access_reg && RegionInitBoxes(&reg, pbox, nbox)) {
PixmapPtr pPixmap = exaGetDrawablePixmap(pSrc);
exaGetDrawableDeltas(pSrc, pPixmap, &xoff, &yoff);
RegionTranslate(&reg, xoff + dx, yoff + dy);
pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_SRC, &reg);
RegionUninit(&reg);
}
else
exaPrepareAccess(pSrc, EXA_PREPARE_SRC);
if (pExaScr->prepare_access_reg &&
!exaGCReadsDestination(pDst, pGC->planemask, pGC->fillStyle,
pGC->alu, pGC->clientClip != NULL) &&
RegionInitBoxes(&reg, pbox, nbox)) {
PixmapPtr pPixmap = exaGetDrawablePixmap(pDst);
exaGetDrawableDeltas(pDst, pPixmap, &xoff, &yoff);
RegionTranslate(&reg, xoff, yoff);
pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_DEST, &reg);
RegionUninit(&reg);
}
else
exaPrepareAccess(pDst, EXA_PREPARE_DEST);
/* This will eventually call fbCopyNtoN, with some calculation overhead. */
while (nbox--) {
pGC->ops->CopyArea(pSrc, pDst, pGC, pbox->x1 - pSrc->x + dx,
pbox->y1 - pSrc->y + dy, pbox->x2 - pbox->x1,
pbox->y2 - pbox->y1, pbox->x1 - pDst->x,
pbox->y1 - pDst->y);
pbox++;
}
exaFinishAccess(pSrc, EXA_PREPARE_SRC);
exaFinishAccess(pDst, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
static void
ExaFallbackPrepareReg(DrawablePtr pDrawable,
GCPtr pGC,
int x, int y, int width, int height,
int index, Bool checkReads)
{
ScreenPtr pScreen = pDrawable->pScreen;
ExaScreenPriv(pScreen);
if (pExaScr->prepare_access_reg &&
!(checkReads && exaGCReadsDestination(pDrawable, pGC->planemask,
pGC->fillStyle, pGC->alu,
pGC->clientClip != NULL))) {
BoxRec box;
RegionRec reg;
int xoff, yoff;
PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
box.x1 = pDrawable->x + x + xoff;
box.y1 = pDrawable->y + y + yoff;
box.x2 = box.x1 + width;
box.y2 = box.y1 + height;
RegionInit(&reg, &box, 1);
pExaScr->prepare_access_reg(pPixmap, index, &reg);
RegionUninit(&reg);
}
else
exaPrepareAccess(pDrawable, index);
}
RegionPtr
ExaCheckCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
int srcx, int srcy, int w, int h, int dstx, int dsty)
{
RegionPtr ret;
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
exaDrawableLocation(pSrc), exaDrawableLocation(pDst)));
ExaFallbackPrepareReg(pSrc, pGC, srcx, srcy, w, h, EXA_PREPARE_SRC, FALSE);
ExaFallbackPrepareReg(pDst, pGC, dstx, dsty, w, h, EXA_PREPARE_DEST, TRUE);
ret = pGC->ops->CopyArea(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty);
exaFinishAccess(pSrc, EXA_PREPARE_SRC);
exaFinishAccess(pDst, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
return ret;
}
RegionPtr
ExaCheckCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
int srcx, int srcy, int w, int h, int dstx, int dsty,
unsigned long bitPlane)
{
RegionPtr ret;
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
exaDrawableLocation(pSrc), exaDrawableLocation(pDst)));
ExaFallbackPrepareReg(pSrc, pGC, srcx, srcy, w, h, EXA_PREPARE_SRC, FALSE);
ExaFallbackPrepareReg(pDst, pGC, dstx, dsty, w, h, EXA_PREPARE_DEST, TRUE);
ret = pGC->ops->CopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty,
bitPlane);
exaFinishAccess(pSrc, EXA_PREPARE_SRC);
exaFinishAccess(pDst, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
return ret;
}
void
ExaCheckPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
DDXPointPtr pptInit)
{
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
pGC->ops->PolyPoint(pDrawable, pGC, mode, npt, pptInit);
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
void
ExaCheckPolylines(DrawablePtr pDrawable, GCPtr pGC,
int mode, int npt, DDXPointPtr ppt)
{
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("to %p (%c), width %d, mode %d, count %d\n",
pDrawable, exaDrawableLocation(pDrawable),
pGC->lineWidth, mode, npt));
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
exaPrepareAccessGC(pGC);
pGC->ops->Polylines(pDrawable, pGC, mode, npt, ppt);
exaFinishAccessGC(pGC);
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
void
ExaCheckPolySegment(DrawablePtr pDrawable, GCPtr pGC,
int nsegInit, xSegment * pSegInit)
{
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("to %p (%c) width %d, count %d\n", pDrawable,
exaDrawableLocation(pDrawable), pGC->lineWidth, nsegInit));
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
exaPrepareAccessGC(pGC);
pGC->ops->PolySegment(pDrawable, pGC, nsegInit, pSegInit);
exaFinishAccessGC(pGC);
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
void
ExaCheckPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc * pArcs)
{
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
exaPrepareAccessGC(pGC);
pGC->ops->PolyArc(pDrawable, pGC, narcs, pArcs);
exaFinishAccessGC(pGC);
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
void
ExaCheckPolyFillRect(DrawablePtr pDrawable, GCPtr pGC,
int nrect, xRectangle *prect)
{
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
exaPrepareAccessGC(pGC);
pGC->ops->PolyFillRect(pDrawable, pGC, nrect, prect);
exaFinishAccessGC(pGC);
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
void
ExaCheckImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
int x, int y, unsigned int nglyph,
CharInfoPtr * ppci, void *pglyphBase)
{
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
exaPrepareAccessGC(pGC);
pGC->ops->ImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
exaFinishAccessGC(pGC);
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
void
ExaCheckPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
int x, int y, unsigned int nglyph,
CharInfoPtr * ppci, void *pglyphBase)
{
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("to %p (%c), style %d alu %d\n", pDrawable,
exaDrawableLocation(pDrawable), pGC->fillStyle, pGC->alu));
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
exaPrepareAccessGC(pGC);
pGC->ops->PolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
exaFinishAccessGC(pGC);
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
void
ExaCheckPushPixels(GCPtr pGC, PixmapPtr pBitmap,
DrawablePtr pDrawable, int w, int h, int x, int y)
{
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("from %p to %p (%c,%c)\n", pBitmap, pDrawable,
exaDrawableLocation(&pBitmap->drawable),
exaDrawableLocation(pDrawable)));
ExaFallbackPrepareReg(pDrawable, pGC, x, y, w, h, EXA_PREPARE_DEST, TRUE);
ExaFallbackPrepareReg(&pBitmap->drawable, pGC, 0, 0, w, h,
EXA_PREPARE_SRC, FALSE);
exaPrepareAccessGC(pGC);
pGC->ops->PushPixels(pGC, pBitmap, pDrawable, w, h, x, y);
exaFinishAccessGC(pGC);
exaFinishAccess(&pBitmap->drawable, EXA_PREPARE_SRC);
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
void
ExaCheckCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
{
DrawablePtr pDrawable = &pWin->drawable;
ScreenPtr pScreen = pDrawable->pScreen;
EXA_PRE_FALLBACK(pScreen);
EXA_FALLBACK(("from %p\n", pWin));
/* Only need the source bits, the destination region will be overwritten */
if (pExaScr->prepare_access_reg) {
PixmapPtr pPixmap = pScreen->GetWindowPixmap(pWin);
int xoff, yoff;
exaGetDrawableDeltas(&pWin->drawable, pPixmap, &xoff, &yoff);
RegionTranslate(prgnSrc, xoff, yoff);
pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_SRC, prgnSrc);
RegionTranslate(prgnSrc, -xoff, -yoff);
}
else
exaPrepareAccess(pDrawable, EXA_PREPARE_SRC);
swap(pExaScr, pScreen, CopyWindow);
pScreen->CopyWindow(pWin, ptOldOrg, prgnSrc);
swap(pExaScr, pScreen, CopyWindow);
exaFinishAccess(pDrawable, EXA_PREPARE_SRC);
EXA_POST_FALLBACK(pScreen);
}
void
ExaCheckGetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
unsigned int format, unsigned long planeMask, char *d)
{
ScreenPtr pScreen = pDrawable->pScreen;
EXA_PRE_FALLBACK(pScreen);
EXA_FALLBACK(("from %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
ExaFallbackPrepareReg(pDrawable, NULL, x, y, w, h, EXA_PREPARE_SRC, FALSE);
swap(pExaScr, pScreen, GetImage);
pScreen->GetImage(pDrawable, x, y, w, h, format, planeMask, d);
swap(pExaScr, pScreen, GetImage);
exaFinishAccess(pDrawable, EXA_PREPARE_SRC);
EXA_POST_FALLBACK(pScreen);
}
void
ExaCheckGetSpans(DrawablePtr pDrawable,
int wMax,
DDXPointPtr ppt, int *pwidth, int nspans, char *pdstStart)
{
ScreenPtr pScreen = pDrawable->pScreen;
EXA_PRE_FALLBACK(pScreen);
EXA_FALLBACK(("from %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
exaPrepareAccess(pDrawable, EXA_PREPARE_SRC);
swap(pExaScr, pScreen, GetSpans);
pScreen->GetSpans(pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
swap(pExaScr, pScreen, GetSpans);
exaFinishAccess(pDrawable, EXA_PREPARE_SRC);
EXA_POST_FALLBACK(pScreen);
}
static void
ExaSrcValidate(DrawablePtr pDrawable,
int x, int y, int width, int height, unsigned int subWindowMode)
{
ScreenPtr pScreen = pDrawable->pScreen;
ExaScreenPriv(pScreen);
PixmapPtr pPix = exaGetDrawablePixmap(pDrawable);
BoxRec box;
RegionRec reg;
RegionPtr dst;
int xoff, yoff;
if (pExaScr->srcPix == pPix)
dst = &pExaScr->srcReg;
else if (pExaScr->maskPix == pPix)
dst = &pExaScr->maskReg;
else
return;
exaGetDrawableDeltas(pDrawable, pPix, &xoff, &yoff);
box.x1 = x + xoff;
box.y1 = y + yoff;
box.x2 = box.x1 + width;
box.y2 = box.y1 + height;
RegionInit(&reg, &box, 1);
RegionUnion(dst, dst, &reg);
RegionUninit(&reg);
swap(pExaScr, pScreen, SourceValidate);
pScreen->SourceValidate(pDrawable, x, y, width, height, subWindowMode);
swap(pExaScr, pScreen, SourceValidate);
}
static Bool
ExaPrepareCompositeReg(ScreenPtr pScreen,
CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask,
INT16 yMask,
INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
{
RegionRec region;
RegionPtr dstReg = NULL;
RegionPtr srcReg = NULL;
RegionPtr maskReg = NULL;
PixmapPtr pSrcPix = NULL;
PixmapPtr pMaskPix = NULL;
PixmapPtr pDstPix;
ExaScreenPriv(pScreen);
Bool ret;
RegionNull(&region);
if (pSrc->pDrawable) {
pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
RegionNull(&pExaScr->srcReg);
srcReg = &pExaScr->srcReg;
pExaScr->srcPix = pSrcPix;
if (pSrc != pDst)
RegionTranslate(pSrc->pCompositeClip,
-pSrc->pDrawable->x, -pSrc->pDrawable->y);
} else
pExaScr->srcPix = NULL;
if (pMask && pMask->pDrawable) {
pMaskPix = exaGetDrawablePixmap(pMask->pDrawable);
RegionNull(&pExaScr->maskReg);
maskReg = &pExaScr->maskReg;
pExaScr->maskPix = pMaskPix;
if (pMask != pDst && pMask != pSrc)
RegionTranslate(pMask->pCompositeClip,
-pMask->pDrawable->x, -pMask->pDrawable->y);
} else
pExaScr->maskPix = NULL;
RegionTranslate(pDst->pCompositeClip,
-pDst->pDrawable->x, -pDst->pDrawable->y);
pExaScr->SavedSourceValidate = ExaSrcValidate;
swap(pExaScr, pScreen, SourceValidate);
ret = miComputeCompositeRegion(&region, pSrc, pMask, pDst,
xSrc, ySrc, xMask, yMask,
xDst, yDst, width, height);
swap(pExaScr, pScreen, SourceValidate);
RegionTranslate(pDst->pCompositeClip,
pDst->pDrawable->x, pDst->pDrawable->y);
if (pSrc->pDrawable && pSrc != pDst)
RegionTranslate(pSrc->pCompositeClip,
pSrc->pDrawable->x, pSrc->pDrawable->y);
if (pMask && pMask->pDrawable && pMask != pDst && pMask != pSrc)
RegionTranslate(pMask->pCompositeClip,
pMask->pDrawable->x, pMask->pDrawable->y);
if (!ret) {
if (srcReg)
RegionUninit(srcReg);
if (maskReg)
RegionUninit(maskReg);
return FALSE;
}
/**
* Don't limit alphamaps readbacks for now until we've figured out how that
* should be done.
*/
if (pSrc->alphaMap && pSrc->alphaMap->pDrawable)
pExaScr->
prepare_access_reg(exaGetDrawablePixmap(pSrc->alphaMap->pDrawable),
EXA_PREPARE_AUX_SRC, NULL);
if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
pExaScr->
prepare_access_reg(exaGetDrawablePixmap(pMask->alphaMap->pDrawable),
EXA_PREPARE_AUX_MASK, NULL);
if (pSrcPix)
pExaScr->prepare_access_reg(pSrcPix, EXA_PREPARE_SRC, srcReg);
if (pMaskPix)
pExaScr->prepare_access_reg(pMaskPix, EXA_PREPARE_MASK, maskReg);
if (srcReg)
RegionUninit(srcReg);
if (maskReg)
RegionUninit(maskReg);
pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
if (!exaOpReadsDestination(op)) {
int xoff;
int yoff;
exaGetDrawableDeltas(pDst->pDrawable, pDstPix, &xoff, &yoff);
RegionTranslate(&region, pDst->pDrawable->x + xoff,
pDst->pDrawable->y + yoff);
dstReg = &region;
}
if (pDst->alphaMap && pDst->alphaMap->pDrawable)
pExaScr->
prepare_access_reg(exaGetDrawablePixmap(pDst->alphaMap->pDrawable),
EXA_PREPARE_AUX_DEST, dstReg);
pExaScr->prepare_access_reg(pDstPix, EXA_PREPARE_DEST, dstReg);
RegionUninit(&region);
return TRUE;
}
void
ExaCheckComposite(CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask,
INT16 yMask,
INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
{
ScreenPtr pScreen = pDst->pDrawable->pScreen;
PictureScreenPtr ps = GetPictureScreen(pScreen);
EXA_PRE_FALLBACK(pScreen);
if (pExaScr->prepare_access_reg) {
if (!ExaPrepareCompositeReg(pScreen, op, pSrc, pMask, pDst, xSrc,
ySrc, xMask, yMask, xDst, yDst, width,
height))
goto out_no_clip;
}
else {
/* We need to prepare access to any separate alpha maps first,
* in case the driver doesn't support EXA_PREPARE_AUX*,
* in which case EXA_PREPARE_SRC may be used for moving them out.
*/
if (pSrc->alphaMap && pSrc->alphaMap->pDrawable)
exaPrepareAccess(pSrc->alphaMap->pDrawable, EXA_PREPARE_AUX_SRC);
if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
exaPrepareAccess(pMask->alphaMap->pDrawable, EXA_PREPARE_AUX_MASK);
if (pDst->alphaMap && pDst->alphaMap->pDrawable)
exaPrepareAccess(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX_DEST);
exaPrepareAccess(pDst->pDrawable, EXA_PREPARE_DEST);
EXA_FALLBACK(("from picts %p/%p to pict %p\n", pSrc, pMask, pDst));
if (pSrc->pDrawable != NULL)
exaPrepareAccess(pSrc->pDrawable, EXA_PREPARE_SRC);
if (pMask && pMask->pDrawable != NULL)
exaPrepareAccess(pMask->pDrawable, EXA_PREPARE_MASK);
}
swap(pExaScr, ps, Composite);
ps->Composite(op,
pSrc,
pMask,
pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height);
swap(pExaScr, ps, Composite);
if (pMask && pMask->pDrawable != NULL)
exaFinishAccess(pMask->pDrawable, EXA_PREPARE_MASK);
if (pSrc->pDrawable != NULL)
exaFinishAccess(pSrc->pDrawable, EXA_PREPARE_SRC);
exaFinishAccess(pDst->pDrawable, EXA_PREPARE_DEST);
if (pDst->alphaMap && pDst->alphaMap->pDrawable)
exaFinishAccess(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX_DEST);
if (pSrc->alphaMap && pSrc->alphaMap->pDrawable)
exaFinishAccess(pSrc->alphaMap->pDrawable, EXA_PREPARE_AUX_SRC);
if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
exaFinishAccess(pMask->alphaMap->pDrawable, EXA_PREPARE_AUX_MASK);
out_no_clip:
EXA_POST_FALLBACK(pScreen);
}
/**
* Avoid migration ping-pong when using a mask.
*/
void
ExaCheckGlyphs(CARD8 op,
PicturePtr pSrc,
PicturePtr pDst,
PictFormatPtr maskFormat,
INT16 xSrc,
INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs)
{
ScreenPtr pScreen = pDst->pDrawable->pScreen;
EXA_PRE_FALLBACK(pScreen);
miGlyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
EXA_POST_FALLBACK(pScreen);
}
void
ExaCheckAddTraps(PicturePtr pPicture,
INT16 x_off, INT16 y_off, int ntrap, xTrap * traps)
{
ScreenPtr pScreen = pPicture->pDrawable->pScreen;
PictureScreenPtr ps = GetPictureScreen(pScreen);
EXA_PRE_FALLBACK(pScreen);
EXA_FALLBACK(("to pict %p (%c)\n", pPicture,
exaDrawableLocation(pPicture->pDrawable)));
exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
swap(pExaScr, ps, AddTraps);
ps->AddTraps(pPicture, x_off, y_off, ntrap, traps);
swap(pExaScr, ps, AddTraps);
exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK(pScreen);
}
/**
* Gets the 0,0 pixel of a pixmap. Used for doing solid fills of tiled pixmaps
* that happen to be 1x1. Pixmap must be at least 8bpp.
*/
CARD32
exaGetPixmapFirstPixel(PixmapPtr pPixmap)
{
switch (pPixmap->drawable.bitsPerPixel) {
case 32:
{
CARD32 pixel;
pPixmap->drawable.pScreen->GetImage(&pPixmap->drawable, 0, 0, 1, 1,
ZPixmap, ~0, (char *) &pixel);
return pixel;
}
case 16:
{
CARD16 pixel;
pPixmap->drawable.pScreen->GetImage(&pPixmap->drawable, 0, 0, 1, 1,
ZPixmap, ~0, (char *) &pixel);
return pixel;
}
case 8:
case 4:
case 1:
{
CARD8 pixel;
pPixmap->drawable.pScreen->GetImage(&pPixmap->drawable, 0, 0, 1, 1,
ZPixmap, ~0, (char *) &pixel);
return pixel;
}
default:
FatalError("%s called for invalid bpp %d\n", __func__,
pPixmap->drawable.bitsPerPixel);
}
}

View File

@ -1,24 +0,0 @@
srcs_exa = [
'exa.c',
'exa_classic.c',
'exa_migration_classic.c',
'exa_driver.c',
'exa_mixed.c',
'exa_migration_mixed.c',
'exa_accel.c',
'exa_glyphs.c',
'exa_offscreen.c',
'exa_render.c',
'exa_unaccel.c',
]
libxserver_exa = static_library('libxserver_exa',
srcs_exa,
include_directories: inc,
dependencies: common_dep,
c_args: '-DHAVE_XORG_CONFIG_H'
)
if build_xorg
install_data('exa.h', install_dir: xorgsdkdir)
endif

View File

@ -1,49 +0,0 @@
noinst_LTLIBRARIES = libfb.la libwfb.la
AM_CFLAGS = $(DIX_CFLAGS)
if XORG
sdk_HEADERS = fb.h fbrop.h fboverlay.h wfbrename.h fbpict.h
endif
libfb_la_CFLAGS = $(AM_CFLAGS)
libfb_la_LIBADD = $(PIXMAN_LIBS)
libwfb_la_CFLAGS = $(AM_CFLAGS) -DFB_ACCESS_WRAPPER
libwfb_la_LIBADD = $(PIXMAN_LIBS)
libfb_la_SOURCES = \
fb.h \
fballpriv.c \
fbarc.c \
fbbits.c \
fbbits.h \
fbblt.c \
fbbltone.c \
fbcmap_mi.c \
fbcopy.c \
fbfill.c \
fbfillrect.c \
fbfillsp.c \
fbgc.c \
fbgetsp.c \
fbglyph.c \
fbimage.c \
fbline.c \
fboverlay.c \
fboverlay.h \
fbpict.c \
fbpict.h \
fbpixmap.c \
fbpoint.c \
fbpush.c \
fbrop.h \
fbscreen.c \
fbseg.c \
fbsetsp.c \
fbsolid.c \
fbtrap.c \
fbutil.c \
fbwindow.c
libwfb_la_SOURCES = $(libfb_la_SOURCES)

View File

@ -53,5 +53,3 @@ libxserver_wfb = static_library('libxserver_wfb',
pic: true,
build_by_default: false,
)
install_data(hdrs_fb, install_dir: xorgsdkdir)

View File

@ -1,62 +0,0 @@
noinst_LTLIBRARIES = libglamor.la libglamor_egl_stubs.la
libglamor_la_LIBADD = $(GLAMOR_LIBS)
AM_CFLAGS = $(CWARNFLAGS) $(DIX_CFLAGS) $(GLAMOR_CFLAGS)
libglamor_la_SOURCES = \
glamor.c \
glamor_context.h \
glamor_copy.c \
glamor_core.c \
glamor_dash.c \
glamor_debug.h \
glamor_font.c \
glamor_font.h \
glamor_glx.c \
glamor_composite_glyphs.c \
glamor_image.c \
glamor_lines.c \
glamor_segs.c \
glamor_render.c \
glamor_gradient.c \
glamor_prepare.c \
glamor_prepare.h \
glamor_program.c \
glamor_program.h \
glamor_rects.c \
glamor_spans.c \
glamor_text.c \
glamor_transfer.c \
glamor_transfer.h \
glamor_transform.c \
glamor_transform.h \
glamor_trapezoid.c \
glamor_triangles.c\
glamor_addtraps.c\
glamor_glyphblt.c\
glamor_points.c\
glamor_priv.h\
glamor_pixmap.c\
glamor_largepixmap.c\
glamor_picture.c\
glamor_vbo.c \
glamor_window.c\
glamor_fbo.c\
glamor_compositerects.c\
glamor_utils.c\
glamor_utils.h\
glamor_sync.c \
glamor.h
if XV
libglamor_la_SOURCES += \
glamor_xv.c
endif
libglamor_egl_stubs_la_SOURCES = \
glamor_egl_stubs.c \
glamor_egl_ext.h \
glamor_egl.h
sdk_HEADERS = glamor.h

View File

@ -414,6 +414,7 @@ glamor_debug_output_callback(GLenum source,
LogMessageVerb(X_ERROR, 0, "glamor%d: GL error: %*s\n",
screen->myNum, length, message);
xorg_backtrace();
}
/**

View File

@ -54,7 +54,3 @@ glamor_egl_stubs = static_library('glamor_egl_stubs',
include_directories: inc,
dependencies: common_dep,
)
if build_xorg
install_data('glamor.h', install_dir: xorgsdkdir)
endif

View File

@ -1,95 +0,0 @@
if DRI2
GLXDRI_LIBRARY = libglxdri.la
endif
noinst_LTLIBRARIES = libglx.la $(GLXDRI_LIBRARY) libglxvnd.la
AM_CFLAGS = \
@DIX_CFLAGS@ \
@GL_CFLAGS@ \
@XLIB_CFLAGS@ \
@LIBDRM_CFLAGS@ \
@GLX_DEFINES@ \
@GLX_ARCH_DEFINES@
sdk_HEADERS = vndserver.h
AM_CPPFLAGS = \
-I$(top_srcdir)/hw/xfree86/os-support \
-I$(top_srcdir)/hw/xfree86/os-support/bus \
-I$(top_srcdir)/hw/xfree86/common \
-I$(top_srcdir)/hw/xfree86/dri \
-I$(top_srcdir)/hw/xfree86/dri2 \
-I$(top_srcdir)/mi \
-I$(top_srcdir)/present
indirect_sources = \
indirect_dispatch.c \
indirect_dispatch.h \
indirect_dispatch_swap.c \
indirect_reqsize.c \
indirect_reqsize.h \
indirect_size.h \
indirect_size_get.c \
indirect_size_get.h \
indirect_table.c
libglxdri_la_SOURCES =
if DRI2
libglxdri_la_SOURCES += glxdri2.c
endif
libglxdri_la_LIBADD = $(DLOPEN_LIBS)
libglx_la_SOURCES = \
$(indirect_sources) \
clientinfo.c \
createcontext.c \
extension_string.c \
extension_string.h \
indirect_util.c \
indirect_util.h \
indirect_program.c \
indirect_table.h \
indirect_texture_compression.c \
glxbyteorder.h \
glxcmds.c \
glxcmdsswap.c \
glxcontext.h \
glxdrawable.h \
glxext.c \
glxext.h \
glxdriswrast.c \
glxdricommon.c \
glxdricommon.h \
glxscreens.c \
glxscreens.h \
glxserver.h \
glxutil.h \
render2.c \
render2swap.c \
renderpix.c \
renderpixswap.c \
rensize.c \
single2.c \
single2swap.c \
singlepix.c \
singlepixswap.c \
singlesize.c \
singlesize.h \
swap_interval.c \
unpack.h \
xfont.c
libglx_la_LIBADD = $(DLOPEN_LIBS) $(top_builddir)/Xext/libhashtable.la
libglxvnd_la_SOURCES = \
vndcmds.c \
vndext.c \
vndservermapping.c \
vndservervendor.h \
vndservervendor.c
libglxvnd_la_LIBADD = $(top_builddir)/Xext/libhashtable.la
EXTRA_DIST = vnd_dispatch_stubs.c

View File

@ -487,8 +487,15 @@ __glXGetDrawable(__GLXcontext * glxc, GLXDrawable drawId, ClientPtr client,
__GLXscreen *pGlxScreen;
int rc;
if (validGlxDrawable(client, drawId, GLX_DRAWABLE_ANY,
DixWriteAccess, &pGlxDraw, &rc)) {
rc = dixLookupResourceByType((void **)&pGlxDraw, drawId,
__glXDrawableRes, client, DixWriteAccess);
if (rc == Success &&
/* If pGlxDraw->drawId == drawId, drawId is a valid GLX drawable.
* Otherwise, if pGlxDraw->type == GLX_DRAWABLE_WINDOW, drawId is
* an X window, but the client has already created a GLXWindow
* associated with it, so we don't want to create another one. */
(pGlxDraw->drawId == drawId ||
pGlxDraw->type == GLX_DRAWABLE_WINDOW)) {
if (glxc != NULL &&
glxc->config != NULL &&
glxc->config != pGlxDraw->config) {
@ -655,11 +662,12 @@ xorgGlxMakeCurrent(ClientPtr client, GLXContextTag tag, XID drawId, XID readId,
glxc->readPriv = NULL;
return __glXError(GLXBadContext);
}
glxc->currentClient = client;
glxServer.setContextTagPrivate(client, newContextTag, glxc);
}
glxServer.setContextTagPrivate(client, newContextTag, glxc);
if (glxc)
glxc->currentClient = client;
if (prevglxc) {
prevglxc->currentClient = NULL;
if (!prevglxc->idExists) {

View File

@ -51,7 +51,7 @@ if build_glx
endif
srcs_glxdri2 = []
if build_dri2 or build_dri3
if build_dri3
srcs_glxdri2 = files('glxdri2.c')
endif
@ -78,6 +78,4 @@ if build_glx
dependency('gl', version: '>= 1.2'),
],
)
install_data(hdrs_vnd, install_dir : xorgsdkdir)
endif

View File

@ -1,46 +0,0 @@
if DMX
DMX_SUBDIRS = dmx
endif
if XORG
XORG_SUBDIRS = xfree86
endif
if XVFB
XVFB_SUBDIRS = vfb
endif
if XNEST
XNEST_SUBDIRS = xnest
endif
if XWIN
XWIN_SUBDIRS = xwin
endif
if KDRIVE
KDRIVE_SUBDIRS = kdrive
endif
if XQUARTZ
XQUARTZ_SUBDIRS = xquartz
endif
if XWAYLAND
XWAYLAND_SUBDIRS = xwayland
endif
SUBDIRS = \
$(XORG_SUBDIRS) \
$(XWIN_SUBDIRS) \
$(XVFB_SUBDIRS) \
$(XNEST_SUBDIRS) \
$(DMX_SUBDIRS) \
$(KDRIVE_SUBDIRS) \
$(XQUARTZ_SUBDIRS) \
$(XWAYLAND_SUBDIRS)
DIST_SUBDIRS = dmx xfree86 vfb xnest xwin xquartz kdrive xwayland
relink:
$(AM_V_at)for i in $(SUBDIRS) ; do $(MAKE) -C $$i relink || exit 1 ; done

2
hw/dmx/.gitignore vendored
View File

@ -1,2 +0,0 @@
# Add & Override for this directory and its subdirectories
Xdmx

View File

@ -1,87 +0,0 @@
SUBDIRS = input config examples doc doxygen man
bin_PROGRAMS = Xdmx
if XINERAMA
PANORAMIX_SRCS = $(top_srcdir)/Xext/panoramiX.c
endif
if GLX
SUBDIRS += glxProxy
GLX_LIBS = glxProxy/libglxproxy.a
GLX_SRCS = $(PANORAMIX_SRCS) dmx_glxvisuals.c dmx_glxvisuals.h
GLX_INCS = -I$(top_srcdir)/hw/xfree86/dixmods/extmod
GLX_DEFS = @GL_CFLAGS@
endif
AM_CFLAGS = \
-DHAVE_DMX_CONFIG_H \
$(DIX_CFLAGS) \
$(GLX_INCS) \
$(GLX_DEFS) \
$(DMX_CFLAGS) \
@DMXMODULES_CFLAGS@
Xdmx_SOURCES = dmx.c \
dmxcb.c \
dmxcb.h \
dmxclient.h \
dmxcmap.c \
dmxcmap.h \
dmx-config.h \
dmxcursor.c \
dmxcursor.h \
dmxdpms.c \
dmxdpms.h \
dmxextension.c \
dmxextension.h \
dmxfont.c \
dmxfont.h \
dmxgc.c \
dmxgc.h \
dmxgcops.c \
dmxgcops.h \
dmx.h \
dmxinit.c \
dmxinit.h \
dmxinput.c \
dmxinput.h \
dmxlog.c \
dmxlog.h \
dmxpict.c \
dmxpict.h \
dmxpixmap.c \
dmxpixmap.h \
dmxprop.c \
dmxprop.h \
dmxscrinit.c \
dmxscrinit.h \
dmxstat.c \
dmxstat.h \
dmxsync.c \
dmxsync.h \
dmxvisual.c \
dmxvisual.h \
dmxwindow.c \
dmxwindow.h \
$(top_srcdir)/mi/miinitext.c \
$(top_srcdir)/mi/miinitext.h \
$(GLX_SRCS)
#if COMPOSITE
#Xdmx_SOURCES += fakecw.c
#endif
XDMX_LIBS = \
$(GLX_LIBS) \
@XDMX_LIBS@ \
input/libdmxinput.a \
config/libdmxconfig.a
Xdmx_LDFLAGS = $(LD_EXPORT_SYMBOLS_FLAG)
Xdmx_DEPENDENCIES= $(XDMX_LIBS)
Xdmx_LDADD = $(XDMX_LIBS) $(XDMX_SYS_LIBS) $(XSERVER_SYS_LIBS)
relink:
$(AM_V_at)rm -f Xdmx$(EXEEXT) && $(MAKE) Xdmx$(EXEEXT)

View File

@ -1,7 +0,0 @@
# Add & Override for this directory and its subdirectories
dmxtodmx
parser.c
parser.h
scanner.c
vdltodmx
xdmxconfig

View File

@ -1,165 +0,0 @@
/*
* Copyright 1987, 1998 The Open Group
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of The Open Group shall not be
* used in advertising or otherwise to promote the sale, use or other dealings
* in this Software without prior written authorization from The Open Group.
*/
/*
* Copyright 2002 Red Hat Inc., Durham, North Carolina.
*
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation on the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* Authors:
* Rickard E. (Rik) Faith <faith@redhat.com>
*
* This file was originally taken from xc/lib/Xaw/Template.c
*/
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include "CanvasP.h"
static void
CanvasInitialize(Widget request, Widget w, ArgList args, Cardinal * num_args)
{
}
static void
CanvasExpose(Widget w, XEvent * event, Region region)
{
CanvasExposeDataRec data;
data.w = w;
data.event = event;
data.region = region;
if (!XtIsRealized(w))
return;
XtCallCallbacks(w, XtNcanvasExposeCallback, (XtPointer) &data);
}
static void
CanvasResize(Widget w)
{
if (!XtIsRealized(w))
return;
XtCallCallbacks(w, XtNcanvasResizeCallback, (XtPointer) w);
}
static void
CanvasAction(Widget w, XEvent * event, String * params, Cardinal * num_params)
{
XtCallCallbacks(w, XtNcallback, (XtPointer) event);
}
#define offset(field) XtOffsetOf(CanvasRec, canvas.field)
static XtResource resources[] = {
{XtNcallback, XtCCallback, XtRCallback,
sizeof(XtCallbackList), offset(input_callback), XtRCallback, NULL}
,
{(char *) XtNcanvasExposeCallback, (char *) XtCcanvasExposeCallback, XtRCallback,
sizeof(XtCallbackList), offset(expose_callback), XtRCallback, NULL}
,
{(char *) XtNcanvasResizeCallback, (char *) XtCcanvasResizeCallback, XtRCallback,
sizeof(XtCallbackList), offset(resize_callback), XtRCallback, NULL}
,
};
#undef offset
static XtActionsRec actions[] = {
{(char *) "canvas", CanvasAction},
};
static char translations[] = "<Key>: canvas()\n\
<Motion>: canvas()\n\
<BtnDown>: canvas()\n\
<BtnUp>: canvas()\n\
";
#define Superclass (&widgetClassRec)
CanvasClassRec canvasClassRec = {
/* core */
{
(WidgetClass) Superclass, /* superclass */
(char *) "Canvas", /* class_name */
sizeof(CanvasRec), /* widget_size */
NULL, /* class_initialize */
NULL, /* class_part_initialize */
False, /* class_inited */
CanvasInitialize, /* initialize */
NULL, /* initialize_hook */
XtInheritRealize, /* realize */
actions, /* actions */
XtNumber(actions), /* num_actions */
resources, /* resources */
XtNumber(resources), /* num_resources */
NULLQUARK, /* xrm_class */
True, /* compress_motion */
True, /* compress_exposure */
True, /* compress_enterleave */
False, /* visible_interest */
NULL, /* destroy */
CanvasResize, /* resize */
CanvasExpose, /* expose */
NULL, /* set_values */
NULL, /* set_values_hook */
XtInheritSetValuesAlmost, /* set_values_almost */
NULL, /* get_values_hook */
NULL, /* accept_focus */
XtVersion, /* version */
NULL, /* callback_private */
translations, /* tm_table */
XtInheritQueryGeometry, /* query_geometry */
XtInheritDisplayAccelerator, /* display_accelerator */
NULL, /* extension */
}
,
/* canvas */
{
NULL, /* extension */
}
};
WidgetClass canvasWidgetClass = (WidgetClass) &canvasClassRec;

View File

@ -1,55 +0,0 @@
/*
Copyright 1987, 1998 The Open Group
Copyright 2002 Red Hat Inc., Durham, North Carolina.
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
*/
/*
* Authors:
* Rickard E. (Rik) Faith <faith@redhat.com>
*
* This file was originally taken from xc/lib/Xaw/Template.h
*/
#ifndef _Canvas_h
#define _Canvas_h
#include <X11/Intrinsic.h>
#define XtNcanvasExposeCallback "canvasExposeCallback"
#define XtCcanvasExposeCallback "CanvasExposeCallback"
#define XtNcanvasResizeCallback "canvasResizeCallback"
#define XtCcanvasResizeCallback "CanvasResizeCallback"
typedef struct _CanvasClassRec *CanvasWidgetClass;
typedef struct _CanvasRec *CanvasWidget;
extern WidgetClass canvasWidgetClass;
typedef struct _CanvasExposeDataRec {
Widget w;
XEvent *event;
Region region;
} CanvasExposeDataRec, *CanvasExposeDataPtr;
#endif /* _Canvas_h */

View File

@ -1,65 +0,0 @@
/*
Copyright 1987, 1998 The Open Group
Copyright 2002 Red Hat Inc., Durham, North Carolina.
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
*/
/*
* Authors:
* Rickard E. (Rik) Faith <faith@redhat.com>
*
* This file was originally taken from xc/lib/Xaw/TemplateP.h
*/
#ifndef _CanvasP_h
#define _CanvasP_h
#include "Canvas.h"
/* include superclass private header file */
#include <X11/CoreP.h>
typedef struct {
XtPointer extension;
} CanvasClassPart;
typedef struct _CanvasClassRec {
CoreClassPart core_class;
CanvasClassPart canvas_class;
} CanvasClassRec;
extern CanvasClassRec canvasClassRec;
typedef struct {
XtCallbackList input_callback;
XtCallbackList expose_callback;
XtCallbackList resize_callback;
} CanvasPart;
typedef struct _CanvasRec {
CorePart core;
CanvasPart canvas;
} CanvasRec;
#endif /* _CanvasP_h */

View File

@ -1,71 +0,0 @@
SUBDIRS = man
noinst_LIBRARIES = libdmxconfig.a
LIBSRCS = parser.y \
scanner.l \
dmxparse.c \
dmxparse.h \
dmxprint.c \
dmxprint.h \
dmxcompat.c \
dmxcompat.h \
dmxconfig.c \
dmxconfig.h
parser.h: parser.c
scanner.c: scanner.l parser.h
BUILT_SOURCES = parser.c parser.h scanner.c
MAINTAINERCLEANFILES = $(BUILT_SOURCES)
libdmxconfig_a_SOURCES = $(LIBSRCS)
libdmxconfig_a_SOURCES += $(top_srcdir)/os/strlcpy.c
if GLX
GLX_DEFS = @GL_CFLAGS@
endif
AM_YFLAGS = -d
AM_CFLAGS = \
$(DIX_CFLAGS) \
-I$(top_srcdir)/hw/dmx \
-DHAVE_DMX_CONFIG_H \
-DDMX_LOG_STANDALONE \
$(GLX_DEFS) \
@DMXMODULES_CFLAGS@
bin_PROGRAMS = xdmxconfig vdltodmx dmxtodmx
xdmxconfig_DEPENDENCIES = libdmxconfig.a
xdmxconfig_SOURCES = \
xdmxconfig.c \
$(top_srcdir)/hw/dmx/dmxlog.c \
Canvas.c \
Canvas.h \
CanvasP.h
xdmxconfig_LDADD = -L. -ldmxconfig @XDMXCONFIG_DEP_LIBS@
xdmxconfig_CFLAGS = $(AM_CFLAGS) @XDMXCONFIG_DEP_CFLAGS@
vdltodmx_DEPENDENCIES = libdmxconfig.a
vdltodmx_SOURCES = vdltodmx.c
vdltodmx_LDADD = -L. -ldmxconfig
dmxtodmx_DEPENDENCIES = libdmxconfig.a
dmxtodmx_SOURCES = dmxtodmx.c
dmxtodmx_LDADD = -L. -ldmxconfig
EXTRA_DIST = \
test-a.in test-a.out \
test-b.in test-b.out \
test-c.in test-c.out \
test-d.in test-d.out \
test-e.in test-e.out \
test-f.in test-f.out \
test-g.in test-g.out \
test-h.in test-h.out \
test-i.in test-i.out \
test-j.in test-j.out \
test-k.in test-k.out \
test-l.in test-l.out

View File

@ -1,7 +0,0 @@
Fri May 31 13:20:17 2002
1) Sanitize values from input boxes.
2) Add canvas colors to cavas widget resources or to command-line options.
3) Add ability to edit option line(s) and wall.

View File

@ -1,234 +0,0 @@
/*
* Copyright 2002 Red Hat Inc., Durham, North Carolina.
*
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation on the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* Authors:
* Rickard E. (Rik) Faith <faith@redhat.com>
*/
/** \file
* This file provides some compatibility support for reading VDL files
* that are used by xmovie
* (http://www.llnl.gov/icc/sdd/img/xmovie/xmovie.shtml).
*
* This file is not used by the DMX server.
*/
#ifdef HAVE_DMX_CONFIG_H
#include <dmx-config.h>
#endif
#include "os.h"
#include "dmxconfig.h"
#include "dmxparse.h"
#include "dmxcompat.h"
#include "parser.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
static int
dmxVDLReadLine(FILE * str, char *buf, int len)
{
if (fgets(buf, len, str))
return strlen(buf);
return 0;
}
static int
dmxVDLCount(const char *buf)
{
return strtol(buf, NULL, 10);
}
static void
dmxVDLVirtualEntry(const char *buf, char *name, int *len, int *x, int *y)
{
char *end;
const char *s;
char *d;
int start;
*x = strtol(buf, &end, 10);
*y = strtol(end, &end, 10);
for (s = end, d = name, start = 1; *s && *s != '['; ++s) {
if (start && isspace(*s))
continue;
*d++ = *s;
start = 0;
}
*d = '\0';
while (d > name && isspace(d[-1]))
*--d = '\0'; /* remove trailing space */
*len = strlen(name);
}
static void
dmxVDLDisplayEntry(const char *buf,
char *name, int *len,
int *x, int *y, int *xoff, int *yoff, int *xorig, int *yorig)
{
const char *pt;
char *end;
pt = strchr(buf, ' ');
strlcpy(name, buf, 1 + pt - buf);
*len = strlen(name);
*x = strtol(pt, &end, 10);
*y = strtol(end, &end, 10);
*xorig = strtol(end, &end, 10);
*yorig = strtol(end, &end, 10);
*xoff = strtol(end, &end, 10);
*yoff = strtol(end, NULL, 10);
}
/** Read from the VDL format \a filename and return a newly allocated \a
* DMXConfigEntryPtr */
DMXConfigEntryPtr
dmxVDLRead(const char *filename)
{
FILE *str;
char buf[2048]; /* RATS: Use ok */
char *pt;
int lineno = 0;
DMXConfigEntryPtr entry = NULL;
DMXConfigVirtualPtr virtual = NULL;
DMXConfigSubPtr sub = NULL;
DMXConfigDisplayPtr display = NULL;
DMXConfigFullDimPtr fdim = NULL;
int dcount = 0;
int icount = 0;
int x, y, xoff, yoff, xorig, yorig;
char name[2048]; /* RATS: Use ok */
const char *tmp;
int len;
enum {
simulateFlag,
virtualCount,
virtualEntry,
displayCount,
displayEntry,
ignoreCount,
ignoreEntry
} state = simulateFlag;
if (!filename)
str = stdin;
else
str = fopen(filename, "r");
if (!str)
return NULL;
while (dmxVDLReadLine(str, buf, sizeof(buf))) {
DMXConfigCommentPtr comment = NULL;
++lineno;
for (pt = buf; *pt; pt++)
if (*pt == '\r' || *pt == '\n') {
*pt = '\0';
break;
}
if (buf[0] == '#') {
tmp = dmxConfigCopyString(buf + 1, strlen(buf + 1));
comment = dmxConfigCreateComment(T_COMMENT, lineno, tmp);
entry = dmxConfigAddEntry(entry, dmxConfigComment, comment, NULL);
continue;
}
switch (state) {
case simulateFlag:
state = virtualCount;
break;
case virtualCount:
state = virtualEntry;
break;
case virtualEntry:
len = sizeof(name);
dmxVDLVirtualEntry(buf, name, &len, &x, &y);
tmp = dmxConfigCopyString(name, len);
virtual = dmxConfigCreateVirtual(NULL,
dmxConfigCreateString(T_STRING,
lineno,
NULL,
tmp),
dmxConfigCreatePair(T_DIMENSION,
lineno,
NULL,
x, y, 0, 0),
NULL, NULL, NULL);
state = displayCount;
break;
case displayCount:
dcount = dmxVDLCount(buf);
state = displayEntry;
break;
case displayEntry:
dmxVDLDisplayEntry(buf, name, &len, &x, &y, &xoff, &yoff,
&xorig, &yorig);
tmp = dmxConfigCopyString(name, len);
fdim =
dmxConfigCreateFullDim(dmxConfigCreatePartDim
(dmxConfigCreatePair
(T_DIMENSION, lineno, NULL, x, y, 0, 0),
dmxConfigCreatePair(T_OFFSET, lineno,
NULL, xoff, yoff,
xoff, yoff)), NULL);
display =
dmxConfigCreateDisplay(NULL,
dmxConfigCreateString(T_STRING, lineno,
NULL, tmp), fdim,
dmxConfigCreatePair(T_ORIGIN, lineno,
NULL, xorig, yorig,
0, 0), NULL);
sub = dmxConfigAddSub(sub, dmxConfigSubDisplay(display));
if (!--dcount) {
state = ignoreCount;
virtual->subentry = sub;
entry = dmxConfigAddEntry(entry,
dmxConfigVirtual, NULL, virtual);
virtual = NULL;
sub = NULL;
}
break;
case ignoreCount:
icount = dmxVDLCount(buf);
state = ignoreEntry;
break;
case ignoreEntry:
if (!--icount)
state = virtualEntry;
break;
}
}
if (str != stdin)
fclose(str);
return entry;
}

View File

@ -1,44 +0,0 @@
/*
* Copyright 2002 Red Hat Inc., Durham, North Carolina.
*
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation on the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* Authors:
* Rickard E. (Rik) Faith <faith@redhat.com>
*
*/
/** \file
* Interface to VDL compatibility support. \see dmxcompat.c
*
* This file is not used by the DMX server.
*/
#ifndef _DMXCOMPAT_H_
#define _DMXCOMPAT_H_
extern DMXConfigEntryPtr dmxVDLRead(const char *filename);
#endif

View File

@ -1,561 +0,0 @@
/*
* Copyright 2002-2003 Red Hat Inc., Durham, North Carolina.
*
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation on the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* Authors:
* Rickard E. (Rik) Faith <faith@redhat.com>
*
*/
/** \file
* Provides interface for reading DMX configuration files and for
* combining that information with command-line configuration parameters. */
#ifdef HAVE_DMX_CONFIG_H
#include <dmx-config.h>
#endif
#include "dmx.h"
#include "dmxinput.h"
#include "dmxconfig.h"
#include "dmxparse.h"
#include "dmxlog.h"
#include "dmxcb.h"
#include "dmxstat.h"
#include "parser.h"
extern int yydebug;
extern FILE *yyin;
static char *dmxXkbRules;
static char *dmxXkbModel;
static char *dmxXkbLayout;
static char *dmxXkbVariant;
static char *dmxXkbOptions;
/** Stores lists of configuration information. */
typedef struct DMXConfigListStruct {
const char *name;
struct DMXConfigListStruct *next;
} DMXConfigList, *DMXConfigListPtr;
/** This structure stores the parsed configuration information. */
typedef struct DMXConfigCmdStruct {
const char *filename;
const char *config;
DMXConfigList *displays;
DMXConfigList *inputs;
DMXConfigList *xinputs;
} DMXConfigCmd, *DMXConfigCmdPtr;
extern DMXConfigEntryPtr dmxConfigEntry;
static DMXConfigCmd dmxConfigCmd;
static int dmxDisplaysFromCommandLine;
/** Make a note that \a display is the name of an X11 display that
* should be initialized as a backend (output) display. Called from
* #ddxProcessArgument. */
void
dmxConfigStoreDisplay(const char *display)
{
DMXConfigListPtr entry = malloc(sizeof(*entry));
entry->name = strdup(display);
entry->next = NULL;
if (!dmxConfigCmd.displays)
dmxConfigCmd.displays = entry;
else {
DMXConfigList *pt;
for (pt = dmxConfigCmd.displays; pt->next; pt = pt->next);
if (!pt)
dmxLog(dmxFatal, "dmxConfigStoreDisplay: end of list non-NULL\n");
pt->next = entry;
}
++dmxDisplaysFromCommandLine;
}
/** Make a note that \a input is the name of an X11 display that should
* be used for input (either a backend or a console input device). */
void
dmxConfigStoreInput(const char *input)
{
DMXConfigListPtr entry = malloc(sizeof(*entry));
entry->name = strdup(input);
entry->next = NULL;
if (!dmxConfigCmd.inputs)
dmxConfigCmd.inputs = entry;
else {
DMXConfigList *pt;
for (pt = dmxConfigCmd.inputs; pt->next; pt = pt->next);
if (!pt)
dmxLog(dmxFatal, "dmxConfigStoreInput: end of list non-NULL\n");
pt->next = entry;
}
}
/** Make a note that \a input is the name of an X11 display that should
* be used for input from XInput extension devices. */
void
dmxConfigStoreXInput(const char *input)
{
DMXConfigListPtr entry = malloc(sizeof(*entry));
entry->name = strdup(input);
entry->next = NULL;
if (!dmxConfigCmd.xinputs)
dmxConfigCmd.xinputs = entry;
else {
DMXConfigList *pt;
for (pt = dmxConfigCmd.xinputs; pt->next; pt = pt->next);
if (!pt)
dmxLog(dmxFatal, "dmxConfigStoreXInput: end of list non-NULL\n");
pt->next = entry;
}
}
/** Make a note that \a file is the configuration file. */
void
dmxConfigStoreFile(const char *file)
{
if (dmxConfigCmd.filename)
dmxLog(dmxFatal, "Only one -configfile allowed\n");
dmxConfigCmd.filename = strdup(file);
}
/** Make a note that \a config should be used as the configuration for
* current instantiation of the DMX server. */
void
dmxConfigStoreConfig(const char *config)
{
if (dmxConfigCmd.config)
dmxLog(dmxFatal, "Only one -config allowed\n");
dmxConfigCmd.config = strdup(config);
}
static int
dmxConfigReadFile(const char *filename, int debug)
{
FILE *str;
if (!(str = fopen(filename, "r")))
return -1;
dmxLog(dmxInfo, "Reading configuration file \"%s\"\n", filename);
yyin = str;
yydebug = debug;
yyparse();
fclose(str);
return 0;
}
static const char *
dmxConfigMatch(const char *target, DMXConfigEntryPtr entry)
{
DMXConfigVirtualPtr v = entry->virtual;
const char *name = NULL;
if (v && v->name)
name = v->name;
if (v && !dmxConfigCmd.config)
return v->name ? v->name : "<noname>";
if (!name)
return NULL;
if (!strcmp(name, target))
return name;
return NULL;
}
static DMXScreenInfo *
dmxConfigAddDisplay(const char *name,
int scrnWidth, int scrnHeight,
int scrnX, int scrnY,
int scrnXSign, int scrnYSign,
int rootWidth, int rootHeight,
int rootX, int rootY, int rootXSign, int rootYSign)
{
DMXScreenInfo *dmxScreen;
if (!(dmxScreens = reallocarray(dmxScreens, dmxNumScreens + 1,
sizeof(*dmxScreens))))
dmxLog(dmxFatal,
"dmxConfigAddDisplay: realloc failed for screen %d (%s)\n",
dmxNumScreens, name);
dmxScreen = &dmxScreens[dmxNumScreens];
memset(dmxScreen, 0, sizeof(*dmxScreen));
dmxScreen->name = name;
dmxScreen->index = dmxNumScreens;
dmxScreen->scrnWidth = scrnWidth;
dmxScreen->scrnHeight = scrnHeight;
dmxScreen->scrnX = scrnX;
dmxScreen->scrnY = scrnY;
dmxScreen->scrnXSign = scrnXSign;
dmxScreen->scrnYSign = scrnYSign;
dmxScreen->rootWidth = rootWidth;
dmxScreen->rootHeight = rootHeight;
dmxScreen->rootX = rootX;
dmxScreen->rootY = rootY;
dmxScreen->stat = dmxStatAlloc();
++dmxNumScreens;
return dmxScreen;
}
DMXInputInfo *
dmxConfigAddInput(const char *name, int core)
{
DMXInputInfo *dmxInput;
if (!(dmxInputs = reallocarray(dmxInputs, dmxNumInputs + 1,
sizeof(*dmxInputs))))
dmxLog(dmxFatal,
"dmxConfigAddInput: realloc failed for input %d (%s)\n",
dmxNumInputs, name);
dmxInput = &dmxInputs[dmxNumInputs];
memset(dmxInput, 0, sizeof(*dmxInput));
dmxInput->name = name;
dmxInput->inputIdx = dmxNumInputs;
dmxInput->scrnIdx = -1;
dmxInput->core = core;
++dmxNumInputs;
return dmxInput;
}
static void
dmxConfigCopyFromDisplay(DMXConfigDisplayPtr d)
{
DMXScreenInfo *dmxScreen;
dmxScreen = dmxConfigAddDisplay(d->name,
d->scrnWidth, d->scrnHeight,
d->scrnX, d->scrnY,
d->scrnXSign, d->scrnYSign,
d->rootWidth, d->rootHeight,
d->rootX, d->rootY,
d->rootXSign, d->rootXSign);
dmxScreen->where = PosAbsolute;
dmxScreen->whereX = d->rootXOrigin;
dmxScreen->whereY = d->rootYOrigin;
}
static void
dmxConfigCopyFromWall(DMXConfigWallPtr w)
{
DMXConfigStringPtr pt;
DMXScreenInfo *dmxScreen;
int edge = dmxNumScreens;
int last = dmxNumScreens;
if (!w->xwall && !w->ywall) { /* Try to make it square */
int count;
for (pt = w->nameList, count = 0; pt; pt = pt->next)
++count;
w->xwall = sqrt(count) + .5;
}
for (pt = w->nameList; pt; pt = pt->next) {
dmxScreen = dmxConfigAddDisplay(pt->string, w->width, w->height,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
if (pt == w->nameList) { /* Upper left */
dmxScreen->where = PosAbsolute;
dmxScreen->whereX = 0;
dmxScreen->whereY = 0;
}
else if (w->xwall) { /* Tile left to right, then top to bottom */
if (!((dmxNumScreens - 1) % w->xwall)) {
dmxScreen->where = PosBelow;
dmxScreen->whereRefScreen = edge;
edge = dmxNumScreens - 1;
}
else {
dmxScreen->where = PosRightOf;
dmxScreen->whereRefScreen = last;
}
}
else { /* Tile top to bottom, then left to right */
if (!((dmxNumScreens - 1) % w->ywall)) {
dmxScreen->where = PosRightOf;
dmxScreen->whereRefScreen = edge;
edge = dmxNumScreens - 1;
}
else {
dmxScreen->where = PosBelow;
dmxScreen->whereRefScreen = last;
}
}
last = dmxNumScreens - 1;
if (dmxScreen->where == PosAbsolute)
dmxLog(dmxInfo, "Added %s at %d %d\n",
pt->string, dmxScreen->whereX, dmxScreen->whereY);
else
dmxLog(dmxInfo, "Added %s %s %s\n",
pt->string,
dmxScreen->where == PosBelow ? "below" : "right of",
dmxScreens[dmxScreen->whereRefScreen].name);
}
}
static void
dmxConfigCopyFromOption(DMXConfigOptionPtr o)
{
DMXConfigStringPtr pt;
int argc = 0;
char **argv = NULL;
if (serverGeneration != 1)
return; /* FIXME: only do once, for now */
if (!o || !o->string)
return;
for (pt = o->option; pt; pt = pt->next) {
if (pt->string) {
++argc;
argv = reallocarray(argv, argc + 1, sizeof(*argv));
argv[argc] = (char *) pt->string;
}
}
argv[0] = NULL;
ProcessCommandLine(argc + 1, argv);
free(argv);
}
static void
dmxConfigCopyFromParam(DMXConfigParamPtr p)
{
const char **argv;
int argc;
if ((argv = dmxConfigLookupParam(p, "xkbrules", &argc)) && argc == 2) {
dmxConfigSetXkbRules(argv[1]);
}
else if ((argv = dmxConfigLookupParam(p, "xkbmodel", &argc))
&& argc == 2) {
dmxConfigSetXkbModel(argv[1]);
}
else if ((argv = dmxConfigLookupParam(p, "xkblayout", &argc))
&& argc == 2) {
dmxConfigSetXkbLayout(argv[1]);
}
else if ((argv = dmxConfigLookupParam(p, "xkbvariant", &argc))
&& argc == 2) {
dmxConfigSetXkbVariant(argv[1]);
}
else if ((argv = dmxConfigLookupParam(p, "xkboptions", &argc))
&& argc == 2) {
dmxConfigSetXkbOptions(argv[1]);
}
}
static void
dmxConfigCopyData(DMXConfigVirtualPtr v)
{
DMXConfigSubPtr sub;
if (v->dim)
dmxSetWidthHeight(v->dim->x, v->dim->y);
else
dmxSetWidthHeight(0, 0);
for (sub = v->subentry; sub; sub = sub->next) {
switch (sub->type) {
case dmxConfigDisplay:
dmxConfigCopyFromDisplay(sub->display);
break;
case dmxConfigWall:
dmxConfigCopyFromWall(sub->wall);
break;
case dmxConfigOption:
dmxConfigCopyFromOption(sub->option);
break;
case dmxConfigParam:
dmxConfigCopyFromParam(sub->param);
break;
default:
dmxLog(dmxFatal,
"dmxConfigCopyData: not a display, wall, or value\n");
}
}
}
static void
dmxConfigFromCommandLine(void)
{
DMXConfigListPtr pt;
dmxLog(dmxInfo, "Using configuration from command line\n");
for (pt = dmxConfigCmd.displays; pt; pt = pt->next) {
DMXScreenInfo *dmxScreen = dmxConfigAddDisplay(pt->name,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0);
if (dmxNumScreens == 1) {
dmxScreen->where = PosAbsolute;
dmxScreen->whereX = 0;
dmxScreen->whereY = 0;
dmxLog(dmxInfo, "Added %s at %d %d\n",
dmxScreen->name, dmxScreen->whereX, dmxScreen->whereY);
}
else {
dmxScreen->where = PosRightOf;
dmxScreen->whereRefScreen = dmxNumScreens - 2;
if (dmxScreen->whereRefScreen < 0)
dmxScreen->whereRefScreen = 0;
dmxLog(dmxInfo, "Added %s %s %s\n",
dmxScreen->name,
dmxScreen->where == PosBelow ? "below" : "right of",
dmxScreens[dmxScreen->whereRefScreen].name);
}
}
}
static void
dmxConfigFromConfigFile(void)
{
DMXConfigEntryPtr pt;
const char *name;
for (pt = dmxConfigEntry; pt; pt = pt->next) {
/* FIXME -- if an input is specified, use it */
if (pt->type != dmxConfigVirtual)
continue;
if ((name = dmxConfigMatch(dmxConfigCmd.config, pt))) {
dmxLog(dmxInfo, "Using configuration \"%s\"\n", name);
dmxConfigCopyData(pt->virtual);
return;
}
}
dmxLog(dmxFatal, "Could not find configuration \"%s\" in \"%s\"\n",
dmxConfigCmd.config, dmxConfigCmd.filename);
}
static void
dmxConfigConfigInputs(void)
{
DMXConfigListPtr pt;
if (dmxNumInputs)
return;
if (dmxConfigCmd.inputs) { /* Use command line */
for (pt = dmxConfigCmd.inputs; pt; pt = pt->next)
dmxConfigAddInput(pt->name, TRUE);
}
else if (dmxNumScreens) { /* Use first display */
dmxConfigAddInput(dmxScreens[0].name, TRUE);
}
else { /* Use dummy */
dmxConfigAddInput("dummy", TRUE);
}
if (dmxConfigCmd.xinputs) { /* Non-core devices from command line */
for (pt = dmxConfigCmd.xinputs; pt; pt = pt->next)
dmxConfigAddInput(pt->name, FALSE);
}
}
/** Set up the appropriate global variables so that the DMX server will
* be initialized using the configuration specified in the config file
* and on the command line. */
void
dmxConfigConfigure(void)
{
if (dmxConfigEntry) {
dmxConfigFreeEntry(dmxConfigEntry);
dmxConfigEntry = NULL;
}
if (dmxConfigCmd.filename) {
if (dmxConfigCmd.displays)
dmxLog(dmxWarning,
"Using configuration file \"%s\" instead of command line\n",
dmxConfigCmd.filename);
dmxConfigReadFile(dmxConfigCmd.filename, 0);
dmxConfigFromConfigFile();
}
else {
if (dmxConfigCmd.config)
dmxLog(dmxWarning,
"Configuration name (%s) without configuration file\n",
dmxConfigCmd.config);
dmxConfigFromCommandLine();
}
dmxConfigConfigInputs();
}
/** This function determines the number of displays we WILL have and
* sets MAXSCREENS to that value. This is difficult since the number
* depends on the command line (which is easy to count) or on the config
* file, which has to be parsed. */
void
dmxConfigSetMaxScreens(void)
{
static int processing = 0;
if (processing)
return; /* Prevent reentry via ProcessCommandLine */
processing = 1;
if (dmxConfigCmd.filename) {
if (!dmxNumScreens)
dmxConfigConfigure();
#ifndef MAXSCREENS
SetMaxScreens(dmxNumScreens);
#endif
}
else
#ifndef MAXSCREENS
SetMaxScreens(dmxDisplaysFromCommandLine);
#endif
processing = 0;
}
/** This macro is used to generate the following access methods:
* - dmxConfig{Set,Get}rules
* - dmxConfig{Set,Get}model
* - dmxConfig{Set,Get}layout
* - dmxConfig{Set,Get}variant
* - dmxConfig{Set,Get}options
* These methods are used to read and write information about the keyboard. */
#define GEN(param,glob,def) \
void dmxConfigSet##glob(const char *param) { \
if (dmx##glob) free((void *)dmx##glob); \
dmx##glob = strdup(param); \
} \
char *dmxConfigGet##glob(void) { \
return (char *)(dmx##glob ? dmx##glob : def); \
}
GEN(rules, XkbRules, XKB_DFLT_RULES)
GEN(model, XkbModel, XKB_DFLT_MODEL)
GEN(layout, XkbLayout, XKB_DFLT_LAYOUT)
GEN(variant, XkbVariant, XKB_DFLT_VARIANT)
GEN(options, XkbOptions, XKB_DFLT_OPTIONS)

View File

@ -1,61 +0,0 @@
/*
* Copyright 2002 Red Hat Inc., Durham, North Carolina.
*
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation on the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* Authors:
* Rickard E. (Rik) Faith <faith@redhat.com>
*
*/
/** \file
* Interface for DMX configuration file support. \see dmxconfig.c */
#ifndef _DMXCONFIG_H_
#define _DMXCONFIG_H_
#include <xkb-config.h>
extern void dmxConfigStoreDisplay(const char *display);
extern void dmxConfigStoreInput(const char *input); /* Core devices */
extern void dmxConfigStoreXInput(const char *input); /* Non-core devices */
extern void dmxConfigStoreFile(const char *file);
extern void dmxConfigStoreConfig(const char *config);
extern void dmxConfigConfigure(void);
extern void dmxConfigSetMaxScreens(void);
extern void dmxConfigSetXkbRules(const char *rules);
extern void dmxConfigSetXkbModel(const char *model);
extern void dmxConfigSetXkbLayout(const char *layout);
extern void dmxConfigSetXkbVariant(const char *variant);
extern void dmxConfigSetXkbOptions(const char *options);
extern char *dmxConfigGetXkbRules(void);
extern char *dmxConfigGetXkbModel(void);
extern char *dmxConfigGetXkbLayout(void);
extern char *dmxConfigGetXkbVariant(void);
extern char *dmxConfigGetXkbOptions(void);
#endif

View File

@ -1,688 +0,0 @@
/*
* Copyright 2002 Red Hat Inc., Durham, North Carolina.
*
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation on the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* Authors:
* Rickard E. (Rik) Faith <faith@redhat.com>
*
*/
/** \file
*
* This file provides support routines and helper functions to be used
* by the DMX configuration file parser.
*
* Because the DMX configuration file parsing should be capable of being
* used in a stand-alone fashion (i.e., independent from the DMX server
* source tree), no dependencies on other DMX routines are made. */
#ifdef HAVE_DMX_CONFIG_H
#include <dmx-config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "dmxparse.h"
/** A general error logging routine that does not depend on the dmxLog
* functions. */
void
dmxConfigLog(const char *format, ...)
{
va_list args;
va_start(args, format);
vprintf(format, args); /* RATS: All calls to dmxConfigLog from
* dmxparse.c and dmxprint.c use a
* trusted format. */
va_end(args);
}
void *
dmxConfigAlloc(unsigned long bytes)
{
void *area = calloc(1, bytes);
if (!area) {
dmxConfigLog("dmxConfigAlloc: out of memory\n");
return NULL;
}
return area;
}
void *
dmxConfigRealloc(void *orig, unsigned long orig_bytes, unsigned long bytes)
{
unsigned char *area = realloc(orig, bytes);
if (!area) {
dmxConfigLog("dmxConfigRealloc: out of memory\n");
return NULL;
}
memset(area + orig_bytes, 0, bytes - orig_bytes);
return area;
}
const char *
dmxConfigCopyString(const char *string, int length)
{
char *copy;
if (!length)
length = strlen(string);
copy = dmxConfigAlloc(length + 1);
if (length)
strncpy(copy, string, length);
copy[length] = '\0';
return copy;
}
void
dmxConfigFree(void *area)
{
free(area);
}
DMXConfigTokenPtr
dmxConfigCreateToken(int token, int line, const char *comment)
{
DMXConfigTokenPtr pToken = dmxConfigAlloc(sizeof(*pToken));
pToken->token = token;
pToken->line = line;
pToken->comment = comment;
return pToken;
}
void
dmxConfigFreeToken(DMXConfigTokenPtr p)
{
if (!p)
return;
dmxConfigFree((void *) p->comment);
dmxConfigFree(p);
}
DMXConfigStringPtr
dmxConfigCreateString(int token, int line,
const char *comment, const char *string)
{
DMXConfigStringPtr pString = dmxConfigAlloc(sizeof(*pString));
pString->token = token;
pString->line = line;
pString->comment = comment;
pString->string = string;
return pString;
}
void
dmxConfigFreeString(DMXConfigStringPtr p)
{
DMXConfigStringPtr next;
if (!p)
return;
do {
next = p->next;
dmxConfigFree((void *) p->comment);
dmxConfigFree((void *) p->string);
dmxConfigFree(p);
} while ((p = next));
}
DMXConfigNumberPtr
dmxConfigCreateNumber(int token, int line, const char *comment, int number)
{
DMXConfigNumberPtr pNumber = dmxConfigAlloc(sizeof(*pNumber));
pNumber->token = token;
pNumber->line = line;
pNumber->comment = comment;
pNumber->number = number;
return pNumber;
}
void
dmxConfigFreeNumber(DMXConfigNumberPtr p)
{
if (!p)
return;
dmxConfigFree((void *) p->comment);
dmxConfigFree(p);
}
DMXConfigPairPtr
dmxConfigCreatePair(int token, int line,
const char *comment, int x, int y, int xsign, int ysign)
{
DMXConfigPairPtr pPair = dmxConfigAlloc(sizeof(*pPair));
pPair->token = token;
pPair->line = line;
pPair->comment = comment;
pPair->x = x;
pPair->y = y;
pPair->xsign = (xsign < 0) ? -1 : 1;
pPair->ysign = (ysign < 0) ? -1 : 1;
return pPair;
}
void
dmxConfigFreePair(DMXConfigPairPtr p)
{
if (!p)
return;
dmxConfigFree((void *) p->comment);
dmxConfigFree(p);
}
DMXConfigCommentPtr
dmxConfigCreateComment(int token, int line, const char *comment)
{
DMXConfigCommentPtr pComment = dmxConfigAlloc(sizeof(*pComment));
pComment->token = token;
pComment->line = line;
pComment->comment = comment;
return pComment;
}
void
dmxConfigFreeComment(DMXConfigCommentPtr p)
{
if (!p)
return;
dmxConfigFree((void *) p->comment);
dmxConfigFree(p);
}
DMXConfigPartDimPtr
dmxConfigCreatePartDim(DMXConfigPairPtr pDim, DMXConfigPairPtr pOffset)
{
DMXConfigPartDimPtr pPart = dmxConfigAlloc(sizeof(*pPart));
pPart->dim = pDim;
pPart->offset = pOffset;
return pPart;
}
void
dmxConfigFreePartDim(DMXConfigPartDimPtr p)
{
if (!p)
return;
dmxConfigFreePair(p->dim);
dmxConfigFreePair(p->offset);
dmxConfigFree(p);
}
DMXConfigFullDimPtr
dmxConfigCreateFullDim(DMXConfigPartDimPtr pScrn, DMXConfigPartDimPtr pRoot)
{
DMXConfigFullDimPtr pFull = dmxConfigAlloc(sizeof(*pFull));
pFull->scrn = pScrn;
pFull->root = pRoot;
return pFull;
}
void
dmxConfigFreeFullDim(DMXConfigFullDimPtr p)
{
if (!p)
return;
dmxConfigFreePartDim(p->scrn);
dmxConfigFreePartDim(p->root);
dmxConfigFree(p);
}
DMXConfigDisplayPtr
dmxConfigCreateDisplay(DMXConfigTokenPtr pStart,
DMXConfigStringPtr pName,
DMXConfigFullDimPtr pDim,
DMXConfigPairPtr pOrigin, DMXConfigTokenPtr pEnd)
{
DMXConfigDisplayPtr pDisplay = dmxConfigAlloc(sizeof(*pDisplay));
pDisplay->start = pStart;
pDisplay->dname = pName;
pDisplay->dim = pDim;
pDisplay->origin = pOrigin;
pDisplay->end = pEnd;
pDisplay->name = pName ? pName->string : NULL;
pDisplay->rootXOrigin = pOrigin ? pOrigin->x : 0;
pDisplay->rootYOrigin = pOrigin ? pOrigin->y : 0;
if (pDim && pDim->scrn && pDim->scrn->dim) {
pDisplay->scrnWidth = pDim->scrn->dim->x;
pDisplay->scrnHeight = pDim->scrn->dim->y;
}
if (pDim && pDim->scrn && pDim->scrn->offset) {
pDisplay->scrnX = pDim->scrn->offset->x;
pDisplay->scrnY = pDim->scrn->offset->y;
pDisplay->scrnXSign = pDim->scrn->offset->xsign;
pDisplay->scrnYSign = pDim->scrn->offset->ysign;
}
if (pDim && pDim->root) {
if (pDim->root->dim) {
pDisplay->rootWidth = pDim->root->dim->x;
pDisplay->rootHeight = pDim->root->dim->y;
}
if (pDim->root->offset) {
pDisplay->rootX = pDim->root->offset->x;
pDisplay->rootY = pDim->root->offset->y;
pDisplay->rootXSign = pDim->root->offset->xsign;
pDisplay->rootYSign = pDim->root->offset->ysign;
}
}
else { /* If no root specification, copy width
* and height from scrn -- leave offset
* as zero, since it is relative to
* scrn. */
pDisplay->rootWidth = pDisplay->scrnWidth;
pDisplay->rootHeight = pDisplay->scrnHeight;
}
return pDisplay;
}
void
dmxConfigFreeDisplay(DMXConfigDisplayPtr p)
{
if (!p)
return;
dmxConfigFreeToken(p->start);
dmxConfigFreeString(p->dname);
dmxConfigFreeFullDim(p->dim);
dmxConfigFreeToken(p->end);
dmxConfigFree(p);
}
DMXConfigWallPtr
dmxConfigCreateWall(DMXConfigTokenPtr pStart,
DMXConfigPairPtr pWallDim,
DMXConfigPairPtr pDisplayDim,
DMXConfigStringPtr pNameList, DMXConfigTokenPtr pEnd)
{
DMXConfigWallPtr pWall = dmxConfigAlloc(sizeof(*pWall));
pWall->start = pStart;
pWall->wallDim = pWallDim;
pWall->displayDim = pDisplayDim;
pWall->nameList = pNameList;
pWall->end = pEnd;
pWall->width = pDisplayDim ? pDisplayDim->x : 0;
pWall->height = pDisplayDim ? pDisplayDim->y : 0;
pWall->xwall = pWallDim ? pWallDim->x : 0;
pWall->ywall = pWallDim ? pWallDim->y : 0;
return pWall;
}
void
dmxConfigFreeWall(DMXConfigWallPtr p)
{
if (!p)
return;
dmxConfigFreeToken(p->start);
dmxConfigFreePair(p->wallDim);
dmxConfigFreePair(p->displayDim);
dmxConfigFreeString(p->nameList);
dmxConfigFreeToken(p->end);
dmxConfigFree(p);
}
DMXConfigOptionPtr
dmxConfigCreateOption(DMXConfigTokenPtr pStart,
DMXConfigStringPtr pOption, DMXConfigTokenPtr pEnd)
{
int length = 0;
int offset = 0;
DMXConfigStringPtr p;
DMXConfigOptionPtr option = dmxConfigAlloc(sizeof(*option));
for (p = pOption; p; p = p->next) {
if (p->string)
length += strlen(p->string) + 1;
}
option->string = dmxConfigAlloc(length + 1);
for (p = pOption; p; p = p->next) {
if (p->string) {
int len = strlen(p->string);
memcpy(option->string + offset, p->string, len);
offset += len;
if (p->next)
option->string[offset++] = ' ';
}
}
option->string[offset] = '\0';
option->start = pStart;
option->option = pOption;
option->end = pEnd;
return option;
}
void
dmxConfigFreeOption(DMXConfigOptionPtr p)
{
if (!p)
return;
free(p->string);
dmxConfigFreeToken(p->start);
dmxConfigFreeString(p->option);
dmxConfigFreeToken(p->end);
dmxConfigFree(p);
}
const char **
dmxConfigLookupParam(DMXConfigParamPtr p, const char *key, int *argc)
{
DMXConfigParamPtr pt;
for (pt = p; pt; pt = pt->next) {
if (pt->argv && !strcasecmp(pt->argv[0], key)) {
*argc = pt->argc;
return pt->argv;
}
}
*argc = 0;
return NULL;
}
DMXConfigParamPtr
dmxConfigCreateParam(DMXConfigTokenPtr pStart,
DMXConfigTokenPtr pOpen,
DMXConfigStringPtr pParam,
DMXConfigTokenPtr pClose, DMXConfigTokenPtr pEnd)
{
DMXConfigParamPtr param = dmxConfigAlloc(sizeof(*param));
DMXConfigStringPtr pt;
param->argc = 0;
param->argv = NULL;
for (pt = pParam; pt; pt = pt->next) {
if (pt->string) {
param->argv = realloc(param->argv,
(param->argc + 2) * sizeof(*param->argv));
param->argv[param->argc] = pt->string;
++param->argc;
}
}
if (param->argv)
param->argv[param->argc] = NULL;
param->start = pStart;
param->open = pOpen;
param->param = pParam;
param->close = pClose;
param->end = pEnd;
return param;
}
void
dmxConfigFreeParam(DMXConfigParamPtr p)
{
DMXConfigParamPtr next;
if (!p)
return;
do {
next = p->next;
dmxConfigFreeToken(p->start);
dmxConfigFreeToken(p->open);
dmxConfigFreeString(p->param);
dmxConfigFreeToken(p->close);
dmxConfigFreeToken(p->end);
dmxConfigFree(p->argv);
dmxConfigFree(p);
} while ((p = next));
}
DMXConfigSubPtr
dmxConfigCreateSub(DMXConfigType type,
DMXConfigCommentPtr comment,
DMXConfigDisplayPtr display,
DMXConfigWallPtr wall,
DMXConfigOptionPtr option, DMXConfigParamPtr param)
{
DMXConfigSubPtr pSub = dmxConfigAlloc(sizeof(*pSub));
pSub->type = type;
switch (type) {
case dmxConfigComment:
pSub->comment = comment;
break;
case dmxConfigDisplay:
pSub->display = display;
break;
case dmxConfigWall:
pSub->wall = wall;
break;
case dmxConfigOption:
pSub->option = option;
break;
case dmxConfigParam:
pSub->param = param;
break;
default:
dmxConfigLog("Type %d not supported in subentry\n", type);
break;
}
return pSub;
}
void
dmxConfigFreeSub(DMXConfigSubPtr sub)
{
DMXConfigSubPtr pt;
for (pt = sub; pt; pt = pt->next) {
switch (pt->type) {
case dmxConfigComment:
dmxConfigFreeComment(pt->comment);
break;
case dmxConfigDisplay:
dmxConfigFreeDisplay(pt->display);
break;
case dmxConfigWall:
dmxConfigFreeWall(pt->wall);
break;
case dmxConfigOption:
dmxConfigFreeOption(pt->option);
break;
case dmxConfigParam:
dmxConfigFreeParam(pt->param);
break;
default:
dmxConfigLog("Type %d not supported in subentry\n", pt->type);
break;
}
}
dmxConfigFree(sub);
}
DMXConfigSubPtr
dmxConfigSubComment(DMXConfigCommentPtr comment)
{
return dmxConfigCreateSub(dmxConfigComment, comment, NULL, NULL, NULL,
NULL);
}
DMXConfigSubPtr
dmxConfigSubDisplay(DMXConfigDisplayPtr display)
{
return dmxConfigCreateSub(dmxConfigDisplay, NULL, display, NULL, NULL,
NULL);
}
DMXConfigSubPtr
dmxConfigSubWall(DMXConfigWallPtr wall)
{
return dmxConfigCreateSub(dmxConfigWall, NULL, NULL, wall, NULL, NULL);
}
DMXConfigSubPtr
dmxConfigSubOption(DMXConfigOptionPtr option)
{
return dmxConfigCreateSub(dmxConfigOption, NULL, NULL, NULL, option, NULL);
}
DMXConfigSubPtr
dmxConfigSubParam(DMXConfigParamPtr param)
{
return dmxConfigCreateSub(dmxConfigParam, NULL, NULL, NULL, NULL, param);
}
extern DMXConfigSubPtr
dmxConfigAddSub(DMXConfigSubPtr head, DMXConfigSubPtr sub)
{
DMXConfigSubPtr pt;
if (!head)
return sub;
for (pt = head; pt->next; pt = pt->next);
pt->next = sub;
return head;
}
DMXConfigVirtualPtr
dmxConfigCreateVirtual(DMXConfigTokenPtr pStart,
DMXConfigStringPtr pName,
DMXConfigPairPtr pDim,
DMXConfigTokenPtr pOpen,
DMXConfigSubPtr pSubentry, DMXConfigTokenPtr pClose)
{
DMXConfigVirtualPtr pVirtual = dmxConfigAlloc(sizeof(*pVirtual));
pVirtual->start = pStart;
pVirtual->vname = pName;
pVirtual->dim = pDim;
pVirtual->open = pOpen;
pVirtual->subentry = pSubentry;
pVirtual->close = pClose;
pVirtual->name = pName ? pName->string : NULL;
pVirtual->width = pDim ? pDim->x : 0;
pVirtual->height = pDim ? pDim->y : 0;
return pVirtual;
}
void
dmxConfigFreeVirtual(DMXConfigVirtualPtr virtual)
{
dmxConfigFreeToken(virtual->start);
dmxConfigFreeString(virtual->vname);
dmxConfigFreePair(virtual->dim);
dmxConfigFreeToken(virtual->open);
dmxConfigFreeSub(virtual->subentry);
dmxConfigFreeToken(virtual->close);
dmxConfigFree(virtual);
}
DMXConfigEntryPtr
dmxConfigCreateEntry(DMXConfigType type,
DMXConfigCommentPtr comment, DMXConfigVirtualPtr virtual)
{
DMXConfigEntryPtr pEntry = dmxConfigAlloc(sizeof(*pEntry));
pEntry->type = type;
switch (type) {
case dmxConfigComment:
pEntry->comment = comment;
break;
case dmxConfigVirtual:
pEntry->virtual = virtual;
break;
default:
dmxConfigLog("Type %d not supported in entry\n", type);
break;
}
return pEntry;
}
void
dmxConfigFreeEntry(DMXConfigEntryPtr entry)
{
DMXConfigEntryPtr pt;
for (pt = entry; pt; pt = pt->next) {
switch (pt->type) {
case dmxConfigComment:
dmxConfigFreeComment(pt->comment);
break;
case dmxConfigVirtual:
dmxConfigFreeVirtual(pt->virtual);
break;
default:
dmxConfigLog("Type %d not supported in entry\n", pt->type);
break;
}
}
dmxConfigFree(entry);
}
DMXConfigEntryPtr
dmxConfigAddEntry(DMXConfigEntryPtr head,
DMXConfigType type,
DMXConfigCommentPtr comment, DMXConfigVirtualPtr virtual)
{
DMXConfigEntryPtr child = dmxConfigCreateEntry(type, comment, virtual);
DMXConfigEntryPtr pt;
if (!head)
return child;
for (pt = head; pt->next; pt = pt->next);
pt->next = child;
return head;
}
DMXConfigEntryPtr
dmxConfigEntryComment(DMXConfigCommentPtr comment)
{
return dmxConfigCreateEntry(dmxConfigComment, comment, NULL);
}
DMXConfigEntryPtr
dmxConfigEntryVirtual(DMXConfigVirtualPtr virtual)
{
return dmxConfigCreateEntry(dmxConfigVirtual, NULL, virtual);
}

View File

@ -1,291 +0,0 @@
/*
* Copyright 2002 Red Hat Inc., Durham, North Carolina.
*
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation on the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* Authors:
* Rickard E. (Rik) Faith <faith@redhat.com>
*
*/
/** \file
* Interface to DMX configuration file parser. \see dmxparse.c */
#ifndef _DMXPARSE_H_
#define _DMXPARSE_H_
#include <stdio.h> /* For FILE */
#include <X11/Xfuncproto.h> /* For _X_ATTRIBUTE_PRINTF */
/** Stores tokens not stored in other structures (e.g., keywords and ;) */
typedef struct _DMXConfigToken {
int token;
int line;
const char *comment;
} DMXConfigToken, *DMXConfigTokenPtr;
/** Stores parsed strings. */
typedef struct _DMXConfigString {
int token;
int line;
const char *comment;
const char *string;
struct _DMXConfigString *next;
} DMXConfigString, *DMXConfigStringPtr;
/** Stores parsed numbers. */
typedef struct _DMXConfigNumber {
int token;
int line;
const char *comment;
int number;
} DMXConfigNumber, *DMXConfigNumberPtr;
/** Stores parsed pairs (e.g., x y) */
typedef struct _DMXConfigPair {
int token;
int line;
const char *comment;
int x;
int y;
int xsign;
int ysign;
} DMXConfigPair, *DMXConfigPairPtr;
/** Stores parsed comments not stored with a token. */
typedef struct _DMXConfigComment {
int token;
int line;
const char *comment;
} DMXConfigComment, *DMXConfigCommentPtr;
typedef enum {
dmxConfigComment,
dmxConfigVirtual,
dmxConfigDisplay,
dmxConfigWall,
dmxConfigOption,
dmxConfigParam
} DMXConfigType;
/** Stores a geometry specification. */
typedef struct _DMXConfigPartDim {
DMXConfigPairPtr dim;
DMXConfigPairPtr offset;
} DMXConfigPartDim, *DMXConfigPartDimPtr;
/** Stores a pair of geometry specifications. */
typedef struct _DMXConfigFullDim {
DMXConfigPartDimPtr scrn;
DMXConfigPartDimPtr root;
} DMXConfigFullDim, *DMXConfigFullDimPtr;
/** Stores parsed display information. */
typedef struct _DMXConfigDisplay {
/* Summary information */
const char *name;
/* Screen Window Geometry */
int scrnWidth, scrnHeight;
int scrnX, scrnY;
int scrnXSign, scrnYSign;
/* Root Window Geometry */
int rootWidth, rootHeight;
int rootX, rootY;
int rootXSign, rootYSign;
/* Origin in global space */
int rootXOrigin, rootYOrigin;
/* Raw configuration information */
DMXConfigTokenPtr start;
DMXConfigStringPtr dname;
DMXConfigFullDimPtr dim;
DMXConfigPairPtr origin;
DMXConfigTokenPtr end;
} DMXConfigDisplay, *DMXConfigDisplayPtr;
/** Stores parsed wall information. */
typedef struct _DMXConfigWall {
/* Summary information */
int width, height; /* dimensions of displays */
int xwall, ywall; /* dimensions of wall, in tiles */
/* Raw configuration information */
DMXConfigTokenPtr start;
DMXConfigPairPtr wallDim;
DMXConfigPairPtr displayDim;
DMXConfigStringPtr nameList;
DMXConfigTokenPtr end;
} DMXConfigWall, *DMXConfigWallPtr;
/** Stores parsed option information. */
typedef struct _DMXConfigOption {
/* Summary information */
char *string;
/* Raw configuration information */
DMXConfigTokenPtr start;
DMXConfigStringPtr option;
DMXConfigTokenPtr end;
} DMXConfigOption, *DMXConfigOptionPtr;
/** Stores parsed param information. */
typedef struct _DMXConfigParam {
int argc;
const char **argv;
DMXConfigTokenPtr start;
DMXConfigTokenPtr open;
DMXConfigStringPtr param;
DMXConfigTokenPtr close;
DMXConfigTokenPtr end; /* Either open/close OR end */
struct _DMXConfigParam *next;
} DMXConfigParam, *DMXConfigParamPtr;
/** Stores options under an entry (subentry). */
typedef struct _DMXConfigSub {
DMXConfigType type;
DMXConfigCommentPtr comment;
DMXConfigDisplayPtr display;
DMXConfigWallPtr wall;
DMXConfigOptionPtr option;
DMXConfigParamPtr param;
struct _DMXConfigSub *next;
} DMXConfigSub, *DMXConfigSubPtr;
/** Stores parsed virtual information. */
typedef struct _DMXConfigVirtual {
/* Summary information */
const char *name;
int width, height;
/* Raw configuration information */
DMXConfigTokenPtr start;
DMXConfigStringPtr vname;
DMXConfigPairPtr dim;
DMXConfigTokenPtr open;
DMXConfigSubPtr subentry;
DMXConfigTokenPtr close;
} DMXConfigVirtual, *DMXConfigVirtualPtr;
/** Heads entry storage. */
typedef struct _DMXConfigEntry {
DMXConfigType type;
DMXConfigCommentPtr comment;
DMXConfigVirtualPtr virtual;
struct _DMXConfigEntry *next;
} DMXConfigEntry, *DMXConfigEntryPtr;
extern DMXConfigEntryPtr dmxConfigEntry;
extern void yyerror(const char *message);
extern void dmxConfigLog(const char *format, ...) _X_ATTRIBUTE_PRINTF(1,0);
extern void *dmxConfigAlloc(unsigned long bytes);
extern void *dmxConfigRealloc(void *orig,
unsigned long orig_bytes, unsigned long bytes);
extern const char *dmxConfigCopyString(const char *string, int length);
extern void dmxConfigFree(void *area);
extern DMXConfigTokenPtr dmxConfigCreateToken(int token, int line,
const char *comment);
extern void dmxConfigFreeToken(DMXConfigTokenPtr p);
extern DMXConfigStringPtr dmxConfigCreateString(int token, int line,
const char *comment,
const char *string);
extern void dmxConfigFreeString(DMXConfigStringPtr p);
extern DMXConfigNumberPtr dmxConfigCreateNumber(int token, int line,
const char *comment,
int number);
extern void dmxConfigFreeNumber(DMXConfigNumberPtr p);
extern DMXConfigPairPtr dmxConfigCreatePair(int token, int line,
const char *comment,
int x, int y, int xsign, int ysign);
extern void dmxConfigFreePair(DMXConfigPairPtr p);
extern DMXConfigCommentPtr dmxConfigCreateComment(int token, int line,
const char *comment);
extern void dmxConfigFreeComment(DMXConfigCommentPtr p);
extern DMXConfigPartDimPtr dmxConfigCreatePartDim(DMXConfigPairPtr pDim,
DMXConfigPairPtr pOffset);
extern void dmxConfigFreePartDim(DMXConfigPartDimPtr p);
extern DMXConfigFullDimPtr dmxConfigCreateFullDim(DMXConfigPartDimPtr pScrn,
DMXConfigPartDimPtr pRoot);
extern void dmxConfigFreeFullDim(DMXConfigFullDimPtr p);
extern DMXConfigDisplayPtr dmxConfigCreateDisplay(DMXConfigTokenPtr pStart,
DMXConfigStringPtr pName,
DMXConfigFullDimPtr pDim,
DMXConfigPairPtr pOrigin,
DMXConfigTokenPtr pEnd);
extern void dmxConfigFreeDisplay(DMXConfigDisplayPtr p);
extern DMXConfigWallPtr dmxConfigCreateWall(DMXConfigTokenPtr pStart,
DMXConfigPairPtr pWallDim,
DMXConfigPairPtr pDisplayDim,
DMXConfigStringPtr pNameList,
DMXConfigTokenPtr pEnd);
extern void dmxConfigFreeWall(DMXConfigWallPtr p);
extern DMXConfigOptionPtr dmxConfigCreateOption(DMXConfigTokenPtr pStart,
DMXConfigStringPtr pOption,
DMXConfigTokenPtr pEnd);
extern void dmxConfigFreeOption(DMXConfigOptionPtr p);
extern DMXConfigParamPtr dmxConfigCreateParam(DMXConfigTokenPtr pStart,
DMXConfigTokenPtr pOpen,
DMXConfigStringPtr pParam,
DMXConfigTokenPtr pClose,
DMXConfigTokenPtr pEnd);
extern void dmxConfigFreeParam(DMXConfigParamPtr p);
extern const char **dmxConfigLookupParam(DMXConfigParamPtr p,
const char *key, int *argc);
extern DMXConfigSubPtr dmxConfigCreateSub(DMXConfigType type,
DMXConfigCommentPtr comment,
DMXConfigDisplayPtr display,
DMXConfigWallPtr wall,
DMXConfigOptionPtr option,
DMXConfigParamPtr param);
extern void dmxConfigFreeSub(DMXConfigSubPtr sub);
extern DMXConfigSubPtr dmxConfigSubComment(DMXConfigCommentPtr comment);
extern DMXConfigSubPtr dmxConfigSubDisplay(DMXConfigDisplayPtr display);
extern DMXConfigSubPtr dmxConfigSubWall(DMXConfigWallPtr wall);
extern DMXConfigSubPtr dmxConfigSubOption(DMXConfigOptionPtr option);
extern DMXConfigSubPtr dmxConfigSubParam(DMXConfigParamPtr param);
extern DMXConfigSubPtr dmxConfigAddSub(DMXConfigSubPtr head,
DMXConfigSubPtr sub);
extern DMXConfigVirtualPtr dmxConfigCreateVirtual(DMXConfigTokenPtr pStart,
DMXConfigStringPtr pName,
DMXConfigPairPtr pDim,
DMXConfigTokenPtr pOpen,
DMXConfigSubPtr pSubentry,
DMXConfigTokenPtr pClose);
extern void dmxConfigFreeVirtual(DMXConfigVirtualPtr virtual);
extern DMXConfigEntryPtr dmxConfigCreateEntry(DMXConfigType type,
DMXConfigCommentPtr comment,
DMXConfigVirtualPtr virtual);
extern void dmxConfigFreeEntry(DMXConfigEntryPtr entry);
extern DMXConfigEntryPtr dmxConfigAddEntry(DMXConfigEntryPtr head,
DMXConfigType type,
DMXConfigCommentPtr comment,
DMXConfigVirtualPtr virtual);
extern DMXConfigEntryPtr dmxConfigEntryComment(DMXConfigCommentPtr comment);
extern DMXConfigEntryPtr dmxConfigEntryVirtual(DMXConfigVirtualPtr virtual);
#endif

View File

@ -1,532 +0,0 @@
/*
* Copyright 2002 Red Hat Inc., Durham, North Carolina.
*
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation on the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* Authors:
* Rickard E. (Rik) Faith <faith@redhat.com>
*
*/
/** \file
*
* This file provides support routines and helper functions to be used
* to pretty-print DMX configurations.
*
* Because the DMX configuration file parsing should be capable of being
* used in a stand-alone fashion (i.e., independent from the DMX server
* source tree), no dependencies on other DMX routines are made. */
#ifdef HAVE_DMX_CONFIG_H
#include <dmx-config.h>
#endif
#include "dmxconfig.h"
#include "dmxparse.h"
#include "dmxprint.h"
#include "parser.h"
#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>
static FILE *str = NULL;
static int indent = 0;
static int pos = 0;
/** Stack of indentation information used for pretty-printing
* configuration information. */
static struct stack {
int base;
int comment;
int step;
struct stack *next;
} *stack, initialStack = {
0, 0, 4, NULL};
static void
dmxConfigIndent(void)
{
int i;
if (indent < 0)
indent = 0;
if (indent > 40)
indent = 40;
for (i = 0; i < indent; i++)
fprintf(str, " ");
}
static void
dmxConfigNewline(void)
{
if (pos)
fprintf(str, "\n");
pos = 0;
}
static void
dmxConfigPushState(int base, int comment, int step)
{
struct stack *new = dmxConfigAlloc(sizeof(*new));
new->base = base;
new->comment = comment;
new->step = step;
new->next = stack;
stack = new;
indent = base;
dmxConfigNewline();
}
static void
dmxConfigPushComment(void)
{
if (stack)
indent = stack->comment;
}
static void
dmxConfigPushStep(void)
{
if (stack)
indent = stack->step;
}
static void
dmxConfigPopState(void)
{
struct stack *old = stack;
if (!stack)
return;
indent = old->base;
stack = old->next;
if (!stack)
dmxConfigLog("Stack underflow\n");
dmxConfigFree(old);
dmxConfigNewline();
}
static void _X_ATTRIBUTE_PRINTF(4, 5)
dmxConfigOutput(int addSpace, int doNewline, const char *comment,
const char *format, ...)
{
va_list args;
if (!pos)
dmxConfigIndent();
else if (addSpace)
fprintf(str, " ");
if (format) {
va_start(args, format);
/* RATS: This hasn't been audited -- it
* could probably result in a buffer
* overflow. */
pos += vfprintf(str, format, args); /* assumes no newlines! */
va_end(args);
}
if (comment) {
if (pos)
fprintf(str, " ");
pos += fprintf(str, "#%s", comment);
dmxConfigNewline();
dmxConfigPushComment();
}
else if (doNewline)
dmxConfigNewline();
}
static void
dmxConfigPrintComment(DMXConfigCommentPtr p)
{
dmxConfigOutput(1, 1, p->comment, NULL);
}
static void
dmxConfigPrintTokenFlag(DMXConfigTokenPtr p, int flag)
{
if (!p)
return;
switch (p->token) {
case T_VIRTUAL:
dmxConfigPushState(0, 4, 4);
dmxConfigOutput(0, 0, p->comment, "virtual");
break;
case T_DISPLAY:
dmxConfigPushState(4, 12, 16);
dmxConfigOutput(0, 0, p->comment, "display");
break;
case T_WALL:
dmxConfigPushState(4, 12, 16);
dmxConfigOutput(0, 0, p->comment, "wall");
break;
case T_OPTION:
dmxConfigPushState(4, 12, 16);
dmxConfigOutput(0, 0, p->comment, "option");
break;
case T_PARAM:
dmxConfigPushState(4, 8, 12);
dmxConfigOutput(0, 0, p->comment, "param");
break;
case ';':
dmxConfigOutput(0, 1, p->comment, ";");
if (flag)
dmxConfigPopState();
break;
case '{':
dmxConfigOutput(1, 1, p->comment, "{");
dmxConfigPushStep();
break;
case '}':
if (flag)
dmxConfigPopState();
dmxConfigOutput(0, 1, p->comment, "}");
break;
case '/':
dmxConfigOutput(1, 0, NULL, "/");
break;
default:
dmxConfigLog("unknown token %d on line %d\n", p->token, p->line);
}
}
static void
dmxConfigPrintToken(DMXConfigTokenPtr p)
{
dmxConfigPrintTokenFlag(p, 1);
}
static void
dmxConfigPrintTokenNopop(DMXConfigTokenPtr p)
{
dmxConfigPrintTokenFlag(p, 0);
}
static int
dmxConfigPrintQuotedString(const char *s)
{
const char *pt;
if (!s || !s[0])
return 1; /* Quote empty string */
for (pt = s; *pt; ++pt)
if (isspace(*pt))
return 1;
return 0;
}
static void
dmxConfigPrintString(DMXConfigStringPtr p, int quote)
{
DMXConfigStringPtr pt;
if (!p)
return;
for (pt = p; pt; pt = pt->next) {
if (quote && dmxConfigPrintQuotedString(pt->string)) {
dmxConfigOutput(1, 0, pt->comment, "\"%s\"",
pt->string ? pt->string : "");
}
else
dmxConfigOutput(1, 0, pt->comment, "%s",
pt->string ? pt->string : "");
}
}
static int
dmxConfigPrintPair(DMXConfigPairPtr p, int addSpace)
{
if (!p)
return 0;
if (p->token == T_OFFSET) {
if (!p->comment && !p->x && !p->y && p->xsign >= 0 && p->ysign >= 0)
return 0;
dmxConfigOutput(addSpace, 0, p->comment, "%c%d%c%d",
p->xsign < 0 ? '-' : '+', p->x,
p->ysign < 0 ? '-' : '+', p->y);
}
else {
if (!p->comment && !p->x && !p->y)
return 0;
dmxConfigOutput(addSpace, 0, p->comment, "%s%dx%d",
(p->token == T_ORIGIN) ? "@" : "", p->x, p->y);
}
return 1;
}
static void
dmxConfigPrintDisplay(DMXConfigDisplayPtr p)
{
DMXConfigToken dummyStart = { T_DISPLAY, 0, NULL };
DMXConfigToken dummyEnd = { ';', 0, NULL };
DMXConfigToken dummySep = { '/', 0, NULL };
DMXConfigString dummyName = { T_STRING, 0, NULL, NULL, NULL };
DMXConfigPair dummySDim = { T_DIMENSION, 0, NULL, 0, 0, 0, 0 };
DMXConfigPair dummySOffset = { T_OFFSET, 0, NULL, 0, 0, 0, 0 };
DMXConfigPair dummyRDim = { T_DIMENSION, 0, NULL, 0, 0, 0, 0 };
DMXConfigPair dummyROffset = { T_OFFSET, 0, NULL, 0, 0, 0, 0 };
DMXConfigPair dummyOrigin = { T_ORIGIN, 0, NULL, 0, 0, 0, 0 };
int output;
if (p->dname)
p->dname->string = p->name;
else
dummyName.string = p->name;
if (p->dim && p->dim->scrn && p->dim->scrn->dim) {
p->dim->scrn->dim->x = p->scrnWidth;
p->dim->scrn->dim->y = p->scrnHeight;
}
else {
dummySDim.x = p->scrnWidth;
dummySDim.y = p->scrnHeight;
}
if (p->dim && p->dim->scrn && p->dim->scrn->offset) {
p->dim->scrn->offset->x = p->scrnX;
p->dim->scrn->offset->y = p->scrnY;
}
else {
dummySOffset.x = p->scrnX;
dummySOffset.y = p->scrnY;
}
if (p->dim && p->dim->root && p->dim->root->dim) {
p->dim->root->dim->x = p->rootWidth;
p->dim->root->dim->y = p->rootHeight;
}
else {
dummyRDim.x = p->rootWidth;
dummyRDim.y = p->rootHeight;
}
if (p->dim && p->dim->root && p->dim->root->offset) {
p->dim->root->offset->x = p->rootX;
p->dim->root->offset->y = p->rootY;
}
else {
dummyROffset.x = p->rootX;
dummyROffset.y = p->rootY;
}
if (p->origin) {
p->origin->x = p->rootXOrigin, p->origin->y = p->rootYOrigin;
p->origin->xsign = p->rootXSign, p->origin->ysign = p->rootYSign;
}
else {
dummyOrigin.x = p->rootXOrigin, dummyOrigin.y = p->rootYOrigin;
dummyOrigin.xsign = p->rootXSign, dummyOrigin.ysign = p->rootYSign;
}
dmxConfigPrintToken(p->start ? p->start : &dummyStart);
dmxConfigPrintString(p->dname ? p->dname : &dummyName, 1);
if (p->dim && p->dim->scrn && p->dim->scrn->dim)
output = dmxConfigPrintPair(p->dim->scrn->dim, 1);
else
output = dmxConfigPrintPair(&dummySDim, 1);
if (p->dim && p->dim->scrn && p->dim->scrn->offset)
dmxConfigPrintPair(p->dim->scrn->offset, !output);
else
dmxConfigPrintPair(&dummySOffset, !output);
if (p->scrnWidth != p->rootWidth
|| p->scrnHeight != p->rootHeight || p->rootX || p->rootY) {
dmxConfigPrintToken(&dummySep);
if (p->dim && p->dim->root && p->dim->root->dim)
output = dmxConfigPrintPair(p->dim->root->dim, 1);
else
output = dmxConfigPrintPair(&dummyRDim, 1);
if (p->dim && p->dim->root && p->dim->root->offset)
dmxConfigPrintPair(p->dim->root->offset, !output);
else
dmxConfigPrintPair(&dummyROffset, !output);
}
dmxConfigPrintPair(p->origin ? p->origin : &dummyOrigin, 1);
dmxConfigPrintToken(p->end ? p->end : &dummyEnd);
}
static void
dmxConfigPrintWall(DMXConfigWallPtr p)
{
dmxConfigPrintToken(p->start);
dmxConfigPrintPair(p->wallDim, 1);
dmxConfigPrintPair(p->displayDim, 1);
dmxConfigPrintString(p->nameList, 1);
dmxConfigPrintToken(p->end);
}
static void
dmxConfigPrintOption(DMXConfigOptionPtr p)
{
DMXConfigToken dummyStart = { T_OPTION, 0, NULL };
DMXConfigString dummyOption = { T_STRING, 0, NULL, NULL, NULL };
DMXConfigToken dummyEnd = { ';', 0, NULL };
dummyOption.string = p->string;
dmxConfigPrintToken(p->start ? p->start : &dummyStart);
dmxConfigPrintString(&dummyOption, 0);
dmxConfigPrintToken(p->end ? p->end : &dummyEnd);
}
static void
dmxConfigPrintParam(DMXConfigParamPtr p)
{
if (!p)
return;
if (p->start) {
if (p->open && p->close) {
dmxConfigPrintToken(p->start);
dmxConfigPrintToken(p->open);
dmxConfigPrintParam(p->next);
dmxConfigPrintToken(p->close);
}
else if (p->end && p->param) {
dmxConfigPrintToken(p->start);
dmxConfigPrintString(p->param, 1);
dmxConfigPrintToken(p->end);
}
else
dmxConfigLog("dmxConfigPrintParam: cannot handle format (a)\n");
}
else if (p->end && p->param) {
dmxConfigPrintString(p->param, 1);
dmxConfigPrintTokenNopop(p->end);
dmxConfigPrintParam(p->next);
}
else
dmxConfigLog("dmxConfigPrintParam: cannot handle format (b)\n");
}
static void
dmxConfigPrintSub(DMXConfigSubPtr p)
{
DMXConfigSubPtr pt;
if (!p)
return;
for (pt = p; pt; pt = pt->next) {
switch (pt->type) {
case dmxConfigComment:
dmxConfigPrintComment(pt->comment);
break;
case dmxConfigDisplay:
dmxConfigPrintDisplay(pt->display);
break;
case dmxConfigWall:
dmxConfigPrintWall(pt->wall);
break;
case dmxConfigOption:
dmxConfigPrintOption(pt->option);
break;
case dmxConfigParam:
dmxConfigPrintParam(pt->param);
break;
default:
dmxConfigLog("dmxConfigPrintSub:"
" cannot handle type %d in subentry\n", pt->type);
}
}
}
static void
dmxConfigPrintVirtual(DMXConfigVirtualPtr p)
{
DMXConfigToken dummyStart = { T_VIRTUAL, 0, NULL };
DMXConfigToken dummyOpen = { '{', 0, NULL };
DMXConfigToken dummyClose = { '}', 0, NULL };
DMXConfigString dummyName = { T_STRING, 0, NULL, NULL, NULL };
DMXConfigPair dummyDim = { T_DIMENSION, 0, NULL, 0, 0 };
if (p->vname)
p->vname->string = p->name;
else
dummyName.string = p->name;
if (p->dim)
p->dim->x = p->width, p->dim->y = p->height;
else
dummyDim.x = p->width, dummyDim.y = p->height;
dmxConfigPrintToken(p->start ? p->start : &dummyStart);
dmxConfigPrintString(p->vname ? p->vname : &dummyName, 1);
dmxConfigPrintPair(p->dim ? p->dim : &dummyDim, 1);
dmxConfigPrintToken(p->open ? p->open : &dummyOpen);
dmxConfigPrintSub(p->subentry);
dmxConfigPrintToken(p->close ? p->close : &dummyClose);
}
/** The configuration information in \a entry will be pretty-printed to
* the \a stream. If \a stream is NULL, then stdout will be used. */
void
dmxConfigPrint(FILE * stream, DMXConfigEntryPtr entry)
{
DMXConfigEntryPtr pt;
if (!stream)
str = stdout;
else
str = stream;
stack = &initialStack;
for (pt = entry; pt; pt = pt->next) {
switch (pt->type) {
case dmxConfigComment:
dmxConfigPrintComment(pt->comment);
break;
case dmxConfigVirtual:
dmxConfigPrintVirtual(pt->virtual);
break;
default:
dmxConfigLog("dmxConfigPrint: cannot handle type %d in entry\n",
pt->type);
}
}
if (pos)
dmxConfigNewline();
}
/** The configuration information in \a p will be pretty-printed to the
* \a stream. If \a stream is NULL, then stdout will be used. */
void
dmxConfigVirtualPrint(FILE * stream, DMXConfigVirtualPtr p)
{
if (!stream)
str = stdout;
else
str = stream;
stack = &initialStack;
dmxConfigPrintVirtual(p);
if (pos)
dmxConfigNewline();
}

View File

@ -1,43 +0,0 @@
/*
* Copyright 2002 Red Hat Inc., Durham, North Carolina.
*
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation on the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* Authors:
* Rickard E. (Rik) Faith <faith@redhat.com>
*
*/
/** \file
* Interface to DMX configuration file pretty-printer. \see dmxprint.c */
#ifndef _DMXPRINT_H_
#define _DMXPRINT_H_
void dmxConfigPrint(FILE * str, DMXConfigEntryPtr entry);
void dmxConfigVirtualPrint(FILE * str, DMXConfigVirtualPtr p);
#endif

View File

@ -1,51 +0,0 @@
/*
* Copyright 2002 Red Hat Inc., Durham, North Carolina.
*
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation on the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* Authors:
* Rickard E. (Rik) Faith <faith@redhat.com>
*
* This is a simple filter for testing.
*/
#include "dmxconfig.h"
#include "dmxparse.h"
#include "dmxprint.h"
#include "dmxcompat.h"
extern int yyparse(void);
extern int yydebug;
extern FILE *yyin;
int
main(int argc, char **argv)
{
yydebug = 0;
yyparse();
dmxConfigPrint(stdout, dmxConfigEntry);
return 0;
}

View File

@ -1,2 +0,0 @@
include $(top_srcdir)/manpages.am
appman_PRE = xdmxconfig.man vdltodmx.man dmxtodmx.man

View File

@ -1,41 +0,0 @@
.\" $XFree86$
.\" Copyright 2002 Red Hat Inc., Durham, North Carolina.
.\" All Rights Reserved.
.\"
.\" Permission is hereby granted, free of charge, to any person obtaining
.\" a copy of this software and associated documentation files (the
.\" "Software"), to deal in the Software without restriction, including
.\" without limitation on the rights to use, copy, modify, merge,
.\" publish, distribute, sublicense, and/or sell copies of the Software,
.\" and to permit persons to whom the Software is furnished to do so,
.\" subject to the following conditions:
.\"
.\" The above copyright notice and this permission notice (including the
.\" next paragraph) shall be included in all copies or substantial
.\" portions of the Software.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
.\" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
.\" NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
.\" BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
.\" ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
.\" CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
.\" SOFTWARE.
.\"
.\" Authors:
.\" Rickard E. (Rik) Faith <faith@redhat.com>
.\"
.TH dmxtodmx 1 @vendorversion@
.SH NAME
dmxtodmx - dmx configuration file parser and printer
.SH SYNOPSIS
.B dmxtodmx
.SH DESCRIPTION
.I dmxtodmx
reads the standard input, parsing a configuration file for the
.I Xdmx
distributed multi-head X server. After a successful parse, the file is
pretty-printed to standard output.
.SH "SEE ALSO"
Xdmx(1), vdltodmx(1), xdmxconfig(1)

View File

@ -1,95 +0,0 @@
.\" $XFree86$
.\" Copyright 2002 Red Hat Inc., Durham, North Carolina.
.\" All Rights Reserved.
.\"
.\" Permission is hereby granted, free of charge, to any person obtaining
.\" a copy of this software and associated documentation files (the
.\" "Software"), to deal in the Software without restriction, including
.\" without limitation on the rights to use, copy, modify, merge,
.\" publish, distribute, sublicense, and/or sell copies of the Software,
.\" and to permit persons to whom the Software is furnished to do so,
.\" subject to the following conditions:
.\"
.\" The above copyright notice and this permission notice (including the
.\" next paragraph) shall be included in all copies or substantial
.\" portions of the Software.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
.\" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
.\" NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
.\" BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
.\" ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
.\" CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
.\" SOFTWARE.
.\"
.\" Authors:
.\" Rickard E. (Rik) Faith <faith@redhat.com>
.\"
.TH vdltodmx 1 @vendorversion@
.SH NAME
vdltodmx - dmx configuration file parser and printer
.SH SYNOPSIS
.B vdltodmx
.I infile
.I outfile
.SH DESCRIPTION
.I vdltodmx
reads the input file, which should be in VDL configuration file format.
After a successful parse, a file in Xdmx configuration file format is
written to the output file.
.P
The VDL file format is used with
.IR xmovie ,
which is available from
http://www.llnl.gov/icc/lc/img/xmovie/xmovie.html
.SH EXAMPLE
Given the following VDL-format file:
.RS
.nf
0
2
#
#
2560 2048 Left two-thirds [restrict=*:2]
2
:2.1 1280 2048 0 0 0 0
:2.2 1280 2048 1280 0 0 0
4
1280 1024 0 0
1280 1024 0 1024
1280 1024 1280 0
1280 1024 1280 1024
#
2560 2048 Right two-thirds [restrict=*:2]
2
:2.2 1280 2048 0 0 0 0
:2.3 1280 2048 1280 0 0 0
4
1280 1024 1280 0
1280 1024 1280 1024
1280 1024 2560 0
1280 1024 2560 1024
.fi
.RE
the following DMX-format file will be produced:
.RS
.nf
#
#
virtual "Left two-thirds" 2560x2048 {
display :2.1 1280x2048;
display :2.2 1280x2048 @1280x0;
}
#
virtual "Right two-thirds" 2560x2048 {
display :2.2 1280x2048;
display :2.3 1280x2048 @1280x0;
}
.fi
.RE
.SH BUGS
If the VDL file is not in the expected format, the program will probably
dump core.
.SH "SEE ALSO"
Xdmx(1), xdmxconfig(1), vdl(3), xmovie(1)

View File

@ -1,63 +0,0 @@
.\" $XFree86$
.\" Copyright 2002 Red Hat Inc., Durham, North Carolina.
.\" All Rights Reserved.
.\"
.\" Permission is hereby granted, free of charge, to any person obtaining
.\" a copy of this software and associated documentation files (the
.\" "Software"), to deal in the Software without restriction, including
.\" without limitation on the rights to use, copy, modify, merge,
.\" publish, distribute, sublicense, and/or sell copies of the Software,
.\" and to permit persons to whom the Software is furnished to do so,
.\" subject to the following conditions:
.\"
.\" The above copyright notice and this permission notice (including the
.\" next paragraph) shall be included in all copies or substantial
.\" portions of the Software.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
.\" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
.\" NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
.\" BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
.\" ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
.\" CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
.\" SOFTWARE.
.\"
.\" Authors:
.\" Rickard E. (Rik) Faith <faith@redhat.com>
.\"
.TH xdmxconfig 1 @vendorversion@
.SH NAME
xdmxconfig - a graphical configuration tool for Xdmx configuration files
.SH SYNOPSIS
.B xdmxconfig
[filename]
.SH DESCRIPTION
.I xdmxconfig
reads, edits, and writes configuration files for the Xdmx server. The
grammar for the configuration file is specified in the Xdmx(1) manual
page.
.PP
To start from scratch, create a "New Global" and specify the name and
overall dimensions for the configuration. Then use "New Display" to
enter more displays.
.PP
If there is more than one configuration, the configuration name button
will bring up a selection menu.
.PP
In the right-hand panel, the left mouse button will move the
highlighted display at "tool resolution"; the middle mouse button will
move the highlighted display by a single pixel (at "wall resolution");
and the right mouse button will bring up a menu allowing the highlighted
display to be edited or deleted. The arrow keys will also move the
highlighted display by a single pixel.
.SH BUGS
Currently, entries with the
.B wall
keyword are not editable, but will be preserved in the new output file.
The tool will quit when requested by the user, even if a configuration
file has not been written out (i.e., without warning). The menu
interaction should be improved (menu entries that don't currently work
should be greyed-out, for example). The Help button does not work.
.SH "SEE ALSO"
Xdmx(1), vdltodmx(1)

View File

@ -1,82 +0,0 @@
flex = find_program('flex')
bison = find_program('bison')
lgen = generator(
flex,
output : '@PLAINNAME@.yy.c',
arguments : ['-o', '@OUTPUT@', '@INPUT@']
)
lfiles = lgen.process('scanner.l')
pgen = generator(
bison,
output : ['@BASENAME@.c', '@BASENAME@.h'],
arguments : ['@INPUT@', '--defines=@OUTPUT1@', '--output=@OUTPUT0@']
)
pfiles = pgen.process('parser.y')
srcs_dmx_config = [
'dmxparse.c',
'dmxprint.c',
'dmxcompat.c',
'dmxconfig.c',
pfiles,
lfiles,
]
dmx_inc = [
inc,
include_directories('../')
]
dmx_c_args = [
'-DHAVE_DMX_CONFIG_H',
'-DDMX_LOG_STANDALONE',
]
dmx_config = static_library('dmx_config',
srcs_dmx_config,
include_directories: dmx_inc,
dependencies: common_dep,
link_with: libxlibc,
c_args: dmx_c_args,
)
executable('xdmxconfig',
[
'xdmxconfig.c',
'../dmxlog.c',
'Canvas.c',
],
include_directories: [
inc,
include_directories('../')
],
dependencies: [
common_dep,
dependency('xaw7'),
dependency('xmu'),
dependency('xt'),
dependency('xpm'),
dependency('x11'),
],
link_with: dmx_config,
c_args: dmx_c_args,
install: true,
)
executable('vdltodmx',
'vdltodmx.c',
include_directories: dmx_inc,
link_with: dmx_config,
c_args: dmx_c_args,
install: true,
)
executable('dmxtodmx',
'dmxtodmx.c',
include_directories: dmx_inc,
link_with: dmx_config,
c_args: dmx_c_args,
install: true,
)

View File

@ -1,227 +0,0 @@
/* $XFree86$ */
/*
* Copyright 2002-2003 Red Hat Inc., Durham, North Carolina.
*
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation on the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* Authors:
* Rickard E. (Rik) Faith <faith@redhat.com>
*
*/
%{
#ifdef HAVE_DMX_CONFIG_H
#include <dmx-config.h>
#endif
#include "dmxparse.h"
#include <string.h>
#include <stdlib.h>
#define YYDEBUG 1
#define YYERROR_VERBOSE
#define YY_USE_PROTOS
extern int yylex(void);
DMXConfigEntryPtr dmxConfigEntry = NULL;
#define APPEND(type, h, t) \
{ \
type pt; \
for (pt = h; pt->next; pt = pt->next); \
pt->next = t; \
}
%}
%union {
DMXConfigTokenPtr token;
DMXConfigStringPtr string;
DMXConfigNumberPtr number;
DMXConfigPairPtr pair;
DMXConfigFullDimPtr fdim;
DMXConfigPartDimPtr pdim;
DMXConfigDisplayPtr display;
DMXConfigWallPtr wall;
DMXConfigOptionPtr option;
DMXConfigParamPtr param;
DMXConfigCommentPtr comment;
DMXConfigSubPtr subentry;
DMXConfigVirtualPtr virtual;
DMXConfigEntryPtr entry;
}
/* Terminals */
%token <token> '{' '}' ';' '/' T_VIRTUAL T_DISPLAY T_WALL T_OPTION T_PARAM
%token <string> T_STRING
%token <pair> T_DIMENSION T_OFFSET T_ORIGIN
%token <comment> T_COMMENT T_LINE_COMMENT
/* Non-termials */
%type <token> Display Wall Terminal Open Close
%type <string> NameList Name
%type <pair> Dimension Offset Origin
%type <pdim> PartialDim
%type <fdim> FullDim
%type <display> DisplayEntry
%type <option> OptionEntry
%type <param> ParamEntry ParamList Param
%type <subentry> SubList Sub
%type <wall> WallEntry
%type <virtual> Virtual
%type <entry> Program EntryList Entry
%%
Program : EntryList { dmxConfigEntry = $1; }
;
EntryList : Entry
| EntryList Entry { APPEND(DMXConfigEntryPtr,$1,$2); $$ = $1; }
;
Entry : Virtual { $$ = dmxConfigEntryVirtual($1); }
| T_LINE_COMMENT { $$ = dmxConfigEntryComment($1); }
;
Virtual : T_VIRTUAL Open SubList Close
{ $$ = dmxConfigCreateVirtual($1, NULL, NULL, $2, $3, $4); }
| T_VIRTUAL Dimension Open SubList Close
{ $$ = dmxConfigCreateVirtual($1, NULL, $2, $3, $4, $5); }
| T_VIRTUAL Name Open SubList Close
{ $$ = dmxConfigCreateVirtual($1, $2, NULL, $3, $4, $5); }
| T_VIRTUAL Name Dimension Open SubList Close
{ $$ = dmxConfigCreateVirtual($1, $2, $3, $4, $5, $6 ); }
;
SubList : Sub
| SubList Sub { APPEND(DMXConfigSubPtr,$1,$2); $$ = $1; }
;
Sub : T_LINE_COMMENT { $$ = dmxConfigSubComment($1); }
| DisplayEntry { $$ = dmxConfigSubDisplay($1); }
| WallEntry { $$ = dmxConfigSubWall($1); }
| OptionEntry { $$ = dmxConfigSubOption($1); }
| ParamEntry { $$ = dmxConfigSubParam($1); }
;
OptionEntry : T_OPTION NameList Terminal
{ $$ = dmxConfigCreateOption($1, $2, $3); }
;
ParamEntry : T_PARAM NameList Terminal
{ $$ = dmxConfigCreateParam($1, NULL, $2, NULL, $3); }
| T_PARAM Open ParamList Close
{ $$ = dmxConfigCreateParam($1, $2, NULL, $4, NULL);
$$->next = $3;
}
;
ParamList : Param
| ParamList Param { APPEND(DMXConfigParamPtr,$1,$2); $$ = $1; }
;
Param : NameList Terminal
{ $$ = dmxConfigCreateParam(NULL, NULL, $1, NULL, $2); }
;
PartialDim : Dimension Offset
{ $$ = dmxConfigCreatePartDim($1, $2); }
| Dimension
{ $$ = dmxConfigCreatePartDim($1, NULL); }
| Offset
{ $$ = dmxConfigCreatePartDim(NULL, $1); }
;
FullDim : PartialDim '/' PartialDim
{ $$ = dmxConfigCreateFullDim($1, $3); }
| '/' PartialDim
{ $$ = dmxConfigCreateFullDim(NULL, $2); }
| PartialDim
{ $$ = dmxConfigCreateFullDim($1, NULL); }
;
DisplayEntry : Display Name FullDim Origin Terminal
{ $$ = dmxConfigCreateDisplay($1, $2, $3, $4, $5); }
| Display FullDim Origin Terminal
{ $$ = dmxConfigCreateDisplay($1, NULL, $2, $3, $4); }
| Display Name Origin Terminal
{ $$ = dmxConfigCreateDisplay($1, $2, NULL, $3, $4); }
| Display Name FullDim Terminal
{ $$ = dmxConfigCreateDisplay($1, $2, $3, NULL, $4); }
| Display FullDim Terminal
{ $$ = dmxConfigCreateDisplay($1, NULL, $2, NULL, $3); }
| Display Name Terminal
{ $$ = dmxConfigCreateDisplay($1, $2, NULL, NULL, $3); }
| Display Terminal
{ $$ = dmxConfigCreateDisplay($1, NULL, NULL, NULL, $2); }
;
WallEntry : Wall Dimension Dimension NameList Terminal
{ $$ = dmxConfigCreateWall($1, $2, $3, $4, $5); }
| Wall Dimension NameList Terminal
{ $$ = dmxConfigCreateWall($1, $2, NULL, $3, $4); }
| Wall NameList Terminal
{ $$ = dmxConfigCreateWall($1, NULL, NULL, $2, $3); }
;
Display : T_DISPLAY
| T_DISPLAY T_COMMENT { $$ = $1; $$->comment = $2->comment; }
;
Name : T_STRING
| T_STRING T_COMMENT { $$ = $1; $$->comment = $2->comment; }
;
Dimension : T_DIMENSION
| T_DIMENSION T_COMMENT { $$ = $1; $$->comment = $2->comment; }
;
Offset : T_OFFSET
| T_OFFSET T_COMMENT { $$ = $1; $$->comment = $2->comment; }
;
Origin : T_ORIGIN
| T_ORIGIN T_COMMENT { $$ = $1; $$->comment = $2->comment; }
;
Terminal : ';'
| ';' T_COMMENT { $$ = $1; $$->comment = $2->comment; }
;
Open : '{'
| '{' T_COMMENT { $$ = $1; $$->comment = $2->comment; }
;
Close : '}'
| '}' T_COMMENT { $$ = $1; $$->comment = $2->comment; }
;
Wall : T_WALL
| T_WALL T_COMMENT { $$ = $1; $$->comment = $2->comment; }
;
NameList : Name
| NameList Name { APPEND(DMXConfigStringPtr, $1, $2); $$ = $1; }
;

View File

@ -1,187 +0,0 @@
/* $XFree86$ */
/*
* Copyright 2002 Red Hat Inc., Durham, North Carolina.
*
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation on the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* Authors:
* Rickard E. (Rik) Faith <faith@redhat.com>
*
*/
%{
#ifdef HAVE_DMX_CONFIG_H
#include <dmx-config.h>
#endif
#include "dmxparse.h"
#include "parser.h"
#include "os.h"
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
static int getdimension(int token, const char *text, int leng);
static int getstring(int token, const char *text, int leng);
static int gettoken(int token, const char *text, int leng);
static int getcomment(int token, const char *text, int leng);
static int lineno = 1;
%}
%s OTHER
comment #.*
word ([[:alpha:]_/:\-\+\.\*][[:alnum:]_/:\-\+\.\*]+)
string \"(([^\"\n])|\"\")*\"
badstring \"(([^\"\n])|\"\")*
number [[:digit:]x]+
dimension [[:digit:]]+[[:blank:]]*x[[:blank:]]*[[:digit:]]+
offset [+-][[:digit:]]+[[:blank:]]*[+-][[:blank:]]*[[:digit:]]+
origin @[[:blank:]]*[[:digit:]]+[[:blank:]]*[[:blank:]]*x[[:digit:]]+
NL \n
WS [[:blank:]]+
%%
virtual return gettoken(T_VIRTUAL, yytext, yyleng);
display return gettoken(T_DISPLAY, yytext, yyleng);
wall return gettoken(T_WALL, yytext, yyleng);
option return gettoken(T_OPTION, yytext, yyleng);
param return gettoken(T_PARAM, yytext, yyleng);
{dimension} return getdimension(T_DIMENSION, yytext, yyleng);
{offset} return getdimension(T_OFFSET, yytext+1, yyleng-1);
{origin} return getdimension(T_ORIGIN, yytext+1, yyleng-1);
{word} return getstring(T_STRING, yytext, yyleng);
{string} return getstring(T_STRING, yytext+1, yyleng-2);
{NL} ++lineno;
{WS}
\{ return gettoken(yytext[0], yytext, yyleng);
\} return gettoken(yytext[0], yytext, yyleng);
\; return gettoken(yytext[0], yytext, yyleng);
\/ return gettoken(yytext[0], yytext, yyleng);
^{comment} return getcomment(T_LINE_COMMENT, yytext, yyleng);
{comment} return getcomment(T_COMMENT, yytext, yyleng);
. return getstring(T_STRING, yytext, yyleng);
<<EOF>> return 0;
%%
int yywrap(void)
{
(void) &yyunput;
(void) &input;
return 1;
}
_X_NORETURN void yyerror(const char *message)
{
const char *pt, *end;
struct _entry {
const char *from;
const char *to;
} *entry, list[] = {
{ "T_VIRTUAL", "\"virtual\"" },
{ "T_DISPLAY", "\"display\"" },
{ "T_WALL", "\"wall\"" },
{ "T_OPTION", "\"option\"" },
{ "T_PARAM", "\"param\"" },
{ "T_DIMENSION", "dimension (e.g., 2x2 or 1024x768)" },
{ "T_OFFSET", "display offset (e.g., +10-10)" },
{ "T_ORIGIN", "tile origin (e.g., @1280x1024)" },
{ "T_STRING", "string" },
{ "T_COMMENT", "comment (e.g., #...)" },
{ "T_LINE_COMMENT", "comment (e.g., #...)" },
{ NULL, NULL }
};
fprintf(stderr, "parse error on line %d at token \"%*.*s\"\n",
lineno, (int)yyleng, (int)yyleng, yytext);
end = message + strlen(message);
for (pt = message; *pt; pt++) {
if (pt[0] == 'T' && pt[1] == '_') {
const char *next = strchr(pt, ' ');
if (!next || !*next) next = strchr(pt, '\0');
if (!next) goto bail;
--next;
if (next-pt == 1 && next[1]
&& next[2] == '\'' && next[3] == '\'') {
fprintf(stderr, "\"%c\"", next[1]);
pt += 4;
goto cnt;
}
for (entry = list; entry->from; ++entry) {
if (!strncmp(entry->from, pt, strlen(entry->from))) {
fprintf(stderr, "%s", entry->to);
pt = next;
goto cnt;
}
}
} else if (end-pt >= 5 && pt[0] == '\'' && pt[1] == '\'' && pt[3]
&& pt[4] == '\'' && pt[5] == '\'') {
fprintf(stderr, "\"%c\"", pt[3]);
pt += 5;
} else if (end-pt >= 3 && pt[0] == '\'' && pt[1] && pt[2] == '\'') {
fprintf(stderr, "\"%c\"", pt[1]);
pt += 3;
}
bail:
putc(*pt, stderr);
cnt:
;
}
fprintf(stderr, "\n");
exit( 1 );
}
static int getdimension(int token, const char *text, int leng)
{
char *endptr;
char *tmp = dmxConfigAlloc(leng+1);
int x, y;
strlcpy(tmp, text, leng+1);
x = strtol(tmp, &endptr, 10);
while (*endptr && !isdigit(*endptr)) ++endptr;
y = strtol(endptr, NULL, 10);
dmxConfigFree(tmp);
yylval.pair = dmxConfigCreatePair(token, lineno, NULL, x, y, 1, 1);
return token;
}
static int getstring(int token, const char *text, int leng)
{
yylval.string = dmxConfigCreateString(token, lineno, NULL,
dmxConfigCopyString(leng ? text : "",
leng));
return token;
}
static int gettoken(int token, const char *text, int leng)
{
yylval.token = dmxConfigCreateToken(token, lineno, NULL);
return token;
}
static int getcomment(int token, const char *text, int leng)
{
yylval.comment = dmxConfigCreateComment(token, lineno,
dmxConfigCopyString(text + 1,
leng - 1));
return token;
}

View File

@ -1 +0,0 @@
error

View File

@ -1,2 +0,0 @@
parse error on line 1 at token "error"
syntax error, unexpected string expecting "virtual" or comment (e.g., #...)

View File

@ -1 +0,0 @@
# comment

View File

@ -1 +0,0 @@
# comment

View File

@ -1 +0,0 @@
virtual

View File

@ -1,2 +0,0 @@
parse error on line 2 at token " "
syntax error, unexpected $end, expecting "{" or string or dimension (e.g., 2x2 or 1024x768)

View File

@ -1 +0,0 @@
display

View File

@ -1,2 +0,0 @@
parse error on line 1 at token "display"
syntax error, unexpected "display" expecting "virtual" or comment (e.g., #...)

View File

@ -1 +0,0 @@
display;

View File

@ -1,2 +0,0 @@
parse error on line 1 at token "display"
syntax error, unexpected "display" expecting "virtual" or comment (e.g., #...)

View File

@ -1,2 +0,0 @@
virtual {
}

Binary file not shown.

View File

@ -1,4 +0,0 @@
virtual a {
display d0:0 1280x1024;
display d1:0 1280x1024;
}

View File

@ -1,4 +0,0 @@
virtual a {
display d0:0 1280x1024;
display d1:0 1280x1024;
}

View File

@ -1,7 +0,0 @@
# comment a
# comment b
## comment c
# <-- tab
# Next comment is empty
#
# Non empty

View File

@ -1,7 +0,0 @@
# comment a
# comment b
## comment c
# <-- tab
# Next comment is empty
#
# Non empty

View File

@ -1,3 +0,0 @@
virtual a {
param a b; # comment
}

Some files were not shown because too many files have changed in this diff Show More