Store window properties in the server. Moved property.c to dlls/user.

diff --git a/server/protocol.def b/server/protocol.def
index fa0b81e..95bc13a 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -133,6 +133,14 @@
     int   signaled;  /* wait result */
 };
 
+/* structure returned in the list of window properties */
+typedef struct
+{
+    atom_t         atom;     /* property atom */
+    short          string;   /* was atom a string originally? */
+    handle_t       handle;   /* handle stored in property */
+} property_data_t;
+
 /****************************************************************/
 /* Request declarations */
 
@@ -1469,3 +1477,38 @@
     user_handle_t  first_child;   /* first child */
     user_handle_t  last_child;    /* last child */
 @END
+
+
+/* Set a window property */
+@REQ(set_window_property)
+    user_handle_t  window;        /* handle to the window */
+    atom_t         atom;          /* property atom (high-word set if it was a string) */
+    int            string;        /* was atom a string originally? */
+    handle_t       handle;        /* handle to store */
+@END
+
+
+/* Remove a window property */
+@REQ(remove_window_property)
+    user_handle_t  window;        /* handle to the window */
+    atom_t         atom;          /* property atom */
+@REPLY
+    handle_t       handle;        /* handle stored in property */
+@END
+
+
+/* Get a window property */
+@REQ(get_window_property)
+    user_handle_t  window;        /* handle to the window */
+    atom_t         atom;          /* property atom */
+@REPLY
+    handle_t       handle;        /* handle stored in property */
+@END
+
+
+/* Get the list of properties of a window */
+@REQ(get_window_properties)
+    user_handle_t  window;        /* handle to the window */
+@REPLY
+    VARARG(props,properties);     /* list of properties */
+@END
diff --git a/server/request.h b/server/request.h
index 1269e17..8939854 100644
--- a/server/request.h
+++ b/server/request.h
@@ -194,6 +194,10 @@
 DECL_HANDLER(get_window_parents);
 DECL_HANDLER(get_window_children);
 DECL_HANDLER(get_window_tree);
+DECL_HANDLER(set_window_property);
+DECL_HANDLER(remove_window_property);
+DECL_HANDLER(get_window_property);
+DECL_HANDLER(get_window_properties);
 
 #ifdef WANT_REQUEST_HANDLERS
 
@@ -329,6 +333,10 @@
     (req_handler)req_get_window_parents,
     (req_handler)req_get_window_children,
     (req_handler)req_get_window_tree,
+    (req_handler)req_set_window_property,
+    (req_handler)req_remove_window_property,
+    (req_handler)req_get_window_property,
+    (req_handler)req_get_window_properties,
 };
 #endif  /* WANT_REQUEST_HANDLERS */
 
diff --git a/server/trace.c b/server/trace.c
index 094ff25..bd4de67 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -271,6 +271,23 @@
     return get_size(req);
 }
 
+static size_t dump_varargs_properties( const void *req )
+{
+    const property_data_t *prop = get_data(req);
+    size_t len = get_size(req) / sizeof(*prop);
+
+    fputc( '{', stderr );
+    while (len > 0)
+    {
+        fprintf( stderr, "{atom=%04x,str=%d,handle=%08x}",
+                 prop->atom, prop->string, prop->handle );
+        prop++;
+        if (--len) fputc( ',', stderr );
+    }
+    fputc( '}', stderr );
+    return get_size(req);
+}
+
 typedef void (*dump_func)( const void *req );
 
 /* Everything below this line is generated automatically by tools/make_requests */
@@ -1743,6 +1760,47 @@
     fprintf( stderr, " last_child=%08x", req->last_child );
 }
 
