#include #include #include #include #include #include #include "private.h" struct csx_window * csx_window_create(struct csx_display *display, struct csx_window *parent) { struct csx_window *window; window = malloc(sizeof *window); if (window == NULL) return 0; memset(window, 0, sizeof *window); window->id = csx_display_add_resource(display, window); window->parent = parent; window->display = display; wl_list_init(&window->child_list); if (parent) wl_list_insert(&parent->child_list, &window->link); pixman_region32_init(&window->output_clip); pixman_region32_init(&window->border_clip); wl_list_init(&window->property_list); return window; } struct csx_window * csx_window_pick(struct csx_window *window, int x, int y, int *local_x, int *local_y) { struct csx_window *w; wl_list_for_each(w, &window->child_list, link) { if (w->mapped && w->x <= x && w->y <= y && x < w->x + w->width && y < w->y + w->height) return csx_window_pick(w, x - w->x, y - w->y, local_x, local_y); } *local_x = x; *local_y = y; return window; } static void csx_window_send_create_notify(struct csx_window *window) { struct csx_display *display = window->display; struct csx_event *event; event = malloc(sizeof *event); event->xevent.xcreatewindow.type = CreateNotify; event->xevent.xcreatewindow.serial = display->serial; event->xevent.xcreatewindow.send_event = False; event->xevent.xcreatewindow.display = display->xdisplay; event->xevent.xcreatewindow.parent = window->parent->id; event->xevent.xcreatewindow.window = window->id; event->xevent.xcreatewindow.x = window->x; event->xevent.xcreatewindow.y = window->y; event->xevent.xcreatewindow.width = window->width; event->xevent.xcreatewindow.height = window->height; event->xevent.xcreatewindow.border_width = window->border_width; event->xevent.xcreatewindow.override_redirect = False; wl_list_insert(display->event_list.prev, &event->link); } static void csx_window_send_destroy_notify(struct csx_window *window, struct csx_window *event_window) { struct csx_display *display = window->display; struct csx_event *event; event = malloc(sizeof *event); event->xevent.xdestroywindow.type = DestroyNotify; event->xevent.xdestroywindow.serial = display->serial; event->xevent.xdestroywindow.send_event = False; event->xevent.xdestroywindow.display = display->xdisplay; event->xevent.xdestroywindow.event = event_window->id; event->xevent.xdestroywindow.window = window->id; wl_list_insert(display->event_list.prev, &event->link); } WL_EXPORT Window XCreateWindow(Display *xdisplay, Window xparent, int x, int y, unsigned int width, unsigned int height, unsigned int border_width, int depth, unsigned int class, Visual *visual, unsigned long valuemask, XSetWindowAttributes *attributes) { struct csx_display *display = csx_display(xdisplay); struct csx_window *window, *parent; int i; csx_display_enter(display, X_CreateWindow, 0); parent = csx_display_lookup_resource(display, xparent); if (parent == NULL) { csx_display_error(display, xparent, BadWindow); /* FIXME: I'm sure we can't just return None here. */ return None; } window = csx_window_create(display, parent); if (window == NULL) { csx_display_error(display, 0, BadAlloc); return None; } window->x = x; window->y = y; window->width = width; window->height = height; window->border_width = border_width; window->depth = depth; window->class = class; window->visual = visual; for (i = 0; i < 15; i++) { switch (valuemask & (1 << i)) { case CWBackPixmap: case CWBackPixel: case CWBorderPixmap: case CWBorderPixel: case CWBitGravity: case CWWinGravity: case CWBackingStore: case CWBackingPlanes: case CWBackingPixel: case CWOverrideRedirect: case CWSaveUnder: break; case CWEventMask: window->event_mask = attributes->event_mask; break; case CWDontPropagate: case CWColormap: case CWCursor: break; } } if (parent->event_mask & SubstructureNotifyMask) csx_window_send_create_notify(window); return window->id; } WL_EXPORT Window XCreateSimpleWindow(Display *xdisplay, Window parent, int x, int y, unsigned int width, unsigned int height, unsigned int border_width, unsigned long border, unsigned long background) { XSetWindowAttributes attributes; attributes.background_pixel = background; attributes.border_pixel = border; return XCreateWindow(xdisplay, parent, x, y, width, height, border_width, 0, CopyFromParent, CopyFromParent, CWBackPixel | CWBorderPixel, &attributes); } WL_EXPORT Status XGetWindowAttributes(Display *xdisplay, Window xwindow, XWindowAttributes *attrs) { struct csx_display *display = csx_display(xdisplay); csx_display_enter(display, X_GetWindowAttributes, 0); STUB(); return 1; } static void handle_ping(void *data, struct wl_shell_surface *shell_surface, uint32_t serial) { wl_shell_surface_pong(shell_surface, serial); } static void handle_configure(void *data, struct wl_shell_surface *shell_surface, uint32_t edges, int32_t width, int32_t height) { } static void handle_popup_done(void *data, struct wl_shell_surface *shell_surface) { } static const struct wl_shell_surface_listener shell_surface_listener = { handle_ping, handle_configure, handle_popup_done }; static void csx_window_send_map_notify(struct csx_window *window, struct csx_window *event_window) { struct csx_display *display = window->display; struct csx_event *event; if (!(window->event_mask & StructureNotifyMask)) return; event = malloc(sizeof *event); event->xevent.xmap.type = MapNotify; event->xevent.xmap.serial = display->serial; event->xevent.xmap.send_event = False; event->xevent.xmap.display = display->xdisplay; event->xevent.xmap.event = event_window->id; event->xevent.xmap.window = window->id; event->xevent.xmap.override_redirect = False; wl_list_insert(display->event_list.prev, &event->link); } static void csx_window_send_expose(struct csx_window *window, pixman_box32_t *rect, int count) { struct csx_display *display = window->display; struct csx_event *event; event = malloc(sizeof *event); event->xevent.xexpose.type = Expose; event->xevent.xexpose.serial = display->serial; event->xevent.xexpose.send_event = False; event->xevent.xexpose.display = display->xdisplay; event->xevent.xexpose.window = window->id; event->xevent.xexpose.x = rect->x1; event->xevent.xexpose.y = rect->y1; event->xevent.xexpose.width = rect->x2 - rect->x1; event->xevent.xexpose.height = rect->y2 - rect->y1; event->xevent.xexpose.count = count; wl_list_insert(display->event_list.prev, &event->link); } static void csx_window_calculate_output_clip(struct csx_window *window) { pixman_region32_t output_clip, expose_region; struct csx_window *child; pixman_box32_t *rects; int i, nrects; pixman_region32_init(&output_clip); pixman_region32_copy(&output_clip, &window->border_clip); wl_list_for_each(child, &window->child_list, link) { if (!child->mapped) continue; pixman_region32_intersect_rect(&child->border_clip, &output_clip, child->x, child->y, child->width, child->height); pixman_region32_subtract(&output_clip, &output_clip, &child->border_clip); pixman_region32_translate(&child->border_clip, -child->x, -child->y); csx_window_calculate_output_clip(child); } pixman_region32_init(&expose_region); pixman_region32_subtract(&expose_region, &output_clip, &window->output_clip); pixman_region32_copy(&window->output_clip, &output_clip); rects = pixman_region32_rectangles(&expose_region, &nrects); for (i = 0; i < nrects; i++) csx_window_send_expose(window, &rects[i], nrects - i - 1); pixman_region32_fini(&expose_region); pixman_region32_fini(&output_clip); } static void csx_window_map_tree(struct csx_window *window, struct csx_pixmap *pixmap) { struct csx_window *child; wl_list_for_each(child, &window->child_list, link) csx_window_map_tree(child, pixmap); window->pixmap = pixmap; } static void csx_window_map_toplevel(struct csx_window *window) { struct csx_display *display = window->display; struct csx_pixmap *pixmap; pixmap = csx_pixmap_create(window->display, window->width, window->height, 32); csx_window_map_tree(window, pixmap); pixman_region32_fini(&window->border_clip); pixman_region32_init_rect(&window->border_clip, 0, 0, window->width, window->height); csx_window_calculate_output_clip(window); window->surface = wl_compositor_create_surface(display->compositor); wl_surface_set_user_data(window->surface, window); wl_surface_attach(window->surface, window->pixmap->buffer, 0, 0); window->shell_surface = wl_shell_get_shell_surface(display->shell, window->surface); wl_shell_surface_add_listener(window->shell_surface, &shell_surface_listener, window); wl_shell_surface_set_toplevel(window->shell_surface); wl_surface_commit(window->surface); } WL_EXPORT int XMapWindow(Display *xdisplay, Window xwindow) { struct csx_display *display = csx_display(xdisplay); struct csx_window *window; csx_display_enter(display, X_MapWindow, 0); window = csx_display_lookup_resource(display, xwindow); if (window == NULL) { csx_display_error(display, xwindow, BadWindow); return 1; } if (window->mapped) /* Already mapped */ return 1; window->mapped = 1; if (window->event_mask & StructureNotifyMask) csx_window_send_map_notify(window, window); if (window->parent && window->parent->event_mask & SubstructureNotifyMask) csx_window_send_map_notify(window, window->parent); if (window->parent == display->root) { csx_window_map_toplevel(window); } else if (window->parent->mapped) { window->pixmap = window->parent->pixmap; csx_window_calculate_output_clip(window->parent); } return 1; } WL_EXPORT int XMapSubwindows(Display *xdisplay, Window xwindow) { struct csx_display *display = csx_display(xdisplay); csx_display_enter(display, X_MapSubwindows, 0); STUB(); return 1; } WL_EXPORT int XUnmapSubwindows(Display *xdisplay, Window xwindow) { struct csx_display *display = csx_display(xdisplay); csx_display_enter(display, X_UnmapSubwindows, 0); STUB(); return 1; } WL_EXPORT int XUnmapWindow(Display *xdisplay, Window xwindow) { struct csx_display *display = csx_display(xdisplay); csx_display_enter(display, X_UnmapWindow, 0); STUB(); return 1; } WL_EXPORT int XChangeWindowAttributes(Display *xdisplay, Window xwindow, unsigned long mask, XSetWindowAttributes *attributes) { struct csx_display *display = csx_display(xdisplay); struct csx_window *window; csx_display_enter(display, X_ChangeWindowAttributes, 0); window = csx_display_lookup_resource(display, xwindow); if (window == NULL) { csx_display_error(display, xwindow, BadWindow); return 1; } STUB(); return 1; } static void csx_window_send_configure_notify(struct csx_window *window, struct csx_window *event_window) { struct csx_display *display = window->display; struct csx_event *event; event = malloc(sizeof *event); event->xevent.xconfigure.type = ConfigureNotify; event->xevent.xconfigure.serial = display->serial; event->xevent.xconfigure.send_event = False; event->xevent.xconfigure.display = display->xdisplay; event->xevent.xconfigure.event = event_window->id; event->xevent.xconfigure.window = window->id; event->xevent.xconfigure.x = window->x; event->xevent.xconfigure.y = window->y; event->xevent.xconfigure.width = window->width; event->xevent.xconfigure.height = window->height; event->xevent.xconfigure.border_width = window->border_width; event->xevent.xconfigure.above = None; /* FIXME */ event->xevent.xconfigure.override_redirect = False; wl_list_insert(display->event_list.prev, &event->link); } WL_EXPORT int XConfigureWindow(Display *xdisplay, Window xwindow, unsigned int mask, XWindowChanges *values) { struct csx_display *display = csx_display(xdisplay); struct csx_window *window; csx_display_enter(display, X_ConfigureWindow, 0); window = csx_display_lookup_resource(display, xwindow); if (window == NULL) { csx_display_error(display, xwindow, BadWindow); return 1; } if ((mask & CWSibling) && !(mask & CWStackMode)) { csx_display_error(display, mask, BadMatch); return 1; } if (mask & CWX) window->x = values->x; if (mask & CWY) window->y = values->y; if (mask & CWWidth) window->width = values->width; if (mask & CWHeight) window->height = values->height; if (mask & CWBorderWidth) window->border_width = values->border_width; if (mask & CWSibling) window->border_width = values->border_width; if (mask & (CWX | CWY | CWWidth | CWHeight)) csx_window_calculate_output_clip(window->parent); if (window->event_mask & StructureNotifyMask) csx_window_send_configure_notify(window, window); if (window->parent && window->parent->event_mask & StructureNotifyMask) csx_window_send_configure_notify(window, window->parent); return 1; } WL_EXPORT int XCirculateSubwindows(Display *xdisplay, Window xwindow, int direction) { struct csx_display *display = csx_display(xdisplay); csx_display_enter(display, X_CirculateWindow, 0); STUB(); return 1; } WL_EXPORT int XCirculateSubwindowsDown(Display *xdisplay, Window xwindow) { struct csx_display *display = csx_display(xdisplay); csx_display_enter(display, X_CirculateWindow, 0); STUB(); return 1; } WL_EXPORT int XCirculateSubwindowsUp(Display *xdisplay, Window xwindow) { struct csx_display *display = csx_display(xdisplay); csx_display_enter(display, X_CirculateWindow, 0); STUB(); return 1; } WL_EXPORT int XReparentWindow(Display *xdisplay, Window xwindow, Window xparent, int x, int y) { struct csx_display *display = csx_display(xdisplay); struct csx_window *window, *parent; csx_display_enter(display, X_ReparentWindow, 0); window = csx_display_lookup_resource(display, xwindow); if (window == NULL) { csx_display_error(display, xwindow, BadWindow); return 1; } parent = csx_display_lookup_resource(display, xparent); if (parent == NULL) { csx_display_error(display, xparent, BadWindow); return 1; } /* FIXME: Lot more to do here... */ wl_list_remove(&window->link); wl_list_insert(&parent->child_list, &window->link); return 1; } WL_EXPORT int XResizeWindow(Display *xdisplay, Window xwindow, unsigned int width, unsigned int height) { XWindowChanges values; values.width = width; values.height = height; return XConfigureWindow(xdisplay, xwindow, CWWidth | CWHeight, &values); } WL_EXPORT int XMoveResizeWindow(Display *xdisplay, Window xwindow, int x, int y, unsigned int width, unsigned int height) { XWindowChanges values; values.x = x; values.y = y; values.width = width; values.height = height; return XConfigureWindow(xdisplay, xwindow, CWX | CWY | CWWidth | CWHeight, &values); } WL_EXPORT int XMoveWindow(Display *xdisplay, Window xwindow, int x, int y) { XWindowChanges values; values.x = x; values.y = y; return XConfigureWindow(xdisplay, xwindow, CWX | CWY, &values); } WL_EXPORT int XLowerWindow(Display *xdisplay, Window xwindow) { XWindowChanges values; values.stack_mode = Below; return XConfigureWindow(xdisplay, xwindow, CWStackMode, &values); } WL_EXPORT int XRaiseWindow(Display *xdisplay, Window xwindow) { XWindowChanges values; values.stack_mode = Above; return XConfigureWindow(xdisplay, xwindow, CWStackMode, &values); } WL_EXPORT int XMapRaised(Display *xdisplay, Window xwindow) { struct csx_display *display = csx_display(xdisplay); struct csx_window *window; window = csx_display_lookup_resource(display, xwindow); if (window == NULL) { csx_display_error(display, xwindow, BadWindow); return 1; } STUB(); return 1; } WL_EXPORT Status XGetGeometry(Display *xdisplay, Drawable drawable, Window *xroot, int *x, int *y, unsigned int *width, unsigned int *height, unsigned int *border_width, unsigned int *depth) { struct csx_display *display = csx_display(xdisplay); struct csx_window *window; csx_display_enter(display, X_GetGeometry, 0); window = csx_display_lookup_resource(display, drawable); if (window == NULL) { csx_display_error(display, drawable, BadWindow); return 0; } *x = window->x; *y = window->y; *width = window->width; *height = window->height; *border_width = window->border_width; *depth = window->depth; return 1; } void csx_window_destroy(struct csx_window *window) { struct csx_window *child, *next; wl_list_for_each_safe(child, next, &window->child_list, link) csx_window_destroy(child); if (window->event_mask & StructureNotifyMask) csx_window_send_destroy_notify(window, window); if (window->parent->event_mask & SubstructureNotifyMask) csx_window_send_map_notify(window, window->parent); csx_display_remove_resource(window->display, window->id); wl_list_remove(&window->link); free(window); } WL_EXPORT int XDestroyWindow(Display *xdisplay, Window xwindow) { struct csx_display *display = csx_display(xdisplay); struct csx_window *window; csx_display_enter(display, X_DestroyWindow, 0); window = csx_display_lookup_resource(display, xwindow); if (window == NULL) { csx_display_error(display, xwindow, BadWindow); return 1; } if (window == display->root) return 1; csx_window_destroy(window); return 1; } WL_EXPORT int XChangeSaveSet(Display *xdisplay, Window xwindow, int change_mode) { struct csx_display *display = csx_display(xdisplay); csx_display_enter(display, X_ChangeSaveSet, 0); STUB(); return 1; } WL_EXPORT int XDestroySubwindows(Display *xdisplay, Window xwindow) { struct csx_display *display = csx_display(xdisplay); struct csx_window *window, *child, *next; csx_display_enter(display, X_DestroySubwindows, 0); window = csx_display_lookup_resource(display, xwindow); if (window == NULL) { csx_display_error(display, xwindow, BadWindow); return 1; } wl_list_for_each_reverse_safe(child, next, &window->child_list, link) csx_window_destroy(child); return 1; } static struct csx_property * csx_window_get_property(struct csx_window *window, Atom name) { struct csx_property *p; wl_list_for_each(p, &window->property_list, link) if (p->name == name) return p; return NULL; } static struct csx_property * csx_property_create(Atom name, Atom type, int format, const void *data1, int nelements1, const void *data2, int nelements2) { struct csx_property *property; char *p; int bpe, size; bpe = format / 8; size = (nelements1 + nelements2) * bpe; property = malloc(sizeof *property + size); property->name = name; property->type = type; property->format = format; property->nelements = nelements1 + nelements2; p = (char *) (property + 1); memcpy(p, data1, nelements1 * bpe); memcpy(p + nelements1 * bpe, data2, nelements2 * bpe); return property; } WL_EXPORT int XChangeProperty(Display *xdisplay, Window xwindow, Atom name, Atom type, int format, int mode, const unsigned char *data, int nelements) { struct csx_display *display = csx_display(xdisplay); struct csx_window *window; struct csx_property *property, *current; csx_display_enter(display, X_ChangeProperty, 0); if (format != 8 && format != 16 && format != 32) { csx_display_error(display, format, BadValue); return 1; } window = csx_display_lookup_resource(display, xwindow); if (window == NULL) { csx_display_error(display, xwindow, BadWindow); return 1; } current = csx_window_get_property(window, name); if (current && mode != PropModeReplace) { if (current->type != type || current->format != format) { csx_display_error(display, format, BadValue); return 1; } } if (current && mode == PropModePrepend) property = csx_property_create(name, type, format, data, nelements, current + 1, current->nelements); else if (current && mode == PropModeAppend) property = csx_property_create(name, type, format, current + 1, current->nelements, data, nelements); else property = csx_property_create(name, type, format, data, nelements, NULL, 0); if (current) { wl_list_insert(¤t->link, &property->link); wl_list_remove(¤t->link); free(current); } else { wl_list_insert(&window->property_list, &property->link); } return 1; } WL_EXPORT int XDeleteProperty(Display *xdisplay, Window xwindow, Atom name) { struct csx_display *display = csx_display(xdisplay); struct csx_window *window; struct csx_property *property; csx_display_enter(display, X_DeleteProperty, 0); window = csx_display_lookup_resource(display, xwindow); if (window == NULL) { csx_display_error(display, xwindow, BadWindow); return 1; } property = csx_window_get_property(window, name); if (property) { wl_list_remove(&property->link); free(property); } return 1; } WL_EXPORT int XGetWindowProperty(Display *xdisplay, Window xwindow, Atom name, long offset, long length, Bool delete, Atom req_type, Atom *actual_type, int *actual_format, unsigned long *nitems, unsigned long *bytes_after, unsigned char **prop) { struct csx_display *display = csx_display(xdisplay); struct csx_window *window; struct csx_property *property; unsigned char *data; long byte_length, copy, index; csx_display_enter(display, X_GetProperty, 0); window = csx_display_lookup_resource(display, xwindow); if (window == NULL) { csx_display_error(display, xwindow, BadWindow); return 1; } property = csx_window_get_property(window, name); if (property == NULL) { *actual_type = None; *actual_format = 0; *bytes_after = 0; return 1; } byte_length = property->nelements * property->format / 8; index = offset * 4; if (req_type != AnyPropertyType && req_type != property->type) { *actual_type = property->type; *actual_format = property->format; *bytes_after = byte_length; return 1; } if (length < 0 || index > byte_length) { csx_display_error(display, xwindow, BadValue); return 1; } *actual_type = property->type; *actual_format = property->format; copy = length * 4; if (index + copy > byte_length) copy = byte_length - index; *prop = malloc(copy); if (*prop == NULL) { csx_display_error(display, xwindow, BadAlloc); return 1; } data = (unsigned char *) (property + 1); memcpy(*prop, data + index, copy); *nitems = copy / (property->format / 8); *bytes_after = byte_length - (index + copy); if (delete) { wl_list_remove(&property->link); free(property); } return Success; } WL_EXPORT Atom * XListProperties(Display *xdisplay, Window xwindow, int *num_prop) { struct csx_display *display = csx_display(xdisplay); struct csx_window *window; struct csx_property *property; int i, length; Atom *atoms; csx_display_enter(display, X_ListProperties, 0); window = csx_display_lookup_resource(display, xwindow); if (window == NULL) { csx_display_error(display, xwindow, BadWindow); return NULL; } length = wl_list_length(&window->property_list); atoms = malloc(sizeof *atoms * length); if (atoms == NULL) return NULL; i = 0; wl_list_for_each(property, &window->property_list, link) atoms[i++] = property->name; *num_prop = length; return atoms; } WL_EXPORT int XRotateWindowProperties(Display *xdisplay, Window w, Atom *properties, int nprops, int npositions) { struct csx_display *display = csx_display(xdisplay); csx_display_enter(display, X_RotateProperties, 0); STUB(); return 1; } WL_EXPORT Status XQueryTree(Display *xdisplay, Window w, Window *root, Window *parent, Window **children, unsigned int *nchildren) { struct csx_display *display = csx_display(xdisplay); csx_display_enter(display, X_QueryTree, 0); STUB(); return 1; } WL_EXPORT int XTranslateCoordinates(Display *xdisplay, Window src_win, Window dest_win, int src_x, int src_y, int *dst_x, int *dst_y, Window *child) { struct csx_display *display = csx_display(xdisplay); csx_display_enter(display, X_TranslateCoords, 0); STUB(); return 1; }