- fixed copy&paste bug (GENERIC_WRITE instead of GENERIC_READ)
[wine] / server / window.c
1 /*
2  * Server-side window handling
3  *
4  * Copyright (C) 2001 Alexandre Julliard
5  */
6
7 #include <assert.h>
8
9 #include "object.h"
10 #include "request.h"
11 #include "thread.h"
12 #include "process.h"
13 #include "user.h"
14
15 struct window
16 {
17     struct window   *parent;      /* parent window */
18     struct window   *owner;       /* owner of this window */
19     struct window   *first_child; /* first child window */
20     struct window   *last_child;  /* last child window */
21     struct window   *next;        /* next window in Z-order */
22     struct window   *prev;        /* prev window in Z-order */
23     user_handle_t    handle;      /* full handle for this window */
24     struct thread   *thread;      /* thread owning the window */
25 };
26
27 static struct window *top_window;  /* top-level (desktop) window */
28
29
30 /* retrieve a pointer to a window from its handle */
31 inline static struct window *get_window( user_handle_t handle )
32 {
33     struct window *ret = get_user_object( handle, USER_WINDOW );
34     if (!ret) set_error( STATUS_INVALID_HANDLE );
35     return ret;
36 }
37
38 /* link a window into the tree (or unlink it if the new parent is NULL)  */
39 static void link_window( struct window *win, struct window *parent, struct window *previous )
40 {
41     if (win->parent)  /* unlink it from the previous location */
42     {
43         if (win->next) win->next->prev = win->prev;
44         else if (win->parent->last_child == win) win->parent->last_child = win->prev;
45         if (win->prev) win->prev->next = win->next;
46         else if (win->parent->first_child == win) win->parent->first_child = win->next;
47     }
48     if (parent)
49     {
50         win->parent = parent;
51         if ((win->prev = previous))
52         {
53             if ((win->next = previous->next)) win->next->prev = win;
54             else if (win->parent->last_child == previous) win->parent->last_child = win;
55             win->prev->next = win;
56         }
57         else
58         {
59             if ((win->next = parent->first_child)) win->next->prev = win;
60             else win->parent->last_child = win;
61             parent->first_child = win;
62         }
63     }
64     else
65     {
66         /* don't touch parent; an unlinked window still has a valid parent pointer */
67         win->next = win->prev = NULL;
68     }
69 }
70
71 /* destroy a window */
72 static void destroy_window( struct window *win )
73 {
74     assert( win != top_window );
75
76     /* destroy all children */
77     while (win->first_child) destroy_window( win->first_child );
78
79     /* reset siblings owner */
80     if (win->parent)
81     {
82         struct window *ptr;
83         for (ptr = win->parent->first_child; ptr; ptr = ptr->next)
84             if (ptr->owner == win) ptr->owner = NULL;
85     }
86
87     if (win->thread->queue) queue_cleanup_window( win->thread, win->handle );
88     free_user_handle( win->handle );
89     link_window( win, NULL, NULL );
90     memset( win, 0x55, sizeof(*win) );
91     free( win );
92 }
93
94 /* create a new window structure (note: the window is not linked in the window tree) */
95 static struct window *create_window( struct window *parent, struct window *owner )
96 {
97     struct window *win = mem_alloc( sizeof(*win) );
98     if (!win) return NULL;
99
100     if (!(win->handle = alloc_user_handle( win, USER_WINDOW )))
101     {
102         free( win );
103         return NULL;
104     }
105     win->parent      = parent;
106     win->owner       = owner;
107     win->first_child = NULL;
108     win->last_child  = NULL;
109     win->next        = NULL;
110     win->prev        = NULL;
111     win->thread      = current;
112     return win;
113 }
114
115 /* destroy all windows belonging to a given thread */
116 void destroy_thread_windows( struct thread *thread )
117 {
118     user_handle_t handle = 0;
119     struct window *win;
120
121     while ((win = next_user_handle( &handle, USER_WINDOW )))
122     {
123         if (win->thread != thread) continue;
124         destroy_window( win );
125     }
126 }
127
128 /* check whether child is a descendant of parent */
129 int is_child_window( user_handle_t parent, user_handle_t child )
130 {
131     struct window *child_ptr = get_user_object( child, USER_WINDOW );
132     struct window *parent_ptr = get_user_object( parent, USER_WINDOW );
133
134     if (!child_ptr || !parent_ptr) return 0;
135     while (child_ptr->parent)
136     {
137         if (child_ptr->parent == parent_ptr) return 1;
138         child_ptr = child_ptr->parent;
139     }
140     return 0;
141 }
142
143 /* create a window */
144 DECL_HANDLER(create_window)
145 {
146     req->handle = 0;
147     if (!req->parent)  /* return desktop window */
148     {
149         if (!top_window)
150         {
151             if (!(top_window = create_window( NULL, NULL ))) return;
152             top_window->thread = NULL;  /* no thread owns the desktop */
153         }
154         req->handle = top_window->handle;
155     }
156     else
157     {
158         struct window *win, *parent, *owner = NULL;
159
160         if (!(parent = get_window( req->parent ))) return;
161         if (req->owner && !(owner = get_window( req->owner ))) return;
162         if (!(win = create_window( parent, owner ))) return;
163         req->handle = win->handle;
164     }
165 }
166
167
168 /* link a window into the tree */
169 DECL_HANDLER(link_window)
170 {
171     struct window *win, *parent = NULL, *previous = NULL;
172
173     if (!(win = get_window( req->handle ))) return;
174     if (req->parent && !(parent = get_window( req->parent ))) return;
175     if (parent && req->previous)
176     {
177         if (req->previous == (user_handle_t)1)  /* special case: HWND_BOTTOM */
178         {
179             previous = parent->last_child;
180             if (previous == win) return;  /* nothing to do */
181         }
182         else
183         {
184             if (!(previous = get_window( req->previous ))) return;
185             /* previous must be a child of parent, and not win itself */
186             if (previous->parent != parent || previous == win)
187             {
188                 set_error( STATUS_INVALID_PARAMETER );
189                 return;
190             }
191         }
192     }
193     link_window( win, parent, previous );
194 }
195
196
197 /* destroy a window */
198 DECL_HANDLER(destroy_window)
199 {
200     struct window *win = get_window( req->handle );
201     if (win)
202     {
203         if (win != top_window) destroy_window( win );
204         else set_error( STATUS_ACCESS_DENIED );
205     }
206 }
207
208
209 /* get information from a window handle */
210 DECL_HANDLER(get_window_info)
211 {
212     struct window *win = get_window( req->handle );
213
214     req->full_handle = 0;
215     req->tid = req->pid = 0;
216     if (win)
217     {
218         req->full_handle = win->handle;
219         if (win->thread)
220         {
221             req->tid = get_thread_id( win->thread );
222             req->pid = get_process_id( win->thread->process );
223         }
224     }
225 }
226
227
228 /* get a list of the window parents, up to the root of the tree */
229 DECL_HANDLER(get_window_parents)
230 {
231     struct window *ptr, *win = get_window( req->handle );
232     int total = 0;
233     size_t len;
234
235     if (win) for (ptr = win->parent; ptr; ptr = ptr->parent) total++;
236
237     req->count = total;
238     len = min( get_req_data_size(req), total * sizeof(user_handle_t) );
239     set_req_data_size( req, len );
240     if (len)
241     {
242         user_handle_t *data = get_req_data(req);
243         for (ptr = win->parent; ptr && len; ptr = ptr->parent, len -= sizeof(*data))
244             *data++ = ptr->handle;
245     }
246 }
247
248
249 /* get a list of the window children */
250 DECL_HANDLER(get_window_children)
251 {
252     struct window *ptr, *parent = get_window( req->parent );
253     int total = 0;
254     size_t len;
255
256     if (parent)
257         for (ptr = parent->first_child, total = 0; ptr; ptr = ptr->next) total++;
258
259     req->count = total;
260     len = min( get_req_data_size(req), total * sizeof(user_handle_t) );
261     set_req_data_size( req, len );
262     if (len)
263     {
264         user_handle_t *data = get_req_data(req);
265         for (ptr = parent->first_child; ptr && len; ptr = ptr->next, len -= sizeof(*data))
266             *data++ = ptr->handle;
267     }
268 }
269
270
271 /* get window tree information from a window handle */
272 DECL_HANDLER(get_window_tree)
273 {
274     struct window *win = get_window( req->handle );
275
276     if (!win) return;
277
278     if (win->parent)
279     {
280         struct window *parent = win->parent;
281         req->parent        = parent->handle;
282         req->owner         = win->owner ? win->owner->handle : 0;
283         req->next_sibling  = win->next ? win->next->handle : 0;
284         req->prev_sibling  = win->prev ? win->prev->handle : 0;
285         req->first_sibling = parent->first_child ? parent->first_child->handle : 0;
286         req->last_sibling  = parent->last_child ? parent->last_child->handle : 0;
287     }
288     else
289     {
290         req->parent        = 0;
291         req->owner         = 0;
292         req->next_sibling  = 0;
293         req->prev_sibling  = 0;
294         req->first_sibling = 0;
295         req->last_sibling  = 0;
296     }
297     req->first_child = win->first_child ? win->first_child->handle : 0;
298     req->last_child  = win->last_child ? win->last_child->handle : 0;
299 }