+static void dump_set_window_property_request( const struct set_window_property_request *req )
+{
+    fprintf( stderr, " window=%08x,", req->window );
+    fprintf( stderr, " atom=%04x,", req->atom );
+    fprintf( stderr, " string=%d,", req->string );
+    fprintf( stderr, " handle=%d", req->handle );
+}
+
+static void dump_remove_window_property_request( const struct remove_window_property_request *req )
+{
+    fprintf( stderr, " window=%08x,", req->window );
+    fprintf( stderr, " atom=%04x", req->atom );
+}
+
+static void dump_remove_window_property_reply( const struct remove_window_property_request *req )
+{
+    fprintf( stderr, " handle=%d", req->handle );
+}
+
+static void dump_get_window_property_request( const struct get_window_property_request *req )
+{
+    fprintf( stderr, " window=%08x,", req->window );
+    fprintf( stderr, " atom=%04x", req->atom );
+}
+
+static void dump_get_window_property_reply( const struct get_window_property_request *req )
+{
+    fprintf( stderr, " handle=%d", req->handle );
+}
+
+static void dump_get_window_properties_request( const struct get_window_properties_request *req )
+{
+    fprintf( stderr, " window=%08x", req->window );
+}
+
+static void dump_get_window_properties_reply( const struct get_window_properties_request *req )
+{
+    fprintf( stderr, " props=" );
+    cur_pos += dump_varargs_properties( req );
+}
+
 static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_new_process_request,
     (dump_func)dump_get_new_process_info_request,
@@ -1873,6 +1931,10 @@
     (dump_func)dump_get_window_parents_request,
     (dump_func)dump_get_window_children_request,
     (dump_func)dump_get_window_tree_request,
+    (dump_func)dump_set_window_property_request,
+    (dump_func)dump_remove_window_property_request,
+    (dump_func)dump_get_window_property_request,
+    (dump_func)dump_get_window_properties_request,
 };
 
 static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -2005,6 +2067,10 @@
     (dump_func)dump_get_window_parents_reply,
     (dump_func)dump_get_window_children_reply,
     (dump_func)dump_get_window_tree_reply,
+    (dump_func)0,
+    (dump_func)dump_remove_window_property_reply,
+    (dump_func)dump_get_window_property_reply,
+    (dump_func)dump_get_window_properties_reply,
 };
 
 static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -2137,6 +2203,10 @@
     "get_window_parents",
     "get_window_children",
     "get_window_tree",
+    "set_window_property",
+    "remove_window_property",
+    "get_window_property",
+    "get_window_properties",
 };
 
 /* ### make_requests end ### */
diff --git a/server/window.c b/server/window.c
index c57aadf..ff9ba82 100644
--- a/server/window.c
+++ b/server/window.c
@@ -12,6 +12,22 @@
 #include "process.h"
 #include "user.h"
 
+/* a window property */
+struct property
+{
+    unsigned short type;     /* property type (see below) */
+    atom_t         atom;     /* property atom */
+    handle_t       handle;   /* property handle (user-defined storage) */
+};
+
+enum property_type
+{
+    PROP_TYPE_FREE,   /* free entry */
+    PROP_TYPE_STRING, /* atom that was originally a string */
+    PROP_TYPE_ATOM    /* plain atom */
+};
+
+
 struct window
 {
     struct window   *parent;          /* parent window */
@@ -23,7 +39,10 @@
     struct window   *prev;            /* prev window in Z-order */
     user_handle_t    handle;          /* full handle for this window */
     struct thread   *thread;          /* thread owning the window */
-    unsigned int     atom;            /* class atom */
+    atom_t           atom;            /* class atom */
+    int              prop_inuse;      /* number of in-use window properties */
+    int              prop_alloc;      /* number of allocated window properties */
+    struct property *properties;      /* window properties array */
 };
 
 static struct window *top_window;  /* top-level (desktop) window */
@@ -83,6 +102,118 @@
     }
 }
 
