x11: Remove async-getprop
xcb can do this for us now.
This commit is contained in:
parent
82a7060cdb
commit
0e73ceb4bd
@ -41,9 +41,6 @@ endif
|
|||||||
# Some random test programs for bits of the code
|
# Some random test programs for bits of the code
|
||||||
|
|
||||||
testboxes_SOURCES = core/testboxes.c
|
testboxes_SOURCES = core/testboxes.c
|
||||||
testasyncgetprop_SOURCES = x11/testasyncgetprop.c
|
|
||||||
|
|
||||||
noinst_PROGRAMS+=testboxes testasyncgetprop
|
|
||||||
|
|
||||||
testboxes_LDADD = $(MUTTER_LIBS) libmutter.la
|
testboxes_LDADD = $(MUTTER_LIBS) libmutter.la
|
||||||
testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter.la
|
|
||||||
|
noinst_PROGRAMS += testboxes
|
||||||
|
@ -210,8 +210,6 @@ libmutter_la_SOURCES = \
|
|||||||
meta/theme.h \
|
meta/theme.h \
|
||||||
ui/theme-private.h \
|
ui/theme-private.h \
|
||||||
ui/ui.c \
|
ui/ui.c \
|
||||||
x11/async-getprop.c \
|
|
||||||
x11/async-getprop.h \
|
|
||||||
x11/atomnames.h \
|
x11/atomnames.h \
|
||||||
x11/events.c \
|
x11/events.c \
|
||||||
x11/events.h \
|
x11/events.h \
|
||||||
|
@ -1,680 +0,0 @@
|
|||||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
||||||
|
|
||||||
/* Asynchronous X property getting hack */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2002 Havoc Pennington
|
|
||||||
* Copyright (C) 1986, 1998 The Open Group
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, distribute, and sell this software
|
|
||||||
* and its documentation for any purpose is hereby granted without
|
|
||||||
* fee, provided that the above copyright notice appear in all copies
|
|
||||||
* and that both that copyright notice and this permission notice
|
|
||||||
* appear in supporting documentation.
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR
|
|
||||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
||||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*
|
|
||||||
* Except as contained in this notice, the name of The Open Group shall not be
|
|
||||||
* used in advertising or otherwise to promote the sale, use or other dealings
|
|
||||||
* in this Software without prior written authorization from The Open Group.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#undef DEBUG_SPEW
|
|
||||||
#ifdef DEBUG_SPEW
|
|
||||||
#include <stdio.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "async-getprop.h"
|
|
||||||
|
|
||||||
#define NEED_REPLIES
|
|
||||||
#include <X11/Xlibint.h>
|
|
||||||
|
|
||||||
#ifndef NULL
|
|
||||||
#define NULL ((void*)0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct _ListNode ListNode;
|
|
||||||
typedef struct _AgPerDisplayData AgPerDisplayData;
|
|
||||||
|
|
||||||
struct _ListNode
|
|
||||||
{
|
|
||||||
ListNode *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _AgGetPropertyTask
|
|
||||||
{
|
|
||||||
ListNode node;
|
|
||||||
|
|
||||||
AgPerDisplayData *dd;
|
|
||||||
Window window;
|
|
||||||
Atom property;
|
|
||||||
|
|
||||||
unsigned long request_seq;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
Atom actual_type;
|
|
||||||
int actual_format;
|
|
||||||
|
|
||||||
unsigned long n_items;
|
|
||||||
unsigned long bytes_after;
|
|
||||||
char *data;
|
|
||||||
|
|
||||||
Bool have_reply;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _AgPerDisplayData
|
|
||||||
{
|
|
||||||
ListNode node;
|
|
||||||
_XAsyncHandler async;
|
|
||||||
|
|
||||||
Display *display;
|
|
||||||
ListNode *pending_tasks;
|
|
||||||
ListNode *pending_tasks_tail;
|
|
||||||
ListNode *completed_tasks;
|
|
||||||
ListNode *completed_tasks_tail;
|
|
||||||
int n_tasks_pending;
|
|
||||||
int n_tasks_completed;
|
|
||||||
};
|
|
||||||
|
|
||||||
static ListNode *display_datas = NULL;
|
|
||||||
static ListNode *display_datas_tail = NULL;
|
|
||||||
|
|
||||||
static void
|
|
||||||
append_to_list (ListNode **head,
|
|
||||||
ListNode **tail,
|
|
||||||
ListNode *task)
|
|
||||||
{
|
|
||||||
task->next = NULL;
|
|
||||||
|
|
||||||
if (*tail == NULL)
|
|
||||||
{
|
|
||||||
assert (*head == NULL);
|
|
||||||
*head = task;
|
|
||||||
*tail = task;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
(*tail)->next = task;
|
|
||||||
*tail = task;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
remove_from_list (ListNode **head,
|
|
||||||
ListNode **tail,
|
|
||||||
ListNode *task)
|
|
||||||
{
|
|
||||||
ListNode *prev;
|
|
||||||
ListNode *node;
|
|
||||||
|
|
||||||
prev = NULL;
|
|
||||||
node = *head;
|
|
||||||
while (node != NULL)
|
|
||||||
{
|
|
||||||
if (node == task)
|
|
||||||
{
|
|
||||||
if (prev)
|
|
||||||
prev->next = node->next;
|
|
||||||
else
|
|
||||||
*head = node->next;
|
|
||||||
|
|
||||||
if (node == *tail)
|
|
||||||
*tail = prev;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
prev = node;
|
|
||||||
node = node->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* can't remove what's not there */
|
|
||||||
assert (node != NULL);
|
|
||||||
|
|
||||||
node->next = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
move_to_completed (AgPerDisplayData *dd,
|
|
||||||
AgGetPropertyTask *task)
|
|
||||||
{
|
|
||||||
remove_from_list (&dd->pending_tasks,
|
|
||||||
&dd->pending_tasks_tail,
|
|
||||||
&task->node);
|
|
||||||
|
|
||||||
append_to_list (&dd->completed_tasks,
|
|
||||||
&dd->completed_tasks_tail,
|
|
||||||
&task->node);
|
|
||||||
|
|
||||||
dd->n_tasks_pending -= 1;
|
|
||||||
dd->n_tasks_completed += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static AgGetPropertyTask*
|
|
||||||
find_pending_by_request_sequence (AgPerDisplayData *dd,
|
|
||||||
unsigned long request_seq)
|
|
||||||
{
|
|
||||||
ListNode *node;
|
|
||||||
|
|
||||||
/* if the sequence is after our last pending task, we
|
|
||||||
* aren't going to find a match
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
AgGetPropertyTask *task = (AgGetPropertyTask*) dd->pending_tasks_tail;
|
|
||||||
if (task != NULL)
|
|
||||||
{
|
|
||||||
if (task->request_seq < request_seq)
|
|
||||||
return NULL;
|
|
||||||
else if (task->request_seq == request_seq)
|
|
||||||
return task; /* why not check this */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Generally we should get replies in the order we sent
|
|
||||||
* requests, so we should usually be using the task
|
|
||||||
* at the head of the list, if we use any task at all.
|
|
||||||
* I'm not sure this is 100% guaranteed, if it is,
|
|
||||||
* it would be a big speedup.
|
|
||||||
*/
|
|
||||||
|
|
||||||
node = dd->pending_tasks;
|
|
||||||
while (node != NULL)
|
|
||||||
{
|
|
||||||
AgGetPropertyTask *task = (AgGetPropertyTask*) node;
|
|
||||||
|
|
||||||
if (task->request_seq == request_seq)
|
|
||||||
return task;
|
|
||||||
|
|
||||||
node = node->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Bool
|
|
||||||
async_get_property_handler (Display *dpy,
|
|
||||||
xReply *rep,
|
|
||||||
char *buf,
|
|
||||||
int len,
|
|
||||||
XPointer data)
|
|
||||||
{
|
|
||||||
xGetPropertyReply replbuf;
|
|
||||||
xGetPropertyReply *reply;
|
|
||||||
AgGetPropertyTask *task;
|
|
||||||
AgPerDisplayData *dd;
|
|
||||||
int bytes_read;
|
|
||||||
|
|
||||||
dd = (AgPerDisplayData*) data;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
printf ("%s: seeing request seq %ld buflen %d\n", __FUNCTION__,
|
|
||||||
dpy->last_request_read, len);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
task = find_pending_by_request_sequence (dd, dpy->last_request_read);
|
|
||||||
|
|
||||||
if (task == NULL)
|
|
||||||
return False;
|
|
||||||
|
|
||||||
assert (dpy->last_request_read == task->request_seq);
|
|
||||||
|
|
||||||
task->have_reply = True;
|
|
||||||
move_to_completed (dd, task);
|
|
||||||
|
|
||||||
/* read bytes so far */
|
|
||||||
bytes_read = SIZEOF (xReply);
|
|
||||||
|
|
||||||
if (rep->generic.type == X_Error)
|
|
||||||
{
|
|
||||||
xError errbuf;
|
|
||||||
|
|
||||||
task->error = rep->error.errorCode;
|
|
||||||
|
|
||||||
#ifdef DEBUG_SPEW
|
|
||||||
printf ("%s: error code = %d (ignoring error, eating %d bytes, generic.length = %ld)\n",
|
|
||||||
__FUNCTION__, task->error, (SIZEOF (xError) - bytes_read),
|
|
||||||
rep->generic.length);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* We return True (meaning we consumed the reply)
|
|
||||||
* because otherwise it would invoke the X error handler,
|
|
||||||
* and an async API is useless if you have to synchronously
|
|
||||||
* trap X errors. Also GetProperty can always fail, pretty
|
|
||||||
* much, so trapping errors is always what you want.
|
|
||||||
*
|
|
||||||
* We have to eat all the error reply data here.
|
|
||||||
* (kind of a charade as we know sizeof(xError) == sizeof(xReply))
|
|
||||||
*
|
|
||||||
* Passing discard = True seems to break things; I don't understand
|
|
||||||
* why, because there should be no extra data in an error reply,
|
|
||||||
* right?
|
|
||||||
*/
|
|
||||||
_XGetAsyncReply (dpy, (char *)&errbuf, rep, buf, len,
|
|
||||||
(SIZEOF (xError) - bytes_read) >> 2, /* in 32-bit words */
|
|
||||||
False); /* really seems like it should be True */
|
|
||||||
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_SPEW
|
|
||||||
printf ("%s: already read %d bytes reading %d more for total of %d; generic.length = %ld\n",
|
|
||||||
__FUNCTION__, bytes_read, (SIZEOF (xGetPropertyReply) - bytes_read) >> 2,
|
|
||||||
SIZEOF (xGetPropertyReply), rep->generic.length);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* (kind of a silly as we know sizeof(xGetPropertyReply) == sizeof(xReply)) */
|
|
||||||
reply = (xGetPropertyReply *)
|
|
||||||
_XGetAsyncReply (dpy, (char *)&replbuf, rep, buf, len,
|
|
||||||
(SIZEOF (xGetPropertyReply) - bytes_read) >> 2, /* in 32-bit words */
|
|
||||||
False); /* False means expecting more data to follow,
|
|
||||||
* don't eat the rest of the reply
|
|
||||||
*/
|
|
||||||
|
|
||||||
bytes_read = SIZEOF (xGetPropertyReply);
|
|
||||||
|
|
||||||
#ifdef DEBUG_SPEW
|
|
||||||
printf ("%s: have reply propertyType = %ld format = %d n_items = %ld\n",
|
|
||||||
__FUNCTION__, reply->propertyType, reply->format, reply->nItems);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
assert (task->data == NULL);
|
|
||||||
|
|
||||||
/* This is all copied from XGetWindowProperty(). Not sure we should
|
|
||||||
* LockDisplay(). Not sure I'm passing the right args to
|
|
||||||
* XGetAsyncData(). Not sure about a lot of things.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* LockDisplay (dpy); */
|
|
||||||
|
|
||||||
if (reply->propertyType != None)
|
|
||||||
{
|
|
||||||
long nbytes, netbytes;
|
|
||||||
|
|
||||||
/* this alignment macro from orbit2 */
|
|
||||||
#define ALIGN_VALUE(this, boundary) \
|
|
||||||
(( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
|
|
||||||
|
|
||||||
switch (reply->format)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* One extra byte is malloced than is needed to contain the property
|
|
||||||
* data, but this last byte is null terminated and convenient for
|
|
||||||
* returning string properties, so the client doesn't then have to
|
|
||||||
* recopy the string to make it null terminated.
|
|
||||||
*/
|
|
||||||
case 8:
|
|
||||||
nbytes = reply->nItems;
|
|
||||||
/* there's padding to word boundary */
|
|
||||||
netbytes = ALIGN_VALUE (nbytes, 4);
|
|
||||||
if (nbytes + 1 > 0 &&
|
|
||||||
(task->data = (char *) Xmalloc ((unsigned)nbytes + 1)))
|
|
||||||
{
|
|
||||||
#ifdef DEBUG_SPEW
|
|
||||||
printf ("%s: already read %d bytes using %ld, more eating %ld more\n",
|
|
||||||
__FUNCTION__, bytes_read, nbytes, netbytes);
|
|
||||||
#endif
|
|
||||||
/* _XReadPad (dpy, (char *) task->data, netbytes); */
|
|
||||||
_XGetAsyncData (dpy, task->data, buf, len,
|
|
||||||
bytes_read, nbytes,
|
|
||||||
netbytes);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 16:
|
|
||||||
nbytes = reply->nItems * sizeof (short);
|
|
||||||
netbytes = reply->nItems << 1;
|
|
||||||
netbytes = ALIGN_VALUE (netbytes, 4); /* align to word boundary */
|
|
||||||
if (nbytes + 1 > 0 &&
|
|
||||||
(task->data = (char *) Xmalloc ((unsigned)nbytes + 1)))
|
|
||||||
{
|
|
||||||
#ifdef DEBUG_SPEW
|
|
||||||
printf ("%s: already read %d bytes using %ld more, eating %ld more\n",
|
|
||||||
__FUNCTION__, bytes_read, nbytes, netbytes);
|
|
||||||
#endif
|
|
||||||
/* _XRead16Pad (dpy, (short *) task->data, netbytes); */
|
|
||||||
_XGetAsyncData (dpy, task->data, buf, len,
|
|
||||||
bytes_read, nbytes, netbytes);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 32:
|
|
||||||
/* NOTE buffer is in longs to match XGetWindowProperty() */
|
|
||||||
nbytes = reply->nItems * sizeof (long);
|
|
||||||
netbytes = reply->nItems << 2; /* wire size is always 32 bits though */
|
|
||||||
if (nbytes + 1 > 0 &&
|
|
||||||
(task->data = (char *) Xmalloc ((unsigned)nbytes + 1)))
|
|
||||||
{
|
|
||||||
#ifdef DEBUG_SPEW
|
|
||||||
printf ("%s: already read %d bytes using %ld more, eating %ld more\n",
|
|
||||||
__FUNCTION__, bytes_read, nbytes, netbytes);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* We have to copy the XGetWindowProperty() crackrock
|
|
||||||
* and get format 32 as long even on 64-bit platforms.
|
|
||||||
*/
|
|
||||||
if (sizeof (long) == 8)
|
|
||||||
{
|
|
||||||
char *netdata;
|
|
||||||
char *lptr;
|
|
||||||
char *end_lptr;
|
|
||||||
|
|
||||||
/* Store the 32-bit values in the end of the array */
|
|
||||||
netdata = task->data + nbytes / 2;
|
|
||||||
|
|
||||||
_XGetAsyncData (dpy, netdata, buf, len,
|
|
||||||
bytes_read, netbytes,
|
|
||||||
netbytes);
|
|
||||||
|
|
||||||
/* Now move the 32-bit values to the front */
|
|
||||||
|
|
||||||
lptr = task->data;
|
|
||||||
end_lptr = task->data + nbytes;
|
|
||||||
while (lptr != end_lptr)
|
|
||||||
{
|
|
||||||
*(long*) lptr = *(CARD32*) netdata;
|
|
||||||
lptr += sizeof (long);
|
|
||||||
netdata += sizeof (CARD32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Here the wire format matches our actual format */
|
|
||||||
_XGetAsyncData (dpy, task->data, buf, len,
|
|
||||||
bytes_read, netbytes,
|
|
||||||
netbytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
/*
|
|
||||||
* This part of the code should never be reached. If it is,
|
|
||||||
* the server sent back a property with an invalid format.
|
|
||||||
* This is a BadImplementation error.
|
|
||||||
*
|
|
||||||
* However this async GetProperty API doesn't report errors
|
|
||||||
* via the standard X mechanism, so don't do anything about
|
|
||||||
* it, other than store it in task->error.
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
xError error;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
task->error = BadImplementation;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
error.sequenceNumber = task->request_seq;
|
|
||||||
error.type = X_Error;
|
|
||||||
error.majorCode = X_GetProperty;
|
|
||||||
error.minorCode = 0;
|
|
||||||
error.errorCode = BadImplementation;
|
|
||||||
|
|
||||||
_XError (dpy, &error);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
nbytes = netbytes = 0L;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (task->data == NULL)
|
|
||||||
{
|
|
||||||
task->error = BadAlloc;
|
|
||||||
|
|
||||||
#ifdef DEBUG_SPEW
|
|
||||||
printf ("%s: already read %d bytes eating %ld\n",
|
|
||||||
__FUNCTION__, bytes_read, netbytes);
|
|
||||||
#endif
|
|
||||||
/* _XEatData (dpy, (unsigned long) netbytes); */
|
|
||||||
_XGetAsyncData (dpy, NULL, buf, len,
|
|
||||||
bytes_read, 0, netbytes);
|
|
||||||
|
|
||||||
/* UnlockDisplay (dpy); */
|
|
||||||
return BadAlloc; /* not Success */
|
|
||||||
}
|
|
||||||
|
|
||||||
(task->data)[nbytes] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_SPEW
|
|
||||||
printf ("%s: have data\n", __FUNCTION__);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
task->actual_type = reply->propertyType;
|
|
||||||
task->actual_format = reply->format;
|
|
||||||
task->n_items = reply->nItems;
|
|
||||||
task->bytes_after = reply->bytesAfter;
|
|
||||||
|
|
||||||
/* UnlockDisplay (dpy); */
|
|
||||||
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
static AgPerDisplayData*
|
|
||||||
get_display_data (Display *display,
|
|
||||||
Bool create)
|
|
||||||
{
|
|
||||||
ListNode *node;
|
|
||||||
AgPerDisplayData *dd;
|
|
||||||
|
|
||||||
node = display_datas;
|
|
||||||
while (node != NULL)
|
|
||||||
{
|
|
||||||
dd = (AgPerDisplayData*) node;
|
|
||||||
|
|
||||||
if (dd->display == display)
|
|
||||||
return dd;
|
|
||||||
|
|
||||||
node = node->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!create)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
dd = Xcalloc (1, sizeof (AgPerDisplayData));
|
|
||||||
if (dd == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
dd->display = display;
|
|
||||||
dd->async.next = display->async_handlers;
|
|
||||||
dd->async.handler = async_get_property_handler;
|
|
||||||
dd->async.data = (XPointer) dd;
|
|
||||||
dd->display->async_handlers = &dd->async;
|
|
||||||
|
|
||||||
append_to_list (&display_datas,
|
|
||||||
&display_datas_tail,
|
|
||||||
&dd->node);
|
|
||||||
|
|
||||||
return dd;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
maybe_free_display_data (AgPerDisplayData *dd)
|
|
||||||
{
|
|
||||||
if (dd->pending_tasks == NULL &&
|
|
||||||
dd->completed_tasks == NULL)
|
|
||||||
{
|
|
||||||
DeqAsyncHandler (dd->display, &dd->async);
|
|
||||||
remove_from_list (&display_datas, &display_datas_tail,
|
|
||||||
&dd->node);
|
|
||||||
XFree (dd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AgGetPropertyTask*
|
|
||||||
ag_task_create (Display *dpy,
|
|
||||||
Window window,
|
|
||||||
Atom property,
|
|
||||||
long offset,
|
|
||||||
long length,
|
|
||||||
Bool delete,
|
|
||||||
Atom req_type)
|
|
||||||
{
|
|
||||||
AgGetPropertyTask *task;
|
|
||||||
xGetPropertyReq *req;
|
|
||||||
AgPerDisplayData *dd;
|
|
||||||
|
|
||||||
/* Fire up our request */
|
|
||||||
LockDisplay (dpy);
|
|
||||||
|
|
||||||
dd = get_display_data (dpy, True);
|
|
||||||
if (dd == NULL)
|
|
||||||
{
|
|
||||||
UnlockDisplay (dpy);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
GetReq (GetProperty, req);
|
|
||||||
req->window = window;
|
|
||||||
req->property = property;
|
|
||||||
req->type = req_type;
|
|
||||||
req->delete = delete;
|
|
||||||
req->longOffset = offset;
|
|
||||||
req->longLength = length;
|
|
||||||
|
|
||||||
/* Queue up our async task */
|
|
||||||
task = Xcalloc (1, sizeof (AgGetPropertyTask));
|
|
||||||
if (task == NULL)
|
|
||||||
{
|
|
||||||
UnlockDisplay (dpy);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
task->dd = dd;
|
|
||||||
task->window = window;
|
|
||||||
task->property = property;
|
|
||||||
task->request_seq = dpy->request;
|
|
||||||
|
|
||||||
append_to_list (&dd->pending_tasks,
|
|
||||||
&dd->pending_tasks_tail,
|
|
||||||
&task->node);
|
|
||||||
dd->n_tasks_pending += 1;
|
|
||||||
|
|
||||||
UnlockDisplay (dpy);
|
|
||||||
|
|
||||||
SyncHandle ();
|
|
||||||
|
|
||||||
return task;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
free_task (AgGetPropertyTask *task)
|
|
||||||
{
|
|
||||||
remove_from_list (&task->dd->completed_tasks,
|
|
||||||
&task->dd->completed_tasks_tail,
|
|
||||||
&task->node);
|
|
||||||
task->dd->n_tasks_completed -= 1;
|
|
||||||
maybe_free_display_data (task->dd);
|
|
||||||
XFree (task);
|
|
||||||
}
|
|
||||||
|
|
||||||
Status
|
|
||||||
ag_task_get_reply_and_free (AgGetPropertyTask *task,
|
|
||||||
Atom *actual_type,
|
|
||||||
int *actual_format,
|
|
||||||
unsigned long *nitems,
|
|
||||||
unsigned long *bytesafter,
|
|
||||||
unsigned char **prop)
|
|
||||||
{
|
|
||||||
Display *dpy;
|
|
||||||
|
|
||||||
*prop = NULL;
|
|
||||||
|
|
||||||
dpy = task->dd->display; /* Xlib macros require a variable named "dpy" */
|
|
||||||
|
|
||||||
if (task->error != Success)
|
|
||||||
{
|
|
||||||
Status s = task->error;
|
|
||||||
|
|
||||||
free_task (task);
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!task->have_reply)
|
|
||||||
{
|
|
||||||
free_task (task);
|
|
||||||
|
|
||||||
return BadAlloc; /* not Success */
|
|
||||||
}
|
|
||||||
|
|
||||||
*actual_type = task->actual_type;
|
|
||||||
*actual_format = task->actual_format;
|
|
||||||
*nitems = task->n_items;
|
|
||||||
*bytesafter = task->bytes_after;
|
|
||||||
|
|
||||||
*prop = (unsigned char*) task->data; /* pass out ownership of task->data */
|
|
||||||
|
|
||||||
SyncHandle ();
|
|
||||||
|
|
||||||
free_task (task);
|
|
||||||
|
|
||||||
return Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool
|
|
||||||
ag_task_have_reply (AgGetPropertyTask *task)
|
|
||||||
{
|
|
||||||
return task->have_reply;
|
|
||||||
}
|
|
||||||
|
|
||||||
Atom
|
|
||||||
ag_task_get_property (AgGetPropertyTask *task)
|
|
||||||
{
|
|
||||||
return task->property;
|
|
||||||
}
|
|
||||||
|
|
||||||
Window
|
|
||||||
ag_task_get_window (AgGetPropertyTask *task)
|
|
||||||
{
|
|
||||||
return task->window;
|
|
||||||
}
|
|
||||||
|
|
||||||
Display*
|
|
||||||
ag_task_get_display (AgGetPropertyTask *task)
|
|
||||||
{
|
|
||||||
return task->dd->display;
|
|
||||||
}
|
|
||||||
|
|
||||||
AgGetPropertyTask*
|
|
||||||
ag_get_next_completed_task (Display *display)
|
|
||||||
{
|
|
||||||
AgPerDisplayData *dd;
|
|
||||||
|
|
||||||
dd = get_display_data (display, False);
|
|
||||||
|
|
||||||
if (dd == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
#ifdef DEBUG_SPEW
|
|
||||||
printf ("%d pending %d completed\n",
|
|
||||||
dd->n_tasks_pending,
|
|
||||||
dd->n_tasks_completed);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return (AgGetPropertyTask*) dd->completed_tasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
void*
|
|
||||||
ag_Xmalloc (unsigned long bytes)
|
|
||||||
{
|
|
||||||
return (void*) Xmalloc (bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void*
|
|
||||||
ag_Xmalloc0 (unsigned long bytes)
|
|
||||||
{
|
|
||||||
return (void*) Xcalloc (bytes, 1);
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
||||||
|
|
||||||
/* Asynchronous X property getting hack */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2002 Havoc Pennington
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, distribute, and sell this software
|
|
||||||
* and its documentation for any purpose is hereby granted without
|
|
||||||
* fee, provided that the above copyright notice appear in all copies
|
|
||||||
* and that both that copyright notice and this permission notice
|
|
||||||
* appear in supporting documentation.
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR
|
|
||||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
||||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*
|
|
||||||
* Except as contained in this notice, the name of The Open Group shall not be
|
|
||||||
* used in advertising or otherwise to promote the sale, use or other dealings
|
|
||||||
* in this Software without prior written authorization from The Open Group.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef ASYNC_GETPROP_H
|
|
||||||
#define ASYNC_GETPROP_H
|
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <X11/Xutil.h>
|
|
||||||
|
|
||||||
typedef struct _AgGetPropertyTask AgGetPropertyTask;
|
|
||||||
|
|
||||||
AgGetPropertyTask* ag_task_create (Display *display,
|
|
||||||
Window window,
|
|
||||||
Atom property,
|
|
||||||
long offset,
|
|
||||||
long length,
|
|
||||||
Bool delete,
|
|
||||||
Atom req_type);
|
|
||||||
Status ag_task_get_reply_and_free (AgGetPropertyTask *task,
|
|
||||||
Atom *actual_type,
|
|
||||||
int *actual_format,
|
|
||||||
unsigned long *nitems,
|
|
||||||
unsigned long *bytesafter,
|
|
||||||
unsigned char **prop);
|
|
||||||
|
|
||||||
Bool ag_task_have_reply (AgGetPropertyTask *task);
|
|
||||||
Atom ag_task_get_property (AgGetPropertyTask *task);
|
|
||||||
Window ag_task_get_window (AgGetPropertyTask *task);
|
|
||||||
Display* ag_task_get_display (AgGetPropertyTask *task);
|
|
||||||
|
|
||||||
AgGetPropertyTask* ag_get_next_completed_task (Display *display);
|
|
||||||
|
|
||||||
/* so other headers don't have to include internal Xlib goo */
|
|
||||||
void* ag_Xmalloc (unsigned long bytes);
|
|
||||||
void* ag_Xmalloc0 (unsigned long bytes);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,496 +0,0 @@
|
|||||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2002 Havoc Pennington
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, distribute, and sell this software
|
|
||||||
* and its documentation for any purpose is hereby granted without
|
|
||||||
* fee, provided that the above copyright notice appear in all copies
|
|
||||||
* and that both that copyright notice and this permission notice
|
|
||||||
* appear in supporting documentation.
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR
|
|
||||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
||||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*
|
|
||||||
* Except as contained in this notice, the name of The Open Group shall not be
|
|
||||||
* used in advertising or otherwise to promote the sale, use or other dealings
|
|
||||||
* in this Software without prior written authorization from The Open Group.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "async-getprop.h"
|
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#ifndef TRUE
|
|
||||||
#define TRUE 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef FALSE
|
|
||||||
#define FALSE 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef NULL
|
|
||||||
#define NULL ((void*) 0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_BACKTRACE
|
|
||||||
#include <execinfo.h>
|
|
||||||
static void
|
|
||||||
print_backtrace (void)
|
|
||||||
{
|
|
||||||
void *bt[500];
|
|
||||||
int bt_size;
|
|
||||||
int i;
|
|
||||||
char **syms;
|
|
||||||
|
|
||||||
bt_size = backtrace (bt, 500);
|
|
||||||
|
|
||||||
syms = backtrace_symbols (bt, bt_size);
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
while (i < bt_size)
|
|
||||||
{
|
|
||||||
fprintf (stderr, " %s\n", syms[i]);
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
free (syms);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static void
|
|
||||||
print_backtrace (void)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "Not compiled with backtrace support\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int error_trap_depth = 0;
|
|
||||||
|
|
||||||
static int
|
|
||||||
x_error_handler (Display *xdisplay,
|
|
||||||
XErrorEvent *error)
|
|
||||||
{
|
|
||||||
char buf[64];
|
|
||||||
|
|
||||||
XGetErrorText (xdisplay, error->error_code, buf, 63);
|
|
||||||
|
|
||||||
if (error_trap_depth == 0)
|
|
||||||
{
|
|
||||||
print_backtrace ();
|
|
||||||
|
|
||||||
fprintf (stderr, "Unexpected X error: %s serial %ld error_code %d request_code %d minor_code %d)\n",
|
|
||||||
buf,
|
|
||||||
error->serial,
|
|
||||||
error->error_code,
|
|
||||||
error->request_code,
|
|
||||||
error->minor_code);
|
|
||||||
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1; /* return value is meaningless */
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
error_trap_push (Display *xdisplay)
|
|
||||||
{
|
|
||||||
++error_trap_depth;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
error_trap_pop (Display *xdisplay)
|
|
||||||
{
|
|
||||||
if (error_trap_depth == 0)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "Error trap underflow!\n");
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
XSync (xdisplay, False); /* get all errors out of the queue */
|
|
||||||
--error_trap_depth;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char*
|
|
||||||
my_strdup (const char *str)
|
|
||||||
{
|
|
||||||
char *s;
|
|
||||||
|
|
||||||
s = malloc (strlen (str) + 1);
|
|
||||||
if (s == NULL)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "malloc failed\n");
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
strcpy (s, str);
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char*
|
|
||||||
atom_name (Display *display,
|
|
||||||
Atom atom)
|
|
||||||
{
|
|
||||||
if (atom == None)
|
|
||||||
{
|
|
||||||
return my_strdup ("None");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
char *xname;
|
|
||||||
char *ret;
|
|
||||||
|
|
||||||
error_trap_push (display);
|
|
||||||
xname = XGetAtomName (display, atom);
|
|
||||||
error_trap_pop (display);
|
|
||||||
if (xname == NULL)
|
|
||||||
return my_strdup ("[unknown atom]");
|
|
||||||
|
|
||||||
ret = my_strdup (xname);
|
|
||||||
XFree (xname);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define ELAPSED(start_time, current_time) \
|
|
||||||
(((((double)current_time.tv_sec - start_time.tv_sec) * 1000000 + \
|
|
||||||
(current_time.tv_usec - start_time.tv_usec))) / 1000.0)
|
|
||||||
|
|
||||||
static struct timeval program_start_time;
|
|
||||||
|
|
||||||
static Bool
|
|
||||||
try_get_reply (Display *xdisplay,
|
|
||||||
AgGetPropertyTask *task)
|
|
||||||
{
|
|
||||||
if (ag_task_have_reply (task))
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
Atom actual_type;
|
|
||||||
int actual_format;
|
|
||||||
unsigned long n_items;
|
|
||||||
unsigned long bytes_after;
|
|
||||||
unsigned char *data;
|
|
||||||
char *name;
|
|
||||||
struct timeval current_time;
|
|
||||||
|
|
||||||
gettimeofday (¤t_time, NULL);
|
|
||||||
|
|
||||||
printf (" %gms (we have a reply for property %ld)\n",
|
|
||||||
ELAPSED (program_start_time, current_time),
|
|
||||||
ag_task_get_property (task));
|
|
||||||
|
|
||||||
data = NULL;
|
|
||||||
|
|
||||||
name = atom_name (xdisplay,
|
|
||||||
ag_task_get_property (task));
|
|
||||||
printf (" %s on 0x%lx:\n", name,
|
|
||||||
ag_task_get_window (task));
|
|
||||||
free (name);
|
|
||||||
|
|
||||||
result = ag_task_get_reply_and_free (task,
|
|
||||||
&actual_type,
|
|
||||||
&actual_format,
|
|
||||||
&n_items,
|
|
||||||
&bytes_after,
|
|
||||||
&data);
|
|
||||||
task = NULL;
|
|
||||||
|
|
||||||
if (result != Success)
|
|
||||||
{
|
|
||||||
fprintf (stderr, " error code %d getting reply\n", result);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
name = atom_name (xdisplay, actual_type);
|
|
||||||
printf (" actual_type = %s\n", name);
|
|
||||||
free (name);
|
|
||||||
|
|
||||||
printf (" actual_format = %d\n", actual_format);
|
|
||||||
|
|
||||||
printf (" n_items = %lu\n", n_items);
|
|
||||||
printf (" bytes_after = %lu\n", bytes_after);
|
|
||||||
|
|
||||||
printf (" data = \"%s\"\n", data ? (char*) data : "NULL");
|
|
||||||
}
|
|
||||||
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void run_speed_comparison (Display *xdisplay,
|
|
||||||
Window window);
|
|
||||||
|
|
||||||
int
|
|
||||||
main (int argc, char **argv)
|
|
||||||
{
|
|
||||||
Display *xdisplay;
|
|
||||||
int i;
|
|
||||||
int n_left;
|
|
||||||
int n_props;
|
|
||||||
Window window;
|
|
||||||
const char *window_str;
|
|
||||||
char *end;
|
|
||||||
Atom *props;
|
|
||||||
struct timeval current_time;
|
|
||||||
|
|
||||||
if (argc < 2)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "specify window ID\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
window_str = argv[1];
|
|
||||||
|
|
||||||
end = NULL;
|
|
||||||
window = strtoul (window_str, &end, 0);
|
|
||||||
if (end == NULL || *end != '\0')
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\"%s\" does not parse as a window ID\n", window_str);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
xdisplay = XOpenDisplay (NULL);
|
|
||||||
if (xdisplay == NULL)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "Could not open display\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getenv ("MUTTER_SYNC") != NULL)
|
|
||||||
XSynchronize (xdisplay, True);
|
|
||||||
|
|
||||||
XSetErrorHandler (x_error_handler);
|
|
||||||
|
|
||||||
n_props = 0;
|
|
||||||
props = XListProperties (xdisplay, window, &n_props);
|
|
||||||
if (n_props == 0 || props == NULL)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "Window has no properties\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
gettimeofday (&program_start_time, NULL);
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
while (i < n_props)
|
|
||||||
{
|
|
||||||
gettimeofday (¤t_time, NULL);
|
|
||||||
printf (" %gms (sending request for property %ld)\n",
|
|
||||||
ELAPSED (program_start_time, current_time),
|
|
||||||
props[i]);
|
|
||||||
if (ag_task_create (xdisplay,
|
|
||||||
window, props[i],
|
|
||||||
0, 0xffffffff,
|
|
||||||
False,
|
|
||||||
AnyPropertyType) == NULL)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "Failed to send request\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
XFree (props);
|
|
||||||
props = NULL;
|
|
||||||
|
|
||||||
n_left = n_props;
|
|
||||||
|
|
||||||
while (TRUE)
|
|
||||||
{
|
|
||||||
XEvent xevent;
|
|
||||||
int connection;
|
|
||||||
fd_set set;
|
|
||||||
AgGetPropertyTask *task;
|
|
||||||
|
|
||||||
/* Mop up event queue */
|
|
||||||
while (XPending (xdisplay) > 0)
|
|
||||||
{
|
|
||||||
XNextEvent (xdisplay, &xevent);
|
|
||||||
gettimeofday (¤t_time, NULL);
|
|
||||||
printf (" %gms (processing event type %d)\n",
|
|
||||||
ELAPSED (program_start_time, current_time),
|
|
||||||
xevent.xany.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((task = ag_get_next_completed_task (xdisplay)))
|
|
||||||
{
|
|
||||||
try_get_reply (xdisplay, task);
|
|
||||||
n_left -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n_left == 0)
|
|
||||||
{
|
|
||||||
printf ("All %d replies received.\n", n_props);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wake up if we may have a reply */
|
|
||||||
connection = ConnectionNumber (xdisplay);
|
|
||||||
|
|
||||||
FD_ZERO (&set);
|
|
||||||
FD_SET (connection, &set);
|
|
||||||
|
|
||||||
gettimeofday (¤t_time, NULL);
|
|
||||||
printf (" %gms (blocking for data %d left)\n",
|
|
||||||
ELAPSED (program_start_time, current_time), n_left);
|
|
||||||
select (connection + 1, &set, NULL, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
run_speed_comparison (xdisplay, window);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This function doesn't have all the printf's
|
|
||||||
* and other noise, it just compares async to sync
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
run_speed_comparison (Display *xdisplay,
|
|
||||||
Window window)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int n_props;
|
|
||||||
struct timeval start, end;
|
|
||||||
int n_left;
|
|
||||||
|
|
||||||
/* We just use atom values (0 to n_props) % 200, many are probably
|
|
||||||
* BadAtom, that's fine, but the %200 keeps most of them valid. The
|
|
||||||
* async case is about twice as advantageous when using valid atoms
|
|
||||||
* (or the issue may be that it's more advantageous when the
|
|
||||||
* properties are present and data is transmitted).
|
|
||||||
*/
|
|
||||||
n_props = 4000;
|
|
||||||
printf ("Timing with %d property requests\n", n_props);
|
|
||||||
|
|
||||||
gettimeofday (&start, NULL);
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
while (i < n_props)
|
|
||||||
{
|
|
||||||
if (ag_task_create (xdisplay,
|
|
||||||
window, (Atom) i % 200,
|
|
||||||
0, 0xffffffff,
|
|
||||||
False,
|
|
||||||
AnyPropertyType) == NULL)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "Failed to send request\n");
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
n_left = n_props;
|
|
||||||
|
|
||||||
while (TRUE)
|
|
||||||
{
|
|
||||||
int connection;
|
|
||||||
fd_set set;
|
|
||||||
XEvent xevent;
|
|
||||||
AgGetPropertyTask *task;
|
|
||||||
|
|
||||||
/* Mop up event queue */
|
|
||||||
while (XPending (xdisplay) > 0)
|
|
||||||
XNextEvent (xdisplay, &xevent);
|
|
||||||
|
|
||||||
while ((task = ag_get_next_completed_task (xdisplay)))
|
|
||||||
{
|
|
||||||
Atom actual_type;
|
|
||||||
int actual_format;
|
|
||||||
unsigned long n_items;
|
|
||||||
unsigned long bytes_after;
|
|
||||||
unsigned char *data;
|
|
||||||
|
|
||||||
assert (ag_task_have_reply (task));
|
|
||||||
|
|
||||||
data = NULL;
|
|
||||||
ag_task_get_reply_and_free (task,
|
|
||||||
&actual_type,
|
|
||||||
&actual_format,
|
|
||||||
&n_items,
|
|
||||||
&bytes_after,
|
|
||||||
&data);
|
|
||||||
|
|
||||||
if (data)
|
|
||||||
XFree (data);
|
|
||||||
|
|
||||||
n_left -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n_left == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Wake up if we may have a reply */
|
|
||||||
connection = ConnectionNumber (xdisplay);
|
|
||||||
|
|
||||||
FD_ZERO (&set);
|
|
||||||
FD_SET (connection, &set);
|
|
||||||
|
|
||||||
select (connection + 1, &set, NULL, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
gettimeofday (&end, NULL);
|
|
||||||
|
|
||||||
printf ("Async time: %gms\n",
|
|
||||||
ELAPSED (start, end));
|
|
||||||
|
|
||||||
gettimeofday (&start, NULL);
|
|
||||||
|
|
||||||
error_trap_push (xdisplay);
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
while (i < n_props)
|
|
||||||
{
|
|
||||||
Atom actual_type;
|
|
||||||
int actual_format;
|
|
||||||
unsigned long n_items;
|
|
||||||
unsigned long bytes_after;
|
|
||||||
unsigned char *data;
|
|
||||||
|
|
||||||
data = NULL;
|
|
||||||
if (XGetWindowProperty (xdisplay, window,
|
|
||||||
(Atom) i % 200,
|
|
||||||
0, 0xffffffff,
|
|
||||||
False,
|
|
||||||
AnyPropertyType,
|
|
||||||
&actual_type,
|
|
||||||
&actual_format,
|
|
||||||
&n_items,
|
|
||||||
&bytes_after,
|
|
||||||
&data) == Success)
|
|
||||||
{
|
|
||||||
if (data)
|
|
||||||
XFree (data);
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
error_trap_pop (xdisplay);
|
|
||||||
|
|
||||||
gettimeofday (&end, NULL);
|
|
||||||
|
|
||||||
printf ("Sync time: %gms\n",
|
|
||||||
ELAPSED (start, end));
|
|
||||||
}
|
|
179
src/x11/xprops.c
179
src/x11/xprops.c
@ -78,17 +78,21 @@ from The Open Group.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <config.h>
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "xprops.h"
|
#include "xprops.h"
|
||||||
#include <meta/errors.h>
|
#include <meta/errors.h>
|
||||||
#include "util-private.h"
|
#include "util-private.h"
|
||||||
#include "async-getprop.h"
|
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include "mutter-Xatomtype.h"
|
#include "mutter-Xatomtype.h"
|
||||||
#include <X11/Xatom.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "window-private.h"
|
#include "window-private.h"
|
||||||
|
|
||||||
|
#include <X11/Xatom.h>
|
||||||
|
#include <X11/Xlib-xcb.h>
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
MetaDisplay *display;
|
MetaDisplay *display;
|
||||||
@ -168,13 +172,50 @@ validate_or_free_results (GetPropertyResults *results,
|
|||||||
|
|
||||||
if (results->prop)
|
if (results->prop)
|
||||||
{
|
{
|
||||||
XFree (results->prop);
|
g_free (results->prop);
|
||||||
results->prop = NULL;
|
results->prop = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static xcb_get_property_cookie_t
|
||||||
|
async_get_property (xcb_connection_t *xcb_conn, Window xwindow,
|
||||||
|
Atom xatom, Atom required_type)
|
||||||
|
{
|
||||||
|
return xcb_get_property (xcb_conn, False, xwindow,
|
||||||
|
xatom, required_type, 0, G_MAXULONG);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
async_get_property_finish (xcb_connection_t *xcb_conn,
|
||||||
|
xcb_get_property_cookie_t cookie,
|
||||||
|
GetPropertyResults *results)
|
||||||
|
{
|
||||||
|
xcb_get_property_reply_t *reply;
|
||||||
|
xcb_generic_error_t *error;
|
||||||
|
|
||||||
|
reply = xcb_get_property_reply (xcb_conn, cookie, &error);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
free (error);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
results->n_items = reply->value_len;
|
||||||
|
results->type = reply->type;
|
||||||
|
results->bytes_after = reply->bytes_after;
|
||||||
|
results->format = reply->format;
|
||||||
|
results->prop = NULL;
|
||||||
|
|
||||||
|
if (results->type != None)
|
||||||
|
results->prop = g_memdup (xcb_get_property_value (reply),
|
||||||
|
xcb_get_property_value_length (reply));
|
||||||
|
|
||||||
|
free (reply);
|
||||||
|
return (results->prop != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
get_property (MetaDisplay *display,
|
get_property (MetaDisplay *display,
|
||||||
Window xwindow,
|
Window xwindow,
|
||||||
@ -182,6 +223,9 @@ get_property (MetaDisplay *display,
|
|||||||
Atom req_type,
|
Atom req_type,
|
||||||
GetPropertyResults *results)
|
GetPropertyResults *results)
|
||||||
{
|
{
|
||||||
|
xcb_get_property_cookie_t cookie;
|
||||||
|
xcb_connection_t *xcb_conn = XGetXCBConnection (display->xdisplay);
|
||||||
|
|
||||||
results->display = display;
|
results->display = display;
|
||||||
results->xwindow = xwindow;
|
results->xwindow = xwindow;
|
||||||
results->xatom = xatom;
|
results->xatom = xatom;
|
||||||
@ -191,29 +235,8 @@ get_property (MetaDisplay *display,
|
|||||||
results->bytes_after = 0;
|
results->bytes_after = 0;
|
||||||
results->format = 0;
|
results->format = 0;
|
||||||
|
|
||||||
meta_error_trap_push (display);
|
cookie = async_get_property (xcb_conn, xwindow, xatom, req_type);
|
||||||
if (XGetWindowProperty (display->xdisplay, xwindow, xatom,
|
return async_get_property_finish (xcb_conn, cookie, results);
|
||||||
0, G_MAXLONG,
|
|
||||||
False, req_type, &results->type, &results->format,
|
|
||||||
&results->n_items,
|
|
||||||
&results->bytes_after,
|
|
||||||
&results->prop) != Success ||
|
|
||||||
results->type == None)
|
|
||||||
{
|
|
||||||
if (results->prop)
|
|
||||||
XFree (results->prop);
|
|
||||||
meta_error_trap_pop_with_return (display);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (meta_error_trap_pop_with_return (display) != Success)
|
|
||||||
{
|
|
||||||
if (results->prop)
|
|
||||||
XFree (results->prop);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -318,7 +341,7 @@ motif_hints_from_results (GetPropertyResults *results,
|
|||||||
* MotifWmHints than the one we expect, apparently. I'm not sure of
|
* MotifWmHints than the one we expect, apparently. I'm not sure of
|
||||||
* the history behind it. See bug #89841 for example.
|
* the history behind it. See bug #89841 for example.
|
||||||
*/
|
*/
|
||||||
*hints_p = ag_Xmalloc (sizeof (MotifWmHints));
|
*hints_p = malloc (sizeof (MotifWmHints));
|
||||||
if (*hints_p == NULL)
|
if (*hints_p == NULL)
|
||||||
{
|
{
|
||||||
if (results->prop)
|
if (results->prop)
|
||||||
@ -409,7 +432,7 @@ utf8_string_from_results (GetPropertyResults *results,
|
|||||||
meta_warning ("Property %s on window 0x%lx contained invalid UTF-8\n",
|
meta_warning ("Property %s on window 0x%lx contained invalid UTF-8\n",
|
||||||
name, results->xwindow);
|
name, results->xwindow);
|
||||||
meta_XFree (name);
|
meta_XFree (name);
|
||||||
XFree (results->prop);
|
g_free (results->prop);
|
||||||
results->prop = NULL;
|
results->prop = NULL;
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -492,7 +515,7 @@ utf8_list_from_results (GetPropertyResults *results,
|
|||||||
meta_warning ("Property %s on window 0x%lx contained invalid UTF-8 for item %d in the list\n",
|
meta_warning ("Property %s on window 0x%lx contained invalid UTF-8 for item %d in the list\n",
|
||||||
name, results->xwindow, i);
|
name, results->xwindow, i);
|
||||||
meta_XFree (name);
|
meta_XFree (name);
|
||||||
meta_XFree (results->prop);
|
g_free (results->prop);
|
||||||
results->prop = NULL;
|
results->prop = NULL;
|
||||||
|
|
||||||
g_strfreev (retval);
|
g_strfreev (retval);
|
||||||
@ -508,7 +531,7 @@ utf8_list_from_results (GetPropertyResults *results,
|
|||||||
*str_p = retval;
|
*str_p = retval;
|
||||||
*n_str_p = i;
|
*n_str_p = i;
|
||||||
|
|
||||||
meta_XFree (results->prop);
|
g_free (results->prop);
|
||||||
results->prop = NULL;
|
results->prop = NULL;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -585,7 +608,7 @@ latin1_list_from_results (GetPropertyResults *results,
|
|||||||
*str_p = retval;
|
*str_p = retval;
|
||||||
*n_str_p = i;
|
*n_str_p = i;
|
||||||
|
|
||||||
meta_XFree (results->prop);
|
g_free (results->prop);
|
||||||
results->prop = NULL;
|
results->prop = NULL;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -844,7 +867,7 @@ wm_hints_from_results (GetPropertyResults *results,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
hints = ag_Xmalloc0 (sizeof (XWMHints));
|
hints = calloc (1, sizeof (XWMHints));
|
||||||
|
|
||||||
raw = (xPropWMHints*) results->prop;
|
raw = (xPropWMHints*) results->prop;
|
||||||
|
|
||||||
@ -902,7 +925,7 @@ class_hint_from_results (GetPropertyResults *results,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
len_name = strlen ((char *) results->prop);
|
len_name = strlen ((char *) results->prop);
|
||||||
if (! (class_hint->res_name = ag_Xmalloc (len_name+1)))
|
if (! (class_hint->res_name = malloc (len_name+1)))
|
||||||
{
|
{
|
||||||
XFree (results->prop);
|
XFree (results->prop);
|
||||||
results->prop = NULL;
|
results->prop = NULL;
|
||||||
@ -916,7 +939,7 @@ class_hint_from_results (GetPropertyResults *results,
|
|||||||
|
|
||||||
len_class = strlen ((char *)results->prop + len_name + 1);
|
len_class = strlen ((char *)results->prop + len_name + 1);
|
||||||
|
|
||||||
if (! (class_hint->res_class = ag_Xmalloc(len_class+1)))
|
if (! (class_hint->res_class = malloc(len_class+1)))
|
||||||
{
|
{
|
||||||
XFree(class_hint->res_name);
|
XFree(class_hint->res_name);
|
||||||
class_hint->res_name = NULL;
|
class_hint->res_name = NULL;
|
||||||
@ -970,7 +993,7 @@ size_hints_from_results (GetPropertyResults *results,
|
|||||||
|
|
||||||
raw = (xPropSizeHints*) results->prop;
|
raw = (xPropSizeHints*) results->prop;
|
||||||
|
|
||||||
hints = ag_Xmalloc (sizeof (XSizeHints));
|
hints = malloc (sizeof (XSizeHints));
|
||||||
|
|
||||||
/* XSizeHints misdeclares these as int instead of long */
|
/* XSizeHints misdeclares these as int instead of long */
|
||||||
hints->flags = raw->flags;
|
hints->flags = raw->flags;
|
||||||
@ -1027,18 +1050,6 @@ meta_prop_get_size_hints (MetaDisplay *display,
|
|||||||
return size_hints_from_results (&results, hints_p, flags_p);
|
return size_hints_from_results (&results, hints_p, flags_p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static AgGetPropertyTask*
|
|
||||||
get_task (MetaDisplay *display,
|
|
||||||
Window xwindow,
|
|
||||||
Atom xatom,
|
|
||||||
Atom req_type)
|
|
||||||
{
|
|
||||||
return ag_task_create (display->xdisplay,
|
|
||||||
xwindow,
|
|
||||||
xatom, 0, G_MAXLONG,
|
|
||||||
False, req_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
static char*
|
static char*
|
||||||
latin1_to_utf8 (const char *text)
|
latin1_to_utf8 (const char *text)
|
||||||
{
|
{
|
||||||
@ -1064,7 +1075,8 @@ meta_prop_get_values (MetaDisplay *display,
|
|||||||
int n_values)
|
int n_values)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
AgGetPropertyTask **tasks;
|
xcb_get_property_cookie_t *tasks;
|
||||||
|
xcb_connection_t *xcb_conn = XGetXCBConnection (display->xdisplay);
|
||||||
|
|
||||||
meta_verbose ("Requesting %d properties of 0x%lx at once\n",
|
meta_verbose ("Requesting %d properties of 0x%lx at once\n",
|
||||||
n_values, xwindow);
|
n_values, xwindow);
|
||||||
@ -1072,7 +1084,7 @@ meta_prop_get_values (MetaDisplay *display,
|
|||||||
if (n_values == 0)
|
if (n_values == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
tasks = g_new0 (AgGetPropertyTask*, n_values);
|
tasks = g_new0 (xcb_get_property_cookie_t, n_values);
|
||||||
|
|
||||||
/* Start up tasks. The "values" array can have values
|
/* Start up tasks. The "values" array can have values
|
||||||
* with atom == None, which means to ignore that element.
|
* with atom == None, which means to ignore that element.
|
||||||
@ -1132,9 +1144,7 @@ meta_prop_get_values (MetaDisplay *display,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (values[i].atom != None)
|
if (values[i].atom != None)
|
||||||
tasks[i] = get_task (display, xwindow,
|
tasks[i] = async_get_property (xcb_conn, xwindow, values[i].atom, values[i].required_type);
|
||||||
values[i].atom, values[i].required_type);
|
|
||||||
|
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1147,10 +1157,11 @@ meta_prop_get_values (MetaDisplay *display,
|
|||||||
i = 0;
|
i = 0;
|
||||||
while (i < n_values)
|
while (i < n_values)
|
||||||
{
|
{
|
||||||
AgGetPropertyTask *task;
|
|
||||||
GetPropertyResults results;
|
GetPropertyResults results;
|
||||||
|
|
||||||
if (tasks[i] == NULL)
|
/* We're relying on the fact that sequence numbers can never be zero
|
||||||
|
* in Xorg. This is a bit disgusting... */
|
||||||
|
if (tasks[i].sequence == 0)
|
||||||
{
|
{
|
||||||
/* Probably values[i].type was None, or ag_task_create()
|
/* Probably values[i].type was None, or ag_task_create()
|
||||||
* returned NULL.
|
* returned NULL.
|
||||||
@ -1159,10 +1170,6 @@ meta_prop_get_values (MetaDisplay *display,
|
|||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
task = ag_get_next_completed_task (display->xdisplay);
|
|
||||||
g_assert (task != NULL);
|
|
||||||
g_assert (ag_task_have_reply (task));
|
|
||||||
|
|
||||||
results.display = display;
|
results.display = display;
|
||||||
results.xwindow = xwindow;
|
results.xwindow = xwindow;
|
||||||
results.xatom = values[i].atom;
|
results.xatom = values[i].atom;
|
||||||
@ -1172,21 +1179,8 @@ meta_prop_get_values (MetaDisplay *display,
|
|||||||
results.bytes_after = 0;
|
results.bytes_after = 0;
|
||||||
results.format = 0;
|
results.format = 0;
|
||||||
|
|
||||||
if (ag_task_get_reply_and_free (task,
|
if (!async_get_property_finish (xcb_conn, tasks[i], &results))
|
||||||
&results.type, &results.format,
|
goto next;
|
||||||
&results.n_items,
|
|
||||||
&results.bytes_after,
|
|
||||||
&results.prop) != Success ||
|
|
||||||
results.type == None)
|
|
||||||
{
|
|
||||||
values[i].type = META_PROP_VALUE_INVALID;
|
|
||||||
if (results.prop)
|
|
||||||
{
|
|
||||||
XFree (results.prop);
|
|
||||||
results.prop = NULL;
|
|
||||||
}
|
|
||||||
goto next;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (values[i].type)
|
switch (values[i].type)
|
||||||
{
|
{
|
||||||
@ -1216,18 +1210,9 @@ meta_prop_get_values (MetaDisplay *display,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *new_str;
|
char *new_str;
|
||||||
char *xmalloc_new_str;
|
|
||||||
|
|
||||||
new_str = latin1_to_utf8 (values[i].v.str);
|
new_str = latin1_to_utf8 (values[i].v.str);
|
||||||
xmalloc_new_str = ag_Xmalloc (strlen (new_str) + 1);
|
free (values[i].v.str);
|
||||||
if (xmalloc_new_str != NULL)
|
values[i].v.str = new_str;
|
||||||
{
|
|
||||||
strcpy (xmalloc_new_str, new_str);
|
|
||||||
meta_XFree (values[i].v.str);
|
|
||||||
values[i].v.str = xmalloc_new_str;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_free (new_str);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case META_PROP_VALUE_MOTIF_HINTS:
|
case META_PROP_VALUE_MOTIF_HINTS:
|
||||||
@ -1305,42 +1290,44 @@ free_value (MetaPropValue *value)
|
|||||||
break;
|
break;
|
||||||
case META_PROP_VALUE_UTF8:
|
case META_PROP_VALUE_UTF8:
|
||||||
case META_PROP_VALUE_STRING:
|
case META_PROP_VALUE_STRING:
|
||||||
|
free (value->v.str);
|
||||||
|
break;
|
||||||
case META_PROP_VALUE_STRING_AS_UTF8:
|
case META_PROP_VALUE_STRING_AS_UTF8:
|
||||||
meta_XFree (value->v.str);
|
g_free (value->v.str);
|
||||||
break;
|
break;
|
||||||
case META_PROP_VALUE_MOTIF_HINTS:
|
case META_PROP_VALUE_MOTIF_HINTS:
|
||||||
meta_XFree (value->v.motif_hints);
|
free (value->v.motif_hints);
|
||||||
break;
|
break;
|
||||||
case META_PROP_VALUE_CARDINAL:
|
case META_PROP_VALUE_CARDINAL:
|
||||||
break;
|
break;
|
||||||
case META_PROP_VALUE_WINDOW:
|
case META_PROP_VALUE_WINDOW:
|
||||||
break;
|
break;
|
||||||
case META_PROP_VALUE_ATOM_LIST:
|
case META_PROP_VALUE_ATOM_LIST:
|
||||||
meta_XFree (value->v.atom_list.atoms);
|
free (value->v.atom_list.atoms);
|
||||||
break;
|
break;
|
||||||
case META_PROP_VALUE_TEXT_PROPERTY:
|
case META_PROP_VALUE_TEXT_PROPERTY:
|
||||||
meta_XFree (value->v.str);
|
free (value->v.str);
|
||||||
break;
|
break;
|
||||||
case META_PROP_VALUE_WM_HINTS:
|
case META_PROP_VALUE_WM_HINTS:
|
||||||
meta_XFree (value->v.wm_hints);
|
free (value->v.wm_hints);
|
||||||
break;
|
break;
|
||||||
case META_PROP_VALUE_CLASS_HINT:
|
case META_PROP_VALUE_CLASS_HINT:
|
||||||
meta_XFree (value->v.class_hint.res_class);
|
free (value->v.class_hint.res_class);
|
||||||
meta_XFree (value->v.class_hint.res_name);
|
free (value->v.class_hint.res_name);
|
||||||
break;
|
break;
|
||||||
case META_PROP_VALUE_SIZE_HINTS:
|
case META_PROP_VALUE_SIZE_HINTS:
|
||||||
meta_XFree (value->v.size_hints.hints);
|
free (value->v.size_hints.hints);
|
||||||
break;
|
break;
|
||||||
case META_PROP_VALUE_UTF8_LIST:
|
case META_PROP_VALUE_UTF8_LIST:
|
||||||
g_strfreev (value->v.string_list.strings);
|
g_strfreev (value->v.string_list.strings);
|
||||||
break;
|
break;
|
||||||
case META_PROP_VALUE_CARDINAL_LIST:
|
case META_PROP_VALUE_CARDINAL_LIST:
|
||||||
meta_XFree (value->v.cardinal_list.cardinals);
|
free (value->v.cardinal_list.cardinals);
|
||||||
break;
|
break;
|
||||||
case META_PROP_VALUE_SYNC_COUNTER:
|
case META_PROP_VALUE_SYNC_COUNTER:
|
||||||
break;
|
break;
|
||||||
case META_PROP_VALUE_SYNC_COUNTER_LIST:
|
case META_PROP_VALUE_SYNC_COUNTER_LIST:
|
||||||
meta_XFree (value->v.xcounter_list.counters);
|
free (value->v.xcounter_list.counters);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user