- use global atoms for the format ids
- add timeout when calling XCheckTypedWindowEvent
- fix broken IsClipboardFormatAvailable; it tried to do a trick with
EnumClipboardFormats by making incorrect assumptions
- in X11DRV_IsClipboardFormatAvailable do a quick exit if no one owns
the selection
- add 1 second *minimum* time lapse between XSelectionOwner calls
- sync clipboard ownership between different wine processes
- prevents apps from getting into wierd state where they thought they
didn't own the selection but they did and as a result queried
themselves for available selection data
diff --git a/server/Makefile.in b/server/Makefile.in
index 1d6211c..828b37f 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -9,6 +9,7 @@
async.c \
atom.c \
change.c \
+ clipboard.c \
console.c \
context_i386.c \
context_powerpc.c \
diff --git a/server/clipboard.c b/server/clipboard.c
new file mode 100644
index 0000000..5a885a0
--- /dev/null
+++ b/server/clipboard.c
@@ -0,0 +1,160 @@
+/*
+ * Server-side clipboard management
+ *
+ * Copyright (C) 2002 Ulrich Czekalla
+ *
+ * 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 "request.h"
+#include "object.h"
+#include "user.h"
+
+struct thread *cbthread; /* thread id that has clipboard open */
+static user_handle_t clipboard; /* window that has clipboard open */
+
+struct thread *cbowner; /* thread id that owns the clipboard */
+static user_handle_t owner; /* window that owns the clipboard data */
+
+static user_handle_t viewer; /* first window in clipboard viewer list */
+static unsigned int seqno; /* clipboard change sequence number */
+static time_t seqnots; /* time stamp of last seqno increment */
+
+#define MINUPDATELAPSE 2
+
+/* Called when thread terminates to allow release of clipboard */
+void cleanup_clipboard_thread(struct thread *thread)
+{
+ if (thread == cbthread)
+ {
+ clipboard = 0;
+ cbthread = NULL;
+ }
+ if (thread == cbowner)
+ {
+ owner = 0;
+ cbowner = NULL;
+ }
+}
+
+static int set_clipboard_window(user_handle_t win, int clear)
+{
+ if (cbthread && cbthread != current)
+ {
+ set_error(STATUS_WAS_LOCKED);
+ return 0;
+ }
+ else if (!clear)
+ {
+ clipboard = win;
+ cbthread = current;
+ }
+ else
+ {
+ cbthread = NULL;
+ clipboard = 0;
+ }
+ return 1;
+}
+
+
+static int set_clipboard_owner(user_handle_t win, int clear)
+{
+ if (cbthread == current)
+ {
+ if (!clear)
+ {
+ cbowner = current;
+ owner = win;
+ }
+ else
+ {
+ cbowner = 0;
+ owner = 0;
+ }
+ seqno++;
+ return 1;
+ }
+ else
+ {
+ set_error(STATUS_WAS_LOCKED);
+ return 0;
+ }
+}
+
+
+static int get_seqno(void)
+{
+ time_t tm = time(NULL);
+
+ if (!cbowner && (tm > (seqnots + MINUPDATELAPSE)))
+ {
+ seqnots = tm;
+ seqno++;
+ }
+ return seqno;
+}
+
+
+DECL_HANDLER(set_clipboard_info)
+{
+ reply->old_clipboard = clipboard;
+ reply->old_owner = owner;
+ reply->old_viewer = viewer;
+
+ if (req->flags & SET_CB_OPEN)
+ {
+ if (!set_clipboard_window(req->clipboard, 0))
+ return;
+ }
+ else if (req->flags & SET_CB_CLOSE)
+ {
+ if (!set_clipboard_window(0, 1))
+ return;
+ }
+
+ if (req->flags & SET_CB_OWNER)
+ {
+ if (!set_clipboard_owner(req->owner, 0))
+ return;
+ }
+ else if (req->flags & SET_CB_RELOWNER)
+ {
+ if (!set_clipboard_owner(0, 1))
+ return;
+ }
+
+ if (req->flags & SET_CB_VIEWER)
+ viewer = req->viewer;
+
+ if (req->flags & SET_CB_SEQNO)
+ seqno++;
+
+ reply->seqno = get_seqno();
+
+ if (cbthread == current)
+ reply->flags |= CB_OPEN;
+
+ if (cbowner == current)
+ reply->flags |= CB_OWNER;
+}
diff --git a/server/protocol.def b/server/protocol.def
index fb820a8..bb3e37a 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2124,3 +2124,28 @@
int next_unicode; /* is the next a unicode hook? */
VARARG(module,unicode_str); /* module name */
@END
+
+
+/* Set/get clipboard information */
+@REQ(set_clipboard_info)
+ unsigned int flags; /* flags for fields to set (see below) */
+ user_handle_t clipboard; /* clipboard window */
+ user_handle_t owner; /* clipboard owner */
+ user_handle_t viewer; /* first clipboard viewer */
+ unsigned int seqno; /* change sequence number */
+@REPLY
+ unsigned int flags; /* status flags (see below) */
+ user_handle_t old_clipboard; /* old clipboard window */
+ user_handle_t old_owner; /* old clipboard owner */
+ user_handle_t old_viewer; /* old clipboard viewer */
+ unsigned int seqno; /* current sequence number */
+@END
+
+#define SET_CB_OPEN 0x001
+#define SET_CB_OWNER 0x002
+#define SET_CB_VIEWER 0x004
+#define SET_CB_SEQNO 0x008
+#define SET_CB_RELOWNER 0x010
+#define SET_CB_CLOSE 0x020
+#define CB_OPEN 0x040
+#define CB_OWNER 0x080
diff --git a/server/request.h b/server/request.h
index 60d9439..e28594e 100644
--- a/server/request.h
+++ b/server/request.h
@@ -278,6 +278,7 @@
DECL_HANDLER(start_hook_chain);
DECL_HANDLER(finish_hook_chain);
DECL_HANDLER(get_next_hook);
+DECL_HANDLER(set_clipboard_info);
#ifdef WANT_REQUEST_HANDLERS
@@ -459,6 +460,7 @@
(req_handler)req_start_hook_chain,
(req_handler)req_finish_hook_chain,
(req_handler)req_get_next_hook,
+ (req_handler)req_set_clipboard_info,
};
#endif /* WANT_REQUEST_HANDLERS */
diff --git a/server/thread.c b/server/thread.c
index c6ef4ac..a600bf1 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -210,6 +210,7 @@
if (thread->wait_fd) release_object( thread->wait_fd );
if (thread->hooks) release_object( thread->hooks );
free_msg_queue( thread );
+ cleanup_clipboard_thread(thread);
destroy_thread_windows( thread );
for (i = 0; i < MAX_INFLIGHT_FDS; i++)
{
diff --git a/server/trace.c b/server/trace.c
index 1e93cb1..2067695 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -2458,6 +2458,24 @@
dump_varargs_unicode_str( cur_size );
}
+static void dump_set_clipboard_info_request( const struct set_clipboard_info_request *req )
+{
+ fprintf( stderr, " flags=%08x,", req->flags );
+ fprintf( stderr, " clipboard=%p,", req->clipboard );
+ fprintf( stderr, " owner=%p,", req->owner );
+ fprintf( stderr, " viewer=%p,", req->viewer );
+ fprintf( stderr, " seqno=%08x", req->seqno );
+}
+
+static void dump_set_clipboard_info_reply( const struct set_clipboard_info_reply *req )
+{
+ fprintf( stderr, " flags=%08x,", req->flags );
+ fprintf( stderr, " old_clipboard=%p,", req->old_clipboard );
+ fprintf( stderr, " old_owner=%p,", req->old_owner );
+ fprintf( stderr, " old_viewer=%p,", req->old_viewer );
+ fprintf( stderr, " seqno=%08x", req->seqno );
+}
+
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_new_process_request,
(dump_func)dump_get_new_process_info_request,
@@ -2634,6 +2652,7 @@
(dump_func)dump_start_hook_chain_request,
(dump_func)dump_finish_hook_chain_request,
(dump_func)dump_get_next_hook_request,
+ (dump_func)dump_set_clipboard_info_request,
};
static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -2812,6 +2831,7 @@
(dump_func)dump_start_hook_chain_reply,
(dump_func)0,
(dump_func)dump_get_next_hook_reply,
+ (dump_func)dump_set_clipboard_info_reply,
};
static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -2990,6 +3010,7 @@
"start_hook_chain",
"finish_hook_chain",
"get_next_hook",
+ "set_clipboard_info",
};
/* ### make_requests end ### */
diff --git a/server/user.h b/server/user.h
index 24c18d5..0d038b6 100644
--- a/server/user.h
+++ b/server/user.h
@@ -42,6 +42,10 @@
extern void *free_user_handle( user_handle_t handle );
extern void *next_user_handle( user_handle_t *handle, enum user_object type );
+/* clipboard functions */
+
+extern void cleanup_clipboard_thread( struct thread *thread );
+
/* hook functions */
extern void close_global_hooks(void);