Added window classes in the server, and support for inter-process
GetClassWord/Long (based on a patch by Mike McCormack).
Various fixes to the class instance handling.
diff --git a/server/Makefile.in b/server/Makefile.in
index 1955d67..2f4275d 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -9,6 +9,7 @@
async.c \
atom.c \
change.c \
+ class.c \
clipboard.c \
console.c \
context_i386.c \
diff --git a/server/class.c b/server/class.c
new file mode 100644
index 0000000..13d9d5c
--- /dev/null
+++ b/server/class.c
@@ -0,0 +1,204 @@
+/*
+ * Server-side window class management
+ *
+ * Copyright (C) 2002 Mike McCormack
+ * Copyright (C) 2003 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "wine/list.h"
+
+#include "request.h"
+#include "object.h"
+#include "process.h"
+#include "user.h"
+
+struct window_class
+{
+ struct list entry; /* entry in process list */
+ struct process *process; /* process owning the class */
+ int count; /* reference count */
+ int local; /* local class? */
+ atom_t atom; /* class atom */
+ void *instance; /* module instance */
+ unsigned int style; /* class style */
+ int win_extra; /* number of window extra bytes */
+ int nb_extra_bytes; /* number of extra bytes */
+ char extra_bytes[1]; /* extra bytes storage */
+};
+
+static struct window_class *create_class( struct process *process, int extra_bytes, int local )
+{
+ struct window_class *class;
+
+ if (!(class = mem_alloc( sizeof(*class) + extra_bytes - 1 ))) return NULL;
+
+ class->process = (struct process *)grab_object( process );
+ class->count = 0;
+ class->local = local;
+ class->nb_extra_bytes = extra_bytes;
+ memset( class->extra_bytes, 0, extra_bytes );
+ /* other fields are initialized by caller */
+
+ /* local classes have priority so we put them first in the list */
+ if (local) list_add_head( &process->classes, &class->entry );
+ else list_add_tail( &process->classes, &class->entry );
+ return class;
+}
+
+static void destroy_class( struct window_class *class )
+{
+ list_remove( &class->entry );
+ release_object( class->process );
+ free( class );
+}
+
+void destroy_process_classes( struct process *process )
+{
+ struct list *ptr;
+
+ while ((ptr = list_head( &process->classes )))
+ {
+ struct window_class *class = LIST_ENTRY( ptr, struct window_class, entry );
+ destroy_class( class );
+ }
+}
+
+static struct window_class *find_class( struct process *process, atom_t atom, void *instance )
+{
+ struct list *ptr;
+
+ LIST_FOR_EACH( ptr, &process->classes )
+ {
+ struct window_class *class = LIST_ENTRY( ptr, struct window_class, entry );
+ if (class->atom != atom) continue;
+ if (!instance || !class->local || class->instance == instance) return class;
+ }
+ return NULL;
+}
+
+struct window_class *grab_class( struct process *process, atom_t atom, void *instance )
+{
+ struct window_class *class = find_class( process, atom, instance );
+ if (class) class->count++;
+ else set_error( STATUS_INVALID_HANDLE );
+ return class;
+}
+
+void release_class( struct window_class *class )
+{
+ assert( class->count > 0 );
+ class->count--;
+}
+
+atom_t get_class_atom( struct window_class *class )
+{
+ return class->atom;
+}
+
+/* create a window class */
+DECL_HANDLER(create_class)
+{
+ struct window_class *class = find_class( current->process, req->atom, req->instance );
+
+ if (class && !class->local == !req->local)
+ {
+ set_win32_error( ERROR_CLASS_ALREADY_EXISTS );
+ return;
+ }
+ if (req->extra < 0 || req->extra > 4096) /* don't allow stupid values here */
+ {
+ set_error( STATUS_INVALID_PARAMETER );
+ return;
+ }
+ if (!grab_global_atom( req->atom )) return;
+
+ if (!(class = create_class( current->process, req->extra, req->local )))
+ {
+ release_global_atom( req->atom );
+ return;
+ }
+ class->atom = req->atom;
+ class->instance = req->instance;
+ class->style = req->style;
+ class->win_extra = req->win_extra;
+}
+
+/* destroy a window class */
+DECL_HANDLER(destroy_class)
+{
+ struct window_class *class = find_class( current->process, req->atom, req->instance );
+
+ if (!class)
+ set_error( STATUS_INVALID_HANDLE );
+ else if (class->count)
+ set_win32_error( ERROR_CLASS_HAS_WINDOWS );
+ else
+ destroy_class( class );
+}
+
+
+/* set some information in a class */
+DECL_HANDLER(set_class_info)
+{
+ struct window_class *class = get_window_class( req->window );
+
+ if (!class) return;
+
+ if (req->extra_size > sizeof(req->extra_value) ||
+ req->extra_offset < -1 ||
+ req->extra_offset > class->nb_extra_bytes - (int)req->extra_size)
+ {
+ set_win32_error( ERROR_INVALID_INDEX );
+ return;
+ }
+ if (req->extra_offset != -1)
+ {
+ memcpy( &reply->old_extra_value, class->extra_bytes + req->extra_offset, req->extra_size );
+ }
+ else if (req->flags & SET_CLASS_EXTRA)
+ {
+ set_win32_error( ERROR_INVALID_INDEX );
+ return;
+ }
+
+ reply->old_atom = class->atom;
+ reply->old_style = class->style;
+ reply->old_extra = class->nb_extra_bytes;
+ reply->old_win_extra = class->win_extra;
+ reply->old_instance = class->instance;
+
+ if (req->flags & SET_CLASS_ATOM)
+ {
+ if (!grab_global_atom( req->atom )) return;
+ release_global_atom( class->atom );
+ class->atom = req->atom;
+ }
+ if (req->flags & SET_CLASS_STYLE) class->style = req->style;
+ if (req->flags & SET_CLASS_WINEXTRA) class->win_extra = req->win_extra;
+ if (req->flags & SET_CLASS_INSTANCE) class->instance = req->instance;
+ if (req->flags & SET_CLASS_EXTRA) memcpy( class->extra_bytes + req->extra_offset,
+ &req->extra_value, req->extra_size );
+}
+
diff --git a/server/process.c b/server/process.c
index fd96614..0927559 100644
--- a/server/process.c
+++ b/server/process.c
@@ -44,6 +44,7 @@
#include "thread.h"
#include "request.h"
#include "console.h"
+#include "user.h"
/* process structure */
@@ -283,6 +284,7 @@
process->group_id = 0;
process->token = create_token();
list_init( &process->locks );
+ list_init( &process->classes );
gettimeofday( &process->start_time, NULL );
if ((process->next = first_process) != NULL) process->next->prev = process;
@@ -597,6 +599,7 @@
if (dll->filename) free( dll->filename );
free( dll );
}
+ destroy_process_classes( process );
set_process_startup_state( process, STARTUP_ABORTED );
if (process->exe.file) release_object( process->exe.file );
process->exe.file = NULL;
diff --git a/server/process.h b/server/process.h
index cd759f2..cbf41f9 100644
--- a/server/process.h
+++ b/server/process.h
@@ -68,6 +68,7 @@
int suspend; /* global process suspend count */
int create_flags; /* process creation flags */
struct list locks; /* list of file locks owned by the process */
+ struct list classes; /* window classes owned by the process */
struct console_input*console; /* console input */
enum startup_state startup_state; /* startup state */
struct startup_info *startup_info; /* startup info while init is in progress */
diff --git a/server/protocol.def b/server/protocol.def
index c9d4df9..16c6c50 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1780,6 +1780,7 @@
user_handle_t parent; /* parent window */
user_handle_t owner; /* owner window */
atom_t atom; /* class atom */
+ void* instance; /* module instance */
int extra; /* number of extra bytes */
@REPLY
user_handle_t handle; /* created window */
@@ -2129,6 +2130,50 @@
@END
+/* Create a window class */
+@REQ(create_class)
+ int local; /* is it a local class? */
+ atom_t atom; /* class atom */
+ unsigned int style; /* class style */
+ void* instance; /* module instance */
+ int extra; /* number of extra class bytes */
+ int win_extra; /* number of window extra bytes */
+@END
+
+
+/* Destroy a window class */
+@REQ(destroy_class)
+ atom_t atom; /* class atom */
+ void* instance; /* module instance */
+@END
+
+
+/* Set some information in a class */
+@REQ(set_class_info)
+ user_handle_t window; /* handle to the window */
+ unsigned int flags; /* flags for info to set (see below) */
+ atom_t atom; /* class atom */
+ unsigned int style; /* class style */
+ int win_extra; /* number of window extra bytes */
+ void* instance; /* module instance */
+ int extra_offset; /* offset to set in extra bytes */
+ size_t extra_size; /* size to set in extra bytes */
+ unsigned int extra_value; /* value to set in extra bytes */
+@REPLY
+ atom_t old_atom; /* previous class atom */
+ unsigned int old_style; /* previous class style */
+ int old_extra; /* previous number of class extra bytes */
+ int old_win_extra; /* previous number of window extra bytes */
+ void* old_instance; /* previous module instance */
+ unsigned int old_extra_value; /* old value in extra bytes */
+@END
+#define SET_CLASS_ATOM 0x0001
+#define SET_CLASS_STYLE 0x0002
+#define SET_CLASS_WINEXTRA 0x0004
+#define SET_CLASS_INSTANCE 0x0008
+#define SET_CLASS_EXTRA 0x0010
+
+
/* Set/get clipboard information */
@REQ(set_clipboard_info)
unsigned int flags; /* flags for fields to set (see below) */
diff --git a/server/request.h b/server/request.h
index a0287ad..ec2d5a1 100644
--- a/server/request.h
+++ b/server/request.h
@@ -279,6 +279,9 @@
DECL_HANDLER(start_hook_chain);
DECL_HANDLER(finish_hook_chain);
DECL_HANDLER(get_next_hook);
+DECL_HANDLER(create_class);
+DECL_HANDLER(destroy_class);
+DECL_HANDLER(set_class_info);
DECL_HANDLER(set_clipboard_info);
DECL_HANDLER(open_token);
DECL_HANDLER(set_global_windows);
@@ -464,6 +467,9 @@
(req_handler)req_start_hook_chain,
(req_handler)req_finish_hook_chain,
(req_handler)req_get_next_hook,
+ (req_handler)req_create_class,
+ (req_handler)req_destroy_class,
+ (req_handler)req_set_class_info,
(req_handler)req_set_clipboard_info,
(req_handler)req_open_token,
(req_handler)req_set_global_windows,
diff --git a/server/trace.c b/server/trace.c
index 3405a00..97ec3f5 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -2096,6 +2096,7 @@
fprintf( stderr, " parent=%p,", req->parent );
fprintf( stderr, " owner=%p,", req->owner );
fprintf( stderr, " atom=%04x,", req->atom );
+ fprintf( stderr, " instance=%p,", req->instance );
fprintf( stderr, " extra=%d", req->extra );
}
@@ -2503,6 +2504,45 @@
dump_varargs_unicode_str( cur_size );
}
+static void dump_create_class_request( const struct create_class_request *req )
+{
+ fprintf( stderr, " local=%d,", req->local );
+ fprintf( stderr, " atom=%04x,", req->atom );
+ fprintf( stderr, " style=%08x,", req->style );
+ fprintf( stderr, " instance=%p,", req->instance );
+ fprintf( stderr, " extra=%d,", req->extra );
+ fprintf( stderr, " win_extra=%d", req->win_extra );
+}
+
+static void dump_destroy_class_request( const struct destroy_class_request *req )
+{
+ fprintf( stderr, " atom=%04x,", req->atom );
+ fprintf( stderr, " instance=%p", req->instance );
+}
+
+static void dump_set_class_info_request( const struct set_class_info_request *req )
+{
+ fprintf( stderr, " window=%p,", req->window );
+ fprintf( stderr, " flags=%08x,", req->flags );
+ fprintf( stderr, " atom=%04x,", req->atom );
+ fprintf( stderr, " style=%08x,", req->style );
+ fprintf( stderr, " win_extra=%d,", req->win_extra );
+ fprintf( stderr, " instance=%p,", req->instance );
+ fprintf( stderr, " extra_offset=%d,", req->extra_offset );
+ fprintf( stderr, " extra_size=%d,", req->extra_size );
+ fprintf( stderr, " extra_value=%08x", req->extra_value );
+}
+
+static void dump_set_class_info_reply( const struct set_class_info_reply *req )
+{
+ fprintf( stderr, " old_atom=%04x,", req->old_atom );
+ fprintf( stderr, " old_style=%08x,", req->old_style );
+ fprintf( stderr, " old_extra=%d,", req->old_extra );
+ fprintf( stderr, " old_win_extra=%d,", req->old_win_extra );
+ fprintf( stderr, " old_instance=%p,", req->old_instance );
+ fprintf( stderr, " old_extra_value=%08x", req->old_extra_value );
+}
+
static void dump_set_clipboard_info_request( const struct set_clipboard_info_request *req )
{
fprintf( stderr, " flags=%08x,", req->flags );
@@ -2726,6 +2766,9 @@
(dump_func)dump_start_hook_chain_request,
(dump_func)dump_finish_hook_chain_request,
(dump_func)dump_get_next_hook_request,
+ (dump_func)dump_create_class_request,
+ (dump_func)dump_destroy_class_request,
+ (dump_func)dump_set_class_info_request,
(dump_func)dump_set_clipboard_info_request,
(dump_func)dump_open_token_request,
(dump_func)dump_set_global_windows_request,
@@ -2908,6 +2951,9 @@
(dump_func)dump_start_hook_chain_reply,
(dump_func)0,
(dump_func)dump_get_next_hook_reply,
+ (dump_func)0,
+ (dump_func)0,
+ (dump_func)dump_set_class_info_reply,
(dump_func)dump_set_clipboard_info_reply,
(dump_func)dump_open_token_reply,
(dump_func)dump_set_global_windows_reply,
@@ -3090,6 +3136,9 @@
"start_hook_chain",
"finish_hook_chain",
"get_next_hook",
+ "create_class",
+ "destroy_class",
+ "set_class_info",
"set_clipboard_info",
"open_token",
"set_global_windows",
diff --git a/server/user.h b/server/user.h
index a075dd7..8c07b7f 100644
--- a/server/user.h
+++ b/server/user.h
@@ -27,6 +27,7 @@
struct window;
struct msg_queue;
struct hook_table;
+struct window_class;
enum user_object
{
@@ -72,5 +73,13 @@
extern struct thread *get_window_thread( user_handle_t handle );
extern user_handle_t window_from_point( int x, int y );
extern user_handle_t find_window_to_repaint( user_handle_t parent, struct thread *thread );
+extern struct window_class *get_window_class( user_handle_t window );
+
+/* window class functions */
+
+extern void destroy_process_classes( struct process *process );
+extern struct window_class *grab_class( struct process *process, atom_t atom, void *instance );
+extern void release_class( struct window_class *class );
+extern atom_t get_class_atom( struct window_class *class );
#endif /* __WINE_SERVER_USER_H */
diff --git a/server/window.c b/server/window.c
index 6373068..d6a1b6f 100644
--- a/server/window.c
+++ b/server/window.c
@@ -63,6 +63,7 @@
struct window *prev; /* prev window in Z-order */
user_handle_t handle; /* full handle for this window */
struct thread *thread; /* thread owning the window */
+ struct window_class *class; /* window class */
atom_t atom; /* class atom */
user_handle_t last_active; /* last active popup */
rectangle_t window_rect; /* window rectangle */
@@ -260,6 +261,7 @@
free_user_handle( win->handle );
destroy_properties( win );
unlink_window( win );
+ release_class( win->class );
if (win->text) free( win->text );
memset( win, 0x55, sizeof(*win) );
free( win );
@@ -267,13 +269,23 @@
/* 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, atom_t atom,
- int extra_bytes )
+ void *instance, int extra_bytes )
{
- struct window *win = mem_alloc( sizeof(*win) + extra_bytes - 1 );
- if (!win) return NULL;
+ struct window *win;
+ struct window_class *class = grab_class( current->process, atom, instance );
+
+ if (!class) return NULL;
+
+ win = mem_alloc( sizeof(*win) + extra_bytes - 1 );
+ if (!win)
+ {
+ release_class( class );
+ return NULL;
+ }
if (!(win->handle = alloc_user_handle( win, USER_WINDOW )))
{
+ release_class( class );
free( win );
return NULL;
}
@@ -283,6 +295,7 @@
win->last_child = NULL;
win->first_unlinked = NULL;
win->thread = current;
+ win->class = class;
win->atom = atom;
win->last_active = win->handle;
win->style = 0;
@@ -449,6 +462,15 @@
}
+/* get the window class of a window */
+struct window_class* get_window_class( user_handle_t window )
+{
+ struct window *win;
+ if (!(win = get_window( window ))) return NULL;
+ return win->class;
+}
+
+
/* create a window */
DECL_HANDLER(create_window)
{
@@ -462,7 +484,7 @@
{
if (!top_window)
{
- if (!(top_window = create_window( NULL, NULL, req->atom, req->extra ))) return;
+ if (!(top_window = create_window( NULL, NULL, req->atom, req->instance, req->extra ))) return;
top_window->thread = NULL; /* no thread owns the desktop */
top_window->style = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
}
@@ -481,7 +503,7 @@
set_error( STATUS_ACCESS_DENIED );
return;
}
- if (!(win = create_window( parent, owner, req->atom, req->extra ))) return;
+ if (!(win = create_window( parent, owner, req->atom, req->instance, req->extra ))) return;
reply->handle = win->handle;
}
}
@@ -569,7 +591,7 @@
{
reply->tid = get_thread_id( win->thread );
reply->pid = get_process_id( win->thread->process );
- reply->atom = win->atom;
+ reply->atom = get_class_atom( win->class );
}
}
}
@@ -648,7 +670,7 @@
if (parent)
for (ptr = parent->first_child, total = 0; ptr; ptr = ptr->next)
{
- if (req->atom && ptr->atom != req->atom) continue;
+ if (req->atom && get_class_atom(ptr->class) != req->atom) continue;
if (req->tid && get_thread_id(ptr->thread) != req->tid) continue;
total++;
}
@@ -659,7 +681,7 @@
{
for (ptr = parent->first_child; ptr && len; ptr = ptr->next)
{
- if (req->atom && ptr->atom != req->atom) continue;
+ if (req->atom && get_class_atom(ptr->class) != req->atom) continue;
if (req->tid && get_thread_id(ptr->thread) != req->tid) continue;
*data++ = ptr->handle;
len -= sizeof(*data);