[Xcb] magical callback funness

Jeremy Kolb jkolb at brandeis.edu
Thu Mar 24 09:27:57 PST 2005


Henrik Sandklef wrote:
>>I've run into a snag with record.  It there's a request/reply called
>>RecordGetContext.  This gets the events recorded on the current
>>connection.
> 
> 
> When working with RECORD you use a context type. When having made one such
> you can:
> 
>  1 Query the state
>   -------------------
>   Done using the function XRecordGetContext
> 
>   The request "RecordGetContext" is sent after the
>   function XRecordGetContext has been called
> 
>   2 Start/stop recording
>   -------------------
>   Done using the function XRecordEnableContext/XRecordDisableContext
> 
>   The request RecordEnableContext is sent after the
>   function XRecordEnableContext has been called
> 
>   The request RecordDisableContext is sent after the
>   function XRecordDisableContext has been called
> 
> 
> 
>>However when calling the reply it enters a loop and prints
>>out how no record was found for such and such an event.
> 
> 
> Calling the reply? Can you please give some more info? Do you mean sending?
> 
> Can you show me your source code?
> 
> 
>> The problem is
>>that I can't get out of this loop to do other things like parse the
>>information and what not.
> 
> 
> Where is your code located? In the client or the server?
> 
> 
> 
>>Xlib seems to solve this problem by installing a callback (I'm not
>>really sure how it works though). when enabling the context
>>(RecordEnableContext).
> 
> This is right.
> 
> 
>>I'm not sure how to solve this.  Ideas, suggestions?
> 
> Show the sources :)
> 
> /h
> 

I just committed my record.xml file, you'll have to edit Makefile.in in 
both cvs/xcb-proto/src and cvs/xcb/src to build it.  I don't want to 
enable it by default yet because I want to fully test it first. 
Anyways, here's my test program.  record_test.c.orig is the xlib version 
from blogs.sun.com/yongsun (used with his permission).  record_test.c 
will be the xcbified version.

Jeremy
-------------- next part --------------
// Assuming xcb is installed to /opt/fdo
// gcc -I/opt/fdo/include -L/opt/fdo/lib -lXCB -g record_test.c -o record_test


#include <stdio.h>
#include <stdlib.h>
#include <X11/XCB/xcb.h>
#include <X11/XCB/record.h>


XCBConnection *rec_con = NULL;
XCBConnection *loc_con = NULL;

int main(int argc, char **argv)
{
	int major = 1;
	int minor = 13;
	
	loc_con = XCBConnectBasic();
	rec_con = XCBConnectBasic();

	if (!loc_con || !rec_con) {
		fprintf(stderr, "Error, cannot open display!\n");
		exit(1);
	}

	XCBRecordQueryVersionRep *qv = NULL;
	XCBGenericError *err = NULL;
	qv = XCBRecordQueryVersionReply(rec_con,
			XCBRecordQueryVersion(rec_con, major, minor),
			&err);

	if (!qv || err) {
		fprintf(stderr, "RECORD extension not supported on this server!\n");
		exit(1);
	}
	major = qv->major_version;
	minor = qv->minor_version;
	printf("RECORD extension version is %d.%d\n", major, minor);

	XCBRecordRange *rr;
	rr = (XCBRecordRange *)calloc(1, sizeof(XCBRecordRange)); // IMPORTANT
	CARD32 rcs = XCBRecordCSAllClients;
	XCBRecordContext rc = XCBRecordContextNew(rec_con);

	rr->device_events.first = XCBKeyPress;
	rr->device_events.last = XCBMotionNotify;
	
	// Make sure to check context later.
	XCBRecordCreateContext(rec_con, rc, 0, 1, 1, &rcs, rr);

	XCBRecordEnableContextRep *ecr = NULL;
	XCBRecordEnableContextCookie ecc;
	ecc = XCBRecordEnableContext(rec_con, rc);
	ecr = XCBRecordEnableContextReply(rec_con, ecc, &err);

	if (!ecr || err) {
		fprintf(stderr, "Could not enable the record context!\n");
		XCBRecordBadContextError *berr;
		berr = ((XCBRecordBadContextError *) err);
		fprintf(stderr, "Context: %d\tCode: %d\tInvalid: %d\n",
				rc.xid, berr->error_code, berr->invalid_record);
		exit(1);
	}
	
	//while(1) {
		XCBRecordGetContextCookie gcc;
		XCBRecordGetContextRep *gcr;
		gcc = XCBRecordGetContext(rec_con, rc);
		gcr = XCBRecordGetContextReply(rec_con, gcc, &err);
		if (!gcr || err) {
			fprintf(stderr, "Could not get context.\n");
			exit(1);
		}
		printf("enabled: %d, num_clients: %d\n", gcr->enabled, gcr->num_intercepted_clients);
	//}
	
	XCBRecordDisableContext(rec_con, rc);
	XCBRecordFreeContext(rec_con, rc);
	free(rr);
}
-------------- next part --------------
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlibint.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include <X11/keysymdef.h>
#include <X11/keysym.h>
#include <X11/extensions/record.h>
#include <X11/extensions/XTest.h>

