PKG_CHECK_MODULES(DRM_BACKEND, [libinput >= 0.6.0])
fi
+# x11 backend
+AC_ARG_ENABLE(x11-backend,
+ AC_HELP_STRING([--enable-x11-backend], [enable x11 backend]),
+ [enable_x11_backend=$enableval], [enable_x11_backend=yes])
+# [enable_x11_backend=$enableval], [enable_x11_backend=no])
+
+AM_CONDITIONAL(ENABLE_X11_BACKEND, test $enable_x11_backend = yes)
+
+if test $enable_x11_backend = yes; then
+ AC_DEFINE(ENABLE_X11_BACKEND, 1, [Enable x11 backend])
+ PKG_CHECK_MODULES(X11_BACKEND, [x11 xcb-shm x11-xcb])
+fi
+
# pepper server
AC_ARG_ENABLE(pepper-server,
AC_HELP_STRING([--enable-pepper-server], [build pepper reference server]),
lib_LTLIBRARIES += libpepper.la
include_HEADERS += pepper.h
-libpepper_la_CFLAGS = $(LIB_PEPPER_CFLAGS)
+libpepper_la_CFLAGS = $(LIB_PEPPER_CFLAGS) -Wall
libpepper_la_LIBADD = $(LIB_PEPPER_LIBS)
libpepper_la_SOURCES = pepper.h \
libpepper_la_SOURCES += modules/drm/drm-internal.h
endif
+# x11 backend
+if ENABLE_X11_BACKEND
+include_HEADERS += modules/x11/pepper-x11.h
+
+libpepper_la_CFLAGS += $(X11_BACKEND_CFLAGS)
+libpepper_la_LIBADD += $(X11_BACKEND_LIBS)
+
+libpepper_la_SOURCES += modules/x11/x11-common.c \
+ modules/x11/x11-output.c \
+ modules/x11/x11-input.c \
+ modules/x11/x11-internal.h
+endif
+
+
# Pepper server executable
if ENABLE_PEPPER_SERVER
bin_PROGRAMS += pepper
wl_global_create(compositor->display, &wl_compositor_interface, 3, compositor,
compositor_bind);
wl_list_init(&compositor->surfaces);
+ wl_list_init(&compositor->seat_list);
compositor->shell = pepper_shell_create(compositor);
if (!compositor->shell)
--- /dev/null
+#ifndef PEPPER_X11_H
+#define PEPPER_X11_h
+
+#include <pepper.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct pepper_x11_connection pepper_x11_connection_t;
+
+PEPPER_API pepper_x11_connection_t *
+pepper_x11_connect(pepper_compositor_t *compositor, const char *display_name);
+
+PEPPER_API void
+pepper_x11_destroy(pepper_x11_connection_t *conn);
+
+PEPPER_API pepper_output_t *
+pepper_x11_output_create(pepper_x11_connection_t *connection, int32_t w, int32_t h);
+
+PEPPER_API void
+pepper_x11_seat_create(pepper_x11_connection_t* connection);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PEPPER_X11_H */
--- /dev/null
+#include <wayland-server.h>
+#include <common.h>
+#include "x11-internal.h"
+
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+/*
+ * xcb version
+ * xcb is faster than xlib
+ */
+
+static inline pepper_bool_t
+x11_get_next_event(xcb_connection_t *xcb_conn, xcb_generic_event_t **event, uint32_t mask)
+{
+ if (mask & WL_EVENT_READABLE)
+ *event = xcb_poll_for_event(xcb_conn);
+
+ if (mask & WL_EVENT_WRITABLE)
+ PEPPER_ERROR("WL_EVENT_WRITABLE\n");
+
+ return *event != NULL;
+}
+
+static int
+x11_handle_event(int fd, uint32_t mask, void *data)
+{
+ pepper_x11_connection_t *connection = data;
+ x11_seat_t *seat;
+ xcb_generic_event_t *event = NULL;
+
+ uint32_t count = 0;
+
+ if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR))
+ return 0;
+
+ if (!connection->use_xinput)
+ return 0;
+
+ /* TODO: At now, x11-backend has only 1 seat per connection, "seat0"
+ * but if not, we need to find matched seat at here
+ */
+ seat = connection->seat;
+
+ while(x11_get_next_event(connection->xcb_connection, &event, mask))
+ {
+ uint32_t type = event->response_type & ~0x80;
+ switch (type)
+ {
+ case XCB_ENTER_NOTIFY:
+ case XCB_LEAVE_NOTIFY:
+ case XCB_KEY_PRESS:
+ case XCB_KEY_RELEASE:
+ case XCB_BUTTON_PRESS:
+ case XCB_BUTTON_RELEASE:
+ case XCB_MOTION_NOTIFY:
+ x11_handle_input_event(seat, type, event);
+ break;
+ case XCB_EXPOSE:
+ /*PEPPER_ERROR("x11:event:not input event\n");*/
+ break;
+ default :
+ PEPPER_ERROR("x11:common:Unknown event\n");
+ break;
+ }
+
+ free(event);
+ count++;
+ }
+
+ return count;
+}
+
+#define F(field) offsetof(pepper_x11_connection_t, field)
+static void
+x11_init_atoms(pepper_x11_connection_t *conn)
+{
+ static const struct
+ {
+ const char *name;
+ int offset;
+ } atoms[] =
+ {
+ { "WM_PROTOCOLS", F(atom.wm_protocols) },
+ { "WM_NORMAL_HINTS", F(atom.wm_normal_hints) },
+ { "WM_SIZE_HINTS", F(atom.wm_size_hints) },
+ { "WM_DELETE_WINDOW", F(atom.wm_delete_window) },
+ { "WM_CLASS", F(atom.wm_class) },
+ { "_NET_WM_NAME", F(atom.net_wm_name) },
+ { "_NET_WM_ICON", F(atom.net_wm_icon) },
+ { "_NET_WM_STATE", F(atom.net_wm_state) },
+ { "_NET_WM_STATE_FULLSCREEN", F(atom.net_wm_state_fullscreen) },
+ { "_NET_SUPPORTING_WM_CHECK", F(atom.net_supporting_wm_check) },
+ { "_NET_SUPPORTED", F(atom.net_supported) },
+ { "STRING", F(atom.string) },
+ { "UTF8_STRING", F(atom.utf8_string) },
+ { "CARDINAL", F(atom.cardinal) },
+ };
+
+ xcb_intern_atom_cookie_t cookies[ARRAY_LENGTH(atoms)];
+ xcb_intern_atom_reply_t *reply;
+
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_LENGTH(atoms); i++)
+ {
+ cookies[i] = xcb_intern_atom(conn->xcb_connection, 0,
+ strlen(atoms[i].name),
+ atoms[i].name);
+ }
+
+ for (i = 0; i < ARRAY_LENGTH(atoms); i++)
+ {
+ reply = xcb_intern_atom_reply(conn->xcb_connection, cookies[i], NULL);
+ *(xcb_atom_t *) ((char *)conn + atoms[i].offset) = reply->atom;
+ free(reply);
+ }
+}
+
+PEPPER_API pepper_x11_connection_t *
+pepper_x11_connect(pepper_compositor_t *compositor, const char *display_name)
+{
+ pepper_x11_connection_t *connection = NULL;
+ struct wl_display *wdisplay;
+ struct wl_event_loop *loop;
+ xcb_screen_iterator_t scr_iter;
+
+ if (!compositor)
+ {
+ PEPPER_ERROR("x11:common:%s: compositor is null\n", __FUNCTION__);
+ return NULL;
+ }
+
+ connection = (pepper_x11_connection_t *)pepper_calloc(1, sizeof(pepper_x11_connection_t));
+ if (!connection)
+ {
+ PEPPER_ERROR("x11:common:%s: memory allocation failed\n", __FUNCTION__);
+ return NULL;
+ }
+
+ connection->display = XOpenDisplay(display_name);
+ if (!connection->display)
+ {
+ PEPPER_ERROR("x11:common:%s: XOpenDisplay failed\n", __FUNCTION__);
+ pepper_free(connection);
+ return NULL;
+ }
+
+ connection->xcb_connection = XGetXCBConnection(connection->display);
+ XSetEventQueueOwner(connection->display, XCBOwnsEventQueue);
+
+ if (xcb_connection_has_error(connection->xcb_connection))
+ {
+ PEPPER_ERROR("x11:common:%s: xcb connection has error\n", __FUNCTION__);
+ pepper_free(connection);
+ return NULL;
+ }
+
+ scr_iter = xcb_setup_roots_iterator(xcb_get_setup(connection->xcb_connection));
+ connection->screen = scr_iter.data;
+
+ connection->compositor = compositor;
+ connection->fd = xcb_get_file_descriptor(connection->xcb_connection);
+ if (display_name)
+ connection->display_name = pepper_string_copy(display_name);
+ else
+ connection->display_name = NULL;
+
+ x11_init_atoms(connection);
+
+ wdisplay = pepper_compositor_get_display(compositor);
+ loop = wl_display_get_event_loop(wdisplay);
+
+ connection->xcb_event_source = wl_event_loop_add_fd(loop,
+ connection->fd,
+ WL_EVENT_READABLE,
+ x11_handle_event,
+ connection);
+ wl_event_source_check(connection->xcb_event_source);
+
+ wl_list_init(&connection->outputs);
+
+ wl_signal_init(&connection->destroy_signal);
+
+ return connection;
+}
+
+PEPPER_API void
+pepper_x11_destroy(pepper_x11_connection_t *conn)
+{
+ /* TODO */
+}
--- /dev/null
+
+
+static void *
+x11_output_cursor_set(void *o, void *c)
+{
+ x11_output_t *output = o;
+ x11_cursor_t *cursor = c;
+ x11_cursor_t *current_cursor;
+ pepper_x11_connection_t *conn;
+
+ if (!output)
+ {
+ PEPPER_ERROR("x11:output:cursor:%s output is null\n", __FUNCTION__);
+ return NULL;
+ }
+
+ if (!cursor)
+ {
+ PEPPER_ERROR("x11:output:cursor:%s cursor is null\n", __FUNCTION__);
+ return NULL;
+ }
+
+ conn = output->connection;
+
+ current_cursor = output->cursor;
+ output->cursor = cursor;
+
+ /* set cursor for window*/
+ {
+ uint32_t mask = XCB_CW_CURSOR;
+ uint32_t value_list = cursor->xcb_cursor;
+ xcb_change_window_attributes(conn->xcb_connection,
+ output->window,
+ mask,
+ &value_list);
+ }
+
+ return current_cursor;
+}
+
+static void *
+x11_output_cursor_create(void *output, int32_t w, int32_t h, void *image)
+{
+ xcb_pixmap_t pixmap;
+ xcb_gc_t gc;
+ pepper_x11_connection_t *conn;
+ x11_cursor_t *cursor;
+
+ if (!output)
+ {
+ PEPPER_ERROR("x11:output:cursor:%s: output is null\n", __FUNCTION__);
+ return NULL;
+ }
+ if (!image)
+ {
+ PEPPER_ERROR("x11:output:cursor:%s: image is null\n", __FUNCTION__);
+ return NULL;
+ }
+ if (w<0 || h<0)
+ {
+ PEPPER_ERROR("x11:output:cursor:%s: width(%d) or height(%d) is invalid\n",
+ __FUNCTION__, w, h);
+ return NULL;
+ }
+
+ cursor = pepper_calloc(1, sizeof(x11_cursor_t));
+ if (!cursor)
+ {
+ PEPPER_ERROR("x11:cursor: memory allocation failed");
+ return NULL;
+ }
+ cursor->data = image;
+ cursor->w = w;
+ cursor->h = h;
+
+ conn = ((x11_output_t *)output)->connection;
+
+ pixmap = xcb_generate_id(conn->xcb_connection);
+ gc = xcb_generate_id(conn->xcb_connection);
+
+ xcb_create_pixmap(conn->xcb_connection, 1/*depth?*/,
+ pixmap, conn->screen->root, w, h);
+ xcb_create_gc(conn->xcb_connection, gc, pixmap, 0, NULL);
+ xcb_put_image(conn->xcb_connection, XCB_IMAGE_FORMAT_XY_PIXMAP, pixmap,
+ gc, w, h, 0, 0, 0, 32, w*h*sizeof(uint8_t), cursor->data);
+ cursor->xcb_cursor = xcb_generate_id(conn->xcb_connection);
+ /*
+ * cb_void_cookie_t xcb_create_cursor(xcb_connection_t *conn,
+ * xcb_cursor_t cid,
+ * xcb_pixmap_t source,
+ * xcb_pixmap_t mask,
+ * uint16_t fore_red, TODO: NOT YET DOCUMENTED.
+ * uint16_t fore_green,
+ * uint16_t fore_blue,
+ * uint16_t back_red,
+ * uint16_t back_green,
+ * uint16_t back_blue,
+ * uint16_t x,
+ * uint16_t y);
+ */
+ xcb_create_cursor(conn->xcb_connection, cursor->xcb_cursor,
+ pixmap, pixmap, 0, 0, 0, 0, 0, 0, 1, 1);
+
+ xcb_free_gc(conn->xcb_connection, gc);
+ xcb_free_pixmap(conn->xcb_connection, pixmap);
+
+ return (void *)cursor;
+}
+
+static void
+x11_output_cursor_destroy(void *o, void *c)
+{
+ xcb_connection_t *conn;
+ x11_cursor_t *cursor;
+
+ if (!o)
+ {
+ PEPPER_ERROR("x11:output:cursor:%s: output is null\n", __FUNCTION__);
+ return ;
+ }
+ if (!c)
+ {
+ PEPPER_ERROR("x11:output:cursor:%s: cursor is null\n", __FUNCTION__);
+ return ;
+ }
+
+ conn = ((x11_output_t *)o)->connection->xcb_connection;
+ cursor = (x11_cursor_t *)c;
+
+ xcb_free_cursor(conn, cursor->xcb_cursor);
+ /* XXX: pepper_free(cursor->data); ??? */
+ pepper_free(cursor);
+}
--- /dev/null
+#include "x11-internal.h"
+
+void
+x11_handle_input_event(x11_seat_t* seat, uint32_t type, xcb_generic_event_t* xev)
+{
+ pepper_input_event_t event;
+
+ memset(&event, 0x00, sizeof(pepper_input_event_t));
+
+ switch (type)
+ {
+ case XCB_ENTER_NOTIFY:
+ case XCB_LEAVE_NOTIFY:
+ case XCB_KEY_PRESS:
+ case XCB_KEY_RELEASE:
+ break;
+ case XCB_BUTTON_PRESS:
+ {
+ xcb_button_press_event_t *bp = (xcb_button_press_event_t *)xev;
+ switch (bp->detail)
+ {
+ case XCB_BUTTON_INDEX_1:/* FIXME: LEFT */
+ PEPPER_ERROR("left click\n");
+ event.index = 1;
+ break;
+ case XCB_BUTTON_INDEX_3:/* FIXME: RIGHT */
+ PEPPER_ERROR("right click\n");
+ event.index = 3;
+ break;
+ default:
+ PEPPER_ERROR("wheel or something pressed\n");
+ break;
+ }
+ event.type = PEPPER_INPUT_EVENT_POINTER_BUTTON;
+ event.time = bp->time;
+ event.serial = bp->sequence;
+ event.state = PEPPER_INPUT_EVENT_STATE_PRESSED;
+ event.value = 0;
+ event.x = bp->event_x;
+ event.y = bp->event_y;;
+ }
+ break;
+ case XCB_BUTTON_RELEASE:
+ {
+ xcb_button_release_event_t *br = (xcb_button_release_event_t *)xev;
+ switch (br->detail)
+ {
+ case XCB_BUTTON_INDEX_1:/* FIXME: LEFT */
+ PEPPER_ERROR("left released\n");
+ event.index = 1;
+ break;
+ case XCB_BUTTON_INDEX_3:/* FIXME: RIGHT */
+ PEPPER_ERROR("right released\n");
+ event.index = 3;
+ break;
+ default:
+ PEPPER_ERROR("wheel or something pressed\n");
+ break;
+ }
+ event.type = PEPPER_INPUT_EVENT_POINTER_BUTTON;
+ event.time = br->time;
+ event.serial = br->sequence;
+ event.state = PEPPER_INPUT_EVENT_STATE_RELEASED;
+ event.value = 0;
+ event.x = br->event_x;
+ event.y = br->event_y;;
+ }
+ break;
+ case XCB_MOTION_NOTIFY:
+ {
+ xcb_motion_notify_event_t *motion = (xcb_motion_notify_event_t *)xev;
+ event.type = PEPPER_INPUT_EVENT_POINTER_MOTION;
+ event.time = motion->time;
+ event.serial = motion->sequence;
+ event.index = 0;
+ event.state = 0;
+ event.value = 0;
+ event.x = motion->event_x;
+ event.y = motion->event_y;
+ }
+ break;
+ default :
+ PEPPER_ERROR("x11:input: unknown input event\n");
+ }
+
+ pepper_seat_handle_event(seat->base, &event);
+}
+
+void
+x11_window_input_property_change(xcb_connection_t *conn, xcb_window_t window)
+{
+ const static uint32_t values[] =
+ {
+ XCB_EVENT_MASK_EXPOSURE |
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY |
+ XCB_EVENT_MASK_KEY_PRESS |
+ XCB_EVENT_MASK_KEY_RELEASE |
+ XCB_EVENT_MASK_BUTTON_PRESS |
+ XCB_EVENT_MASK_BUTTON_RELEASE |
+ XCB_EVENT_MASK_POINTER_MOTION |
+ XCB_EVENT_MASK_ENTER_WINDOW |
+ XCB_EVENT_MASK_LEAVE_WINDOW |
+ XCB_EVENT_MASK_KEYMAP_STATE |
+ XCB_EVENT_MASK_FOCUS_CHANGE
+ };
+ xcb_change_window_attributes(conn, window, XCB_CW_EVENT_MASK, values);
+ xcb_flush(conn);
+}
+
+static void
+x11_seat_destroy(void *data)
+{
+ PEPPER_IGNORE(data);
+ /* TODO : x11_seat_t *seat = (x11_seat_t *)data; */
+ return;
+}
+
+static void
+x11_seat_add_capability_listener(void *data, struct wl_listener *listener)
+{
+ x11_seat_t *seat = (x11_seat_t *)data;
+ wl_signal_add(&seat->capability_signal, listener);
+ return;
+}
+
+static void
+x11_seat_add_name_listener(void *data, struct wl_listener *listener)
+{
+ x11_seat_t *seat = (x11_seat_t *)data;
+ wl_signal_add(&seat->name_signal, listener);
+ return;
+}
+
+static uint32_t
+x11_seat_get_capabilities(void *data)
+{
+ x11_seat_t *seat = (x11_seat_t *)data;
+ return seat->caps;
+}
+
+static const char *
+x11_seat_get_name(void *data)
+{
+ x11_seat_t *seat = (x11_seat_t *)data;
+ return seat->name;
+}
+
+static const pepper_seat_interface_t x11_seat_interface =
+{
+ x11_seat_destroy,
+ x11_seat_add_capability_listener,
+ x11_seat_add_name_listener,
+ x11_seat_get_capabilities,
+ x11_seat_get_name,
+};
+
+PEPPER_API void
+pepper_x11_seat_create(pepper_x11_connection_t* conn)
+{
+ x11_seat_t *seat;
+
+ if (!conn)
+ {
+ PEPPER_ERROR("x11:input:%s: connection is null...\n", __FUNCTION__);
+ return ;
+ }
+
+ PEPPER_ERROR("x11:input: initialize input module...\n");
+
+ seat = pepper_calloc(1, sizeof(x11_seat_t));
+ if (!seat)
+ {
+ PEPPER_ERROR("x11:input:%s: failed to allocate memory\n", __FUNCTION__);
+ return ;
+ }
+
+ conn->use_xinput = PEPPER_TRUE;
+
+ if (!wl_list_empty(&conn->outputs))
+ {
+ x11_output_t *out;
+ wl_list_for_each(out, &conn->outputs, link)
+ x11_window_input_property_change(conn->xcb_connection, out->window);
+ }
+ /* XXX: if x-input-module used with out x-output-module,
+ * need to create dummy window for input with output-size */
+
+ wl_signal_init(&seat->capability_signal);
+ wl_signal_init(&seat->name_signal);
+
+ seat->base = pepper_compositor_add_seat(conn->compositor, &x11_seat_interface, seat);
+ seat->id = X11_BACKEND_INPUT_ID;
+
+ /* x-connection has only 1 seat */
+ conn->seat = seat;
+}
+
--- /dev/null
+#ifndef X11_INTERNAL_H
+#define X11_INTERNAL_H
+
+#include "pepper-x11.h"
+
+#include <common.h>
+#include <xcb/xcb.h>
+#include <xcb/shm.h>
+#include <X11/Xlib.h>
+#include <X11/Xlib-xcb.h>
+#include <string.h>
+
+#define X11_BACKEND_INPUT_ID 0x12345678
+
+typedef struct x11_output x11_output_t;
+typedef struct x11_cursor x11_cursor_t;
+typedef struct x11_seat x11_seat_t;
+
+struct x11_output
+{
+ pepper_x11_connection_t* connection;
+
+ int32_t x, y;
+ uint32_t w, h;
+ uint32_t subpixel;
+ uint32_t scale;
+ uint8_t depth;
+
+ xcb_window_t window;
+ xcb_gc_t gc;
+ x11_cursor_t *cursor;
+
+ struct wl_signal destroy_signal;
+ struct wl_signal mode_change_signal;
+
+ struct wl_listener conn_destroy_listener;
+
+ struct wl_list link;
+};
+
+struct x11_seat
+{
+ pepper_seat_t *base;
+
+ uint32_t id;
+ uint32_t caps;
+ char *name;
+
+ wl_fixed_t pointer_x_last;
+ wl_fixed_t pointer_y_last;
+ wl_fixed_t touch_x_last; /* FIXME */
+ wl_fixed_t touch_y_last; /* FIXME */
+
+ struct wl_list link;
+ struct wl_signal capability_signal;
+ struct wl_signal name_signal;
+};
+
+struct pepper_x11_connection
+{
+ pepper_compositor_t *compositor;
+ char *display_name;
+
+ Display *display;
+ xcb_screen_t *screen;
+ xcb_connection_t *xcb_connection;
+
+ struct wl_event_source *xcb_event_source;
+ struct wl_list link;
+ int fd;
+
+ struct wl_list outputs;
+
+ pepper_bool_t use_xinput;
+ x11_seat_t *seat;
+
+ struct {
+ xcb_atom_t wm_protocols;
+ xcb_atom_t wm_normal_hints;
+ xcb_atom_t wm_size_hints;
+ xcb_atom_t wm_delete_window;
+ xcb_atom_t wm_class;
+ xcb_atom_t net_wm_name;
+ xcb_atom_t net_supporting_wm_check;
+ xcb_atom_t net_supported;
+ xcb_atom_t net_wm_icon;
+ xcb_atom_t net_wm_state;
+ xcb_atom_t net_wm_state_fullscreen;
+ xcb_atom_t string;
+ xcb_atom_t utf8_string;
+ xcb_atom_t cardinal;
+ xcb_atom_t xkb_names;
+ } atom;
+
+ struct wl_signal destroy_signal;
+};
+
+struct x11_cursor
+{
+ xcb_cursor_t xcb_cursor;
+ int w;
+ int h;
+ uint8_t *data;
+};
+
+/* it declared in xcb-icccm.h */
+typedef struct xcb_size_hints {
+ uint32_t flags;
+ uint32_t pad[4];
+ int32_t min_width, min_height;
+ int32_t max_width, max_height;
+ int32_t width_inc, height_inc;
+ int32_t min_aspect_x, min_aspect_y;
+ int32_t max_aspect_x, max_aspect_y;
+ int32_t base_width, base_height;
+ int32_t win_gravity;
+}xcb_size_hints_t;
+#define WM_NORMAL_HINTS_MIN_SIZE 16
+#define WM_NORMAL_HINTS_MAX_SIZE 32
+/* -- xcb-icccm.h */
+
+pepper_x11_connection_t *
+pepper_x11_connect(pepper_compositor_t *compositor, const char *display_name);
+
+void
+x11_window_input_property_change(xcb_connection_t *conn, xcb_window_t window);
+
+void
+x11_handle_input_event(x11_seat_t* seat, uint32_t type, xcb_generic_event_t* xev);
+
+#endif /*X11_INTERNAL_H*/
--- /dev/null
+#include "x11-internal.h"
+
+static uint8_t
+x11_get_depth_of_visual(xcb_screen_t *screen, xcb_visualid_t id)
+{
+ xcb_depth_iterator_t i;
+ xcb_visualtype_iterator_t j;
+
+ i = xcb_screen_allowed_depths_iterator(screen);
+ for (; i.rem; xcb_depth_next(&i))
+ {
+ j = xcb_depth_visuals_iterator(i.data);
+ for (; j.rem; xcb_visualtype_next(&j))
+ {
+ if (j.data->visual_id == id)
+ return i.data->depth;
+ }
+ }
+ return 0;
+}
+
+static void
+x11_output_visual_iterate(void *o)
+{
+ x11_output_t *output = o;
+
+ xcb_screen_t *screen;
+ xcb_visualtype_t *visual_type = NULL; /* the returned visual type */
+
+ screen = output->connection->screen;
+ if (screen)
+ {
+ xcb_depth_iterator_t depth_iter;
+
+ depth_iter = xcb_screen_allowed_depths_iterator(screen);
+ for (; depth_iter.rem; xcb_depth_next(&depth_iter))
+ {
+ xcb_visualtype_iterator_t visual_iter;
+
+ visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
+ for (; visual_iter.rem; xcb_visualtype_next(&visual_iter))
+ {
+ visual_type = visual_iter.data;
+ printf("visual %d, class: %d, bits per rgb value: %d, colormap_entries %d, r:%#010x, g:%#010x, b:%#010x, depth %d\n",
+ visual_type->visual_id,
+ visual_type->_class,
+ visual_type->colormap_entries,
+ visual_type->bits_per_rgb_value,
+ visual_type->red_mask,
+ visual_type->green_mask,
+ visual_type->blue_mask,
+ x11_get_depth_of_visual(screen, visual_type->visual_id));
+ }
+ }
+ }
+}
+
+static void
+x11_output_destroy(void *o)
+{
+ x11_output_t *output;
+ pepper_x11_connection_t *conn;
+
+ if (!o)
+ {
+ PEPPER_ERROR("x11:output:%s: output is null\n", __FUNCTION__);
+ return ;
+ }
+
+ output = o;
+ conn = output->connection;
+
+ wl_signal_emit(&output->destroy_signal, output);
+
+ xcb_destroy_window(conn->xcb_connection, output->window);
+
+ wl_list_remove(&output->link);
+
+ pepper_free(output);
+}
+
+static int32_t
+x11_output_get_subpixel_order(void *o)
+{
+ x11_output_t *output = o;
+ return output->subpixel;
+}
+
+static const char *
+x11_output_get_maker_name(void *o)
+{
+ PEPPER_IGNORE(o);
+ return "pepper_x11";
+}
+
+static const char *
+x11_output_get_model_name(void *o)
+{
+ PEPPER_IGNORE(o);
+ return "pepper_x11";
+}
+
+static int
+x11_output_get_mode_count(void *o)
+{
+ PEPPER_IGNORE(o);
+
+ /* There's only one available mode in x11 backend which is also the current mode. */
+ return 1;
+}
+
+static void
+x11_output_get_mode(void *o, int index, pepper_output_mode_t *mode)
+{
+ x11_output_t *output = o;
+
+ if (index != 0)
+ return;
+
+ mode->flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
+ mode->w = output->w;
+ mode->h = output->h;
+ mode->refresh = 60000;
+}
+
+static pepper_bool_t
+x11_output_set_mode(void *o, const pepper_output_mode_t *mode)
+{
+ x11_output_t *output = o;
+
+ if (mode->w <= 0 || mode->h <= 0)
+ return PEPPER_FALSE;
+
+ if (mode->refresh != 60000)
+ return PEPPER_FALSE;
+
+ if (output->w != mode->w || output->h != mode->h)
+ {
+ output->w = mode->w;
+ output->h = mode->h;
+
+ /* TODO: Handle resize here. */
+
+ wl_signal_emit(&output->mode_change_signal, output);
+ }
+
+ return PEPPER_TRUE;
+}
+
+static void
+x11_output_add_destroy_listener(void *o, struct wl_listener *listener)
+{
+ x11_output_t *output = o;
+ wl_signal_add(&output->destroy_signal, listener);
+}
+
+static void
+x11_output_add_mode_change_listener(void *o, struct wl_listener *listener)
+{
+ x11_output_t *output = o;
+ wl_signal_add(&output->mode_change_signal, listener);
+}
+
+static const pepper_output_interface_t x11_output_interface =
+{
+ x11_output_destroy,
+ x11_output_add_destroy_listener,
+ x11_output_add_mode_change_listener,
+
+ x11_output_get_subpixel_order,
+ x11_output_get_maker_name,
+ x11_output_get_model_name,
+
+ x11_output_get_mode_count,
+ x11_output_get_mode,
+ x11_output_set_mode,
+};
+
+static void
+handle_connection_destroy(struct wl_listener *listener, void *data)
+{
+ x11_output_t *output = wl_container_of(listener, output, conn_destroy_listener);
+ x11_output_destroy(output);
+}
+
+PEPPER_API pepper_output_t *
+pepper_x11_output_create(pepper_x11_connection_t *connection, int32_t w, int32_t h)
+{
+ static const char *window_name = "PePPer Compositor";
+ static const char *class_name = "pepper-1\0PePPer Compositor";
+
+ pepper_output_t *base;
+ x11_output_t *output;
+
+ output = pepper_calloc(1, sizeof(x11_output_t));
+ if (!output)
+ {
+ PEPPER_ERROR("x11:output:%s: memory allocation failed", __FUNCTION__);
+ return NULL;
+ }
+
+ output->connection = connection;
+ output->w = w;
+ output->h = h;
+
+ /* Hard-Coded: subpixel order to horizontal RGB. */
+ output->subpixel = WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
+
+ /* Hard-Coded: scale value to 1. */
+ output->scale = 1;
+
+ /* create X11 window */
+ {
+ uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
+ uint32_t values[2] = {
+ connection->screen->white_pixel,
+ 0
+ };
+ xcb_size_hints_t hints;
+
+ output->window = xcb_generate_id(connection->xcb_connection);
+ xcb_create_window(connection->xcb_connection,
+ XCB_COPY_FROM_PARENT,
+ output->window,
+ connection->screen->root,
+ 0, /* X position of top-left corner of window */
+ 0, /* Y position of top-left corner of window */
+ w*output->scale,
+ h*output->scale,
+ 0, /* width of windows' border */
+ XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ connection->screen->root_visual,
+ mask,
+ values);
+
+
+ /* cannot resize */
+ memset(&hints, 0, sizeof(hints));
+ hints.flags = WM_NORMAL_HINTS_MAX_SIZE | WM_NORMAL_HINTS_MIN_SIZE;
+ hints.min_width = hints.max_width = w*output->scale;
+ hints.min_height = hints.max_height = h*output->scale;
+ xcb_change_property(connection->xcb_connection,
+ XCB_PROP_MODE_REPLACE,
+ output->window,
+ connection->atom.wm_normal_hints,
+ connection->atom.wm_size_hints,
+ 32,
+ sizeof(hints) / 4,
+ (uint8_t *)&hints);
+
+ /* set window name */
+ xcb_change_property(connection->xcb_connection, XCB_PROP_MODE_REPLACE,
+ output->window,
+ connection->atom.net_wm_name,
+ connection->atom.utf8_string, 8,
+ strlen(window_name), window_name);
+ xcb_change_property(connection->xcb_connection, XCB_PROP_MODE_REPLACE,
+ output->window,
+ connection->atom.wm_class,
+ connection->atom.string, 8,
+ strlen(class_name), class_name);
+
+ xcb_map_window(connection->xcb_connection, output->window);
+
+ if (connection->use_xinput)
+ x11_window_input_property_change(connection->xcb_connection,
+ output->window);
+
+ wl_list_insert(&connection->outputs, &output->link);
+
+ xcb_flush(connection->xcb_connection);
+ }
+
+ wl_signal_init(&output->destroy_signal);
+ wl_signal_init(&output->mode_change_signal);
+
+ /*x11_output_visual_iterate(output);*/
+
+ base = pepper_compositor_add_output(connection->compositor,
+ &x11_output_interface,
+ output);
+ if (!base)
+ {
+ PEPPER_ERROR("x11:output:%s: pepper_compositor_add_output failed\n", __FUNCTION__);
+ x11_output_destroy(output);
+ return NULL;
+ }
+
+ output->conn_destroy_listener.notify = handle_connection_destroy;
+ wl_signal_add(&connection->destroy_signal, &output->conn_destroy_listener);
+
+ return base;
+}