1/* 2 * Copyright © 2013 Keith Packard 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that copyright 7 * notice and this permission notice appear in supporting documentation, and 8 * that the name of the copyright holders not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. The copyright holders make no representations 11 * about the suitability of this software for any purpose. It is provided "as 12 * is" without express or implied warranty. 13 * 14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 * OF THIS SOFTWARE. 21 */ 22 23#include "present_priv.h" 24 25static RESTYPE present_event_type; 26 27static int 28present_free_event(void *data, XID id) 29{ 30 present_event_ptr present_event = (present_event_ptr) data; 31 present_window_priv_ptr window_priv = present_window_priv(present_event->window); 32 present_event_ptr *previous, current; 33 34 for (previous = &window_priv->events; (current = *previous); previous = ¤t->next) { 35 if (current == present_event) { 36 *previous = present_event->next; 37 break; 38 } 39 } 40 free((void *) present_event); 41 return 1; 42 43} 44 45void 46present_free_events(WindowPtr window) 47{ 48 present_window_priv_ptr window_priv = present_window_priv(window); 49 present_event_ptr event; 50 51 if (!window_priv) 52 return; 53 54 while ((event = window_priv->events)) 55 FreeResource(event->id, RT_NONE); 56} 57 58static void 59present_event_swap(xGenericEvent *from, xGenericEvent *to) 60{ 61 *to = *from; 62 swaps(&to->sequenceNumber); 63 swapl(&to->length); 64 swaps(&to->evtype); 65 switch (from->evtype) { 66 case PresentConfigureNotify: { 67 xPresentConfigureNotify *c = (xPresentConfigureNotify *) to; 68 69 swapl(&c->eid); 70 swapl(&c->window); 71 swaps(&c->x); 72 swaps(&c->y); 73 swaps(&c->width); 74 swaps(&c->height); 75 swaps(&c->off_x); 76 swaps(&c->off_y); 77 swaps(&c->pixmap_width); 78 swaps(&c->pixmap_height); 79 swapl(&c->pixmap_flags); 80 break; 81 } 82 case PresentCompleteNotify: 83 { 84 xPresentCompleteNotify *c = (xPresentCompleteNotify *) to; 85 swapl(&c->eid); 86 swapl(&c->window); 87 swapl(&c->serial); 88 swapll(&c->ust); 89 swapll(&c->msc); 90 break; 91 } 92 case PresentIdleNotify: 93 { 94 xPresentIdleNotify *c = (xPresentIdleNotify *) to; 95 swapl(&c->eid); 96 swapl(&c->window); 97 swapl(&c->serial); 98 swapl(&c->idle_fence); 99 break; 100 } 101 } 102} 103 104void 105present_send_config_notify(WindowPtr window, int x, int y, int w, int h, 106 int bw, WindowPtr sibling, CARD32 flags) 107{ 108 present_window_priv_ptr window_priv = present_window_priv(window); 109 110 if (window_priv) { 111 xPresentConfigureNotify cn = { 112 .type = GenericEvent, 113 .extension = present_request, 114 .length = (sizeof(xPresentConfigureNotify) - 32) >> 2, 115 .evtype = PresentConfigureNotify, 116 .eid = 0, 117 .window = window->drawable.id, 118 .x = x, 119 .y = y, 120 .width = w, 121 .height = h, 122 .off_x = 0, 123 .off_y = 0, 124 .pixmap_width = w, 125 .pixmap_height = h, 126 .pixmap_flags = flags 127 }; 128 present_event_ptr event; 129 130 for (event = window_priv->events; event; event = event->next) { 131 if (event->mask & (1 << PresentConfigureNotify)) { 132 cn.eid = event->id; 133 WriteEventsToClient(event->client, 1, (xEvent *) &cn); 134 } 135 } 136 } 137} 138 139static present_complete_notify_proc complete_notify; 140 141void 142present_register_complete_notify(present_complete_notify_proc proc) 143{ 144 complete_notify = proc; 145} 146 147void 148present_send_complete_notify(WindowPtr window, CARD8 kind, CARD8 mode, CARD32 serial, uint64_t ust, uint64_t msc) 149{ 150 present_window_priv_ptr window_priv = present_window_priv(window); 151 152 if (window_priv) { 153 xPresentCompleteNotify cn = { 154 .type = GenericEvent, 155 .extension = present_request, 156 .length = (sizeof(xPresentCompleteNotify) - 32) >> 2, 157 .evtype = PresentCompleteNotify, 158 .kind = kind, 159 .mode = mode, 160 .eid = 0, 161 .window = window->drawable.id, 162 .serial = serial, 163 .ust = ust, 164 .msc = msc, 165 }; 166 present_event_ptr event; 167 168 for (event = window_priv->events; event; event = event->next) { 169 if (event->mask & PresentCompleteNotifyMask) { 170 cn.eid = event->id; 171 WriteEventsToClient(event->client, 1, (xEvent *) &cn); 172 } 173 } 174 } 175 if (complete_notify) 176 (*complete_notify)(window, kind, mode, serial, ust, msc); 177} 178 179void 180present_send_idle_notify(WindowPtr window, CARD32 serial, PixmapPtr pixmap, struct present_fence *idle_fence) 181{ 182 present_window_priv_ptr window_priv = present_window_priv(window); 183 184 if (window_priv) { 185 xPresentIdleNotify in = { 186 .type = GenericEvent, 187 .extension = present_request, 188 .length = (sizeof(xPresentIdleNotify) - 32) >> 2, 189 .evtype = PresentIdleNotify, 190 .eid = 0, 191 .window = window->drawable.id, 192 .serial = serial, 193 .pixmap = pixmap->drawable.id, 194 .idle_fence = present_fence_id(idle_fence) 195 }; 196 present_event_ptr event; 197 198 for (event = window_priv->events; event; event = event->next) { 199 if (event->mask & PresentIdleNotifyMask) { 200 in.eid = event->id; 201 WriteEventsToClient(event->client, 1, (xEvent *) &in); 202 } 203 } 204 } 205} 206 207int 208present_select_input(ClientPtr client, XID eid, WindowPtr window, CARD32 mask) 209{ 210 present_window_priv_ptr window_priv; 211 present_event_ptr event; 212 int ret; 213 214 /* Check to see if we're modifying an existing event selection */ 215 ret = dixLookupResourceByType((void **) &event, eid, present_event_type, 216 client, DixWriteAccess); 217 if (ret == Success) { 218 /* Match error for the wrong window; also don't modify some other 219 * client's event selection 220 */ 221 if (event->window != window || event->client != client) 222 return BadMatch; 223 224 if (mask) 225 event->mask = mask; 226 else 227 FreeResource(eid, RT_NONE); 228 return Success; 229 } 230 if (ret != BadValue) 231 return ret; 232 233 if (mask == 0) 234 return Success; 235 236 LEGAL_NEW_RESOURCE(eid, client); 237 238 window_priv = present_get_window_priv(window, TRUE); 239 if (!window_priv) 240 return BadAlloc; 241 242 event = calloc (1, sizeof (present_event_rec)); 243 if (!event) 244 return BadAlloc; 245 246 event->client = client; 247 event->window = window; 248 event->id = eid; 249 event->mask = mask; 250 251 event->next = window_priv->events; 252 window_priv->events = event; 253 254 if (!AddResource(event->id, present_event_type, (void *) event)) 255 return BadAlloc; 256 257 return Success; 258} 259 260Bool 261present_event_init(void) 262{ 263 present_event_type = CreateNewResourceType(present_free_event, "PresentEvent"); 264 if (!present_event_type) 265 return FALSE; 266 267 GERegisterExtension(present_request, present_event_swap); 268 return TRUE; 269} 270