typedef union {
    unsigned char   type;
    xEvent          event;
    xResourceReq    req;
    xGenericReply   reply;
    xError          error;
    xConnSetupPrefix setup;
} XRecordDatum;

/*
 * FIXME: We need define a private struct for callback function,
 * to store cur_x, cur_y, rec_disp, loc_disp etc.
 */
Display        *rec_disp = NULL;
Display        *loc_disp = NULL;

void            event_callback(XPointer, XRecordInterceptData *);

int
main(int argc, char **argv)
{
    loc_disp = XOpenDisplay(NULL);
    rec_disp = XOpenDisplay(NULL);

    if (!loc_disp || !rec_disp) {
	fprintf(stderr, "Error to open local display!\n");
	exit(1);
    }

    int             major,
                    minor;

    if (!XRecordQueryVersion(rec_disp, &major, &minor)) {
	fprintf(stderr,
		"RECORD extension not supported on this X server!\n");
	exit(2);
    }

    printf("RECORD extension for local server is version is %d.%d\n",
	   major, minor);

    XRecordRange   *rr;
    XRecordClientSpec rcs;
    XRecordContext  rc;

    rr = XRecordAllocRange();
    if (!rr) {
	fprintf(stderr, "Could not alloc record range object!\n");
	exit(3);
    }


    rr->device_events.first = KeyPress;
    rr->device_events.last = MotionNotify;
    rcs = XRecordAllClients;

    rc = XRecordCreateContext(rec_disp, 0, &rcs, 1, &rr, 1);
    if (!rc) {
	fprintf(stderr, "Could not create a record context!\n");
	exit(4);
    }

    if (!XRecordEnableContextAsync(rec_disp, rc, event_callback, NULL)) {
	fprintf(stderr, "Cound not enable the record context!\n");
	exit(5);
    }

    while (1)
	XRecordProcessReplies(rec_disp);

    XRecordDisableContext(rec_disp, rc);
    XRecordFreeContext(rec_disp, rc);
    XFree(rr);

    XCloseDisplay(rec_disp);
    XCloseDisplay(loc_disp);
    return 0;
}

void
event_callback(XPointer priv, XRecordInterceptData * hook)
{
    /*
     * FIXME: we need use XQueryPointer to get the first location 
     */
    static int      cur_x = 0;
    static int      cur_y = 0;

    if (hook->category != XRecordFromServer) {
	XRecordFreeData(hook);
	return;
    }

    XRecordDatum   *data = (XRecordDatum *) hook->data;

    int             event_type = data->type;

    BYTE            btncode,
                    keycode;
    btncode = keycode = data->event.u.u.detail;

    int             rootx = data->event.u.keyButtonPointer.rootX;
    int             rooty = data->event.u.keyButtonPointer.rootY;
    int             time = hook->server_time;

    switch (event_type) {
    case KeyPress:
	printf("KeyPress: \t%s",
	       XKeysymToString(XKeycodeToKeysym(loc_disp, keycode, 0)));
	break;
    case KeyRelease:
	printf("KeyRelease: \t%s",
	       XKeysymToString(XKeycodeToKeysym(loc_disp, keycode, 0)));
	break;
    case ButtonPress:
	printf("ButtonPress: \t%d, rootX=%d, rootY=%d", btncode, cur_x,
	       cur_y);
	break;
    case ButtonRelease:
	printf("ButtonRelease: \t%d, rootX=%d, rootY=%d", btncode, cur_x,
	       cur_y);
	break;
    case MotionNotify:
	printf("MouseMove: \trootX=%d, rootY=%d", rootx, rooty);
	cur_x = rootx;
	cur_y = rooty;
	break;
    case CreateNotify:
	break;
    case DestroyNotify:
	break;
    case NoExpose:
	break;
    case Expose:
	break;
    default:
	break;
    }

    printf(", time=%d\n", time);

    XRecordFreeData(hook);
}


More information about the xcb mailing list