wine/server/clipboard.c
Ulrich Czekalla 5067909587 Create a thread-specific selection window to make sure we receive the
selection events in the correct thread.
2005-03-07 19:31:46 +00:00

173 lines
3.9 KiB
C

/*
* 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"
static struct thread *cbthread; /* thread id that has clipboard open */
static user_handle_t clipboard; /* window that has clipboard open */
static 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 && cbthread->process != current->process)
{
set_error(STATUS_WAS_LOCKED);
return 0;
}
else if (!clear)
{
owner = win;
cbowner = current;
}
else
{
owner = 0;
cbowner = NULL;
}
return 1;
}
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 (cbthread)
{
/* clipboard already opened */
set_error(STATUS_WAS_LOCKED);
return;
}
if (!set_clipboard_window(req->clipboard, 0))
return;
}
else if (req->flags & SET_CB_CLOSE)
{
if (cbthread != current)
{
set_win32_error(ERROR_CLIPBOARD_NOT_OPEN);
return;
}
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;
if (cbowner &&
cbowner->process == current->process)
reply->flags |= CB_PROCESS;
}