
org.freedesktop.wayland.client.Display Maven / Gradle / Ivy
//Copyright 2015 Erik De Rijcke
//
//Licensed under the Apache License,Version2.0(the"License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//
//http://www.apache.org/licenses/LICENSE-2.0
//
//Unless required by applicable law or agreed to in writing,software
//distributed under the License is distributed on an"AS IS"BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
package org.freedesktop.wayland.client;
import org.freedesktop.wayland.client.jaccall.WaylandClientCore;
/**
* Represents a connection to the compositor and acts as a proxy to
* the {@code Display} singleton object.
*
* A {@code Display} object represents a client connection to a Wayland
* compositor. It is created with either {@code WlDisplayProxy.connect()} or
* {@code WlDisplayProxy.connectToFd()}. A connection is terminated using
* {@link #disconnect()}.
*
* A {@code Display} is also used as the {@link Proxy} for the {@code Display}
* singleton object on the compositor side.
*
* A {@code Display} object handles all the data sent from and to the
* compositor. When a {@link Proxy} marshals a request, it will write its wire
* representation to the display's write buffer. The data is sent to the
* compositor when the client calls {@link #flush()}.
*
* Incoming data is handled in two steps: queueing and dispatching. In the
* queue step, the data coming from the display fd is interpreted and
* added to a queue. On the dispatch step, the handler for the incoming
* event set by the client on the corresponding {@link Proxy} is called.
*
* A {@code Display} has at least one event queue, called the main
* queue. Clients can create additional event queues with \ref
* {@link #createQueue()} and assign {@link Proxy}'s to it. Events
* occurring in a particular proxy are always queued in its assigned queue.
* A client can ensure that a certain assumption, such as holding a lock
* or running from a given thread, is true when a proxy event handler is
* called by assigning that proxy to an event queue and making sure that
* this queue is only dispatched when the assumption holds.
*
* The main queue is dispatched by calling {@link #dispatch()}.
* This will dispatch any events queued on the main queue and attempt
* to read from the display fd if its empty. Events read are then queued
* on the appropriate queues according to the proxy assignment. Calling
* that function makes the calling thread the main thread.
*
* A user created queue is dispatched with {@link #dispatchQueue(EventQueue)}.
* If there are no events to dispatch this function will block. If this
* is called by the main thread, this will attempt to read data from the
* display fd and queue any events on the appropriate queues. If calling
* from any other thread, the function will block until the main thread
* queues an event on the queue being dispatched.
*
* A real world example of event queue usage is Mesa's implementation of
* {@code eglSwapBuffers()} for the Wayland platform. This function might need
* to block until a frame callback is received, but dispatching the main
* queue could cause an event handler on the client to start drawing
* again. This problem is solved using another event queue, so that only
* the events handled by the EGL code are dispatched during the block.
*
* This creates a problem where the main thread dispatches a non-main
* queue, reading all the data from the display fd. If the application
* would call poll(2) after that it would block, even though there
* might be events queued on the main queue. Those events should be
* dispatched with {@link #dispatchPending()} before
* flushing and blocking.
*/
public abstract class Display extends Proxy {
public static final int OBJECT_ID = 1;
protected Display(final Long pointer) {
super(pointer,
null,
1);
}
/**
* Close a connection to a Wayland display
*
* Close the connection to the display and free all resources associated
* with it.
*/
public void disconnect() {
WaylandClientCore.INSTANCE()
.wl_display_disconnect(this.pointer);
}
/**
* Get a display context's file descriptor
*
* Return the file descriptor associated with a display so it can be
* integrated into the client's main loop.
*
* @return Display object file descriptor
*/
public int getFD() {
return WaylandClientCore.INSTANCE()
.wl_display_get_fd(this.pointer);
}
/**
* Process incoming events
*
* Dispatch the display's main event queue.
*
* If the main event queue is empty, this function blocks until there are
* events to be read from the display fd. Events are read and queued on
* the appropriate event queues. Finally, events on the main event queue
* are dispatched.
*
* It is not possible to check if there are events on the main queue
* or not. For dispatching main queue events without blocking, see {@link #dispatchPending()}.
*
* Calling this will release the display file descriptor if this
* thread acquired it using wl_display_acquire_fd().
*
* @return The number of dispatched events on success or -1 on failure
*
* @see #dispatchPending()
* @see #dispatchQueue(EventQueue)
*/
public int dispatch() {
return WaylandClientCore.INSTANCE()
.wl_display_dispatch(this.pointer);
}
/**
* Dispatch main queue events without reading from the display fd
*
* This function dispatches events on the main event queue. It does not
* attempt to read the display fd and simply returns zero if the main
* queue is empty, i.e., it doesn't block.
*
* This is necessary when a client's main loop wakes up on some fd other
* than the display fd (network socket, timer fd, etc) and calls
* {@link #dispatchQueue(EventQueue)} from that callback. This may queue up
* events in the main queue while reading all data from the display fd.
* When the main thread returns to the main loop to block, the display fd
* no longer has data, causing a call to {@code poll(2)} (or similar
* functions) to block indefinitely, even though there are events ready
* to dispatch.
*
* To proper integrate the wayland display fd into a main loop, the
* client should always call {@code dispatchPending()} and then
* {@link #flush()} prior to going back to sleep. At that point,
* the fd typically doesn't have data so attempting I/O could block, but
* events queued up on the main queue should be dispatched.
*
* A real-world example is a main loop that wakes up on a timerfd (or a
* sound card fd becoming writable, for example in a video player), which
* then triggers GL rendering and eventually eglSwapBuffers().
* eglSwapBuffers() may call {@link #dispatchQueue(EventQueue)} if it didn't
* receive the frame event for the previous frame, and as such queue
* events in the main queue.
*
* Calling this makes the current thread the main one.
*
* @return The number of dispatched events or -1 on failure
*
* @see #dispatch()
* @see #dispatchQueue(EventQueue)
* @see #flush()
*/
public int dispatchPending() {
return WaylandClientCore.INSTANCE()
.wl_display_dispatch_pending(this.pointer);
}
/**
* Dispatch events in an event queue
*
* Dispatch all incoming events for objects assigned to the given
* event queue. On failure -1 is returned and errno set appropriately.
*
* This function blocks if there are no events to dispatch. If calling from
* the main thread, it will block reading data from the display fd. For other
* threads this will block until the main thread queues events on the queue
* passed as argument.
*
* @param queue The event queue to dispatch
*
* @return The number of dispatched events on success or -1 on failure
*/
public int dispatchQueue(final EventQueue queue) {
return WaylandClientCore.INSTANCE()
.wl_display_dispatch_queue(this.pointer,
queue.pointer);
}
/**
* Dispatch pending events in an event queue
*
* Dispatch all incoming events for objects assigned to the given
* event queue. On failure -1 is returned and errno set appropriately.
* If there are no events queued, this function returns immediately.
*
* @param queue The event queue to dispatch
*
* @return The number of dispatched events on success or -1 on failure
*
* @since 1.0.2
*/
public int dispatchQueuePending(final EventQueue queue) {
return WaylandClientCore.INSTANCE()
.wl_display_dispatch_queue_pending(this.pointer,
queue.pointer);
}
/**
* Send all buffered requests on the display to the server
*
* Send all buffered data on the client side to the server. Clients
* should call this function before blocking. On success, the number
* of bytes sent to the server is returned. On failure, this
* function returns -1 and errno is set appropriately.
*
* flush() never blocks. It will write as much data as
* possible, but if all data could not be written, errno will be set
* to EAGAIN and -1 returned. In that case, use poll on the display
* file descriptor to wait for it to become writable again.
*
* @return The number of bytes sent on success or -1 on failure
*/
public int flush() {
return WaylandClientCore.INSTANCE()
.wl_display_flush(this.pointer);
}
/**
* Block until all pending request are processed by the server
*
* Blocks until the server process all currently issued requests and
* sends out pending events on all event queues.
*
* @return The number of dispatched events on success or -1 on failure
*/
public int roundtrip() {
return WaylandClientCore.INSTANCE()
.wl_display_roundtrip(this.pointer);
}
/**
* Create a new event queue for this display
*
*
* @return A new event queue associated with this display or NULL on
* failure.
*/
public EventQueue createQueue() {
return new EventQueue(WaylandClientCore.INSTANCE()
.wl_display_create_queue(this.pointer));
}
/**
* Retrieve the last error that occurred on a display
*
* Return the last error that occurred on the display. This may be an error sent
* by the server or caused by the local client.
*
* Errors are fatal. If this function returns non-zero the display
* can no longer be used.
*
* @return The last error that occurred on display or 0 if no error occurred
*/
public int getError() {
return WaylandClientCore.INSTANCE()
.wl_display_get_error(this.pointer);
}
public int prepareReadQueue(final EventQueue queue) {
return WaylandClientCore.INSTANCE()
.wl_display_prepare_read_queue(this.pointer,
queue.pointer);
}
/**
* Prepare to read events after polling file descriptor
*
* This function must be called before reading from the file
* descriptor using {@link #readEvents()}. Calling
* {@code prepareRead()} announces the calling threads intention
* to read and ensures that until the thread is ready to read and
* calls {@link #readEvents()}, no other thread will read from the
* file descriptor. This only succeeds if the event queue is empty
* though, and if there are undispatched events in the queue, -1 is
* returned and errno set to EAGAIN.
*
* If a thread successfully calls {@code prepareRead()}, it must
* either call {@link #readEvents()} when it's ready or cancel the
* read intention by calling {@link #cancelRead()}.
*
* Use this function before polling on the display fd or to integrate
* the fd into a toolkit event loop in a race-free way. Typically, a
* toolkit will call {@link #dispatchPending()} before sleeping, to
* make sure it doesn't block with unhandled events. Upon waking up,
* it will assume the file descriptor is readable and read events from
* the fd by calling {@link #dispatch()}. Simplified, we have:
*
*
* {@code
*
* display.dispatchPending();
* display.flush();
* poll(fds, nfds, -1);
* display.dispatch();
* }
*
*
* There are two races here: first, before blocking in poll(), the fd
* could become readable and another thread reads the events. Some of
* these events may be for the main queue and the other thread will
* queue them there and then the main thread will go to sleep in
* poll(). This will stall the application, which could be waiting
* for a event to kick of the next animation frame, for example.
*
* The other race is immediately after poll(), where another thread
* could preempt and read events before the main thread calls
* {@link #dispatch()}. This call now blocks and starves the other
* fds in the event loop.
*
* A correct sequence would be:
*
*
* {@code
* while (display.prepareRead() != 0)
* display.dispatch_Pending();
* display.flush();
* poll(fds, nfds, -1);
* display.readEvents();
* display.dispatchPending();
* }
*
*
* Here we call {@code prepareRead()}, which ensures that between
* returning from that call and eventually calling
* {@link #readEvents()}, no other thread will read from the fd and
* queue events in our queue. If the call to
* {@code prepareRead()} fails, we dispatch the pending events and
* try again until we're successful.
*
* @return 0 on success or -1 if event queue was not empty
*/
public int prepareRead() {
return WaylandClientCore.INSTANCE()
.wl_display_prepare_read(this.pointer);
}
/**
* Release exclusive access to display file descriptor
*
* This releases the exclusive access. Useful for canceling the lock
* when a timed out poll returns fd not readable and we're not going
* to read from the fd anytime soon.
*/
public void cancelRead() {
WaylandClientCore.INSTANCE()
.wl_display_cancel_read(this.pointer);
}
/**
* Read events from display file descriptor
*
* This will read events from the file descriptor for the display.
* This function does not dispatch events, it only reads and queues
* events into their corresponding event queues. If no data is
* avilable on the file descriptor, {@code readEvents()} returns
* immediately. To dispatch events that may have been queued, call
* {@link #dispatchPending()} or
* {@link #dispatchQueuePending(EventQueue)}.
*
* Before calling this function, {@link #prepareRead()} must be
* called first.
*
* @return 0 on success or -1 on error. In case of error errno will
* be set accordingly
*/
public int readEvents() {
return WaylandClientCore.INSTANCE()
.wl_display_read_events(this.pointer);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy