Added proper support for storing window parents in the server.
[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 == 1)  /* special case: HWND_BOTTOM */
178             previous = parent->last_child;
179         else
180             if (!(previous = get_window( req->previous ))) return;
181
182         if (previous && previous->parent != parent)  /* previous must be a child of parent */
183         {
184             set_error( STATUS_INVALID_PARAMETER );
185             return;
186         }
187     }
188     link_window( win, parent, previous );
189 }
190
191
192 /* destroy a window */
193 DECL_HANDLER(destroy_window)
194 {
195     struct window *win = get_window( req->handle );
196     if (win)
197     {
198         if (win != top_window) destroy_window( win );
199         else set_error( STATUS_ACCESS_DENIED );
200     }
201 }
202
203
204 /* get information from a window handle */
205 DECL_HANDLER(get_window_info)
206 {
207     struct window *win = get_window( req->handle );
208
209     req->full_handle = 0;
210     req->tid = req->pid = 0;
211     if (win)
212     {
213         req->full_handle = win->handle;
214         if (win->thread)
215         {
216             req->tid = get_thread_id( win->thread );
217             req->pid = get_process_id( win->thread->process );
218         }
219     }
220 }
221
222
223 /* get a list of the window parents, up to the root of the tree */
224 DECL_HANDLER(get_window_parents)
225 {
226     struct window *ptr, *win = get_window( req->handle );
227     int total = 0;
228     size_t len;
229
230     if (win) for (ptr = win->parent; ptr; ptr = ptr->parent) total++;
231
232     req->count = total;
233     len = min( get_req_data_size(req), total * sizeof(user_handle_t) );
234     set_req_data_size( req, len );
235     if (len)
236     {
237         user_handle_t *data = get_req_data(req);
238         for (ptr = win->parent; ptr && len; ptr = ptr->parent, len -= sizeof(*data))
239             *data++ = ptr->handle;
240     }
241 }
242
243
244 /* get a list of the window children */
245 DECL_HANDLER(get_window_children)
246 {
247     struct window *ptr, *parent = get_window( req->parent );
248     int total = 0;
249     size_t len;
250
251     if (parent)
252         for (ptr = parent->first_child, total = 0; ptr; ptr = ptr->next) total++;
253
254     req->count = total;
255     len = min( get_req_data_size(req), total * sizeof(user_handle_t) );
256     set_req_data_size( req, len );
257     if (len)
258     {
259         user_handle_t *data = get_req_data(req);
260         for (ptr = parent->first_child; ptr && len; ptr = ptr->next, len -= sizeof(*data))
261             *data++ = ptr->handle;
262     }
263 }
264
265
266 /* get window tree information from a window handle */
267 DECL_HANDLER(get_window_tree)
268 {
269     struct window *win = get_window( req->handle );
270
271     if (!win) return;
272
273     if (win->parent)
274     {
275         struct window *parent = win->parent;
276         req->parent        = parent->handle;
277         req->owner         = win->owner ? win->owner->handle : 0;
278         req->next_sibling  = win->next ? win->next->handle : 0;
279         req->prev_sibling  = win->prev ? win->prev->handle : 0;
280         req->first_sibling = parent->first_child ? parent->first_child->handle : 0;
281         req->last_sibling  = parent->last_child ? parent->last_child->handle : 0;
282     }
283     else
284     {
285         req->parent        = 0;
286         req->owner         = 0;
287         req->next_sibling  = 0;
288         req->prev_sibling  = 0;
289         req->first_sibling = 0;
290         req->last_sibling  = 0;
291     }
292     req->first_child = win->first_child ? win->first_child->handle : 0;
293     req->last_child  = win->last_child ? win->last_child->handle : 0;
294 }