Move the Check* type functions into wined3d and copy from d3d9, and
[wine] / server / window.c
1 /*
2  * Server-side window handling
3  *
4  * Copyright (C) 2001 Alexandre Julliard
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 <stdarg.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31
32 #include "object.h"
33 #include "request.h"
34 #include "thread.h"
35 #include "process.h"
36 #include "user.h"
37 #include "unicode.h"
38
39 /* a window property */
40 struct property
41 {
42     unsigned short type;     /* property type (see below) */
43     atom_t         atom;     /* property atom */
44     obj_handle_t   handle;   /* property handle (user-defined storage) */
45 };
46
47 enum property_type
48 {
49     PROP_TYPE_FREE,   /* free entry */
50     PROP_TYPE_STRING, /* atom that was originally a string */
51     PROP_TYPE_ATOM    /* plain atom */
52 };
53
54
55 struct window
56 {
57     struct window   *parent;          /* parent window */
58     user_handle_t    owner;           /* owner of this window */
59     struct window   *first_child;     /* first child in Z-order */
60     struct window   *last_child;      /* last child in Z-order */
61     struct window   *first_unlinked;  /* first child not linked in the Z-order list */
62     struct window   *next;            /* next window in Z-order */
63     struct window   *prev;            /* prev window in Z-order */
64     user_handle_t    handle;          /* full handle for this window */
65     struct thread   *thread;          /* thread owning the window */
66     struct window_class *class;       /* window class */
67     atom_t           atom;            /* class atom */
68     user_handle_t    last_active;     /* last active popup */
69     rectangle_t      window_rect;     /* window rectangle (relative to parent client area) */
70     rectangle_t      client_rect;     /* client rectangle (relative to parent client area) */
71     struct region   *win_region;      /* region for shaped windows (relative to window rect) */
72     unsigned int     style;           /* window style */
73     unsigned int     ex_style;        /* window extended style */
74     unsigned int     id;              /* window id */
75     void*            instance;        /* creator instance */
76     void*            user_data;       /* user-specific data */
77     WCHAR           *text;            /* window caption text */
78     int              paint_count;     /* count of pending paints for this window */
79     int              prop_inuse;      /* number of in-use window properties */
80     int              prop_alloc;      /* number of allocated window properties */
81     struct property *properties;      /* window properties array */
82     int              nb_extra_bytes;  /* number of extra bytes */
83     char             extra_bytes[1];  /* extra bytes storage */
84 };
85
86 /* growable array of user handles */
87 struct user_handle_array
88 {
89     user_handle_t *handles;
90     int            count;
91     int            total;
92 };
93
94 static struct window *top_window;  /* top-level (desktop) window */
95
96 /* global window pointers */
97 static struct window *shell_window;
98 static struct window *shell_listview;
99 static struct window *progman_window;
100 static struct window *taskman_window;
101
102 /* retrieve a pointer to a window from its handle */
103 inline static struct window *get_window( user_handle_t handle )
104 {
105     struct window *ret = get_user_object( handle, USER_WINDOW );
106     if (!ret) set_error( STATUS_INVALID_HANDLE );
107     return ret;
108 }
109
110 /* unlink a window from the tree */
111 static void unlink_window( struct window *win )
112 {
113     struct window *parent = win->parent;
114
115     assert( parent );
116
117     if (win->next) win->next->prev = win->prev;
118     else if (parent->last_child == win) parent->last_child = win->prev;
119
120     if (win->prev) win->prev->next = win->next;
121     else if (parent->first_child == win) parent->first_child = win->next;
122     else if (parent->first_unlinked == win) parent->first_unlinked = win->next;
123 }
124
125
126 /* link a window into the tree (or unlink it if the new parent is NULL)  */
127 static void link_window( struct window *win, struct window *parent, struct window *previous )
128 {
129     unlink_window( win );  /* unlink it from the previous location */
130
131     if (parent)
132     {
133         win->parent = parent;
134         if ((win->prev = previous))
135         {
136             if ((win->next = previous->next)) win->next->prev = win;
137             else if (win->parent->last_child == previous) win->parent->last_child = win;
138             win->prev->next = win;
139         }
140         else
141         {
142             if ((win->next = parent->first_child)) win->next->prev = win;
143             else win->parent->last_child = win;
144             parent->first_child = win;
145         }
146     }
147     else  /* move it to parent unlinked list */
148     {
149         parent = win->parent;
150         if ((win->next = parent->first_unlinked)) win->next->prev = win;
151         win->prev = NULL;
152         parent->first_unlinked = win;
153     }
154 }
155
156 /* append a user handle to a handle array */
157 static int add_handle_to_array( struct user_handle_array *array, user_handle_t handle )
158 {
159     if (array->count >= array->total)
160     {
161         int new_total = max( array->total * 2, 32 );
162         user_handle_t *new_array = realloc( array->handles, new_total * sizeof(*new_array) );
163         if (!new_array)
164         {
165             free( array->handles );
166             set_error( STATUS_NO_MEMORY );
167             return 0;
168         }
169         array->handles = new_array;
170         array->total = new_total;
171     }
172     array->handles[array->count++] = handle;
173     return 1;
174 }
175
176 /* set a window property */
177 static void set_property( struct window *win, atom_t atom, obj_handle_t handle,
178                           enum property_type type )
179 {
180     int i, free = -1;
181     struct property *new_props;
182
183     /* check if it exists already */
184     for (i = 0; i < win->prop_inuse; i++)
185     {
186         if (win->properties[i].type == PROP_TYPE_FREE)
187         {
188             free = i;
189             continue;
190         }
191         if (win->properties[i].atom == atom)
192         {
193             win->properties[i].type = type;
194             win->properties[i].handle = handle;
195             return;
196         }
197     }
198
199     /* need to add an entry */
200     if (!grab_global_atom( atom )) return;
201     if (free == -1)
202     {
203         /* no free entry */
204         if (win->prop_inuse >= win->prop_alloc)
205         {
206             /* need to grow the array */
207             if (!(new_props = realloc( win->properties,
208                                        sizeof(*new_props) * (win->prop_alloc + 16) )))
209             {
210                 set_error( STATUS_NO_MEMORY );
211                 release_global_atom( atom );
212                 return;
213             }
214             win->prop_alloc += 16;
215             win->properties = new_props;
216         }
217         free = win->prop_inuse++;
218     }
219     win->properties[free].atom   = atom;
220     win->properties[free].type   = type;
221     win->properties[free].handle = handle;
222 }
223
224 /* remove a window property */
225 static obj_handle_t remove_property( struct window *win, atom_t atom )
226 {
227     int i;
228
229     for (i = 0; i < win->prop_inuse; i++)
230     {
231         if (win->properties[i].type == PROP_TYPE_FREE) continue;
232         if (win->properties[i].atom == atom)
233         {
234             release_global_atom( atom );
235             win->properties[i].type = PROP_TYPE_FREE;
236             return win->properties[i].handle;
237         }
238     }
239     /* FIXME: last error? */
240     return 0;
241 }
242
243 /* find a window property */
244 static obj_handle_t get_property( struct window *win, atom_t atom )
245 {
246     int i;
247
248     for (i = 0; i < win->prop_inuse; i++)
249     {
250         if (win->properties[i].type == PROP_TYPE_FREE) continue;
251         if (win->properties[i].atom == atom) return win->properties[i].handle;
252     }
253     /* FIXME: last error? */
254     return 0;
255 }
256
257 /* destroy all properties of a window */
258 inline static void destroy_properties( struct window *win )
259 {
260     int i;
261
262     if (!win->properties) return;
263     for (i = 0; i < win->prop_inuse; i++)
264     {
265         if (win->properties[i].type == PROP_TYPE_FREE) continue;
266         release_global_atom( win->properties[i].atom );
267     }
268     free( win->properties );
269 }
270
271 /* destroy a window */
272 static void destroy_window( struct window *win )
273 {
274     assert( win != top_window );
275
276     /* destroy all children */
277     while (win->first_child) destroy_window( win->first_child );
278     while (win->first_unlinked) destroy_window( win->first_unlinked );
279
280     if (win->thread->queue)
281     {
282         if (win->paint_count) inc_queue_paint_count( win->thread, -win->paint_count );
283         queue_cleanup_window( win->thread, win->handle );
284     }
285     /* reset global window pointers, if the corresponding window is destroyed */
286     if (win == shell_window) shell_window = NULL;
287     if (win == shell_listview) shell_listview = NULL;
288     if (win == progman_window) progman_window = NULL;
289     if (win == taskman_window) taskman_window = NULL;
290     free_user_handle( win->handle );
291     destroy_properties( win );
292     unlink_window( win );
293     if (win->win_region) free_region( win->win_region );
294     release_class( win->class );
295     if (win->text) free( win->text );
296     memset( win, 0x55, sizeof(*win) );
297     free( win );
298 }
299
300 /* create a new window structure (note: the window is not linked in the window tree) */
301 static struct window *create_window( struct window *parent, struct window *owner,
302                                      atom_t atom, void *instance )
303 {
304     int extra_bytes;
305     struct window *win;
306     struct window_class *class = grab_class( current->process, atom, instance, &extra_bytes );
307
308     if (!class) return NULL;
309
310     win = mem_alloc( sizeof(*win) + extra_bytes - 1 );
311     if (!win)
312     {
313         release_class( class );
314         return NULL;
315     }
316
317     if (!(win->handle = alloc_user_handle( win, USER_WINDOW )))
318     {
319         release_class( class );
320         free( win );
321         return NULL;
322     }
323     win->parent         = parent;
324     win->owner          = owner ? owner->handle : 0;
325     win->first_child    = NULL;
326     win->last_child     = NULL;
327     win->first_unlinked = NULL;
328     win->thread         = current;
329     win->class          = class;
330     win->atom           = atom;
331     win->last_active    = win->handle;
332     win->win_region     = NULL;
333     win->style          = 0;
334     win->ex_style       = 0;
335     win->id             = 0;
336     win->instance       = NULL;
337     win->user_data      = NULL;
338     win->text           = NULL;
339     win->paint_count    = 0;
340     win->prop_inuse     = 0;
341     win->prop_alloc     = 0;
342     win->properties     = NULL;
343     win->nb_extra_bytes = extra_bytes;
344     memset( win->extra_bytes, 0, extra_bytes );
345
346     if (parent)  /* put it on parent unlinked list */
347     {
348         if ((win->next = parent->first_unlinked)) win->next->prev = win;
349         win->prev = NULL;
350         parent->first_unlinked = win;
351     }
352     else win->next = win->prev = NULL;
353
354     /* if parent belongs to a different thread, attach the two threads */
355     if (parent && parent->thread && parent->thread != current)
356         attach_thread_input( current, parent->thread );
357     return win;
358 }
359
360 /* destroy all windows belonging to a given thread */
361 void destroy_thread_windows( struct thread *thread )
362 {
363     user_handle_t handle = 0;
364     struct window *win;
365
366     while ((win = next_user_handle( &handle, USER_WINDOW )))
367     {
368         if (win->thread != thread) continue;
369         destroy_window( win );
370     }
371 }
372
373 /* check whether child is a descendant of parent */
374 int is_child_window( user_handle_t parent, user_handle_t child )
375 {
376     struct window *child_ptr = get_user_object( child, USER_WINDOW );
377     struct window *parent_ptr = get_user_object( parent, USER_WINDOW );
378
379     if (!child_ptr || !parent_ptr) return 0;
380     while (child_ptr->parent)
381     {
382         if (child_ptr->parent == parent_ptr) return 1;
383         child_ptr = child_ptr->parent;
384     }
385     return 0;
386 }
387
388 /* check whether window is a top-level window */
389 int is_top_level_window( user_handle_t window )
390 {
391     struct window *win = get_user_object( window, USER_WINDOW );
392     return (win && win->parent == top_window);
393 }
394
395 /* make a window active if possible */
396 int make_window_active( user_handle_t window )
397 {
398     struct window *owner, *win = get_window( window );
399
400     if (!win) return 0;
401
402     /* set last active for window and its owner */
403     win->last_active = win->handle;
404     if ((owner = get_user_object( win->owner, USER_WINDOW ))) owner->last_active = win->handle;
405     return 1;
406 }
407
408 /* check if point is inside the window */
409 static inline int is_point_in_window( struct window *win, int x, int y )
410 {
411     if (!(win->style & WS_VISIBLE)) return 0; /* not visible */
412     if ((win->style & (WS_POPUP|WS_CHILD|WS_DISABLED)) == (WS_CHILD|WS_DISABLED))
413         return 0;  /* disabled child */
414     if ((win->ex_style & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == (WS_EX_LAYERED|WS_EX_TRANSPARENT))
415         return 0;  /* transparent */
416     if (x < win->window_rect.left || x >= win->window_rect.right ||
417         y < win->window_rect.top || y >= win->window_rect.bottom)
418         return 0;  /* not in window */
419     if (win->win_region &&
420         !point_in_region( win->win_region, x - win->window_rect.left, y - win->window_rect.top ))
421         return 0;  /* not in window region */
422     return 1;
423 }
424
425 /* find child of 'parent' that contains the given point (in parent-relative coords) */
426 static struct window *child_window_from_point( struct window *parent, int x, int y )
427 {
428     struct window *ptr;
429
430     for (ptr = parent->first_child; ptr; ptr = ptr->next)
431     {
432         if (!is_point_in_window( ptr, x, y )) continue;  /* skip it */
433
434         /* if window is minimized or disabled, return at once */
435         if (ptr->style & (WS_MINIMIZE|WS_DISABLED)) return ptr;
436
437         /* if point is not in client area, return at once */
438         if (x < ptr->client_rect.left || x >= ptr->client_rect.right ||
439             y < ptr->client_rect.top || y >= ptr->client_rect.bottom)
440             return ptr;
441
442         return child_window_from_point( ptr, x - ptr->client_rect.left, y - ptr->client_rect.top );
443     }
444     return parent;  /* not found any child */
445 }
446
447 /* find all children of 'parent' that contain the given point */
448 static int get_window_children_from_point( struct window *parent, int x, int y,
449                                            struct user_handle_array *array )
450 {
451     struct window *ptr;
452
453     for (ptr = parent->first_child; ptr; ptr = ptr->next)
454     {
455         if (!is_point_in_window( ptr, x, y )) continue;  /* skip it */
456
457         /* if point is in client area, and window is not minimized or disabled, check children */
458         if (!(ptr->style & (WS_MINIMIZE|WS_DISABLED)) &&
459             x >= ptr->client_rect.left && x < ptr->client_rect.right &&
460             y >= ptr->client_rect.top && y < ptr->client_rect.bottom)
461         {
462             if (!get_window_children_from_point( ptr, x - ptr->client_rect.left,
463                                                  y - ptr->client_rect.top, array ))
464                 return 0;
465         }
466
467         /* now add window to the array */
468         if (!add_handle_to_array( array, ptr->handle )) return 0;
469     }
470     return 1;
471 }
472
473 /* find window containing point (in absolute coords) */
474 user_handle_t window_from_point( int x, int y )
475 {
476     struct window *ret;
477
478     if (!top_window) return 0;
479     ret = child_window_from_point( top_window, x, y );
480     return ret->handle;
481 }
482
483 /* return list of all windows containing point (in absolute coords) */
484 static int all_windows_from_point( struct window *top, int x, int y, struct user_handle_array *array )
485 {
486     struct window *ptr;
487
488     /* make point relative to top window */
489     for (ptr = top->parent; ptr && ptr != top_window; ptr = ptr->parent)
490     {
491         x -= ptr->client_rect.left;
492         y -= ptr->client_rect.top;
493     }
494
495     if (!is_point_in_window( top, x, y )) return 1;
496
497     /* if point is in client area, and window is not minimized or disabled, check children */
498     if (!(top->style & (WS_MINIMIZE|WS_DISABLED)) &&
499         x >= top->client_rect.left && x < top->client_rect.right &&
500         y >= top->client_rect.top && y < top->client_rect.bottom)
501     {
502         if (!get_window_children_from_point( top, x - top->client_rect.left,
503                                              y - top->client_rect.top, array ))
504             return 0;
505     }
506     /* now add window to the array */
507     if (!add_handle_to_array( array, top->handle )) return 0;
508     return 1;
509 }
510
511
512 /* return the thread owning a window */
513 struct thread *get_window_thread( user_handle_t handle )
514 {
515     struct window *win = get_user_object( handle, USER_WINDOW );
516     if (!win || !win->thread) return NULL;
517     return (struct thread *)grab_object( win->thread );
518 }
519
520 /* find a child of the specified window that needs repainting */
521 static struct window *find_child_to_repaint( struct window *parent, struct thread *thread )
522 {
523     struct window *ptr, *ret = NULL;
524
525     for (ptr = parent->first_child; ptr && !ret; ptr = ptr->next)
526     {
527         if (!(ptr->style & WS_VISIBLE)) continue;
528         if (ptr->paint_count && ptr->thread == thread)
529             ret = ptr;
530         else /* explore its children */
531             ret = find_child_to_repaint( ptr, thread );
532     }
533
534     if (ret && (ret->ex_style & WS_EX_TRANSPARENT))
535     {
536         /* transparent window, check for non-transparent sibling to paint first */
537         for (ptr = ret->next; ptr; ptr = ptr->next)
538         {
539             if (!(ptr->style & WS_VISIBLE)) continue;
540             if (ptr->ex_style & WS_EX_TRANSPARENT) continue;
541             if (ptr->paint_count && ptr->thread == thread) return ptr;
542         }
543     }
544     return ret;
545 }
546
547
548 /* find a window that needs repainting */
549 user_handle_t find_window_to_repaint( user_handle_t parent, struct thread *thread )
550 {
551     struct window *win = parent ? get_window( parent ) : top_window;
552
553     if (!win || !(win->style & WS_VISIBLE)) return 0;
554     if (!win->paint_count || win->thread != thread)
555         win = find_child_to_repaint( win, thread );
556     return win ? win->handle : 0;
557 }
558
559
560 /* intersect the window region with the specified region, relative to the window parent */
561 static struct region *intersect_window_region( struct region *region, struct window *win )
562 {
563     /* make region relative to window rect */
564     offset_region( region, -win->window_rect.left, -win->window_rect.top );
565     if (!intersect_region( region, region, win->win_region )) return NULL;
566     /* make region relative to parent again */
567     offset_region( region, win->window_rect.left, win->window_rect.top );
568     return region;
569 }
570
571
572 /* clip all children of a given window out of the visible region */
573 static struct region *clip_children( struct window *parent, struct window *last,
574                                      struct region *region, int offset_x, int offset_y )
575 {
576     struct window *ptr;
577     struct region *tmp = create_empty_region();
578
579     if (!tmp) return NULL;
580     for (ptr = parent->first_child; ptr && ptr != last; ptr = ptr->next)
581     {
582         if (!(ptr->style & WS_VISIBLE)) continue;
583         if (ptr->ex_style & WS_EX_TRANSPARENT) continue;
584         set_region_rect( tmp, &ptr->window_rect );
585         if (ptr->win_region && !intersect_window_region( tmp, ptr ))
586         {
587             free_region( tmp );
588             return NULL;
589         }
590         offset_region( tmp, offset_x, offset_y );
591         if (!(region = subtract_region( region, region, tmp ))) break;
592         if (is_region_empty( region )) break;
593     }
594     free_region( tmp );
595     return region;
596 }
597
598
599 /* compute the visible region of a window */
600 static struct region *get_visible_region( struct window *win, struct window *top,
601                                           unsigned int flags )
602 {
603     struct region *tmp, *region;
604     struct window *ptr;
605     int offset_x, offset_y;
606
607     if (!(region = create_empty_region())) return NULL;
608
609     /* first check if all ancestors are visible */
610
611     for (ptr = win; ptr != top_window; ptr = ptr->parent)
612         if (!(ptr->style & WS_VISIBLE)) return region;  /* empty region */
613
614     /* create a region relative to the window itself */
615
616     if ((flags & DCX_PARENTCLIP) && win != top && win->parent)
617     {
618         rectangle_t rect;
619         rect.left = rect.top = 0;
620         rect.right = win->parent->client_rect.right - win->parent->client_rect.left;
621         rect.bottom = win->parent->client_rect.bottom - win->parent->client_rect.top;
622         set_region_rect( region, &rect );
623         offset_x = win->client_rect.left;
624         offset_y = win->client_rect.top;
625     }
626     else if (flags & DCX_WINDOW)
627     {
628         set_region_rect( region, &win->window_rect );
629         if (win->win_region && !intersect_window_region( region, win )) goto error;
630         offset_x = win->window_rect.left;
631         offset_y = win->window_rect.top;
632     }
633     else
634     {
635         set_region_rect( region, &win->client_rect );
636         if (win->win_region && !intersect_window_region( region, win )) goto error;
637         offset_x = win->client_rect.left;
638         offset_y = win->client_rect.top;
639     }
640     offset_region( region, -offset_x, -offset_y );
641
642     /* clip children */
643
644     if (flags & DCX_CLIPCHILDREN)
645     {
646         if (!clip_children( win, NULL, region,
647                             offset_x - win->client_rect.left,
648                             offset_y - win->client_rect.top )) goto error;
649     }
650
651     /* clip siblings of ancestors */
652
653     if (top && top != win && (tmp = create_empty_region()) != NULL)
654     {
655         offset_region( region, offset_x, offset_y );  /* make it relative to parent */
656         while (win != top && win->parent)
657         {
658             if (win->style & WS_CLIPSIBLINGS)
659             {
660                 if (!clip_children( win->parent, win, region, 0, 0 )) goto error;
661                 if (is_region_empty( region )) break;
662             }
663             /* clip to parent client area */
664             win = win->parent;
665             offset_x += win->client_rect.left;
666             offset_y += win->client_rect.top;
667             offset_region( region, win->client_rect.left, win->client_rect.top );
668             set_region_rect( tmp, &win->client_rect );
669             if (win->win_region && !intersect_window_region( tmp, win ))
670             {
671                 free_region( tmp );
672                 goto error;
673             }
674             if (!intersect_region( region, region, tmp ))
675             {
676                 free_region( tmp );
677                 goto error;
678             }
679             if (is_region_empty( region )) break;
680         }
681         offset_region( region, -offset_x, -offset_y );  /* make it relative to target window again */
682         free_region( tmp );
683     }
684     return region;
685
686 error:
687     free_region( region );
688     return NULL;
689 }
690
691
692 /* get the window class of a window */
693 struct window_class* get_window_class( user_handle_t window )
694 {
695     struct window *win;
696     if (!(win = get_window( window ))) return NULL;
697     return win->class;
698 }
699
700
701 /* create a window */
702 DECL_HANDLER(create_window)
703 {
704     struct window *win;
705
706     reply->handle = 0;
707     if (!req->parent)  /* return desktop window */
708     {
709         if (!top_window)
710         {
711             if (!(top_window = create_window( NULL, NULL, req->atom, req->instance ))) return;
712             top_window->thread = NULL;  /* no thread owns the desktop */
713             top_window->style  = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
714         }
715         win = top_window;
716     }
717     else
718     {
719         struct window *parent, *owner = NULL;
720
721         if (!(parent = get_window( req->parent ))) return;
722         if (req->owner && !(owner = get_window( req->owner ))) return;
723         if (owner == top_window) owner = NULL;
724         else if (owner && parent != top_window)
725         {
726             /* an owned window must be created as top-level */
727             set_error( STATUS_ACCESS_DENIED );
728             return;
729         }
730         if (!(win = create_window( parent, owner, req->atom, req->instance ))) return;
731     }
732     reply->handle    = win->handle;
733     reply->extra     = win->nb_extra_bytes;
734     reply->class_ptr = get_class_client_ptr( win->class );
735 }
736
737
738 /* link a window into the tree */
739 DECL_HANDLER(link_window)
740 {
741     struct window *win, *parent = NULL, *previous = NULL;
742
743     if (!(win = get_window( req->handle ))) return;
744     if (req->parent && !(parent = get_window( req->parent ))) return;
745
746     if (win == top_window)
747     {
748         set_error( STATUS_INVALID_PARAMETER );
749         return;
750     }
751     reply->full_parent = parent ? parent->handle : 0;
752     if (parent && req->previous)
753     {
754         if (req->previous == (user_handle_t)1)  /* special case: HWND_BOTTOM */
755         {
756             previous = parent->last_child;
757             if (previous == win) return;  /* nothing to do */
758         }
759         else
760         {
761             if (!(previous = get_window( req->previous ))) return;
762             /* previous must be a child of parent, and not win itself */
763             if (previous->parent != parent || previous == win)
764             {
765                 set_error( STATUS_INVALID_PARAMETER );
766                 return;
767             }
768         }
769     }
770     link_window( win, parent, previous );
771 }
772
773
774 /* destroy a window */
775 DECL_HANDLER(destroy_window)
776 {
777     struct window *win = get_window( req->handle );
778     if (win)
779     {
780         if (win != top_window) destroy_window( win );
781         else set_error( STATUS_ACCESS_DENIED );
782     }
783 }
784
785
786 /* set a window owner */
787 DECL_HANDLER(set_window_owner)
788 {
789     struct window *win = get_window( req->handle );
790     struct window *owner = NULL;
791
792     if (!win) return;
793     if (req->owner && !(owner = get_window( req->owner ))) return;
794     if (win == top_window)
795     {
796         set_error( STATUS_ACCESS_DENIED );
797         return;
798     }
799     reply->prev_owner = win->owner;
800     reply->full_owner = win->owner = owner ? owner->handle : 0;
801 }
802
803
804 /* get information from a window handle */
805 DECL_HANDLER(get_window_info)
806 {
807     struct window *win = get_window( req->handle );
808
809     reply->full_handle = 0;
810     reply->tid = reply->pid = 0;
811     if (win)
812     {
813         reply->full_handle = win->handle;
814         reply->last_active = win->handle;
815         if (get_user_object( win->last_active, USER_WINDOW )) reply->last_active = win->last_active;
816         if (win->thread)
817         {
818             reply->tid  = get_thread_id( win->thread );
819             reply->pid  = get_process_id( win->thread->process );
820             reply->atom = get_class_atom( win->class );
821         }
822     }
823 }
824
825
826 /* set some information in a window */
827 DECL_HANDLER(set_window_info)
828 {
829     struct window *win = get_window( req->handle );
830
831     if (!win) return;
832     if (req->flags && win == top_window)
833     {
834         set_error( STATUS_ACCESS_DENIED );
835         return;
836     }
837     if (req->extra_size > sizeof(req->extra_value) ||
838         req->extra_offset < -1 ||
839         req->extra_offset > win->nb_extra_bytes - (int)req->extra_size)
840     {
841         set_win32_error( ERROR_INVALID_INDEX );
842         return;
843     }
844     if (req->extra_offset != -1)
845     {
846         memcpy( &reply->old_extra_value, win->extra_bytes + req->extra_offset, req->extra_size );
847     }
848     else if (req->flags & SET_WIN_EXTRA)
849     {
850         set_win32_error( ERROR_INVALID_INDEX );
851         return;
852     }
853     reply->old_style     = win->style;
854     reply->old_ex_style  = win->ex_style;
855     reply->old_id        = win->id;
856     reply->old_instance  = win->instance;
857     reply->old_user_data = win->user_data;
858     if (req->flags & SET_WIN_STYLE) win->style = req->style;
859     if (req->flags & SET_WIN_EXSTYLE) win->ex_style = req->ex_style;
860     if (req->flags & SET_WIN_ID) win->id = req->id;
861     if (req->flags & SET_WIN_INSTANCE) win->instance = req->instance;
862     if (req->flags & SET_WIN_USERDATA) win->user_data = req->user_data;
863     if (req->flags & SET_WIN_EXTRA) memcpy( win->extra_bytes + req->extra_offset,
864                                             &req->extra_value, req->extra_size );
865 }
866
867
868 /* get a list of the window parents, up to the root of the tree */
869 DECL_HANDLER(get_window_parents)
870 {
871     struct window *ptr, *win = get_window( req->handle );
872     int total = 0;
873     user_handle_t *data;
874     size_t len;
875
876     if (win) for (ptr = win->parent; ptr; ptr = ptr->parent) total++;
877
878     reply->count = total;
879     len = min( get_reply_max_size(), total * sizeof(user_handle_t) );
880     if (len && ((data = set_reply_data_size( len ))))
881     {
882         for (ptr = win->parent; ptr && len; ptr = ptr->parent, len -= sizeof(*data))
883             *data++ = ptr->handle;
884     }
885 }
886
887
888 /* get a list of the window children */
889 DECL_HANDLER(get_window_children)
890 {
891     struct window *ptr, *parent = get_window( req->parent );
892     int total = 0;
893     user_handle_t *data;
894     size_t len;
895
896     if (parent)
897         for (ptr = parent->first_child, total = 0; ptr; ptr = ptr->next)
898         {
899             if (req->atom && get_class_atom(ptr->class) != req->atom) continue;
900             if (req->tid && get_thread_id(ptr->thread) != req->tid) continue;
901             total++;
902         }
903
904     reply->count = total;
905     len = min( get_reply_max_size(), total * sizeof(user_handle_t) );
906     if (len && ((data = set_reply_data_size( len ))))
907     {
908         for (ptr = parent->first_child; ptr && len; ptr = ptr->next)
909         {
910             if (req->atom && get_class_atom(ptr->class) != req->atom) continue;
911             if (req->tid && get_thread_id(ptr->thread) != req->tid) continue;
912             *data++ = ptr->handle;
913             len -= sizeof(*data);
914         }
915     }
916 }
917
918
919 /* get a list of the window children that contain a given point */
920 DECL_HANDLER(get_window_children_from_point)
921 {
922     struct user_handle_array array;
923     struct window *parent = get_window( req->parent );
924     size_t len;
925
926     if (!parent) return;
927
928     array.handles = NULL;
929     array.count = 0;
930     array.total = 0;
931     if (!all_windows_from_point( parent, req->x, req->y, &array )) return;
932
933     reply->count = array.count;
934     len = min( get_reply_max_size(), array.count * sizeof(user_handle_t) );
935     if (len) set_reply_data_ptr( array.handles, len );
936     else free( array.handles );
937 }
938
939
940 /* get window tree information from a window handle */
941 DECL_HANDLER(get_window_tree)
942 {
943     struct window *win = get_window( req->handle );
944
945     if (!win) return;
946
947     if (win->parent)
948     {
949         struct window *parent = win->parent;
950         reply->parent        = parent->handle;
951         reply->owner         = win->owner;
952         reply->next_sibling  = win->next ? win->next->handle : 0;
953         reply->prev_sibling  = win->prev ? win->prev->handle : 0;
954         reply->first_sibling = parent->first_child ? parent->first_child->handle : 0;
955         reply->last_sibling  = parent->last_child ? parent->last_child->handle : 0;
956     }
957     else
958     {
959         reply->parent        = 0;
960         reply->owner         = 0;
961         reply->next_sibling  = 0;
962         reply->prev_sibling  = 0;
963         reply->first_sibling = 0;
964         reply->last_sibling  = 0;
965     }
966     reply->first_child = win->first_child ? win->first_child->handle : 0;
967     reply->last_child  = win->last_child ? win->last_child->handle : 0;
968 }
969
970
971 /* set the window and client rectangles of a window */
972 DECL_HANDLER(set_window_rectangles)
973 {
974     struct window *win = get_window( req->handle );
975
976     if (win)
977     {
978         win->window_rect = req->window;
979         win->client_rect = req->client;
980     }
981 }
982
983
984 /* get the window and client rectangles of a window */
985 DECL_HANDLER(get_window_rectangles)
986 {
987     struct window *win = get_window( req->handle );
988
989     if (win)
990     {
991         reply->window = win->window_rect;
992         reply->client = win->client_rect;
993     }
994 }
995
996
997 /* get the window text */
998 DECL_HANDLER(get_window_text)
999 {
1000     struct window *win = get_window( req->handle );
1001
1002     if (win && win->text)
1003     {
1004         size_t len = strlenW( win->text ) * sizeof(WCHAR);
1005         if (len > get_reply_max_size()) len = get_reply_max_size();
1006         set_reply_data( win->text, len );
1007     }
1008 }
1009
1010
1011 /* set the window text */
1012 DECL_HANDLER(set_window_text)
1013 {
1014     struct window *win = get_window( req->handle );
1015
1016     if (win)
1017     {
1018         WCHAR *text = NULL;
1019         size_t len = get_req_data_size() / sizeof(WCHAR);
1020         if (len)
1021         {
1022             if (!(text = mem_alloc( (len+1) * sizeof(WCHAR) ))) return;
1023             memcpy( text, get_req_data(), len * sizeof(WCHAR) );
1024             text[len] = 0;
1025         }
1026         if (win->text) free( win->text );
1027         win->text = text;
1028     }
1029 }
1030
1031
1032 /* increment the window paint count */
1033 DECL_HANDLER(inc_window_paint_count)
1034 {
1035     struct window *win = get_window( req->handle );
1036
1037     if (win && win->thread)
1038     {
1039         int old = win->paint_count;
1040         if ((win->paint_count += req->incr) < 0) win->paint_count = 0;
1041         inc_queue_paint_count( win->thread, win->paint_count - old );
1042     }
1043 }
1044
1045
1046 /* get the coordinates offset between two windows */
1047 DECL_HANDLER(get_windows_offset)
1048 {
1049     struct window *win;
1050
1051     reply->x = reply->y = 0;
1052     if (req->from)
1053     {
1054         if (!(win = get_window( req->from ))) return;
1055         while (win)
1056         {
1057             reply->x += win->client_rect.left;
1058             reply->y += win->client_rect.top;
1059             win = win->parent;
1060         }
1061     }
1062     if (req->to)
1063     {
1064         if (!(win = get_window( req->to ))) return;
1065         while (win)
1066         {
1067             reply->x -= win->client_rect.left;
1068             reply->y -= win->client_rect.top;
1069             win = win->parent;
1070         }
1071     }
1072 }
1073
1074
1075 /* get the visible region of a window */
1076 DECL_HANDLER(get_visible_region)
1077 {
1078     struct region *region;
1079     struct window *win = get_window( req->window );
1080     struct window *top = NULL;
1081
1082     if (!win) return;
1083     if (req->top_win && !(top = get_window( req->top_win ))) return;
1084
1085     if ((region = get_visible_region( win, top, req->flags )))
1086     {
1087         rectangle_t *data = get_region_data_and_free( region, get_reply_max_size(), &reply->total_size );
1088         if (data) set_reply_data_ptr( data, reply->total_size );
1089     }
1090 }
1091
1092
1093 /* get the window region */
1094 DECL_HANDLER(get_window_region)
1095 {
1096     struct window *win = get_window( req->window );
1097
1098     if (!win) return;
1099
1100     if (win->win_region)
1101     {
1102         rectangle_t *data = get_region_data( win->win_region, get_reply_max_size(), &reply->total_size );
1103         if (data) set_reply_data_ptr( data, reply->total_size );
1104     }
1105 }
1106
1107
1108 /* set the window region */
1109 DECL_HANDLER(set_window_region)
1110 {
1111     struct region *region = NULL;
1112     struct window *win = get_window( req->window );
1113
1114     if (!win) return;
1115
1116     if (get_req_data_size())  /* no data means remove the region completely */
1117     {
1118         if (!(region = create_region_from_req_data( get_req_data(), get_req_data_size() )))
1119             return;
1120     }
1121     if (win->win_region) free_region( win->win_region );
1122     win->win_region = region;
1123 }
1124
1125
1126 /* set a window property */
1127 DECL_HANDLER(set_window_property)
1128 {
1129     struct window *win = get_window( req->window );
1130
1131     if (win) set_property( win, req->atom, req->handle,
1132                            req->string ? PROP_TYPE_STRING : PROP_TYPE_ATOM );
1133 }
1134
1135
1136 /* remove a window property */
1137 DECL_HANDLER(remove_window_property)
1138 {
1139     struct window *win = get_window( req->window );
1140     reply->handle = 0;
1141     if (win) reply->handle = remove_property( win, req->atom );
1142 }
1143
1144
1145 /* get a window property */
1146 DECL_HANDLER(get_window_property)
1147 {
1148     struct window *win = get_window( req->window );
1149     reply->handle = 0;
1150     if (win) reply->handle = get_property( win, req->atom );
1151 }
1152
1153
1154 /* get the list of properties of a window */
1155 DECL_HANDLER(get_window_properties)
1156 {
1157     property_data_t *data;
1158     int i, count, max = get_reply_max_size() / sizeof(*data);
1159     struct window *win = get_window( req->window );
1160
1161     reply->total = 0;
1162     if (!win) return;
1163
1164     for (i = count = 0; i < win->prop_inuse; i++)
1165         if (win->properties[i].type != PROP_TYPE_FREE) count++;
1166     reply->total = count;
1167
1168     if (count > max) count = max;
1169     if (!count || !(data = set_reply_data_size( count * sizeof(*data) ))) return;
1170
1171     for (i = 0; i < win->prop_inuse && count; i++)
1172     {
1173         if (win->properties[i].type == PROP_TYPE_FREE) continue;
1174         data->atom   = win->properties[i].atom;
1175         data->string = (win->properties[i].type == PROP_TYPE_STRING);
1176         data->handle = win->properties[i].handle;
1177         data++;
1178         count--;
1179     }
1180 }
1181
1182
1183 /* get the new window pointer for a global window, checking permissions */
1184 /* helper for set_global_windows request */
1185 static int get_new_global_window( struct window **win, user_handle_t handle )
1186 {
1187     if (!handle)
1188     {
1189         *win = NULL;
1190         return 1;
1191     }
1192     else if (*win)
1193     {
1194         set_error( STATUS_ACCESS_DENIED );
1195         return 0;
1196     }
1197     *win = get_window( handle );
1198     return (*win != NULL);
1199 }
1200
1201 /* Set/get the global windows */
1202 DECL_HANDLER(set_global_windows)
1203 {
1204     struct window *new_shell_window   = shell_window;
1205     struct window *new_shell_listview = shell_listview;
1206     struct window *new_progman_window = progman_window;
1207     struct window *new_taskman_window = taskman_window;
1208
1209     reply->old_shell_window   = shell_window ? shell_window->handle : 0;
1210     reply->old_shell_listview = shell_listview ? shell_listview->handle : 0;
1211     reply->old_progman_window = progman_window ? progman_window->handle : 0;
1212     reply->old_taskman_window = taskman_window ? taskman_window->handle : 0;
1213
1214     if (req->flags & SET_GLOBAL_SHELL_WINDOWS)
1215     {
1216         if (!get_new_global_window( &new_shell_window, req->shell_window )) return;
1217         if (!get_new_global_window( &new_shell_listview, req->shell_listview )) return;
1218     }
1219     if (req->flags & SET_GLOBAL_PROGMAN_WINDOW)
1220     {
1221         if (!get_new_global_window( &new_progman_window, req->progman_window )) return;
1222     }
1223     if (req->flags & SET_GLOBAL_TASKMAN_WINDOW)
1224     {
1225         if (!get_new_global_window( &new_taskman_window, req->taskman_window )) return;
1226     }
1227     shell_window   = new_shell_window;
1228     shell_listview = new_shell_listview;
1229     progman_window = new_progman_window;
1230     taskman_window = new_taskman_window;
1231 }