Move named pipe objects into directory name space.
[wine] / server / clipboard.c
1 /*
2  * Server-side clipboard management
3  *
4  * Copyright (C) 2002 Ulrich Czekalla
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <assert.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 #include "ntstatus.h"
30 #define WIN32_NO_STATUS
31 #include "request.h"
32 #include "object.h"
33 #include "user.h"
34 #include "winuser.h"
35 #include "winternl.h"
36
37 struct clipboard
38 {
39     struct object  obj;              /* object header */
40     struct thread *open_thread;      /* thread id that has clipboard open */
41     user_handle_t  open_win;         /* window that has clipboard open */
42     struct thread *owner_thread;     /* thread id that owns the clipboard */
43     user_handle_t  owner_win;        /* window that owns the clipboard data */
44     user_handle_t  viewer;           /* first window in clipboard viewer list */
45     unsigned int   seqno;            /* clipboard change sequence number */
46     time_t         seqno_timestamp;  /* time stamp of last seqno increment */
47 };
48
49 static void clipboard_dump( struct object *obj, int verbose );
50
51 static const struct object_ops clipboard_ops =
52 {
53     sizeof(struct clipboard),     /* size */
54     clipboard_dump,               /* dump */
55     no_add_queue,                 /* add_queue */
56     NULL,                         /* remove_queue */
57     NULL,                         /* signaled */
58     NULL,                         /* satisfied */
59     no_signal,                    /* signal */
60     no_get_fd,                    /* get_fd */
61     no_lookup_name,               /* lookup_name */
62     no_close_handle,              /* close_handle */
63     no_destroy                    /* destroy */
64 };
65
66
67 #define MINUPDATELAPSE 2
68
69 /* dump a clipboard object */
70 static void clipboard_dump( struct object *obj, int verbose )
71 {
72     struct clipboard *clipboard = (struct clipboard *)obj;
73
74     fprintf( stderr, "Clipboard open_thread=%p open_win=%p owner_thread=%p owner_win=%p viewer=%p seq=%u\n",
75              clipboard->open_thread, clipboard->open_win, clipboard->owner_thread,
76              clipboard->owner_win, clipboard->viewer, clipboard->seqno );
77 }
78
79 /* retrieve the clipboard info for the current process, allocating it if needed */
80 static struct clipboard *get_process_clipboard(void)
81 {
82     struct clipboard *clipboard;
83     struct winstation *winstation = get_process_winstation( current->process, WINSTA_ACCESSCLIPBOARD );
84
85     if (!winstation) return NULL;
86
87     if (!(clipboard = winstation->clipboard))
88     {
89         if ((clipboard = alloc_object( &clipboard_ops )))
90         {
91             clipboard->open_thread = NULL;
92             clipboard->open_win = 0;
93             clipboard->owner_thread = NULL;
94             clipboard->owner_win = 0;
95             clipboard->viewer = 0;
96             clipboard->seqno = 0;
97             clipboard->seqno_timestamp = 0;
98             winstation->clipboard = clipboard;
99         }
100     }
101     release_object( winstation );
102     return clipboard;
103 }
104
105
106 /* Called when thread terminates to allow release of clipboard */
107 void cleanup_clipboard_thread(struct thread *thread)
108 {
109     struct clipboard *clipboard;
110     struct winstation *winstation = get_process_winstation( thread->process, WINSTA_ACCESSCLIPBOARD );
111
112     if (!winstation) return;
113
114     if ((clipboard = winstation->clipboard))
115     {
116         if (thread == clipboard->open_thread)
117         {
118             clipboard->open_win = 0;
119             clipboard->open_thread = NULL;
120         }
121         if (thread == clipboard->owner_thread)
122         {
123             clipboard->owner_win = 0;
124             clipboard->owner_thread = NULL;
125         }
126     }
127     release_object( winstation );
128 }
129
130 static int set_clipboard_window( struct clipboard *clipboard, user_handle_t win, int clear )
131 {
132     if (clipboard->open_thread && clipboard->open_thread != current)
133     {
134         set_error(STATUS_WAS_LOCKED);
135         return 0;
136     }
137     else if (!clear)
138     {
139         clipboard->open_win = win;
140         clipboard->open_thread = current;
141     }
142     else
143     {
144         clipboard->open_thread = NULL;
145         clipboard->open_win = 0;
146     }
147     return 1;
148 }
149
150
151 static int set_clipboard_owner( struct clipboard *clipboard, user_handle_t win, int clear )
152 {
153     if (clipboard->open_thread && clipboard->open_thread->process != current->process)
154     {
155         set_error(STATUS_WAS_LOCKED);
156         return 0;
157     }
158     else if (!clear)
159     {
160         clipboard->owner_win = win;
161         clipboard->owner_thread = current;
162     }
163     else
164     {
165         clipboard->owner_win = 0;
166         clipboard->owner_thread = NULL;
167     }
168     return 1;
169 }
170
171
172 static int get_seqno( struct clipboard *clipboard )
173 {
174     time_t tm = time(NULL);
175
176     if (!clipboard->owner_thread && (tm > (clipboard->seqno_timestamp + MINUPDATELAPSE)))
177     {
178         clipboard->seqno_timestamp = tm;
179         clipboard->seqno++;
180     }
181     return clipboard->seqno;
182 }
183
184
185 DECL_HANDLER(set_clipboard_info)
186 {
187     struct clipboard *clipboard = get_process_clipboard();
188
189     if (!clipboard) return;
190
191     reply->old_clipboard = clipboard->open_win;
192     reply->old_owner     = clipboard->owner_win;
193     reply->old_viewer    = clipboard->viewer;
194
195     if (req->flags & SET_CB_OPEN)
196     {
197         if (clipboard->open_thread)
198         {
199             /* clipboard already opened */
200             set_error(STATUS_WAS_LOCKED);
201             return;
202         }
203
204         if (!set_clipboard_window( clipboard, req->clipboard, 0 )) return;
205     }
206     else if (req->flags & SET_CB_CLOSE)
207     {
208         if (clipboard->open_thread != current)
209         {
210             set_win32_error(ERROR_CLIPBOARD_NOT_OPEN);
211             return;
212         }
213
214         if (!set_clipboard_window( clipboard, 0, 1 )) return;
215     }
216
217     if (req->flags & SET_CB_OWNER)
218     {
219         if (!set_clipboard_owner( clipboard, req->owner, 0 )) return;
220     }
221     else if (req->flags & SET_CB_RELOWNER)
222     {
223         if (!set_clipboard_owner( clipboard, 0, 1 )) return;
224     }
225
226     if (req->flags & SET_CB_VIEWER) clipboard->viewer = req->viewer;
227
228     if (req->flags & SET_CB_SEQNO) clipboard->seqno++;
229
230     reply->seqno = get_seqno( clipboard );
231
232     if (clipboard->open_thread == current) reply->flags |= CB_OPEN;
233     if (clipboard->owner_thread == current) reply->flags |= CB_OWNER;
234     if (clipboard->owner_thread && clipboard->owner_thread->process == current->process)
235         reply->flags |= CB_PROCESS;
236 }