+/* set a window property */
+static void set_property( struct window *win, atom_t atom, handle_t handle,
+                          enum property_type type )
+{
+    int i, free = -1;
+    struct property *new_props;
+
+    /* check if it exists already */
+    for (i = 0; i < win->prop_inuse; i++)
+    {
+        if (win->properties[i].type == PROP_TYPE_FREE)
+        {
+            free = i;
+            continue;
+        }
+        if (win->properties[i].atom == atom)
+        {
+            win->properties[i].type = type;
+            win->properties[i].handle = handle;
+            return;
+        }
+    }
+
+    /* need to add an entry */
+    if (!grab_global_atom( atom )) return;
+    if (free == -1)
+    {
+        /* no free entry */
+        if (win->prop_inuse >= win->prop_alloc)
+        {
+            /* need to grow the array */
+            if (!(new_props = realloc( win->properties,
+                                       sizeof(*new_props) * (win->prop_alloc + 16) )))
+            {
+                set_error( STATUS_NO_MEMORY );
+                release_global_atom( atom );
+                return;
+            }
+            win->prop_alloc += 16;
+            win->properties = new_props;
+        }
+        free = win->prop_inuse++;
+    }
+    win->properties[free].atom   = atom;
+    win->properties[free].type   = type;
+    win->properties[free].handle = handle;
+}
+
+/* remove a window property */
+static handle_t remove_property( struct window *win, atom_t atom )
+{
+    int i;
+
+    for (i = 0; i < win->prop_inuse; i++)
+    {
+        if (win->properties[i].type == PROP_TYPE_FREE) continue;
+        if (win->properties[i].atom == atom)
+        {
+            release_global_atom( atom );
+            win->properties[i].type = PROP_TYPE_FREE;
+            return win->properties[i].handle;
+        }
+    }
+    /* FIXME: last error? */
+    return 0;
+}
+
+/* find a window property */
+static handle_t get_property( struct window *win, atom_t atom )
+{
+    int i;
+
+    for (i = 0; i < win->prop_inuse; i++)
+    {
+        if (win->properties[i].type == PROP_TYPE_FREE) continue;
+        if (win->properties[i].atom == atom) return win->properties[i].handle;
+    }
+    /* FIXME: last error? */
+    return 0;
+}
+
+/* destroy all properties of a window */
+inline static void destroy_properties( struct window *win )
+{
+    int i;
+
+    if (!win->properties) return;
+    for (i = 0; i < win->prop_inuse; i++)
+    {
+        if (win->properties[i].type == PROP_TYPE_FREE) continue;
+        release_global_atom( win->properties[i].atom );
+    }
+    free( win->properties );
+}
+
+/* enum all properties into the data array */
+static int enum_properties( struct window *win, property_data_t *data, int max )
+{
+    int i, count;
+
+    for (i = count = 0; i < win->prop_inuse && count < max; i++)
+    {
+        if (win->properties[i].type == PROP_TYPE_FREE) continue;
+        data->atom   = win->properties[i].atom;
+        data->string = (win->properties[i].type == PROP_TYPE_STRING);
+        data->handle = win->properties[i].handle;
+        data++;
+        count++;
+    }
+    return count;
+}
+
 /* destroy a window */
 static void destroy_window( struct window *win )
 {
@@ -104,14 +235,14 @@
 
     if (win->thread->queue) queue_cleanup_window( win->thread, win->handle );
     free_user_handle( win->handle );
+    destroy_properties( win );
     unlink_window( win );
     memset( win, 0x55, sizeof(*win) );
     free( win );
 }
 
 /* create a new window structure (note: the window is not linked in the window tree) */
-static struct window *create_window( struct window *parent, struct window *owner,
-                                     unsigned int atom )
+static struct window *create_window( struct window *parent, struct window *owner, atom_t atom )
 {
     struct window *win = mem_alloc( sizeof(*win) );
     if (!win) return NULL;
@@ -128,6 +259,9 @@
     win->first_unlinked = NULL;
     win->thread         = current;
     win->atom           = atom;
+    win->prop_inuse     = 0;
+    win->prop_alloc     = 0;
+    win->properties     = NULL;
 
     if (parent)  /* put it on parent unlinked list */
     {
@@ -340,3 +474,43 @@
     req->first_child = win->first_child ? win->first_child->handle : 0;
     req->last_child  = win->last_child ? win->last_child->handle : 0;
 }
+
+
+/* set a window property */
+DECL_HANDLER(set_window_property)
+{
+    struct window *win = get_window( req->window );
+
+    if (win) set_property( win, req->atom, req->handle,
+                           req->string ? PROP_TYPE_STRING : PROP_TYPE_ATOM );
+}
+
+
+/* remove a window property */
+DECL_HANDLER(remove_window_property)
+{
+    struct window *win = get_window( req->window );
+    req->handle = 0;
+    if (win) req->handle = remove_property( win, req->atom );
+}
+
+
+/* get a window property */
+DECL_HANDLER(get_window_property)
+{
+    struct window *win = get_window( req->window );
+    req->handle = 0;
+    if (win) req->handle = get_property( win, req->atom );
+}
+
+
+/* get the list of properties of a window */
+DECL_HANDLER(get_window_properties)
+{
+    int count = 0;
+    property_data_t *data = get_req_data(req);
+    struct window *win = get_window( req->window );
+
+    if (win) count = enum_properties( win, data, get_req_data_size(req) / sizeof(*data) );
+    set_req_data_size( req, count * sizeof(*data) );
+}