Hello,
Ok, the problem is now solved.
This example code works just fine.

from Xlib import X, display, Xutil, Xatom
from Xlib.protocol import event
import struct

# Ref: http://python-xlib.sourceforge.net/doc/html/python-xlib_14.html  
     
disp = display.Display()
screen = disp.screen()
xroot_win = screen.root
atom = disp.intern_atom("_NET_CURRENT_DESKTOP", 0)
  
# Switch to desktop # 1 (0 based)
frmt = "llbbbb"
data_str = struct.pack(frmt, 1, X.CurrentTime, 0, 0, 0,0)
data_len = struct.calcsize(frmt)

print "len=", data_len, "   data=", data_str
print "len=", len(data_str)

event = event.ClientMessage(
            client_type = atom,      
            window = xroot_win,
            data = (8, data_str))

mask = X.StructureNotifyMask | X.SubstructureNotifyMask

# xroot_win.send_event(event, mask, 0)
disp.send_event(xroot_win, event , mask, 0)
disp.flush()

# -----------------------------------------------

Cheers,
  Moma Antero
  Oslo, Grønland



Osmo Maatta wrote:
Hello again,
I have code that sends a message to the window manager to switch to a given desktop number.
I have converted this code from C to Python/Xlib.

# The code is this.

from Xlib import X, display, Xutil, Xatom
from Xlib.protocol import event

import struct  # trying to pack string data
   
disp = display.Display()
screen = disp.screen()
xroot_win = screen.root
atom = disp.intern_atom("_NET_CURRENT_DESKTOP", 0)
# disp.send_client_message(xroot_win, atom, 32, 0)
mask = X.StructureNotifyMask | X.SubstructureNotifyMask
   
# Switch to desktop # 1  (0 based)
data_str = struct.pack("llll", 1, X.CurrentTime, 0, 0)

event = event.ClientMessage(
            type = atom,       
               window = xroot_win,
               client_type = X.ClientMessage,
               data = (8, data_str))

# How to set the data?
#data = (4, "\1\0\0\0"))
#data = (8, "G'day mate\0\0\0\0\0\0\0\0\0\0"))

# Is this right?
xroot_win.send_event(event, mask, 0)
disp.flush()

# ------------------------------------------

But the code does nothing.
I have problem with setting the data string right. I suppose the data should be in (binary) string format so I pack it with struct.pack("llll", 1, X.CurrentTime, 0, 0) . It should switch to desktop number 1 (the second Metacity desktop).

This is the original C/Xlib code that works very well.
http://code.google.com/p/gscreendump/source/browse/trunk/src/sd_xutils.c

Function:
void metacity_set_active_desktop(guint desktop_num)
{
    /* Switch to/set active desktop.
       The desktop_num is zero-based: 0, 1, 2...
    */

    /* Metacity or other standards respecting window manager */
    if (desktop_num+1 > get_number_of_desktops()) return;

    Display *display = GDK_DISPLAY();
    Window root_win = GDK_WINDOW_XWINDOW(gdk_get_default_root_window());

    Atom atom_net_current_desktop = XInternAtom(display, "_NET_CURRENT_DESKTOP", False);

    XEvent xevent;
    xevent.type   = ClientMessage;
    xevent.xclient.type = ClientMessage;
    xevent.xclient.display  = display;
    xevent.xclient.window = root_win;
    xevent.xclient.message_type = atom_net_current_desktop;
    xevent.xclient.format  = 32;
    xevent.xclient.data.l[0] = desktop_num;
    xevent.xclient.data.l[1] = CurrentTime;
    xevent.xclient.data.l[2] = 0;
    xevent.xclient.data.l[3] = 0;
    xevent.xclient.data.l[4] = 0;
    XSendEvent(display, root_win, False, SubstructureNotifyMask | SubstructureRedirectMask, &xevent);

    XFlush(display);
}

---------------------
Notice:  The atom "_NET_CURRENT_DESKTOP" works only with flat Metacity or equivalent window manager.
Compiz uses "_NET_DESKTOP_VIEWPORT" atom. And the data values are not desktop numbers, but viewport widths.
This is explained in the compiz_set_active_viewport(guint viewport_num) function in the above C code link.

You should absolutely switch to Metacity (or equivalent GNOME/KDE) window manager before testing this Python code. It will not work with Compiz WM. Type
$ metacity --replace

Thanks in advance.

Kindly Moma Antero.
Oslo, Norway