* \memberof weston_head
* \internal
*/
-static void
+WL_EXPORT void
weston_head_init(struct weston_head *head, const char *name)
{
/* Add some (in)sane defaults which can be used
* \memberof weston_compositor
* \internal
*/
-static void
+WL_EXPORT void
weston_compositor_add_head(struct weston_compositor *compositor,
struct weston_head *head)
{
return container_of(node, struct weston_head, compositor_link);
}
+/** Iterate over attached heads
+ *
+ * \param output The output whose heads to iterate.
+ * \param item The iterator, or NULL for start.
+ * \return The next attached head in the list.
+ *
+ * Returns all heads currently attached to the output.
+ *
+ * You can iterate over all heads as follows:
+ * \code
+ * struct weston_head *head = NULL;
+ *
+ * while ((head = weston_output_iterate_heads(output, head))) {
+ * ...
+ * }
+ * \endcode
+ *
+ * If you cause \c iter to be removed from the list, you cannot use it to
+ * continue iterating. Removing any other item is safe.
+ *
+ * \memberof weston_compositor
+ */
+WL_EXPORT struct weston_head *
+weston_output_iterate_heads(struct weston_output *output,
+ struct weston_head *iter)
+{
+ struct wl_list *list = &output->head_list;
+ struct wl_list *node;
+
+ assert(output);
+ assert(!iter || iter->output == output);
+
+ if (iter)
+ node = iter->output_link.next;
+ else
+ node = list->next;
+
+ assert(node);
+ assert(!iter || node != &iter->output_link);
+
+ if (node == list)
+ return NULL;
+
+ return container_of(node, struct weston_head, output_link);
+}
+
/** Attach a head to an inactive output
*
* \param output The output to attach to.
*
* \memberof weston_output
*/
-static int
+WL_EXPORT int
weston_output_attach_head(struct weston_output *output,
struct weston_head *head)
{
if (!wl_list_empty(&head->output_link))
return -1;
- /* XXX: no support for multi-head yet */
- if (!wl_list_empty(&output->head_list))
+ if (output->attach_head) {
+ if (output->attach_head(output, head) < 0)
+ return -1;
+ } else if (!wl_list_empty(&output->head_list)) {
+ /* No support for clones in the legacy path. */
return -1;
+ }
head->output = output;
wl_list_insert(output->head_list.prev, &head->output_link);
*
* It is safe to detach a non-attached head.
*
+ * If the head is attached to an enabled output and the output will be left
+ * with no heads, the output will be disabled.
+ *
* \memberof weston_head
+ * \sa weston_output_disable
*/
-static void
+WL_EXPORT void
weston_head_detach(struct weston_head *head)
{
+ struct weston_output *output = head->output;
+
wl_list_remove(&head->output_link);
wl_list_init(&head->output_link);
head->output = NULL;
+
+ if (!output)
+ return;
+
+ if (output->detach_head)
+ output->detach_head(output, head);
+
+ if (output->enabled) {
+ weston_head_remove_global(head);
+
+ if (wl_list_empty(&output->head_list))
+ weston_output_disable(output);
+ }
}
/** Destroy a head
* \memberof weston_head
* \internal
*/
-static void
+WL_EXPORT void
weston_head_release(struct weston_head *head)
{
weston_head_detach(head);
return head->output->enabled;
}
+/** Get the name of a head
+ *
+ * \param head The head to query.
+ * \return The head's name, not NULL.
+ *
+ * The name depends on the backend. The DRM backend uses connector names,
+ * other backends may use hardcoded names or user-given names.
+ */
+WL_EXPORT const char *
+weston_head_get_name(struct weston_head *head)
+{
+ return head->name;
+}
+
+/** Get the output the head is attached to
+ *
+ * \param head The head to query.
+ * \return The output the head is attached to, or NULL if detached.
+ */
+WL_EXPORT struct weston_output *
+weston_head_get_output(struct weston_head *head)
+{
+ return head->output;
+}
+
/* Move other outputs when one is resized so the space remains contiguous. */
static void
weston_compositor_reflow_outputs(struct weston_compositor *compositor,
wl_list_init(&output->head_list);
weston_head_init(&output->head, name);
- weston_head_set_connection_status(&output->head, true);
- weston_compositor_add_head(compositor, &output->head);
+ output->head.allocator_output = output;
+ if (!compositor->backend->create_output) {
+ weston_head_set_connection_status(&output->head, true);
+ weston_compositor_add_head(compositor, &output->head);
+ }
/* Add some (in)sane defaults which can be used
* for checking if an output was properly configured
free(output->name);
}
+/** Create an output for an unused head
+ *
+ * \param compositor The compositor.
+ * \param head The head to attach to the output.
+ * \return A new \c weston_output, or NULL on failure.
+ *
+ * This creates a new weston_output that starts with the given head attached.
+ * The output inherits the name of the head. The head must not be already
+ * attached to another output.
+ *
+ * An output must be configured before it can be enabled.
+ *
+ * \memberof weston_compositor
+ */
+WL_EXPORT struct weston_output *
+weston_compositor_create_output_with_head(struct weston_compositor *compositor,
+ struct weston_head *head)
+{
+ struct weston_output *output;
+
+ if (head->allocator_output) {
+ /* XXX: compatibility path to be removed after all converted */
+ output = head->allocator_output;
+ } else {
+ assert(compositor->backend->create_output);
+ output = compositor->backend->create_output(compositor,
+ head->name);
+ }
+
+ if (!output)
+ return NULL;
+
+ if (weston_output_attach_head(output, head) < 0) {
+ if (!head->allocator_output)
+ output->destroy(output);
+
+ return NULL;
+ }
+
+ return output;
+}
+
+/** Destroy an output
+ *
+ * \param output The output to destroy.
+ *
+ * The heads attached to the given output are detached and become unused again.
+ *
+ * It is not necessary to explicitly destroy all outputs at compositor exit.
+ * weston_compositor_destroy() will automatically destroy any remaining
+ * outputs.
+ *
+ * \memberof weston_output
+ */
+WL_EXPORT void
+weston_output_destroy(struct weston_output *output)
+{
+ struct weston_head *head;
+
+ /* XXX: compatibility path to be removed after all converted */
+ head = weston_output_get_first_head(output);
+ if (head->allocator_output) {
+ /* The old design: backend is responsible for destroying the
+ * output, so just undo create_output_with_head()
+ */
+ weston_head_detach(head);
+ return;
+ }
+
+ output->destroy(output);
+}
+
/** When you need a head...
*
* This function is a hack, used until all code has been converted to become
char *name; /**< head name, e.g. connector name */
bool connected; /**< is physically connected */
+
+ struct weston_output *allocator_output; /**< XXX: to be removed */
};
struct weston_output {
int (*enable)(struct weston_output *output);
int (*disable)(struct weston_output *output);
+
+ /** Attach a head in the backend
+ *
+ * @param output The output to attach to.
+ * @param head The head to attach.
+ * @return 0 on success, -1 on failure.
+ *
+ * Do anything necessary to account for a new head being attached to
+ * the output, and check any conditions possible. On failure, both
+ * the head and the output must be left as before the call.
+ *
+ * Libweston core will add the head to the head_list after a successful
+ * call.
+ */
+ int (*attach_head)(struct weston_output *output,
+ struct weston_head *head);
+
+ /** Detach a head in the backend
+ *
+ * @param output The output to detach from.
+ * @param head The head to detach.
+ *
+ * Do any clean-up necessary to detach this head from the output.
+ * The head has already been removed from the output's head_list.
+ */
+ void (*detach_head)(struct weston_output *output,
+ struct weston_head *head);
};
enum weston_pointer_motion_mask {
*/
void (*repaint_flush)(struct weston_compositor *compositor,
void *repaint_data);
+
+ /** Allocate a new output
+ *
+ * @param compositor The compositor.
+ * @param name Name for the new output.
+ *
+ * Allocates a new output structure that embeds a weston_output,
+ * initializes it, and returns the pointer to the weston_output
+ * member.
+ *
+ * Must set weston_output members @c destroy, @c enable and @c disable.
+ */
+ struct weston_output *
+ (*create_output)(struct weston_compositor *compositor,
+ const char *name);
};
struct weston_desktop_xwayland;
weston_compositor_load_xwayland(struct weston_compositor *compositor);
void
+weston_head_init(struct weston_head *head, const char *name);
+
+void
+weston_head_release(struct weston_head *head);
+
+void
+weston_compositor_add_head(struct weston_compositor *compositor,
+ struct weston_head *head);
+
+void
weston_head_set_monitor_strings(struct weston_head *head,
const char *make,
const char *model,
bool
weston_head_is_enabled(struct weston_head *head);
+const char *
+weston_head_get_name(struct weston_head *head);
+
+struct weston_output *
+weston_head_get_output(struct weston_head *head);
+
+void
+weston_head_detach(struct weston_head *head);
+
struct weston_head *
weston_compositor_iterate_heads(struct weston_compositor *compositor,
struct weston_head *iter);
weston_compositor_add_heads_changed_listener(struct weston_compositor *compositor,
struct wl_listener *listener);
+struct weston_output *
+weston_compositor_create_output_with_head(struct weston_compositor *compositor,
+ struct weston_head *head);
+
+void
+weston_output_destroy(struct weston_output *output);
+
+int
+weston_output_attach_head(struct weston_output *output,
+ struct weston_head *head);
+
+struct weston_head *
+weston_output_iterate_heads(struct weston_output *output,
+ struct weston_head *iter);
+
void
weston_output_set_scale(struct weston_output *output,
int32_t scale);