00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include <assert.h>
00032
00033 #undef DEBUG_SPEW
00034 #ifdef DEBUG_SPEW
00035 #include <stdio.h>
00036 #endif
00037
00038 #include "async-getprop.h"
00039
00040 #define NEED_REPLIES
00041 #include <X11/Xlibint.h>
00042
00043 #ifndef NULL
00044 #define NULL ((void*)0)
00045 #endif
00046
00047 typedef struct _ListNode ListNode;
00048 typedef struct _AgPerDisplayData AgPerDisplayData;
00049
00050 struct _ListNode
00051 {
00052 ListNode *next;
00053 };
00054
00055 struct _AgGetPropertyTask
00056 {
00057 ListNode node;
00058
00059 AgPerDisplayData *dd;
00060 Window window;
00061 Atom property;
00062
00063 unsigned long request_seq;
00064 int error;
00065
00066 Atom actual_type;
00067 int actual_format;
00068
00069 unsigned long n_items;
00070 unsigned long bytes_after;
00071 char *data;
00072
00073 Bool have_reply;
00074 };
00075
00076 struct _AgPerDisplayData
00077 {
00078 ListNode node;
00079 _XAsyncHandler async;
00080
00081 Display *display;
00082 ListNode *pending_tasks;
00083 ListNode *pending_tasks_tail;
00084 ListNode *completed_tasks;
00085 ListNode *completed_tasks_tail;
00086 int n_tasks_pending;
00087 int n_tasks_completed;
00088 };
00089
00090 static ListNode *display_datas = NULL;
00091 static ListNode *display_datas_tail = NULL;
00092
00093 static void
00094 append_to_list (ListNode **head,
00095 ListNode **tail,
00096 ListNode *task)
00097 {
00098 task->next = NULL;
00099
00100 if (*tail == NULL)
00101 {
00102 assert (*head == NULL);
00103 *head = task;
00104 *tail = task;
00105 }
00106 else
00107 {
00108 (*tail)->next = task;
00109 *tail = task;
00110 }
00111 }
00112
00113 static void
00114 remove_from_list (ListNode **head,
00115 ListNode **tail,
00116 ListNode *task)
00117 {
00118 ListNode *prev;
00119 ListNode *node;
00120
00121 prev = NULL;
00122 node = *head;
00123 while (node != NULL)
00124 {
00125 if (node == task)
00126 {
00127 if (prev)
00128 prev->next = node->next;
00129 else
00130 *head = node->next;
00131
00132 if (node == *tail)
00133 *tail = prev;
00134
00135 break;
00136 }
00137
00138 prev = node;
00139 node = node->next;
00140 }
00141
00142
00143 assert (node != NULL);
00144
00145 node->next = NULL;
00146 }
00147
00148 static void
00149 move_to_completed (AgPerDisplayData *dd,
00150 AgGetPropertyTask *task)
00151 {
00152 remove_from_list (&dd->pending_tasks,
00153 &dd->pending_tasks_tail,
00154 &task->node);
00155
00156 append_to_list (&dd->completed_tasks,
00157 &dd->completed_tasks_tail,
00158 &task->node);
00159
00160 dd->n_tasks_pending -= 1;
00161 dd->n_tasks_completed += 1;
00162 }
00163
00164 static AgGetPropertyTask*
00165 find_pending_by_request_sequence (AgPerDisplayData *dd,
00166 unsigned long request_seq)
00167 {
00168 ListNode *node;
00169
00170
00171
00172
00173 {
00174 AgGetPropertyTask *task = (AgGetPropertyTask*) dd->pending_tasks_tail;
00175 if (task != NULL)
00176 {
00177 if (task->request_seq < request_seq)
00178 return NULL;
00179 else if (task->request_seq == request_seq)
00180 return task;
00181 }
00182 }
00183
00184
00185
00186
00187
00188
00189
00190
00191 node = dd->pending_tasks;
00192 while (node != NULL)
00193 {
00194 AgGetPropertyTask *task = (AgGetPropertyTask*) node;
00195
00196 if (task->request_seq == request_seq)
00197 return task;
00198
00199 node = node->next;
00200 }
00201
00202 return NULL;
00203 }
00204
00205 static Bool
00206 async_get_property_handler (Display *dpy,
00207 xReply *rep,
00208 char *buf,
00209 int len,
00210 XPointer data)
00211 {
00212 xGetPropertyReply replbuf;
00213 xGetPropertyReply *reply;
00214 AgGetPropertyTask *task;
00215 AgPerDisplayData *dd;
00216 int bytes_read;
00217
00218 dd = (AgPerDisplayData*) data;
00219
00220 #if 0
00221 printf ("%s: seeing request seq %ld buflen %d\n", __FUNCTION__,
00222 dpy->last_request_read, len);
00223 #endif
00224
00225 task = find_pending_by_request_sequence (dd, dpy->last_request_read);
00226
00227 if (task == NULL)
00228 return False;
00229
00230 assert (dpy->last_request_read == task->request_seq);
00231
00232 task->have_reply = True;
00233 move_to_completed (dd, task);
00234
00235
00236 bytes_read = SIZEOF (xReply);
00237
00238 if (rep->generic.type == X_Error)
00239 {
00240 xError errbuf;
00241
00242 task->error = rep->error.errorCode;
00243
00244 #ifdef DEBUG_SPEW
00245 printf ("%s: error code = %d (ignoring error, eating %d bytes, generic.length = %ld)\n",
00246 __FUNCTION__, task->error, (SIZEOF (xError) - bytes_read),
00247 rep->generic.length);
00248 #endif
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263 _XGetAsyncReply (dpy, (char *)&errbuf, rep, buf, len,
00264 (SIZEOF (xError) - bytes_read) >> 2,
00265 False);
00266
00267 return True;
00268 }
00269
00270 #ifdef DEBUG_SPEW
00271 printf ("%s: already read %d bytes reading %d more for total of %d; generic.length = %ld\n",
00272 __FUNCTION__, bytes_read, (SIZEOF (xGetPropertyReply) - bytes_read) >> 2,
00273 SIZEOF (xGetPropertyReply), rep->generic.length);
00274 #endif
00275
00276
00277 reply = (xGetPropertyReply *)
00278 _XGetAsyncReply (dpy, (char *)&replbuf, rep, buf, len,
00279 (SIZEOF (xGetPropertyReply) - bytes_read) >> 2,
00280 False);
00281
00282
00283
00284 bytes_read = SIZEOF (xGetPropertyReply);
00285
00286 #ifdef DEBUG_SPEW
00287 printf ("%s: have reply propertyType = %ld format = %d n_items = %ld\n",
00288 __FUNCTION__, reply->propertyType, reply->format, reply->nItems);
00289 #endif
00290
00291 assert (task->data == NULL);
00292
00293
00294
00295
00296
00297
00298
00299
00300 if (reply->propertyType != None)
00301 {
00302 long nbytes, netbytes;
00303
00304
00305 #define ALIGN_VALUE(this, boundary) \
00306 (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
00307
00308 switch (reply->format)
00309 {
00310
00311
00312
00313
00314
00315
00316 case 8:
00317 nbytes = reply->nItems;
00318
00319 netbytes = ALIGN_VALUE (nbytes, 4);
00320 if (nbytes + 1 > 0 &&
00321 (task->data = (char *) Xmalloc ((unsigned)nbytes + 1)))
00322 {
00323 #ifdef DEBUG_SPEW
00324 printf ("%s: already read %d bytes using %ld, more eating %ld more\n",
00325 __FUNCTION__, bytes_read, nbytes, netbytes);
00326 #endif
00327
00328 _XGetAsyncData (dpy, task->data, buf, len,
00329 bytes_read, nbytes,
00330 netbytes);
00331 }
00332 break;
00333
00334 case 16:
00335 nbytes = reply->nItems * sizeof (short);
00336 netbytes = reply->nItems << 1;
00337 netbytes = ALIGN_VALUE (netbytes, 4);
00338 if (nbytes + 1 > 0 &&
00339 (task->data = (char *) Xmalloc ((unsigned)nbytes + 1)))
00340 {
00341 #ifdef DEBUG_SPEW
00342 printf ("%s: already read %d bytes using %ld more, eating %ld more\n",
00343 __FUNCTION__, bytes_read, nbytes, netbytes);
00344 #endif
00345
00346 _XGetAsyncData (dpy, task->data, buf, len,
00347 bytes_read, nbytes, netbytes);
00348 }
00349 break;
00350
00351 case 32:
00352
00353 nbytes = reply->nItems * sizeof (long);
00354 netbytes = reply->nItems << 2;
00355 if (nbytes + 1 > 0 &&
00356 (task->data = (char *) Xmalloc ((unsigned)nbytes + 1)))
00357 {
00358 #ifdef DEBUG_SPEW
00359 printf ("%s: already read %d bytes using %ld more, eating %ld more\n",
00360 __FUNCTION__, bytes_read, nbytes, netbytes);
00361 #endif
00362
00363
00364
00365
00366 if (sizeof (long) == 8)
00367 {
00368 char *netdata;
00369 char *lptr;
00370 char *end_lptr;
00371
00372
00373 netdata = task->data + nbytes / 2;
00374
00375 _XGetAsyncData (dpy, netdata, buf, len,
00376 bytes_read, netbytes,
00377 netbytes);
00378
00379
00380
00381 lptr = task->data;
00382 end_lptr = task->data + nbytes;
00383 while (lptr != end_lptr)
00384 {
00385 *(long*) lptr = *(CARD32*) netdata;
00386 lptr += sizeof (long);
00387 netdata += sizeof (CARD32);
00388 }
00389 }
00390 else
00391 {
00392
00393 _XGetAsyncData (dpy, task->data, buf, len,
00394 bytes_read, netbytes,
00395 netbytes);
00396 }
00397 }
00398 break;
00399
00400 default:
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410 {
00411 #if 0
00412 xError error;
00413 #endif
00414
00415 task->error = BadImplementation;
00416
00417 #if 0
00418 error.sequenceNumber = task->request_seq;
00419 error.type = X_Error;
00420 error.majorCode = X_GetProperty;
00421 error.minorCode = 0;
00422 error.errorCode = BadImplementation;
00423
00424 _XError (dpy, &error);
00425 #endif
00426 }
00427
00428 nbytes = netbytes = 0L;
00429 break;
00430 }
00431
00432 if (task->data == NULL)
00433 {
00434 task->error = BadAlloc;
00435
00436 #ifdef DEBUG_SPEW
00437 printf ("%s: already read %d bytes eating %ld\n",
00438 __FUNCTION__, bytes_read, netbytes);
00439 #endif
00440
00441 _XGetAsyncData (dpy, NULL, buf, len,
00442 bytes_read, 0, netbytes);
00443
00444
00445 return BadAlloc;
00446 }
00447
00448 (task->data)[nbytes] = '\0';
00449 }
00450
00451 #ifdef DEBUG_SPEW
00452 printf ("%s: have data\n", __FUNCTION__);
00453 #endif
00454
00455 task->actual_type = reply->propertyType;
00456 task->actual_format = reply->format;
00457 task->n_items = reply->nItems;
00458 task->bytes_after = reply->bytesAfter;
00459
00460
00461
00462 return True;
00463 }
00464
00465 static AgPerDisplayData*
00466 get_display_data (Display *display,
00467 Bool create)
00468 {
00469 ListNode *node;
00470 AgPerDisplayData *dd;
00471
00472 node = display_datas;
00473 while (node != NULL)
00474 {
00475 dd = (AgPerDisplayData*) node;
00476
00477 if (dd->display == display)
00478 return dd;
00479
00480 node = node->next;
00481 }
00482
00483 if (!create)
00484 return NULL;
00485
00486 dd = Xcalloc (1, sizeof (AgPerDisplayData));
00487 if (dd == NULL)
00488 return NULL;
00489
00490 dd->display = display;
00491 dd->async.next = display->async_handlers;
00492 dd->async.handler = async_get_property_handler;
00493 dd->async.data = (XPointer) dd;
00494 dd->display->async_handlers = &dd->async;
00495
00496 append_to_list (&display_datas,
00497 &display_datas_tail,
00498 &dd->node);
00499
00500 return dd;
00501 }
00502
00503 static void
00504 maybe_free_display_data (AgPerDisplayData *dd)
00505 {
00506 if (dd->pending_tasks == NULL &&
00507 dd->completed_tasks == NULL)
00508 {
00509 DeqAsyncHandler (dd->display, &dd->async);
00510 remove_from_list (&display_datas, &display_datas_tail,
00511 &dd->node);
00512 XFree (dd);
00513 }
00514 }
00515
00516 AgGetPropertyTask*
00517 ag_task_create (Display *dpy,
00518 Window window,
00519 Atom property,
00520 long offset,
00521 long length,
00522 Bool delete,
00523 Atom req_type)
00524 {
00525 AgGetPropertyTask *task;
00526 xGetPropertyReq *req;
00527 AgPerDisplayData *dd;
00528
00529
00530 LockDisplay (dpy);
00531
00532 dd = get_display_data (dpy, True);
00533 if (dd == NULL)
00534 {
00535 UnlockDisplay (dpy);
00536 return NULL;
00537 }
00538
00539 GetReq (GetProperty, req);
00540 req->window = window;
00541 req->property = property;
00542 req->type = req_type;
00543 req->delete = delete;
00544 req->longOffset = offset;
00545 req->longLength = length;
00546
00547
00548 task = Xcalloc (1, sizeof (AgGetPropertyTask));
00549 if (task == NULL)
00550 {
00551 UnlockDisplay (dpy);
00552 return NULL;
00553 }
00554
00555 task->dd = dd;
00556 task->window = window;
00557 task->property = property;
00558 task->request_seq = dpy->request;
00559
00560 append_to_list (&dd->pending_tasks,
00561 &dd->pending_tasks_tail,
00562 &task->node);
00563 dd->n_tasks_pending += 1;
00564
00565 UnlockDisplay (dpy);
00566
00567 SyncHandle ();
00568
00569 return task;
00570 }
00571
00572 static void
00573 free_task (AgGetPropertyTask *task)
00574 {
00575 remove_from_list (&task->dd->completed_tasks,
00576 &task->dd->completed_tasks_tail,
00577 &task->node);
00578 task->dd->n_tasks_completed -= 1;
00579 maybe_free_display_data (task->dd);
00580 XFree (task);
00581 }
00582
00583 Status
00584 ag_task_get_reply_and_free (AgGetPropertyTask *task,
00585 Atom *actual_type,
00586 int *actual_format,
00587 unsigned long *nitems,
00588 unsigned long *bytesafter,
00589 char **prop)
00590 {
00591 Display *dpy;
00592
00593 *prop = NULL;
00594
00595 dpy = task->dd->display;
00596
00597 if (task->error != Success)
00598 {
00599 Status s = task->error;
00600
00601 free_task (task);
00602
00603 return s;
00604 }
00605
00606 if (!task->have_reply)
00607 {
00608 free_task (task);
00609
00610 return BadAlloc;
00611 }
00612
00613 *actual_type = task->actual_type;
00614 *actual_format = task->actual_format;
00615 *nitems = task->n_items;
00616 *bytesafter = task->bytes_after;
00617
00618 *prop = task->data;
00619
00620 SyncHandle ();
00621
00622 free_task (task);
00623
00624 return Success;
00625 }
00626
00627 Bool
00628 ag_task_have_reply (AgGetPropertyTask *task)
00629 {
00630 return task->have_reply;
00631 }
00632
00633 Atom
00634 ag_task_get_property (AgGetPropertyTask *task)
00635 {
00636 return task->property;
00637 }
00638
00639 Window
00640 ag_task_get_window (AgGetPropertyTask *task)
00641 {
00642 return task->window;
00643 }
00644
00645 Display*
00646 ag_task_get_display (AgGetPropertyTask *task)
00647 {
00648 return task->dd->display;
00649 }
00650
00651 AgGetPropertyTask*
00652 ag_get_next_completed_task (Display *display)
00653 {
00654 AgPerDisplayData *dd;
00655
00656 dd = get_display_data (display, False);
00657
00658 if (dd == NULL)
00659 return NULL;
00660
00661 #ifdef DEBUG_SPEW
00662 printf ("%d pending %d completed\n",
00663 dd->n_tasks_pending,
00664 dd->n_tasks_completed);
00665 #endif
00666
00667 return (AgGetPropertyTask*) dd->completed_tasks;
00668 }
00669
00670 void*
00671 ag_Xmalloc (unsigned long bytes)
00672 {
00673 return (void*) Xmalloc (bytes);
00674 }
00675
00676 void*
00677 ag_Xmalloc0 (unsigned long bytes)
00678 {
00679 return (void*) Xcalloc (bytes, 1);
00680 }