Hello.

I've spent last day investigating this bug. The problem lies whithin
Xlib and the integer format in librep, but the short-term solution goes
in sawfish. I would like to reopen this bug as soon as it is closed and
reassing it to Xlib.

I will describe what I could find out about this bug and attach a patch
that you should test. I also think #403100 and #406559 are the same
bug, but I will wait for a confirmation before merging them.

In fact, I have done my tests based on the experience of #403100,
opening fbpanel, but have watched the same error as in #406559, the bad
argument for make-vector.

The error is triggered when sawfish receives a _NET_WM_DESKTOP from the
client with 0xFFFFFFFF as a parameter, which EWMH describes as sticking
the window for every desktop/workspace. The rep/lisp code is the
following:

        ((_NET_WM_DESKTOP)
         (when (windowp w)
           (let ((desktop (aref data 0)))
             (if (eql desktop #xffffffff)
                 ;; making window sticky
                 (make-window-sticky/workspace w)
               ;; changing the desktop
               (make-window-unsticky/workspace w)
               (send-window-to-workspace-from-first w desktop nil)))))

This means the window will be made stick to all workspaces if the
parameter is 0xFFFFFFFF and will be made unstick and sent to the
desktop-nth workspace.

In 64 bits, this number turns to be 0xFFFFFFFFFFFFFFFF, i.e., a 64-bit
-1. In amd64, adding this 8 more digits solves the problem. We could do
an or for both values as a solution. Using -1 as a solution does not
solve it, since sawfish creates this rep number as unsigned and librep
turns these into BigInt, since it uses 2 bits in the number
representation for distinguishing between types.

So, when calling the client-message-hook from C code, sawfish creates
the vector and the numbers for the parameters. X protocol has 3 formats
for these messages: 20 8-bit parameters, 10 16-bit parameters or 5
32-bit parameters. _NET_WM_DESKTOP has format 32. Xlib, however, uses
long as the type of the 32-bit parameters. And it tries to be smart
when sending this data to the user, converting it from 32 bit unsigned
to the native long format of the host. So, a 32-bit 1's is converted to
64-bit 1's.

So, what is my fix? Well, before creating the numbers for rep from the
64-bit data Xlib gives us, I convert them back to unsigned 32-bit,
using uint32_t type. So, we get 0xFFFFFFFF back. This is also a more
generic fix, since any other messages, not only _NET_WM_DESKTOP, will
be fixed.

As a bonus, I attach my XCB code that will trigger the problem. Please,
try it and the fix in 32-bit too, so we can be sure there will be no
regression.

Regards,
Thadeu Cascardo.
--- sawfish-1.3.1.old/src/events.c	2008-01-01 01:46:12.000000000 -0200
+++ sawfish-1.3.1/src/events.c	2008-01-01 01:45:22.000000000 -0200
@@ -21,6 +21,7 @@
 
 #include "sawmill.h"
 #include <limits.h>
+#include <stdint.h>
 #include <string.h>
 #include <time.h>
 #include <X11/extensions/shape.h>
@@ -641,7 +642,10 @@
     case 32:
 	data = Fmake_vector (rep_MAKE_INT(5), Qnil);
 	for (i = 0; i < 5; i++)
-	    rep_VECTI(data,i) = rep_make_long_uint (ev->xclient.data.l[i]);
+	{
+	    unsigned long l = (uint32_t) ev->xclient.data.l[i];
+	    rep_VECTI(data,i) = rep_make_long_uint (l);
+	}
 	break;
 
     default:
#include <xcb/xcb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

xcb_atom_t
X_GetAtom (xcb_connection_t *conn, char *name, size_t name_len)
{
  xcb_atom_t atom;
  xcb_intern_atom_cookie_t cookie;
  xcb_intern_atom_reply_t *reply;
  cookie = xcb_intern_atom (conn, 0, name_len, name);
  reply = xcb_intern_atom_reply (conn, cookie, NULL);
  if (reply)
    {
      atom = reply->atom;
      free (reply);
      return atom;
    }
  return -1;
}

int
main (int argc, char **argv)
{
  xcb_connection_t *conn;
  xcb_screen_iterator_t iter;
  xcb_client_message_event_t event;
  xcb_void_cookie_t cookie;
  xcb_generic_error_t *error;
  xcb_window_t root;
  xcb_window_t window;
  conn = xcb_connect (NULL, NULL);
  iter = xcb_setup_roots_iterator (xcb_get_setup (conn));
  root = iter.data->root;
  window = xcb_generate_id (conn);
  fprintf (stdout, "Root window has ID %x\n", root);
  fprintf (stdout, "New window has ID %x\n", window);
  cookie = xcb_create_window_checked (conn, 0, window, root, 0, 0,
                                      128, 128, XCB_COPY_FROM_PARENT,
                                      XCB_WINDOW_CLASS_COPY_FROM_PARENT,
                                      XCB_COPY_FROM_PARENT, 0, NULL);
  error = xcb_request_check (conn, cookie);
  if (error != NULL)
    {
      xcb_request_error_t *rerror = (xcb_request_error_t *) error;
      fprintf (stderr, "Could not create window: ");
      fprintf (stderr, "Response is %d and error code is %d\n",
                        error->response_type, error->error_code);
      fprintf (stderr, "Bad value is %x\n", rerror->bad_value);
      free (error);
    }
  cookie = xcb_map_window_checked (conn, window);
  error = xcb_request_check (conn, cookie);
  if (error != NULL)
    {
      xcb_request_error_t *rerror = (xcb_request_error_t *) error;
      fprintf (stderr, "Could not map window: ");
      fprintf (stderr, "Response is %d and error code is %d\n",
                        error->response_type, error->error_code);
      fprintf (stderr, "Bad value is %x\n", rerror->bad_value);
      free (error);
    }
  event.response_type = XCB_CLIENT_MESSAGE;
  event.format = 32;
  event.sequence = 0xCAFE;
  event.window = window;
  /*
  event.type = X_GetAtom (conn, "_NET_WM_DESKTOP",
                          sizeof ("_NET_WM_DESKTOP"));
  */
  event.type = 241;
  memset (event.data.data8, 0, 20);
  event.data.data32[0] = -1;
  event.data.data32[1] = -1;
  cookie = xcb_send_event_checked (conn, 0, root,
                                   XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
                                   XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
                                   (char *) &event);
  error = xcb_request_check (conn, cookie);
  if (error != NULL)
    {
      fprintf (stderr, "Could not send client message: ");
      fprintf (stderr, "Response is %d and error code is %d\n",
                        error->response_type, error->error_code);
      free (error);
    }
  while (1);
  xcb_disconnect (conn);
  return 0;
}

Reply via email to